调试更新moderl阶段,未调用setter

时间:2016-05-03 20:22:56

标签: jsf cdi jsf-2.2

我猜这是构建与渲染时间的问题。 我是评论部分,是评论树。一切正常......除了一些注释之外没有调用bean setter。

所以我的理解是:

  • 使用ui时:重复复合组件在构建时包含一次,然后为每个项目呈现其适当的值。它为什么不起作用?没有头绪。

  • 当使用c:forEach时,复合组件被多次集成,然后在渲染时,当要填充commandButton操作时,该项将丢失。

以下是重现错误的完整工作示例:

WorkingTest Bean

import java.io.Serializable;
import javax.faces.view.ViewScoped;
import javax.inject.Named;

@Named
@ViewScoped
public class WorkingTest implements Serializable{
    private static final long serialVersionUID = 1L;

    private Post topNode;
    private String replyContent;
    private int counter;

    public WorkingTest(){
        topNode = new Post();
        Post p1 = new Post(1, "reply here works");
        p1.getReplies().add(new Post(3, "Reply to this comment <b style=\"color:red\">doesn't works</b>, the  content of the comment is null"));
        Post p2 = new Post(1, "reply here works");
        topNode.getReplies().add(p1);
        topNode.getReplies().add(p2);
        counter = 6;

    }

    public void addReply(Post post){
        post.getReplies().add(new Post(counter, replyContent));
        replyContent = "";
        counter++;
    }

    public Post getTopNode() {
        return topNode;
    }

    public void setTopNode(Post topNode) {
        this.topNode = topNode;
    }

    public String getReplyContent() {
        return replyContent;
    }

    public void setReplyContent(String replyContent) {
        System.out.println("settting reply content");
        this.replyContent = replyContent;
    }

}

发布课程

import java.util.ArrayList;
import java.util.List;

public class Post {

    private long idpost;
    private String content;
    private List<Post> replies = new ArrayList<Post>();

    public Post(){}

    public Post(long id, String content){ 
        this.content = content; 
        this.idpost = id;
    }

    public String getContent() {
        return content;
    }
    public void setContent(String content) {
        this.content = content;
    }
    public List<Post> getReplies() {
        return replies;
    }
    public void setReplies(List<Post> replies) {
        this.replies = replies;
    }

    public long getIdpost() {
        return idpost;
    }

    public void setIdpost(long id) {
        this.idpost = id;
    }
}

Test.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:ui="http://xmlns.jcp.org/jsf/facelets"
    xmlns:h="http://xmlns.jcp.org/jsf/html"
    xmlns:f="http://xmlns.jcp.org/jsf/core"
    xmlns:c="http://java.sun.com/jsp/jstl/core">

    <h:head>
        <title>
            <ui:insert>Test</ui:insert>
        </title>

    </h:head>

    <h:body id="whole">

    Refresh your page between tries, you will see that for some comments the 

value of the comment doesn't appear.
    Because of a bug in mojarra the viewstate is lost after ajax request, that is why u gotta refresh.
    see http://balusc.omnifaces.org/2011/09/communication-in-jsf-20.html#AutomaticallyFixMissingJSFViewStateAfterAjaxRendering if you want more info
    <h:panelGroup  id="replies">
        <div class="replies">
            <ui:include src="pv.xhtml" >
                <ui:param name="node" value="#{workingTest.topNode.replies}"/>
                <ui:param name="count" value="8"/>
                <ui:param name="backgroundVar" value="0"/>
                <ui:param name="isFirst" value="true"/>     
            </ui:include> 
        </div>
    </h:panelGroup>

    </h:body>
</html>

pv.xhtml

<ui:composition xmlns="http://www.w3.org/1999/xhtml"
    xmlns:ui="http://xmlns.jcp.org/jsf/facelets"
    xmlns:h="http://xmlns.jcp.org/jsf/html"
    xmlns:f="http://xmlns.jcp.org/jsf/core"
    xmlns:p="http://primefaces.org/ui"
    xmlns:c="http://java.sun.com/jsp/jstl/core"
    xmlns:my="http://xmlns.jcp.org/jsf/composite/cc">


    <ui:repeat value="#{node}" var="forumPost">

        <div style="padding: 0.4rem; border: 1px solid grey; margin-bottom: #{isFirst ? '1rem' : '0' }">
            <h:panelGroup id="c">

                <!-- comment content -->
                <div class="replyContent">
                    <h:outputText value="#{forumPost.content}" escape="false"/>
                </div>

                <!-- reply block   -->
                <div class="replyAuthor" id="r-#{forumPost.idpost}">
                    <my:commentForm value="#{workingTest.replyContent}" actionMethod="#{workingTest.addReply(forumPost)}"/>
                </div>
                <!-- reply block end -->
            </h:panelGroup>


            <!--  Replies  -->
            <c:if test="#{count gt 0}">
                <ui:include src="pv.xhtml">
                    <ui:param name="node" value="#{forumPost.replies}"/>
                    <ui:param name="count" value="#{count-1}"/>
                    <ui:param name="backgroundVar" value="#{backgroundVar+1}" />
                    <ui:param name="isFirst" value="false" />
                </ui:include>
            </c:if>
        </div>

    </ui:repeat>

