Java 会话范围意外行为

Java 会话范围意外行为,java,jsf,jakarta-ee,primefaces,Java,Jsf,Jakarta Ee,Primefaces,我有一个JSF页面,用户可以将他们的汽车输入我的数据库。表单有三个输入字段: 制造商 模型 登记 制造商和型号字段都是自动完成字段。为了完成Model字段,在提交表单之前,我需要知道用户在Manufacturer字段中选择的值。为此,我设置了一个AJAX调用来通知托管bean所选的值: <p:autoComplete id="manufacturer" minQueryLength="3" completeMethod="

我有一个JSF页面,用户可以将他们的汽车输入我的数据库。表单有三个输入字段:

  • 制造商
  • 模型
  • 登记
制造商
型号
字段都是自动完成字段。为了完成
Model
字段,在提交表单之前,我需要知道用户在
Manufacturer
字段中选择的值。为此,我设置了一个AJAX调用来通知托管bean所选的值:

<p:autoComplete id="manufacturer"
                minQueryLength="3"
                completeMethod="#{carController.complete}"
                forceSelection="true">
   <p:ajax event="itemSelect"
           listener="#{carController.manufacturerSelected}" />
</p:autoComplete>
模型的autocomplete字段和handler方法看起来大致相同,但值略有不同

为了在多个XHR请求中保留
manufacturer
值,我将bean设置为
ConversationScoped
,并以
@PostConstruct
注释方法开始对话:

@Named
@ConversationScoped
public class CarController implements Serializable {

@Inject
private Conversation conversation;

@PostConstruct
private void init() {
    conversation.begin();
}
我所期望的是,bean只为页面实例化一次,因为会话还没有结束,并在
manufacturer
字段中保留该值。然而,这并不成立,对于每个XHR请求,bean被再次实例化,导致
manufacturer
字段也是
null
。在
PostConstruct
方法中设置断点表明它实际上正在被调用,
manufacturerSelected
方法也是如此

我怀疑这与我没有手动传播会话ID有关,但文档中说,该ID应该随任何faces请求自动传播。这是真的吗?这是否意味着XHR请求不一定是faces请求


Edit:在bean中的不同位置设置断点表明每个XHR请求都有一个新bean(
conversation.getId()
不断变化),因此我显然没有正确地传播ID。如何使用p:ajax传播ID?使用EL在哪里可以获得ID?

既然您没有真正使用对话(至少在您给出的示例中没有),为什么不使用视图范围?这将完全满足您的需求,而无需分发会话id


请注意,要使@ViewScoped工作,必须将bean更改为JSF管理的bean(删除@Named)。这是由于JavaEE6中的设计缺陷/规范疏忽造成的。如果您想继续使用CDI,那么Seam 3提供了一个JavaEE6扩展来修复这个bug。

是的。这是JSF2和Primefaces一起没有传播会话id的问题。您可以尝试下面的解决方法。(这是为其他因同一问题将在这里结束的人准备的)



尽管对话可能不是解决问题的方法,但您可以通过firebug或Burproxy等工具调试实际的ajax请求,以查看真正发送的是什么。哎哟,这需要花很多时间。我阅读了有关组件绑定的内容,最后求助于,而不是将输入字段绑定到托管bean中的字符串值,将其绑定到HtmlInputText并对其执行getValue(),这似乎确实有效。无论如何谢谢你!这不是规格疏忽。JSF在CDI之前完成。它目前不适用于接缝3(接缝面)。关于它的一个有趣的线程和一个替代方案是,例如,是的,JSF在更早的时候就完成了,但是JavaEE6作为一个整体不应该仅仅是将各个规范放在一起,而是确保它们一起工作并且不冲突。另外,由于JSF完成得更早,CDI有时间以某种方式集成@ViewScope。
@Named
@ConversationScoped
public class CarController implements Serializable {

@Inject
private Conversation conversation;

@PostConstruct
private void init() {
    conversation.begin();
}
<p:autoComplete id="manufacturer"
            minQueryLength="3"
            completeMethod="#{carController.complete}"
            forceSelection="true" onchange="updateManufacturer([{name:'cid',value:'#{javax.enterprise.context.conversation.id}'}])">
</p:autoComplete>
<p:remoteCommand name="updateManufacturer" action="#{carController.manufacturerSelected}"
                                 process="manufacturer" />