jsf将新请求关系bean对象传递给使用自定义标记的会话bean无效

时间:2012-03-03 03:13:06

标签: jsf request javabeans custom-tag

在我的申请中,我有城市(A)和邮政编码(B)之间的关系。

所以我有两个SelectOneMenu,其中第一个代表A,第二个代表所选A的B,它们通过ajax更新。

由于我多次使用这两个菜单,我为它们编写了一个自定义标签,通常可以正常工作,因为A和B值被分配给会话bean中的现有变量。

但是有一种情况我想将一个新的关系对象传递给我的bean,它不能使用标签组件。

我想作为参数传递给逻辑会话bean的add方法的新请求作用域AToB对象的属性A和B为空!

* 附加说明

  1. 将标记组件与现有会话bean变量一起使用。
  2. 使用标记组件添加基于请求bean的新关系对象不起作用。
  3. 所选的A始终(在第1和第2种情况下)使用ajax change事件正确传递给bean。
  4. SelectOneMenu的转换器始终有效。 (在调试模式下测试)
  5. 使用标记组件JSF从不调用setter来设置新的AToB对象的A和B,并在调试模式下进行测试。
  6. 使用jsf默认h:commandButton而不是primefaces会产生相同的错误。
  7. 完全不使用代码组件!
  8. 环境:

    Mojarra 2.14
    GlassFish 3.01

    我简化了删除构造函数和getter&的类。 setter方法。

    DTO,Pojo:

    public Class A{}
    
    public Class B{}
    
    public Class AToB
    {
        private A a;
        private B b;
    }
    

    会话Bean:

    public Class Bean
    {
        private List<A> as;
        private List<B> bs;
    
        private AConverter aConverter;
        private BConverter bConverter;
    
        //updates bs list
        public void updateBsByA(AjaxBehaviorEvent event) {}
    
        //does something with the given AToB
        public void add(AToB aToB)
    }
    

    面-config.xml中:

    <managed-bean>
        <managed-bean-name>beanLogic</managed-bean-name>
        <managed-bean-class>package.Bean</managed-bean-class>
        <managed-bean-scope>session</managed-bean-scope>
    </managed-bean>
    <managed-bean>
        <description>new AToB Object I want to add at database</description>
        <managed-bean-name>newAToB</managed-bean-name>
        <managed-bean-class>package.Bean</managed-bean-class>
        <managed-bean-scope>request</managed-bean-scope>
    </managed-bean>
    

    abSelect标记文件:

    <ui:composition
        xmlns="http://www.w3.org/1999/xhtml"
        xmlns:h="http://java.sun.com/jsf/html"
        xmlns:f="http://java.sun.com/jsf/core"
        xmlns:ui="http://java.sun.com/jsf/facelets"
        xmlns:p="http://primefaces.org/ui"
        xmlns:abcd="http://store24.de/jsf/admin">
        <h:selectOneMenu value="#{tagA}" converter="#{beanLogic.aConverter}">
            <f:selectItems value="#{beanLogic.as}"/>
            <p:ajax event="change" listener="#{beanLogic.updateBsByA}" update="selectB"/>
        </h:selectOneMenu>
            <h:selectOneMenu id="selectB" value="#{tagB}" converter="#{beanLogic.bConverter}">
            <f:selectItems value="#{beanLogic.bs}"/>
        </h:selectOneMenu>
    </ui:composition>
    

    abcd.taglib.xml

    <?xml version="1.0" encoding="UTF-8"?>
    <facelet-taglib 
        xmlns="http://java.sun.com/xml/ns/javaee"
        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-facelettaglibrary_2_0.xsd"
        version="2.0">
        <namespace>http://abcd.com/jsf</namespace>
        <tag>
            <tag-name>abSelect</tag-name>
            <source>tags/abSelect.xhtml</source>
            <attribute>
                <display-name>a</display-name>
                <name>tagA</name>
                <required>true</required>
                <type>package.A</type>
            </attribute>
            <attribute>
                <display-name>a</display-name>
                <name>tagB</name>
                <required>true</required>
                <type>package.B</type>
            </attribute>
        </tag>
    </facelet-taglib>
    

    致电网站:

    <abcd:abSelect a="#{newAToB.a} b="#{newAToB.b}"/>
    <p:commandButton value="add" action="#{beanLogic.add(newAToB)}"/>
    

    相反,在没有标记组件的情况下添加新的AToB(参见上面的#2)

    <h:selectOneMenu value="#{newAToB.a}" converter="#{beanLogic.aConverter}">
        <f:selectItems value="#{beanLogic.as}"/>
        <p:ajax event="change" listener="#{beanLogic.updateBsByA}" update="selectB"/>
    </h:selectOneMenu>
        <h:selectOneMenu id="selectB" value="#{newAToB.b}" converter="#{beanLogic.bConverter}">
        <f:selectItems value="#{beanLogic.bs}"/>
    </h:selectOneMenu>
    <p:commandButton value="add" action="#{beanLogic.add(newAToB)}"/>
    

1 个答案:

答案 0 :(得分:0)

你真的需要AToB课吗?不能private A a;和private B b;在会话范围内的bean?我发现重新创建代码的主要问题是,每次我想要使用它时,请求scooped AToB都会重新创建 - 只需将System.out.println()添加到它的构造函数中即可查看它。我不知道为什么会这样。但我会使用JSF依赖注入来执行您可能想要的操作(将AToB注入会话bean)。

您可能缺少转换器(没有转换器) - 将p:commandButton更改为h:commandButton以查看我的意思。我不知道为什么Primefaces的按钮不会抛出任何错误,但我之前已经看过了。

如果您使用string在selectMany中显示A和B,并在处理之前解码并重新创建它会更容易。

这对我有用:

的web.xml

  ...
  <!-- registering my custom tag -->
    <context-param>
        <param-name>javax.faces.FACELETS_LIBRARIES</param-name>
        <param-value>/WEB-INF/mytags.taglib.xml</param-value>
    </context-param>

mytags.taglim.xml

<?xml version="1.0" encoding="UTF-8"?>
<facelet-taglib 
    xmlns="http://java.sun.com/xml/ns/javaee"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-facelettaglibrary_2_0.xsd"
    version="2.0">
    <namespace>http://mytags.com/jsf</namespace>
    <tag>
        <tag-name>abSelect</tag-name>
        <source>tags/mytags/abselect.xhtml</source>
        <attribute>
            <display-name>a</display-name>
            <name>tagA</name>
            <required>true</required>
            <type>mytagstest.A</type>
        </attribute>
        <attribute>
            <display-name>a</display-name>
            <name>tagB</name>
            <required>true</required>
            <type>mytagstest.B</type>
        </attribute>
    </tag>
</facelet-taglib>

面-confix.xml

...
<!-- Converters -->
<converter>
    <converter-id>aConverter</converter-id>
    <converter-class>mytagstest.AConverter</converter-class>
</converter>
<converter>
    <converter-id>bConverter</converter-id>
    <converter-class>mytagstest.BConverter</converter-class>
</converter>

abselect.xml

<ui:composition
xmlns="http://www.w3.org/1999/xhtml"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:f="http://java.sun.com/jsf/core"
xmlns:ui="http://java.sun.com/jsf/facelets"
xmlns:p="http://primefaces.org/ui"
>
<h:selectOneMenu value="#{tagA}">  <!--  {aBBean.a} or {tagA} -->
    <f:converter converterId="aConverter" />
    <f:selectItems value="#{aBBean.as}"/> 
    <!--I dont know why you are tyring to update sth in  aBBean, new value from menu is used to update tagA -->
    <f:ajax event="change" listener="#{aBBean.updateBsByA}" execute="@form"/>
</h:selectOneMenu>
<h:selectOneMenu id="selectB" value="#{tagB}"> <!--  {aBBean.b} or {tagB} -->
    <f:converter converterId="bConverter" />
    <f:selectItems value="#{aBBean.bs}"/>
    <f:ajax event="change" listener="#{aBBean.updateBsByA}" execute="@form"/>
</h:selectOneMenu>

答:#{aBBean.a} B:#{aBBean.b}

请注意,如果您真的不需要AToB,则可以跳过标记中的属性,并将用户选择保存在会话bean中。这可能会更清洁。

A.java(注意equals和hashCode方法)

package mytagstest;

import java.io.Serializable;

public class A  implements Serializable{

    private String name ="";

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }



    public A() {
    }


    A(String n) {
      this.name = n;
    }

    @Override
    public String toString() {
        return "A{" + "name=" + name + '}';
    }

    @Override
    public boolean equals(Object obj) {
        if (obj == null) {
            return false;
        }
        if (getClass() != obj.getClass()) {
            return false;
        }
        final A other = (A) obj;
        if ((this.name == null) ? (other.name != null) : !this.name.equals(other.name)) {
            return false;
        }
        return true;
    }

    @Override
    public int hashCode() {
        int hash = 5;
        hash = 19 * hash + (this.name != null ? this.name.hashCode() : 0);
        return hash;
    }



}

