Servlet + Spring 搭建Thymeleaf模板引擎小案例
Servlet + Spring 搭建Thymeleaf模板引擎小案例
前言
Thymeleaf模板引擎比较倾向于前端,了解过一点前端的人都会很快上手的。之所以不用JSP模板,是因为他还是原生的Java代码。换句话来说,就是Thymeleaf可以直接查看效果无需启动服务器,反之JSP就不行,必须依赖于服务器。这两种模板属于同一个方向,技术应用是要结合应用场景的。如果单纯从学习角度来看,学习哪个技术都没有错。但如果是要做产品,做项目,那技术选型就非常关键了。
正文
-
项目目录:
- pom.xml文件
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>vip.wulang</groupId>
<artifactId>thymeleaf</artifactId>
<version>1.0-SNAPSHOT</version>
<packaging>war</packaging>
<properties>
<mysql.version>5.1.34</mysql.version>
<spring.version>4.3.0.RELEASE</spring.version>
<hibernate.version>5.1.0.Final</hibernate.version>
<druid.version>1.1.10</druid.version>
<jpa.version>1.10.4.RELEASE</jpa.version>
<test.version>4.12</test.version>
<common.version>3.3.2</common.version>
<servlet.version>3.1.0</servlet.version>
<fastjson.version>1.2.47</fastjson.version>
<slf4j.version>1.7.25</slf4j.version>
<aspectj.version>1.8.10</aspectj.version>
<validation.version>6.0.13.Final</validation.version>
<thymeleaf.version>3.0.9.RELEASE</thymeleaf.version>
</properties>
<dependencies>
<!-- Spring Framework start -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-beans</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context-support</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-orm</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-tx</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-web</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>${spring.version}</version>
</dependency>
<!-- Spring Framework end -->
<!-- Druid start -->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>${druid.version}</version>
</dependency>
<!-- Druid end -->
<!-- JPA start -->
<dependency>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-jpa</artifactId>
<version>${jpa.version}</version>
<exclusions>
<exclusion>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
</exclusion>
<exclusion>
<groupId>org.springframework</groupId>
<artifactId>spring-aop</artifactId>
</exclusion>
<exclusion>
<groupId>org.springframework</groupId>
<artifactId>spring-beans</artifactId>
</exclusion>
<exclusion>
<groupId>org.springframework</groupId>
<artifactId>spring-tx</artifactId>
</exclusion>
<exclusion>
<groupId>org.springframework</groupId>
<artifactId>spring-orm</artifactId>
</exclusion>
<exclusion>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
</exclusion>
<exclusion>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
</exclusion>
</exclusions>
</dependency>
<!-- JPA end -->
<!-- Hibernate start -->
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-core</artifactId>
<version>${hibernate.version}</version>
</dependency>
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-entitymanager</artifactId>
<version>${hibernate.version}</version>
</dependency>
<!-- Hibernate end -->
<!-- Mysql start -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>${mysql.version}</version>
</dependency>
<!-- Mysql end -->
<!-- Test start -->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>${test.version}</version>
<scope>test</scope>
</dependency>
<!-- Test end -->
<!-- Common start -->
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
<version>${common.version}</version>
</dependency>
<!-- Common end -->
<!-- Servlet start -->
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>${servlet.version}</version>
<scope>provided</scope>
</dependency>
<!-- Servlet end -->
<!-- FastJson start -->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>${fastjson.version}</version>
</dependency>
<!-- FastJson end -->
<!-- Slf4j start -->
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>${slf4j.version}</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-simple</artifactId>
<version>${slf4j.version}</version>
</dependency>
<!-- Slf4j end -->
<!-- Aspectj start -->
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>${aspectj.version}</version>
</dependency>
<!-- Aspectj end -->
<!-- Validation start -->
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-validator</artifactId>
<version>${validation.version}</version>
</dependency>
<!-- Validation end -->
<!-- Thymeleaf start -->
<dependency>
<groupId>org.thymeleaf</groupId>
<artifactId>thymeleaf-spring4</artifactId>
<version>${thymeleaf.version}</version>
</dependency>
<dependency>
<groupId>org.thymeleaf</groupId>
<artifactId>thymeleaf</artifactId>
<version>${thymeleaf.version}</version>
</dependency>
<!-- Thymeleaf end -->
</dependencies>
</project>
- web.xml文件,我是基于Java配置文件的方式,你们也可以使用其他方式,个人喜好
<!DOCTYPE web-app PUBLIC
"-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
"http://java.sun.com/dtd/web-app_2_3.dtd" >
<web-app>
<context-param>
<param-name>contextClass</param-name>
<param-value>org.springframework.web.context.support.AnnotationConfigWebApplicationContext</param-value>
</context-param>
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>vip.wulang.config.MyApplicationContext</param-value>
</context-param>
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<servlet>
<servlet-name>IGTVGController</servlet-name>
<servlet-class>vip.wulang.servlet.IGTVGController</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>IGTVGController</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
</web-app>
- MyApplicationContext.java,Spring容器
package vip.wulang.config;
import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.io.ClassPathResource;
import org.springframework.web.context.ServletContextAware;
import org.thymeleaf.ITemplateEngine;
import org.thymeleaf.TemplateEngine;
import org.thymeleaf.messageresolver.IMessageResolver;
import org.thymeleaf.messageresolver.StandardMessageResolver;
import org.thymeleaf.templatemode.TemplateMode;
import org.thymeleaf.templateresolver.ITemplateResolver;
import org.thymeleaf.templateresolver.ServletContextTemplateResolver;
import javax.servlet.ServletContext;
import java.io.IOException;
import java.util.Properties;
/**
* @author CoolerWu on 2018/11/20.
* @version 1.0
*/
@Configuration
@ComponentScan("vip.wulang")
public class MyApplicationContext implements ApplicationContextAware, ServletContextAware {
private static ApplicationContext applicationContext;
private static ServletContext servletContext;
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
MyApplicationContext.applicationContext = applicationContext;
}
public static ApplicationContext getApplicationContext() {
return applicationContext;
}
@Override
public void setServletContext(ServletContext servletContext) {
MyApplicationContext.servletContext = servletContext;
}
public static ServletContext getServletContext() {
return servletContext;
}
@Bean
public ITemplateResolver templateResolver() {
ServletContextTemplateResolver servletContextTemplateResolver
= new ServletContextTemplateResolver(servletContext);
servletContextTemplateResolver.setTemplateMode(TemplateMode.HTML);
servletContextTemplateResolver.setPrefix("/WEB-INF/templates/");
servletContextTemplateResolver.setSuffix(".html");
servletContextTemplateResolver.setCacheTTLMs(3600000L);
servletContextTemplateResolver.setCacheable(true);
return servletContextTemplateResolver;
}
@Bean
public IMessageResolver messageResolver() throws IOException {
ClassPathResource classPathResource = new ClassPathResource("./home.properties");
Properties properties = new Properties();
properties.load(classPathResource.getInputStream());
StandardMessageResolver standardMessageResolver = new StandardMessageResolver();
standardMessageResolver.setDefaultMessages(properties);
return standardMessageResolver;
}
@Bean
public ITemplateEngine templateEngine(ITemplateResolver templateResolver, IMessageResolver messageResolver) {
TemplateEngine templateEngine = new TemplateEngine();
templateEngine.setTemplateResolver(templateResolver);
templateEngine.setMessageResolver(messageResolver);
return templateEngine;
}
}
首先,笔者实现了两个接口 ApplicationContextAware、ServletContextAware,Spring启动时会自动注入 ApplicationContext、ServletContext。其次从官方文档来看,我们先要配置 ITemplateResolver Bean,其实就是模板解析器,ServletContextTemplateResolver 是该接口的实现类,并在其中设置前缀、后缀、模板类型、是否缓存、缓存多久等信息。再配置 IMessageResolver Bean,就是消息解析器,这个也可以不用配置。默认/WEB-INF/templates/home.html在同一文件夹中找到属性文件中的消息,并使用与模板相同的名称,例如:
- /WEB-INF/templates/home_en.properties 用于英文文本。
- /WEB-INF/templates/home_es.properties 西班牙语文本。
- /WEB-INF/templates/home_pt_BR.properties 用于葡萄牙语(巴西)语言文本。
- /WEB-INF/templates/home.properties 对于默认文本(如果区域设置不匹配)。
而笔者则是设置的是在根目录中,"./home.properties"。然后就到了最重要的一个环节了,ITemplateEngine 这个接口,就是模板引擎,里面包含了之前了模板解析器、消息解析器等。至少需要配置模板解析器。以后要进行页面跳转也是通过模板引擎,我们可以当成模板引擎就是操作按钮,其他的解析器都是已经在模板引擎装配好了。
- IGTVGController.java 配置,继承了 GenericServlet
package vip.wulang.servlet;
import org.thymeleaf.ITemplateEngine;
import org.thymeleaf.TemplateEngine;
import org.thymeleaf.context.WebContext;
import vip.wulang.config.MyApplicationContext;
import javax.servlet.GenericServlet;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
/**
* @author CoolerWu on 2018/11/20.
* @version 1.0
*/
public class IGTVGController extends GenericServlet {
@Override
public void service(ServletRequest req, ServletResponse res) throws ServletException, IOException {
HttpServletRequest request = (HttpServletRequest) req;
HttpServletResponse response = (HttpServletResponse) res;
TemplateEngine templateEngine =
((TemplateEngine) MyApplicationContext.getApplicationContext().getBean(ITemplateEngine.class));
WebContext webContext =
new WebContext(request, response, MyApplicationContext.getServletContext(), request.getLocale());
templateEngine.process("home", webContext, response.getWriter());
}
}
官方文档介绍,Thymeleaf有一个上下文,这个上下文就是接口 IContext,而 IWebContext 扩展了该基础接口,WebContext 就是实现类。
WebContext ctx = new WebContext(request, response, servletContext, request.getLocale());
这四个构造函数参数中只有三个是必需的,因为如果没有指定系统,将使用系统的默认语言环境(尽管在实际应用程序中不应该发生这种情况)。准备好上下文对象后,现在我们可以告诉模板引擎使用上下文处理模板(通过其名称),并将响应编写器传递给它,以便可以将响应写入它:
templateEngine.process("home", webContext, response.getWriter());
- home.properties
home.welcome=Bienvenido a nuestra tienda de comestibles!!!!
- home.html
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
<title>Good Thymes Virtual Grocery</title>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<link rel="stylesheet" type="text/css" media="all"
href="../../css/gtvg.css" th:href="@{/css/gtvg.css}" />
</head>
<body>
<p th:text="#{home.welcome}">Welcome to our grocery store!</p>
</body>
</html>
已经搭建完成了,不过需要注意的是:
<html xmlns:th="http://www.thymeleaf.org">
就是增加一个约束空间。只适用于html模板,也可以不可以不写约束语句,即:
<!DOCTYPE html>
<html>
<head>
<title>Good Thymes Virtual Grocery</title>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<link rel="stylesheet" type="text/css" media="all"
href="../../css/gtvg.css" th:href="@{/css/gtvg.css}" />
</head>
<body>
<p data-th-text="#{home.welcome}">Welcome to our grocery store!</p>
</body>
</html>
这种语句通用于 Thymeleaf 的所有模板。看个人喜好。不启动服务器打开:
启动服务器打开:
结束语
更多详情,了解官方文档:https://www.thymeleaf.org/