Implementation of Custom Interceptor
We can verify the parameters of the interface by customizing the interceptor. How to implement a custom interceptor, please refer to Simple Implementation of Custom Interceptor in Sprboot 2.x
public boolean preHandle (HttpServletRequest request, HttpServletResponse response, Object handler )
By implementing the preHandle method, we can validate the parameters before requesting. This method has three parameters, and we can get all the request parameters through HttpServletRequest.
Request object:
@Data public class RequestUser implements Serializable { @NotNull (message = "user ID Can not be empty") private Integer userId; @NotNull(message = "User name cannot be empty") //@ Pattern (regexp = "^.{6,12}$",message = username does not conform to the specification") @Length(min = 6,max = 12,message = "User name does not conform to specifications") private String userName; @Max (value = 65, message = "Age is not within the prescribed range") @Min (value = 18,message = "Age is not within the prescribed range") @NotNull( message = "Age cannot be empty") private Integer age; @NotNull (message = "Transaction amount cannot be empty") @Pattern (regexp = "^([1-9][0-9]*)$", message = "Invalid transaction amount") private String tradeAmount; }
The annotations in validation-api-2.0.1.Final.jar are used.
@ Length can only be used for String types.
Interceptor Implementation Method
public boolean preHandle ( HttpServletRequest request, HttpServletResponse response, Object handler ) throws Exception { logger.info ("Interception before request:{}",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 (); //Judgment is the object of the request if (reqClass.newInstance () instanceof RequestUser) { //Map to bean RequestUser ru = vail.mapToBean (map, RequestUser.class); //Verification String msg = vail.validata (ru); if (StringUtils.isNotEmpty(msg)) { logger.error ("Verification results:{}",msg); //Throw custom exception results throw new VailException (msg); } } return true; }
Tool classes for validation:
public class VailUtils { private static ValidatorFactory factory = Validation.buildDefaultValidatorFactory(); public static <T> List<String> validateAll( T o) { List<String> errorList = new ArrayList<String> (); Set<ConstraintViolation<T>> 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<String> errorList = validateAll(param); Assert.isTrue(CollectionUtils.isEmpty(errorList), errorList.toString()); } catch (Exception e) { errorMessage = e.getMessage(); } return errorMessage; } public <T> T mapToBean( Map<String,String> map, Class<T> 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); //This method automatically assigns values to Integer Double fields for null, so ConvertUtils.register processing is required. BeanUtils.populate(bean, map); } catch ( Exception e ){ e.printStackTrace (); } return bean; } }
Exception handling:
@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<String,String> 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 other exception handling return JSON.toJSONString (map); } }
controller Control Layer
@RequestMapping ("/api") @RestController public class APIController { @GetMapping (value = "/users") String test (RequestUser requestUser){ return JSON.toJSONString (requestUser); } }
Visit http://localhost:881/api/users? UserId=1&age=18&userName=%27test%27&tradeAmount Amount=
You can see hints: {"msg": "[invalid transaction amount]", "code": "vail Error"}
As you can see from the annotation of the request object, the requirement is that the tradeAmount parameter cannot be empty, and the parameter value is limited.
Verify @Valid + BindingResult on method parameters
If only the parameters of a single interface need to be validated, then the interceptor can not be implemented and the validation can be implemented in the controller method.
For example, in APIController, we add a method
Use @Valid + BindingResult to complete parameter validation. Note that @Valid + BindingResult appears in pairs.
@GetMapping (value = "/qry") String test ( @Valid RequestDto requestDto, BindingResult err) { //Is there an exception? if ( err.hasErrors () ) { //Save each exception in a map HashMap<String,String> 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 object:
@Data public class RequestDto implements Serializable { private static final long serialVersionUID = 8049172738251461758L; @NotNull(message = "The phone number can not be empty.") @Length(min = 11,max = 11,message = "Wrong phone number format") private String telnum; @NotNull(message = "Attribution cannot be empty") @Length(min = 3,max = 3,message = "Ownership data format error") private String region; private String billType; private String stauts; }
Direct access to http://localhost:881/api/qry can see the result is {"region": "attribution can not be empty", "telnum": "mobile phone number can not be empty"}
demo download