一.JSR-303简介:
JSR-303 是JAVA EE 6 中的一项子规范,叫做Java Bean Validation,Hibernate Validator 是 Bean Validation 的参考实现, Hibernate Validator 提供了 JSR 303 规范中所有内置 constraint 的实现,除此之外还有一些附加的 constraint,大致来说就是对Java Bean 对象做参数校验的,Validator 中定义了大量校验参数的注解,为我们日常开发提供了便利,摈弃了传统的方式中业务代码中的串行校验
普通maven依赖
<!--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>
SpringBoot项目中已经包含在starter-web依赖中
二.应用:
下面是我们生产中用到的示例代码
@Data
@ApiModel("添加用户的dto")
public class AddUserDto implements Serializable {
/**
* 渠道id
*/
@ApiModelProperty("渠道id")
private Integer channelId;
/**
* 用户名
*/
@ApiModelProperty("用户名 *不能为纯数字")
@NotBlank(message = "用户名不能为空")
@Pattern(regexp = "^(?!\\d+$)[\\da-zA-Z]+$",message = "用户名必须包含字母")
private String userName;
/**
* 密码
*/
@ApiModelProperty("密码")
@NotBlank(message = "密码不能为空")
@Length(min = 6,message = "密码长度不能少于6位")
private String password;
/**
* 手机号
*/
@ApiModelProperty("手机号")
@NotBlank(message = "手机号不能为空")
@Pattern(regexp = "^1(3|4|5|7|8|9)\\d{9}$",message = "手机号格式错误")
private String phone;
/**
* 姓名
*/
@ApiModelProperty("姓名")
@NotBlank(message = "姓名不能为空")
private String name;
/**
* 性别 1 男 2 女
*/
@ApiModelProperty("性别 1 男 2 女")
private Byte sex;
/**
* 出生日期
*/
@ApiModelProperty("出生日期")
private Date birth;
/**
* 电子邮件
*/
@ApiModelProperty("电子邮件")
@Email
private String email;
/**
* 部门id
*/
@ApiModelProperty("部门id")
@NotNull(message = "部门不能为空")
private Integer deptId;
/**
* 部门id
*/
@ApiModelProperty("角色id")
@NotNull(message = "角色id不能为空")
private Integer roleId;
/**
* 状态 1 正常 2 锁定
*/
@ApiModelProperty("状态 1 正常 2 锁定")
private Byte status;
/**
* 类型 1 普通用户 2 管理员
*/
@ApiModelProperty("类型 1 普通用户 2 管理员")
private Byte type;
/**
* 头像
*/
@ApiModelProperty("头像")
private String image;
/**
* 头像地址
*/
@ApiModelProperty("头像地址")
private String imageAddress;
/**
* 操作人
*/
@ApiModelProperty("操作人")
private Integer operator;
/**
* 备注
*/
@ApiModelProperty("备注")
private String remark;
}
基于Restful风格以及集成Swagger的Controller层
/**
* @description: 用户控制器
* @author: WanMing
* @date: Created in 2019/8/19 17:25
*/
@Slf4j
@Validated
@RestController
@EnableResponseHandler
@RequestMapping(value = "/user")
@Api(value = "用户控制器", tags = "用户控制器API")
public class UserController {
@Autowired
private UserService userService;
/**
* @description 添加用户信息
* @param addUserDto
* @return boolean
* @date 2019/8/19 20:42
*/
@PostMapping(value = "/addUser")
@ApiOperation(value = "添加用户", response = Boolean.class)
public boolean addUser(@Validated @RequestBody AddUserDto addUserDto) {
return userService.addUser(addUserDto);
}
/**
* @description 删除用户信息
* @param
* @return
* @date 2019/8/19 20:43
*/
@DeleteMapping(value = "/deleteUser")
@ApiOperation(value = "删除用户", response = Boolean.class)
public boolean deleteUser(@RequestParam("id") @NotNull(message = "用户id不能为空") Integer id){
return userService.deleteUser(id);
}
/**
* @description 根据id修改用户信息
* @param modifyUserDto
* @return boolean
* @date 2019/8/19 20:49
*/
@PutMapping(value = "/modifyUser")
@ApiOperation(value = "根据id修改用户信息",response = Boolean.class)
public boolean modifyUser( @RequestBody @Validated ModifyUserDto modifyUserDto){
return userService.modifyUser(modifyUserDto);
}
/**
* @description 根据条件分页查询用户信息
* @param queryUserDto
* @return UserVo
* @date 2019/8/19 20:49
*/
@PostMapping(value = "/queryUserListByCondition")
@ApiOperation(value = "根据条件分页查询用户信息",response = UserVo.class)
public PageInfo<UserVo> queryUserListByCondition( @RequestBody @Validated QueryUserDto queryUserDto){
return userService.queryUserListByCondition(queryUserDto);
}
}
三.常用的校验注解
@Null 验证对象是否为null
@NotNull 验证对象是否不为null, 无法查检长度为0的字符串
@NotBlank 检查约束字符串是不是Null还有被Trim的长度是否大于0
@NotEmpty 检查约束元素是否为NULL或者是EMPTY.
@AssertTrue 验证 Boolean 对象是否为 true
@AssertFalse 验证 Boolean 对象是否为 false
@Size(min=, max=) 验证对象(Array,Collection,Map,String)长度是否在给定的范围之内
@Length(min=, max=) Validates that the annotated string is between min and max included.
@Past 验证 Date 和 Calendar 对象是否在当前时间之前
@Future 验证 Date 和 Calendar 对象是否在当前时间之后
@Pattern 验证 String 对象是否符合正则表达式的规则
@Min 验证 Number 和 String 对象是否大等于指定的值
@Max 验证 Number 和 String 对象是否小等于指定的值
@DecimalMax 被标注的值必须不大于约束中指定的最大值. 这个约束的参数是一个通过BigDecimal定义的最大值的字符串表示.小数存在精度
@DecimalMin 被标注的值必须不小于约束中指定的最小值. 这个约束的参数是一个通过BigDecimal定义的最小值的字符串表示.小数存在精度
@Digits 验证 Number 和 String 的构成是否合法
@Digits(integer=,fraction=) 验证字符串是否是符合指定格式的数字,interger指定整数精度,fraction指定小数精度。
@Range(min=, max=) 检查数字是否介于min和max之间.
@Range(min=10000,max=50000,message="range.bean.wage")
@Valid 递归的对关联对象进行校验, 如果关联对象是个集合或者数组,那么对其中的元素进行递归校验,如果是一个map,则对其中的值部分进行校验.(是否进行递归验证)
@CreditCardNumber信用卡验证
@Email 验证是否是邮件地址,如果为null,不进行验证,算通过验证。
@ScriptAssert(lang= ,script=, alias=)
@URL(protocol=,host=, port=,regexp=, flags=)
四.拓展 自定义注解校验
@IdentityCardNumber
/**
* @description: 验证身份证格式
* @author: WanMing
* @date: 2019/9/9 11:05
*/
@Documented
@Target({ElementType.PARAMETER, ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
@Constraint(validatedBy = IdentityCardNumberValidator.class)
public @interface IdentityCardNumber {
String message() default "身份证格式有误";
Class<?>[] groups() default {};
Class<? extends Payload>[] payload() default {};
}
添加到校验器中
/**
* @description: 将注解注册到 validator 中
* @author: WanMing
* @date: 2019/9/9 11:06
*/
@Slf4j
public class IdentityCardNumberValidator implements ConstraintValidator<IdentityCardNumber, Object> {
private static final String IDENTITY_CARD_REGEXP = "=/^[1-9]\\d{7}((0\\d)|(1[0-2]))(([0|1|2]\\d)|3[0-1])\\d{3}$|^[1-9]\\d{5}[1-9]\\d{3}((0\\d)|(1[0-2]))(([0|1|2]\\d)|3[0-1])\\d{3}([0-9]|X)$/";
@Override
public void initialize(IdentityCardNumber constraintAnnotation) {
log.info("IdentityCardNumberValidator initialize");
}
@Override
public boolean isValid(Object o, ConstraintValidatorContext constraintValidatorContext) {
return Pattern.matches(IDENTITY_CARD_REGEXP,o.toString());
}
}
定义全局异常捕捉
package com.wanm.hmplatform.config.common.web;
import com.wanm.hmplatform.config.common.wrapper.WrapMapper;
import com.wanm.hmplatform.config.common.wrapper.Wrapper;
import lombok.extern.slf4j.Slf4j;
import org.springframework.validation.ObjectError;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestControllerAdvice;
import springfox.documentation.spring.web.json.Json;
import javax.servlet.http.HttpServletResponse;
import javax.validation.ConstraintViolation;
import javax.validation.ConstraintViolationException;
import java.nio.charset.StandardCharsets;
import java.util.stream.Collectors;
/**
* @description: 全局异常处理器
* @author: WanMing
* @create: 2019-01-10 12:16
**/
@RestControllerAdvice
@Slf4j
public class GlobalExceptionHandler {
private static int PARAM_FAIL_CODE = 1002;
/**
* 方法参数校验
*
* @param e
* @param response
* @return
*/
@ExceptionHandler(MethodArgumentNotValidException.class)
public Wrapper<String> handleException(MethodArgumentNotValidException e, HttpServletResponse response) {
String errors = e.getBindingResult().getAllErrors().stream().map(ObjectError::getDefaultMessage).collect(Collectors.joining(","));
log.error("异常说明:{}", errors);
return WrapMapper.error(PARAM_FAIL_CODE, errors);
}
@ExceptionHandler(ConstraintViolationException.class)
public Wrapper<String> handleException(ConstraintViolationException e, HttpServletResponse response) {
String errors = e.getConstraintViolations().stream().map(ConstraintViolation::getMessage).collect(Collectors.joining(","));
log.error("异常说明:{}", errors);
return WrapMapper.error(errors);
}
@ExceptionHandler(Exception.class)
public Wrapper<String> handleException(Exception e, HttpServletResponse response) {
String errors = e.getMessage();
log.error("异常说明:{}", errors);
return WrapMapper.error(errors);
}
}
在入参的dto的属性上加注解即可