第5章 Spring Boot的Web开发 一、Thymeleaf模板引擎

学习目标:

本章首先介绍Spring Boot的Web开发支持,然后介绍Thymeleaf视图模板引擎技术,最后介绍Spring Boot的Web开发技术(JSON数据交互、文件上传与下载、异常统一处理以及对JSP的支持)。通过对本章的学习,掌握Spring Boot的Web开发技术。


学习大纲:

一、Thymeleaf模板引擎

二、Spring Boot处理JSON数据

三、Spring Boot的文件上传与下载

四、Spring Boot的异常处理

五、Spring Boot对JSP的支持


学习内容:

Web开发是一种基于B/S架构(即浏览器/服务器)的应用软件开发技术,分为前端(用户接口)和后端(业务逻辑和数据),前端的可视化及用户交互由浏览器实现,即以浏览器作为客户端,实现客户与浏览器远程的数据交互。Spring Boot的Web开发内容主要包括内嵌Servlet容器和Spring MVC。

Spring Boot的Web开发支持

如果开发者希望开发Spring Boot的Web应用程序,可以在Spring Boot项目的pom.xml文件中,添加如下依赖配置:

<dependency>
	<groupId>org.springframework.boot</groupId>
	<artifactId>spring-boot-starter-web</artifactId>
</dependency>

Spring Boot将自动关联Web开发的相关依赖,如tomcat、spring-webmvc等,进而对Web开发的支持,并将相关技术的配置实现自动配置。

另外,开发者也可以使用Spring Tool Suite集成开发工具创建Spring Starter Project,在New Spring Starter Project Dependencies对话框中添加Spring Boot的Web依赖,如下图所示:
在这里插入图片描述

一、Thymeleaf模板引擎

在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层显示数据。

1、Spring Boot的Thymeleaf支持

在Spring Boot 1.X版本中,spring-boot-starter-thymeleaf依赖包含了spring-boot-starter-web模块。但是,在Spring 5中,WebFlux的出现对于Web应用的解决方案将不再唯一。所以,spring-boot-starter-thymeleaf依赖不再包含spring-boot-starter-web模块,需要开发人员自己选择spring-boot-starter-web模块依赖。

【例5-1】创建基于Thymeleaf模板引擎的Spring Boot Web应用ch5_1。
具体实现步骤如下:
1)创建Spring Starter Project
选择菜单File|New|Spring Starter Project,打开New Spring Starter Project对话框,在该对话框中选择和输入相关信息,如图所示:

在这里插入图片描述
2)选择依赖
单击上图的Next按钮,打开New Spring Starter Project Dependencies对话框,选择Spring Web Starter和Thymeleaf依赖,如图所示:

在这里插入图片描述
3、打开项目目录
单击上图的Finish按钮,创建如下图所示的基于Thymeleaf模板引擎的Spring Boot Web应用。

在这里插入图片描述
Thymeleaf模板默认将JS脚本、CSS样式、图片等静态文件放置在src/main/resourses/static目录下,将视图页面放在src/main/resourses/temolates目录下。

4)创建控制器类

创建名为com.ch.ch5_1.controller的包

在这里插入图片描述
并在该包中创建控制器类TestThymeleafController,代码如下:

package com.ch.ch5_1.controller;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;

@Controller
public class TestThymeleafController {
    @RequestMapping("/")
    public String test() {
    	//根据Tymeleaf模板,默认返回src/main/resources/templates/index.html
    	return "index";
    }
}

5)新建index.html页面
在src/main/resourses/templates目录下新建index.html页面,代码如下:

在这里插入图片描述

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>
测试Spring Boot的Thymeleaf支持
</body>
</html>

6)运行测试
首先,运行Ch51Application主类。然后,访问http://localhost:8080/ch5_1/(因为配置文件中配置了Web应用的上下文路径为ch5_1)。运行效果如图:
在这里插入图片描述

2、Thymeleaf基础语法

1.引入Thymeleaf

<html xmlns:th="http://www.thymeleaf.org">
<img th:src="'images/' + ${aBook.picture}"/>

