第5章Spring Boot的Web开发
学习目的与要求
本章首先介绍Spring Boot的Web开发支持,然后介绍Thymeleaf视图模板引擎技术,最后介绍Spring Boot的Web开发技术(JSON数据交互、文件上传与下载、异常统一处理以及对JSP的支持)。通过本章的学习,掌握Spring Boot的Web开发技术。
本章主要内容
Thymeleaf模板引擎。
Spring Boot处理JSON数据。
Spring Boot的文件上传与下载。
Spring Boot的异常处理。
Web开发是一种基于B/S架构(即浏览器/服务器)的应用软件开发技术,分为前端(用户接口)和后端(业务逻辑和数据),前端的可视化及用户交互由浏览器实现,即以浏览器作为客户端,实现客户与服务器远程的数据交互。Spring Boot的Web开发内容主要包括内嵌Servlet容器和Spring MVC。
5.1Spring Boot的Web开发支持
Spring Boot提供了springbootstarterweb依赖模块,该依赖模块包含Spring Boot预定义的Web开发常用依赖包,为Web开发者提供了内嵌的Servlet容器(Tomcat)以及Spring MVC的依赖。如果开发者希望开发Spring Boot的Web应用程序,可以在Spring Boot项目的pom.xml文件中添加如下依赖配置:
视频讲解
org.springframework.boot
spring-boot-starter-web
Spring Boot将自动关联Web开发的相关依赖,如tomcat、springwebmvc等,进而对Web开发提供支持,并对相关技术的配置实现自动配置。
另外,开发者也可以使用Spring Tool Suite集成开发工具快速创建Spring Starter Project,在New Spring Starter Project Dependencies对话框中添加Spring Boot的Web依赖,如图5.1所示。
图5.1添加Spring Boot的Web依赖
视频讲解
5.2Thymeleaf模板引擎
在Spring Boot的Web应用中,建议开发者使用HTML完成动态页面。Spring Boot提供了许多模板引擎,主要包括FreeMarker、Groovy、Thymeleaf、Velocity和Mustache。因为Thymeleaf提供了完美的Spring MVC支持,所以在Spring Boot的Web应用中推荐使用Thymeleaf作为模板引擎。
Thymeleaf是一个Java类库,是一个XML/XHTML/HTML5的模板引擎,能够处理HTML、XML、JavaScript以及CSS,可以作为MVC Web应用的View层显示数据。
5.2.1Spring Boot的Thymeleaf支持
在Spring Boot 1.X版本中,springbootstarterthymeleaf依赖包含了springbootstarterweb模块。但是,在Spring 5中,WebFlux的出现对于Web应用的解决方案将不再唯一。所以,springbootstarterthymeleaf依赖不再包含springbootstarterweb模块,需要开发人员自己选择springbootstarterweb模块依赖。下面通过一个实例,讲解如何创建基于Thymeleaf模板引擎的Spring Boot Web应用ch5_1。
【例51】创建基于Thymeleaf模板引擎的Spring Boot Web应用ch5_1。
具体实现步骤如下。
1. 创建Spring Starter Project
选择菜单File|New|Spring Starter Project,打开New Spring Starter Project对话框,在该对话框中选择和输入相关信息,如图5.2所示。
图5.2创建基于Thymeleaf模板引擎的Spring Boot Web应用ch5_1
2. 选择依赖
单击图5.2中的Next按钮,打开New Spring Starter Project Dependencies对话框,选择Spring Web Starter和Thymeleaf依赖,如图5.3所示。
3. 打开项目目录
单击图5.3中的Finish按钮,创建如图5.4所示的基于Thymeleaf模板引擎的Spring Boot Web应用ch5_1。
图5.3选择Spring Web Starter和Thymeleaf依赖
图5.4基于Thymeleaf模板引擎的Spring Boot Web应用ch5_1
Tymeleaf模板默认将JS脚本、CSS样式、图片等静态文件放置在src/main/resources/static目录下,将视图页面放在src/main/resources/templates目录下。
4. 创建控制器类
创建一个名为com.ch.ch5_1.controller的包。并在该包中创建控制器类TestThymeleafController,代码如下:
package com.ch.ch5_1.controller;
import org.springframework.stereotype.Controller;
@Controller
public class TestThymeleafController {
@RequestMapping("/")
public String test(){
//根据Tymeleaf模板,默认将返回src/main/resources/templates/index.html
return "index";
}
}
5. 新建index.html页面
在src/main/resources/templates目录下新建index.html页面,代码如下:
Insert title here
测试Spring Boot的Thymeleaf支持
图5.5例51运行结果
6. 运行测试
首先,运行Ch51Application主类。然后,访问http://localhost:8080/ch5_1/(因为配置文件中配置了Web应用的上下文路径为ch5_1)。运行效果如图5.5所示。
5.2.2Thymeleaf基础语法
1. 引入Thymeleaf
首先,将View层页面文件的html标签修改如下:
然后,在View层页面文件的其他标签里,使用th:*动态处理页面,示例代码如下:
其中,${aBook.picture}获得数据对象aBook的picture属性。
2. 输出内容
使用th:text和th:utext(对HTML标签解析)将文本内容输出到所在标签的body中。假如在国际化资源文件messages_en_US.properties中有消息文本“test.myText=Test International Message ”,那么在页面中可以使用如下两种方式获得消息文本:
3. 基本表达式
1) 变量表达式: ${…}
变量表达式用于访问容器上下文环境中的变量,示例代码如下:
2) 选择变量表达式: *{…}
选择变量表达式计算的是选定的对象(th:object属性绑定的对象),示例代码如下:
name:
surname:
nationality:
3) 信息表达式: #{…}
信息表达式一般用于显示页面静态文本,将可能需要根据需求而整体变动的静态文本放在properties文件中以便维护(如国际化),通常与th:text属性一起使用,示例代码如下:
4. 引入URL
Thymeleaf模板通过@{…}表达式引入URL,示例代码如下:
去看看
去清华大学出版社
5. 访问WebContext对象中的属性
Thymeleaf模板通过一些专门的表达式从模板的WebContext获取请求参数、请求、会话和应用程序中的属性,具体如下:
${xxx}将返回存储在Thymeleaf模板上下文中的变量xxx或请求request作用域中的属性xxx。
${param.xxx}将返回一个名为xxx的请求参数(可能是多个值)。
${session.xxx}将返回一个名为xxx的HttpSession作用域中的属性。
${application.xxx}将返回一个名为xxx的全局ServletContext上下文作用中的属性。
与EL表达式一样,使用${xxx}获得变量值,使用${对象变量名.属性名}获取JavaBean属性值。但需要注意的是,${}表达式只能在th标签内部有效。
6. 运算符
在Thymeleaf模板的表达式中可以使用+、-、*、/、%等各种算术运算符,也可以使用>、<、<=、>=、==、!=等各种逻辑运算符。示例代码如下:
…
7. 条件判断
1) if和unless
只有在th:if条件成立时才显示标签内容; th:unless与th:if相反,只有在条件不成立时才显示标签内容。示例代码如下:
成功
成功
2) switch语句
Thymeleaf模板也支持多路选择switch语句结构,默认属性default可用“*”表示。示例代码如下:
User is an administrator
User is a teacher
User is a student
8. 循环
1) 基本循环
Thymeleaf模板使用th:each="obj,iterStat:${objList}"标签进行迭代循环,迭代对象可以是java.util.List、java.util.Map或数组等。示例代码如下:
2) 循环状态的使用
在th:each标签中可以使用循环状态变量,该变量有如下属性。
index: 当前迭代对象的index(从0开始计数)。
count: 当前迭代对象的index(从1开始计数)。
size: 迭代对象的大小。
current: 当前迭代变量。
even/odd: 布尔值,当前循环是否是偶数/奇数(从0开始计数)。
first: 布尔值,当前循环是否是第一个。
last: 布尔值,当前循环是否是最后一个。
使用循环状态变量的示例代码如下:
9. 内置对象
在实际Web项目开发中,经常传递列表、日期等数据。所以,Thymeleaf模板提供了很多内置对象,可以通过#直接访问。这些内置对象一般都以s结尾,如dates、lists、numbers、strings等。Thymeleaf模板通过${#…}表达式访问内置对象。常见的内置对象如下。
#dates: 日期格式化的内置对象,操作的方法是java.util.Date类的方法。
#calendars: 类似于#dates,但操作的方法是java.util.Calendar类的方法。
#numbers: 数字格式化的内置对象。
#strings: 字符串格式化的内置对象,操作的方法参照java.lang.String。
#objects: 参照java.lang.Object。
#bools: 判断boolean类型的内置对象。
#arrays: 数组操作的内置对象。
#lists: 列表操作的内置对象,参照java.util.List。
#sets: Set操作的内置对象,参照java.util.Set。
#maps: Map操作的内置对象,参照java.util.Map。
#aggregates: 创建数组或集合的聚合的内置对象。
#messages: 在变量表达式内部获取外部消息的内置对象。
假如有如下控制器方法:
@RequestMapping("/testObject")
public String testObject(Model model) {
//系统时间new Date()
model.addAttribute("nowTime", new Date());
//系统日历对象
model.addAttribute("nowCalendar", Calendar.getInstance());
//创建BigDecimal对象
BigDecimal money = new BigDecimal(2019.613);
model.addAttribute("myMoney", money);
//字符串
String tsts = "Test strings";
model.addAttribute("str", tsts);
//boolean类型
boolean b = false;
model.addAttribute("bool", b);
//数组(这里不能使用int定义数组)
Integer aint[] = {1,2,3,4,5};
model.addAttribute("mya", aint);
//List列表1
List nameList1 = new ArrayList();
nameList1.add("陈恒1");
nameList1.add("陈恒3");
nameList1.add("陈恒2");
model.addAttribute("myList1", nameList1);
//Set集合
Set st = new HashSet();
st.add("set1");
st.add("set2");
model.addAttribute("mySet", st);
//Map集合
Map map = new HashMap();
map.put("key1", "value1");
map.put("key2", "value2");
model.addAttribute("myMap", map);
//List列表2
List nameList2 = new ArrayList();
nameList2.add("陈恒6");
nameList2.add("陈恒5");
nameList2.add("陈恒4");
model.addAttribute("myList2", nameList2);
return "showObject";
}
那么,可以在src/main/resources/templates/showObject.html视图页面文件中使用内置对象操作数据。showObject.html的代码如下:
Insert title here
格式化控制器传递过来的系统时间nowTime
创建一个日期对象
格式化控制器传递过来的系统日历nowCalendar:
格式化控制器传递过来的BigDecimal对象myMoney:
计算控制器传递过来的字符串str的长度:
返回对象,当控制器传递过来的BigDecimal对象myMoney为空时,返回默认值9999:
判断boolean数据是否是false:
判断数组mya中是否包含元素5:
排序列表myList1的数据:
判断集合mySet中是否包含元素set2:
判断myMap中是否包含key1关键字:
将数组mya中的元素求和:
将数组mya中的元素求平均:
如果未找到消息,则返回默认消息(如"??msgKey_zh_CN??"):
5.2.3Thymeleaf的常用属性
通过5.2.2节的学习,我们发现Thymeleaf语法的使用都是通过在html页面的标签中添加th:xxx关键字来实现模板套用,且其属性与html页面标签基本类似。常用属性有以下几种。
1. th:action
th:action定义后台控制器路径,类似于
2. th:each
th:each用于集合对象遍历,功能类似于JSTL标签。示例代码如下:
3. th:field
th:field常用于表单参数绑定,通常与th:object一起使用。示例代码如下:
4. th:href
th:href用于定义超链接,类似于标签的href属性。value形式为@{/logout},示例代码如下:
5. th:id
th:id用于id的声明,类似于html标签中的id属性。示例代码如下:
6. th:if
th:if用于条件判断,如果为否则标签不显示。示例代码如下:
… do something …
7. th:fragment
th:fragment声明定义该属性的div为模板片段,常用于头文件、页尾文件的引入,常与th:include、th:replace一起使用。
假如在ch5_1的src/main/resources/templates目录下声明模板片段文件footer.html,具体代码如下:
Insert title here
主体内容
清华大学出版社
那么,可以在ch5_1的src/main/resources/templates/index.html文件中引入模板片段,具体代码如下:
Insert title here
测试Spring Boot的Thymeleaf支持
引入主体内容模板片段:
引入版权所有模板片段:
8. th:object
th:object用于表单数据对象绑定,将表单绑定到后台controller的一个JavaBean参数,常与th:field一起使用,进行表单数据绑定。下面通过实例讲解表单提交及数据绑定的实现过程。
【例52】表单提交及数据绑定的实现过程。
具体实现步骤如下。
1) 创建实体类
在Web应用ch5_1的src/main/java目录下,创建com.ch.ch5_1.model包,并在该包中创建实体类LoginBean,代码如下:
package com.ch.ch5_1.model;
public class LoginBean {
String uname;
String urole;
//省略set和get方法
}
2) 创建控制器类
在Web应用ch5_1的com.ch.ch5_1.controller包中,创建控制器类LoginController,具体代码如下:
package com.ch.ch5_1.controller;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.RequestMapping;
import com.ch.ch5_1.model.LoginBean;
@Controller
public class LoginController {
@RequestMapping("/toLogin")
public String toLogin(Model model) {
/*loginBean与login.html页面中的th:object="${loginBean}"相同,类似于Spring MVC的表单绑定。*/
model.addAttribute("loginBean", new LoginBean());
return "login";
}
@RequestMapping("/login")
public String greetingSubmit(@ModelAttribute LoginBean loginBean) {
/*@ModelAttribute LoginBean loginBean接收login.html页面中的表单数据,并将loginBean对象保存到model中返回给result .html页面显示。*/
System.out.println("测试提交的数据:" + loginBean.getUname());
return "result";
}
}
3) 创建页面表示层
在Web应用ch5_1的src/main/resources/templates目录下,创建页面login.html和result.html。
页面login.html的代码如下:
Insert title here
Form
页面result.html的代码如下:
Insert title here
Result
继续提交
4) 运行
首先,运行Ch51Application主类。然后,访问http://localhost:8080/ch5_1/toLogin。运行结果如图5.6所示。
在图5.6的文本框中输入信息后,单击Sumbit按钮,打开如图5.7所示的页面。
图5.6页面login.html的运行结果
图5.7页面result.html的运行结果
9. th:src
th:src用于外部资源引入,类似于