前言
前后端拆散开发,常常用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数据封装类
@Datapublic 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@Slf4jpublic 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@RestControllerAdvicepublic 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(); }}
后端的对立数据封装差不多就这样了。。。