JSF CDI会话范围

时间:2016-07-12 13:20:52

标签: jsf cdi

我的CDI范围有问题。

我有一个带有会话作用域的bean,ClientController,我有客户端和电话对象来推送服务订单。当我注册一个新客户端时,我可以将一个或多个电话推送到该客户端。为此,我使用了会话范围。但是,将新手机推送到我的客户端的每个请求都在执行@PostContruct方法,使bean失去状态,即使我在推送第一部手机时开始对话。

首先,我猜问题是bean配置,但是当我删除在客户端页面上声明的模板时,应用程序工作正常。此模板使用具有会话范围的bean,以通过用户选择来控制页面语言。

接下来有我的代码,您可以通过此链接https://github.com/mcqueide/service-order在github存储库上关注我的代码。

ClientController.java

package br.com.codeshare.controller;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

import javax.annotation.PostConstruct;
import javax.enterprise.context.Conversation;
import javax.enterprise.context.ConversationScoped;
import javax.enterprise.inject.Produces;
import javax.faces.application.FacesMessage;
import javax.faces.context.FacesContext;
import javax.inject.Inject;
import javax.inject.Named;

import br.com.codeshare.enums.ErrorCode;
import br.com.codeshare.exception.BusinessException;
import br.com.codeshare.model.Client;
import br.com.codeshare.model.Phone;
import br.com.codeshare.qualifiers.SessionMap;
import br.com.codeshare.service.ClientService;
import br.com.codeshare.service.PhoneService;
import br.com.codeshare.util.WebResources;

@Named
@ConversationScoped
public class ClientController implements Serializable {

    private static final long serialVersionUID = 1L;

    @Inject
    private FacesContext facesContext;
    @Inject @SessionMap
    private Map<String, Object> sessionMap;
    @Inject
    private ClientService clientService;

    private Client newClient;

    @Inject
    private PhoneController phoneController;
    @Inject
    private PhoneService phoneService;

    @Inject
    private Conversation conversation;

    private String filterName;

    private List<Client> listClients;

    private Client clientSelected;
    private List<Phone> phoneToBeRemove;

    @Produces
    @Named
    public Client getNewClient() {
        return newClient;
    }

    @PostConstruct
    public void initNewClient() {
        newClient = new Client();
        newClient.setTelefones(new ArrayList<Phone>());
        listClients = clientService.findAll();
    }

    public String save() throws Exception {
        try {
            validatePhoneLeastOnePhoneObligatory(newClient);

            clientService.save(newClient);
            facesContext.addMessage(null, new FacesMessage(FacesMessage.SEVERITY_INFO, WebResources.getMessage("register"),WebResources.getMessage("sucess_register")));
            initNewClient();
        }catch (BusinessException e) {
            FacesMessage m = new FacesMessage(FacesMessage.SEVERITY_ERROR,WebResources.getMessage(e.getErrorCode()),"");
            facesContext.addMessage(null, m);
        }catch (Exception e) {
            String errorMessage = getRootErrorMessage(e);
            FacesMessage m = new FacesMessage(FacesMessage.SEVERITY_ERROR,errorMessage,WebResources.getMessage("unsuccessful"));
            facesContext.addMessage(null, m);
        }
        if(!conversation.isTransient()){
            conversation.end();
        }
        return null;
    }

    public String update(Client client) throws Exception{
        try {
            validatePhoneLeastOnePhoneObligatory(client);

            clientService.update(client,phoneToBeRemove);
            facesContext.addMessage(null, new FacesMessage(FacesMessage.SEVERITY_INFO,  WebResources.getMessage("register"),WebResources.getMessage("sucess_register")));
            initNewClient();
        }catch (BusinessException e) {
            FacesMessage m = new FacesMessage(FacesMessage.SEVERITY_ERROR,WebResources.getMessage(e.getErrorCode()),"");
            facesContext.addMessage(null, m);
            return null;
        } catch (Exception e) {
            String errorMessage = getRootErrorMessage(e);
            FacesMessage m = new FacesMessage(FacesMessage.SEVERITY_ERROR, errorMessage, WebResources.getMessage("unsuccessful"));
            facesContext.addMessage(null, m);
            return null;
        }
        if(!conversation.isTransient()){
            conversation.end();
        }
        return "clients";
    }