2.输出内容
使用th:text和th:utext将文本内容输出到所在标签的body中。假如在国际化资源文件messages_en_US.properties中有消息文本“test.myText=<strong>Test International Message</strong>”,那么在页面中可以使用如下两种方式获得消息文本:

<p th:text="#{test.myText}"></p>
<!-- 不识别HTML标签,即输出<strong>Test International Message</strong> -->
<p th:utext="#{test.myText}"></p>
<!– 识别HTML标签,即输出加粗的“Test International Message” -->

3.基本表达式
1)变量表达式:${...}
用于访问容器上下文环境中的变量,示例代码如下:

<span th:text="${information}">

2)选择变量表达式:*{...}
选择变量表达式计算的是选定的对象(th:object属性绑定的对象),示例代码如下:

<div th:object="${session.user}">
name: <span th: text="*{firstName}"></span><br>
<!-- firstName为user对象的属性-->
surname: <span th: text="*{lastName}"></span><br>
nationality: <span th: text="*{nationality}"></span><br>
</div>

3)信息表达式:#{...}
一般用于显示页面静态文本。将可能需要根据需求而整体变动的静态文本放在properties文件中以便维护(如国际化)。通常与th:text属性一起使用,示例代码如下:

<p th:text="#{test.myText}"></p>

4.引入URL
Thymeleaf模板通过@{...}表达式引入URL,示例代码如下:

<!-- 默认访问 src/main/resources/static下的css文件夹-->
<link rel="stylesheet" th:href="@{css/bootstrap.min.css}" />
<!--访问相对路径-->
<a th:href="@{/}">去看看</a>
<!--访问绝对路径-->
<a th:href="@{http://www.tup.tsinghua.edu.cn/index.html(param1='传参')}">去清华大学出版社</a>
<!-- 默认访问 src/main/resources/static下的'images文件夹-->
<img th:src="'images/' + ${aBook.picture}"/>

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模板的表达式中可以使用+、-、*、/、%等各种算术运算符,也可以使用>、<、<=、>=、==、!=等各种逻辑运算符。示例代码如下:

<tr th:class="(${row}== 'even')? 'even' : 'odd'">...</tr>

7.条件判断
1)if和unless
标签只有在th:if条件成立时才显示,th:unless与th:if相反,只有条件不成立时,才显示标签内容。示例代码如下:

<a href="success.html" th:if="${user != nul}">成功</a>
<a href="success.html" th:unless="${user = nul}">成功</a>

2)switch语句
Thymeleaf模板也支持多路选择switch语句结构,默认属性default可用“*”表示。示例代码如下:

<div th:switch="${user.role}">
<p th:case="'admin'">User is an administrator</p>
<p th:case="'teacher'">User is a teacher</p>
<p th:case="*">User is a student </p>
</div>

8.循环
1)基本循环
Thymeleaf模板使用th:each="obj,iterStat:${objList}"标签进行迭代循环,迭代对象可以是java.util.List、java.util.Map或数组等。示例代码如下:

<!-- 循环取出集合数据 -->
<div class="col-md-4 col-sm-6" th:each="book:${books}">
	<a href="">
		<img th:src="'images/' + ${book.picture}" alt="图书封面" style="height: 180px; width: 40%;"/>
	</a>
	<div class="caption">
		<h4 th:text="${book.bname}"></h4>
		<p th:text="${book.author}"></p>
		<p th:text="${book.isbn}"></p>
		<p th:text="${book.price}"></p>
		<p th:text="${book.publishing}"></p>
	</div>
</div>

2)循环状态的使用
在th:each标签中可以使用循环状态变量,该变量有如下属性:
index:当前迭代对象的index(从0开始计数)。
count:当前迭代对象的index(从1开始计数)。
size:迭代对象的大小。
current:当前迭代变量。
even/odd:布尔值,当前循环是否是偶数/奇数(从0开始计数)。
first:布尔值,当前循环是否是第一个。
last:布尔值,当前循环是否是最后一个。
使用循环状态变量的示例代码如下:

<!-- 循环取出集合数据 -->
<div class="col-md-4 col-sm-6" th:each="book,bookStat:${books}">
	<a href="">
		<img th:src="'images/' + ${book.picture}" alt="图书封面" style="height: 180px; width: 40%;"/>
	</a>
	<div class="caption">
		<!--循环状态bookStat-->
		<h3 th:text="${bookStat.count}"></h3>
		<h4 th:text="${book.bname}"></h4>
		<p th:text="${book.author}"></p>
		<p th:text="${book.isbn}"></p>
		<p th:text="${book.price}"></p>
		<p th:text="${book.publishing}"></p>
	</div>
</div>

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:在变量表达式内部获取外部消息的内置对象。

假如,有如下控制器方法:
那么,可以在src/main/resources/templates/showObject.html视图页面文件中,使用内置对象操作数据,showObject.html的代码如下:

<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>
	格式化控制器传递过来的系统时间nowTime
	<span th:text="${#dates.format(nowTime, 'yyyy/MM/dd')}"></span>
	<br>
	创建一个日期对象
	<span th:text="${#dates.create(2019,6,13)}"></span>
	<br>
	格式化控制器传递过来的系统日历nowCalendar:
	<span th:text="${#calendars.format(nowCalendar, 'yyyy-MM-dd')}"></span>
	<br>
	格式化控制器传递过来的BigDecimal对象myMoney:
	<span th:text="${#numbers.formatInteger(myMoney,3)}"></span>
	<br>
	计算控制器传递过来的字符串str的长度:
	<span th:text="${#strings.length(str)}"></span>
	<br>
	返回对象,当控制器传递过来的BigDecimal对象myMoney为空时,返回默认值9999<span th:text="${#objects.nullSafe(myMoney, 9999)}"></span>
	<br>
	判断boolean数据是否是false<span th:text="${#bools.isFalse(bool)}"></span>
	<br>
	判断数组mya中是否包含元素5<span th:text="${#arrays.contains(mya, 5)}"></span>
	<br>
	排序列表myList1的数据:
	<span th:text="${#lists.sort(myList1)}"></span>
	<br>
	判断集合mySet中是否包含元素set2:
	<span th:text="${#sets.contains(mySet, 'set2')}"></span>
	<br>
	判断myMap中是否包含key1关键字:
	<span th:text="${#maps.containsKey(myMap, 'key1')}"></span>
	<br>
	将数组mya中的元素求和:
	<span th:text="${#aggregates.sum(mya)}"></span>
	<br>
	将数组mya中的元素求平均:
	<span th:text="${#aggregates.avg(mya)}"></span>
	<br>
	如果未找到消息,则返回默认消息(如“??msgKey_zh_CN??”):
	<span th:text="${#messages.msg('msgKey')}"></span>
</body>
</html>
3、Thymeleaf的常用属性

常用属性有:
1.th:action
定义后台控制器路径,类似标签的action属性。示例代码如下:

<form th:action="@{/login}">...</form>

2.th:each
集合对象遍历,功能类似JSTL标签<c:forEach>。示例代码如下:

<div class="col-md-4 col-sm-6" th:each="gtype:${gtypes}">
	<div class="caption">
		<p th:text="${gtype.id}"></p>
		<p th:text="${gtype.typename}"></p>
	</div>
</div>

3.th:field
常用于表单参数绑定,通常与th:object一起使用。示例代码如下:

<form th:action="@{/login}" th:object="${user}">
<input type="text" value="" th:field="*{username}"></input>
<input type="text" value="" th:field="*{role}"></input>
</form>

4.th:href
定义超链接,类似<a>标签的href属性。value形式为@{/logout},示例代码如下:

<a th:href="@{/gogo}"></a>

5.th:id
div的id声明,类似html标签中的id属性,示例代码如下:

<div th:id ="stu+(${rowStat.index}+1)"></div>

6.th:if
条件判断。如果为否则标签不显示,示例代码如下:

<div th:if="${rowStat.index} == 0">... do something ...</div>

7.th:fragment
声明定义该属性的div为模板片段,常用于头文件、页尾文件的引入。常与th:include、th:replace一起使用。假如,在ch5_1的src/main/resources/templates目录下声明模板片段文件footer.html

