JSR303参数校验

本文介绍了JSR303参数校验在Spring MVC中的应用,包括客户端和服务端表单验证的区别,以及如何使用JSR303进行JavaBean参数校验。详细阐述了各种校验注解的使用,如@NotNull、@Size等,并通过实例演示了分组验证、Spring Validator方法级别校验以及错误处理的方式。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1、Spring mvc 的表单验证
客户端表单验证:代码写在js上,容易被攻击。
服务端表单验证 :不容易被攻击,它是在后台进行验证就不会被人恶意攻击,不容易被人随意登陆其他的信息或者窃取他人信息。

如果使用需要JSR303 ,就要导入hibernate-validator依赖

<dependency>
      <groupId>org.hibernate</groupId>
      <artifactId>hibernate-validator</artifactId>
      <version>5.0.2.Final</version>
    </dependency>

2、校验框架介绍
JSR303 是一套JavaBean参数校验的标准,它定义了很多常用的校验注解,我们可以直接将这些注解加在我们JavaBean的属性上面,就可以在需要校验的时候进行校验了。注解如下:
参考配置
@Null 限制只能为null
@NotNull 限制必须不为null
@AssertFalse 限制必须为false
@AssertTrue 限制必须为true
@DecimalMax(value) 限制必须为一个不大于指定值的数字
@DecimalMin(value) 限制必须为一个不小于指定值的数字
@Digits(integer,fraction) 限制必须为一个小数,且整数部分的位数不能超过integer,小数部分的位数不能超过fraction
@Future 限制必须是一个将来的日期
@Max(value) 限制必须为一个不大于指定值的数字
@Min(value) 限制必须为一个不小于指定值的数字
@Past 限制必须是一个过去的日期
@Pattern(value) 限制必须符合指定的正则表达式
@Size(max,min) 限制字符长度必须在min到max之间
@Past 验证注解的元素值(日期类型)比当前时间早
@NotEmpty 验证注解的元素值不为null且不为空(字符串长度不为0、集合大小不为0)
@NotBlank 验证注解的元素值不为空(不为null、去除首位空格后长度为0),不同于@NotEmpty,@NotBlank只应用于字符串且在比较时会去除字符串的空格
@Email 验证注解的元素值是Email,也可以通过正则表达式和flag指定自定义的email格式