    private void validatePhoneLeastOnePhoneObligatory(Client client) throws BusinessException {
        if(client.getHomePhone().isEmpty() && client.getBisenessPhone().isEmpty()){
            throw new BusinessException(ErrorCode.LEAST_ONE_PHONE_OBLIGATORY.getErrorCode());
        }
    }

    private String getRootErrorMessage(Exception e) {
        String errorMessage = "Registration failed. See server log for more information";
        if (e == null) {
            return errorMessage;
        }

        Throwable t = e;
        while (t != null) {
            errorMessage = t.getLocalizedMessage();
            t = t.getCause();
        }
        return errorMessage;
    }

    public void addClientPhone() {
        if(conversation.isTransient()){
            conversation.begin();
        }

        phoneController.getNewPhone().setClient(newClient);
        if (newClient.getPhones() == null) {
            newClient.setTelefones(new ArrayList<Phone>());
        }
        newClient.getPhones().add(phoneController.getNewPhone());
        phoneController.initNewPhone();
    }

    public void removeClientPhone(Phone phone){
        if(conversation.isTransient()){
            conversation.begin();
        }

        clientSelected.getPhones().remove(phone);
        if(phoneToBeRemove == null){
            phoneToBeRemove = new ArrayList<Phone>();
        }
        phoneToBeRemove.add(phone);
    }

    public void addClientPhoneOnUpdate() {
        if(conversation.isTransient()){
            conversation.begin();
        }

        phoneController.getNewPhone().setClient(clientSelected);
        if (clientSelected.getPhones() == null) {
            clientSelected.setTelefones(new ArrayList<Phone>());
        }
        clientSelected.getPhones().add(phoneController.getNewPhone());
        phoneController.initNewPhone();
    }

    public void searchByName() {
        listClients = null;
        if(filterName == null){
            listClients = clientService.findAll();
        }
        listClients = clientService.findByName(filterName);
    }

    public String edit(Client client) {
        if(conversation.isTransient()){
            conversation.begin();
        }
        this.clientSelected = client;
        List<Phone> phoneList = phoneService.findPhoneByClientId(clientSelected.getId());
        clientSelected.setTelefones(phoneList);
        sessionMap.put("client", client);
        return "update_client";
    }

    public Client getClientSelected() {
        return (Client) sessionMap.get("client");
    }

    public String getFilterName() {
        return filterName;
    }

    public void setFilterName(String filterName) {
        this.filterName = filterName;
    }

    public List<Client> getListClients() {
        return listClients;
    }

}

Language.java

package br.com.codeshare.util;

import java.io.Serializable;
import java.util.Locale;

import javax.annotation.PostConstruct;
import javax.enterprise.context.SessionScoped;
import javax.faces.context.FacesContext;
import javax.inject.Inject;
import javax.inject.Named;

@Named
@SessionScoped
public class Language implements Serializable {

    private static final long serialVersionUID = 1L;

    @Inject
    private FacesContext facesContext;

    @PostConstruct
    public void init(){
        localeCode = "pt";
        countryLocaleCodeChanged();
    }

    private String localeCode;

    public String getLocaleCode() {
        return localeCode;
    }

    public void setLocaleCode(String localeCode) {
        this.localeCode = localeCode;
    }

    // value change event listener
    public void countryLocaleCodeChanged() {
        facesContext.getViewRoot().setLocale(new Locale(localeCode));
    }
}

client.xhtml

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

