3

我对 JSF 和 primefaces 有点陌生,我遇到了一个非常烦人的问题。

我正在制作一个非常基本的应用程序来了解更多关于 primefaces 的信息。我有一个简单的表单,它有几个文本输入字段、两个日期选择器和一个下拉菜单(selectOneMenu)。

一切正常,当我提交表单时,所有值都放在支持 bean 中,下拉菜单中的值除外。该项目的设置器永远不会被调用。并且应用程序不会调用public void saveNewActivity(ActionEvent evt)命令按钮上定义的控制器上的方法。但是,当我在 html 中删除或注释掉下拉菜单时,它确实调用了该方法(但下拉菜单的字段显然是null)。

我已经尝试了将近两天,但仍然无法使其正常工作。

我有以下代码(片段):

我的 html/jsf 代码

<div id="newActivitycontent">
            <h:form id="newActivityForm">
                <h:messages id="messages"/>
                <table>
                    <tr>
                        <td>Gebruiker:</td>
                        <td><p:selectOneMenu value="#{plannedActivityController.newActivity.organiser}}"
                                             converter="#{userConverter}">
                            <f:selectItem itemLabel="Kies een gebruiker" itemValue=""/>
                            <f:selectItems value="#{plannedActivityController.users}" var="user"
                                           itemLabel="#{user.firstname} #{user.lastname}" itemValue="#{user}"/>
                        </p:selectOneMenu></td>
                    </tr>
                    <tr>
                        <td>Titel:</td>
                        <td><p:inputText value="#{plannedActivityController.newActivity.name}"/></td>
                    </tr>
                    <tr>
                        <td>Beschrijving:</td>
                        <td><p:inputText value="#{plannedActivityController.newActivity.desctription}"/></td>
                    </tr>
                    <tr>
                        <td>Startdatum:</td>
                        <td><p:calendar value="#{plannedActivityController.newActivity.startDateDate}"/></td>
                    </tr>
                    <tr>
                        <td>Einddatum:</td>
                        <td><p:calendar value="#{plannedActivityController.newActivity.endDateDate}"/></td>
                    </tr>
                </table>
                <p:commandButton id="btnSaveNewActivity" value="Opslaan"
                                 actionListener="#{plannedActivityController.saveNewActivity}"
                                 update=":overviewForm:activityTable messages"/>
                <p:commandButton id="btnCancelNewActivity" value="Annuleren"
                                 actionListener="#{plannedActivityController.cancelNewActivity}" onclick="hideAddNewUI()"
                                 update=":overviewForm:activityTable" type="reset" immediate="true"/>
            </h:form>
        </div>

该代码使用的控制器:

@Named
@SessionScoped
public class PlannedActivityController implements Serializable {

    @Inject
    private ApplicationModel appModel;

    @Inject
    private SessionModel sessionModel;

    @Inject
    private ActivityMapper activityMapper;

    @Inject
    private UserMapper userMapper;

    private ActivityBean newActivity;

    private ActivityBean selectedActivity;

    private List<ActivityBean> activities;

    private List<UserBean> users;

    public PlannedActivityController() {
    }

    @PostConstruct
    public void onCreated() {
        convertActivities();
        onNewActivity();

        users = userMapper.mapToValueObjects(appModel.getUsers());
    }

    public void convertActivities() {
        List<PlannedActivity> originalActivities = appModel.getActivities();
        this.activities = activityMapper.mapToValueObjects(originalActivities);
    }

    public void onRowEditComplete(RowEditEvent event) {
        System.out.println("row edited : " + event.getObject());
        //TODO: save changes back to db!
    }

    public void onRowSelectionMade(SelectEvent event) {
        System.out.println("row selected : " + event.getObject());
        selectedActivity = (ActivityBean)event.getObject();
    }

    //Activity crud methods
    public void onNewActivity() {
        newActivity = new ActivityBean();
        newActivity.setId(new Date().getTime());
    }

