项目中的接口一般都是需要进行参数校验的,这里简单记录一下springboot项目中使用 @Validated和@Valid注解实现接口入参的校验;
maven pom文件所需依赖
springboot 在2.3.0版本之后就没有引入validation对应的包,需要收到添加
<!-- 参数校验注解 @Valid 所需依赖 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-validation</artifactId>
</dependency>
第一步:创建用于接收参数的实体类
package com.zhh.demo.entity.ro.user;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import org.hibernate.validator.constraints.Range;
import javax.validation.constraints.NotBlank;
import javax.validation.constraints.NotNull;
import javax.validation.constraints.Size;
/**
* @Description: 创建用户接口的请求实体
* @Author: zhaoheng
*/
@Data
@ApiModel("创建用户接口的入参请求实体")
public class CreateUserRO {
@ApiModelProperty(value = "姓名")
@Size(message = "姓名应为{min}至{max}个字符", min = 1, max = 10)
@NotBlank(message = "姓名不能为空")
private String name;
@ApiModelProperty(value = "年龄")
@NotNull(message = "年龄不能为空")
@Range(message = "年龄范围为 {min} 到 {max} 之间", min = 1, max = 100)
private Integer age;
@ApiModelProperty(value = "地址")
private String address;
}
第二步:创建controller类
package com.zhh.demo.controller;
import com.zhh.demo.common.response.Response;
import com.zhh.demo.common.response.ResponseFactory;
import com.zhh.demo.entity.common.ResponsePage;
import com.zhh.demo.entity.dto.user.UserDTO;
import com.zhh.demo.entity.ro.user.CreateUserRO;
import com.zhh.demo.entity.ro.user.QueryUserListRO;
import com.zhh.demo.service.user.IUserService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import javax.validation.Valid;
import java.util.ArrayList;
import java.util.List;
/**
* @Description: 用户
* @Author: zhaoheng
*/
@Api(tags = "用户管理-api")
@RequestMapping("/api/user")
@RestController
@Validated // 开启入参校验
public class UserController {
@Autowired
private IUserService iUserService;
@ApiOperation("添加用户")
@PostMapping("/save")
public Response<UserDTO> saveUser(@Valid @RequestBody CreateUserRO createUserRO){
UserDTO userDTO1 = iUserService.saveUser(createUserRO);
return ResponseFactory.success(userDTO1);
}
}
第三步:创建全局返回对象
@Data
@ApiModel("接口出参统一响应实体")
public class Response<T> implements Serializable {
private static final long serialVersionUID = 3692286106860121474L;
@ApiModelProperty(value = "状态码")
private String code;
@ApiModelProperty(value = "说明")
private String message;
private T data;
public Response(){}
public Response(String code, String message) {
this.code = code;
this.message = message;
}
public Response(String code, String message, T data) {
this.code = code;
this.message = message;
this.data = data;
}
}
public class ResponseFactory {
/**
* 默认成功
* @param t
* @param <T>
* @return
*/
public static <T> Response<T> success(T t){
return new Response<T>(ResponseCode.OK.getCode(),ResponseCode.OK.getMsg(),t);
}
/**
* 成功
* @param responseCode 响应code和说明
* @param t
* @param <T>
* @return
*/
public static <T> Response<T> success(ResponseCode responseCode, T t){
return new Response<T>(responseCode.getCode(),responseCode.getMsg(),t);
}
/**
* 成功
* @param responseCode 响应code和说明
* @return
*/
public static <T> Response<T> success(ResponseCode responseCode){
return new Response<T>(responseCode.getCode(),responseCode.getMsg());
}
/**
* 默认失败
* @param <T>
* @return
*/
public static <T> Response<T> error(){
return new Response<T>(ResponseCode.FAIL.getCode(),ResponseCode.FAIL.getMsg());
}
/**
* 失败
* @param responseCode 响应code和说明
* @param t
* @param <T>
* @return
*/
public static <T> Response<T> error(ResponseCode responseCode, T t){
return new Response<T>(responseCode.getCode(),responseCode.getMsg(),t);
}
/**
* 失败
* @param responseCode 响应code和说明
* @return
*/
public static <T> Response<T> error(ResponseCode responseCode){
return new Response<T>(responseCode.getCode(),responseCode.getMsg());
}
/**
* 失败
* @param code 错误码
* @param msg 说明
* @param t 响应数据
* @param <T>
* @return
*/
public static <T> Response<T> error(String code, String msg, T t){
return new Response<T>(code,msg,t);
}
/**
* 失败
* @param code 错误码
* @param msg 说明
* @return
*/
public static <T> Response<T> error(String code, String msg){
return new Response<T>(code,msg);
}
public static <T> ResponsePage pageResult(List<T> list, int total){
return new ResponsePage<T>(list,total);
}
}
public enum ResponseCode {
/** 通用码 **/
FAIL("-1", "系统错误"),
OK("200", "成功"),
/**
* 参考阿里巴巴开发手册
* 错误码为字符串类型,共5位,分两部分组成:错误标识+4位数字编号。
* 例:A0001,A1001,B0001,C0001... A、B、分别代表不通业务或者来源
**/
/** 参数校验不通过 **/
PARAMETER_CHECK_FAILS("A0001","参数校验不通过"),
/** 用户相关 A1xxx **/
USER_NAME_NONSTANDARD("A1002", "用户名不合规");
ResponseCode(String code, String msg) {
this.code = code;
this.msg = msg;
}
@Getter
private String code;
@Getter
private String msg;
}
第三步,创建全局异常处理类
@Slf4j
@RestControllerAdvice
public class ExceptionHandle {
/**
* 处理Exception异常
* @param exception 异常类型
* @return
*/
@ExceptionHandler(value = Exception.class)
public Response<?> ExceptionHandle(Exception exception){
log.error("系统出现异常:",exception);
return ResponseFactory.error(ResponseCode.FAIL);
}
/**
* 入参校验异常,校验不通过,抛出异常信息
* @param exception Valid 入参校验异常
* @return
*/
@ExceptionHandler(value = MethodArgumentNotValidException.class)
public Response<?> methodArgumentNotValidExceptionHandle(MethodArgumentNotValidException exception){
log.error("入参校验不通过",exception);
BindingResult bindingResult = exception.getBindingResult();
List<FieldError> fieldErrorList = bindingResult.getFieldErrors();
fieldErrorList.forEach(fieldError -> {
log.info("字段:{},message:{}",fieldError.getField(),fieldError.getDefaultMessage());
});
// 一个一个给调用方返回提示
String message = fieldErrorList.get(0).getDefaultMessage();
return ResponseFactory.error(ResponseCode.PARAMETER_CHECK_FAILS.getCode(), message);
}
}
执行结果:
{
"code": "A0001",
"message": "年龄不能为空",
"data": null
}
注意点:
controller类上面需要添加注解:@Validated
接口方法的参数前面添加注解:@Valid