<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:p="http://primefaces.org/ui"
    xmlns:ui="http://java.sun.com/jsf/facelets" template="/template.xhtml">

    <ui:define name="titulo">
        #{label['client.title']}
    </ui:define>

    <ui:define name="body">
        <h:form id="form">
            <p:messages />
            <p:fieldset legend="#{label['client.fieldset.client']}" id="client">
                <p:panelGrid columns="1" styleClass="panelGrid-semBorda">
                    <p:outputLabel for="name" value="#{label['client.name']}" />
                    <p:inputText id="name" value="#{newClient.name}" />

                    <p:outputLabel for="adress" value="#{label['client.adress']}" />
                    <p:inputText id="adress" value="#{newClient.adress}" />

                    <p:fragment rendered='#{!language.localeCode.equals("en")}'>
                        <p:panelGrid columns="1" styleClass="panelGrid-semBorda">
                            <p:outputLabel for="homePhone_pt" value="#{label['client.homePhone']}" />
                            <p:inputMask id="homePhone_pt" value="#{newClient.homePhone}" mask="(99)99999-9999"/>

                            <p:outputLabel for="bisenessPhone_pt" value="#{label['client.businessPhone']}" />
                            <p:inputMask id="bisenessPhone_pt" value="#{newClient.bisenessPhone}" mask="(99)9999-9999"/>
                        </p:panelGrid>
                    </p:fragment>

                    <p:fragment rendered='#{language.localeCode.equals("en")}'>
                        <p:panelGrid columns="1" styleClass="panelGrid-semBorda">
                            <p:outputLabel for="homePhone_en" value="#{label['client.homePhone']}" />
                            <p:inputText id="homePhone_en" value="#{newClient.homePhone}"/>

                            <p:outputLabel for="bisenessPhone_en" value="#{label['client.businessPhone']}" />
                            <p:inputText id="bisenessPhone_en" value="#{newClient.bisenessPhone}"/>
                        </p:panelGrid>
                    </p:fragment>
                </p:panelGrid>
            </p:fieldset>
            <p:fieldset legend="#{label['client.fieldset.phone']}" id="phones">
                <p:panelGrid id="phone" columns="1" styleClass="panelGrid-semBorda">
                    <p:outputLabel for="brand" value="#{label['phone.brand']}" />
                    <p:inputText id="brand" value="#{newPhone.brand}" />

                    <p:outputLabel for="model" value="#{label['phone.model']}" />
                    <p:inputText id="model" value="#{newPhone.model}" />

                    <p:outputLabel for="state" value="#{label['phone.state']}"/>
                    <p:selectOneRadio id="state" value="#{newPhone.state}">
                        <f:selectItems value="#{phoneStates}" var="p" itemValue="#{p}" itemLabel="#{label[p.label]}" />
                    </p:selectOneRadio>

                    <p:outputLabel for="esn" value="#{label['phone.esn']}" />
                    <p:inputText id="esn" value="#{newPhone.esn}" />
                </p:panelGrid>
                <p:commandButton value="#{label['phone.add']}" action="#{clientController.addClientPhone}" update="phoneTable phones"/>

                <p:dataTable value="#{newClient.phones}" var="phone" emptyMessage="#{label['phone.notadd']}"
                    id="phoneTable">
                    <p:column headerText="#{label['phone.brand']}">
                        <p:outputLabel value="#{phone.brand}"/>
                    </p:column>

                    <p:column headerText="#{label['phone.model']}">
                        <p:outputLabel value="#{phone.model}"/>
                    </p:column>
                </p:dataTable>
            </p:fieldset>
            <p:commandButton action="#{clientController.save}" value="#{label['client.save']}" update="@form"/>


        </h:form>
    </ui:define>
</ui:composition>

的template.xhtml

<?xml version="1.0" encoding="UTF-8" ?>
<!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:f="http://java.sun.com/jsf/core"
     xmlns:h="http://java.sun.com/jsf/html"
     xmlns:p="http://primefaces.org/ui"
     xmlns:ui="http://java.sun.com/jsf/facelets">
