1、杜绝通篇 if else 参数判断!!!
2、普通参数方式
3、实体对象参数方式

效果
参数不合法,自动使用统一异常返回错误,例如:

{
    "code": "-3",
    "message": "参数{age}最小18"
}

实现代码
代码一次性给全,主要包含如下几个Java类,拿过去拷贝到项目中就能用:
1、ValidatorController
2、ValidatorVo
3、ExampleValidatorService
4、ResultCode
5、ResultResponseBodyAdvice
6、ResultVO_IGNORE
7、ResultVO


import javax.validation.constraints.Email;
import javax.validation.constraints.NotNull;
import javax.validation.constraints.Size;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import link.nuggets.user.module.example.model.ValidatorVo;
import link.nuggets.user.module.example.service.ExampleValidatorService;

/**
 * Validator示例
 * 
 * @author 单红宇
 * @date 2019年7月8日
 *
 */
@Validated // 注意!1) 如果想在参数中使用 @NotNull 这种注解校验,就必须在类上添加 @Validated;2) 如果方法中的参数是对象类型,则必须要在参数对象前面添加 @Validated
@RestController
@RequestMapping("/example/valid")
public class ValidatorController {
	
	@Autowired
	private ExampleValidatorService exampleValidatorService;

	/**
	 * 直接参数校验
	 * 要特别提醒的是,验证框架里面大部分都不需要我们显示设置message,每个注解框架都给了一个默认提示语,大多数提示还都比较友好
	 * 
	 * @param email
	 * @return
	 */
	@GetMapping("/test1")
	public String test1(@NotNull(message = "不能为空") @Size(max = 32, min = 6, message = "长度需要在6-32之间") @Email String email) {
		return "OK";
	}

	/**
	 * 实体类校验
	 * 
	 * @param validatorVo
	 * @return
	 */
	@GetMapping("/test2")
	public String test2(@Validated ValidatorVo validatorVo) {
		return "Validator OK";
	}

	/**
	 * 内部Service校验
	 * 
	 * @return
	 */
	@GetMapping("/test3")
	public String test3() {
		return exampleValidatorService.show("16");
	}

}


import javax.validation.constraints.Max;
import javax.validation.constraints.Min;
import javax.validation.constraints.NotNull;
import javax.validation.constraints.Size;

import lombok.Data;

/**
 * 验证示例VO
 * 
 * @author 单红宇
 * @date 2019年7月10日
 *
 */
@Data
public class ValidatorVo {

	@NotNull(message = "不能为空")
	@Size(max = 16, min = 6, message = "字符串长度需要在6-16之间")
	private String name;
	@Max(value = 100, message = "最大100")
	@Min(value = 18, message = "最小18")
	private String age;
}


import javax.validation.constraints.Min;
import javax.validation.constraints.NotNull;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;
import org.springframework.validation.annotation.Validated;

/**
 * 示例
 * 
 * @author 单红宇
 * @date 2019年7月10日
 *
 */
@Validated
@Service
public class ExampleValidatorService {

	private static final Logger logger = LoggerFactory.getLogger(ExampleValidatorService.class);

	public String show(@NotNull(message = "不能为空") @Min(value = 18, message = "最小18") String age) {
		logger.info("age = {}", age);
		return age;
	}

}


/**
 * 统一返回值
 * 
 * @author 单红宇
 * @date   2019年6月26日
 *
 */
public enum ResultCode {

	/** 操作成功 */
	SUCCESS("1", "成功"),

	/** 操作失败 */
	FAIL("0", "失败"),
	
	/** 操作失败 */
	NULL("-1", "数据不存在"),

	/** 系统发生异常 */
	EXCEPTION("-2", "系统异常"),
	
	/** 没有权限 */
	FORBIDDEN("9403", "没有权限"),
	
	/** 参数错误 */
	PARAM_INVALID("-3", "参数错误");
	
	private String code;
	private String msg;
	
	private ResultCode(String code, String msg) {
		this.code = code;
		this.msg = msg;
	}

	public String code() {
		return code;
	}

	public String msg() {
		return msg;
	}

}


import java.util.Set;

import javax.servlet.http.HttpServletRequest;
import javax.validation.ConstraintViolation;
import javax.validation.ConstraintViolationException;

