前言
前后端拆散开发,常常用 json 数据格式进行交互,对立的响应数据格式,造成对立标准,能够大大不便前后端人员的开发。
Response 数据封装
- 编码枚举类 ResultCode.java
public enum ResResultCode {
/**
* 胜利
*/
SUCCESS(200, "ok"),
/**
* 申请谬误
*/
BAD_REQUEST(400, "申请参数谬误"),
/**
* 未登录受权
*/
UNAUTHORIZED(401, "有效令牌"),
/**
* 权限有余
*/
FORBIDDEN(403, "权限有余"),
/**
* 服务器谬误
*/
FAILED(500, "server error"),
/**
* 业务异样
*/
BIZ_ERROR(600, "业务异样");
private int status;
private String message;
ResResultCode(int status, String message) {
this.status = status;
this.message = message;
}
public int getStatus() {return status;}
public String getMessage() {return message;}
public void setStatus(int status) {this.status = status;}
public void setMessage(String message) {this.message = message;}
}
- json 数据封装类
@Data
public class ResResult {
/**
* 响应编码
*/
private int code;
/**
* 响应信息
*/
private String msg;
/**
* 响应数据
*/
private Object data;
public ResResult(int code, String msg) {
this.code = code;
this.msg = msg;
}
public ResResult(int code, String msg, Object data) {
this.code = code;
this.msg = msg;
this.data = data;
}
public static ResResult success() {return new ResResult(ResResultCode.SUCCESS.getStatus(), ResResultCode.SUCCESS.getMessage(), null);
}
public static ResResult success(Object data) {return new ResResult(ResResultCode.SUCCESS.getStatus(), ResResultCode.SUCCESS.getMessage(), data);
}
public static ResResult failure() {return new ResResult(ResResultCode.FAILED.getStatus(), ResResultCode.FAILED.getMessage());
}
public static ResResult failure(ResResultCode ResResultCode) {return new ResResult(ResResultCode.getStatus(), ResResultCode.getMessage());
}
}
自定义异样类
- BizErrorException.java 用来抛出业务异样
public class BizErrorException extends RuntimeException {
private ResResultCode resResultCode;
private String message;
public BizErrorException(ResResultCode resResultCode) {this.resResultCode = resResultCode;}
public BizErrorException(ResResultCode resResultCode, String message) {
this.resResultCode = resResultCode;
this.message = message;
}
public ResResultCode getResResultCode() {return resResultCode;}
@Override
public String getMessage() {return message;}
public void setMessage(String message) {this.message = message;}
}
- BadRequestException.java 用来抛出申请参数异样
public class BadRequestException extends RuntimeException {public BadRequestException() { }
public BadRequestException(String message) {super(message);
}
}
全局申请参数校验
尽管 spring 提供了 @Valid 能够进行申请参数的校验
留神一个坑:hibernate-validator 在 springboot 2.3 之后就须要手动引入了,不再主动配置。
<!-- springboot 2.3 之后隐没的 hibernate-validator 解决办法 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-validation</artifactId>
</dependency>
作为一个前后端拆散我的项目,并且接口并不对外裸露,后端每个接口调用都创立一个 vo 类,显然是十分麻烦的,这边就不必这种形式。
这里就抉择了一个偷懒的办法,就是 利用 Knife4j
动静申请参数 再加上 AOP 进行校验。具体实现步骤:
- 引入 AOP 依赖
<!-- AOP -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
</dependency>
- 新建一个 aop 类 ReqValidateAop.java
在执行每个 @DynamicParameters 注解润饰的接口是进行校验,对每个 required = true 的参数进行校验。
/**
* 对含有 @DynamicParameters 动静参数的接口 进行申请参数校验
*/
@Aspect
@Component
@Slf4j
public class ReqValidateAop {
/**
* 所有办法:@Pointcut("execution(* com.ify.formwork.web.controller.*.*.*(..))")
* 含有 @DynamicParameters 注解:@Pointcut("@annotation(com.github.xiaoymin.knife4j.annotations.DynamicParameters)")
*/
@Pointcut("@annotation(com.github.xiaoymin.knife4j.annotations.DynamicParameters)")
public void paramValidate() {}
@Before("paramValidate()")
public void before(JoinPoint joinPoint) throws BadRequestException {List<String> errList = new ArrayList<>();
Object[] objects = joinPoint.getArgs();
JSONObject param = (JSONObject) objects[0];
// 获取以后办法
MethodSignature methodSignature = (MethodSignature) joinPoint.getSignature();
Method method = methodSignature.getMethod();
// 获取办法 @DynamicParameters properties
DynamicParameters annotation = method.getAnnotation(DynamicParameters.class);
List<DynamicParameter> list = Arrays.asList(annotation.properties());
for (DynamicParameter dynamicParameter : list) {
// 必传参数校验
if (dynamicParameter.required()) {Object o = param.get(dynamicParameter.name());
// 申请参数为 null 或申请参数为字符串为空串
boolean badRequest = (null == o) || (o instanceof String && StrUtil.isEmpty((String) o));
if (badRequest) {errList.add(dynamicParameter.name() + "不能为空");
}
}
}
if (!errList.isEmpty()) {throw new BadRequestException(StrUtil.join(",", errList));
}
}
}
全局异样拦挡解决
对服务抛出的异样进行接管,对立解决返回给前端
@Slf4j
@RestControllerAdvice
public class GlobalExceptionHandler {
/***
* 性能形容: 捕捉申请参数异样 ReqValidateAop.java 自定义校验形式
*/
@ResponseStatus(HttpStatus.BAD_REQUEST)
@ExceptionHandler(BadRequestException.class)
public ResResult handleBadRequestException(BadRequestException e) {return new ResResult(ResResultCode.BAD_REQUEST.getStatus(), e.getMessage());
}
/**
* 性能形容: 捕捉申请参数异样 @valid 校验参数形式 (如果采纳这种形式的话能够进行应用)
*/
@ResponseStatus(HttpStatus.BAD_REQUEST)
@ExceptionHandler(MethodArgumentNotValidException.class)
public ResResult handleBadRequestException(MethodArgumentNotValidException e) {BindingResult bindingResult = e.getBindingResult();
List<String> errors = new ArrayList<>();
for (FieldError fieldError : bindingResult.getFieldErrors()) {errors.add(fieldError.getField() + fieldError.getDefaultMessage());
}
return new ResResult(ResResultCode.BAD_REQUEST.getStatus(), StrUtil.join("|", errors));
}
/**
* 业务异样捕捉 对立返回 500 状态,具体信息封装在 msg 里
*/
@ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
@ExceptionHandler(BizErrorException.class)
public ResResult handleBizErrorException(BizErrorException e) {if (StrUtil.isNotEmpty(e.getMessage())) {e.getResResultCode().setMessage(e.getMessage());
}
return ResResult.failure(e.getResResultCode());
}
/**
* 性能形容: 异样对立返回, 对立返回 500 状态
*/
@ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
@ExceptionHandler(Exception.class)
public ResResult handleException(Exception e) {log.error("server error = {}", e.getMessage());
return ResResult.failure();}
}
后端的对立数据封装差不多就这样了。。。