Spring MVC数据校验

数据校验是每个项目中必不可少的模块,SpringMVC提供了两种数据校验的组件:

  • 基于Validator接口进行校验
  • 使用Annotation JSR-303标准校验

使用基于Validator接口进行校验会复杂一些,因为具体的数据校验规则需要开发者手动设置,而使用Annotation JSR-303标准相对简单一些,开发者不需要编写校验规则,直接通过注解的形式给每一条数据添加验证规则,具体的操作是直接在实体类的属性上添加对应的校验注解即可。

基于Validator接口

1、创建实体类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
package com.bitzh.entity;

import lombok.Data;

/**
* @Auther: oyy0v0
* @Date: 2024/8/2 - 08 - 02 - 8:07
* @Description: com.bitzh.entity
* @version: 1.0
*/
@Data
public class Student {
private String name;
private String password;
}

2、自定义数据校验器StudentValidation,实现Validator接口,并且需要重写接口的抽象方法,加入校验的规则。

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
package com.bitzh.validation;

import com.bitzh.entity.Student;
import org.springframework.validation.Errors;
import org.springframework.validation.ValidationUtils;
import org.springframework.validation.Validator;

/**
* @Auther: oyy0v0
* @Date: 2024/8/3 - 08 - 03 - 18:35
* @Description: com.bitzh.validation
* @version: 1.0
*/
public class StudentValidation implements Validator {
@Override
public boolean supports(Class<?> clazz) {
return Student.class.equals(clazz);
}

@Override
public void validate(Object target, Errors errors) {
ValidationUtils.rejectIfEmpty(errors,"name",null,"姓名不能为空");
ValidationUtils.rejectIfEmpty(errors,"password",null,"密码不能为空");
}
}

3、控制层业务方法

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
package com.bitzh.controller;

import com.bitzh.entity.Student;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.ui.ModelMap;
import org.springframework.validation.BindingResult;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;

/**
* @Auther: oyy0v0
* @Date: 2024/8/4 - 08 - 04 - 3:08
* @Description: com.bitzh.controller
* @version: 1.0
*/
@Controller
@RequestMapping("/validate")
public class ValidatetorHandler {

/**
* 给JSP绑定模型对象
* @param model
* @return
*/
@GetMapping("/login")
public String login(Model model){
model.addAttribute(new Student());
return "login";
}

/**
* 数据校验
* @param student
* @param bindingResult
* @return
*/
@PostMapping("/login")
public String login(@Validated Student student, BindingResult bindingResult){
if(bindingResult.hasErrors()){
return "login";
}
return "success";
}
}

4、springmvc.xml中配置validator

1
2
<mvc:annotation-driven validator="studentValidator"></mvc:annotation-driven>
<bean id="studentValidator" class="com.bitzh.validation.StudentValidation"></bean>

5、jsp

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
<%--
Created by IntelliJ IDEA.
User: pc
Date: 2024/8/4
Time: 3:10
To change this template use File | Settings | File Templates.
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@ taglib prefix="form" uri="http://www.springframework.org/tags/form"%>
<html>
<head>
<title>Title</title>
</head>
<body>
<h1>学生登录</h1>
<form:form modelAttribute="student" action="/validate/login" method="post">
学生姓名:<form:input path="name"></form:input><form:errors path="name"></form:errors> <br/>
学生密码:<form:input path="password"></form:input><form:errors path="password"></form:errors><br/>
<input type="submit" value="提交">
</form:form>

</body>
</html>

这里不能直接写form表单因为会不生效,要有一个GET模型将form表单中的数据自动绑定到我们学生类的变量中,然后才能进行数据校验,所以一开始用了GetMapping来动态绑定对应变量,并且在JSP中用了标签库

image-20240804033706110

Annotation JSR-303标准(推荐)

Hibernater Validator,通过注解完成校验规则的绑定。

@Null 只能为null

@NotNull 不能为null

@Size 设置数据长度

@NotEmpty 不能为空

String str= null;