</ui:composition>

commentForm.xhtml (复合组件)

<ui:composition
    xmlns="http://www.w3.org/1999/xhtml"
    xmlns:ui="http://xmlns.jcp.org/jsf/facelets"
    xmlns:h="http://xmlns.jcp.org/jsf/html"
    xmlns:f="http://xmlns.jcp.org/jsf/core"
    xmlns:cc="http://xmlns.jcp.org/jsf/composite"
    xmlns:my="http://xmlns.jcp.org/jsf/composite/cc">

    <cc:interface>
        <cc:attribute name="value" type="java.lang.String" required="true"  />
        <cc:attribute name="actionMethod" method-signature="void action()"/>
    </cc:interface>

    <cc:implementation>

        <h:form>
            <h:inputTextarea value="#{cc.attrs.value}"/>
            <div class="replyBtn">
                <h:commandButton value="Reply" action="#{cc.attrs.actionMethod}">
                    <f:ajax execute="@form" render="replies"/>
                </h:commandButton>
            </div>
        </h:form>
    </cc:implementation>
</ui:composition>

对于有效的评论以及那些不需要http表格数据的评论。但是对于JSF生命周期,验证者不会被调用那些不工作和更新阶段的人不会调用setter:

工作

20:34:35,120 INFO  [stdout] (default task-41) START PHASE RESTORE_VIEW 1

20:34:35,228 INFO  [stdout] (default task-41) END PHASE RESTORE_VIEW 1

20:34:35,229 INFO  [stdout] (default task-41) START PHASE APPLY_REQUEST_VALUES 2

20:34:35,229 INFO  [stdout] (default task-41) before msg The form component needs to have a UIForm in its ancestry.

20:34:35,240 INFO  [stdout] (default task-41) END PHASE APPLY_REQUEST_VALUES 2

20:34:35,240 INFO  [stdout] (default task-41) START PHASE PROCESS_VALIDATIONS 3

20:34:35,240 INFO  [stdout] (default task-41) before msg The form component needs to have a UIForm in its ancestry. 

20:34:35,245 INFO  [stdout] (default task-41) DummyConverter getAsObject

20:34:35,245 INFO  [stdout] (default task-41) FieldsNotTooShort: validate

20:34:35,252 INFO  [stdout] (default task-41) END PHASE PROCESS_VALIDATIONS 3

20:34:35,252 INFO  [stdout] (default task-41) START PHASE UPDATE_MODEL_VALUES 4

20:34:35,253 INFO  [stdout] (default task-41) before msg The form component needs to have a UIForm in its ancestry.

20:34:35,257 INFO  [stdout] (default task-41) setting 5555555555555555555555

20:34:35,261 INFO  [stdout] (default task-41) END PHASE UPDATE_MODEL_VALUES 4

无效

20:39:12,312 INFO  [stdout] (default task-30) START PHASE RESTORE_VIEW 1

20:39:12,432 INFO  [stdout] (default task-30) END PHASE RESTORE_VIEW 1

20:39:12,432 INFO  [stdout] (default task-30) START PHASE APPLY_REQUEST_VALUES 2

20:39:12,432 INFO  [stdout] (default task-30) before msg The form component needs to have a UIForm in its ancestry.

20:39:12,436 INFO  [stdout] (default task-30) END PHASE APPLY_REQUEST_VALUES 2

20:39:12,436 INFO  [stdout] (default task-30) START PHASE PROCESS_VALIDATIONS 3

20:39:12,437 INFO  [stdout] (default task-30) before msg The form component needs to have a UIForm in its ancestry.

20:39:12,440 INFO  [stdout] (default task-30) END PHASE PROCESS_VALIDATIONS 3

20:39:12,441 INFO  [stdout] (default task-30) START PHASE UPDATE_MODEL_VALUES 4

20:39:12,441 INFO  [stdout] (default task-30) before msg The form component needs to have a UIForm in its ancestry.

20:39:12,444 INFO  [stdout] (default task-30) END PHASE UPDATE_MODEL_VALUES 4

lifecyclelistener:

public class LifeCycleListener implements PhaseListener {

    public PhaseId getPhaseId() {
        return PhaseId.ANY_PHASE;
    }

    public void beforePhase(PhaseEvent event) {
        System.out.println("START PHASE " + event.getPhaseId());
        List<FacesMessage> msgs = event.getFacesContext().getMessageList();
        for (FacesMessage msg : msgs) {
            System.out.println("before msg " + msg.getSummary() + " :: " + msg.getDetail());
        }
    }

    public void afterPhase(PhaseEvent event) {
        System.out.println("END PHASE " + event.getPhaseId());
    }

}

0 个答案:

没有答案