| term | classification |
| Spring MVC | request/action based web framework |
| Apache Struts | request/action based web framework |
| JSF | component based web framework (API corresponding to JSR 344) |
| Apache MyFaces | component based web framework (JSF implementation provided by the Apache Software Foundation) |
| Morraja | component based web framework (JSF implementation provided by the Oracle) |
| Spring WebFlow | component based web framework |
| GWT | component based web framework |
| Vaadin | component based web framework |
| Apache Tapestry | component based web framework |
| Apache Wicket | component based web framework |
| Sitemesh | template engine |
| Thymeleaf | template engine |
| Velocity | template engine |
| Apache Tiles | template engine |
| Primefaces | extension library with JSF based widgets |
| Dojo Toolkit | extension library with JavaScript based widgets |
For each of the stacks mentioned above I have created a branch in my Github repository:

Looking at the initial selection criteria, I have to come to the following conclusions:
| criteria | Stack 1 | Stack 2 | Stack 3 |
| open source framework | |
|
|
| integration with the existing Spring-based eco-system | |
||
| ready to use UI components | |
At first, we need to do a couple of adjustments in the pom.xml:
1.) include Spring WebFlow, JSF and Primefaces:
<!-- Spring Webflow: spring faces -->
<dependency>
<groupId>org.springframework.webflow</groupId>
<artifactId>spring-faces</artifactId>
<version>2.4.4.RELEASE</version>
</dependency>
<!-- JSF implementation: Mojarra -->
<dependency>
<groupId>com.sun.faces</groupId>
<artifactId>jsf-api</artifactId>
<version>2.2.13</version>
</dependency>
<dependency>
<groupId>com.sun.faces</groupId>
<artifactId>jsf-impl</artifactId>
<version>2.2.13</version>
</dependency>
<!-- JSF extension: Primefaces -->
<dependency>
<groupId>org.primefaces</groupId>
<artifactId>primefaces</artifactId>
<version>6.0</version>
</dependency>
2.) set packaging type explicitly to war (this is needed to build the application properly):
<packaging>war</packaging>
3.) add dependency for spring security taglib in order to be able to access Spring Security functionality in JSF facelets:
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-taglibs</artifactId>
</dependency>
Addtionally, we need to store some configuration files for JSF and Spring security. That's why we have to create a webapp containing a WEB-INF directory underneath src/main. This directory will be picked up and included in the application when it is built. A boringly ordinary faces-config.xml has to be placed underneath src/main/webapp/WEB-INF. Furthermore, a Spring Security specific taglib has to be stored at src/main/webapp/WEB-INF/springsecurity.taglib.xml. This will allow us later on to use spring security functionality in JSF faclets.
In our next step, we have to add further JSF configuration parameters to src/main/resources/application.properties:
# javax.faces.* properties to configure JSF behaviour
#
# DEFAULT_SUFFIX: file ending for view templates used with Facelets
# PROJECT_STAGE: enables special Facelets debug output during development
# FACELETS_REFRESH_PERIOD: causes Facelets to refresh templates during development
# FACELETS_LIBRARIES: registers addional tag libraries for usage in facelets
server.context-parameters.javax.faces.DEFAULT_SUFFIX=.xhtml
server.context-parameters.javax.faces.PROJECT_STAGE=Development
server.context-parameters.javax.faces.FACELETS_REFRESH_PERIOD=1
server.context-parameters.javax.faces.FACELETS_LIBRARIES=/WEB-INF/springsecurity.taglib.xml
# set context param 'com.sun.faces.forceLoadConfiguration' in order to force JSF
# implementation to neglect the need of a FacesServlet(-Mapping) and ConfigureListener
# in a web.xml and to use annotation based configuration
server.context-parameters.com.sun.faces.forceLoadConfiguration=true
We do that by means of server.context-parameters.* which Spring Boot will use to set the acutal context parameters of our web application. Please refer to the comments in the file for further details.
Before we have look at the decisive changes, I want to point out some refactoring that was done to was to as improvement of our application:
In order to maintain the actual context path of the application only once, we added the new config parameter dispatcherServletCxtpth in the application.yaml underneath src/main/resources and made it accessable in the class ConfigurationSettings.
This can now be used in the SecurityConfig class. There we have to adjust our security configuration to work well together with JSF and Spring Webflow. Therefore CSRF had to be disabled (see https://jira.springsource.org/browse/SEC-2498). Only the last HTTP POST request is saved in order to mitigate the risk of turning of Spring Security's protection against CSRF:
@Override
protected void configure(HttpSecurity http) throws Exception {
// retrieve configured contextPath for dispatcher servlet
String cxtpth = config.getDispatcherServletCxtpth();
http.formLogin()
.loginPage(cxtpth + "/login")
.loginProcessingUrl(cxtpth + "/loginProcess")
.defaultSuccessUrl(cxtpth + "/stock-info")
.failureUrl(cxtpth + "/login?login_error=1")
.and().logout()
.logoutUrl(cxtpth + "/logout")
.logoutSuccessUrl(cxtpth + "/index")
// Disable CSRF (won't work with JSF) but ensure last HTTP POST request is saved
// See https://jira.springsource.org/browse/SEC-2498
.and().csrf()
.disable()
.requestCache()
.requestCache(new HttpSessionRequestCache());
}
Do you remember that we have removed the HomeController as part of a clean-up and refactoring task? Of course, the conding that was that class has to go somewhere. Because of the usage of Spring WebFlow, there is no need of custom Controllers anymore because all requests are handled by a generic Spring Webflow controller. Thus our contoller logic is moved to the service class StockInfoServiceImpl:
*****************************************
* Copyright (c) 2016 Dominique Lopes.
* All rights reserved.
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*
* Contributors:
* Dominique Lopes - initial API and implementation
*******************************************************************************/
package de.dlopes.stocks.facilitator.services.impl;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import de.dlopes.stocks.facilitator.config.ConfigurationSettings;
import de.dlopes.stocks.facilitator.data.StockInfo;
import de.dlopes.stocks.facilitator.data.StockInfoRepository;
import de.dlopes.stocks.facilitator.services.StockDataCollector;
import de.dlopes.stocks.facilitator.services.StockInfoService;
@Service("stockInfoService")
public class StockInfoServiceImpl implements StockInfoService {
@Autowired
ConfigurationSettings cs;
@Autowired
StockInfoRepository siRepo;
@Override
public List<StockInfo> findAll() {
List<StockInfo> siList = siRepo.findAll();
return siList;
}
@Override
public List<StockInfo> loadAll() {
StockDataCollector dataCollector = cs.getDataCollector();
List<StockInfo> siList = dataCollector.getData();
for (StockInfo si : siList) {
siRepo.save(si);
}
siRepo.flush();
return findAll();
}
}
This service class is very closely aligned with the initial controller logic. However, one thing that is different and very important here is that we register this class as a named service (see line 25). Only if we do that we can use the methods of this service in the flow definition XMLs that describe the possible navigation path and actions in our application.
Additionally, create the class WebFlowServiceUtil - another named service that provides us with access to utility methods.
/*******************************************************************************
* Copyright (c) 2016 Dominique Lopes.
* All rights reserved.
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*
* Contributors:
* Dominique Lopes - initial API and implementation
*******************************************************************************/
package de.dlopes.stocks.facilitator.services.impl;
import java.util.List;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;
@Service("serviceUtil")
public class WebFlowServiceUtil {
public boolean isNull(Object object) {
return object == null;
};
public boolean notNull(Object object) {
return !isNull(object);
};
public boolean isEmpty(String string) {
return StringUtils.isEmpty(string);
};
public boolean notEmpty(String string) {
return !isEmpty(string);
};
public boolean isEmpty(List<?> list) {
return CollectionUtils.isEmpty(list);
};
public boolean notEmpty(List<?> list) {
return !isEmpty(list);
};
}
As a next step, we can to create the flow definition file stock-info-flow.xml underneath src/main/webapp/WEB-INF/flows/stock-info:
<?xml version="1.0" encoding="UTF-8"?>
<!--
Copyright (c) 2016 Dominique Lopes.
All rights reserved.
This Source Code Form is subject to the terms of the Mozilla Public
License, v. 2.0. If a copy of the MPL was not distributed with this
file, You can obtain one at http://mozilla.org/MPL/2.0/.
Contributors:
Dominique Lopes - initial API and implementation
-->
<flow xmlns="http://www.springframework.org/schema/webflow"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/webflow
http://www.springframework.org/schema/webflow/spring-webflow-2.0.xsd">
<!-- only registered users can access this flow -->
<secured attributes="ROLE_USER" />
<on-start>
<evaluate expression="stockInfoService.findAll()" result="flowScope.stocks" />
</on-start>
<decision-state id="isStockInfoLoaded">
<if test="serviceUtil.notEmpty(flowScope.stocks)" then="viewStockInfo" else="loadStockInfo" />
</decision-state>
<view-state id="loadStockInfo">
<transition on="load" to="viewStockInfo">
<evaluate expression="stockInfoService.loadAll()" result="flowScope.stocks" />
</transition>
</view-state>
<view-state id="viewStockInfo">
<transition on="end" to="finish" />
</view-state>
<end-state id="finish" />
</flow>
The flow definition file finally contains the process flow of our application in decerative way:
Finally, we have to create the JSF facelets that will be used to render the HTML web pages. Spring Webflow automatically looks for views with exactly the same name as the ID of the view states that we have defined in the flow definition file. The possibility of using JSF faclets allows us to define only the relevant parts of the web pages. Therefore we create a JSF faclet at first that wraps all common parts of the web pages underneath src/main/webapp/WEB-INF/layout and name it standard.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:h="http://java.sun.com/jsf/html"
xmlns:f="http://java.sun.com/jsf/core"
xmlns:ui="http://java.sun.com/jsf/facelets"
xmlns:p="http://primefaces.org/ui"
xmlns:sec="http://www.springframework.org/security/tags">
<f:view contentType="text/html">
<h:head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<title>
Stock Facilitator: <ui:insert name="title"/>
</title>
<link rel="stylesheet" href="/${request.contextPath}/styles/blueprint/screen.css" type="text/css" media="screen, projection" />
<link rel="stylesheet" href="/${request.contextPath}/styles/blueprint/print.css" type="text/css" media="print" />
<!--[if lt IE 8]>
<link rel="stylesheet" href="/${request.contextPath}/styles/blueprint/ie.css" type="text/css" media="screen, projection" />
<![endif]-->
</h:head>
<h:body>
<div>
<sec:authorize ifAnyGranted="ROLE_USER">
<p:menubar>
<f:facet name="options">
Welcome, ${currentUser.name} | <a href="/logout">Logout</a>
</f:facet>
</p:menubar>
</sec:authorize>
</div>
<div>
<ui:insert name="content"/>
</div>
</h:body>
</f:view>
</html>
The JSF facelet from above contains the general layout of our website and defines two slots: "title" (see line 14) and "content" (see line 34). The content of these slots are only determined in the views that correspond to the view states that we have defined in the flow definition file.
As one of our last steps we have to define the two missing views that correspond to the view states. At first, the view loadStockInfo.xhtml underneath src/main/webapp/WEB-INF/flows/stock-info:
<!DOCTYPE composition PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<!--/*
Copyright (c) 2016 Dominique Lopes.
All rights reserved.
This Source Code Form is subject to the terms of the Mozilla Public
License, v. 2.0. If a copy of the MPL was not distributed with this
file, You can obtain one at http://mozilla.org/MPL/2.0/.
Contributors:
Dominique Lopes - initial API and implementation
*/-->
<ui:composition xmlns="http://www.w3.org/1999/xhtml"
xmlns:ui="http://java.sun.com/jsf/facelets"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:f="http://java.sun.com/jsf/core"
xmlns:p="http://primefaces.org/ui"
template="/WEB-INF/layouts/standard.xhtml">
<ui:define name="title">Load Stock Info</ui:define>
<ui:define name="content">
Stock info not loaded yet.
Click here to refresh stock information:
<h:form>
<p:commandLink action="load" value="Load" />
</h:form>
</ui:define>
</ui:composition>
As you can see, this view template contains just the relevant content and does not care about any common items on the web page (e. g. corporate logo, header, footer, etc.). The second view template viewStockInfo.xhtml underneath src/main/webapp/WEB-INF/flows/stock-info is not much different in this regard (although it is a little more complex):
<!DOCTYPE composition PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<!--/*
Copyright (c) 2016 Dominique Lopes.
All rights reserved.
This Source Code Form is subject to the terms of the Mozilla Public
License, v. 2.0. If a copy of the MPL was not distributed with this
file, You can obtain one at http://mozilla.org/MPL/2.0/.
Contributors:
Dominique Lopes - initial API and implementation
*/-->
<ui:composition xmlns="http://www.w3.org/1999/xhtml"
xmlns:ui="http://java.sun.com/jsf/facelets"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:f="http://java.sun.com/jsf/core"
xmlns:p="http://primefaces.org/ui"
template="/WEB-INF/layouts/standard.xhtml">
<ui:define name="title">Overview</ui:define>
<ui:define name="content">
<p>The following table lists all loaded stock information:</p>
<p:dataTable id="stocks" var="si" value="#{stocks}">
<!-- later:
paginator="true" dynamic="true" rows="#{stocks.pageSize}" page="#{stocks.currentPage}" lazy="true"> -->
<f:facet name="header">Index: DAX</f:facet>
<p:column sortBy="#{si.name}">
<f:facet name="header">Name</f:facet>
#{si.name}
</p:column>
<p:column>
<f:facet name="header">WKN/ISIN</f:facet>
#{si.WKN}/#{si.ISIN}
</p:column>
<p:column>
<f:facet name="header">Price</f:facet>
#{si.price}
</p:column>
<p:column>
<f:facet name="header">Bid</f:facet>
#{si.bid}
</p:column>
<p:column>
<f:facet name="header">Ask</f:facet>
#{si.ask}
</p:column>
<p:column>
<f:facet name="header">Change (abs./%)</f:facet>
#{si.changeAbsolute}/#{si.changePercentage}%
</p:column>
<p:column>
<f:facet name="header">Last update</f:facet>
#{si.time}
</p:column>
</p:dataTable>
</ui:define>
</ui:composition>
In lines 27 to 60 we use a primefaces data table to render the content of the flowScope variable stocks. The table is defined in a column-wise manner by means of a <p:column> tag. The captions of these columns are defined within a faclet facet (<f:facet> tag).
As a last step, we move all existing HTML files to src/main/resources/templates to src/main/webapp/WEB-INF/views and rewrite them to JSF faclets (no further details specified here because this is considered trival).
This conludes the changes that we need to do.
Today, we had a look at JAVA based view technologys in general and compared 3 different approaches to one another. We finally decided to use Spring Webflow together with JSF and Primefaces - a JSF based extension library with modern UI compents. Finally, we made the necessary adjustments to our application in order to implement the new view technologies.
In the past iterations of this software project I found a lot of interesting web-based tools and services which make the life of application developers easier. That is why I want to dedicate the next session to a walk trough of my current project setup with all those freely accessible web tools.
This is the new high-level architecture of our application after switching to the implementation based on Spring Webflow, JSF and Primefaces:
This blog entry was inspired by the following sources:

Dominique Lopes is a Senior SAP Consultant at MHP with more than 10 years experience in Software Development in various programming languages. In his leisure time he enjoys to try out new IT trends in his private software projects.