String str = “”;这是空

1、pom.xml导入依赖

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
<!--JSR-303-->
<dependency>
<groupId>org.hibernate.validator</groupId>
<artifactId>hibernate-validator</artifactId>
<version>6.2.0.Final</version>
</dependency>
<dependency>
<groupId>jakarta.validation</groupId>
<artifactId>jakarta.validation-api</artifactId>
<version>3.0.2</version>
</dependency>
<dependency>
<groupId>org.jboss.logging</groupId>
<artifactId>jboss-logging</artifactId>
<version>3.3.0.Final</version>
</dependency>

<!--JDK9以上-->
<dependency>
<groupId>jakarta.xml.bind</groupId>
<artifactId>jakarta.xml.bind-api</artifactId>
<version>4.0.0</version>
</dependency>
<dependency>
<groupId>org.glassfish.jaxb</groupId>
<artifactId>jaxb-core</artifactId>
<version>2.3.0.1</version>
</dependency>
<dependency>
<groupId>jakarta.activation</groupId>
<artifactId>jakarta.activation-api</artifactId>
<version>2.1.2</version>
</dependency>
<dependency>
<groupId>com.sun.xml.bind</groupId>
<artifactId>jaxb-impl</artifactId>
<version>4.0.5</version>
</dependency>

2、创建实体类,通过注解的方式给属性指定校验规则。

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
package com.bitzh.entity;

import jakarta.validation.constraints.Pattern;
import jakarta.validation.constraints.Size;
import lombok.Data;
import org.hibernate.validator.constraints.Email;
import org.hibernate.validator.constraints.NotEmpty;

/**
* @Auther: oyy0v0
* @Date: 2024/8/4 - 08 - 04 - 3:54
* @Description: com.bitzh.entity
* @version: 1.0
*/
@Data
public class Account {
@NotEmpty(message = "用户名不能为空")
private String name;
@Size(min = 6,max = 20,message = "密码长度为6-20位")
private String password;
@Email(regexp = "^[a-zA-Z0-9_.-]+@[a-zA-Z0-9-]+(\\.[a-zA-Z0-9-]+)*\\.[a-zA-Z0-9]{2,6}$", message = "请输入正确的邮箱")
private String email;
@Pattern(regexp = "/^(13[0-9]|14[01456879]|15[0-35-9]|16[2567]|17[0-8]|18[0-9]|19[0-35-9])\\d{8}$/",message = "请输入正确的电话格式")
private String phone;

}


3、业务方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
@GetMapping("/register")
public String register(Model model){
model.addAttribute(new Account());
return "register";
}

@PostMapping("/register")
public String register(@Valid Account account,BindingResult bindingResult){
if(bindingResult.hasErrors()){
return "register";
}
return "success";

}

4、配置springmvc.xml

1
<mvc:annotation-driven></mvc:annotation-driven>

5、register.jsp

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
<%--
Created by IntelliJ IDEA.
User: pc
Date: 2024/8/4
Time: 4:10
To change this template use File | Settings | File Templates.
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@ taglib prefix="form" uri="http://www.springframework.org/tags/form"%>
<html>
<head>
<title>Title</title>
</head>
<body>
<h1>用户注册</h1>
<form:form modelAttribute="account" action="/validate/register">
用户名:<form:input path="name"></form:input><form:errors path="name"></form:errors> <br/>
密码:<form:input path="password"></form:input><form:errors path="password"></form:errors><br/>
邮箱:<form:input path="email"></form:input><form:errors path="email"></form:errors><br/>
电话:<form:input path="phone"></form:input><form:errors path="phone"></form:errors><br/>
<input type="submit" value="提交">
</form:form>

</body>
</html>

Spring MVC表单标签库

为什么要使用表单标签库,为了实现快速开发,

1、创建Student实体类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
package com.bitzh.entity2;

import lombok.Data;

