I’m a big fan of Spring Boot. If you need to bootstrap a Java Enterprise application in a short space of time its an excellent project to get you moving and within a few lines you can expose or consume RESTful services, initiate an embedded Tomcat servlet container and auto-configure your way into the whole Spring ecosystem with barely a line of XML in site (yes, there’s still the Maven POM).
This leads us to a new application design paradigm, that of the micro-service or application. Each web app in a self-contained jar, its own embedded web-server with its own configuration running in its own JVM instance sitting behind a web proxy presenting a suite or cloud of services to the outside world seemingly as a single product.
You can of course use Spring Web with Thymeleaf or simple JSP with AngularJS but I wanted to demonstrate how to build a web interface to such a service using JSF and Primefaces and have posted a fully functional demo application to GitHub:
This an Eclipse Maven Spring Boot project, get it built and running and navigate to http://localhost:9090 and have a look at its behaviour. The data is also exposed as a RESTful service using Spring Web’s @RestController
at http://localhost:9090/service/books/ and individual items on http://localhost:9090/service/book/0/.
The embedded Tomcat container has very little functionality of its own, JSF capabilities are bestowed by adding the appropriate JSF and Primefaces dependencies to the Maven POM followed by additional annotated bean definitions to augment the Spring Boot auto-configuration. Although Tomcat is using java config it still requires the presence of a web.xml
file and a faces-config.xml file in the webapp/WEB-INF
directory. Any configuration that would normally be done in the web.xml
file is done in a class that implements ServletContextInitializer
such as our class Initializer
in the example which must in turn be announced to the Spring Boot SpringApplicationBuilder
during bootstrap.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
@EnableAutoConfiguration @ComponentScan({"com.oakdalesoft.bootfaces"}) public class Application extends SpringBootServletInitializer { @Value("${init.json}") private String init; public static void main(String[] args) { SpringApplication.run(Application.class, args); } @Override protected SpringApplicationBuilder configure(SpringApplicationBuilder application) { return application.sources(Application.class, Initializer.class); } } |
We now have two different types of containers active, one Spring container and a J2EE Servlet container (Tomcat) and really its better to keep them separate in your mind and technically but if we are going to transfer values between them we need some sort of interop bridge. Spring provides this through expression language via a SpringBeanFacesELResolver
which is referenced in your faces-config.xml
and injected by Spring for you. Now you can access Spring beans in your managed faces bean, passing vales both ways. See class BookModel
.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 |
package com.oakdalesoft.bootfaces.view; import com.oakdalesoft.bootfaces.domain.Book; import com.oakdalesoft.bootfaces.persistence.BookRepository; import javax.faces.application.FacesMessage; import javax.faces.bean.ManagedBean; import javax.faces.bean.ManagedProperty; import javax.faces.bean.RequestScoped; import javax.faces.context.FacesContext; import java.util.ArrayList; import java.util.List; /** * Created by Alex on 07/03/2015. */ @ManagedBean(name = "model", eager = true) @RequestScoped public class BookModel { public void setBook(BookView book) { this.book = book; } public BookView getBook() { return book; } @ManagedProperty(value = "#{book}") private BookView book; public BookRepository getBookRepository() { return bookRepository; } public void setBookRepository(BookRepository bookRepository) { this.bookRepository = bookRepository; } @ManagedProperty(value = "#{bookRepository}") BookRepository bookRepository; public String doCreateBook() { Book created = new Book(); created.setId(this.book.getId()); created.setTitle(this.book.getTitle()); created.setPrice(this.book.getPrice()); created.setnbofpage(this.book.getnbofpage()); created.setDescription(this.book.getDescription()); Book newBook = this.bookRepository.save(created); FacesContext.getCurrentInstance().addMessage("errors", new FacesMessage(FacesMessage.SEVERITY_INFO, "Book created", "The book " + created.getTitle() + " has been created with id=" + newBook.getId())); this.book.setTitle(""); this.book.setPrice(null); this.book.setDescription(""); this.book.setIllustrations(false); this.book.setnbofpage(null); return "index.xhtml"; } public void doFindBookById() { Book found = bookRepository.findOne(this.book.getId()); this.book.setId(found.getId()); this.book.setTitle(found.getTitle()); this.book.setPrice(found.getPrice()); this.book.setnbofpage(found.getnbofpage()); this.book.setDescription(found.getDescription()); this.book.setDescription(found.getDescription()); } public List<BookView> findAllBooks() { List<BookView> books = new ArrayList<BookView>(); for(Book entity : this.bookRepository.findAll()) { BookView view = new BookView(); view.setId(entity.getId()); view.setTitle(entity.getTitle()); view.setPrice(entity.getPrice()); view.setnbofpage(entity.getnbofpage()); view.setDescription(entity.getDescription()); view.setDescription(entity.getDescription()); books.add(view); } return books; } } |
Everything else in the project is simply a demonstration of the power of Spring Boot and how easy it is to add features thanks to auto configuration. The project includes:
- Spring Data JPA
- Spring Rest
- Spring Actuator
- Jackson Repository Populators
- URL Rewriting
Details of all of these can be found in the Spring Boot documentation except the last item, URL Rewriting. The one thing I hate about JSF is the ugly URL schema it leaves you with. This can be remedied by adding OcpSoft’s Rewrite Project to your project. I’m bringing this up now because once you’ve added the dependency to your POM the configuration requires a little special Spring Boot configuration voodoo too.
If you recall I mentioned that the web.xml
file is not loaded by the embedded Tomcat server and that all configuration is done through java config, well that includes activating the RewriteFilter
bean. This is performed in the class that extends SpringBootServletInitializer
:
1 2 3 4 5 6 7 8 |
@Bean public FilterRegistrationBean rewriteFilter() { FilterRegistrationBean rwFilter = new FilterRegistrationBean(new RewriteFilter()); rwFilter.setDispatcherTypes(EnumSet.of(DispatcherType.FORWARD, DispatcherType.REQUEST, DispatcherType.ASYNC, DispatcherType.ERROR)); rwFilter.addUrlPatterns("/*"); return rwFilter; } |
From here on you just need to define a HttpConfigurationProvider
and annotate it with the @RewriteConfiguration
annotation as per the documentation.
See also: The AngularFaces Project See Also: JSF on Spring Boot (Understanding Scopes)
Hi Alex,
I think you don’t need web.xml at all. Try to look here https://github.com/bilak/spring-boot-primefaces-template (project is not working because there is moyara 2.2.11, but if you downgrade to 2.2.10 everything will work)
Hi Bilak,
That’s interesting. If I remove the web.xml from my project it fails on page load, I suspect the discrepancy is something to do with the differences in the pom.xml files between our projects.
When I get some time I’ll investigate the cause further. Nevertheless, it does no harm to leave it in and if it makes a project less sensitive to classpath changes then all the better.
Thank you for raising this though.
Why your pom.xml has following instruction?
src/main/webapp/WEB-INF/classes
This is required because I’m running JSF scoped beans in an embedded Tomcat container and that’s where JSF will scan for them. I think it only happens in Eclipse but it needs checking.
Alex, I read your valuable article carefully. I think src/main/webapp folder is not necessary with spring boot JAR packaged. JSF resources (xhtml, js, css) should be located at src/main/resources/META-INF/resources folder.
I put an example app at https://github.com/persapiens/jsf-spring-boot-starter-example
This example uses jsf-spring-boot-starter that solves JSF and Spring Boot integration issues.
Best regards.
Hi Bilak,,
when i use postconstruct annotation in my managed bean ,nothing it perform , do you know why and do you have any solution for this problem ?
Helpful post, Thank you
Hi Alex,
Have you tried to build the jar and run it with java -jar boot-faces-1.0-SNAPSHOT.jar ?
It gives and error:
Tue May 31 18:22:48 EEST 2016
There was an unexpected error (type=Internal Server Error, status=500).
No Factories configured for this Application. This happens if the faces-initialization does not work at all – make sure that you properly include all configuration settings necessary for a basic faces application and that all the necessary libs are included. Also check the logging output of your web application and your container for any exceptions! If you did that and find nothing, the mistake might be due to the fact that you use some special web-containers which do not support registering context-listeners via TLD files and a context listener is not setup in your web.xml. A typical config looks like this; org.apache.myfaces.webapp.StartupServletContextListener
It works if you have the src folder next to jar. Somehow myfaces is reading in src folder:
.a.m.c.DefaultFacesConfigurationProvider : Reading config : jar:file:/C:/Users/cosmin.ghita/Downloads/Primedash/src/main/webapp/WEB-INF/lib/atlas-theme-1.1.jar!/META-INF/faces-config.xml
Do you know how can I fix this?
Thanks
Cosmin,
I changed the packaging to WAR and it helped
Hi,
Thanks for this post, It has helped to Integrated JSF with Spring boot and it is working fine.
But I have another challenge to integrate CDI along with JSF with Spring boot (Embedded Tomcat) for @BeanManager(javax.enterprise.inject.spi.BeanManager) required in the applicaton.
Please help with CSI Integration with Spring Boot + JSF (tomcat)..
Best Regards…
How can I add to this project the Spring web flow project ??
visit this page hydra onion
FaucetPay codes free cash Dogecoin
cvv trading system Wiredpay
inbox mass Payeer
paid to click method of pay usdt Ripple
http://clickview.site