2011-07-25 11 views
4

J'ai un contrôleur qui est apatride et qui s'occupe du traitement des formulaires. Ceci est défini comme ApplicationScoped. Sur ma page, j'ai un formulaire associé à un backing bean défini comme ViewScoped.JSF 2.0 Injecter un bean géré avec une portée différente

L'erreur que je suis quand je veux traiter la forme:

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 

Dans ma forme:

 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"/> 

Le contrôleur:

@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()); 
    } 
} 

Le backing bean:

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

Je pourrais résoudre cela en réglant le contrôleur sur SessionScoped mais ce n'est pas une méthode propre puisque le contrôleur est sans état, donc je n'ai pas besoin d'un contrôleur pour chaque session. Un contrôleur pour l'ensemble de l'application devrait suffire.

J'ai un arrière-plan Spring MVC, c'est pourquoi je suis confus sur la façon de faire des choses avec JSF 2.0

Répondre

11

Il y a une faille dans votre conception. Votre contrôleur n'est pas apatride du tout. Il a une propriété qui est différente pour chaque demande/vue, à savoir le myBean. Si elle était supportée, alors chaque nouvelle requête/vue remplacerait celle précédemment définie et l'utilisateur final ferait face à la valeur de propriété d'un utilisateur final complètement différent. Cela conduit à des problèmes dans des situations concurrentes élevées.

Vous devez faire en sorte que la demande/la vue soit limitée à l'étendue de l'application. Encore alors, je crois que vous devez l'aborder complètement différent. Vous définissez manuellement un attribut dans la portée de session dans la méthode action au lieu de le définir en tant que propriété d'un bean étendu de session (injecté). Comment le résoudre correctement dépend de l'exigence fonctionnelle qui n'est pas claire à partir de la question.

+0

BalusC est correct, n'adaptez pas ma réponse ci-dessus pour obtenir des haricots de portée applicative en référence aux haricots à portée de vue. Il se décomposera lorsque plusieurs utilisateurs référenceront ce bean applicatif en même temps. Qu'est-ce que l'application -> View se résume essentiellement à un singleton dynamique, et ce n'est jamais un design réalisable. Essayez de reconcevoir de telle sorte que vous faites Demande -> Voir les références. – DWoldrich

+0

Je vais retravailler mon design. – Sydney

2

Je Managed Beans JSF avec différents champs d'application faisant référence les uns des autres, et je l'ai trouvé printemps répond adéquatement à mes besoins. La clé du succès a été le Spring AOP qui prénifie les références de bean et me donne un autowiring plus flexible. Je pense qu'il serait logique pour vous de mélanger JSF et Spring de manière similaire pour atteindre vos objectifs.

Je n'utilise pas les annotations de déclaration d'étendue JSF pour déclarer mes beans. Au lieu de cela, j'utilise Spring pour déclarer mes beans, assigner leurs étendues, et spécifier que je veux que les beans de portée étrange aient des proxies aop générés pour eux (ainsi ils peuvent être auto-alimentés de manière appropriée chaque fois qu'ils sont référencés). résolveur pour rendre mes beans Spring adressables en tant que beans gérés par JSF2 dans EL.

Je n'utilise pas la portée de vue dans mon programme, j'utilise la portée de session avec des beans de portée de requête les référençant. Mais, je soupçonne que mon approche pourrait également être adaptée à votre champ de vision.

Je n'utilise pas d'annotations pour déclarer mes beans, j'utilise XML pour déclarer mes beans et leurs étendues. Je trouve juste pratique d'avoir toutes mes déclarations de haricots cataloguées en un seul endroit. Je suis certain qu'il existe une approche purement basée sur les annotations pour réaliser ce que j'ai. J'utilise l'annotation @Autowired dans mes beans pour indiquer où les références aux autres beans doivent être câblées. Cela permet de garder ma configuration XML courte, élimine le besoin de getter/setters, et me donne un peu plus de flexibilité côté Java que J'ai été capable de passer du XML pur.

Enfin, je me suis donné une portée "SmartSession" personnalisée. Ceci est essentiellement similaire à la portée de la session, sauf qu'elle se réapprovisionne chaque fois qu'un bean est retiré de la session (ce qui protège contre les répliques de bean n'apparaissant pas dans un scénario de basculement dans un cluster.)

Je suis venu à la conculsion Pour que les beans définis par la session (et je présume que les visionneuses) fonctionnent, vous devez rendre le bean Serializable et marquer tous les champs @Autowired comme étant transitoires. La SmartSession me donne la confiance dans ce contexte pour être assuré que je reste autowired même dans des cas exceptionnels. J'ai basé mon idée de portée personnalisée de SmartSession hors de cette réponse: Initialize already created objects in Spring aussi bien que des sources d'Internet pour comment écrire des étendues faites sur commande.

Voici quelques extraits de code pour vous donner de donner des idées -

haricot scope Session-échantillon:

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 qui fait référence à mon haricot scope smartSession:

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; 
} 

Extrait de mon applicationConte xt.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> 

extrait de 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> 

extrait 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> 
Questions connexes