springboot参数校验

811 阅读3分钟

传统的参数校验

在平常的开发中,为了保证程序的正确运行和数据的正确性,通常前端传导过来的数据需要校验,而我们一般会把校验逻辑写在service层,导致service 层的业务代码有很多重复代码,所以选择了Bean Validation。

Validation 注解说明

@Valid  被注释的元素是一个对象,需要检查此对象的所有字段值

@Null  被注释的元素必须为 null

@NotNull  被注释的元素必须不为 null

@AssertTrue  被注释的元素必须为 true

@AssertFalse  被注释的元素必须为 false

@Min(value)  被注释的元素必须是一个数字,其值必须大于等于指定的最小值

@Max(value)  被注释的元素必须是一个数字,其值必须小于等于指定的最大值

@DecimalMin(value)  被注释的元素必须是一个数字,其值必须大于等于指定的最小值

@DecimalMax(value)  被注释的元素必须是一个数字,其值必须小于等于指定的最大值
@Size(max, min)  被注释的元素的大小必须在指定的范围内

@Digits (integer, fraction)  被注释的元素必须是一个数字,其值必须在可接受的范围内

@Past  被注释的元素必须是一个过去的日期

@Future 被注释的元素必须是一个将来的日期

@Pattern(value)  被注释的元素必须符合指定的正则表达式

@Email           被注释的元素必须是电子邮箱地址

@Length(min=, max=)  被注释的字符串的大小必须在指定的范围内

@NotEmpty      	被注释的字符串的必须非空

@Range(min=, max=)  被注释的元素必须在合适的范围内

@NotBlank          被注释的字符串的必须非空

@URL(protocol=,host=, port=, regexp=, flags=)  被注释的字符串必须是一个有效的url

@CreditCardNumber  被注释的字符串必须通过Luhn校验算法,银行卡,信用卡等号码一般都用Luhn计算合法性

@ScriptAssert(lang=, script=, alias=)  要有Java Scripting API 即JSR 223("Scripting for the JavaTM Platform")的实现

@SafeHtml(whitelistType=,additionalTags=)  classpath中要有jsoup包

Bean Validation 的使用

  1. pom.xml 的导入
<dependency>
     <groupId>org.springframework.boot</groupId>
     <artifactId>spring-boot-starter-validation</artifactId>
</dependency>
  1. 在controller层加入注解 @Validated
@RequestMapping(path = "/placeOrder", method=RequestMethod.POST)
public GeneralResult placeOrder(@Validated @RequestBody Order order) 
{

   GeneralResult result = new GeneralResult();
   orderService.placeOrder(result, order);
   return result;
   
}
  1. 在模型上加入注解
import javax.validation.constraints.Min;
import javax.validation.constraints.NotEmpty;
import com.smile.vtoken.aop.ValidateErrorCode;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.ToString;

@Data
@Builder
@AllArgsConstructor
@NoArgsConstructor
@ToString
public class Order {
	private Long orderId;

	@NotEmpty(message = "用户编号不能为空")
	@ValidateErrorCode(value = "601")
	private String userId;
	
	@NotEmpty(message = "股票代码不能为空")
	@ValidateErrorCode(value = "606")
	private String stockCode;

	@NotEmpty(message = "数量不能为空")
	@Min(value = 0,message = "输入数量不能小于0 ")
	@ValidateErrorCode(value = "602")
	private String amount;

	@NotEmpty(message = "价格不能为空")
	@ValidateErrorCode(value = "603")
	private String price;

	@NotEmpty(message = "买卖方向不能为空,只能是sell或者buy")
	@ValidateErrorCode(value = "604")
	private String orderType;
	
	@NotEmpty(message = "accountId 不能为空")
	@ValidateErrorCode(value = "605")
	private Integer accountId;

	private Long createTime;

	private Long updateTime;

	private String fee;

	private String filledAmount;

	private String filledCashAmount;

}

4.为了保证每一个参数都返回对应的错误码,加入了@ValidateErrorCode注解

import java.lang.annotation.Retention;
import java.lang.annotation.Target;
import java.lang.annotation.ElementType;
import java.lang.annotation.RetentionPolicy;

@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.FIELD})
public @interface ValidateErrorCode {
    /** 校验错误码 code */
    String value() default "200";
}
  1. 全局异常统一处理
package com.smile.vtoken.utils.exception;

import java.lang.reflect.Field;

import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.bind.annotation.RestControllerAdvice;
import com.smile.vtoken.aop.ValidateErrorCode;
import com.smile.vtoken.constants.ErrorCode;
import com.smile.vtoken.utils.GeneralResult;
@RestControllerAdvice(annotations = RestController.class)
public class GlobalExceptionHandlerAdvice {
	@ExceptionHandler(MethodArgumentNotValidException.class)
	public GeneralResult methodArgumentNotValidException(MethodArgumentNotValidException e) {

		// 从异常对象中拿到ObjectError对象
		GeneralResult result = new GeneralResult();

		ErrorCode errorCode = ErrorCode.INVALID_REQ_PARAMS;

		String errorMsg = e.getBindingResult().getAllErrors().get(0).getDefaultMessage();

		// 参数的Class对象,等下好通过字段名称获取Field对象
		Class<?> parameterType = e.getParameter().getParameterType();
		// 拿到错误的字段名称
		String fieldName = e.getBindingResult().getFieldError().getField();
		Field field = null;
		try {
			field = parameterType.getDeclaredField(fieldName);
		} catch (NoSuchFieldException e1) {
			// TODO Auto-generated catch block
			e1.printStackTrace();
		} catch (SecurityException e1) {
			// TODO Auto-generated catch block
			e1.printStackTrace();
		}
		// 获取Field对象上的自定义注解
		ValidateErrorCode annotation = field.getAnnotation(ValidateErrorCode.class);
		if (annotation != null) {
			errorCode.setCode(annotation.value());
		}

		errorCode.setMsg(errorMsg);

		result.setErr(errorCode);
		// 然后提取错误提示信息进行返回
		return result;
	}


}