- ubuntu12.04环境下使用kvm ioctl接口实现最简单的虚拟机
- Ubuntu 通过无线网络安装Ubuntu Server启动系统后连接无线网络的方法
- 在Ubuntu上搭建网桥的方法
- ubuntu 虚拟机上网方式及相关配置详解
CFSDN坚持开源创造价值,我们致力于搭建一个资源共享平台,让每一个IT人在这里找到属于你的精彩世界.
这篇CFSDN的博客文章SpringBoot后端进行数据校验JSR303的使用详解由作者收集整理,如果你对这篇文章有兴趣,记得点赞哟.
如果只想查看注解,请跳到文章末尾部分 。
在前后端进行数据交互中,在前端把数据传送到后端前,一般会先进行校验一次,校验成功之后,才把数据发送到后端。但是我们在服务端还得在对数据进行一次校验。因为请求数据发送的链接很容易获取,可以不经过前端界面,使用postman等工具直接向后台发送数据,这就可能造成发送的数据是不合法的情况.
首先创建一个springboot项目 。
使用的springboot版本为:(本文代码以该版本为准,不同版本springboot,在下面内容会出现一些差异) 。
<parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>2.3.9.RELEASE</version> <relativePath/> <!-- lookup parent from repository --> </parent>
引入如下依赖 。
<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-devtools</artifactId> <scope>runtime</scope> <optional>true</optional> </dependency> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <optional>true</optional> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> <exclusions> <exclusion> <groupId>org.junit.vintage</groupId> <artifactId>junit-vintage-engine</artifactId> </exclusion> </exclusions> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-validation</artifactId> </dependency> </dependencies>
这个作标在新一点的springboot版本中,需要单独引入。在老版本是默认引入的。这个是用来引入对jsr303注解的支持.
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-validation</artifactId> </dependency>
接着创建一个Java Bean 。
package cn.jxj4869.demo.entity;import lombok.Data;import javax.validation.constraints.NotNull;@Datapublic class User { @NotNull private Integer id; private String username; private String password; private String email;}
返回类型的JavaBean 。
package cn.jxj4869.demo.entity;import java.util.HashMap;public class R extends HashMap<String, Object> { private static final long serialVersionUID = 1L; public R() { put("code", 0); put("msg", "success"); } public static R error(int code, String msg) { R r = new R(); r.put("code", code); r.put("msg", msg); return r; } public static R ok(String msg) { R r = new R(); r.put("msg", msg); return r; } public R put(String key, Object value) { super.put(key, value); return this; }}
创建一个controller.
index方法用来跳转到首页.
package cn.jxj4869.demo.controller;import org.springframework.stereotype.Controller;import org.springframework.web.bind.annotation.*;@Controllerpublic class UserController { @RequestMapping("/") public String index(){ return "index"; }}
首页代码放到resources/templates目录下 。
<!DOCTYPE html><html lang="en"><head> <meta charset="UTF-8"> <title>Title</title> <style> div{ margin-top: 50px; } </style></head><body><div> 新增表单 <br><br> <form method="post"> <label>用户名</label> <input type="text" name="username"/> <br> <label>密码</label> <input type="text" name="password"/> <br> <label>邮箱</label> <input type="email" name="email"/> <br> <input type="submit" value="提交"/> </form></div><div> 更新表单 <br><br> <form method="post"> <input type="hidden" name="id" value="1"> <label>用户名</label> <input type="text" name="username"/> <br> <label>密码</label> <input type="text" name="password"/> <br> <label>邮箱</label> <input type="email" name="email"/> <br> <input type="submit" value="提交"/> </form></div></body></html>
要在后端进行数据校验,传统的校验方式在controller层接受数据后,按照要求对数据进行校验 。
比如要接收一个user bean对象.
现在要对user对象中的username属性进行非空校验,password属性进行非空校验和长度校验.
@PostMapping("/user") @ResponseBody public R user1(User user) throws Exception { if(StringUtils.isEmpty(user.getUsername())) { return R.error(400,"username不能为空"); } if(StringUtils.isEmpty(user.getPassword())||user.getPassword().length()>8||user.getPassword().length() <4) { return R.error(400,"password无效"); } return null; }
如果有多个方法都需要接受user对象, 而且要校验的属性可能不止username和password这两个属性,如果每个方法里面都采用上面这种校验方式的话,代码就会很臃肿,而且不好维护,当改变了userbean的属性,或者对校验规则进行修改后,就得对所有的校验代码进行更新。 这是一件工程量很大的事.
为了解决上述问题,我们可以使用JSR303提供的注解进行校验.
JSR是Java Specification Requests的缩写,意思是Java 规范提案。JSR303也就是第303号提案.
使用JSR303的方法很简单,例如上面的需求,我们只需要在user的属性上加上注解即可.
步骤如下:
1、给Bean添加校验注解,一般是在 javax.validation.constraints这个包下,也还有一些是hibernate提供的.
2、开启校验功能@Valid.
3、当校验失败的时候,会抛出org.springframework.validation.BindException异常.
常用的校验注解在文末 。
package cn.jxj4869.demo.entity;import lombok.Data;import org.hibernate.validator.constraints.Length;import javax.validation.constraints.NotNull;@Datapublic class User { private Integer id; @NotBlank private String username; @NotBlank @Length(min = 4,max = 8) private String password; private String email;}
然后在controller里面的方法上,加上@Valid注解即可 。
@PostMapping("/user2") @ResponseBody public R user2(@Valid User user) throws Exception { System.out.println(user); return null; }
当校验失败后,会出现如下错误。并且会给出默认的提示信息.
那这个错误信息是怎么来的呢.
进入@NotNULL注解的代码里面 。
@Target({ METHOD, FIELD, ANNOTATION_TYPE, CONSTRUCTOR, PARAMETER, TYPE_USE })@Retention(RUNTIME)@Repeatable(List.class)@Documented@Constraint(validatedBy = { })public @interface NotBlank { String message() default "{javax.validation.constraints.NotNull.message}"; ............ ............ ............}
会有一个message属性。显然就是指定错误的提示内容。而这些错误提示是在一个叫validationMessages.properties的文件中,用idea的搜索工具可以找到,双击shift键打开搜索.
发现有这么多validationMessages.properties的文件,而且支持国际化.
打开validationMessages_zh.properties,可以看到里面定义了这么多的提示。而错误提示就是从这文件中获取的.
如果我们不想用默认的校验提示信息的话,可以自己指定.
指定message的值即可.
@NotBlank(message = "用户名不能为空") private String username;
当校验出错时,会默认返回一个错误界面,或者返回错误提示的json数据。但默认提供的显然不是我们想要的,如果可以拿到错误信息,那我们就能自定义相应数据了.
拿到错误信息的方式也很简单,只要在方法中加上BindingResult result这个参数,错误信息就会封装这里面.
@PostMapping("/user2") @ResponseBody public R user2(@Valid User user, BindingResult result) throws Exception { System.out.println(user); if(result.hasErrors()) { //判断是否有错误 Map<String,String> map = new HashMap<>(); //1、获取校验的错误结果 result.getFieldErrors().forEach((item)->{ //FieldError 获取到错误提示 String message = item.getDefaultMessage(); //获取错误的属性的名字 String field = item.getField(); map.put(field,message); }); return R.error(400,"提交的数据不合法").put("data",map); } // 若没有错误,则进行接下去的业务操作。 return null; }
不过不推荐上面这种方式,理由同上,当校验的地方多了,每个方法里面都加上这么个异常处理,会让代码很臃肿.
不知道你们是否还记得,springmvc里面有个全局的异常处理,我们可以自定义一个异常处理,在这里面统一处理异常.
统一处理BinException。这样就可以不用在controller中去处理错误信息了.
package cn.jxj4869.demo.execption;import cn.jxj4869.demo.entity.R;import org.springframework.validation.BindException;import org.springframework.web.bind.annotation.ExceptionHandler;import org.springframework.web.bind.annotation.RestControllerAdvice;import java.util.HashMap;import java.util.Map;@RestControllerAdvice(basePackages = "cn.jxj4869.demo.controller")public class MyExceptionControllerAdvice { @ExceptionHandler(value = BindException.class) public R handleVaildException(BindException e) { Map<String,String> map = new HashMap<>(); //1、获取校验的错误结果 e.getFieldErrors().forEach((item)->{ //FieldError 获取到错误提示 String message = item.getDefaultMessage(); //获取错误的属性的名字 String field = item.getField(); map.put(field,message); }); return R.error(400,"提交的数据不合法").put("data",map); }}
校验出错的时候,会抛出两种异常 。
org.springframework.validation.BindException 。
使用@Valid注解进行校验的时候抛出的 。
org.springframework.web.bind.MethodArgumentNotValidException 。
使用@validated校验的时候抛出的 。
在异常捕获中加入下面这个 。
@ExceptionHandler(value= MethodArgumentNotValidException.class) public R handleVaildException(MethodArgumentNotValidException e){ BindingResult bindingResult = e.getBindingResult(); Map<String,String> map = new HashMap<>(); bindingResult.getFieldErrors().forEach((fieldError)->{ map.put(fieldError.getField(),fieldError.getDefaultMessage()); }); return R.error(400,"提交的数据不合法").put("data",map); }
在不同业务场景下,校验规则是不一样的,比如user对象中id这个属性,在新增的时候,这个属性是不用填的,要为null,但是在修改的时候,id属性是不能为null的.
可以用注解中的groups属性来指定,在什么场合下使用改注解 。
@Documented@Constraint(validatedBy = { })@Target({ METHOD, FIELD, ANNOTATION_TYPE, CONSTRUCTOR, PARAMETER, TYPE_USE })@Retention(RUNTIME)@Repeatable(List.class)public @interface NotBlank { Class<?>[] groups() default { }; ........}
首先定义两个接口AddGroup和UpdateGroup,不需要做任何实现 。
package cn.jxj4869.demo.valid;public interface UpdateGroup {}
package cn.jxj4869.demo.valid;public interface AddGroup {}
在user中指定group.
package cn.jxj4869.demo.entity;import cn.jxj4869.demo.valid.AddGroup;import cn.jxj4869.demo.valid.UpdateGroup;import lombok.Data;import javax.validation.constraints.NotBlank;import javax.validation.constraints.NotEmpty;import javax.validation.constraints.NotNull;import javax.validation.constraints.Null;@Datapublic class User { @Null(groups = {AddGroup.class}) @NotNull(groups = {UpdateGroup.class}) private Integer id; @NotBlank(message = "用户名不能为空",groups = {AddGroup.class,UpdateGroup.class}) private String username; @NotEmpty private String password; private String email;}
在controller中用@Validated注解,指定校验的分组 。
@PostMapping("/user3") @ResponseBody public R user3(@Validated(UpdateGroup.class) User user) { System.out.println(user); return null; }
结果如下图所示,因为password属性没有指定校验的分组,所以在校验的时候,都不会对它进行合法性检查.
当提供的注解不能满足我们需求的时候,可以自定义注解.
例如我们现在给user新加一个属性status,并要求这个属性的值只能是0或者1.
新建一个@StatusValue注解.
根据jsr303的规范,校验注解得有三个属性.
message
:用来获取错误提示的groups
:指定校验分组的。使用@Constraint注解指定该注解的校验器 。
package cn.jxj4869.demo.valid;import javax.validation.Constraint;import javax.validation.Payload;import java.lang.annotation.Documented;import java.lang.annotation.Retention;import java.lang.annotation.Target;import static java.lang.annotation.ElementType.*;import static java.lang.annotation.ElementType.TYPE_USE;import static java.lang.annotation.RetentionPolicy.RUNTIME;@Documented@Constraint(validatedBy = { StatusValueConstraintValidator.class })@Target({ METHOD, FIELD, ANNOTATION_TYPE, CONSTRUCTOR, PARAMETER, TYPE_USE })@Retention(RUNTIME)@interface StatusValue { String message() default "{cn.jxj4869.valid.StatusValue.message}"; Class<?>[] groups() default { }; Class<? extends Payload>[] payload() default { }; int[] value() default { };}
自定义校验器 。
需要实现ConstraintValidator这个接口,第一个泛型是表示要校验哪个注解,第二个泛型是要校验的数据的类型.
initialize
是初始化方法isValid
校验方法,判断是否校验成功package cn.jxj4869.demo.valid;import javax.validation.ConstraintValidator;import javax.validation.ConstraintValidatorContext;import java.util.HashSet;import java.util.Set;public class StatusValueConstraintValidator implements ConstraintValidator<StatusValue,Integer> { private Set<Integer> set = new HashSet<>(); //初始化方法 @Override public void initialize(StatusValue constraintAnnotation) { int[] value = constraintAnnotation.value(); for (int val : value) { set.add(val); } } /** * 判断是否校验成功 * @param value * @param context * @return */ @Override public boolean isValid(Integer value, ConstraintValidatorContext context) { return set.contains(value); }}
最后在resources目录下添加一个ValidationMessages.properties文件 。
用来指定错误信息.
cn.jxj4869.valid.StatusValue.message=必须提交指定的值
UserBean 。
@Datapublic class User { @Null(groups = {AddGroup.class}) @NotNull(groups = {UpdateGroup.class}) private Integer id; @NotBlank(message = "用户名不能为空",groups = {AddGroup.class,UpdateGroup.class}) private String username; @NotEmpty private String password; private String email; @StatusValue(value = {0,1},groups = {AddGroup.class,UpdateGroup.class}) private Integer status;}
常用注解汇总 。
注解 | 功能 |
---|---|
@Null | 对象必须为null |
@NotNull | 对象必须不为null,无法检查长度为0的字符串 |
@NotBlank | 字符串必须不为Null,且去掉前后空格长度必须大于0 |
@NotEmpty | 字符串必须非空 |
@Length(min = 1,max = 50) | 字符串必须在指定长度内 |
@Range(min = 0,max = 100) | 必须在指定范围内 |
@AssertTrue | 对象必须为true |
@AssertFalse | 对象必须为false |
@Max(Value) | 必须为数字,且小于或等于Value |
@Min(Value) | 必须为数字,且大于或等于Value |
@DecimalMax(Value) | 必须为数字( BigDecimal ),且小于或等于Value。小数存在精度 |
@DecimalMin(Value) | 必须为数字( BigDecimal ),且大于或等于Value。小数存在精度 |
@Digits(integer,fraction) | 必须为数字( BigDecimal ),integer整数精度,fraction小数精度 |
@Size(min,max) | 对象(Array、Collection、Map、String)长度必须在给定范围 |
字符串必须是合法邮件地址 | |
@Past | Date和Calendar对象必须在当前时间之前 |
@Future | Date和Calendar对象必须在当前时间之后 |
@Pattern(regexp=“正则”) | 字符串满足正则表达式的值 |
到此这篇关于SpringBoot后端进行数据校验JSR303的使用详解的文章就介绍到这了,更多相关SpringBoot数据校验JSR303的使用内容请搜索我以前的文章或继续浏览下面的相关文章希望大家以后多多支持我! 。
原文链接:https://blog.csdn.net/qq_43058685/article/details/114381502 。
最后此篇关于SpringBoot后端进行数据校验JSR303的使用详解的文章就讲到这里了,如果你想了解更多关于SpringBoot后端进行数据校验JSR303的使用详解的内容请搜索CFSDN的文章或继续浏览相关文章,希望大家以后支持我的博客! 。
如何在 PHP 中生成 CRC-8 校验和? 最佳答案 function crcnifull ($dato, $byte) { static $PolyFull=0x8c; for ($i=0
我正在编写代码来使用 32 位无符号整数计算 CRC16。当尝试打印执行 CRC 操作的 XOR 函数的返回值时,它总是打印 0。我尝试了各种调试方法,例如打印语句,但是,我似乎无法弄清楚! 这是我的
ThinkPHP3.2.3验证码显示、刷新、校验 ,具体如下: 显示验证码 首先在Home/Controller下创建一个公共控制器PublicController
我想将自定义验证绑定(bind)到 TimePicker 自定义控件,但下面的代码显示“无法将内容添加到 TimePicker 的对象类型。”。
目录 Spring 校验(validator,JSR-303)实现 什么是JSR-303规范 与Spring MVC结合 实体类添加
导包和配置 导入 JSR 303 的包、hibernate valid 的包 ?
我是一名优秀的程序员,十分优秀!