SSM框架整合笔记(三)视图解析器Tiles、FreeMarker配置

前言

  在MVC开发模式下,View离不开模板引擎,在Java中模板引擎使用最多的就是JSP、Velocity和FreeMarker。在配置框架的过程中,一般的系统中的前端页面中总是有一些通用的头部、底部或者菜单栏,最原始的方法当然是为每个HTML页面添加需要引入的css或者js等公用资源,但是这种方式似乎太难以维护。

使用JSP的话,尽管JSP存在的时间很长、也特别像HTML,但是由于夹杂了各种标签库,显得特别混乱,因此在传统的单机应用中,在了解了常用的几个前端模板引擎(视图解析器),如Freemarker、Thymeleaf、Velocity、Tiles等:

  • Velocity:自面世以来就以语法简单著称,其写法非常接近Java语法,学习成本低,而且其简单的语法给开发人员带来了很大的自由度,能够自由发挥;
  • FreeMarker: 使用后缀为ftl(FreeMarker Template Language,FTL)和html 的模板,处理动态网页优势比较强,由于不能写Java代码,可以实现严格的MVC分离;
  • Thymeleaf: 该模板会改变普通HTML的写法,需要在HTML中添加一些属性,能够按照原始的方式进行编辑甚至渲染,而不必经过任何类型的处理器;
  • JSP: JSP不是真正的HTML,但是JSP规范和Servlet规范是紧密耦合的,这也限制了它只能用在基于Servlet的Web应用之中。
  • Tiles:Apache Tiles,定义适用于所有页面的通用页面布局。但是Tiles的模板是需要和jsp结合的,内容页和模板页是独立的页面,因此不会影响HTML内容页的写法。

本文内容:使用Tiles、FreeMarker配置前端模板引擎。

相关文章

demo下载地址

该项目持续更新中,会在代码以及该文档里面详细注释和介绍。
项目托管在码云开源平台上,持续更新项目源码链接:

https://gitee.com/nelucifer/ssm-note,点击克隆/下载获取该项目。

本文描述的项目版本为v1.0.1,版本源码链接:
https://gitee.com/nelucifer/ssm-note/releases/v1.0.1

注意:如果项目代码内容有变化和本例不太一样的话,请查看项目标签,标签会具体说明,使用方式如下:

ssm在码云上的tags-201932162926

本文内容

在一个项目中可以配置多个视图解析器,如Tiles、FreeMarker等可以同时配置,为了使得模板简洁和统一,本文仅介绍Tiles和FreeMarker的单独配置。

  • 一、XML方式配置Tiles;
  • 二、配置FreeMarker模板引擎;
  • 三、FreeMarker拆分和复用页面;

一、配置Tiles

0. pom.xml引入依赖

pom.xml 添加配置如下:

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
<!--<properties>-->
<tiles.version>3.0.4</tiles.version>
<!--</properties>-->
<!-- tiles -->
<dependency>
<groupId>org.apache.tiles</groupId>
<artifactId>tiles-extras</artifactId>
<version>${tiles.version}</version>
<exclusions>
<exclusion>
<artifactId>commons-beanutils</artifactId>
<groupId>commons-beanutils</groupId>
</exclusion>
<exclusion>
<artifactId>jcl-over-slf4j</artifactId>
<groupId>org.slf4j</groupId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.apache.tiles</groupId>
<artifactId>tiles-servlet</artifactId>
<version>${tiles.version}</version>
</dependency>
<dependency>
<groupId>org.apache.tiles</groupId>
<artifactId>tiles-jsp</artifactId>
<version>${tiles.version}</version>
</dependency>
<dependency>
<groupId>org.apache.tiles</groupId>
<artifactId>tiles-core</artifactId>
<version>${tiles.version}</version>
</dependency>
<dependency>
<groupId>org.apache.tiles</groupId>
<artifactId>tiles-api</artifactId>
<version>${tiles.version}</version>
</dependency>

1. spring-mvc.xml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
<!--spring-mvc 视图解析器-->
<bean id="viewResolver" class="org.springframework.web.servlet.view.tiles3.TilesViewResolver"/>

<bean class="org.springframework.web.servlet.view.ContentNegotiatingViewResolver">
<property name="contentNegotiationManager" ref="contentNegotiationManager"/>
<property name="defaultViews">
<bean class="org.springframework.web.servlet.view.json.MappingJackson2JsonView"/>
</property>
</bean>

