编写接口时, 不可避免的需要对接受的参数进行判断, 此时便会出现大量 if...else... 影响代码可读性, 且校验不够优雅.
本文给出一个参数校验方案, 给大家一个思路. 如果只是想使用, 基本校验的已足够; 如果想自己编写一套, 切记不要被我的工具类给限死, 理解思路, 它有无限的可能.
知识点
涉及到的知识点
建造者模式
链式调用
枚举
异常
继承与多态
拓展所需知识点
委托模式
使用前准备
自定义异常
- public class BaseException extends RuntimeException {
- private Integer status = HttpStatus.BAD_REQUEST.value();
- public BaseException(Integer status) {
- this.status = status;
- }
- public BaseException(BaseEnum baseEnum) {
- super(baseEnum.getMessage());
- this.status = baseEnum.getCode();
- }
- public BaseException(String message) {
- super(message);
- }
- public BaseException(String message, Throwable cause) {
- super(message, cause);
- }
- public BaseException(Throwable cause) {
- super(cause);
- }
- public BaseException(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace) {
- super(message, cause, enableSuppression, writableStackTrace);
- }
- public Integer getStatus() {
- return status;
- }
- }
举个栗子
- @Getter
- public class BadRequestException extends BaseException {
- public BadRequestException(String msg) {
- super(msg);
- }
- public BadRequestException(BaseEnum baseEnum) {
- super(baseEnum);
- }
- }
统一异常管理
- @Slf4j
- @RestControllerAdvice
- public class GlobalExceptionHandler {
- /**
- * 处理系统自定义异常
- */
- @ExceptionHandler(BaseException.class)
- public ResponseEntity handleBaseException(BaseException e) {
- String message = StringUtil.isContainChinese(e.getMessage()) ? e.getMessage() : null;
- return ResponseEntityUtil.badRequest(JsonResult.buildErrorMsg(e.getStatus(),
- Optional.ofNullable(message).orElse(MicroErrorCodeEnum.OPERATE_ERROR.getMessage())));
- }
- /**
- * Throwable
- * 接收非系统预测内的异常
- */
- @ExceptionHandler(Throwable.class)
- public ResponseEntity handleThrowable(Throwable e) {
- log.error("系统捕捉 Throwable 异常并处理 ==>" + e.getMessage(), e);
- String message = StringUtil.isContainChinese(e.getMessage()) ? e.getMessage() : null;
- return ResponseEntityUtil.internalServerError(JsonResult.buildErrorMsg(HttpStatus.INTERNAL_SERVER_ERROR.value(),
- Optional.ofNullable(message).orElse(MicroErrorCodeEnum.SYSTEM_ERROR.getMessage())));
- }
- }
自定义枚举
基础枚举接口
- public interface BaseEnum {
- Integer getCode();
- String getMessage();
- }
举个栗子 (根据自己需求创建)
- public enum SystemErrorCodeEnum implements BaseEnum {
- /**
- * 后台管理系统错误状态码
- */
- PARAMETER_EMPTY(HttpStatus.BAD_REQUEST, "参数不可为空!"),
- TEACHER_NOT_EXISTS(HttpStatus.BAD_REQUEST, "教师不存在!"),
- ID_CANNOT_BE_NULL(HttpStatus.BAD_REQUEST, "ID 不可为空!"),
- EMAIL_CANNOT_BE_NULL(HttpStatus.BAD_REQUEST, "邮箱不可为空!"),
- ;
- private Integer code;
- private String message;
- SystemErrorCodeEnum(HttpStatus httpStatus, String message) {
- this.code = httpStatus.value();
- this.message = message;
- }
- @Override
- public Integer getCode() {
- return code;
- }
- @Override
- public String getMessage() {
- return message;
- }
- }
Validate 核心代码
校验类 context
- @Data
- @AllArgsConstructor
- public class ValidatorContext {
- /** 校验结果 */
- private Boolean checkResult;
- /** 错误信息枚举 */
- private BaseEnum baseEnum;
- }
校验类上下文
- public class ValidatorHolder {
- /** context 集合 */
- private List<ValidatorContext> validatorContexts;
- /** 校验结果 */
- private Boolean result;
- /** 若 result = true, 保存错误信息 */
- private BaseEnum baseEnum;
- /** 初始化 */
- public ValidatorHolder() {
- this.validatorContexts = new ArrayList<>();
- this.result = true;
- this.baseEnum = null;
- }
- /** 校验链 */
- public ValidatorHolder on(Boolean checkResult, BaseEnum baseEnum){
- if(checkResult != null && baseEnum != null){
- addContext(checkResult, baseEnum);
- }
- return this;
- }
- /** 添加待校验属性和错误信息 */
- private void addContext(Boolean checkResult, BaseEnum baseEnum){
- validatorContexts.add(new ValidatorContext(checkResult, baseEnum));
- }
- /** 校验 */
- public ValidatorHolder doValidate(){
- for (ValidatorContext validatorContext : validatorContexts) {
- if(validatorContext.getCheckResult()){
- result = false;
- baseEnum = validatorContext.getBaseEnum();
- break;
- }
- }
- return this;
- }
- public void checkResult(){
- ValidateHandler.checkValidator(this);
- }
- public Boolean getResult() {
- return result;
- }
- public BaseEnum getBaseEnum() {
- return baseEnum;
- }
- }
校验 builder 类
- public class ValidatorBuilder {
- public static ValidatorHolder build(){
- return new ValidatorHolder();
- }
- }
校验处理器
参考 Guava 类库中提供的一个作参数检查的工具类 --Preconditions 类
- public class ValidateHandler {
- /**
- * 判断校验是否成功, 若存在错误, 抛出异常
- * 针对 ValidatorHolder
- */
- public static void checkValidator(ValidatorHolder validator){
- if(! validator.getResult()){
- throw new BadRequestException(validator.getBaseEnum());
- }
- }
- /**
- * 针对单参数校验
- *
- * @param checkResult true: 参数错误; false: 参数正确
- * @param baseEnum 错误码
- */
- public static void checkParameter(Boolean checkResult, BaseEnum baseEnum){
- if(checkResult){
- throw new BadRequestException(baseEnum);
- }
- }
- }
使用举例
具体项目中是如何使用的, 可以参考博客中我正在开发的 U-Learning 后端开发日志 https://www.cnblogs.com/darren1112/p/12147640.html , 其中有 GitHub 项目地址
- Before1
- @PostMapping("/save")
- public ResponseEntity<JsonResult> save(TeacherDto teacher) {
- if(StringUtil.isEmpty(teacher.getTeaName())){
- return ...;
- }
- if(StringUtil.isEmpty(teacher.getTeaNumber())){
- return ...;
- }
- if(StringUtil.isEmpty(teacher.getTeaEmail())){
- return ...;
- }
- // 接口处理业务代码
- ...
- }
- After1
- @PostMapping("/save")
- public ResponseEntity<JsonResult> save(TeacherDto teacher) {
- ValidatorBuilder.build()
- .on(StringUtil.isEmpty(teacher.getTeaName()), SystemErrorCodeEnum.NAME_CANNOT_BE_NULL)
- .on(StringUtil.isEmpty(teacher.getTeaNumber()), SystemErrorCodeEnum.TEA_NUMBER_CANNOT_BE_NULL)
- .on(StringUtil.isEmpty(teacher.getTeaEmail()), SystemErrorCodeEnum.EMAIL_CANNOT_BE_NULL)
- .doValidate().checkResult();
- // 接口处理业务代码
- ...
- }
- Beafore2
当你只有一个需要校验的参数时, 可能会觉得这有些啰嗦
- @GetMapping("/delete")
- public ResponseEntity<JsonResult> delete(Long id) {
- if(StringUtil.isEmpty(id)){
- return ...;
- }
- // 接口处理业务代码
- ...
- }
- After2
- @GetMapping("/delete")
- public ResponseEntity<JsonResult> delete(Long id) {
- ValidateHandler.checkParameter(StringUtil.isEmpty(id), SystemErrorCodeEnum.ID_CANNOT_BE_NULL);
- // 接口处理业务代码
- ...
- }
来源: http://www.bubuko.com/infodetail-3376966.html