Have a look at the Sitemesh framework, a lightweight and flexible Java web application framework that applies the Gang of Four decorator pattern to allow a clean separation of content from presentation.
Below is an example that shows you how you could use it.
Configuration
pom.xml
<dependency>
<groupId>opensymphony</groupId>
<artifactId>sitemesh</artifactId>
<version>2.4.2</version>
</dependency>
WEB-INF/web.xml
<filter>
<filter-name>sitemeshFilter</filter-name>
<filter-class>com.opensymphony.module.sitemesh.filter.PageFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>sitemeshFilter</filter-name>
<url-pattern>/*</url-pattern>
<dispatcher>FORWARD</dispatcher>
<dispatcher>REQUEST</dispatcher>
</filter-mapping>
WEB-INF/sitemesh.xml
<?xml version="1.0" encoding="UTF-8" ?>
<sitemesh>
<property name="decorators-file" value="/WEB-INF/sitemesh-decorators.xml" />
<excludes file="${decorators-file}" />
<page-parsers>
<parser content-type="text/html" class="com.opensymphony.module.sitemesh.multipass.DivExtractingPageParser"/>
</page-parsers>
<decorator-mappers>
<mapper class="com.opensymphony.module.sitemesh.mapper.ParameterDecoratorMapper">
<param name="decorator.parameter" value="decorator" />
</mapper>
<mapper
class="com.opensymphony.module.sitemesh.mapper.PrintableDecoratorMapper">
<param name="decorator" value="none" />
<param name="parameter.name" value="printable" />
<param name="parameter.value" value="true" />
</mapper>
<mapper class="com.opensymphony.module.sitemesh.mapper.PageDecoratorMapper">
<param name="property.1" value="meta.decorator" />
<param name="property.2" value="decorator" />
</mapper>
<mapper class="com.opensymphony.module.sitemesh.mapper.ConfigDecoratorMapper">
<param name="config" value="${decorators-file}" />
</mapper>
</decorator-mappers>
</sitemesh>
WEB-INF/sitemesh-decorators.xml
<?xml version="1.0" encoding="UTF-8" ?>
<decorators defaultdir="/WEB-INF/sitemesh">
<decorator name="mobile" page="mobile.jsp" />
<decorator name="tablet" page="tablet.jsp" />
<decorator name="desktop" page="desktop.jsp" />
<excludes>
<pattern>*.html*</pattern>
<pattern>*.json*</pattern>
<pattern>*.xml*</pattern>
<pattern>*.download*</pattern>
</excludes>
</decorators>
Templates
WEB-INF/sitemesh/mobile.jsp
<%@ taglib prefix="decorator" uri="http://www.opensymphony.com/sitemesh/decorator"
%><%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"
%><!DOCTYPE HTML>
<html>
<head>
<title>Mobile Template - <decorator:title /></title>
</head>
<body>
<nav class="mobile">
<ul>
<li>Menu 1</li>
<li>Menu 2</li>
</ul>
</nav>
<div id="wrapper">
<decorator:body />
</div>
</body>
</html>
WEB-INF/sitemesh/tablet.jsp
<%@ taglib prefix="decorator" uri="http://www.opensymphony.com/sitemesh/decorator"
%><%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"
%><!DOCTYPE HTML>
<html>
<head>
<title>Tablet Template - <decorator:title /></title>
</head>
<body>
<nav class="tablet">
<ul>
<li>Menu 1</li>
<li>Menu 2</li>
<li>Menu 3</li>
<li>Menu 4</li>
</ul>
</nav>
<div id="wrapper">
<decorator:body />
</div>
</body>
</html>
WEB-INF/sitemesh/desktop.jsp
<%@ taglib prefix="decorator" uri="http://www.opensymphony.com/sitemesh/decorator"
%><%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"
%><!DOCTYPE HTML>
<html>
<head>
<title>Desktop Template - <decorator:title /></title>
</head>
<body>
<nav class="desktop">
<ul>
<li>Menu 1</li>
<li>Menu 2</li>
<li>Menu 3</li>
<li>Menu 4</li>
<li>Menu 5</li>
<li>Menu 6</li>
</ul>
</nav>
<div id="wrapper">
<decorator:body />
</div>
</body>
</html>
Mapping
HomeController.java
@RequestMapping("/")
public String home(Device device) {
if (device.isMobile()) {
return "mobile/home/index";
} else if (device.isTablet()) {
return "tablet/home/index";
} else {
return "desktop/home/index";
}
}
WEB-INF/views/mobile/home/index.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"
%><head>
<meta name="decorator" content="mobile" />
<title>Mobile Home Page</title>
</head>
<body>
<p>Mobile Page Content</p>
</body>
WEB-INF/views/tablet/home/index.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"
%><head>
<meta name="decorator" content="tablet" />
<title>Tablet Home Page</title>
</head>
<body>
<p>Tablet Page Content</p>
</body>
WEB-INF/views/desktop/home/index.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"
%><head>
<meta name="decorator" content="desktop" />
<title>Desktop Home Page</title>
</head>
<body>
<p>Desktop Page Content</p>
</body>