<!-- 模板引擎Tiles -->
<bean id="tilesConfigurer" class="org.springframework.web.servlet.view.tiles3.TilesConfigurer">
<property name="definitions">
<list>
<!-- tiles的模板组件组装配置 -->
<value>/WEB-INF/views/*-tiles.xml</value>
</list>
</property>
</bean>

2. 创建Tiles模板组件

分析下我们要展示的页面内容,具体布局如下图:
其中 header、nav-bar、menu、content(body)、footer可以提取出来,如下:

  • header: 主要用来引入外部文件【header.jsp】;
  • nav-bar:主要用来添加导航栏【nav-bar.jsp】;
  • menu: 菜单模块【menu.jsp】;
  • content: 内容模块,是页面主体【动态添加的内容】;
  • footer: 底部声明等【footer.jsp】;

ssm内容Tiles分析-20193216310

具体思路如下,首先在pom.xml添加Tiles的相关依赖,在spring-mvc.xml中添加视图解析器的配置,在default-tiles.xml中组装主模板和各个页面,即可。详细步骤如下:

1. pom.xml

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
<properties>
<tiles.version>3.0.4</tiles.version>
</properties>
<!-- Apache Tiles -->
<dependency>
<groupId>org.apache.tiles</groupId>
<artifactId>tiles-extras</artifactId>
<version>${tiles.version}</version>
<exclusions>
<exclusion>
<artifactId>commons-beanutils</artifactId>
<groupId>commons-beanutils</groupId>
</exclusion>
<exclusion>
<artifactId>jcl-over-slf4j</artifactId>
<groupId>org.slf4j</groupId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.apache.tiles</groupId>
<artifactId>tiles-servlet</artifactId>
<version>${tiles.version}</version>
</dependency>
<dependency>
<groupId>org.apache.tiles</groupId>
<artifactId>tiles-jsp</artifactId>
<version>${tiles.version}</version>
</dependency>
<dependency>
<groupId>org.apache.tiles</groupId>
<artifactId>tiles-core</artifactId>
<version>${tiles.version}</version>
</dependency>
<dependency>
<groupId>org.apache.tiles</groupId>
<artifactId>tiles-api</artifactId>
<version>${tiles.version}</version>
</dependency>

2. spring-mvc.xml

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
<!-- tiles视图解释器 -->
<bean id="tilesViewResolver" class="org.springframework.web.servlet.view.tiles3.TilesViewResolver">
<property name="order" value="1"></property>
<property name="viewClass" value="org.springframework.web.servlet.view.tiles3.TilesView"/>
</bean>

<bean class="org.springframework.web.servlet.view.ContentNegotiatingViewResolver">
<property name="contentNegotiationManager" ref="contentNegotiationManager"/>
<!-- 视图解析器 -->
<property name="viewResolvers">
<list>
<ref bean="beanNameViewResolver" />
<ref bean="tilesViewResolver" />
</list>
</property>
<property name="defaultViews">
<bean class="org.springframework.web.servlet.view.json.MappingJackson2JsonView"/>
</property>
</bean>

<!-- 模板引擎Tiles配置 -->
<bean id="tilesConfigurer" class="org.springframework.web.servlet.view.tiles3.TilesConfigurer">
<property name="definitions">
<list>
<value>/WEB-INF/views/*-tiles.xml</value>
</list>
</property>
<property name="preparerFactoryClass" value="org.springframework.web.servlet.view.tiles3.SpringBeanPreparerFactory" />
</bean>

3. 组装各页面组件

default-tiles.xml内容如下:

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
<?xml version="1.0" encoding="UTF-8"?>
<!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>
<!-- 定义base Tile,主布局 -->
<definition name="base" template="/templates/base.jsp">
<!-- 定义属性 -->
<put-attribute name="header" value="/templates/components/header.jsp" />
<put-attribute name="nav" value="/templates/components/nav-bar.jsp" />
<put-attribute name="menu" value="/templates/components/menu.jsp" />
<put-attribute name="content" value="" />
<put-attribute name="footer" value="/templates/components/footer.jsp" />
</definition>

<!-- 定义base Tile -->
<definition name="empty" template="/templates/empty.jsp">
<!-- 定义属性 -->
<put-attribute name="header" value="/templates/components/header.jsp" />
</definition>

<!-- 扩展base Tile -->
<definition name="/home" extends="base">
<put-attribute name="content" value="/front-end/welcome.jsp" />
</definition>
<!-- 登录页 -->
<definition name="/login" extends="empty">
<put-attribute name="content" value="/front-end/system/index.jsp" />
</definition>
</tiles-definitions>

4. 主页面 base.jsp

以下为主页面模板配置,引入的其他页面和其他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
<%@ taglib prefix="tiles" uri="http://tiles.apache.org/tags-tiles" %>
<%--
Created by IntelliJ IDEA.
Description: 该模板就是包含所有的模板(有导航栏、菜单栏、内容、页脚)
User: Mr.wang
Date: 2017/6/21
Time: 22:18
To change this template use File | Settings | File Templates.
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title></title>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport"
content="width=device-width, initial-scale=1,user-scalable=no">
<meta name="format-detection" content="telephone=no"/>
<tiles:insertAttribute name="header"/>
<style>
自定义样式...
</style>
</head>
<body class="scroll-bar hold-transition skin-blue sidebar-mini">
<div class="wrapper">
<div>
<header class="main-header">
<tiles:insertAttribute name="nav"/>
</header>
<aside class="main-sidebar">
<tiles:insertAttribute name="menu"/>
</aside>
<section id="lucifer_content" class="content-wrapper">
<tiles:insertAttribute name="content"/>
</section>
<div class="navbar-fixed-bottom">
<footer class="main-footer" style="margin-left: 260px">
<tiles:insertAttribute name="footer"/>
</footer>
</div>
</div>
</div>
</body>
</html>

二、配置FreeMarker模板引擎

0. pom.xml引入依赖

pom.xml 添加配置如下:

1
2
3
4
5
6
7
8
9
<properties>
<freemarker.version>2.3.20</freemarker.version>
</properties>
<!-- FreeMarker -->
<dependency>
<groupId>org.freemarker</groupId>
<artifactId>freemarker</artifactId>
<version>${freemarker.version}</version>
</dependency>

1. spring-mvc.xml

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
<!--spring-mvc 视图解析器-->
<bean class="org.springframework.web.servlet.view.ContentNegotiatingViewResolver">
<property name="contentNegotiationManager" ref="contentNegotiationManager"/>
<!-- 视图解析器 -->
<property name="viewResolvers">
<list>
<ref bean="beanNameViewResolver" />
<!-- 模板引擎中添加FreeMarker配置 -->
<ref bean="freeMarkerViewResolver" />
</list>
</property>
<property name="defaultViews">
<bean class="org.springframework.web.servlet.view.json.MappingJackson2JsonView"/>
</property>
</bean>
<!-- FreeMarker 模板引擎 -->
<bean id="freeMarkerViewResolver" class="org.springframework.web.servlet.view.freemarker.FreeMarkerViewResolver">
<property name="viewClass">
<value>org.springframework.web.servlet.view.freemarker.FreeMarkerView</value>
</property>
<!-- 识别为FreeMarker页面的文件后缀 -->
<property name="suffix" value=".html"/>
<property name="cache" value="false" />
<property name="contentType" value="text/html;charset=utf-8"/>
<property name="order" value="1"/>
<!-- 在FreeMarker页面中使用request对象 -->
<property name="exposeRequestAttributes" value="true" />
<property name="exposeSessionAttributes" value="true" />
<property name="exposeSpringMacroHelpers" value="true" />
<property name="requestContextAttribute" value="rc"/>
</bean>

<!-- FreeMarker 模板引擎配置 -->
<bean id="freemarkerConfig" class="org.springframework.web.servlet.view.freemarker.FreeMarkerConfigurer">
<property name="templateLoaderPaths">
<list>
<value>/front-end</value>
<value>/</value>
</list>
</property>
<property name="defaultEncoding" value="utf-8"/>
<property name="freemarkerSettings"><!-- 设置FreeMarker环境属性 -->
<props>
<prop key="template_update_delay">5</prop><!--刷新模板的周期,单位为秒 -->
<prop key="default_encoding">UTF-8</prop><!--模板的编码格式 -->
<prop key="locale">zh_CN</prop><!-- 本地化设置,设置默认地区 -->
<prop key="template_exception_handler">rethrow</prop>
<prop key="datetime_format">yyyy-MM-dd HH:mm:ss</prop>
<prop key="time_format">HH:mm:ss</prop>
<prop key="number_format">#.####</prop><!-- 设置默认数字输出格式 -->
<prop key="boolean_format">true,false</prop><!-- 设置默认布尔值输出格式 -->
<prop key="whitespace_stripping">true</prop>
<prop key="tag_syntax">auto_detect</prop>
<prop key="url_escaping_charset">UTF-8</prop>
</props>
</property>
</bean>

2. web.xml

注意: FreeMarker配置首页为html页面的话,需要进行特别的配置,需要修改web.xml中设置的登录页,否则直接配置index.html的话会导致页面中的FreeMarker配置无效,因此需修改web.xmlMainController.java,这块需要注意!

web.xml

1
2
3
4
<!-- 默认进入页面,一般为登录页 -->
<welcome-file-list>
<welcome-file>/</welcome-file>
</welcome-file-list>

MainController.java

1
2
3
4
5
6
7
8
9
10
11
/**
* @Author Mr.wang
* @Description // 登录页,控制启动时跳转
* @Date 2019/3/2 23:39
* @Param [request, response]
* @return
**/
@RequestMapping(value = "/", method = RequestMethod.GET)
public String index(HttpServletRequest request, HttpServletResponse response) {
return "index";
}