3 、代码实现(这个代码我是根据https://blog.youkuaiyun.com/u014029255/article/details/55518598 这个博客进行测试)
3.1添加JAR包依赖
在pom.xml中添加如下依赖:

<!--jsr 303-->
       <dependency>
           <groupId>javax.validation</groupId>
           <artifactId>validation-api</artifactId>
           <version>1.1.0.Final</version>
       </dependency>

       <!-- hibernate validator-->
       <dependency>
           <groupId>org.hibernate</groupId>
           <artifactId>hibernate-validator</artifactId>
           <version>5.2.0.Final</version>
       </dependency>

3.2最简单的参数校验
3.2.1、Model 中添加校验注解

public class Book {
//id是自动增加我就没有做操作
   private long id;

   @NotEmpty(message = "书名不能为空")
   private String bookName;

   @NotNull(message = "ISBN号不能为空")
   private String bookIsbn;
   
   @DecimalMin(value = "0.1",message = "单价最低为0.1")
private doubleprice; // getter setter .......  }

3.2.2、在controller中使用此校验

@RequestMapping(value = "/book",method = RequestMethod.POST)

   public void addBook(@RequestBody @Valid Book book) {
       System.out.println(book.toString());

}

当访问这个post接口时,如果参数不符合Model中定义的话,程序中就回抛出400异常,并提示错误信息。

3.3分组验证
对同一个Model,我们在增加和修改时对参数的校验也是不一样的,这个时候我们就需要定义分组验证,步骤如下

3.3.1、定义两个空接口,分别代表Person对象的增加校验规则和修改校验规则

/**
 * 可以在一个Model上面添加多套参数验证规则,此接口定义添加Person模型新增时的参数校验规则
 */

public interface PersonAddView {

}

/**
 * 可以在一个Model上面添加多套参数验证规则,此接口定义添加Person模型修改时的参数校验规则
 */
public interface PersonModifyView {

}

3.3.2、Model上添加注解时使用指明所述的分组

public class Person {

   private long id;

   /**

    * 添加groups 属性,说明只在特定的验证规则里面起作用,不加则表示在使用Deafault规则时起作用

    */

   @NotNull(groups = {PersonAddView.class, PersonModifyView.class}, message= "添加、修改用户时名字不能为空",payload = ValidateErrorLevel.Info.class)

   @ListNotHasNull.List({
           @ListNotHasNull(groups = {PersonAddView.class}, message = "添加上Name不能为空"),
           @ListNotHasNull(groups = {PersonModifyView.class}, message = "修改时Name不能为空")})
   private String name;

 

   @NotNull(groups = {PersonAddView.class}, message = "添加用户时地址不能为空")
   private String address;

   @Min(value = 18, groups = {PersonAddView.class}, message = "姓名不能低于18岁")
   @Max(value = 30, groups = {PersonModifyView.class}, message = "姓名不能超过30岁")
   private int age;

 //getter setter 方法......

}

3.3.3、启用校验
此时启用校验和之前的不同,需要指明启用哪一组规则

/**
    * 添加一个Person对象
    * 此处启用PersonAddView这个验证规则
    * 备注:此处@Validated(PersonAddView.class)表示使用PersonAndView这套校验规则,若使用@Valid 则表示使用默认校验规则,
    * 若两个规则同时加上去,则只有第一套起作用
    */

   @RequestMapping(value = "/person", method =RequestMethod.POST)
   public void addPerson(@RequestBody @Validated({PersonAddView.class,Default.class}) Person person) {

       System.out.println(person.toString());

    }

   /**
    * 修改Person对象
    * 此处启用PersonModifyView这个验证规则
    */
   @RequestMapping(value = "/person", method = RequestMethod.PUT)
   public void modifyPerson(@RequestBody @Validated(value ={PersonModifyView.class}) Person person) {
       System.out.println(person.toString());
}

3.4 Spring validator 方法级别的校验
JSR和Hibernate validator的校验只能对Object的属性进行校验,不能对单个的参数进行校验,spring 在此基础上进行了扩展,添加了MethodValidationPostProcessor拦截器,可以实现对方法参数的校验,实现如下:

3.4.1、实例化MethodValidationPostProcessor

@Bean
    public MethodValidationPostProcessormethodValidationPostProcessor() {
       return new MethodValidationPostProcessor();
    }

3.4.2、在所要实现方法参数校验的类上面添加@Validated,如下

@RestController
@Validated
public class ValidateController {
}

3.4.3、在方法上面添加校验规则:

@RequestMapping(value = "/test",method = RequestMethod.GET)
   public String paramCheck(@Length(min = 10) @RequestParam String name) {
       System.out.println(name);
       return null;
    }

3.5使用BindingResult对象来保存验证结果
每一个模型对象后边都需要跟一个Errors或BindingResult对象来保存验证结果,其方法体内部可以使用这两个验证结果对象来选择出错时跳转的页面或处理的逻辑。

@RequestMapping("/validate/multi") 
public String multi(@Valid@ModelAttribute("a") A a, BindingResult aErrors, @Valid@ModelAttribute("b") B b, BindingResult bErrors) { 
   if (aErrors.hasErrors()) { //如果a模型对象验证失败 
       return "validate/error"; 
   } 

   if (bErrors.hasErrors()) { //如果a模型对象验证失败 
       return "validate/error"; 
   } 
   return "redirect:/success"; 
}
### Spring Boot 中的统一结果集封装与全局异常处理 #### 结果集封装类设计 为了使API响应更加一致,在Spring Boot应用中通常会创建一个通用的结果集封装类`ResponseResult`来标准化返回给客户端的数据结构。 ```java public class ResponseResult<T> { private Integer code; // 响应状态码 private String message; // 提示信息 private T data; // 返回数据体 public static <T> ResponseResult<T> success(T data){ return new ResponseResult<>(HttpStatus.OK.value(), "操作成功", data); } public static ResponseResult<?> failure(Integer errorCode, String errorMessage){ return new ResponseResult<>(errorCode, errorMessage, null); } protected ResponseResult() {} protected ResponseResult(Integer code, String msg, T body) { this.code = code; this.message = msg; this.data = body; } // Getters and Setters... } ``` 此部分实现了对HTTP请求的成功和失败两种情况下的基本反馈机制[^1]。 #### JSR303 参数校验配置 对于表单提交或接口调用中的参数合法性验证,可以利用Hibernate Validator框架提供的JSR-303 Bean Validation标准来进行约束声明。当发生违反这些规则的情况时,系统能够自动触发相应的错误提示并阻止程序继续执行下去。 在实体对象上添加注解: ```java import javax.validation.constraints.NotBlank; public class UserDTO { @NotBlank(message="用户名不能为空") private String username; // Other fields... // Getter & Setter methods... } ``` 上述代码片段展示了如何通过简单的注释方式定义字段级别的检验条件。 #### 全局异常处理器设置 为了让应用程序具备良好的健壮性和用户体验,有必要建立一套完善的异常捕获逻辑。这可以通过继承`@ControllerAdvice`注解的方式实现跨多个控制器共享相同的异常处理策略;同时借助于`@ExceptionHandler`指定具体要拦截哪些类型的Exception实例。 ```java @ControllerAdvice public class GlobalExceptionHandler { /** * 处理MethodArgumentNotValidException异常(即JSR303校验不通过) */ @ExceptionHandler(MethodArgumentNotValidException.class) public ResponseEntity<ResponseResult<?>> handleValidationExceptions( MethodArgumentNotValidException ex) { List<String> errors = ex.getBindingResult() .getFieldErrors() .stream() .map(DefaultMessageSourceResolvable::getDefaultMessage) .collect(Collectors.toList()); return ResponseEntity.status(HttpStatus.BAD_REQUEST).body(ResponseResult.failure(400,"参数校验失败:" + String.join(", ",errors))); } /** * 捕捉其他未预见运行期异常 */ @ExceptionHandler(Exception.class) public ResponseEntity<ResponseResult<?>> handleAllUncaughtException(Exception e) { logger.error("Unexpected error occurred.",e); return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(ResponseResult.failure(500,e.getMessage())); } } ``` 这段Java源文件描述了一个用于集中管理各类业务内外部抛出的不同种类异常事件的方法集合。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值