web-dev-qa-db-fra.com

Intégration Spring Boot JSF

L'environnement:

Tomcat 8

Spring Boot 1.5

JSF 2.2

Apache MyFaces

Spring MVC

Code:

J'intègre Spring Boot et JSF 2.2 dans l'environnement Servlet 3.0.

Classes de configuration:

JSFConfig.Java - Configuration pour JSF.

@Configuration
@ComponentScan({"com.atul.jsf"})
public class JSFConfig {

        @Bean
        public ServletRegistrationBean servletRegistrationBean() {
            FacesServlet servlet = new FacesServlet();
            return new ServletRegistrationBean(servlet, "*.jsf");
        }

}

Classe principale Spring Boot:

@SpringBootApplication
@Import({ // @formatter:off 
    JPAConfig.class,
    ServiceConfig.class, // this contains UserServiceImpl.Java class.
    WebConfig.class,
    JSFConfig.class,
})
public class SpringbootJpaApplication extends SpringBootServletInitializer{

    public static void main(String[] args) {
        SpringApplication.run(SpringbootJpaApplication.class, args);
    }

    @Override
    protected SpringApplicationBuilder configure(SpringApplicationBuilder application) {
            return application.sources(SpringbootJpaApplication.class);
    }
}

Bean géré:

UserBean.Java - Bean géré pour JSF

@ManagedBean
@SessionScoped
public class UserBean implements Serializable{

    /**
     * 
     */
    private static final long serialVersionUID = 1L;
    private String name;
    @ManagedProperty(value="#{userServiceImpl}")
    private UserServiceImpl userServiceImpl;

    public void addUser(){      
        System.out.println("User Gets added "+this.name);       
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }
    public UserServiceImpl getUserServiceImpl() {
        return userServiceImpl;
    }

    public void setUserServiceImpl(UserServiceImpl userServiceImpl) {
        this.userServiceImpl = userServiceImpl;
    }
}

Facelets:

home.xhtml - page d'accueil

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

    <h:head>
        <title>JSF 2.0 Hello World</title>
    </h:head>
    <h:body>
        <h2>JSF 2.0 Hello World Example - hello.xhtml</h2>
        <h:form>
           <h:inputText value="#{userBean.name}"></h:inputText>
           <h:commandButton value="Submit" action="#{userBean.addUser}"></h:commandButton>
        </h:form>
    </h:body>
</html>

faces-config.xml:

<?xml version="1.0" encoding="UTF-8"?>
<faces-config xmlns="http://xmlns.jcp.org/xml/ns/javaee"
              xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
              xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee/web-facesconfig_2_2.xsd"
              version="2.2">

    <application>
        <el-resolver>org.springframework.web.jsf.el.SpringBeanFacesELResolver</el-resolver>
    </application>
    <lifecycle>
        <phase-listener>org.springframework.web.jsf.DelegatingPhaseListenerMulticaster</phase-listener>
    </lifecycle>

</faces-config>

Problème :

1) lorsque je soumets un formulaire dans home.xhtml , userBean.addUser est appelé. 2) userBean.name est défini avec les valeurs entrées par l'utilisateur. 3) Mais userServiceImpl est NULL. 4) Est-ce à dire que Spring et JSF ne s'intègrent pas? J'ai également enregistré SpringBeanFacesELResolver comme mentionné dans

faces-config.xml 

J'ai également essayé de supprimer toutes les annotations spécifiques JSF de UserBean.Java et j'ai utilisé uniquement des annotations spécifiques à Spring comme ci-dessous -

 @Component
    @SessionScoped 
    public class UserBean implements Serializable{

        /**
         * 
         */
        private static final long serialVersionUID = 1L;
        private String name;
        @Autowired
        private UserServiceImpl userServiceImpl;


    }

Mais lorsque je soumets un formulaire, j'obtiens une erreur cible inaccessible pour #{userBean). Cela signifie que userBean n'est pas détectable pour Spring

5) Est-ce que je manque quelque chose ici? 6) Je n'utilise pas Tomcat intégré fourni avec Spring Boot

9
Atul

C'est ainsi que JSF travaille avec Spring Boot (complet exemple de projet chez Github, mis à jour avec JSF 2.3 et Spring Boot 2 ):

1. Dépendances

