表现层为了减少手工写 jsp 页面代码的工作量,出现了许多不同的技术方案,Tiles, SiteMesh, Velocity, FreeMarker 等。这里选用 Tiles3/Sitemesh 负责自定义的 header, body, footer 组装,jsp 页面加入 bootstrap, jQuery ,暂时不用 Velocity/FreeMarker 模板。

Tiles

applicationContext.xml

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
<bean id="tilesConfigurer" class="org.springframework.web.servlet.view.tiles3.TilesConfigurer">
    <property name="definitions">
        <list>
            <value>/WEB-INF/defs/general.xml</value>
        </list>
    </property>
</bean>

<bean id="urlViewResolver" class="org.springframework.web.servlet.view.UrlBasedViewResolver">
    <property name="viewClass" value="org.springframework.web.servlet.view.tiles3.TilesView" />
    <property name="order" value="1" />
</bean>

<mvc:resources mapping="/resources/**" location="/resources/" />

注:不同的 ViewResolver 可以添加 order 属性值,运行时从小到大查找。TilesView 2/3 内置 JSTL 支持。css/js 放在 webapp/resources 目录下。

general.xml

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
<?xml version="1.0" encoding="ISO-8859-1" ?>
<!DOCTYPE tiles-definitions PUBLIC
        "-//Apache Software Foundation//DTD Tiles Configuration 3.0//EN"
        "http://tiles.apache.org/dtds/tiles-config_3_0.dtd">

<tiles-definitions>
    <definition name="common" template="/WEB-INF/layout/classic.jsp">
        <put-attribute name="footer" value="/WEB-INF/layout/footer.jsp" />
    </definition>

    <definition name="index" extends="common">
        <put-attribute name="title" value="Java Blog Aggregator" />
        <put-attribute name="body" value="/WEB-INF/jsp/index.jsp" />
        <put-attribute name="current" value="index" />
    </definition>
</tiles-definitions>

classic.jsp

 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
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@ taglib uri="http://www.springframework.org/tags" prefix="spring"%>
<!DOCTYPE html>
<html>
<head>
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">

    <link rel="stylesheet" href="/resources/css/bootstrap.min.css">
    <script src="/resources/js/jquery-1.11.0.min.js"></script>
    <script src="/resources/js/bootstrap.min.js"></script>

    <title><tiles:getAsString name="title" /></title>
</head>
<body>
<div class="container">

    <!-- Static navbar -->
    <div class="navbar navbar-default" role="navigation">
        <div class="container-fluid">
            <div class="navbar-header">
                <button type="button" class="navbar-toggle collapsed" data-toggle="collapse" data-target=".navbar-collapse">
                    <span class="sr-only">Toggle navigation</span>
                    <span class="icon-bar"></span>
                    <span class="icon-bar"></span>
                    <span class="icon-bar"></span>
                </button>
                <a class="navbar-brand" href="<spring:url value="/" />">Spitter</a>
            </div>
            <div class="navbar-collapse collapse">
                <ul class="nav navbar-nav">
                    <li class="active"><a href="<spring:url value="/" />">Home</a></li>
                    <li><a href="#">Link</a></li>
                    <li><a href="#">Link</a></li>
                    <li class="dropdown">
                        <a href="#" class="dropdown-toggle" data-toggle="dropdown">Dropdown <span class="caret"></span></a>
                        <ul class="dropdown-menu" role="menu">
                            <li><a href="#">Action</a></li>
                            <li><a href="#">Another action</a></li>
                            <li><a href="#">Something else here</a></li>
                            <li class="divider"></li>
                            <li class="dropdown-header">Nav header</li>
                            <li><a href="#">Separated link</a></li>
                            <li><a href="#">One more separated link</a></li>
                        </ul>
                    </li>
                </ul>
                <ul class="nav navbar-nav navbar-right">
                    <li class="active"><a href="./">Default</a></li>
                    <li><a href="../navbar-static-top/">Static top</a></li>
                    <li><a href="../navbar-fixed-top/">Fixed top</a></li>
                </ul>
            </div><!--/.nav-collapse -->
        </div><!--/.container-fluid -->
    </div>

</div> <!-- /container -->

<tiles:insertAttribute name="body" />

<br /><br />

<tiles:insertAttribute name="footer" />
</body>
</html>

footer.jsp

1
2
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<center>@copyright Joseph Pei 2014</center>

