Spring 表单验证

mac2025-08-03  1

1 概述 验证可以避免用户输入不规范的数据,在数据过滤的一道门。这道门有前端验证和后台验证,前端验证使用JavaScript脚本,后台验证使用Java EE验证规范JSR 303。

2 工程结构

为避免反复手动启动程序,我们引入热启动。

pom.xml

<?xml version="1.0" encoding="UTF-8"?>

4.0.0 org.springframework.boot spring-boot-starter-parent 2.1.6.RELEASE com.wangshenghua spring-thymeleaf-form 0.0.1-SNAPSHOT spring-thymeleaf-form Demo project for Spring Boot

<properties> <java.version>1.8</java.version> <maven-jar-plugin.version>3.1.1</maven-jar-plugin.version> </properties> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-thymeleaf</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-devtools</artifactId> <scope>runtime</scope> </dependency> </dependencies> <build> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> </plugin> </plugins> </build> spring-boot-devtools模块可以让工程是源码和配置变更后自动重启嵌入式tomcat。

3 模型层 JSR 303验证规则放置于数据模型层,以注释的形式加入。

User.java

package com.wangshenghua.model;

import javax.validation.constraints.Email; import javax.validation.constraints.Min; import javax.validation.constraints.NotEmpty; import javax.validation.constraints.NotNull; import javax.validation.constraints.Size;

public class User {

@NotNull private long id; @NotNull @Size(min = 2, max = 30,message="姓名在2~30个字符之间") private String name; @NotNull @Min(message="年龄至少15岁",value=15) private Integer age; @NotEmpty @Email(message="邮箱格式不对") private String email; public User() { } public User(@NotNull long id, @NotNull @Size(min = 2, max = 30) String name, @NotNull @Min(15) Integer age, String email) { this.id = id; this.name = name; this.age = age; this.email = email; } public long getId() { return id; } public void setId(long id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } public String getEmail() { return email; } public void setEmail(String email) { this.email = email; } public Integer getAge() { return age; } public void setAge(Integer age) { this.age = age; }

} 常见的验证注释有:

验证规则 说明 @Null 被注释的元素必须为 null @NotNull 被注释的元素必须不为 null @AssertTrue 被注释的元素必须为 true @AssertFalse 被注释的元素必须为 false @Min(value) 被注释的元素必须是一个数字,其值必须大于等于指定的最小值 @Max(value) 被注释的元素必须是一个数字,其值必须小于等于指定的最大值 @DecimalMin(value) 被注释的元素必须是一个数字,其值必须大于等于指定的最小值 @DecimalMax(value) 被注释的元素必须是一个数字,其值必须小于等于指定的最大值 @Size(max, min) 被注释的元素的大小必须在指定的范围内 @Digits (integer, fraction) 被注释的元素必须是一个数字,其值必须在可接受的范围内 @Past 被注释的元素必须是一个过去的日期 @Future 被注释的元素必须是一个将来的日期 @Pattern(value) 被注释的元素必须符合指定的正则表达式 @Email 被注释的元素必须是电子邮箱地址 @Length 被注释的字符串的大小必须在指定的范围内 @NotEmpty 被注释的字符串的必须非空 @Range 被注释的元素必须在合适的范围内 4 数据访问层 数据访问层采用List模拟数据库。

UserDao.java

package com.wangshenghua.dao;

import java.util.ArrayList; import java.util.List;

import org.springframework.stereotype.Repository;

import com.wangshenghua.model.User;

@Repository public class UserDao {

private static List<User> users = new ArrayList<User>(); // 使用List当容器保存数据,来代替数据库 static { users.add(new User(1, "黄志燕", 17, "ssss@qq.com")); users.add(new User(2, "侯慧聪", 19, "hhhh@qq.com")); users.add(new User(3, "王广宏", 15, "gggg@qq.com")); } public long getMaxId() { long id = 0; for (User user : users) { if (user.getId() > id) id = user.getId(); } return id + 1; } public User getUser(long id) { User user = null; for (User u : users) { if (u.getId() == id) { user = u; break; } } return user; } public void update(User user, long id) { for (User u : users) { if (u.getId() == id) { u.setName(user.getName()); u.setEmail(user.getEmail()); u.setAge(user.getAge()); break; } } } public void delete(long id) { for (User u : users) { if (u.getId() == id) { users.remove(u); break; } } } public List<User> getUsers() { return users; }

} @Repository注释表示此类是一个数据访问对象dao。Spring对各MVC各层注释有着规范的要求:

控制器层 @Controller 服务层 @Service 数据访问层 @Repository 在类前加入这些注释后,Spring工程一启动,扫描这些有注释的类,并实例化到内存里。

5 控制器 UserController.java

package com.wangshenghua.controller;

import javax.validation.Valid;

import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Controller; import org.springframework.ui.Model; import org.springframework.validation.BindingResult; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.PostMapping;

import com.wangshenghua.dao.UserDao; import com.wangshenghua.model.User;

@Controller public class UserController {

@Autowired private UserDao userDao; /** 控制器的方法 **/ @GetMapping("/") public String index() { return "redirect:/allUser"; } @GetMapping("/allUser") public String allUser(Model model) { model.addAttribute("users", userDao.getUsers()); return "list-user"; } @GetMapping("/adduser") public String showAddUserForm(Model model) { User user = new User(); user.setId(userDao.getMaxId()); model.addAttribute("user", user); return "add-user"; } @PostMapping("/adduser") public String addUser(@Valid User user, BindingResult bindingResult) { if (bindingResult.hasErrors()) { return "add-user"; } userDao.getUsers().add(user); return "redirect:/allUser"; } @GetMapping("/edit/{id}") // {id}是占位符 public String showUpdateForm(@PathVariable("id") long id, Model model) { // @PathVariable 路径变量 User user = userDao.getUser(id); model.addAttribute("user", user); return "update-user"; } @PostMapping("/update/{id}") public String updateUser(@PathVariable("id") long id, @Valid User user, BindingResult bindingResult) { if (bindingResult.hasErrors()) { return "update-user"; } userDao.update(user, id); return "redirect:/allUser"; } @GetMapping("/delete/{id}") public String deleteUser(@PathVariable("id") long id, Model model) { userDao.delete(id); return "redirect:/allUser"; }

} @Autowired注释将内存里已经实例好的对象引入进来,并赋值给变量。

private UserDao userDao; 如变量userDao指向一个引用,引用内存中的UserDao实例。

这就是Spring中著名的控制反转和依赖注入。之前是由驱动类UserController负责实例化UserDao;现在Spring不是这样玩了,由Spring容器在启动时扫描类上的注释,并实例化到内存,控制权不在驱动类手里,在Spring手里;驱动类要依赖某一个类,只需写注释@Autowired声明一个变量就OK。

在方法addUser里有一个参数User user前,有一个注释@Valid,用于启动数据模型User.java类中JSR 303验证规则,它将对视图层传递过来的User对象进行验证。

验证结果又放置到BindingResult对象里,BindingResult的hasErrors()方法发现有错误,则返回到视图层。

6 视图层 add-user.html

添加用户 姓名 <p th:if="${#fields.hasErrors('name')}" th:errors="*{name}"></p> <label for="age">年龄</label> <input type="text" th:field="*{age}" id="age" placeholder="age"> <p th:if="${#fields.hasErrors('age')}" th:errors="*{age}"></p> <label for="email">邮箱</label> <input type="text" th:field="*{email}" id="email" placeholder="Email"> <p th:if="${#fields.hasErrors('email')}" th:errors="*{email}"></p> <input type="submit" value="保存"> </form> 视图层采用thymeleaf技术,它先判断th:if="${#fields.hasErrors('name')}" 如果有错误,则显示错误消息th:errors="*{name}"

7 总结 本节课程使用Spring Boot和thymeleaf技术实现表单验证功能 world程序。

演示了如何在数据模型层User.java中添加JSR 303验证规则,及在控制器如何启用验证,及视图层如何展示验证的消息提示。

同时简要介绍了Spring的控制反转和依赖注释的使用。

学员位重点掌握表单验证和控制反转和依赖注释的使用。

本节课程源码已经上传到github,可以前往下载。

最新回复(0)