import org.hibernate.validator.internal.engine.path.PathImpl;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.boot.autoconfigure.web.servlet.error.BasicErrorController;
import org.springframework.core.MethodParameter;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter;
import org.springframework.http.server.ServerHttpRequest;
import org.springframework.http.server.ServerHttpResponse;
import org.springframework.http.server.ServletServerHttpRequest;
import org.springframework.validation.BindException;
import org.springframework.validation.FieldError;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.servlet.mvc.method.annotation.ResponseBodyAdvice;

/**
 * Controller 统一返回包装
 * 
 * @author 单红宇
 * @date 2019年6月26日
 *
 */
@ControllerAdvice
public class ResultResponseBodyAdvice implements ResponseBodyAdvice<Object> {

	private static final Logger logger = LoggerFactory.getLogger(ResultResponseBodyAdvice.class);

	@Override
	public Object beforeBodyWrite(Object body, MethodParameter returnType, MediaType selectedContentType,
			Class<? extends HttpMessageConverter<?>> selectedConverterType, ServerHttpRequest request,
			ServerHttpResponse response) {
		// 此处获取到request 为特殊需要的时候处理使用
//		HttpServletRequest req = ((ServletServerHttpRequest) serverHttpRequest).getServletRequest();
		// 下面处理统一返回结果(统一code、msg、sign 加密等)
		if (selectedConverterType == MappingJackson2HttpMessageConverter.class
				&& (selectedContentType.equals(MediaType.APPLICATION_JSON)
						|| selectedContentType.equals(MediaType.APPLICATION_JSON_UTF8))) {
			if (body == null) {
				return ResultVO.NULL;
			} else if (body instanceof ResultVO) {
				return body;
			} else {
				// 异常
				if (returnType.getExecutable().getDeclaringClass().isAssignableFrom(BasicErrorController.class)) {
					ResultVO vo = new ResultVO(ResultCode.EXCEPTION);
					HttpServletRequest req = ((ServletServerHttpRequest) request).getServletRequest();
					if (req.getRequestURL().toString().contains("localhost")
							|| req.getRequestURL().toString().contains("127.0.0.1"))
						vo.setData(body);
					return vo;
				} else {
					return new ResultVO(body);
				}
			}
		}
		return body;
	}

	@Override
	public boolean supports(MethodParameter returnType, Class<? extends HttpMessageConverter<?>> converterType) {
		if (returnType.hasMethodAnnotation(ResultVO_IGNORE.class))
			return false;
		return true;
	}

	/**
	 * Validator 参数校验异常处理
	 * 
	 * @param ex
	 * @return
	 */
	@ExceptionHandler(value = BindException.class)
	public ResponseEntity<Object> handleMethodVoArgumentNotValidException(BindException ex) {
		FieldError err = ex.getFieldError();
		// err.getField() 读取参数字段
		// err.getDefaultMessage() 读取验证注解中的message值
		String message = "参数{".concat(err.getField()).concat("}").concat(err.getDefaultMessage());
		logger.info("{} -> {}", err.getObjectName(), message);
		return new ResponseEntity<Object>(new ResultVO(ResultCode.PARAM_INVALID, message), HttpStatus.OK);
	}

	/**
	 * Validator 参数校验异常处理
	 * 
	 * @param ex
	 * @return
	 */
	@ExceptionHandler(value = ConstraintViolationException.class)
	public ResponseEntity<Object> handleMethodArgumentNotValidException(ConstraintViolationException ex) {
		Set<ConstraintViolation<?>> constraintViolations = ex.getConstraintViolations();
		for (ConstraintViolation<?> constraintViolation : constraintViolations) {
			PathImpl pathImpl = (PathImpl) constraintViolation.getPropertyPath();
			// 读取参数字段,constraintViolation.getMessage() 读取验证注解中的message值
			String paramName = pathImpl.getLeafNode().getName();
			String message = "参数{".concat(paramName).concat("}").concat(constraintViolation.getMessage());
			logger.info("{} -> {} -> {}", constraintViolation.getRootBeanClass().getName(), pathImpl.toString(), message);
			return new ResponseEntity<Object>(new ResultVO(ResultCode.PARAM_INVALID, message), HttpStatus.OK);
		}
		return new ResponseEntity<Object>(new ResultVO(ResultCode.PARAM_INVALID, ex.getMessage()), HttpStatus.OK);
	}

}


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

/**
 * Controller默认进行ResultVO包装,对于特殊不需要的,使用该注解可以忽略包装
 * 
 * @author 单红宇
 * @date 2019年6月26日
 *
 */
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface ResultVO_IGNORE {

}


import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.google.gson.Gson;