index.jsp

1
2
3
<%@ page contentType="text/html;charset=UTF-8" language="java" %>

<h1>hello world</h1>

然后 index 页面就可以看到 bootstrap navbar 了

上面的活动条目跟随页面不同而不同,注意 general.xml 的 current 属性,页面中设置如下

1
2
3
<tilesx:useAttribute name="current"/>

<li class="${current == 'index' ? 'active' : '' }">

Sitemesh

pom.xml

1
2
3
4
5
<dependency>
	<groupId>opensymphony</groupId>
	<artifactId>sitemesh</artifactId>
	<version>2.4.2</version>
</dependency>

web.xml

1
2
3
4
5
6
7
8
9
<filter>
    <filter-name>sitemesh</filter-name>
    <filter-class>com.opensymphony.sitemesh.webapp.SiteMeshFilter</filter-class>
</filter>

<filter-mapping>
    <filter-name>sitemesh</filter-name>
    <url-pattern>/*</url-pattern>
</filter-mapping>

WEB-INF 目录下新建 decorators.xml 和 decorators 目录

decorators.xml

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
<?xml version="1.0" encoding="UTF-8"?>

<decorators defaultdir="/WEB-INF/decorators">
    <!-- Any urls that are excluded will never be decorated by Sitemesh -->
    <excludes>
        <pattern>/about.jsp</pattern>
        <pattern>/static/*</pattern>
    </excludes>

    <decorator name="main-layout" page="main-layout.jsp">
        <pattern>/*</pattern>
    </decorator>
</decorators>

decorators/main-layout.jsp

 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
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@ taglib uri="http://www.opensymphony.com/sitemesh/decorator" prefix="sitemesh" %>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>

<c:set var="ctx" value="${pageContext.request.contextPath}" />

<!DOCTYPE html>
<html>
<head>
    <title><sitemesh:title/></title>
    <meta charset="utf-8">
    <link rel="stylesheet" href="/static/css/bootstrap.min.css">
    <script src="/static/js/jquery-1.11.0.min.js"></script>
    <script src="/static/js/jquery.validate.min.js"></script>
    <script src="/static/js/bootstrap.min.js"></script>

    <sitemesh:head/>
</head>
<body>
<div class="container">
    <%@ include file="/WEB-INF/decorators/navbar.jsp"%>
    <div id="content">
        <sitemesh:body/>
    </div>
    <%@ include file="/WEB-INF/decorators/footer.jsp"%>
</div>
</body>
</html>

navbar.jsp

 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
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<!-- Static navbar -->
<div class="navbar navbar-default" role="navigation">
    <div class="container-fluid">
        <div class="navbar-header">
            <button type="button" class="navbar-toggle collapsed" data-toggle="collapse" data-target=".navbar-collapse">
                <span class="sr-only">Toggle navigation</span>
                <span class="icon-bar"></span>
                <span class="icon-bar"></span>
                <span class="icon-bar"></span>
            </button>
            <a class="navbar-brand" href="#">Spitter</a>
        </div>
        <div class="navbar-collapse collapse">
            <ul class="nav navbar-nav">
                <li class="active"><a href="#">Link</a></li>
                <li><a href="#">Link</a></li>
                <li><a href="#">Link</a></li>
                <li class="dropdown">
                    <a href="#" class="dropdown-toggle" data-toggle="dropdown">Dropdown <span class="caret"></span></a>
                    <ul class="dropdown-menu" role="menu">
                        <li><a href="#">Action</a></li>
                        <li><a href="#">Another action</a></li>
                        <li><a href="#">Something else here</a></li>
                        <li class="divider"></li>
                        <li class="dropdown-header">Nav header</li>
                        <li><a href="#">Separated link</a></li>
                        <li><a href="#">One more separated link</a></li>
                    </ul>
                </li>
            </ul>
        </div><!--/.nav-collapse -->
    </div><!--/.container-fluid -->
</div>

index.jsp 示例,可以看到几乎感觉不到 sitemesh 的存在

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c"%>
<%@taglib prefix="sf" uri="http://www.springframework.org/tags/form"%>
<html>
<head>
    <title>Home Page</title>
</head>
<body>
<div class="h1">Welcome to Spitter</div>
<div class="row">
    <div class="col-sm-8">
        ...
    </div>

    <div class="col-sm-3">
        ...
    </div>
</div>

</body>
</html>