http请求时,对参数进行校验,以post请求为例,直接上代码:
Maven 依赖
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-validator</artifactId>
<version>6.0.18.Final</version>
</dependency>
自定义注解
自定义注解切面
import javax.validation.Constraint;
import javax.validation.Payload;
import java.lang.annotation.*;
/**
* 自定义validation注册校验所传入内容必须在list中
*/
@Target({ElementType.METHOD, ElementType.FIELD, ElementType.CONSTRUCTOR, ElementType.PARAMETER})
@Retention(RetentionPolicy.RUNTIME)
@Documented
//指定校验规则 即注解校验规则
@Constraint(validatedBy = {InListValidator.class})
public @interface InList {
String[] value() default {};
String message() default "{params not found in InList value}";
Class<?>[] groups() default {};
Class<? extends Payload>[] payload() default {};
}
自定义注解实现
import javax.validation.ConstraintValidator;
import javax.validation.ConstraintValidatorContext;
import java.util.Arrays;
import java.util.List;
/**
* InList校验逻辑
*/
class InListValidator implements ConstraintValidator<InList, String> {
private List<String> valueList;
@Override
public void initialize(InList constraintAnnotation) {
valueList = Arrays.asList(constraintAnnotation.value());
}
@Override
public boolean isValid(String value, ConstraintValidatorContext constraintValidatorContext) {
return valueList.contains(value);
}
}
请求参数VO
import lombok.Data;
import org.hibernate.validator.constraints.Length;
import javax.validation.constraints.DecimalMin;
import javax.validation.constraints.NotBlank;
import javax.validation.constraints.NotEmpty;
import java.math.BigDecimal;
@Data
public class RequestVO {
@NotEmpty(message = "单号不能为空")
private String bizOrderNo;
@DecimalMin(value = "0", message = "账单金额不能小于0")
private BigDecimal amount;
private Integer id;
@NotBlank(message = "昵称不能为空")
@Length(min=1, max=3)
private String nickname;
@InList(value = {"1", "2"}, message = "类型必须为1、2")
private String type;
}
Hibernate Validator常用注解
注解 | 释义 |
---|---|
@Null | 必须为null |
@NotNull | 不能为null |
@AssertTrue | 必须为true |
@AssertFalse | 必须为false |
@Min | 必须为数字,其值大于或等于指定的最小值 |
@Max | 必须为数字,其值小于或等于指定的最大值 |
@DecimalMin | 必须为数字,其值大于或等于指定的最小值 |
@DecimalMax | 必须为数字,其值小于或等于指定的最大值 |
@Size | 集合的长度 |
@Digits | 必须为数字,其值必须再可接受的范围内 |
@Past | 必须是过去的日期 |
@Future | 必须是将来的日期 |
@Pattern | 必须符合正则表达式 |
必须是邮箱格式 | |
@Length | 长度范围 |
@NotEmpty | 不能为null,长度大于0 |
@Range | 元素的大小范围 |
@NotBlank | 不能为null,字符串长度大于0(限字符串) |
使用示例
代码调用示例,使用**@Valid注解**:
@RestController
@RequestMapping("/index")
public class IndexController {
@PostMapping("test")
public String test(@Valid @RequestBody RequestVO requestVO) {
return requestVO.toString();
}
}
代码测试示例
使用一下请求参数进行postman进行访问
{"amount":1000,"bizOrderNo":"bizno","id":10,"nickname":"昵称","type":"3"}
测试结果
结果如下:
{
"timestamp": "2020-08-26T10:00:01.445+0000",
"status": 400,
"error": "Bad Request",
"errors": [
{
"codes": [
"InList.requestVO.type",
"InList.type",
"InList.java.lang.String",
"InList"
],
"arguments": [
{
"codes": [
"requestVO.type",
"type"
],
"arguments": null,
"defaultMessage": "type",
"code": "type"
},
[
"1",
"2"
]
],
"defaultMessage": "类型必须为1、2",
"objectName": "requestVO",
"field": "type",
"rejectedValue": "3",
"bindingFailure": false,
"code": "InList"
}
],
"message": "Validation failed for object='requestVO'. Error count: 1",
"path": "/index/test"
}
我们真正所需要的信息其实是:类型必须为1、2"
统一处理异常
将返回的数据统一封装,返回给前端的时候给3种信息,code、message以及data,约定code为指定code时,接口响应成功,data为响应数据
统一处理异常代码
import com.wanli.databoard.vo.BaseDataVO;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections.CollectionUtils;
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;
@Slf4j
@ControllerAdvice
public class ExceptionAspect {
@ResponseBody
@ExceptionHandler(value = MethodArgumentNotValidException.class)
public BaseDataVO notValidExceptionHandler(MethodArgumentNotValidException e) {
String msg;
if (!CollectionUtils.isEmpty(e.getBindingResult().getAllErrors())) {
msg = e.getBindingResult().getAllErrors().get(0).getDefaultMessage();
} else {
msg = e.getMessage();
}
log.warn("接口参数校验未通过: {}", msg);
return buildClientErrorVO(400, msg);
}
//errorCode 参数可以根据场景使用一个枚举来维护,枚举包含两个属性errorCode,message
private static BaseDataVO buildClientErrorVO(int errorCode, String message) {
return buildBaseData(errorCode, message);
}
private static BaseDataVO buildBaseData(int errorCode, String message) {
BaseDataVO result = new BaseDataVO();
result.setCode(errorCode);
result.setData(null);
result.setMessage(message);
return result;
}
}
测试结果
请求结果如下所示:
统一封装代码
Controller统一封装返回参数代码如下:
@RestController
@RequestMapping("/index")
public class IndexController{
@PostMapping("test")
public BaseDataVO test(@Valid @RequestBody RequestVO requestVO) {
return successModel(requestVO);
}
private BaseDataVO successModel(Object data) {
return new BaseDataVO()
.setCode(200)
.setData(data)
.setMessage("Success");
}
}
统一返回VO类
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
@EqualsAndHashCode
@Accessors(chain = true)
public class BaseDataVO {
private Integer code;
private Object data;
private String message;
}