<!-- 声明片段content -->
<div th:fragment="content" >
	主体内容
</div>
<!-- 声明片段copy -->
<div th:fragment="copy" >
	©清华大学出版社
</div>

那么,我们可以在ch5_1的src/main/resources/templates/index.html文件中引入模板片段。

引入主体内容模板片段:
<div th:include="footer::content"></div>
引入版权所有模板片段:
<div th:replace="footer::copy" ></div>

8.th:object
用于表单数据对象绑定,将表单绑定到后台controller的一个JavaBean参数。常与th:field一起使用,进行表单数据绑定。
【例5-2】表单提交及数据绑定的实现过程。
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;
	public String getUname() {
		return uname;
	}
	public void setUname(String uname) {
		this.uname = uname;
	}
	public String getUrole() {
		return urole;
	}
	public void setUrole(String urole) {
		this.urole = urole;
	}
}

2)创建控制器类
在Web应用ch5_1的src/main/resources/templates目录下,创建页面login.html和result.html。
login.html代码如下:

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) {
		model.addAttribute("loginBean", new LoginBean());
		return "login";
	}
	@RequestMapping("/login")
	 public String greetingSubmit(@ModelAttribute LoginBean loginBean) {
		System.out.println("测试提交的数据:" + loginBean.getUname());
	    return "result";
	 }
}

3)创建页面表示层
在Web应用ch5_1的src/main/resources/templates目录下,创建页面login.html和result.html。

login.html代码如下:

<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>
	<h1>Form</h1>
    <form action="#" th:action="@{/login}" th:object="${loginBean}" method="post">
    	<!--th:field="*{uname}"的uname与实体类的属性相同  -->
        <p>Uname: <input type="text" th:field="*{uname}" th:placeholder="请输入用户名" /></p>
        <p>Urole: <input type="text" th:field="*{urole}" th:placeholder="请输入角色"  /></p>
        <p><input type="submit" value="Submit" /> <input type="reset" value="Reset" /></p>
    </form>
</body>
</html>

result.html代码如下:

<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>
	<h1>Result</h1>
    <p th:text="'Uname: ' + ${loginBean.uname}" />
    <p th:text="'Urole: ' + ${loginBean.urole}" />
    <a href="toLogin">继续提交</a>
</body>
</html>

4)运行
首先,运行Ch51Application主类。然后,访问http://localhost:8080/ch5_1/toLogin。
运行结果如下:

在这里插入图片描述
在这里插入图片描述

9.th:src
用于外部资源引入,类似于<script>标签的src属性。示例代码如下:

<img th:src="'images/' + ${aBook.picture}" />

10.th:text
文本显示,将文本内容显示到所在标签的body中。示例代码如下:

<td th:text="${username}"></td>

11.th:value
用于标签赋值,类似标签的value属性。示例代码如下:

<option th:value="Adult">Adult</option>
<input type="hidden" th:value="${msg}" />

12.th:style
用于修改标签style,示例代码如下:

<span th:style="'display:' + @{(${sitrue} ? 'none' : 'inline-block')}"></span>

13.th:onclick
用于修改点击事件,示例代码如下:

<button th:onclick="'getCollect()'"></button>
4 、Spring Boot与Thymeleaf实现页面信息国际化

1.编写国际化资源属性文件
在这里插入图片描述
2.添加配置文件内容,引入资源属性文件

spring.messages.basename=i18n/admin/adminMessages,i18n/before/beforeMessages,i18n/common/commonMessages

3.重写localeResolver方法配置语言区域选择

