如何防止多个复合组件在JSF页面上自行重置? [英] How to prevent multiple composite components reset themselves on a JSF page?

查看:58
本文介绍了如何防止多个复合组件在JSF页面上自行重置?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我将这个问题放在一个简单的示例中,它是一个复合组件,可以计算2个输入的总和并将结果打印在outputText中

I put this problem in a simple example, a composite component that calculates the sum of 2 inputs and prints the result in an outputText

JSF主页:

<html xmlns="http://www.w3.org/1999/xhtml" xmlns:h="http://java.sun.com/jsf/html" xmlns:ez="http://java.sun.com/jsf/composite/ezcomp/">
    <h:head></h:head>
    <h:body>
      <ez:Calculator />
      <br/>
      <br/>
      <ez:Calculator />
      <br/>
      <br/>
      <ez:Calculator />
    </h:body>
</html>

复合组件XHTML:

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
  "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml"
  xmlns:composite="http://java.sun.com/jsf/composite"
  xmlns:h="http://java.sun.com/jsf/html">
    <h:head>
        <title>This content will not be displayed</title>
    </h:head>
    <h:body>
    <composite:interface componentType="calculator">
    </composite:interface>

    <composite:implementation>
      <h:form>
      <h:inputText id="first" value="#{cc.firstNumber}" /> 
      <h:commandButton value="+" action="#{cc.sum}"/>
      <h:inputText id="second" value="#{cc.secondNumber}" /> 
      </h:form>
      <h:outputText id="result" value="#{cc.result}" />
  </composite:implementation>

</h:body>
</html>

复合组件支持bean:

Composite component backing bean:

package ez;


import javax.faces.component.FacesComponent;
import javax.faces.component.UINamingContainer;

@FacesComponent("calculator")
public class Calculator extends UINamingContainer  {

    private Long firstNumber;
    private Long secondNumber;
    private Long result;

    public Calculator() {
    }

    @Override
    public String getFamily() { 
      return "javax.faces.NamingContainer"; 
    }

    public void setFirstNumber(String firstNumber) {
      this.firstNumber = Long.parseLong(firstNumber);
    }

    public String getFirstNumber() {
      if(firstNumber == null) {
        return null;
      }
      return firstNumber.toString();
    }

    public void setSecondNumber(String secondNumber) {
      this.secondNumber = Long.parseLong(secondNumber);
    }

    public String getSecondNumber() {
      if(secondNumber == null) {
        return null;
      }
      return secondNumber.toString();
    }

    public String getResult() {
      if(result == null) {
        return null;
      }
      return result.toString();
    }

    public void setResult(String result) {
      this.result = Long.parseLong(result);
    }     

    public void sum() {
      this.result = this.firstNumber + this.secondNumber;
    }
}

因此,我有3个复合组件,它们都应做相同的事情,但是当我按SUM按钮时,服务器处理请求后,结果将打印在页面上,但其他2个组件被清除了.他们的价值观.

So, I have 3 Composite Components that all should do the same thing, but when I press a SUM button, after the server processes the request, the result is printed out on the page, but the other 2 components are cleared of their values.

如何防止这种情况?我如何强制它保留这些值?

How can I prevent this? How can I force it to retain those values?

推荐答案

UIComponent实例,从而每次都丢失所有实例变量.它们基本上像请求作用域的受管Bean一样,而您打算将它们放在视图作用域中.您需要在每个属性的基础上考虑视图状态保存.默认情况下,通常对于#{cc.attrs}的所有属性都已完成此操作.因此,如果可以的话,请充分利用它:

UIComponent instances are recreated on every request, hereby losing all instance variables everytime. They basically act like request scoped managed beans, while you intend to have them in the view scope. You need to take view state saving into account on a per-attribute basis. This is normally by default already done for all attributes of #{cc.attrs}. So, if you can, just make use of it:

<cc:interface componentType="calculator">
    <cc:attribute name="firstNumber" type="java.lang.Long" />
    <cc:attribute name="secondNumber" type="java.lang.Long" />
</cc:interface>
<cc:implementation>
    <h:form>
        <h:inputText id="first" value="#{cc.attrs.firstNumber}" /> 
        <h:commandButton value="+" action="#{cc.sum}"/>
        <h:inputText id="second" value="#{cc.attrs.secondNumber}" /> 
    </h:form>
    <h:outputText id="result" value="#{cc.attrs.result}" />
</cc:implementation>

仅此一项(忽略空检查;我建议在输入中使用required="true")

with just this (nullchecks omitted; I recommend to make use of required="true" on the inputs)

@FacesComponent("calculator")
public class Calculator extends UINamingContainer {

    public void sum() {
        Long firstNumber = (Long) getAttributes().get("firstNumber");
        Long secondNumber = (Long) getAttributes().get("secondNumber");
        getAttributes().put("result", firstNumber + secondNumber);
    }

}

否则,您必须通过将所有属性获取器/设置器委派给

Otherwise, you'd have to take state saving into account yourself by delegating all attribute getters/setters to UIComponent#getStateHelper(). Based on the very same Facelets code as you have, the entire backing component would look like this:

@FacesComponent("calculator")
public class Calculator extends UINamingContainer {

    public void sum() {
        setResult(getFirstNumber() + getSecondNumber());
    }

    public void setFirstNumber(Long firstNumber) {
        getStateHelper().put("firstNumber", firstNumber);
    }

    public Long getFirstNumber() {
        return (Long) getStateHelper().eval("firstNumber");
    }

    public void setSecondNumber(Long secondNumber) {
        getStateHelper().put("secondNumber", secondNumber);
    }

    public Long getSecondNumber() {
        return (Long) getStateHelper().eval("secondNumber");
    }

    public void setResult(Long result) {
        getStateHelper().put("result", result);
    }

    public Long getResult() {
        return (Long) getStateHelper().eval("result");
    }

}

请参阅,不再有局部变量.请注意,通过声明正确的getter返回类型和setter参数类型,我也消除了对那些丑陋的手动String-Long转换的需要. JSF/EL将根据默认转换器或自定义Converter自动进行转换.由于Long已存在默认值,因此您无需提供自定义Converter.

See, no local variables anymore. Note that I also removed the need for those ugly manual String-Long conversions by just declaring the right getter return type and setter argument type. JSF/EL will do the conversion automagically based on default converters or custom Converters. As there's already a default one for Long, you don't need to provide a custom Converter.

无关与具体问题无关,您可以安全地删除getFamily()方法. UINamingContainer已经完全提供了此功能.如果要实现NamingContainer接口,则确实需要自己提供它,但是这里不是这种情况.上面的支持组件示例已将其删除.

Unrelated to the concrete problem, you can safely remove the getFamily() method. The UINamingContainer already provides exactly this. If you were implementing NamingContainer interface instead, then you'd indeed need to provide it yourself, but this is thus not the case here. The above backing component examples have it already removed.

这篇关于如何防止多个复合组件在JSF页面上自行重置?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