JSF 2.0 Внедрение управляемого компонента с другой областью действия - PullRequest
4 голосов
/ 25 июля 2011

У меня есть контроллер без состояния, который заботится об обработке форм. Это определяется как ApplicationScoped. На моей странице есть форма, связанная с компонентом поддержки, определенным как ViewScoped.

Ошибка, которую я получил, когда хочу обработать форму:

serverError: class com.sun.faces.mgbean.ManagedBeanCreationException Unable to create managed bean myController.  The following problems were found:
     - The scope of the object referenced by expression #{myFormBean}, view, is shorter than the referring managed beans (myController) scope of application

В моем виде:

       Name: <h:inputText value="#{myFormBean.name}" id="name" />
        <h:commandButton value="Save Name" action="#{myController.processForm}">
            <f:ajax render="nameResult" />
        </h:commandButton>
       Your name is <h:outputText value="#{myFormBean.name}" id="nameResult"/>

Контроллер:

@ManagedBean
@ApplicationScoped
public class MyController {
    @ManagedProperty("#{myFormBean}")
    private MyFormBean myBean;
    public void processForm() {
        System.out.println(myBean.getName());
        // Save current name in session
        FacesContext.getCurrentInstance().getExternalContext().getSessionMap().put(
                "name", myBean.getName());
    }
}

Фасоль:

@ManagedBean
@ViewScoped
public class MyFormBean {
    private String name;
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
}

Я мог бы решить эту проблему, установив контроллер в качестве SessionScoped, но это не чистый способ, поскольку контроллер не имеет состояния, поэтому мне не нужен один контроллер для каждой сессии. Достаточно одного контроллера для всего приложения.

У меня есть опыт работы с Spring MVC, поэтому я не совсем понимаю, как работать с JSF 2.0

Ответы [ 2 ]

11 голосов
/ 25 июля 2011

В вашем дизайне есть недостаток.Ваш контроллер вообще не имеет статуса.У него есть свойство, которое отличается для каждого запроса / представления, а именно myBean.Если бы это было поддержано, то каждый новый запрос / представление отменял бы ранее установленный, и конечный пользователь будет сталкиваться со значением свойства совершенно другого конечного пользователя.Это приводит к проблемам в ситуациях с высоким уровнем одновременности.

Вам нужно сделать так, чтобы область запроса / просмотра вместо области приложения.Тем не менее, я считаю, что вы должны подходить к этому совершенно по-другому.Вы вручную устанавливаете атрибут в области сеанса в методе действия вместо того, чтобы устанавливать его как свойство (внедренного) компонента сессионной области.Как ее решить правильно, зависит от функционального требования, которое не ясно из вопроса.

2 голосов
/ 25 июля 2011

У меня есть JSF Managed Beans с разными областями действия, ссылающимися друг на друга, и я обнаружил, что Spring адекватно отвечает моим потребностям.Ключом к успеху была Spring AOP, которая использует ссылки на bean-компоненты и дает мне более гибкое автоматическое подключение.Я думаю, что для вас будет иметь смысл смешивать JSF и Spring одинаково для достижения ваших целей.

Я не использую аннотации декларации области действия JSF для объявления моих компонентов.Вместо этого я использую Spring, чтобы объявить свои bean-компоненты, назначить их области действия и указать, что я хочу, чтобы bean-компоненты со странной областью действия генерировали для них прокси-серверы aop (чтобы они могли соответствующим образом автоматически подключаться при обращении к ним). Я использую Spring el-Средство распознавания, чтобы сделать мои Spring-бины адресуемыми как управляемые JSF2-бины в EL.

Я не использую область представления в моей программе, я использую область сеанса с компонентами, определяемыми запросом, ссылающимися на них.Но я подозреваю, что мой подход может быть адаптирован и для ваших bean-объектов в области видимости.

Я не использую аннотации для объявления моих bean-компонентов, я использую XML для объявления моих bean-компонентов и их областей действия.Мне просто удобно, чтобы все мои объявления бобов каталогизировались в одном месте.Я уверен, что есть чистый подход на основе аннотаций для достижения того, что у меня есть.Я действительно использую аннотацию @Autowired в моих bean-компонентах, чтобы указать, куда должны быть подключены ссылки на другие bean-компоненты. Это делает мою XML-конфигурацию короткой, устраняет необходимость в getter / setters и дает мне немного больше гибкости на стороне Java, чем я »я смог получить чистый XML.

