jsp作为前端渲染的技术,稳坐多年的霸主地位。但是,众所周知,jsp是强依赖servlet规范的, 并且页面中耦合了很多jstl的标签。极其难以维护。在这期间,出现了很多前端渲染的框架,挑战jsp的地位。thymyleaf是其中佼佼者。
thymeleaf的优势如下:
themyleaf是真正的html代码,不依赖标签库,并且和servlet规范没有强耦合,可以涉足很多jsp无法触及的领域。另外一点,themyleaf实现的前端代码可读性极强。
基于以上优点,我想写这样一篇介绍themeleaf的文章。文章借鉴了很多《spring实战4》的例子
文章共分为以下几部分:
1 .引入依赖
2 .定义pojo类
3 .Controller层代码编写
4 .定义thymeleaf的配置类
5 .定义html文件
1 .引入依赖
<dependency>
<groupId>org.thymeleaf</groupId>
<artifactId>thymeleaf</artifactId>
<version>2.1.6.RELEASE</version>
</dependency>
<dependency>
<groupId>org.thymeleaf</groupId>
<artifactId>thymeleaf-spring4</artifactId>
<version>2.1.6.RELEASE</version>
</dependency>
<!--JSR303校验-->
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-validator</artifactId>
<version>5.3.5.Final</version>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.16.0</version>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
<version>3.5</version>
</dependency>
2 .定义pojo类
*/
@Setter
@Getter
@AllArgsConstructor
public class Spitter {
private Long id;
@NotEmpty
@Length(min = 5,max = 15,message = "{username.size}")
private String username;
@NotEmpty
@Length(min = 5,max = 15,message = "{password.size}")
private String password;
@NotEmpty
@Length(min = 2,max = 30,message = "{firstName.size}")
private String firstName;
@NotEmpty
@Length(min = 2,max = 30,message = "{lastName.size}")
private String lastName;
public Spitter() {
}
public Spitter(String username, String password, String firstName, String lastName) {
this.username = username;
this.password = password;
this.firstName = firstName;
this.lastName = lastName;
}
@Override
public boolean equals(Object o) {
return EqualsBuilder.reflectionEquals(this, "username", "password", "firstName", "lastName");
}
@Override
public int hashCode() {
return HashCodeBuilder.reflectionHashCode(this, "username", "password", "firstName", "lastName");
}
}
我在pojo类的重要字段上都加了hibernate-validator的校验注解。同时message的信息都抽取到了ValidationMessages_zh_CN.properties的文件中
文件位置在classpath的根路径下。文件内容如下:
username.size=\u7528\u6237\u59d3\u540d\u7684\u957f\u5ea6\u5fc5\u987b\u5728{min}\u548c{max}\u4e4b\u95f4
password.size=\u7528\u6237\u5bc6\u7801\u7684\u957f\u5ea6\u5fc5\u987b\u5728{min}\u548c{max}\u4e4b\u95f4
firstName.size=\u7528\u6237\u7b2c\u4e00\u540d\u79f0\u7684\u957f\u5ea6\u5fc5\u987b\u5728{min}\u548c{max}\u4e4b\u95f4
lastName.size=\u7528\u6237\u7b2c\u4e8c\u540d\u79f0\u7684\u957f\u5ea6\u5fc5\u987b\u5728{min}\u548c{max}\u4e4b\u95f4
我已经把中文变成了unicode编码,因为java的默认编码方式就是unicode编码。但是计算机的编码方式通常是GBK等编码方式。所以如果不变成unicode方式,会导致错误信息读取出来后乱码。
3 .Controller类编写
@Controller
@RequestMapping("/spitter")
public class SpitterController {
@RequestMapping("/home")
public String home(){
return "home";
}
@RequestMapping("/toRegister")
public String toRegister(Model model){
model.addAttribute(new Spitter());
return "registerForm";
}
@RequestMapping(value = "/register",method = RequestMethod.POST)
public String register(@Valid Spitter spitter, Errors errors,Model model){
if (errors.hasErrors()) {
System.out.println("错误数目:"+errors.getErrorCount());
model.addAttribute(spitter);
return "registerForm";
}
return "redirect:/cal/"+spitter.getId();
}
}
controller类很简单,我只提其中的一点,就是register类的方法签名中,行参spitter的修饰性注解是@Valid,这个注解是和pojo类中的@Length的注解是配套使用的。这个注解会校验前端的入参是否符合校验注解的要求,如果不符合,会将错误信息封装到Errors中。
另外还有一点,非常重要,我们一定要记得开启springmvc的注解驱动
在springMVC配置文件中添加以下配置,否则校验注解会不生效
<mvc:annotation-driven/>
4 .定义thymeleaf的配置类
@Configuration
public class ThymeleafTemplateConfig {
/**
* thymeleaf视图解析器
* @param templateEngine
* @return
*/
@Bean
public ViewResolver viewResolver(SpringTemplateEngine templateEngine){
ThymeleafViewResolver thymeleafViewResolver = new ThymeleafViewResolver();
//和ValidationMessages_zh_CN.properties中的unicode编码方式合起来,可以解决前端错误信息乱码的问题
thymeleafViewResolver.setCharacterEncoding("UTF-8");
thymeleafViewResolver.setTemplateEngine(templateEngine);
return thymeleafViewResolver;
}
/**
* thymeleaf模板引擎
* @param templateResolver
* @return
*/
@Bean
public SpringTemplateEngine templateEngine(TemplateResolver templateResolver){
SpringTemplateEngine templateEngine = new SpringTemplateEngine();
templateEngine.setTemplateResolver(templateResolver);
return templateEngine;
}
/**
* thymeleaf模板解析器
* @return
*/
@Bean
public TemplateResolver templateResolver(){
TemplateResolver templateResolver = new ServletContextTemplateResolver();
templateResolver.setPrefix("/WEB-INF/views/");
templateResolver.setSuffix(".html");
templateResolver.setTemplateMode("HTML5");
return templateResolver;
}
}
5 .定义html文件
第一个html文件
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:th="http://www.thymeleaf.org">
<head>
<title>Insert title here</title>
</head>
<body>
Welcome to Thymeleaf
<br/>
<a th:href="@{/spitter/toRegister.do}">register</a>
</body>
</html>
文件最上端的xmlns以及xmlns:th的命令空间起到了开启thymeleaf的作用
下面的@{}配置,作用和<s:url>以及<c:url>的作用是一样的。都是格式化一个字符串
Jsp 的老方法${pageContext.request.contextPath}=Thymeleaf 的新方式 @{}
所以${pageContext.request.contextPath}/home/abc.do等价于@{/home/abc.do}
第二个html文件
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8" http-equiv="charset" content="utf-8" />
<title>Insert title here</title>
<style type="text/css" >
label.error{
color:red;
}
input.error{
background-color: #ffcccc;
}
</style>
</head>
<body>
<form id="form-1" method="post" th:object="${spitter}" th:action="@{/spitter/register.do}">
<label th:class="${#fields.hasErrors('id')}?'error'">id:</label>
<input th:field="*{id}" th:class="${#fields.hasErrors('id')}?'error'" placeholder="id" type="text" />
<span th:if="${#fields.hasErrors('id')}">
<span th:text="${#fields.errors('id')}" />
</span>
<br/>
<label th:class="${#fields.hasErrors('username')}?'error'">username:</label>
<input th:class="${#fields.hasErrors('username')}?'error'" placeholder="username" type="text" th:field="*{username}"></input>
<span th:if="${#fields.hasErrors('username')}">
<span th:text="${#fields.errors('username')}"></span>
</span>
<br/>
<label th:class="${#fields.hasErrors('password')}?'error'">password:</label>
<input th:class="${#fields.hasErrors('password')}?'error'" th:field="*{password}" placeholder="password"
type="text"></input>
<span th:if="${#fields.hasErrors('password')}">
<span th:text="${#fields.errors('password')}"></span>
</span>
<br/>
<label th:class="${#fields.hasErrors('firstName')}?'error'">firstName:</label>
<input th:class="${#fields.hasErrors('firstName')}?'error'" th:field="*{firstName}" type="text"
placeholder="firstName"></input>
<span th:if="${#fields.hasErrors('firstName')}">
<span th:text="${#fields.errors('firstName')}"></span>
</span>
<br/>
<label th:class="${#fields.hasErrors('lastName')}?'error'">lastName:</label>
<input th:class="${#fields.hasErrors('lastName')}?'error'" placeholder="lastName" th:field="*{lastName}"
type="text"></input>
<span th:if="${#fields.hasErrors('lastName')}">
<span th:text="${#fields.errors('lastName')}"></span>
</span>
<br/>
<input type="submit"></input>
</form>
</body>
</html>
标签解释:
themeleaf提供了一系列的标签,用来和后端的mvc架构进行交互
1 th:object="${spitter}"
取得后端传递到该页面的pojo对象
2 .th:class="${#fields.hasErrors('id')}?'error'"
如果我们的@Valid校验框架校验到某个字段不合法,此时,${#fields.hasErrors('id')}返会true,此时class会取值error。
3 .th:field="*{id}"
*{id}是一个选择表达式,配合上面的th:object标签使用。目的是取得th:object标签中对象的id属性。
thymeleaf里的th:field等同于th:name和th:value
4 .${#fields.errors('id')
会取出校验错误的信息