此类的转换器(如果用h:commandButton替换p:commandButton,您将看到创建转换器修复时出现一些错误)

import javax.faces.component.UIComponent;
import javax.faces.context.FacesContext;
import javax.faces.convert.Converter;


public class AConverter implements Converter {



    public Object getAsObject(FacesContext context, UIComponent component, String value) {
        // Convert the unique String representation of an object to the actual object.
        return new A(value); //Dont need to create new
    }

    public String getAsString(FacesContext context, UIComponent component, Object value) {
        // Convert the Foo object to its unique String representation.
        return ((A) value).getName();
    }

}

B级和BConverter看起来几乎相同。

AToB.java

@ManagedBean
@RequestScoped
public class AToB implements Serializable {

    private A a;
    private B b;

    public AToB() {
        System.out.println("Creating AToB");
    }

    public A getA() {
        System.out.println("Get a");
        return a;
    }

    public void setA(A a) {
        System.out.println("set b");
        this.a = a;
    }

    public B getB() {
        System.out.println("get b");
        return b;
    }

    public void setB(B b) {
        System.out.println("set b");
        this.b = b;
    }
}

ABBEan(会话范围的bean,两种情况都有方法 - 使用AToB而不是)

   @ManagedBean
    @SessionScoped
    public class ABBean implements Serializable {

        private List<A> as = new ArrayList<A>();
        private List<B> bs = new ArrayList<B>();
        private A a;
        private B b;

        public A getA() {
            System.out.println("Get a");
            return a;
        }

        public void setA(A a) {
            System.out.println("set b");
            this.a = a;
        }

        public B getB() {
            System.out.println("get b");
            return b;
        }

        public void setB(B b) {
            System.out.println("set b");
            this.b = b;
        }

        public void updateAB() {
            System.out.println("Selected A and B are:");
            System.out.println(a + " " + b);
        }

        public ABBean() {
            System.out.println("Creating ABBean");
            A a1 = new A("a1");
            B b1 = new B("b1");
            this.a = a1;
            this.b = b1;

            as.add(a1);
            as.add(new A("a2"));
            bs.add(b1);
            bs.add(new B("b2"));
        }

        //updates bs list
        public void updateBsByA(AjaxBehaviorEvent event) {
            System.out.println("updateBsByA");
            System.out.println("Selected A and B are:");
            System.out.println(a + " " + b);
        }

        public List<A> getAs() {
            return as;
        }

        public void setAs(List<A> as) {
            this.as = as;
        }

        public List<B> getBs() {
            return bs;
        }

        public void setBs(List<B> bs) {
            this.bs = bs;
        }

        //does something with the given AToB
        public void add(AToB aToB) {
            System.out.println("AToB added! - aToB");
            System.out.println(aToB.getA() + " " + aToB.getB());

        }

        public void add(A a, B b) {
            System.out.println("AToB added! - A a, B b");
            System.out.println(a + " " + b);

        }
    }

用法:

<h:form>  
  <mt:abSelect  tagA="#{aBBean.a}" tagB="#{aBBean.b}"/>
  <p:commandButton   value="add2works" action="#{aBBean.updateAB}"/> <!-- works -->
</h:form>

  <h:form>  
  <mt:abSelect  tagA="#{aToB.a}" tagB="#{aToB.b}"/>
    <p:commandButton  value="add7" action="#{aBBean.add(aToB)}"/>
 </h:form>