一、模板引擎Thymeleaf
。
1)资源定位(模板来源 ):
通用资源抽象
文件资源: File
ClassPath资源: ClassLoader
统一资源: URL
Web资源: ServletContext
Spring 资源抽象:
Spring 资源: Resource
2)渲染上下文(变量来源 )
不同的实现
Context :Thyemeaf 渲染上下文
Model :Spring Web MVC 模型
Attribute :Servlet 上下文
3)模板引擎(模板渲染)
ITemplateEngine 实现
TemplateEngine :Thymeleaf 原生实现
SpringTemplateEngine :Spring 实现
SpringWebFluxTemplateEngine :Spring WebFlux 实现
二、Thymeleaf 与 Spring 资源整合
这里以多模块构建工程。springboot-view。
pom.xml 继承 父 pom.xml。
父 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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<packaging>pom</packaging>
<modules>
<module>springboot-view</module>
</modules>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.1.0.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.example</groupId>
<artifactId>springbootlearn</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>springbootlearn</name>
<description>Demo project for Spring Boot</description>
<repositories>
<repository>
<id>central</id>
<url>http://maven.aliyun.com/nexus/content/groups/public</url>
</repository>
</repositories>
<pluginRepositories>
<pluginRepository>
<id>central</id>
<url>http://maven.aliyun.com/nexus/content/groups/public</url>
</pluginRepository>
</pluginRepositories>
<properties>
<java.version>1.8</java.version>
<docker.image.prefix>springboot</docker.image.prefix>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<scope>runtime</scope>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
</dependencies>
<build>
</build>
</project>
springboot-view的pom.xml引入thymeleaf相关依赖:
<!-- thymeleaf-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
<packaging>war</packaging>
新建一个 Thymeleaf 引导类:
package com.example.web.template.engine;
import org.apache.tomcat.util.http.fileupload.IOUtils;
import org.springframework.core.io.DefaultResourceLoader;
import org.springframework.core.io.Resource;
import org.springframework.core.io.ResourceLoader;
import org.thymeleaf.context.Context;
import org.thymeleaf.spring5.SpringTemplateEngine;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
/**
* Thymeleaf 引导类
*/
public class ThymeleafTemplateEngineBootstrap {
public static void main(String[] args) throws IOException {
// 构建引擎
SpringTemplateEngine templateEngine = new SpringTemplateEngine(); // 创建渲染上下文
Context context = new Context();
context.setVariable("demomessage", "hello,Thymeleaf");
// 模板的内容,可通过文件方式或者读取
// 读取内容从 templates/thymeleaf/hellothymeleaf.html
// ResourceLoader
ResourceLoader resourceLoader = new DefaultResourceLoader();
// classpath:/templates/thymeleaf/hellothymeleaf.html Resource
Resource resource = resourceLoader.getResource("classpath:/templates/thymeleaf/hellothymeleaf.html");
File templateFile = resource.getFile();
// 文件流
FileInputStream fileInputStream = new FileInputStream(templateFile);
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
//copy
IOUtils.copy(fileInputStream, byteArrayOutputStream);
fileInputStream.close();
// 模板的内容,可通过文件方式或者读取
// String content = "<p th:text=\"${demomessage}\">!!!</p>";
String content = byteArrayOutputStream.toString("UTF-8");
// 渲染(处理)结果
String result = templateEngine.process(content, context);
// 输出渲染(处理)结果
System.out.println(result);
}
}
运行即可。
三、视图处理
1、SpringWebMVC 视图组件
ViewResolver :视图解析器
View : 视图组件
DispatcherServlet :总控
2、Thymeleaf 整合 Spring Web MVC
ViewResolver : ThymeleafViewResolver
View : ThymeleafView
ITemplateEngine : SpringTemplateEngine
交互流程:
DispatcherServlet->ViewResolver(如果多个,优先级处理)->View->DispatcherServlet->视图内容(html、xml等)
多视图处理器并存
1) ThymeleafViewResolver 视图处理器:
新建一个HelloThymeleafController:
package com.example.web.controller;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.ModelAttribute;
/**
* {@link Controller}
*/
@Controller
public class HelloThymeleafController {
@GetMapping("/hellothymeleaf")
public String helloThymeleaf() {
return "hellothymeleaf";
}
@ModelAttribute("demomessage")
public String message() {
return "demomessage,thymeleaf.......";
}
}
新建一个SpringBootViewBootstrap:
package com.example.web.bootstrap;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
/**
* springboot 视图引导类
*/
@SpringBootApplication(scanBasePackages = "com.example.web")
public class SpringBootViewBootstrap {
public static void main(String[] args) {
SpringApplication.run(SpringBootViewBootstrap.class, args);
}
}
新建一个application.properties:
Thymeleaf相关属性可以查看
package org.springframework.boot.autoconfigure.thymeleaf;
下的ThymeleafProperties.java
文件。
在application.properties中修改属性值。
如:
#thymeleaf
spring.thymeleaf.prefix=classpath:/templates/thymeleaf/
spring.thymeleaf.suffix=.html
# 取消缓存
spring.thymeleaf.cache=false
新建一个hellothymeleaf.html:
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<body>
<p th:text="${demomessage}">~~~~</p>
</body>
</html>
2)InternalResourceViewResolver视图处理器:
WebMvcConfig:
package com.example.web.config;
import org.springframework.boot.web.embedded.tomcat.TomcatServletWebServerFactory;
import org.springframework.boot.web.server.WebServerFactoryCustomizer;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.Ordered;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ViewResolver;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
import org.springframework.web.servlet.view.InternalResourceViewResolver;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.File;
/**
* Spring web mvc 配置类
*/
@Configuration
//@EnableWebMvc
public class WebMvcConfig implements WebMvcConfigurer {
@Bean
public ViewResolver myViewResolver() {
InternalResourceViewResolver viewResolver = new InternalResourceViewResolver();
viewResolver.setPrefix("/WEB-INF/jsp/");
viewResolver.setSuffix(".jsp");
// 因为ThymeleafViewResolver ORDER Ordered.LOWEST_PRECEDENCE - 5
// 所以若要在Thymeleaf之前,order比它小即可。
viewResolver.setOrder(Ordered.LOWEST_PRECEDENCE - 10);
return viewResolver;
}
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(new HandlerInterceptor() {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
System.out.println("拦截中。。。");
return true;
}
});
}
// 修复 Maven 多模块 JSP 定位问题。
// Maven多模块,jsp无法读取。无法找到模块下的。src/main/webapp。
// 因为会读到的路径是/Users/xxx/develop/springbootlearn/src/main/webapp
// 而不是期望的 /Users/xxx/develop/springbootlearn/springboot-view/src/main/webapp
// 加上这个方法以解决。
@Bean
public WebServerFactoryCustomizer<TomcatServletWebServerFactory> customizer() {
return (factory) -> {
factory.addContextCustomizers((context) -> {
String relativePath = "springboot-view/src/main/webapp";
// 相对于 user.dir = /Users/xxx/develop/springbootlearn
File docBaseFile = new File(relativePath);
if(docBaseFile.exists()) {
// 路径是否存在
// 解决 Maven 多模块 JSP 无法读取的问题
context.setDocBase(docBaseFile.getAbsolutePath());
}
}
);
};
}
}
HelloThymeleafController:
package com.example.web.controller;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
/**
* {@link Controller}
*/
@Controller
public class HelloThymeleafController {
@RequestMapping("")
public String index(@RequestParam(required = false,defaultValue = "0") int value, Model model) {
return "index";
}
@GetMapping("/hellothymeleaf")
public String helloThymeleaf() {
return "hellothymeleaf";
}
@ModelAttribute("demomessage")
public String message() {
return "demomessage,thymeleaf.......";
}
}
HelloThymeleafControllerAdvice:
package com.example.web.controller;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
@ControllerAdvice(assignableTypes = HelloThymeleafController.class)
public class HelloThymeleafControllerAdvice {
@ModelAttribute("acceptLanguage")
public String acceptLanguage(@RequestHeader("Accept-Language") String acceptLanguage){
return acceptLanguage;
}
@ModelAttribute("jsessionId")
public String jsessionId(@CookieValue(value = "JSESSIONID",required = false) String jsessionId){
return jsessionId;
}
@ModelAttribute("hellomessage")
public String message(){
return "一段hellomessage。。。";
}
@ExceptionHandler(Throwable.class)
public ResponseEntity<String> onException(Throwable throwable) {
return ResponseEntity.ok(throwable.getMessage());
}
}
```在src目录下,新建webapp目录。
```bash
└── src
├── main
├── resources
└── webapp
└── WEB-INF
└── jsp
└── index.jsp
index.jsp:
<jsp:root xmlns:jsp="http://java.sun.com/JSP/Page" version="2.0">
<body>
<hellomessage>${hellomessage}</hellomessage>
<language>${acceptLanguage}</language>
<jsessionId>${jsessionId}</jsessionId>
</body>
</jsp:root>
如果不在上面WebMvcConfig文件中加上处理方法:
@Bean
public WebServerFactoryCustomizer<TomcatServletWebServerFactory> customizer() {
// ...省略
}
而通过maven插件打包,访问war包也可以。
在springboot-view的pom.xml加入:
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
运行:
mvn -Dmaven.test.skip -U clean package
java -jar target/springboot-view-0.0.1-SNAPSHOT.war
在浏览器输入localhost:8080即可。