Unified verification of spring boot 2.x interface parameters

Keywords: JSON Java Mobile

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

Posted by tastyniall on Thu, 03 Oct 2019 07:48:14 -0700