我们可以通过自定义拦截器对接口的参数实现校验。如何实现自定义拦截器请参考spring boot 2.x 简单实现自定义拦截器
public boolean preHandle (HttpServletRequest request, HttpServletResponse response, Object handler )
通过实现preHandle这个方法,我们可以在请求前对各参数进行验证。这个方法有三个参数,通过HttpServletRequest 我们可以获取到所有的请求参数。
请求对象:
@Data
public class RequestUser implements Serializable {
@NotNull (message = "用户ID不能为空")
private Integer userId;
@NotNull(message = "用户名称不能为空")
//@Pattern (regexp = "^.{6,12}$",message = "用户名不符合规范")
@Length(min = 6,max = 12,message = "用户名不符合规范")
private String userName;
@Max (value = 65, message = "年龄不在规定范围内")
@Min (value = 18,message = "年龄不在规定范围内")
@NotNull( message = "年龄不能为空")
private Integer age;
@NotNull (message = "交易金额不能为空")
@Pattern (regexp = "^([1-9][0-9]*)$", message = "无效的交易金额")
private String tradeAmount;
}
用的是 validation-api-2.0.1.Final.jar 中的注解。
@Length 只能用于String 类型。
拦截器实现方法
public boolean preHandle (
HttpServletRequest request, HttpServletResponse response, Object handler ) throws Exception {
logger.info ("请求前拦截 :{}",request.getRequestURL () );
Map map = request.getParameterMap ();
HandlerMethod method = ( HandlerMethod ) handler;
MethodParameter[] params = method.getMethodParameters ();
if (params == null || params.length == 0 ) {
return true;
}
MethodParameter parameter = params[0];
Class reqClass = parameter.getParameterType ();
//判断是那一个请求对象
if (reqClass.newInstance () instanceof RequestUser) {
//Map 转化成 bean
RequestUser ru = vail.mapToBean (map, RequestUser.class);
//验证
String msg = vail.validata (ru);
if (StringUtils.isNotEmpty(msg)) {
logger.error ("验证结果:{}",msg);
//抛出自定义异常结果
throw new VailException (msg);
}
}
return true;
}
验证的工具类:
public class VailUtils {
private static ValidatorFactory factory = Validation.buildDefaultValidatorFactory();
public static List validateAll( T o) {
List errorList = new ArrayList ();
Set> violations = factory.getValidator().validate(o);
if (!CollectionUtils.isEmpty (violations)) {
violations.forEach (tConstraintViolation -> {
errorList.add(tConstraintViolation.getMessage());
});
}
return errorList;
}
public String validata(Object param) throws RuntimeException {
String errorMessage = null;
try {
List errorList = validateAll(param);
Assert.isTrue(CollectionUtils.isEmpty(errorList), errorList.toString());
} catch (Exception e) {
errorMessage = e.getMessage();
}
return errorMessage;
}
public T mapToBean( Map map, Class cla) throws Exception {
T bean = null;
try {
bean = cla.newInstance ();
ConvertUtils.register(new DoubleConverter (null), Double.class);
ConvertUtils.register(new IntegerConverter (null), Integer.class);
ConvertUtils.register(new DateConverter (null), java.util.Date.class);
//此方法会自动给 Integer Double 为 null 的字段赋值,因此需要ConvertUtils.register处理
BeanUtils.populate(bean, map);
} catch ( Exception e ){
e.printStackTrace ();
}
return bean;
}
}
异常处理:
@ControllerAdvice
public class ExecptionHandler {
private Logger logger = LoggerFactory.getLogger (ExecptionHandler.class);
@ExceptionHandler(value = Exception.class)
@ResponseBody
String defaultErrorHandler( HttpServletRequest req, Exception e) throws Exception {
HashMap map = new HashMap <> (2);
if (e instanceof VailException ) {
VailException vex = (VailException) e;
logger.error("{}", vex.getMessage ());
map.put ("code","vailError");
map.put ("msg",vex.getMessage ());
}
//TODO 其他的异常处理
return JSON.toJSONString (map);
}
}
controller 控制层
@RequestMapping ("/api")
@RestController
public class APIController {
@GetMapping (value = "/users")
String test (RequestUser requestUser){
return JSON.toJSONString (requestUser);
}
}
访问 http://localhost:881/api/users?userId=1&age=18&userName=%27test%27&tradeAmount=
可以看到提示 :{“msg”:"[无效的交易金额]",“code”:“vailError”}
从请求对象的注解上可以看到,要求是tradeAmount参数不能为空,并且参数值是有限制的。
如果只是单一接口的参数需要验证,那么可以不用去实现拦截器,在controller方法里就可以实现验证
例如:在APIController 中我们增加一个方法
使用 @Valid + BindingResult 来完成参数验证,注意@Valid + BindingResult是成对出现的。
@GetMapping (value = "/qry")
String test ( @Valid RequestDto requestDto, BindingResult err) {
//是否存在异常
if ( err.hasErrors () ) {
//将每一个异常存入到map中
HashMap errMap = new HashMap <> ();
err.getAllErrors ().stream ().forEach (
er ->{
FieldError fieldError = (FieldError)er;
errMap.put (fieldError.getField (),fieldError.getDefaultMessage ());
}
);
return JSON.toJSONString (errMap);
}
return JSON.toJSONString (requestDto);
}
RequestDto 对象:
@Data
public class RequestDto implements Serializable {
private static final long serialVersionUID = 8049172738251461758L;
@NotNull(message = "手机号不能为空")
@Length(min = 11,max = 11,message = "手机号格式错误")
private String telnum;
@NotNull(message = "归属地不能为空")
@Length(min = 3,max = 3,message = "归属地数据格式错误")
private String region;
private String billType;
private String stauts;
}
直接访问 http://localhost:881/api/qry 可以看到结果是 {“region”:“归属地不能为空”,“telnum”:“手机号不能为空”}
demo下载