Spring Boot 整合视图层技术
这一节我们主要学习如何整合视图层技术:
- Jsp
- Freemarker
- Thymeleaf
在之前的案例中,我们都是通过 @RestController
来处理请求,所以返回的内容为json对象。那么如果需要渲染html页面的时候,要如何实现呢?
Spring Boot推荐使用模板引擎
模板引擎实现伪html 达到seo优化 使动态页面静态化
在动态html上实现Spring Boot依然可以完美胜任,并且提供了多种模板引擎的默认配置支持,所以在推荐的模板引擎下,我们可以很快的上手开发动态网站。
Spring Boot提供了默认配置的模板引擎主要有以下几种:
Thymeleaf
FreeMarker
Velocity
Groovy
Mustache
Spring Boot建议使用这些模板引擎,避免使用jsp。
Jsp
创建项目
创建 war 项目,编写pom.xml
4.0.0 com.springboot springboot-view 1.0-SNAPSHOT war springboot-view Maven Webapp http://www.example.com UTF-8 1.8 1.8 org.springframework.boot spring-boot-starter-parent 2.1.6.RELEASE org.springframework.boot spring-boot-starter-web javax.servlet jstl org.apache.tomcat.embed tomcat-embed-jasper provided
视图解析器
resources/application.properties
spring.mvc.view.prefix=/WEB-INF/jsp/ spring.mvc.view.suffix=.jsp
实体类
User.java
package com.springboot.pojo; import java.io.Serializable; public class User implements Serializable { private Integer id; private String username; private Integer age; public User() { } public User(Integer id, String username, Integer age) { this.id = id; this.username = username; this.age = age; } public Integer getId() { return id; } public void setId(Integer id) { this.id = id; } public String getUsername() { return username; } public void setUsername(String username) { this.username = username; } public Integer getAge() { return age; } public void setAge(Integer age) { this.age = age; } @Override public String toString() { return "User{" + "id=" + id + ", username='" + username + '\'' + ", age=" + age + '}'; } }
控制层
UserController.java
package com.springboot.controller; import com.springboot.pojo.User; import org.springframework.stereotype.Controller; import org.springframework.ui.Model; import org.springframework.web.bind.annotation.RequestMapping; import java.util.ArrayList; import java.util.List; @Controller public class UserController { @RequestMapping("/showUser") public String showUser(Model model) { List list = new ArrayList(); list.add(new User(1, "张三", 18)); list.add(new User(2, "李四", 20)); list.add(new User(3, "王五", 22)); model.addAttribute("list", list); // 跳转视图 return "userList"; } }
视图层
userList.jsp
用户展示
ID | Name | Age |
---|---|---|
${user.id} | ${user.username} | ${user.age} |
启动类
App.java
package com.springboot; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; @SpringBootApplication public class App { public static void main(String[] args) { SpringApplication.run(App.class, args); } }
结果
Freemarker
创建项目
创建 war 项目,编写pom.xml
4.0.0 com.springboot springboot-view 1.0-SNAPSHOT war springboot-view Maven Webapp http://www.example.com UTF-8 1.8 1.8 org.springframework.boot spring-boot-starter-parent 2.1.6.RELEASE org.springframework.boot spring-boot-starter-web org.springframework.boot spring-boot-starter-freemarker
视图解析器
该文件内容不一定非得需要,可以不添加,不添加使用默认值。
resources/application.properties
# FREEMARKER (FreeMarkerAutoConfiguration) spring.freemarker.allow-request-override=false spring.freemarker.allow-session-override=false spring.freemarker.cache=true spring.freemarker.charset=UTF-8 spring.freemarker.check-template-location=true spring.freemarker.content-type=text/html spring.freemarker.enabled=true spring.freemarker.expose-request-attributes=false spring.freemarker.expose-session-attributes=false spring.freemarker.expose-spring-macro-helpers=true spring.freemarker.prefer-file-system-access=true spring.freemarker.suffix=.ftl spring.freemarker.template-loader-path=classpath:/templates/ spring.freemarker.settings.template_update_delay=0 spring.freemarker.settings.default_encoding=UTF-8 spring.freemarker.settings.classic_compatible=true spring.freemarker.order=1
实体类
User.java
package com.springboot.pojo; import java.io.Serializable; public class User implements Serializable { private Integer id; private String username; private Integer age; public User() { } public User(Integer id, String username, Integer age) { this.id = id; this.username = username; this.age = age; } public Integer getId() { return id; } public void setId(Integer id) { this.id = id; } public String getUsername() { return username; } public void setUsername(String username) { this.username = username; } public Integer getAge() { return age; } public void setAge(Integer age) { this.age = age; } @Override public String toString() { return "User{" + "id=" + id + ", username='" + username + '\'' + ", age=" + age + '}'; } }
控制层
UserController.java
package com.springboot.controller; import com.springboot.pojo.User; import org.springframework.stereotype.Controller; import org.springframework.ui.Model; import org.springframework.web.bind.annotation.RequestMapping; import java.util.ArrayList; import java.util.List; @Controller public class UserController { @RequestMapping("/showUser") public String showUser(Model model) { List list = new ArrayList(); list.add(new User(1, "张三", 18)); list.add(new User(2, "李四", 20)); list.add(new User(3, "王五", 22)); model.addAttribute("list", list); // 跳转视图 return "userList"; } }
视图层
Spring Boot要求模板形式的视图层技术的文件必须要放到 src/main/resources 目录下的 templates 目录。
该目录内的模板文件名称必须是 ftl
的后缀结尾。
userList.ftl
用户展示
ID | Name | Age |
---|---|---|
${user.id} | ${user.username} | ${user.age} |
启动类
App.java
package com.springboot; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; @SpringBootApplication public class App { public static void main(String[] args) { SpringApplication.run(App.class, args); } }
结果
Thymeleaf (重点讲解)
入门案例
创建项目
创建 war 项目,编写pom.xml
4.0.0 com.springboot springboot-view 1.0-SNAPSHOT war springboot-view Maven Webapp http://www.example.com UTF-8 1.8 1.8 org.springframework.boot spring-boot-starter-parent 2.1.6.RELEASE org.springframework.boot spring-boot-starter-web org.springframework.boot spring-boot-starter-thymeleaf
控制层
ThymeleafController.java
package com.springboot.controller; import org.springframework.stereotype.Controller; import org.springframework.ui.Model; import org.springframework.web.bind.annotation.RequestMapping; @Controller public class ThymeleafController { @RequestMapping("/show") public String showMsg(Model model) { model.addAttribute("msg", "Thymeleaf 入门案例"); return "msg"; } }
视图层
Spring Boot要求模板形式的视图层技术的文件必须要放到 src/main/resources 目录下的 templates 目录。
msg.html
Thymeleaf
启动类
App.java
package com.springboot; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; @SpringBootApplication public class App { public static void main(String[] args) { SpringApplication.run(App.class, args); } }
运行结果出现异常(如果是 Spring Boot 1.X.X 版本才会出现此异常):
org.xml.sax.SAXParseException: 元素类型 "meta" 必须由匹配的结束标记 "" 终止。
异常处理
如果是 Spring Boot 1.X.X 版本需要以下操作,本案例是 Spring Boot 2.1.6 版本,所以不需要更改。
方式一:编写风格严谨的HTML代码
方式二:更换Thymeleaf的jar包版本
thymeleaf.jar:更新为 3.0 以上的版本
3.0.11.RELEASE
运行结果
Thymeleaf 语法详解
Thymeleaf 内置对象语法:
- 调用内置对象一定要用
#
- 大部分的内置对象都以
s
结尾strings
、numbers
、dates
准备数据
实体类
User.java
package com.springboot.pojo; import java.io.Serializable; public class User implements Serializable { private Integer id; private String username; private Integer age; public User() { } public User(Integer id, String username, Integer age) { this.id = id; this.username = username; this.age = age; } public Integer getId() { return id; } public void setId(Integer id) { this.id = id; } public String getUsername() { return username; } public void setUsername(String username) { this.username = username; } public Integer getAge() { return age; } public void setAge(Integer age) { this.age = age; } @Override public String toString() { return "User{" + "id=" + id + ", username='" + username + '\'' + ", age=" + age + '}'; } }
控制层
ThymeleafController.java
package com.springboot.controller; import com.springboot.pojo.User; import org.springframework.stereotype.Controller; import org.springframework.ui.Model; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.RequestMapping; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.util.*; @Controller public class ThymeleafController { @RequestMapping("/show") public String showMsg(Model model, HttpServletRequest request, HttpServletResponse response) { // 字符串 model.addAttribute("msg", "Thymeleaf 入门案例"); // 日期时间 model.addAttribute("myDate", new Date()); // 条件判断if model.addAttribute("sex", 1); // 条件判断switch model.addAttribute("id", 1); // 对象 model.addAttribute("user", new User(1, "张三", 20)); // 迭代遍历list List userList = new ArrayList(); userList.add(new User(1, "张三", 20)); userList.add(new User(2, "李四", 22)); userList.add(new User(3, "王五", 24)); model.addAttribute("userList", userList); // 迭代遍历map Map userMap = new HashMap(); userMap.put("u1", new User(1, "张三", 20)); userMap.put("u2", new User(2, "李四", 22)); userMap.put("u3", new User(3, "王五", 24)); model.addAttribute("userMap", userMap); // 域对象操作 request.setAttribute("req", "HttpServletRequest"); request.getSession().setAttribute("sess", "HttpSession"); request.getSession().getServletContext().setAttribute("app", "Application"); return "msg"; } /** * URL表达式-相对路径 * @return */ @RequestMapping("/index") public String index() { return "index"; } /** * URL表达式-普通传参 * @param id * @param username * @return */ @RequestMapping("/user") public String user(Integer id, String username) { System.out.println("id:" + id + " username:" + username); return "user"; } /** * URL表达式-restful传参 * @param id * @param username * @return */ @RequestMapping("/person/{id}/{username}") public String person(@PathVariable Integer id, @PathVariable String username) { System.out.println("id:" + id + " username:" + username); return "person"; } }
视图层
index.html
Thymeleaf index
user.html
Thymeleaf user
person.html
Thymeleaf person
字符串
变量输出
th:text
:在页面中输入值
th:value
:可以将一个值设置至input标签的value中
字符串操作
${#strings.isEmpty(key)}
:判断字符串是否为空
${#strings.contains(msg, 'T')}
:判断字符串是否包含子串
${#strings.startsWith(msg, 'T')}
:判断字符串是否以子串开头
${#strings.endsWith(msg, 'T')}
:判断字符串是否以子串结尾
${#strings.length(msg)}
:返回字符串的长度
${#strings.indexOf(msg, 'T')}
:查找子串的位置,并返回该子串的下标,如果没找到则返回-1
${#strings.substring(msg, 5)}
:截取子串,从指定下标开始截止到末尾结束
${#strings.substring(msg, 5, 12)}
:截取子串,从指定下标开始截止到指定下标结束
${#strings.toUpperCase(msg)}
:将字符串转大写
${#strings.toLowerCase(msg)}
:将字符串转小写
日期时间
${#dates.format(key)}
:格式化日期,以浏览器默认语言为格式化标准
${#dates.format(key,'yyy/MM/dd')}
:自定义格式日期转换
${#dates.year(myDate)}
:获取年份,还可以获取月份、日、时、分、秒
年 月 日 时 分 秒
条件判断
th:if
:单选择
性别:男 女
th:switch
:多选择(如果要实现 if else if else 判断表达式,在 Thymeleaf 要使用 th:switch 代替)
编号:
1 张三
2 李四
3 王五
对象
迭代遍历
th:each
:迭代遍历
ID | NAME | AGE |
---|---|---|
th:each
:状态变量属性
- index:当前迭代器的索引 从 0 开始
- count:当前迭代对象的计数 从 1 开始
- size:被迭代对象的长度
- even/odd:布尔值,当前循环是否是偶数/奇数 从 0 开始
- first:布尔值,当前循环的是否是第一条,如果是返回 true 否则返回 false
- last:布尔值,当前循环的是否是最后一条,如果是则返回 true 否则返回 false
Id | Name | Age | Index | Count | Size | Even | Odd | First | Last |
---|---|---|---|---|---|---|---|---|---|
th:each
:迭代 Map
Id | Name | Age |
---|---|---|
Id | Name | Age |
---|---|---|
域对象操作
${#httpServletRequest.getAttribute(key)}
:HttpServletRequest
Request:
${session.key}
:HttpSession
Session:
${application.key}
:ServletContext
Application:
URL表达式
基本语法
URL表达式的基本语法: @{}
th:href
:绝对路径
绝对路径
th:href
:相对路径,相对于当前项目的根路径
相对于当前项目的根路径
th:href
:相对路径, 相对于服务器的根路径
相对于服务器的根路径
参数传递
相对路径-普通传参 相对路径-restful传参 相对路径-restful传参
✍️本章节到这里就结束了,喜欢的话就点赞 加转发:revolving_hearts:吧,我们下章节再见:wave:。