渲染Web视图
理解视图解析
在前面我们已经接触了一个Springmvc中的视图解析器,InternalResourceViewResolver。下图是其继承结构:
InternalResourceViewResolver:这个视图解析器应该不陌生,在SSM项目中整合JSP的时候,一般都会使用到这个视图解析器。下面这段代码应该也似曾相识,在SpringMVC.xml文件中都会配置到,这里只是以代码的方式进行配置,最熟悉的莫过于prefix 和 suffix ,分别是指定视图的前缀和后缀,即当视图解析器根据逻辑视图名映射视图的时候,会在Controller的返回值分别在其前后拼接配置好的前后缀,就形成了物理视图,比如Controller中返回的是home.其物理地址就是/WEB-INF/views/home.jsp 。
1 2 3 4 5 6 7 8 9 10 11 12 13
| @Bean public ViewResolver viewResolver(){ InternalResourceViewResolver resolver = new InternalResourceViewResolver(); resolver.setPrefix("/WEB-INF/views/"); resolver.setSuffix(".jsp"); resolver.setExposeContextBeansAsAttributes(true);
resolver.setViewClass(JstlView.class); return resolver; }
|
我们看一下视图解析器返回的ViewResolver的代码:
1 2 3 4
| public interface ViewResolver { @Nullable View resolveViewName(String viewName, Locale locale) throws Exception; }
|
当给resolveViewName方法传入一个视图名和Locale对象时,会返回一个View实例,View是另外一个接口:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| public interface View {
String RESPONSE_STATUS_ATTRIBUTE = View.class.getName() + ".responseStatus";
String PATH_VARIABLES = View.class.getName() + ".pathVariables";
String SELECTED_CONTENT_TYPE = View.class.getName() + ".selectedContentType";
@Nullable default String getContentType() { return null; } void render(@Nullable Map<String, ?> model, HttpServletRequest request, HttpServletResponse response)throws Exception; }
|
View接口的任务就是接受模型以及Servlet的request和response对象,并将输出结果渲染到response中。
https://docs.spring.io/spring/docs/5.1.9.RELEASE/spring-framework-reference/web.html#mvc-viewresolver
spring官网介绍了几种视图解析器。InternalResourceViewResolver一般会用于JSP。TilesViewResolver用于Apache Tiles视图,而FreeMarkerViewResolver和VelocityViewResolver分别用于FreeMarker和Velocity模板视图。
解析JSTL视图
使用InternalResourceViewResolver进行视图解析,默认会将视图解析为InternalResourceView实例,但是如果我们在JSP文件中使用JSTL标签去处理了例如国际化的这个格式化和信息的化,我们希望将视图解析为JSTLView。JSTL的格式化标签需要一个Locale对象,以便于恰当的格式化地域相关的值,如日期和货币。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| <%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %> <%@ taglib prefix="fmt" uri="http://java.sun.com/jsp/jstl/fmt" %> .... <body> <!-- <fmt:setLocale value="${param.setLocale}"/> 区域语言的值从传过来的参数中得到 --> <fmt:setLocale value="en_US"/> <!--指定区域语言--> <fmt:bundle basename="globalMessages"> <!-- 指定使用basename为globalMessages的资源文件,也即资源文件第一个单词为globalMessages--> <center> <table> <tr> <td><fmt:message key="email"/></td> <td><input type="text" name="email"></td> </tr> </table> </center> </fmt:bundle> </body>
|
如果我们想要将视图渲染为JSTL视图,只需要在下面添加配置:setViewClass即可。
1 2 3 4 5 6 7 8 9 10 11 12 13
| @Bean public ViewResolver viewResolver(){ InternalResourceViewResolver resolver = new InternalResourceViewResolver(); resolver.setPrefix("/WEB-INF/views/"); resolver.setSuffix(".jsp"); resolver.setExposeContextBeansAsAttributes(true);
resolver.setViewClass(JstlView.class); return resolver; }
|
Spring的JSP库
Spring提供了两个JSP标签库,用来帮助定义SpringMVC Web的视图。其中一个标签库会用来渲染HTML表单标签,这些标签可以绑定model中的某个属性。另外一个标签库包含了一些工具类标签,我们随时都可以非常便利地使用它们。
JSP标签
借助Spring表单绑定标签库中所包含的标签,我们能够将模型对象绑定到渲染后的HTML表单中。
JSP标签 |
描述 |
<sf:checkbox> |
渲染成一个HTML<input>标签,其中type属性设置为checkbox |
<sf:checkboxs> |
渲染成多个HTML<input>标签,其中type属性设置为checkbox |
<sf:errors> |
在一个HTML<span>中输入输入域的错误 |
<sf:form> |
渲染成一个HTML<form>标签,并为其内部标签暴露绑定路径,用于数据绑定 |
<sf:hidden> |
渲染成一个HTML<input>标签,其中type属性设置为hidden |
<sf:input> |
渲染成一个HTML<input>标签,其中type属性设置为text |
<sf:label> |
渲染成一个HTML<label>标签 |
<sf:option> |
渲染成一个HTML<option>标签,其selected属性根据所绑定的执行设置 |
<sf:options> |
按照绑定的集合、数组或Map,渲染成一个HTML<option>标签列表 |
<sf:password> |
渲染成一个HTML<input>标签,其中type属性设置为password |
<sf:radiobutton> |
渲染成一个HTML<input>标签,其中type属性设置为radio |
<sf:radiobuttons> |
渲染成多个HTML<input>标签,其中type属性设置为radio |
<sf:select> |
渲染为一个HTML<select>标签 |
<sf:textarea> |
渲染为一个HTML<textarea>标签 |
将标签绑定到模型上
如果在jsp中引入spring标签呢?
1
| <%@ taglib prefix="sf" uri="http://www.springframework.org/tags/form" %>
|
sf:form会渲染成一个HTML
最初的注册表单:
1 2 3 4 5 6
| <form method="post" > 用户名:<input name="username" type="text" ><br> 密码:<input name="password" type="password" ><br> 年龄:<input name="age" type="number" ><br> <input type="submit" value="提交"><br> </form>
|
使用Spring的标签库:
1 2 3 4 5 6 7 8 9
| <sf:form method="post" modelAttribute="user" > 账号:<sf:input path="username"/> <sf:errors path="username" cssClass="error" /><br> 密码:<sf:password path="password"/> <sf:errors path="password" cssClass="error" /><br> 年龄:<sf:input path="age"/> <sf:errors path="age" cssClass="error" /><br> <input type="submit" value="提交" ><br> </sf:form>
|
这里需要自定义一个error的css样式
1 2 3
| span.error{ color:red; }
|
如果不填数据提交,则会出现响应的错误提示。
为什么会出现这种提示信息呢?当然不仅仅是因为将前面的标签换成了Spring的标签。还有就是在Controller中绑定了对象。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| @GetMapping("/register") public String toRegister(Model model){ model.addAttribute("user",new User()); return "register"; }
@PostMapping("/register") public String register(@Valid User user, Errors errors){ if (errors.hasErrors()){ return "register"; } userService.saveUser(user); return "redirect:/registerSuccess"; }
|
User:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| public class User implements Serializable {
@NotNull @Size(min = 4,max = 20, message = "{username.size}") private String username;
@NotNull @Size(min = 6,max = 32,message = "密码需要在{min} 到 {max} 位之间") private String password;
@NotNull(message = "年龄不能为空") @Min(value = 1,message = "年龄要大于等于1") @Max(value = 150,message = "年龄需要小于150") private Integer age; }
|
可以看出,username的@size使用{}大括号来读取配置文件信息,解决了硬编码问题。由于这是输入数据验证,所以默认读取的是classpath下的,ValidationMessages.properties文件。如下:
1
| username.size = 账号需要在{min} 到 {max} 位之间
|
而{min}和{max}可以读取到@size中的min和max属性。
如何将错误信息显示到一个地方呢?
1 2 3 4 5 6 7
| <sf:form method="post" modelAttribute="user" > <sf:errors element="div" path="*" cssClass="errors"/> 账号:<sf:input path="username"/><br> 密码:<sf:password path="password" /><br> 年龄:<sf:input path="age"/><br> <input type="submit" value="提交" ><br> </sf:form>
|
可以看出,将之前每一个输入框后都有一个对应的sf:errors 用来显示错误信息。而这里进行修改了,将错误信息全部放到了一个div元素中,并且path使用通配符*来描述。
并且css样式定义为了errors:
1 2 3 4
| div.errors{ background-color: #ffcccc; border: 2px solid red; }
|
此时,测试结果如下:
通过上面的测试结果图片可以看出,此时虽然错误信息全部显示在一起了,但是并没有明显的显示是哪一个输入框或是输入属性填写有问题。下面,再次修改:
1 2 3 4 5 6 7 8 9 10
| <sf:form method="post" modelAttribute="user" > <sf:errors element="div" path="*" cssClass="errors"/> <sf:label path="username" cssErrorClass="error">账号:</sf:label> <sf:input cssErrorClass="error" path="username"/><br> <sf:label path="password" cssErrorClass="error">密码:</sf:label> <sf:password cssErrorClass="error" path="password" /><br> <sf:label path="age" cssErrorClass="error">年龄:</sf:label> <sf:input cssErrorClass="error" path="age"/><br> <input type="submit" value="提交" ><br> </sf:form>
|
如上代码,我们已经使用div类型的sf:errors来统一显示错误信息,并且将提示信息使用了sf:label进行修饰,使用path进行绑定数据,同时使用cssErrorClass属性来引用出现错误时的css样式。
1 2 3 4 5 6
| label.error{ color:red; } input.error{ background-color: #ffcccc; }
|
所以,上述的代码运行结果如:
至此,Spring的JSP标签就告一段落了。
Spring 通用的标签库
如何引入在JSP文件中引入spring通用的标签库?
1
| <%@ taglib prefix="s" uri="http://www.springframework.org/tags" %>
|
以上标签大部分使用得很少,因为部分标签已被Spring所淘汰了。
展现国际化信息
我们都知道,如果将文本内容硬编码到网页里面,就无法实现动态改变网页显示内容,比如我们在没学习JavaScript之前,构建网页只是使用了HTML+CSS,那么我们的页面一旦写好了,在运行过程中是无法动态修改的。而我们后台系统中,绝大部分数据是以图表的形式展示,而表格的数据是动态切换的,比如:表格分页。分页的时候,网页URL并没有变化,而数据却修改了。而我们如果需要实现国际化也是一样的。所有需要进行国际化编码显示的内容都不可以硬编码到网页中,那么如何实现呢?下面看看Spring提供的方式:
使用到的标签是上面表格中的<s:message code = “”>
home.jsp
1 2 3 4 5 6 7 8 9 10 11 12 13
| <%@ taglib prefix="s" uri="http://www.springframework.org/tags" %> <%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %> <%@ taglib prefix="sf" uri="http://www.springframework.org/tags/form" %> <%@ page contentType="text/html;charset=UTF-8" language="java" %> <html> <head> <title>Blog</title> </head> <body>
<h1><s:message code="article.welcome"/></h1> </body> </html>
|
配置文件中配置引用文件:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
|
@Bean public MessageSource messageSource(){ ReloadableResourceBundleMessageSource messageSource = new ReloadableResourceBundleMessageSource(); messageSource.setBasenames("classpath:message"); messageSource.setCacheSeconds(10); return messageSource; }
|
上述配置类中,这两个类都可以使用,但是有一定的区别:ResourceBundleMessageSource是从classpath中查询message文件,但是ReloadableResourceBundleMessageSource既可以从文件系统file:/,也可以使用classpath来指定类路径下引用,或是web应用的根目录下(没有前缀)查找。
1 2 3 4 5
| -- zh-CN: article.welcome = 欢迎来到spring的大世界
-- en-US: article.welcome = welcome to Spring's world
|
如上图所示:创建两个properties文件,名称如上,en-US表示英文,zh-CN表示中文,由于浏览器更改语言环境不方便,这里我们使用Postman来测试。如下:
注意:Accept-Language的value值,比如zh-CN,需要将-写成中划线,不能写成下划线,否则不会生效。
创建URL
链接对于HTML页面来说,是一种最寻常不过的元素了,下面我们来了解一下spring URL标签的神奇:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35
| <%@ taglib prefix="s" uri="http://www.springframework.org/tags" %> <%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %> <%@ taglib prefix="sf" uri="http://www.springframework.org/tags/form" %> <%@ page contentType="text/html;charset=UTF-8" language="java" %> <html> <head> <title>Blog</title> </head> <body>
<a href="<s:url value="/articles"/>" > 所有文章 </a> | <a href="<s:url value="/register"/>"> 注册 </a> <br>
<h2>使用spring的标签库</h2> <%--定义一个变量,url的作用域默认在页面,但是可以通过scope进行修改--%> <s:url value="/articles" scope="session" var="articlesUrl"/> <%--在连接中使用,--%> <a href="<s:url value="${articlesUrl}"/> ">所有文章</a><br> <%--传参数--%> <s:url value="/article" var="article" > <s:param name="page" value="1"/> <s:param name="size" value="2"/> </s:url> <a href="${article}">分页查询文章,page=1 size=2</a><br/>
<%--路径参数,如果有参数不匹配,则会转为普通参数传递。http: <s:url value="/article/{id}" var="articleId"> <s:param name="id" value="3"/> <s:param name="name" value="ouyang"/> </s:url> <a href="${articleId}">使用路径变量来获取文章{id = 3}</a>
</body> </html>
|
- 普通使用
<a href=”<s:url value=”/articles”/>” >` ,使用spring url标签,jsp页面渲染时,会将项目名自动与/articles 拼接。当我们将鼠标放在所有文章上面,可以看到下面的提示:
即:单纯普通使用spring的url标签,与jstl标签类似,也会自动拼接上项目名。
- 定义成变量,设置scope
1 2 3 4
| <%--定义一个变量,url的作用域默认在页面,但是可以通过scope进行修改--%> <s:url value="/articles" scope="session" var="articlesUrl"/> <%--在连接中使用,--%> <a href="<s:url value="${articlesUrl}"/> ">所有文章</a><br>
|
上述两行代码则说明,可以先将连接独立成一个变量,然后在进行引用,如使用var来定义连接变量。则在需要使用的地方可以使用${}来引用。同时我们可以看到,可以进行scope的设置,即:设置链接的作用域,链接本身的默认的作用域是page,而我们可以设置为request,session,application等作用域。
- 查询参数传递
1 2 3 4 5 6
| <%--传参数--%> <s:url value="/article" var="article" > <s:param name="page" value="1"/> <s:param name="size" value="2"/> </s:url> <a href="${article}">分页查询文章,page=1 size=2</a><br/>
|
我们直接看效果:
- 传递路径参数
1 2 3 4 5 6
| <%--路径参数,如果有参数不匹配,则会转为普通参数传递。http: <s:url value="/article/{id}" var="articleId"> <s:param name="id" value="3"/> <s:param name="name" value="ouyang"/> </s:url> <a href="${articleId}">使用路径变量来获取文章{id = 3}</a>
|
效果:
结合上述说明和效果图可以发现,我们可以使用{}来定义路径参数,如果存在参数匹配不到路径变量,则自动转为查询参数拼接到请求URL上。
转义内容
1 2 3 4 5
| <%--内容转义--%> <s:escapeBody htmlEscape="true"> <h1>这是转义的一级标题标签</h1> </s:escapeBody> <h1>这是没有转义的一级标题标签</h1>
|
我们可以使用<s:escapeBody>来进行内容转义。效果如下:
使用Thymeleaf
如今我们可以发现,jsp慢慢不再使用了,而转向了Thymeleaf,jsp本质来说不是HTML,并且它是依赖于Servlet的,这也就说明,JSP不能独立于Servlet,必须建立于基于Servlet的web容器上。JSP模板不能作为通用的模板(如格式化EMail),也不能用于非Servlet的web应用。
官网:https://www.thymeleaf.org/
Spring整合Thymeleaf
- 添加POM依赖。
可以进到Thymeleaf官网:https://www.thymeleaf.org/download.html
1 2 3 4 5 6 7 8 9 10
| <dependency> <groupId>org.thymeleaf</groupId> <artifactId>thymeleaf</artifactId> <version>3.0.11.RELEASE</version> </dependency> <dependency> <groupId>org.thymeleaf</groupId> <artifactId>thymeleaf-spring5</artifactId> <version>3.0.9.RELEASE</version> </dependency>
|
此时,项目的完整POM文件如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115
| <?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 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>com.ooyhao.spring</groupId> <artifactId>spring-in-action-06-01</artifactId> <version>1.0-SNAPSHOT</version> <packaging>war</packaging>
<name>spring-in-action-06-01 Maven Webapp</name> <url>http://www.example.com</url>
<properties> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <maven.compiler.source>1.7</maven.compiler.source> <maven.compiler.target>1.7</maven.compiler.target> </properties> <dependencies> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-webmvc</artifactId> <version>5.1.9.RELEASE</version> </dependency>
<dependency> <groupId>javax.servlet</groupId> <artifactId>javax.servlet-api</artifactId> <version>4.0.1</version> </dependency>
<dependency> <groupId>org.hibernate.validator</groupId> <artifactId>hibernate-validator</artifactId> <version>6.1.0.Alpha3</version> </dependency>
<dependency> <groupId>jstl</groupId> <artifactId>jstl</artifactId> <version>1.2</version> </dependency>
<dependency> <groupId>com.fasterxml.jackson.core</groupId> <artifactId>jackson-databind</artifactId> <version>2.9.8</version> </dependency>
<dependency> <groupId>com.fasterxml.jackson.core</groupId> <artifactId>jackson-annotations</artifactId> <version>2.9.8</version> </dependency>
<dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>4.11</version> <scope>test</scope> </dependency> <dependency> <groupId>org.thymeleaf</groupId> <artifactId>thymeleaf</artifactId> <version>3.0.11.RELEASE</version> </dependency>
<dependency> <groupId>org.thymeleaf</groupId> <artifactId>thymeleaf-spring5</artifactId> <version>3.0.9.RELEASE</version> </dependency> </dependencies>
<build> <finalName>spring-in-action-06-01</finalName> <pluginManagement> <plugins> <plugin> <artifactId>maven-clean-plugin</artifactId> <version>3.1.0</version> </plugin> <plugin> <artifactId>maven-resources-plugin</artifactId> <version>3.0.2</version> </plugin> <plugin> <artifactId>maven-compiler-plugin</artifactId> <version>3.8.0</version> </plugin> <plugin> <artifactId>maven-surefire-plugin</artifactId> <version>2.22.1</version> </plugin> <plugin> <artifactId>maven-war-plugin</artifactId> <version>3.2.2</version> </plugin> <plugin> <artifactId>maven-install-plugin</artifactId> <version>2.5.2</version> </plugin> <plugin> <artifactId>maven-deploy-plugin</artifactId> <version>2.8.2</version> </plugin> </plugins> </pluginManagement> </build> </project>
|
配置整合Thymeleaf
在ServletConfig配置文件中配置相应的信息来整合Thymeleaf模板。
配置Thymeleaf视图解析器:
为了要在Spring中使用Thymeleaf,我们需要配置三个启用Thymeleaf与Spring集成的bean:
- ThymeleafViewResolver:将逻辑视图名称解析为Thymeleaf模式视图;
- SpringTemplateEngine:处理模板并渲染结果;
- TemplateResolver:加载Thymeleaf模板;
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27
| @Bean public SpringResourceTemplateResolver templateResolver(){ SpringResourceTemplateResolver resolver = new SpringResourceTemplateResolver(); resolver.setTemplateMode(TemplateMode.HTML); resolver.setPrefix("/WEB-INF/templates/"); resolver.setSuffix(".html"); resolver.setCharacterEncoding("utf-8"); resolver.setCacheable(true); return resolver; }
@Bean public SpringTemplateEngine templateEngine(){ SpringTemplateEngine engine = new SpringTemplateEngine(); engine.setTemplateResolver(templateResolver()); engine.setEnableSpringELCompiler(true); return engine; }
@Bean public ThymeleafViewResolver viewResolver(){ ThymeleafViewResolver resolver = new ThymeleafViewResolver(); resolver.setTemplateEngine(templateEngine()); resolver.setCharacterEncoding("utf-8"); return resolver; }
|
注意:需要在templateResolver和viewResolver中设置字符编码,否则会出现中文乱码的情况。
此时,ServletConfig.java的完整文件如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88
| @Configuration @EnableWebMvc @ComponentScan(basePackages = "com.ooyhao.spring.**.controller") public class ServletConfig implements WebMvcConfigurer {
@Bean public MessageSource messageSource(){ ReloadableResourceBundleMessageSource messageSource = new ReloadableResourceBundleMessageSource(); messageSource.setBasenames("classpath:message"); messageSource.setCacheSeconds(10); return messageSource; }
@Override public void configureDefaultServletHandling(DefaultServletHandlerConfigurer configurer) { configurer.enable(); }
@Bean public SpringResourceTemplateResolver templateResolver(){ SpringResourceTemplateResolver resolver = new SpringResourceTemplateResolver(); resolver.setTemplateMode(TemplateMode.HTML); resolver.setPrefix("/WEB-INF/templates/"); resolver.setSuffix(".html"); resolver.setCharacterEncoding("utf-8"); resolver.setCacheable(true); return resolver; }
@Bean public SpringTemplateEngine templateEngine(){ SpringTemplateEngine engine = new SpringTemplateEngine(); engine.setTemplateResolver(templateResolver()); engine.setEnableSpringELCompiler(true); return engine; }
@Bean public ThymeleafViewResolver viewResolver(){ ThymeleafViewResolver resolver = new ThymeleafViewResolver(); resolver.setTemplateEngine(templateEngine()); resolver.setCharacterEncoding("utf-8"); return resolver; } }
|
通过上述配置 Thymeleaf templateResolver 视图解析器,与之前配置JSP视图解析器类似,都是通过逻辑视图名来定位文件,但是这里需要依赖templateEngine。
接下来按照上述代码配置或图中所示的位置编写相应的html页面即可。
Thymeleaf实现表单绑定
html文件
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51
| <!DOCTYPE html> <html xmlns="http://www.w3.org/1999/xhtml" xmlns:th="http://www.thymeleaf.org"> <head> <title>Blog</title> <meta charset="utf-8"> </head>
<style> span.error{ color:red; } div.errors{ background-color: #ffcccc; border: 2px solid red; } label.error{ color:red; } input.error{ background-color: #ffcccc; } </style>
</head> <body>
<h1>欢迎加入Spring的大家庭</h1>
<form method="post" th:object="${user}" >
<div class="errors" th:if="${#fields.hasErrors('*')}" > <ul> <li th:each="err : ${#fields.errors('*')}" th:text="${err}" > Input is Incorrect </li> </ul> </div> <label th:class="${#fields.hasErrors('username')} ? 'error' ">账号:</label> <input type="text" th:field="*{username}" th:class="${#fields.hasErrors('username')} ? 'error'"/><br>
<label th:class="${#fields.hasErrors('password')} ? 'error' ">密码:</label> <input type="password" th:field="*{password}" th:class="${#fields.hasErrors('password')} ? 'error'" /><br>
<label th:class="${#fields.hasErrors('age')} ? 'error' ">年龄:</label> <input th:field="*{age}" th:class="${#fields.hasErrors('age')} ? 'error'"/><br>
<input type="submit" value="提交" ><br> </form> </body> </html>
|
可以看出:代码中是通过使用fields.hasErrors以及后台的数据校验来判断是否有错误的。后台代码与之前的jsp略有不同:
Controller文件
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
|
@PostMapping("/register") public String register(@Valid User user, Errors errors){ if (errors.hasErrors()){ return "register"; } userService.saveUser(user); return "redirect:/registerSuccess"; }
@PostMapping("/register") public String register(@Valid User user, BindingResult bindingResult,Model model){ if (bindingResult.hasErrors()){ System.out.println("错误数目:" + bindingResult.getErrorCount()); model.addAttribute(user); return "register"; } userService.saveUser(user); return "redirect:/registerSuccess"; }
|
jsp使用spring的标签时是用Errors来判断,而html使用Thymeleaf时是使用BindingResult来进行判断。上述代码显示了不同之处。
效果图
总结:
至此,本节已经学习了Spring如何整合JSP,使用Spring的标签,同时也接触了当前正在逐渐替代JSP的Thymeleaf,也实现了之前使用JSP同样地表单双向绑定的效果。
使用Thymeleaf实现表单双向绑定参考了
https://blog.csdn.net/z28126308/article/details/54429853