3. 组装FreeMarker页面

在SSM项目中配置FreeMarker模板引擎时,需要使用特定的指令来配置模板和组装页面组件,页面结构如下:

1
2
3
4
5
6
7
8
9
10
11
|---[front-end](前端页面)
|---|---index.html(登录页)
|---|---welcome.html(首页)
|---[tempaltes](模板文件)
|---|---[components](模板组件)
|---|---|---footer.html(页脚组件)
|---|---|---header.html(页首组件)
|---|---|---menu.html(菜单组件)
|---|---|---nav-bar.html(导航栏组件)
|---|---empty.html(没有菜单的主模板,如登录页使用)
|---|---main.html(包含菜单和页脚的主模板,如首页使用)

具体配置方式如下:

empty.html

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<#macro empty>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="Pragma" content="no-cache">
<#include "../templates/components/header.html">
<style>
自定义的样式
</style>
</head>
<body>
<!-- 插入内容页 -->
<#nested>
</body>
</html>
</#macro>

empty.html

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
<!DOCTYPE html>
<#macro layout>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="Pragma" content="no-cache">
<#include "../templates/components/header.html">
<style>
自定义的样式
</style>
</head>
<body class="scroll-bar hold-transition skin-blue sidebar-mini">
<div class="wrapper">
<div>
<header class="main-header">
<#include "../templates/components/nav-bar.html">
</header>
<aside class="main-sidebar">
<#include "../templates/components/menu.html">
</aside>
<section id="lucifer_content" class="content-wrapper">
<!-- 在这里嵌入主题内容 -->
<#nested>
</section>
<div class="navbar-fixed-bottom">
<footer class="main-footer" style="margin-left: 260px">
<#include "../templates/components/footer.html">
</footer>
</div>
</div>
</div>
</body>
<script>
var InitFrame = (function () {
var setTitle = function (title) {
title && $(document).attr("title", title)
};
return {setTitle: setTitle};
})()
InitFrame.setTitle("SSM框架整合");
</script>
</html>
</#macro>

index.htmlwelcome.html页面引用模板方式主要如下:

1
2
3
4
5
6
7
8
9
10
11
<!-- 引入布局指令的命名空间 -->
<#import "templates/main.html" as main>
<!-- 调用布局指令 -->
<@main.layout>
<!-- 下面的这些内容会自动嵌入到layout指令的nested块中 -->
<h1>SSM框架整合笔记</h1>
<hr>
<div class="text-center">
<h4>~~欢迎关注下方微信公众号,记录javaweb常见的问题和相关技术,欢迎交流学习~~</h4>
</div>
</@main.layout>

至此,FreeMarker配置完成,详细注释和配置参考项目开头源码下载地址。

分享

欢迎扫描下方二维码,关注weyoung公众号,一起交流学习~~

个人微信公众号

更多联系方式

平台 链接
预览项目: https://nelucifer.gitee.io/
个人微信公众号: weyoung
segmentfault: https://segmentfault.com/u/nelucifer
CSDN: https://me.csdn.net/wlx001
简书: https://www.jianshu.com/u/99211cc23788
掘金: https://juejin.im/user/59b08c575188250f4850e80e