Spring Boot JSF интеграция

Околен свят :

Tomcat 8

Пролетно зареждане 1.5

JSF 2.2

Apache MyFaces

Пролетен MVC

код:

Интегрирам Spring Boot и JSF 2.2 в среда на Servlet 3.0.

Конфигурационни класове:

JSFConfig.java - Конфигурация за JSF.

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

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

}

Основен клас на пролетното зареждане:

@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:

UserBean.java - Управляван Bean за 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;
    }
}

Фасети:

home.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">

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

Проблем :

1) когато изпратя формуляр в home.xhtml , userBean.addUser се извиква. 2)userBean.name се задава със стойности, въведени от потребителя. 3) Но userServiceImpl е NULL. 4) Това означава ли, че Spring и JSF не се интегрират? Регистрирах също SpringBeanFacesELResolver, както е споменато в

faces-config.xml 

Също така се опитах да премахна всички специфични за JSF анотации от UserBean.java и използвах само специфични за Spring анотации като по-долу -

 @Component
    @SessionScoped 
    public class UserBean implements Serializable{

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


    }

Но когато изпратя формуляр, получавам целева недостижима грешка за #{userBean). Това означава, че userBean не може да се открие за Spring

5) Пропускам ли нещо тук? 6) Не използвам вграден tomcat, предоставен с Spring Boot


person Atul    schedule 13.09.2017    source източник


Отговори (1)


Това е начинът, по който JSF работи с Spring Boot (пълен примерен проект в Github, актуализиран с JSF 2.3 и Пролетно зареждане 2):

1. Зависимости

В допълнение към стандартната зависимост за уеб стартера, ще трябва да включите вградения jasper в tomcat, маркиран като предоставен (благодаря на @Fencer за коментара тук). В противен случай ще получите изключение при стартиране на приложението, поради JSF в зависимост от JSP процесора (вижте също първата връзка в края на моя отговор).

<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. Регистрация на сервлета

Регистрирайте JSF сървлета и го конфигурирайте да се зарежда при стартиране (няма нужда от web.xml). Ако работите с JSF 2.2, най-добре е да използвате *.xhtml картографиране, поне когато използвате фейслети:

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

Накарайте вашия конфигурационен клас да изпълнява ServletContextAware, за да можете да зададете началните си параметри. Тук трябва да принудите JSF да зареди конфигурация:

@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. ЕЛ интеграцията

Декларирайте EL преобразувател в faces-config.xml. Това ще бъде спойката между вашите файлове за преглед и вашите управлявани свойства и методи на bean:

<?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. Обхватът на изгледа

Напишете персонализиран обхват на Spring, за да емулирате обхвата на JSF изгледа (имайте предвид, че вашите bean-ове ще бъдат управлявани от Spring, а не от JSF). Трябва да изглежда по следния начин:

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

}

И го регистрирайте във вашия клас конфигурация:

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

5. Готови за работа!

Сега можете да декларирате вашите управлявани зърна по начина по-долу. Не забравяйте да използвате @Autowired (за предпочитане в конструкторите) вместо @ManagedProperty, защото имате работа с Spring Beans.

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

    //Ready to go!

}

Все още предстои за постигане

Не можах да накарам JSF специфичните анотации да работят в контекста на Spring Boot. Така че @FacesValidator, @FacesConverter, @FacesComponent и т.н. не могат да се използват. Все пак има възможност да ги декларирате в faces-config.xml (вижте xsd), по старомодния начин.


Вижте също:

person Xtreme Biker    schedule 13.09.2017
comment
Xtreme Biker намерихте ли начин да накарате JSF анотациите да работят? може би с Spring boot 2.0? - person Diego Marinelli; 06.03.2018
comment
Не, но не съм копал твърде много, откакто написах този отговор. Тъй като е пролет, когато управлявате вашите bean-ове тук, можете да опитате някаква анотация, генерираща сингълтони, като @Component. - person Xtreme Biker; 06.03.2018
comment
@XtremeBiker наистина ли се нуждае от зависимостта от Jasper? - person John John Pichler; 10.07.2018
comment
@John, така е. Премахването му ще предизвика изключение. - person Xtreme Biker; 10.07.2018
comment
@XtremeBiker В момента имам проблеми със същата конфигурация. Видях вашия проект в GitHub и изглежда, че сте конфигурирали сървъра за вграждане на tomcat, както е предоставено. Как може приложението да работи с командата java -jar app.jar без вграждането на tomcat, както е описано във вашия readme файл? Бихте ли обяснили накратко? В документацията за Spring Boot те казаха, че тази конфигурация се използва само когато искате да стартирате приложението като военен файл в Jetty/Tomcat сървър, например. - person John John Pichler; 10.07.2018
comment
Приложението също зависи от starter-web. Тази зависимост вече предоставя вградения tomcat. Проблемът тук е свързан с това, че вграденият tomcat не предоставя възможностите на jasper по време на компилиране, което изглежда се изисква от JSF. Така че добавянето на тази зависимост го решава. Вижте също: stackoverflow.com/a/25777709/1199132 - person Xtreme Biker; 10.07.2018
comment
Може да е @Kukeltje. Все пак има няколко отговора тук от хора, които ги карат да работят с пролетни анотации. Ще погледна и ще се опитам да завърша началния си проект. - person Xtreme Biker; 17.07.2018