/**
 * Controller 统一定义返回类
 * 
 * @author 单红宇
 * @date 2019年6月26日
 *
 */
public class ResultVO {

	private static final Logger logger = LoggerFactory.getLogger(ResultVO.class);

	public static final ResultVO SUCCESS = new ResultVO(ResultCode.SUCCESS);
	public static final ResultVO FAIL = new ResultVO(ResultCode.FAIL);
	public static final ResultVO FORBIDDEN = new ResultVO(ResultCode.FORBIDDEN);
	public static final ResultVO NULL = new ResultVO(ResultCode.NULL);
	public static final ResultVO EXCEPTION = new ResultVO(ResultCode.EXCEPTION);
	public static final ResultVO PARAM_INVALID = new ResultVO(ResultCode.PARAM_INVALID);

	/**
	 * 返回代码
	 */
	private String code;

	/**
	 * 返回信息
	 */
	private String message;

	/**
	 * 返回数据
	 */
	private Object data;

	public Object getData() {
		return data;
	}

	public void setData(Object data) {
		this.data = data;
	}

	/**
	 * 默认构造,返回操作正确的返回代码和信息
	 */
	public ResultVO() {
		this.setCode(ResultCode.SUCCESS.code());
		this.setMessage(ResultCode.SUCCESS.msg());
	}

	/**
	 * 构造一个返回特定代码的ResultVO对象
	 * 
	 * @param code
	 */
	public ResultVO(ResultCode code) {
		this.setCode(code.code());
		this.setMessage(code.msg());
	}

	public ResultVO(String code, String message) {
		super();
		this.setCode(code);
		this.setMessage(message);
	}

	/**
	 * 默认值返回,默认返回正确的code和message
	 * 
	 * @param data
	 */
	public ResultVO(Object data) {
		ResultCode rc = data == null ? ResultCode.NULL : ResultCode.SUCCESS;
		this.setCode(rc.code());
		this.setMessage(rc.msg());
		this.setData(data);
	}

	/**
	 * 构造返回代码,以及自定义的错误信息
	 * 
	 * @param code
	 * @param message
	 */
	public ResultVO(ResultCode code, String message) {
		this.setCode(code.code());
		this.setMessage(message);
	}

	/**
	 * 构造自定义的code,message,以及data
	 * 
	 * @param code
	 * @param message
	 * @param data
	 */
	public ResultVO(ResultCode code, String message, Object data) {
		this.setCode(code.code());
		this.setMessage(message);
		this.setData(data);
	}

	public String getMessage() {
		return message;
	}

	public void setMessage(String message) {
		this.message = message;
	}

	public String getCode() {
		// request请求响应的时候,一定会走到这里,判断如果code不是成功状态,就输出日志
		if (!ResultCode.SUCCESS.code().equals(code))
			logger.info("ResultVO={}", new Gson().toJson(this));
		return code;
	}

	public void setCode(String code) {
		this.code = code;
	}

}

一个不需要强调的提示,springboot 的web项目正常都是已经包含如下依赖了,该依赖里已经包含了validation-api

	<dependency>
		<groupId>org.springframework.boot</groupId>
		<artifactId>spring-boot-starter-web</artifactId>
	</dependency>

validation-api 的注解清单

注释 描述
@AssertFalse 被注释的元素必须为 false
@AssertTrue 同@AssertFalse
@DecimalMax 被注释的元素必须是一个数字,其值必须小于等于指定的最大值
@DecimalMin 同DecimalMax
@Digits 带批注的元素必须是一个在可接受范围内的数字
@Email 顾名思义
@Future 将来的日期
@FutureOrPresent 现在或将来
@Max 被注释的元素必须是一个数字,其值必须小于等于指定的最大值
@Min 被注释的元素必须是一个数字,其值必须大于等于指定的最小值
@Negative 带注释的元素必须是一个严格的负数(0为无效值)
@NegativeOrZero 带注释的元素必须是一个严格的负数(包含0)
@NotBlank 同StringUtils.isNotBlank
@NotEmpty 同StringUtils.isNotEmpty
@NotNull 不能是Null
@Null 元素是Null
@Past 被注释的元素必须是一个过去的日期
@PastOrPresent 过去和现在
@Pattern 被注释的元素必须符合指定的正则表达式
@Positive 被注释的元素必须严格的正数(0为无效值)
@PositiveOrZero 被注释的元素必须严格的正数(包含0)
@Szie 带注释的元素大小必须介于指定边界(包括)之间

(END)