/**
* @Auther: oyy0v0
* @Date: 2024/8/4 - 08 - 04 - 13:12
* @Description: com.bitzh.entity2
* @version: 1.0
*/
@Data
public class Student {
private Integer id;
private String name;
private Integer age;
private String gender;
}

2、Handler

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
package com.bitzh.controller;

import com.bitzh.entity.Student;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;

/**
* @Auther: oyy0v0
* @Date: 2024/8/4 - 08 - 04 - 13:14
* @Description: com.bitzh.controller
* @version: 1.0
*/
@Controller
@RequestMapping("/student")
public class StudentHandler {

@RequestMapping("/get")
public String get(Model model){
Student student = new Student();
model.addAttribute("student",student);
return "student";
}
}

3、JSP

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
<%--
Created by IntelliJ IDEA.
User: pc
Date: 2024/8/4
Time: 13:15
To change this template use File | Settings | File Templates.
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@ page isELIgnored="false" %>
<html>
<head>
<title>Title</title>
</head>
<body>
<h1>修改学生信息</h1>
<form action="" method="post">
学生编号:<input type="text" name="id" value="${student.id}" readonly/><br/>
学生姓名:<input type="text" name="name" value="${student.name}"><br/>
学生年龄:<input type="text" name="age" value="${studnet.age}"<br/>
学生性别:<input type="text" name="gender" value="${student.gender}"><br/>
<input type="submit" value="提交"/>
</form>
</body>
</html>


使用Spring MVC表单标签可以直接将业务数据绑定到JSP表单中,非常简单。

表单标签库的使用

1、JSP页面中导入Spring MVC 表单标签库。

1
<%@ taglib prefix="form" uri="http://www.springframework.org/tags/form" %>

2、将form表单与业务数据进行绑定,通过ModelAttribute属性完成绑定,将modelAttribute的值设置为控制器向model对象存值时的name即可。

1
2
3
4
5
6
7
8
<form:form modelAttribute="student" action="/student/update" method="post">
学生编号:<form:input path="id"></form:input><br/>
学生姓名:<form:input path="name"></form:input><br/>
学生年龄:<form:input path="age"></form:input><br/>
学生性别:<form:input path="gender"></form:input><br/>
<input type="submit" value="提交"/>

</form:form>

常用标签

1、form标签

1
<form:form modelAttribute="student" method="post"></form:form>

渲染的是HTML中的form标签,通过modelAttribute属性绑定具体的业务数据。

2、input标签

1
<form:input path="name"></form:input>

渲染的是HTML中的

1
<input type="text"/>

。form标签绑定的是业务数据,input标签绑定的是业务数据中的属性值,通过path与业务数据的属性名对应,支持级联

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
package com.bitzh.entity2;

import lombok.Data;

/**
* @Auther: oyy0v0
* @Date: 2024/8/4 - 08 - 04 - 13:51
* @Description: com.bitzh.entity2
* @version: 1.0
*/
@Data
public class Address {
private Integer id;
private String name;

}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
package com.bitzh.entity2;

import lombok.Data;

/**
* @Auther: oyy0v0
* @Date: 2024/8/4 - 08 - 04 - 13:12
* @Description: com.bitzh.entity2
* @version: 1.0
*/
@Data
public class Student {
private Integer id;
private String name;
private Integer age;
private String gender;
private Address address;
}

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
package com.bitzh.controller;

import com.bitzh.entity2.Address;
import com.bitzh.entity2.Student;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;

/**
* @Auther: oyy0v0
* @Date: 2024/8/4 - 08 - 04 - 13:14
* @Description: com.bitzh.controller
* @version: 1.0
*/
@Controller
@RequestMapping("/student")
public class StudentHandler {

@RequestMapping("/get")
public String get(Model model){
Student student = new Student();
student.setId(1);
student.setName("张三");
student.setAge(22);
student.setGender("男");
Address address = new Address();
address.setId(1);
address.setName("科技路");
student.setAddress(address);
model.addAttribute("student",student);
return "student2";
}

@PostMapping("/update")
public String update(Student student){
System.out.println(student);
return "student2";
}
}

