Primefaces+Hibernate+JPA场景下选择已有客户时ActionListener不触发问题
问题根因
你遇到的现象是JSF组件验证阶段失败导致的,p:selectOneMenu的红色边框是验证不通过的默认样式,验证失败后流程会直接返回前端,不会进入后续的业务方法调用阶段,所以save和valueChange事件都不会触发,你看到的Validation error: value is not valid就是验证失败的明确提示。
解决方案
1. 给v_clientesgds实体重写equals()和hashCode()方法(最高概率解决问题)
JSF验证selectOneMenu提交值合法性时,会将转换器转换得到的对象,和<f:selectItems>列表里的所有itemValue做equals比对,全部匹配失败就会抛出验证错误。
你当前转换器返回的v_clientesgds是通过独立的静态Hibernate Session加载的,而lstClientesGds列表里的对象是业务层通过Spring管理的Session加载的,二者属于不同的持久化上下文,如果没有重写equals方法,默认比对的是对象内存地址,哪怕主键值完全一致也会判定为不相等。
在v_clientesgds类中添加如下代码即可:
import java.util.Objects; // 类内部添加 @Override public boolean equals(Object o) { if (this == o) return true; if (o == null || getClass() != o.getClass()) return false; v_clientesgds that = (v_clientesgds) o; return Objects.equals(getC_id(), that.getC_id()); } @Override public int hashCode() { return Objects.hash(getC_id()); }
2. 检查lstClientesGds的加载逻辑
如果你的lstClientesGds查询逻辑过滤了已经关联过EmailGds的客户,那么已经保存过的客户就不会出现在可选列表里,自然会验证失败。如果你的业务场景允许同一个客户关联多条记录,修改查询逻辑不过滤已关联客户即可;如果不允许重复关联,建议在页面添加友好的重复提示,不要直接阻断提交。
3. 修复转换器的Session使用问题
你转换器中定义的静态全局Session永远不会关闭,会导致内存泄漏和脏数据问题,建议每次调用getAsObject时从Spring上下文获取当前有效的Session,用完后及时释放。
4. 修正组件属性笔误
你贴出的p:selectOneMenu代码中value属性少写了闭合的大括号:value="#{emailGdsMB.selectedEmailGds.c_id",如果实际代码也是这个问题,补上}即可。
内容的提问来源于stack exchange,提问作者Marcos Paulo

