第一次在用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;
}