Наконец-то я дал себе специальную область «SmartSession».По сути, это то же самое, что и область сеанса, за исключением того, что он автоматически пересылает каждый раз, когда bean-компонент извлекается из сеанса (это защищает от появления реплик bean-компонентов, которые не подключены в сценарии отработки отказа в кластере.)вывод о том, что для работы bean-компонентов с сессионной (и я предполагаю view-) областью действия вы должны сделать сериализуемый bean-компонент и пометить любые поля @Autowired как временные.SmartSession дает мне уверенность в этом контексте, чтобы быть уверенным, что я остаюсь подключенным автоматически даже в исключительных случаях.Я основал свою идею настраиваемой области SmartSession на этом ответе: Инициализируйте уже созданные объекты в Spring , а также интернет-источники для написания пользовательских областей.

Вот некоторые фрагменты кода, которые, надеюсь, дадут вамнекоторые идеи -

Пример bean-объекта Session-scoped:

public class UserProfileContainer implements Serializable {
    private static final long serialVersionUID = -6765013004669200867L;

    private User userProfile;

    public void setUserProfile(User userProfile) {
        this.userProfile = userProfile;
    }

    public User getUserProfile() {
        return this.userProfile;
    }
}

Bean-компонент, который ссылается на мой bean-объект scoped:

public class KidProfileEditor implements Serializable {
    private static final long serialVersionUID = 1552049926125644314L;

    private String screenName;
    private String password;
    private String confirmPassword;
    private String firstName;
    private String lastName;
    private String city;
    private String state;
    private String notes;
    private String country;

    @Autowired
    private transient UserProfileContainer userProfileContainer;
}

Фрагмент из моего приложенияContext.xml:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
     xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
     xmlns:aop="http://www.springframework.org/schema/aop"
     xmlns:tx="http://www.springframework.org/schema/tx"
     xmlns:jee="http://www.springframework.org/schema/jee"
     xmlns:util="http://www.springframework.org/schema/util"     
     xmlns:lang="http://www.springframework.org/schema/lang" 
     xmlns:jms="http://www.springframework.org/schema/jms"   
     xmlns:context="http://www.springframework.org/schema/context"             
     xsi:schemaLocation="
         http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
         http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-3.0.xsd
         http://www.springframework.org/schema/jee http://www.springframework.org/schema/jee/spring-jee-3.0.xsd
         http://www.springframework.org/schema/lang http://www.springframework.org/schema/lang/spring-lang-3.0.xsd
         http://www.springframework.org/schema/jms http://www.springframework.org/schema/jms/spring-jms-3.0.xsd
         http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.0.xsd
         http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.0.xsd
         http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd"

    default-lazy-init="true" > 

    <!-- BOILERPLATE magic AOP setup tags -->
    <context:annotation-config />
    <context:component-scan base-package="com.woldrich.kidcompy" />
    <aop:aspectj-autoproxy />

    <!-- JSF2+Spring custom scope configurations -->
    <bean class="org.springframework.beans.factory.config.CustomScopeConfigurer">
        <property name="scopes">
            <map>
                <entry key="safetySession">
                    <bean class="com.woldrich.kidcompy.faces.util.SpringSafetySessionScope"/>
                </entry>
            </map>
        </property>
    </bean>

    <bean id="userProfileContainer" class="com.woldrich.kidcompy.auth.UserProfileContainer" scope="safetySession">      
        <aop:scoped-proxy />
    </bean>
    <bean id="kidProfileEditor" class="com.woldrich.kidcompy.faces.actionview.KidProfileEditor" scope="request" />
</beans>

Фрагмент web.xml:

<web-app xsi:schemaLocation="http://java.sun.com/xml/ns/javaee /WEB-INF/includes/schema/web-app_2_5.xsd" id="KidCompy" version="2.5" metadata-complete="true" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee">
    <distributable/>

    <context-param>
        <description>Allows the Spring Context to load multiple application context files</description>
        <param-name>contextConfigLocation</param-name>
        <param-value>classpath:/mainApplicationContext.xml</param-value>
    </context-param>

    <listener>
        <listener-class>org.springframework.web.context.request.RequestContextListener</listener-class>
    </listener>
</web-app>

лица-config.xml фрагмент:

<faces-config 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 /WEB-INF/includes/schema/web-facesconfig_2_0.xsd" 
              version="2.0">
    <application> 
        <el-resolver>
            org.springframework.web.jsf.el.SpringBeanFacesELResolver
        </el-resolver>
    </application>
</faces-config>
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...