سؤال

كيف يمكنني كتابة محول مخصص عند العمل مع مكونات PrimeFaces التي تستخدم قائمة Pojo؟ مشكلتي الخاصة هي مع <p:pickList>

<p:pickList converter="????" value="#{bean.projects}" var="project" 
                             itemLabel="#{project.name}" itemValue="#{project}">

بدون محول أحصل عليه java.lang.ClassCastException لأن JSF يحدد القيم المقدمة مع غير محول java.lang.String القيم المقدمة.

هل كانت مفيدة؟

المحلول 2

بعد البحث حول كيفية كتابة المحول المخصص ، إليك الحل.
1. قم بإنشاء فئة Java تنفذ javax.faces.convert.Converter;

public class ProjectConverter implements Converter{

   @EJB
   DocumentSBean sBean;

   public ProjectConverter(){
   }

   public Object getAsObject(FacesContext context, UIComponent component, String value){
     return sBean.getProjectById(value);
     //If u look below, I convert the object into a unique string, which is its id.
     //Therefore, I just need to write a method that query the object back from the 
     //database if given a id. getProjectById, is a method inside my Session Bean that
     //does what I just described
   }

   public String getAsString(FacesContext context, UIComponent component, Object value)     
   {
     return ((Project) value).getId().toString(); //--> convert to a unique string.
   }
}

2. قم بتسجيل محولك المخصص في faces-config.xml

<converter>
    <converter-id>projectConverter</converter-id>
    <converter-class>org.xdrawing.converter.ProjectConverter</converter-class>
</converter>

3. حتى الآن داخل مكون Primefaces ، أنت فقط تفعل converter="projectConverter". لاحظ أن projectConverter هل <convert-id> لقد خلقت للتو. حتى لحل مشكلتي أعلاه ، أفعل هذا:

<p:pickList converter="projectConverter" value="#{bean.projects}" var="project" 
                            itemLabel="#{project.name}" itemValue="#{project}">

نصائح أخرى

من الممكن ، مع الوصول إلى قاعدة البيانات الأخرى ، لكنني لا أعرف أفضل طريقة. أستخدم محولًا محددًا للغاية ، ويعمل فقط في قائمة الاختيار. جرب هذا:

