我有一个无状态的控制器,负责处理表格。这被定义为ApplicationScoped
。在我的页面上,我有一个与支持bean关联的表单,定义为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());
}
}
支持bean:
@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做事感到困惑
答案 0 :(得分:11)
您的设计存在缺陷。您的控制器根本不是无状态的。它有一个不同的属性,每个请求/视图,即myBean
。如果它受支持,则每个新请求/视图将覆盖先前设置的请求/视图,并且最终用户将面对完全不同的最终用户的属性值。这导致高并发情况下的问题。
您需要将其作为请求/视图作用域而不是应用程序作用域。然而,我相信你必须完全不同。您在action方法中手动设置会话范围中的属性,而不是将其设置为(注入)会话范围bean的属性。如何正确地解决它取决于功能要求,这个问题不明确。
答案 1 :(得分:2)
我有不同范围的JSF Managed Beans相互引用,我发现Spring充分满足了我的需求。成功的关键是Spring AOP,它代理bean引用并为我提供更灵活的自动装配。我认为将JSF和Spring混合起来以实现目标是有意义的。
我不使用JSF范围声明注释来声明我的bean。相反,我使用Spring来声明我的bean,分配它们的范围,并指定我希望奇怪的bean为它们生成aop代理(因此它们可以在引用时适当地自动装配。)我使用spring el-解析器使我的Spring bean可以作为EL中的JSF2托管bean进行寻址。
我不在程序中使用视图范围,我将会话范围与引用它们的请求范围的bean一起使用。但是,我怀疑我的方法也适用于你的视图范围的bean。
我不使用注释来声明我的bean,我使用XML来声明我的bean及其范围。我发现将所有bean声明编入一个地方都很方便。我确信有一种纯粹的基于注释的方法来实现我所拥有的。我在我的bean中使用@Autowired注释来指示应该连接其他bean的引用。这使我的XML配置保持简短,消除了对getter / setter的需求,并且给了我比Java更多的Java端灵活性已经能够从纯XML中获得。
最后,我给自己定制了一个“SmartSession”范围。这基本上就像会话范围一样,除了每次将bean从会话中拉出时它都会重新自动化(这可以防止在群集中的故障转移方案中出现无线连接的bean副本。)
我已经得出结论,对于session-(并且我假设view-)scoped bean工作,你需要使bean Serializable并将任何@Autowired字段标记为瞬态。 SmartSession让我对这种情况充满信心,即使在特殊情况下我也能保持自动装配。我根据这个答案建立了我的SmartSession自定义范围构思:Initialize already created objects in Spring以及如何编写自定义范围的互联网资源。
这里有一些代码片段,希望能给你一些想法 -
示例会话范围的bean:
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;
}
}
引用我的smartSession-scoped bean的Bean:
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;
}
来自我的applicationContext.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>
faces-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>