1
2
3
4
5
6
7
8
9
<form:form modelAttribute="student" action="/student/update" method="post">
学生编号:<form:input path="id"></form:input><br/>
学生姓名:<form:input path="name"></form:input><br/>
学生年龄:<form:input path="age"></form:input><br/>
学生性别:<form:input path="gender"></form:input><br/>
学生地址:<form:input path="address.name"></form:input><br/>
<input type="submit" value="提交"/>

</form:form>

3、password标签

1
<form:password path="password"></form:password>

渲染的是HTML中的

1
<Input type = “password"/>

,通过path与业务数据的属性名对应,password标签的值不会在页面显示。

4、checkbox标签

1
<form:checkbox path="hobby" value="读书"></form:checkbox>

渲染的是HTML中的

1
<Input type="checkbox"/>

,通过path与业务数据的属性名对应,可以绑定boolean,数组和集合。

如果绑定boolean类型的变量,该变量值为true,则表示选中,false表述不选中

1
checkbox:<form:checkbox path="flag" value="1"></form:checkbox>

如果绑定数组和集合,集合中的元素等于checkbox的value值,则该项选中,否则不选中。

1
2
3
4
5
6
student.setHobby(Arrays.asList("读书","看电影","旅行"));

<form:checkbox path="hobby" value="读书"></form:checkbox>读书<br/>
<form:checkbox path="hobby" value="看电影"></form:checkbox>看电影<br/>
<form:checkbox path="hobby" value="打游戏"></form:checkbox>打游戏<br/>
<form:checkbox path="hobby" value="旅行"></form:checkbox>旅行<br/>

5、checkboxs标签

1
<form:checkbox items="${student.hobby}" path="selectHobby"></form:checkbox>

渲染的是HTML中的一组

1
<input type="checkbox"/>

,这里需要结合items和path两个属性来使用,items绑定被遍历的集合或数组,path绑定的选中的集合或数组

items是全部选型,path为默认选中的选型。

1
2
3
4
        student.setHobby(Arrays.asList("读书","看电影","打游戏","听音乐","旅行"));
student.setSelectHobby(Arrays.asList("读书","看电影"));

<form:checkboxes path="selectHobby" items="${student.hobby}"></form:checkboxes>

path可以直接绑定业务数据的属性,items需要通过EL表达式从域对象中取值,不能直接写属性名。

6、radiobutton标签

1
<form:radiobutton path="radioId" value="0"></form:radionbutton>

渲染的是HTML中的一个

1
<input type="radio"/>

办公的数据与标签的value值相等为选中状态,否则是不选中。

1
2
3
4
student.setRadioId(1);

<form:radiobutton path="radioId" value="0"></form:radiobutton>男
<form:radiobutton path="radioId" value="1"></form:radiobutton>女

7、radiobuttons标签

1
<form:radiobuttons items:${student.grade}" path="selectGrade"></form:radiobuttons>

渲染的是HTML中的一组

1
<input type="radio"/>

。这里需要结合items和path,items绑定被遍历的集合或数组,path绑定被选中的值。

1
2
3
4
5
6
7
8
9
10
Map<Integer,String> gradeMap = new HashMap<>();
gradeMap.put(1,"一年级");
gradeMap.put(2,"二年级");
gradeMap.put(3,"三年级");
gradeMap.put(4,"四年级");
gradeMap.put(5,"五年级");
student.setGradeMap(gradeMap);
student.setSelectGrade(3);

<form:radiobuttons path="selectGrade" items="${student.gradeMap}"></form:radiobuttons>

8、select标签

1
<form:select items="${student.citys}" path="selectCity"/>

渲染的是HTML中的

1
<select/>

,这里需要结合items和path两个属性来使用,items绑定被遍历的集合或数组,path绑定被选中的值,用法和radiobuttons标签一致。

