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/