En plus de la dépendance standard du démarreur Web, vous devrez inclure le jasper intégré Tomcat marqué comme fourni (merci @Fencer pour avoir commenté ici ). Sinon, vous obtiendrez une exception au démarrage de l'application, car JSF dépend du processeur JSP (voir également le premier lien à la fin de ma réponse).

<dependency>
    <groupId>org.Apache.Tomcat.embed</groupId>
    <artifactId>Tomcat-embed-jasper</artifactId>
    <scope>provided</scope>
</dependency>

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
</dependency>

2. Enregistrement de servlet

Enregistrez le servlet JSF et configurez-le pour qu'il se charge au démarrage (pas besoin de web.xml). Si vous travaillez avec JSF 2.2, le mieux est d'utiliser *.xhtml mappage, au moins lors de l'utilisation de facettes:

@Bean
public ServletRegistrationBean servletRegistrationBean() {
    ServletRegistrationBean servletRegistrationBean = new ServletRegistrationBean(
            new FacesServlet(), "*.xhtml");
    servletRegistrationBean.setLoadOnStartup(1);
    return servletRegistrationBean;
}

Faites en sorte que votre classe de configuration implémente ServletContextAware afin que vous puissiez définir vos paramètres init. Ici, vous devez forcer JSF à charger la configuration:

@Override
public void setServletContext(ServletContext servletContext) {
    servletContext.setInitParameter("com.Sun.faces.forceLoadConfiguration",
            Boolean.TRUE.toString());
    servletContext.setInitParameter("javax.faces.FACELETS_SKIP_COMMENTS", "true");
    //More parameters...
}

3. Intégration EL

Déclarez le résolveur EL dans faces-config.xml. Cela va être le lien entre vos fichiers de vue et vos propriétés et méthodes de bean géré:

<?xml version="1.0" encoding="UTF-8"?>
<faces-config xmlns="http://xmlns.jcp.org/xml/ns/javaee"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee/web-facesconfig_2_2.xsd"
    version="2.2">

    <application>
        <el-resolver>org.springframework.web.jsf.el.SpringBeanFacesELResolver
        </el-resolver>
    </application>

</faces-config>

4. La portée de la vue

Écrivez une portée Spring personnalisée pour émuler la portée de la vue JSF (gardez à l'esprit que vos beans seront gérés par Spring, pas JSF). Cela devrait ressembler à ceci:

public class ViewScope implements Scope {

    @Override
    public Object get(String name, ObjectFactory<?> objectFactory) {
        Map<String, Object> viewMap = FacesContext.getCurrentInstance()
            .getViewRoot().getViewMap();
        if (viewMap.containsKey(name)) {
            return viewMap.get(name);
        } else {
            Object object = objectFactory.getObject();
            viewMap.put(name, object);
            return object;
        }
    }

    @Override
    public String getConversationId() {
        return null;
    }

    @Override
    public void registerDestructionCallback(String name, Runnable callback) {

    }

    @Override
    public Object remove(String name) {
        return FacesContext.getCurrentInstance().getViewRoot().getViewMap().remove(name);
    }

    @Override
    public Object resolveContextualObject(String arg0) {
        return null;
    }

}

Et enregistrez-le dans votre classe de configuration:

@Bean
public static CustomScopeConfigurer viewScope() {
    CustomScopeConfigurer configurer = new CustomScopeConfigurer();
    configurer.setScopes(
            new ImmutableMap.Builder<String, Object>().put("view", new ViewScope()).build());
    return configurer;
}

5. Prêt à partir!

Vous pouvez maintenant déclarer vos beans gérés comme indiqué ci-dessous. N'oubliez pas d'utiliser @Autowired (de préférence dans les constructeurs) au lieu de @ManagedProperty, parce que vous avez affaire à des haricots de printemps.

@Component
@Scope("view")
public class MyBean {

    //Ready to go!

}

Toujours en attente de réalisation

Je n'ai pas pu faire fonctionner les annotations spécifiques JSF dans le contexte Spring Boot. Alors @FacesValidator, @FacesConverter, @FacesComponent, etc. ne peut pas être utilisé. Pourtant, il y a la possibilité de les déclarer dans faces-config.xml (voir xsd ), à l'ancienne.


Voir aussi:

9
Xtreme Biker