package com.ch.ch5_1;
import java.util.Locale;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.LocaleResolver;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
import org.springframework.web.servlet.i18n.LocaleChangeInterceptor;
import org.springframework.web.servlet.i18n.SessionLocaleResolver;
@Configuration
@EnableAutoConfiguration
public class LocaleConfig implements WebMvcConfigurer {
	/**
	 *根据用户本次会话过程中的语义设定语言区域
	 *(如用户进入首页时选择的语言种类)
	 * @return
	 */
	@Bean
    public LocaleResolver localeResolver() {
        SessionLocaleResolver slr = new SessionLocaleResolver();
        //默认语言
        slr.setDefaultLocale(Locale.CHINA);
        return slr;
    }
	/**
	 * 使用SessionLocaleResolver存储语言区域时,
	 * 必须配置localeChangeInterceptor拦截器
	 * @return
	 */
    @Bean
    public LocaleChangeInterceptor localeChangeInterceptor() {
        LocaleChangeInterceptor lci = new LocaleChangeInterceptor();
        //选择语言的参数名
        lci.setParamName("locale");
        return lci;
    }
    /**
         * 注册拦截器
     */
    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(localeChangeInterceptor());
    }
}

4.创建控制器类I18nTestController

package com.ch.ch5_1.controller;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
@Controller
@RequestMapping("/i18n")
public class I18nTestController {
	@RequestMapping("/first")
	public String testI18n(){
		return "/i18n/first";
	}
	@RequestMapping("/admin")
	public String admin(){
		return "/i18n/admin";
	}
	@RequestMapping("/before")
	public String before(){
		return "/i18n/before";
	}
}

5.创建视图页面,并获得国际化信息
在这里插入图片描述
admin.html

<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>
	<span th:text="#{admin}"></span><br>
	<a th:href="@{/i18n/first}" th:text="#{return}"></a>
</body>
</html>

before.html

<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>
	<span th:text="#{before}"></span><br>
	<a th:href="@{/i18n/first}" th:text="#{return}"></a>
</body>
</html>

first.html

<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>
	<a th:href="@{/i18n/first(locale='zh_CN')}" th:text="#{chinese.key}"></a>
	<a th:href="@{/i18n/first(locale='en_US')}" th:text="#{english.key}"></a>
	<br>
	<a th:href="@{/i18n/admin}" th:text="#{test.admin}"></a><br>
	<a th:href="@{/i18n/before}"  th:text="#{test.before}"></a><br>
</body>
</html>

6.运行

在这里插入图片描述

5 、Spring Boot与Thymeleaf的表单验证

使用Hibernate Validator验证表单时,需要利用它的标注类型在实体模型的属性上嵌入约束。

1.空检查

@Null:验证对象是否为null。
@NotNull:验证对象是否不为null,无法查检长度为0的字符串。
@NotBlank:检查约束字符串是不是null,还有被trim后的长度是否大于0,只对字符
串,且会去掉前后空格。
@NotEmpty:检查约束元素是否为null或者是empty。
示例如下:

@NotBlank(message="{goods.gname.required}")//goods.gname.required为属性文件的错误代码
private String gname;
2.booelan检查

@AssertTrue:验证boolean属性是否为true。
@AssertFalse:验证boolean属性是否为false。
示例如下:

@AssertTrue
private boolean isLogin;
3.长度检查

@Size(min=, max=):验证对象(Array,Collection,Map,String)长度是否在给定的范围之内。
@Length(min=, max=):验证字符串长度是否在给定的范围之内。
示例如下:

@Length(min=1,max=100)
private String gdescription;
4.日期检查

@Past:验证Date和Calendar对象是否在当前时间之前。
@Future:验证Date和Calendar对象是否在当前时间之后。
@Pattern:验证String对象是否符合正则表达式的规则。
示例如下:

@Past(message="{gdate.invalid}")
private Date gdate;
5.数值检查

@Min:验证Number和String对象是否大等于指定的值。
@Max:验证Number和String对象是否小等于指定的值。
@DecimalMax:被标注的值必须不大于约束中指定的最大值,这个约束的参数是一个通过BigDecimal定义的最大值的字符串表示,小数存在精度。
@DecimalMin:被标注的值必须不小于约束中指定的最小值,这个约束的参数是一个通过BigDecimal定义的最小值的字符串表示,小数存在精度。
@Digits:验证Number和String的构成是否合法。
@Digits(integer=,fraction=):验证字符串是否符合指定格式的数字,interger指定整数精度,fraction指定小数精度。
@Range(min=, max=):检查数字是否介于min和max之间。
@Valid:对关联对象进行校验,如果关联对象是个集合或者数组,那么对其中的元素进行校验,如果是一个map,则对其中的值部分进行校验。
@CreditCardNumber:信用卡验证。
@Email:验证是否是邮件地址,如果为null,不进行验证,通过验证。
示例如下:

@Range(min=0,max=100,message="{gprice.invalid}")
private double gprice;

【例5-4】使用Hibernate Validator验证表单的过程。

1.创建表单实体模型
在这里插入图片描述

package com.ch.ch5_1.model;
import javax.validation.constraints.NotBlank;
import org.hibernate.validator.constraints.Length;
import org.hibernate.validator.constraints.Range;
public class Goods {
	@NotBlank(message="商品名必须输入")
	@Length(min=1, max=5, message="商品名长度在1到5之间")
	private String gname;
	@Range(min=0,max=100,message="商品价格在0到100之间")
	private double gprice;
	public String getGname() {
		return gname;
	}
	public void setGname(String gname) {
		this.gname = gname;
	}
	public double getGprice() {
		return gprice;
	}
	public void setGprice(double gprice) {
		this.gprice = gprice;
	}
}

2.创建控制器
在这里插入图片描述

package com.ch.ch5_1.controller;
import org.springframework.stereotype.Controller;
import org.springframework.validation.BindingResult;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.RequestMapping;
import com.ch.ch5_1.model.Goods;
@Controller
public class TestValidatorController {
	@RequestMapping("/testValidator")
	public String testValidator(@ModelAttribute("goodsInfo") Goods goods){
		goods.setGname("商品名初始化");
		goods.setGprice(0.0);
	    return "testValidator";
	}
	@RequestMapping(value="/add")
	public String add(@ModelAttribute("goodsInfo") @Validated Goods goods,BindingResult rs){
		//@ModelAttribute("goodsInfo")与th:object="${goodsInfo}"相对应
	    if(rs.hasErrors()){//验证失败
	           return "testValidator";
	       }
	    //验证成功,可以到任意地方,在这里直接到testValidator界面
	    return "testValidator";
	}
}

3.创建视图页面
在这里插入图片描述

<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>
	<h2>通过th:object访问对象的方式</h2>
	<div th:object="${goodsInfo}">
	    <p th:text="*{gname}"></p>
	    <p th:text="*{gprice}"></p>
	</div>
	<h1>表单提交</h1>
	<!-- 表单提交用户信息,注意表单参数的设置,直接是*{} -->
	 <form  th:action="@{/add}" th:object="${goodsInfo}" method="post">  
	  <div><span>商品名</span><input type="text" th:field="*{gname}"/><span th:errors="*{gname}"></span></div>
	  <div><span>商品价格</span><input type="text" th:field="*{gprice}"/><span th:errors="*{gprice}"></span></div>
	  <input type="submit" />  
	</form> 
</body>
</html>

6.运行
在这里插入图片描述

6、 基于Thymeleaf与BootStrap的Web开发实例

【例5-5】创建基于Thymeleaf模板引擎的Spring Boot Web应用ch5_2

1.创建基于Thymeleaf模板引擎的Spring Boot Web应用ch5_2

在这里插入图片描述

2.设置Web应用ch5_2的上下文路径
在这里插入图片描述

server.servlet.context-path=/ch5_2

3.创建实体类Book
在这里插入图片描述

package com.ch.ch5_2.model;
public class Book {
	String isbn;
	Double price;
	String bname;
	String publishing;
	String author;
	String picture;
	public Book(String isbn, Double price, String bname, String publishing, String author, String picture) {
		super();
		this.isbn = isbn;
		this.price = price;
		this.bname = bname;
		this.publishing = publishing;
		this.author = author;
		this.picture = picture;
	}
	public String getIsbn() {
		return isbn;
	}
	public void setIsbn(String isbn) {
		this.isbn = isbn;
	}
	public Double getPrice() {
		return price;
	}
	public void setPrice(Double price) {
		this.price = price;
	}
	public String getBname() {
		return bname;
	}
	public void setBname(String bname) {
		this.bname = bname;
	}
	public String getPublishing() {
		return publishing;
	}
	public void setPublishing(String publishing) {
		this.publishing = publishing;
	}
	public String getAuthor() {
		return author;
	}
	public void setAuthor(String author) {
		this.author = author;
	}
	public String getPicture() {
		return picture;
	}
	public void setPicture(String picture) {
		this.picture = picture;
	}
}