    public void saveNewActivity(ActionEvent evt) {
        PlannedActivity newAct = activityMapper.mapToEntity(newActivity);
        if(newAct != null) {
            appModel.getActivities().add(newAct);
        }
        convertActivities();
    }

    public void cancelNewActivity() {
        //TODO: cleanup.
    }

    public void deleteSelectedActivity() {
        if(selectedActivity != null) {
            activities.remove(selectedActivity);
            appModel.setActivities(activityMapper.mapToEntities(activities));
            convertActivities();
        } else {
            //TODO: show error or information dialog, that delete cannot be done when nothing has been selected!
        }
    }

    //Getters & Setters
    public ApplicationModel getAppModel() {
        return appModel;
    }

    public void setAppModel(ApplicationModel appModel) {
        this.appModel = appModel;
    }

    public SessionModel getSessionModel() {
        return sessionModel;
    }

    public void setSessionModel(SessionModel sessionModel) {
        this.sessionModel = sessionModel;
    }

    public ActivityMapper getActivityMapper() {
        return activityMapper;
    }

    public void setActivityMapper(ActivityMapper activityMapper) {
        this.activityMapper = activityMapper;
    }

    public UserMapper getUserMapper() {
        return userMapper;
    }

    public void setUserMapper(UserMapper userMapper) {
        this.userMapper = userMapper;
    }

    public ActivityBean getNewActivity() {
        return newActivity;
    }

    public void setNewActivity(ActivityBean newActivity) {
        this.newActivity = newActivity;
    }

    public ActivityBean getSelectedActivity() {
        return selectedActivity;
    }

    public void setSelectedActivity(ActivityBean selectedActivity) {
        this.selectedActivity = selectedActivity;
    }

    public List<ActivityBean> getActivities() {
        return activities;
    }

    public void setActivities(List<ActivityBean> activities) {
        this.activities = activities;
    }

    public List<UserBean> getUsers() {
        return users;
    }

    public void setUsers(List<UserBean> users) {
        this.users = users;
    }
}

我的活动豆:

public class ActivityBean implements Serializable {

    private Long id = 0L;

    private String name;

    private String desctription;

    private UserBean organiser;

    private Calendar startDate;

    private Calendar endDate;

    public Long getId() {
        return id;
    }

    public void setId(Long id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getDesctription() {
        return desctription;
    }

    public void setDesctription(String desctription) {
        this.desctription = desctription;
    }

    public UserBean getOrganiser() {
        return organiser;
    }

    public void setOrganiser(UserBean organiser) {
        this.organiser = organiser;
    }

    public Calendar getStartDate() {
        return startDate;
    }

    public void setStartDate(Calendar startDate) {
        this.startDate = startDate;
    }

    public Date getStartDateDate() {
        if(this.startDate == null) {
            return null;
        }
        return this.endDate.getTime();
    }

    public void setStartDateDate(Date startDate) {
        if(this.startDate == null) {
            this.startDate = new GregorianCalendar();
        }
        this.startDate.setTime(startDate);
    }

    public String getStartDateString() {
        if(this.startDate == null) {
            return null;
        }
        return startDate.get(Calendar.DAY_OF_MONTH) + "/" + startDate.get(Calendar.MONTH) + "/" + startDate.get(Calendar.YEAR) + "";
    }

    public Calendar getEndDate() {
        return endDate;
    }

    public void setEndDate(Calendar endDate) {
        this.endDate = endDate;
    }

    public Date getEndDateDate() {
        if(this.endDate == null) {
            return null;
        }
        return endDate.getTime();
    }

    public void setEndDateDate(Date endDate) {
        if(this.endDate == null) {
            this.endDate = new GregorianCalendar();
        }
        this.endDate.setTime(endDate);
    }

    public String getEndDateString() {
        if(this.endDate == null) {
            return null;
        }
        return endDate.get(Calendar.DAY_OF_MONTH) + "/" + endDate.get(Calendar.MONTH) + "/" + endDate.get(Calendar.YEAR) + "";
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;

        ActivityBean that = (ActivityBean) o;

        if (id != null ? !id.equals(that.id) : that.id != null) return false;

        return true;
    }

    @Override
    public int hashCode() {
        return id != null ? id.hashCode() : 0;
    }
}

我的用户bean:

public class UserBean {

