亚洲在线久爱草,狠狠天天香蕉网,天天搞日日干久草,伊人亚洲日本欧美

為了賬號安全,請及時綁定郵箱和手機立即綁定
已解決430363個問題,去搜搜看,總會有你想問的

使用Java泛型為實體實現轉換器

使用Java泛型為實體實現轉換器

慕尼黑5688855 2019-12-04 11:10:53
我正在使用Spring和Hibernate進行JSF項目,其中除其他外,還有許多Converter遵循相同模式的s:getAsObject 接收對象id的字符串表示形式,將其轉換為數字,并獲取給定種類和給定id的實體getAsString 接收和實體,并返回轉換為的對象的ID String該代碼實質上是以下代碼(省略了檢查):@ManagedBean(name="myConverter")@SessionScopedpublic class MyConverter implements Converter {    private MyService myService;    /* ... */    @Override    public Object getAsObject(FacesContext facesContext, UIComponent uiComponent, String value) {        int id = Integer.parseInt(value);        return myService.getById(id);    }    @Override    public String getAsString(FacesContext facesContext, UIComponent uiComponent, Object value) {        return ((MyEntity)value).getId().toString();    }}鑒于有大量Converter完全像這樣的s(當然MyService和類型除外MyEntity),我想知道是否值得使用單個通用轉換器。泛型本身的實現并不困難,但是我不確定聲明Bean的正確方法??赡艿慕鉀Q方案如下:1-編寫通用實現,我們稱之為MyGenericConverter,沒有任何Bean批注2-將特定的轉換器廣告編寫為的子類,MyGenericConverter<T>并根據需要對其進行注釋:@ManagedBean(name="myFooConverter")@SessionScopedpublic class MyFooConverter implements MyGenericConverter<Foo> {    /* ... */}在編寫本文時,我意識到也許并不是真的需要泛型,所以也許我可以簡單地編寫具有這兩種方法的實現的基類,并根據需要編寫子類。有一些非瑣碎的細節需要處理(例如,我必須以MyService某種方式抽象類的事實),所以我的第一個問題是:值得為之煩惱嗎?如果是這樣,還有其他方法嗎?
查看完整描述

2 回答

?
阿晨1998

TA貢獻2037條經驗 獲得超6個贊

最簡單的方法是讓您的所有JPA實體都從這樣的基本實體擴展:


public abstract class BaseEntity<T extends Number> implements Serializable {


    private static final long serialVersionUID = 1L;


    public abstract T getId();


    public abstract void setId(T id);


    @Override

    public int hashCode() {

        return (getId() != null) 

            ? (getClass().getSimpleName().hashCode() + getId().hashCode())

            : super.hashCode();

    }


    @Override

    public boolean equals(Object other) {

        return (other != null && getId() != null

                && other.getClass().isAssignableFrom(getClass()) 

                && getClass().isAssignableFrom(other.getClass())) 

            ? getId().equals(((BaseEntity<?>) other).getId())

            : (other == this);

    }


    @Override

    public String toString() {

        return String.format("%s[id=%d]", getClass().getSimpleName(), getId());

    }


}

請注意,擁有一個適當的equals()(和hashCode())很重要,否則您將面臨“ 驗證錯誤:值無效”。該Class#isAssignableFrom()測試是避免如Hibernate基于代理失敗的測試,而不需要回落到休眠特定Hibernate#getClass(Object)的輔助方法。


并擁有這樣的基礎服務(是的,我忽略了您使用Spring的事實;這只是給出基本思想):


@Stateless

public class BaseService {


    @PersistenceContext

    private EntityManager em;


    public BaseEntity<? extends Number> find(Class<BaseEntity<? extends Number>> type, Number id) {

        return em.find(type, id);

    }


}

并實現轉換器如下:


@ManagedBean

@ApplicationScoped

@SuppressWarnings({ "rawtypes", "unchecked" }) // We don't care about BaseEntity's actual type here.

public class BaseEntityConverter implements Converter {


    @EJB

    private BaseService baseService;


    @Override

    public String getAsString(FacesContext context, UIComponent component, Object value) {

        if (value == null) {

            return "";

        }


        if (modelValue instanceof BaseEntity) {

            Number id = ((BaseEntity) modelValue).getId();

            return (id != null) ? id.toString() : null;

        } else {

            throw new ConverterException(new FacesMessage(String.format("%s is not a valid User", modelValue)), e);

        }

    }


    @Override

    public Object getAsObject(FacesContext context, UIComponent component, String value) {

        if (value == null || value.isEmpty()) {

            return null;

        }


        try {

            Class<?> type = component.getValueExpression("value").getType(context.getELContext());

            return baseService.find((Class<BaseEntity<? extends Number>>) type, Long.valueOf(submittedValue));

        } catch (NumberFormatException e) {

            throw new ConverterException(new FacesMessage(String.format("%s is not a valid ID of BaseEntity", submittedValue)), e);

        }

    }


}

請注意,它被注冊為@ManagedBean而不是@FacesConverter。這個技巧可以讓您通過例如在轉換器中注入服務@EJB。另請參見如何在@FacesConverter中注入@ EJB,@ PersistenceContext,@ Inject,@ Autowired等?因此,您需要引用converter="#{baseEntityConverter}"而不是converter="baseEntityConverter"。


如果您碰巧將此類轉換器更多地用于UISelectOne/ UISelectMany組件(<h:selectOneMenu>和朋友),您可能會發現OmniFaces SelectItemsConverter更加有用。它基于可用的值進行轉換,<f:selectItems>而不是每次都進行(可能很昂貴)DB調用。


查看完整回答
反對 回復 2019-12-04
  • 2 回答
  • 0 關注
  • 3046 瀏覽
慕課專欄
更多

添加回答

舉報

0/150
提交
取消
微信客服

購課補貼
聯系客服咨詢優惠詳情

幫助反饋 APP下載

慕課網APP
您的移動學習伙伴

公眾號

掃描二維碼
關注慕課網微信公眾號