Java Bean Validation(参数校验) 最佳实践

 

37. Validation
The method validation feature supported by Bean Validation 1.1 is automatically enabled as long as a JSR-303 implementation (such as Hibernate validator) is on the classpath. This lets bean methods be annotated with javax.validation constraints on their parameters and/or on their return value. Target classes with such annotated methods need to be annotated with the @Validated annotation at the type level for their methods to be searched for inline constraint annotations.html

For instance, the following service triggers the validation of the first argument, making sure its size is between 8 and 10:前端

@Service
@Validated
public class MyBean {

    public Archive findByCodeAndAuthor(@Size(min = 8, max = 10) String code,
            Author author) {
        ...
    }

}

https://docs.spring.io/spring-boot/docs/2.1.10.RELEASE/reference/html/boot-features-validation.htmljava

 

 

 

转载来自:http://www.cnblogs.comgit

参数校验是咱们程序开发中必不可少的过程。用户在前端页面上填写表单时,前端js程序会校验参数的合法性,当数据到了后端,为了防止恶意操做,保持程序的健壮性,后端一样须要对数据进行校验。后端参数校验最简单的作法是直接在业务方法里面进行判断,当判断成功以后再继续往下执行。但这样带给咱们的是代码的耦合,冗余。当咱们多个地方须要校验时,咱们就须要在每个地方调用校验程序,致使代码很冗余,且不美观。spring

那么如何优雅的对参数进行校验呢?JSR303就是为了解决这个问题出现的,本篇文章主要是介绍 JSR303,Hibernate Validator 等校验工具的使用,以及自定义校验注解的使用。后端

校验框架介绍

JSR303 是一套JavaBean参数校验的标准,它定义了不少经常使用的校验注解,咱们能够直接将这些注解加在咱们JavaBean的属性上面,就能够在须要校验的时候进行校验了。注解以下:api

 

Spring validtor 一样扩展了jsr303,并实现了方法参数和返回值的校验数组

Spring 提供了MethodValidationPostProcessor类,用于对方法的校验app

代码实现

添加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>

 

最简单的参数校验

一、Model 中添加校验注解

public class Book { private long id; /** * 书名 */ @NotEmpty(message = "书名不能为空") private String bookName; /** * ISBN号 */ @NotNull(message = "ISBN号不能为空") private String bookIsbn; /** * 单价 */ @DecimalMin(value = "0.1",message = "单价最低为0.1") private double price; // getter setter ....... }

 

二、在controller中使用此校验

/**
     * 添加Book对象
     * @param book
     */ @RequestMapping(value = "/book", method = RequestMethod.POST) public void addBook(@RequestBody @Valid Book book) { System.out.println(book.toString()); }

 

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

自定义校验注解

虽然jSR303和Hibernate Validtor 已经提供了不少校验注解,可是当面对复杂参数校验时,仍是不能知足咱们的要求,这时候咱们就须要 自定义校验注解。

下面以“List数组中不能含有null元素”为实例自定义校验注解

一、注解定义以下:

package com.beiyan.validate.annotation; import javax.validation.Constraint; import javax.validation.Payload; import java.lang.annotation.*; import static java.lang.annotation.ElementType.*; import static java.lang.annotation.ElementType.PARAMETER; import static java.lang.annotation.RetentionPolicy.RUNTIME; /** * 自定义参数校验注解 * 校验 List 集合中是否有null 元素 */ @Target({ElementType.ANNOTATION_TYPE, ElementType.METHOD, ElementType.FIELD}) @Retention(RetentionPolicy.RUNTIME) @Documented @Constraint(validatedBy = ListNotHasNullValidatorImpl.class)////此处指定了注解的实现类为ListNotHasNullValidatorImpl public @interface ListNotHasNull { /** * 添加value属性,能够做为校验时的条件,若不须要,可去掉此处定义 */ int value() default 0; String message() default "List集合中不能含有null元素"; Class<?>[] groups() default {}; Class<? extends Payload>[] payload() default {}; /** * 定义List,为了让Bean的一个属性上能够添加多套规则 */ @Target({METHOD, FIELD, ANNOTATION_TYPE, CONSTRUCTOR, PARAMETER}) @Retention(RUNTIME) @Documented @interface List { ListNotHasNull[] value(); } }

 

二、注解实现类: 

package com.beiyan.validate.annotation; import org.springframework.stereotype.Service; import javax.validation.ConstraintValidator; import javax.validation.ConstraintValidatorContext; import java.util.List; /** * 自定义注解ListNotHasNull 的实现类 * 用于判断List集合中是否含有null元素 */ @Service public class ListNotHasNullValidatorImpl implements ConstraintValidator<ListNotHasNull, List> { private int value; @Override public void initialize(ListNotHasNull constraintAnnotation) { //传入value 值,能够在校验中使用 this.value = constraintAnnotation.value(); } public boolean isValid(List list, ConstraintValidatorContext constraintValidatorContext) { for (Object object : list) { if (object == null) { //若是List集合中含有Null元素,校验失败 return false; } } return true; } }

 

三、model添加注解:

public class User { //其余参数 ....... /** * 所拥有的书籍列表 */ @NotEmpty(message = "所拥有书籍不能为空") @ListNotHasNull(message = "List 中不能含有null元素") @Valid private List<Book> books; //getter setter 方法....... }

 

使用方法同上,在在须要校验的Model上面加上@Valid 便可

分组验证

对同一个Model,咱们在增长和修改时对参数的校验也是不同的,这个时候咱们就须要定义分组验证,步骤以下

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

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

 

二、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 方法...... }

 

三、启用校验

此时启用校验和以前的不一样,须要指明启用哪一组规则

/**
     * 添加一个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()); }

 

Spring validator 方法级别的校验

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

一、实例化MethodValidationPostProcessor

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

 

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

@RestController @Validated public class ValidateController { }

 

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

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

 

当方法上面的参数校验失败,spring 框架就回抛出异常

{ "timestamp": 1476108200558, "status": 500, "error": "Internal Server Error", "exception": "javax.validation.ConstraintViolationException", "message": "No message available", "path": "/test" }

今后能够优雅的对参数进行校验了 

写在后面的话:

本篇文章只列举了经常使用的几种校验方法,其实关于校验的内容还有不少:

校验信息的国际化显示,

组合参数校验,

message中使用EL表达式,

将校验信息绑定到ModelAndView等,这里就不一一列出了,下面这几篇文章写的也不错,读者能够参考:

将校验信息绑定到ModelAndView    http://www.voidcn.com/blog/983836…

集成Bean Validation 1.1(JSR-349)到SpringMVC   my.oschina.net/qjx1208/blo…

本文的所有代码已上传开源中国git仓库: git.oschina.net/beiyan/Vali…

 

http://www.gitout.cn/?p=2532

相关文章
相关标签/搜索