    private Long id;

    private String username;

    private String firstname;

    private String lastname;

    private String email;

    private String phone;

    public Long getId() {
        return id;
    }

    public void setId(Long id) {
        this.id = id;
    }

    public String getUsername() {
        return username;
    }

    public void setUsername(String username) {
        this.username = username;
    }

    public String getFirstname() {
        return firstname;
    }

    public void setFirstname(String firstname) {
        this.firstname = firstname;
    }

    public String getLastname() {
        return lastname;
    }

    public void setLastname(String lastname) {
        this.lastname = lastname;
    }

    public String getEmail() {
        return email;
    }

    public void setEmail(String email) {
        this.email = email;
    }

    public String getPhone() {
        return phone;
    }

    public void setPhone(String phone) {
        this.phone = phone;
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;

        UserBean userBean = (UserBean) o;

        if (id != null ? !id.equals(userBean.id) : userBean.id != null) return false;

        return true;
    }

    @Override
    public int hashCode() {
        return id != null ? id.hashCode() : 0;
    }
}

以及 selectOneMenu 使用的转换器:

@Named
public class userConverter implements Converter{

    @Inject
    private PlannedActivityController activityController;

    @Override
    public Object getAsObject(FacesContext facesContext, UIComponent uiComponent, String s) {
        for (UserBean user : activityController.getUsers()) {
            if(user.getId().toString().equals(s)) {
                return user;
            }
        }
        return null;
    }

    @Override
    public String getAsString(FacesContext facesContext, UIComponent uiComponent, Object o) {
        if(o instanceof UserBean) {
            UserBean user = (UserBean)o;
            return user.getId().toString();
        }
        return "";
    }
}
4

1 回答 1

1

问题就在这里。仔细看。这是无效的 EL 语法。

value="#{plannedActivityController.newActivity.organiser}}"

然而,这应该会PropertyNotWritableException在提交时引发类似这样的事情:

javax.el.PropertyNotWritableException: /test.xhtml @25,39 value="#{plannedActivityController.newActivity.organiser}}": Illegal Syntax for Set Operation
    at com.sun.faces.facelets.el.TagValueExpression.setValue(TagValueExpression.java:136)
    at javax.faces.component.UIInput.updateModel(UIInput.java:822)
    at javax.faces.component.UIInput.processUpdates(UIInput.java:739)
    at javax.faces.component.UIForm.processUpdates(UIForm.java:281)
    at javax.faces.component.UIComponentBase.processUpdates(UIComponentBase.java:1244)
    at javax.faces.component.UIComponentBase.processUpdates(UIComponentBase.java:1244)
    at javax.faces.component.UIViewRoot.processUpdates(UIViewRoot.java:1223)
    at com.sun.faces.lifecycle.UpdateModelValuesPhase.execute(UpdateModelValuesPhase.java:78)
    at com.sun.faces.lifecycle.Phase.doPhase(Phase.java:101)
    at com.sun.faces.lifecycle.LifecycleImpl.execute(LifecycleImpl.java:118)
    at javax.faces.webapp.FacesServlet.service(FacesServlet.java:593)

此异常应该已记录到服务器日志中。然而,默认情况下,这不会最终出现在最终用户的错误页面中,因为 JSF/PrimeFaces 默认情况下没有任何形式的反馈给最终用户,以防在 ajax 请求期间抛出异常。但是,您应该能够在 webbrowser 的内置 HTTP 流量监视器中的实际 ajax 响应正文中看到它。

JSF 实用程序库OmniFacesFullAjaxExceptionHandler为ajax 请求期间完全没有异常反馈的问题提供了一个解决方案。您可能会发现它很有用。当我尝试重新创建您的问题时,我看到了一个清晰的错误页面,因此我不需要在服务器日志或 HTTP 流量监视器中挖掘线索。

于 2013-09-19T13:22:18.793 回答