1
2
3
4
5
6
7
8
9
Map<Integer ,String> cityMap = new HashMap<>();
cityMap.put(1,"北京");
cityMap.put(2,"上海");
cityMap.put(3,"广州");
cityMap.put(4,"深圳");
student.setCityMap(cityMap);
student.setSelectCity(2);

<form:select path="selectCity" items="${student.cityMap}"></form:select>

9、form:select标签结合form:options使用

form:select只定义path属性,在form:select标签内部添加一个子标签form:options,然后设置items属性。

1
2
3
<form:select path="selectCity">
<form:options items="${student.cityMap}"></form:options>
</form:select>

10、form:select标签结合form:option使用

form:select来定义path属性,给每一个form:option都设置value属性,path与哪个value相等就默认选中该项。

1
2
3
4
5
<form:select path="selectCity">
<form:option value="1">西安</form:option>
<form:option value="2">杭州</form:option>
<form:option value="3">成都</form:option>
</form:select>

Spring MVC 国际化

国际化是指同一个应用程序在不同语言设置的浏览器中,自动显示不同的语言,Spring MVC对国际化操作做了很好的继承,我们只需要简单配置即可实现国际化。

1、springmvc.xml中配置国际化

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
<!--国际化资源文件-->
<bean id="messageSource" class="org.springframework.context.support.ReloadableResourceBundleMessageSource">
<!--多语言配置文件放在根路径,以language开头-->
<property name="basename" value="classpath:language"></property>
<property name="useCodeAsDefaultMessage" value="true"></property>
</bean>

<!--拦截器-->
<mvc:interceptors>
<bean id="localeChangeInterceptor" class="org.springframework.web.servlet.i18n.LocaleChangeInterceptor">
<property name="paramName" value="lang"></property>
</bean>

</mvc:interceptors>

<!--配置SessionLocaleResolver,动态获取Locale对象,存入Session-->
<bean id="localeResolver" class="org.springframework.web.servlet.i18n.SessionLocaleResolver"></bean>

2、创建国际化资源文件,language_en_US_properties,language_zh_CN_properties,分别存储英文和中文资源。

1
2
3
4
5
6
7
8
9
10
language.cn = \u4E2D\u6587
language.en = English
info = \u767B\u5F55
username = \u7528\u6237\u540D
password = \u5BC6\u7801
repassword = \u786E\u8BA4\u5BC6\u7801
tel = \u7535\u8BDD
email = \u7535\u5B50\u90AE\u7BB1
submit = \u63D0\u4EA4
reset = \u91CD\u7F6E
1
2
3
4
5
6
7
8
9
10
language.cn = \u4E2D\u6587
language.en = English
info = login
username = username
password = password
repassword = repassword
tel = tel
email = email
submit = submit
reset = reset

3、创建Handler

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
package com.bitzh.controller;

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

/**
* @Auther: oyy0v0
* @Date: 2024/8/4 - 08 - 04 - 15:54
* @Description: com.bitzh.controller
* @version: 1.0
*/
@Controller
@RequestMapping("/inter")
public class InterHandler {
@GetMapping("/index")
public String index(){
return "inter";
}
}

4、JSP

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
<%--
Created by IntelliJ IDEA.
User: pc
Date: 2024/8/4
Time: 15:55
To change this template use File | Settings | File Templates.
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@ taglib prefix="spring" uri="http://www.springframework.org/tags" %>
<html>
<head>
<title>Title</title>
</head>
<body>
<h1><spring:message code="info"></spring:message></h1>

<a href="index?lang=en_US">English</a>
<a href="index?lang=zh_CN">中文</a>
<form>
<spring:message code="username"/>:<input type="text"/><br/>
<spring:message code="password"/>:<input type="password"/><br/>
<spring:message code="repassword"/>:<input type="password"/><br/>
<spring:message code="tel"/>:<input type="text"/><br/>
<spring:message code="email"/><input type="text"/><br/>
<input type="submit" value="<spring:message code="submit"/>"/>
<input type="reset" value="<spring:message code="reset"/>"/>

</form>

</body>
</html>