JSF Validation Error: Value is not valid(值无效)JSF值转换无效的两个解决办法

时间:2020-12-30 20:03:08

第一次在用jsf框架编写物品分类的时候,用下拉列表来选取上级分类,出现了转换错误:值无效的问题。很长一段时间自己都认为是转换器的问题,其实不是。话不多说,上代码:

 

前台页面的写法:

<tr>    <td>上级目录</td>    <td><h:selectOneMenu id="category_fk"                        value="#{itemaddmanager.newItem.category.id}" converter="#{categoryConverterBean}" title="category">           <f:selectItem itemLabel="--选择分类--" />            <f:selectItems value="#{categoryManager.allCategory}" var="Category" itemValue="#{Category.id}" itemLabel="#{Category.name}"/>            </h:selectOneMenu>    </td></tr>

之前的Category的equals的写法:

public boolean equals(Object obj) {

if (this == obj) {
return true;
}

if (obj == null) {
return false;
}

if (getClass() != obj.getClass()) {
return false;
}

final Category other = (Category) obj;

if (id == null) {

if (other.id != null) {
return false;
}

} else if (!id.equals(other.id)) {
return false;
}

return true;

}

很好,你很可能就有机会遭遇seam下这个神奇的value is not valid验证问题了。到底原因何在?原因就在于seam不仅使用了jsf还使用了hibernate,而你的equals方法没有考虑到被对比的双方可能一个是实体类,另一个可能是被hibernate动态增强过的类。JSF在客户端提交表单后,会验证客户端选中的元素是否是当初服务端给他的那些元素。所以,JSF会拿经converter得到的实体与当初的集合里的实体一一调用equals方法对比,如果找不到一个在集合中的实体与提交来的一样,就报错。如果集合里的对象是hibernate 延迟加载时的一个Category,那正常的对象和这个Category对比时就可能出错。对于上面的例子,getClass() != obj.getClass() 会为真,而 other.id != null 也可能为真。怎么办?改写equals方法,如下:

更改之后的Category的equals和hashcode的写法:

@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((id == null) ? 0 : id.hashCode());
result = prime * result
+ ((name == null) ? 0 : name.hashCode());
return result;
}

@Override
public boolean equals(Object obj) {

if (this == obj) {
return true;
}

if (obj == null) {
return false;
}

if (!getClass().isAssignableFrom(obj.getClass())) {
return false;
}

final Category other = (Category) obj;

if (id == null) {

if (other.getId() != null) {
return false;
}

} else if (!id.equals(other.getId())) {
return false;
}

return true;

}

isAssignableFrom方法对子类调用时一样为真。other.getId()时,则会初始化Category,取出id的值。

还有一种更简单的方法,那就是不要让用户选择实体,而是选择实体的id,那就没这个问题了。

用id时的converter写法

@Override
public Object getAsObject(FacesContext ctx, UIComponent component, String value) throws ConverterException {

if (!value.equals("") && value != null) {
String Catname = value;
System.out.println("前台返回的实体名字" + Catname);
Category category = categoryservice.findCategoryByName(Catname);
System.out.println("查询到的实体:" + category.getId() + ",名字:" + category.getName());
int categoryid = category.getId();
return categoryid;
}
return null;
}