<f:view locale="#{language.localeCode}" encoding="utf-8">
<h:head>
    <title>
        <ui:insert name="title"/>
    </title>
    <link rel="stylesheet" type="text/css" href="resources/css/reset.css" />
    <link rel="stylesheet" type="text/css" href="resources/css/style.css" />
    <link rel="stylesheet" type="text/css" href="resources/css/fonts/font-awesome.min.css" />
</h:head>
<body>
    <div class="main">
        <div class="menu">
            <ui:include src="/menu.xhtml" />
        </div>  

        <div id="body">
            <ui:insert name="body"/>
        </div>
    </div>
</body>
</f:view>
</html>

名为menu.xhtml

<?xml version="1.0" encoding="UTF-8" ?>
<!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:f="http://java.sun.com/jsf/core"
     xmlns:h="http://java.sun.com/jsf/html"
     xmlns:p="http://primefaces.org/ui"
     xmlns:ui="http://java.sun.com/jsf/facelets">

    <ui:composition>
        <p:menubar>
            <p:submenu label="#{label['menu.serviceorder']}">
                <p:menuitem value="#{label['menu.serviceorder']}" url="/service-order.jsf"/>
                <p:menuitem value="#{label['menu.serviceorder.new']}" url="/new-service-order.jsf"/>
            </p:submenu>
            <p:submenu label="#{label['menu.client']}">
                <p:menuitem value="#{label['menu.client.new']}" url="/client.jsf"></p:menuitem>
                <p:menuitem value="#{label['menu.clients']}" url="/clients.jsf"></p:menuitem>
            </p:submenu>
        </p:menubar>
        <h:form class="menu_languages">
            <p:selectOneMenu value="#{language.localeCode}">
                <f:selectItem itemLabel="Português" itemValue="pt" />
                <f:selectItem itemLabel="English" itemValue="en" />
                <p:ajax listener="#{language.countryLocaleCodeChanged}" update="@all" />                        
            </p:selectOneMenu>
        </h:form>
    </ui:composition>

</html>

2 个答案:

答案 0 :(得分:0)

我非常确信您遇到了以下问题之一:

  • 会话结束
    • 尝试使用一些@PreDestroy方法来查看对话何时消失
    • 请确保您之前没有end()次对话(检查您的代码是否意味着致电save / update
  • 每次添加手机时都会创建新对话(这很可能是原因)
    • 当您希望将另一个请求与正在运行的会话相关联时,您需要使用会话ID(传播它)
    • 请注意,您可以致电conversation.getId()
    • 获取ID
    • 要验证这一点,请检查您的网址是否包含给定的会话ID
    • 还要注意,如果你每次创建一个新的对话,旧的长期对话仍然挂在那里

通过将cid(会话ID)附加到请求URL来完成会话的传播。以下是CDI spec的引用(我建议您阅读),解释会话何时自动传播:

  

如果当前的Servlet请求是JSF请求,并且会话处于长时间运行状态,则会根据以下规则传播:

     
      
  • 与呈现JSF视图的请求相关联的长时间运行的对话上下文会自动传播到源自该呈现页面的任何面部请求(JSF表单提交)。

  •   
  • 与导致JSF重定向的请求相关联的长时间运行的对话上下文(由导航规则或JSF NavigationHandler生成的重定向)会自动传播到生成的非面部请求,以及任何其他后续请求请求相同的URL。这是通过使用名为cid的请求参数来完成的,该参数包含会话的唯一标识符。

  •   

答案 1 :(得分:0)

我可以用这个来解决这个问题:

<f:metadata>
    <f:event listener="#{clientController.initConversation()}" type="preRenderView" />
</f:metadata>

现在,当我的页面呈现时,我的帖子就有了我的cid。但我不知道这是否是解决此问题的更好方法,因为我想在用户点击添加手机时长时间转换我的交易,所以如果有人有更好的想法,请分享。