@FacesConverter(value = "primeFacesPickListConverter")public class PrimeFacesPickListConverter implements Converter {
@Override
public Object getAsObject(FacesContext arg0, UIComponent arg1, String arg2) {
    Object ret = null;
    if (arg1 instanceof PickList) {
        Object dualList = ((PickList) arg1).getValue();
        DualListModel dl = (DualListModel) dualList;
        for (Object o : dl.getSource()) {
            String id = "" + ((Project) o).getId();
            if (arg2.equals(id)) {
                ret = o;
                break;
            }
        }
        if (ret == null)
            for (Object o : dl.getTarget()) {
                String id = "" + ((Project) o).getId();
                if (arg2.equals(id)) {
                    ret = o;
                    break;
                }
            }
    }
    return ret;
}

@Override
public String getAsString(FacesContext arg0, UIComponent arg1, Object arg2) {
    String str = "";
    if (arg2 instanceof Project) {
        str = "" + ((Project) arg2).getId();
    }
    return str;
}

وقائمة الاختيار:

<p:pickList converter="primeFacesPickListConverter" value="#{bean.projects}" var="project" 
                        itemLabel="#{project.name}" itemValue="#{project}">

العمل بالنسبة لي ، التحسينات ضرورية.

نعم ، يمكنك كتابة محول يقوم بتسلسل/تخلص من الكائنات في قائمة الاختيار مثل هذا:

@FacesConverter(value="PositionMetricConverter")
public class PositionMetricConverter implements Converter {

    private static final Logger log = Logger.getLogger(PositionMetricConverter.class.getName());

    @Override
    public Object getAsObject(FacesContext facesContext, UIComponent uiComponent, String value) {
        try {
            byte[] data = Base64.decodeBase64(value);
            ObjectInputStream ois = new ObjectInputStream(new ByteArrayInputStream(data));
            Object o = ois.readObject();
            ois.close();
            return o;
        } catch (Exception e) {
            log.log(Level.SEVERE, "Unable to decode PositionMetric!", e);
            return null;
        }
    }

    @Override
    public String getAsString(FacesContext facesContext, UIComponent uiComponent, Object value) {
        try {
            ByteArrayOutputStream baos = new ByteArrayOutputStream();
            ObjectOutputStream oos = new ObjectOutputStream(baos);
            oos.writeObject(value);
            oos.close();

            return Base64.encodeBase64String(baos.toByteArray());
        } catch (IOException e) {
            log.log(Level.SEVERE, "Unable to encode PositionMetric!", e);
            return "";
        }
    }

}

ثم قم بتطبيق هذا المحول على قائمة الاختيار مثل هذا:

<p:pickList converter="PositionMetricConverter" value="#{bean.positionMetrics}" 
    var="positionMetric" itemLabel="#{positionMetric.name}" itemValue="#{positionMetric}"/>

وتأكد من أن الأشياء الخاصة بك قابلة للتسلسل.

هذه المشكلة ليست ذات صلة PrimeFaces ، فقط General JSF ذات الصلة.

لماذا يجب أن تضغط على قاعدة البيانات مرة أخرى؟ تحتوي الفاصوليا بالفعل على قائمة الكائنات التي تريد عرضها في مكون ، أم أنها تطلب تحديد النطاق؟

  • قم بإنشاء فئة فائقة لاتحادات السبات التي تحتوي على حقل هوية. إذا كنت لا ترغب في إنشاء فئة فائقة ، فما عليك سوى استخدام فئة PoJo ، ولكنك تحتاج إلى المزيد من فئات المحول.
  • مع هذه الفئة الفائقة ، يمكنك إنشاء محول عام لجميع فئات PoJO التي تحتوي على قائمة من Pojo التي تم تمريرها في المنشئ.
  • أضف المحول كخاصية في حبة الجلسة واستخدم هذا المحول في مكون JSF الخاص بك.

إذا قمت بالوصول إلى القائمة النهائية عبر خاصية GET في الفاصوليا أو التداخل في المحول ، فهو من اختيارك.

public class SuperPojo
{
    protected Integer id;
    //constructor & getter
}

public class PojoTest extends SuperPojo 
{
    private String label = null;    
    //constructor & getter
}

public class SuperPojoConverter<T extends SuperPojo> implements Converter
{
    private Collection<T> superPojos;

    public IdEntityConverter(Collection<T> superPojos)
    {
        this.superPojos = superPojos;
    }

    @Override
    public Object getAsObject(FacesContext context, UIComponent component, String value)
    {
        //catch exceptions and empty or  null value!
        final int intValue = Integer.parseInt(value);
        for(SuperPojo superPojo : this.superPojos)
            if(superPojo.getId().intValue() == intValue)
                return superPojo;

        return null;
    }

    @Override
    public String getAsString(FacesContext context, UIComponent component, Object value)
    {
        //catch null and instanceof
        return String.valueOf(((SuperPojo)value).getId().intValue());
    }

    public Collection<T> getSuperPojos()
    {
        return this.superPojos;
    }
}

public class Bean 
{
    private SuperPojoConverter<PojoTest> pojoTestConverter = null;

    public Bean()
    {
        final List<PojoTest> pojoTests = //get list from hibernate
        this.pojoTestConverter = new SuperPojoConverter<PojoTest>(pojoTests);
    }

    public SuperPojoConverter<PojoTest> getPojoTestConverter()
    {
        return this.pojoTestConverter;
    }
}


<h:selectOneMenu value="#{selPojoTest}" converter="#{bean.getPojoTestConverter}">
    <f:selectItems value="#{bean.getPojoTestConverter.getSuperPojos}" var="varPojoTest" itemLabel="#{varPojoTest.label}" itemValue="#{varPojoTest}"/>
</h:selectOneMenu>

هل هناك أي طريقة لتنفيذ ذلك بدون ضربات قاعدة بيانات 2؟

أعني ، عندما يكون لديك

#{bean.projects}

هذه قاعدة بيانات.

وعندما يضع المحول

sBean.getProjectById(value);

هي قاعدة بيانات غير ضرورية ، لأن Bean.projects لديها بالفعل معرف وقيمة الكائنات

انه من الممكن:

public class DocumentSBean sBean implements Serializable{

private List<Document> projects;
// projects methods...
// ...

public Converter getDocumentConverter(){
 return docConverter;
}

private Converter docConverter = new Converter() {

        @Override
        public Object getAsObject(FacesContext context, UIComponent component, String value) {
            return projects.stream().filter(p -> p.getName().equals(value)).findFirst().orElse(null);
        }

        @Override
        public String getAsString(FacesContext context, UIComponent component, Object value) {
            return (value != null)
                    ? ((Document) value).toString()
                    : null;
        }
    };
}
<p:pickList converter="#{sBean.documentConverter}" value="#...
مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top