4.创建控制器类ThymeleafController
在这里插入图片描述

package com.ch.ch5_2.controller;
import java.util.ArrayList;
import java.util.List;

import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;

import com.ch.ch5_2.model.Book;
@Controller
public class ThymeleafController {
	@RequestMapping("/")
	public String index(Model model) {
		Book teacherGeng = new Book(
				"9787302464259", 
				59.5, 
				"Java 2实用教程(第5版)",
				"清华大学出版社",
				"耿祥义",
				"073423-02.jpg"
				);
		List<Book> chenHeng = new ArrayList<Book>();
		Book b1 = new Book(
				"9787302529118", 
				69.8, 
				"Java Web开发从入门到实战(微课版)", 
				"清华大学出版社", 
				"陈恒",
				"082526-01.jpg"
				);
		chenHeng.add(b1);
		Book b2 = new Book(
				"9787302502968", 
				69.8, 
				"Java EE框架整合开发入门到实战——Spring+Spring MVC+MyBatis(微课版)",
				"清华大学出版社", 
				"陈恒",
				"079720-01.jpg");
		chenHeng.add(b2);
		model.addAttribute("aBook", teacherGeng);
		model.addAttribute("books", chenHeng);
		return "index";
	}
}

5.整理脚本样式静态文件
在这里插入图片描述

6.View视图页面
在这里插入图片描述

<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
<link rel="stylesheet" th:href="@{css/bootstrap.min.css}" />
<!-- 默认访问 src/main/resources/static下的css文件夹-->
<link rel="stylesheet" th:href="@{css/bootstrap-theme.min.css}" />
</head>
<body>
	<!-- 面板 -->
	<div class="panel panel-primary">
		<!-- 面板头信息 -->
		<div class="panel-heading">
			<!-- 面板标题 -->
			<h3 class="panel-title">第一个基于Thymeleaf模板引擎的Spring Boot Web应用</h3>
		</div>
	</div>
	<!-- 容器 -->
	<div class="container">
		<div>
        	<h4>图书列表</h4>
    	</div>
		<div class="row">
			<!-- col-md针对桌面显示器 col-sm针对平板 -->
			<div class="col-md-4 col-sm-6">
				<a href="">
					<img th:src="'images/' + ${aBook.picture}" alt="图书封面" style="height: 180px; width: 40%;"/>
				</a>
				<!-- caption容器中放置其他基本信息,比如标题、文本描述等 -->
				<div class="caption">
					<h4 th:text="${aBook.bname}"></h4>
					<p th:text="${aBook.author}"></p>
					<p th:text="${aBook.isbn}"></p>
					<p th:text="${aBook.price}"></p>
					<p th:text="${aBook.publishing}"></p>
				</div>
			</div>
			<!-- 循环取出集合数据 -->
			<div class="col-md-4 col-sm-6" th:each="book:${books}">
				<a href="">
					<img th:src="'images/' + ${book.picture}" alt="图书封面" style="height: 180px; width: 40%;"/>
				</a>
				<div class="caption">
					<h4 th:text="${book.bname}"></h4>
					<p th:text="${book.author}"></p>
					<p th:text="${book.isbn}"></p>
					<p th:text="${book.price}"></p>
					<p th:text="${book.publishing}"></p>
				</div>
			</div>
		</div>
	</div>
</body>
</html>

7.运行
在这里插入图片描述

二、Spring Boot处理JSON数据

三、Spring Boot的文件上传与下载

四、Spring Boot的异常处理

五、Spring Boot对JSP的支持


学习时间:

在这里插入图片描述


学习产出:

1、 技术笔记 1 遍
2、CSDN 技术博客 1 篇

  • 2
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值