如何实现 Java SpringBoot 自动验证入参数据的有效性
Java SpringBoot 通过javax.validation.constraints下的注解,实现入参数据自动验证
如果碰到 @NotEmpty 否则不生效,注意看下 @RequestBody 前面是否加上了@Valid
Validation常用注解汇总
Constraint 详细信息 @Null 被注释的元素必须为 null @NotNull 被注释的元素必须不为 null @NotBlank 被注释的元素不能为空(空格视为空) @NotEmpty 被注释的元素不能为空 (允许有空格) @Size(max, min) 被注释的元素的大小必须在指定的范围内 @Min(value) 被注释的元素必须是一个数字,其值必须大于等于指定的最小值 @Max(value) 被注释的元素必须是一个数字,其值必须小于等于指定的最大值 @Pattern(value) 被注释的元素必须符合指定的正则表达式 @DecimalMin(value) 被注释的元素必须是一个数字,其值必须大于等于指定的最小值 @DecimalMax(value) 被注释的元素必须是一个数字,其值必须小于等于指定的最大值 @AssertTrue 被注释的元素必须为 true @AssertFalse 被注释的元素必须为 false @Digits (integer, fraction) 被注释的元素必须是一个数字,其值必须在可接受的范围内 @Past 被注释的元素必须是一个过去的日期 @Future 被注释的元素必须是一个将来的日期
示例
/** * 用户名 */ @NotBlank(message = "用户名不能为空") private String username; /** * 用户真实姓名 */ @NotBlank(message = "用户真实姓名不能为空") private String name; /** * 密码 */ @Pattern(regexp = "^(?:(?=.*[A-Z])(?=.*[a-z])(?=.*[0-9])(?=.*[^A-Za-z0-9]))(?=^[^\\u4e00-\\u9fa5]{0,}$).{8,20}$", message = "密码过于简单有被盗风险,请保证密码大于8位,并且由大小写字母、数字,特殊符号组成") private String password; /** * 邮箱 */ @NotBlank(message = "邮箱不能为空") @Email(message = "邮箱格式不正确") private String email; /** * 手机号 */ @NotBlank(message = "手机号不能为空") @Pattern(regexp = "^(1[0-9])\\d{9}$", message = "手机号格式不正确") private String mobile;
Demo
入参对象上,添加注解及说明
package com.vipsoft.web.entity; import javax.validation.constraints.NotBlank; import javax.validation.constraints.Size; import java.io.Serializable; /** * 定时任务调度 */ public class QuartzJob implements Serializable { private static final long serialVersionUID = 1L; /** * 任务序号 */ private long jobId; /** * 任务名称 */ @NotBlank(message = "任务名称不能为空") @Size(max = 10, message = "任务名称不能超过10个字符") private String jobName; /** * 任务组名 */ @NotBlank(message = "任务组名不能为空") @Size(max = 10, message = "任务组名不能超过10个字符") private String jobGroup; /** * 调用目标字符串 */ private String invokeTarget; /** * 执行表达式 */ private String cronExpression; /** * cron计划策略 0=默认,1=立即触发执行,2=触发一次执行,3=不触发立即执行 */ private String misfirePolicy = "0"; /** * 并发执行 0=允许,1=禁止 */ private String concurrent; /** * 任务状态(0正常 1暂停) */ private String status; /** * 备注 */ private String remark; } Controller @RequestBody 前面必须加上 @Valid 否则不生效 import javax.validation.Valid; @RestController @RequestMapping("schedule") public class ScheduleController { private Logger logger = LoggerFactory.getLogger(ScheduleController.class); @RequestMapping("/add") public ApiResult addTask(@Valid @RequestBody QuartzJob param) throws Exception { logger.info("添加调度任务 => {} ", JSONUtil.toJsonStr(param)); return new ApiResult("添加成功"); } }
异常处理,统一返回对象,方便前端解析
GlobalExceptionHandler
package com.vipsoft.web.exception; import cn.hutool.core.util.StrUtil; import com.vipsoft.web.utils.ApiResult; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.validation.BindException; import org.springframework.validation.BindingResult; import org.springframework.validation.FieldError; import org.springframework.validation.ObjectError; import org.springframework.web.HttpRequestMethodNotSupportedException; import org.springframework.web.bind.MethodArgumentNotValidException; import org.springframework.web.bind.annotation.ExceptionHandler; import org.springframework.web.bind.annotation.RestControllerAdvice; import java.util.List; /** * 全局异常处理器 */ @RestControllerAdvice public class GlobalExceptionHandler { private static final Logger logger = LoggerFactory.getLogger(GlobalExceptionHandler.class); /** * 处理自定义异常 */ @ExceptionHandler(CustomException.class) public ApiResult handleException(CustomException e) { // 打印异常信息 logger.error("### 异常信息:{} ###", e.getMessage()); return new ApiResult(e.getCode(), e.getMessage()); } /** * 参数错误异常 */ @ExceptionHandler({MethodArgumentNotValidException.class, BindException.class}) public ApiResult handleException(Exception e) { if (e instanceof MethodArgumentNotValidException) { MethodArgumentNotValidException validException = (MethodArgumentNotValidException) e; BindingResult result = validException.getBindingResult(); StringBuffer errorMsg = new StringBuffer(); if (result.hasErrors()) { Listerrors = result.getAllErrors(); errors.forEach(p -> { FieldError fieldError = (FieldError) p; errorMsg.append(fieldError.getDefaultMessage()).append(","); logger.error("### 请求参数错误:{" + fieldError.getObjectName() + "},field{" + fieldError.getField() + "},errorMessage{" + fieldError.getDefaultMessage() + "}"); }); return new ApiResult(6001, errorMsg.toString()); } } else if (e instanceof BindException) { BindException bindException = (BindException) e; if (bindException.hasErrors()) { logger.error("### 请求参数错误: {}", bindException.getAllErrors()); } } return new ApiResult(6001, "参数无效"); } /** * 处理HttpRequestMethodNotSupporte异常 * @param e * @return */ @ExceptionHandler(HttpRequestMethodNotSupportedException.class) public Object methodHandler(HttpRequestMethodNotSupportedException e) { // 打印异常信息 logger.error("### 异常信息:{} ###", e.getMessage()); return new ApiResult(6000, e.getMessage()); } /** * 处理所有不可知的异常 */ @ExceptionHandler(Exception.class) public ApiResult handleOtherException(Exception e) { // 打印异常信息 logger.error("### 系统内部错误:{} ###", e.getMessage(), e); String warnMsg = StrUtil.isEmpty(e.getMessage()) ? "### 系统内部错误 ###" : e.getMessage(); return new ApiResult(6000, "系统内部错误", e.getMessage()); } }
统一返回对像 ApiResult
package com.vipsoft.web.utils; //import com.github.pagehelper.PageInfo; import java.io.Serializable; public class ApiResult implements Serializable { /** * 返回编码 0:失败、1:成功 */ private int code; /** * 返回消息 */ private String message; /** * 返回对象 */ private Object data; /** * 分页对象 */ private Page page; public ApiResult() { this.code = 1; this.message = "请求成功"; } public ApiResult(Integer code, String message) { this.code = code; this.message = message; } public ApiResult(Integer code, String message, Object data) { this.code = code; this.message = message; this.setData(data); } public ApiResult(Object data) { this.code = 1; this.message = "请求成功"; this.setData(data); } // public ApiResult(PageInfo pageInfo) { // this.code = 1; // this.message = "请求成功"; // this.setData(pageInfo.getList()); // this.setPage(convertToPage(pageInfo)); // } // // public Page convertToPage(PageInfo pageInfo) { // Page result = new Page(); // result.setTotalCount(pageInfo.getTotal()); // result.setPageNum(pageInfo.getPageNum()); // result.setPageCount(pageInfo.getPages()); // result.setPageSize(pageInfo.getPageSize()); // result.setPrePage(pageInfo.getPrePage()); // result.setNextPage(pageInfo.getNextPage()); // return result; // } public int getCode() { return code; } public void setCode(int code) { this.code = code; } public String getMessage() { return message; } public void setMessage(String message) { this.message = message; } public Object getData() { return data; } public void setData(Object data) { this.data = data; } public Page getPage() { return page; } public void setPage(Page page) { this.page = page; } }