一、概述
二、技术点说明
2.1、springboot与mybatisplus整合
【代码生成器、分页、逻辑删除】参看 代码
2.2、log4j2整合
参看 代码
2.3、统一响应【统一异常处理】
1、设置统一响应输出类 BaseResponse
package com.aaa.test.response; import com.aaa.test.enums.ErrorCodeEnum; /** * 统一返回结果 */ public class BaseResponse<T> { /** * 返回的data * */ private T data; /** * 错误码 * */ private Integer errorCode; /** * 错误信息 * */ private String errorMsg; /** * 是否成功 * */ private boolean success = false; /** * 出现异常的构造函数 * */ public BaseResponse(ErrorCodeEnum errorCodeEnum) { this.errorCode = errorCodeEnum.getErrorCode(); this.errorMsg = errorCodeEnum.getErrorMsg(); } /** * 成功返回的结果 * */ public BaseResponse(T data) { success = true; this.data = data; } /** * 成功返回的结果 * */ public BaseResponse(boolean success,ErrorCodeEnum errorCodeEnum,T data) { this.success = success; this.data = data; this.errorCode = errorCodeEnum.getErrorCode(); this.errorMsg = errorCodeEnum.getErrorMsg(); } public static <T> BaseResponse success(T data) { return new BaseResponse(data); } public static <T> BaseResponse success(ErrorCodeEnum errorCodeEnum) { return new BaseResponse(true,errorCodeEnum,null); } public static BaseResponse fail(ErrorCodeEnum errorCodeEnum) { return new BaseResponse(errorCodeEnum); } public static BaseResponse fail() { return new BaseResponse(ErrorCodeEnum.result_exception); } public T getData() { return data; } public void setData(T data) { this.data = data; } public Integer getErrorCode() { return errorCode; } public void setErrorCode(Integer errorCode) { this.errorCode = errorCode; } public String getErrorMsg() { return errorMsg; } public void setErrorMsg(String errorMsg) { this.errorMsg = errorMsg; } public boolean isSuccess() { return success; } public void setSuccess(boolean success) { this.success = success; } @Override public String toString() { return "BaseResponse{" + "data=" + data + ", errorCode='" + errorCode + '\'' + ", errorMsg='" + errorMsg + '\'' + ", success=" + success + '}'; } }
其中用到了错误码 ErrorCodeEnum
package com.aaa.test.enums; /** * 错误代码枚举类 */ public enum ErrorCodeEnum { // 成功类响应 success(200000, "成功"), no_response_data(200001, "没有返回数据"), //请求类响应码 Param_does_not_exist(400001, "查找参数不存在"), Param_does_not_correct(400002, "所传参数格式不正确"), HttpMediaTypeNotSupportedException(400003, "不支持的Content-type类型"), result_exception(600000, "待处理服务端异常"), ; ErrorCodeEnum(Integer errorCode, String errorMsg) { this.errorCode = errorCode; this.errorMsg = errorMsg; } /** * 错误码 */ private Integer errorCode; /** * 错误信息 */ private String errorMsg; public Integer getErrorCode() { return errorCode; } public void setErrorCode(Integer errorCode) { this.errorCode = errorCode; } public String getErrorMsg() { return errorMsg; } public void setErrorMsg(String errorMsg) { this.errorMsg = errorMsg; } }
技术需求
1、统一响应类支持静态的成功失败方法
2、错误码,设计应为6位数值类型,其中200000 类别为成功类型,400000为请求类型码,500000为服务端异常,其他大于 600000码为客户自定义码,
2、Controller编写
支持controller多种响应参数
常见类型String,int,Integer、Map、Object、单个类等
支持使用上述:BaseResponse 包装响应类
支持使用:ResponseEntity接收类型
通过统一响应处理返回统一:BaseResponse格式
3、统一响应处理方案
编写RestControllerAdvice,对响应,以及异常统一处理
/** * 统一返回结果异常处理类 */ @RestControllerAdvice public class ResponseResultBodyAdvice implements ResponseBodyAdvice<Object> { private final Logger log = LoggerFactory.getLogger(ResponseResultBodyAdvice.class); private static final Class<? extends Annotation> ANNOTATION_TYPE = ResponseBody.class; /** * 判断类或者方法是否使用了 @ResponseResultBody */ @Override public boolean supports(MethodParameter returnType, Class<? extends HttpMessageConverter<?>> converterType) { return AnnotatedElementUtils.hasAnnotation(returnType.getContainingClass(), ANNOTATION_TYPE) || returnType.hasMethodAnnotation(ANNOTATION_TYPE); } /** * 当类或者方法使用了 @ResponseResultBody 就会调用这个方法 */ @Override public Object beforeBodyWrite(Object body, MethodParameter returnType, MediaType selectedContentType, Class<? extends HttpMessageConverter<?>> selectedConverterType, ServerHttpRequest request, ServerHttpResponse response) { // 避免已经返回基础类型 多次转换 if (body instanceof BaseResponse) { return body; } return BaseResponse.success(body); } /** * 提供对标准Spring MVC异常的处理 * * @param ex the target exception * @param request the current request */ @ExceptionHandler(Exception.class) public final ResponseEntity<BaseResponse<?>> exceptionHandler(Exception ex, WebRequest request) { log.error("ExceptionHandler: {}", ex.getMessage()); HttpHeaders headers = new HttpHeaders(); if (ex instanceof HttpMediaTypeNotSupportedException) { // 针对 返回String 类型 需要客户端设置Content-type 为application/json return this.handleResultException(new ResultException(ErrorCodeEnum.HttpMediaTypeNotSupportedException), headers, request); } else if (ex instanceof ResultException) { return this.handleResultException((ResultException) ex, headers, request); } //TODO: 这里可以自定义其他的异常拦截 return this.handleException(ex, headers, request); } /** * 对ResultException类返回返回结果的处理 */ protected ResponseEntity<BaseResponse<?>> handleResultException(ResultException ex, HttpHeaders headers, WebRequest request) { BaseResponse<?> body = BaseResponse.fail((ex.getErrorCodeEnum())); HttpStatus status = null; if (ex.getErrorCodeEnum().getErrorCode().intValue() >= 500000) { status = HttpStatus.INTERNAL_SERVER_ERROR; } else if (ex.getErrorCodeEnum().getErrorCode().intValue() >= 400000) { status = HttpStatus.BAD_REQUEST; } return this.handleExceptionInternal(ex, body, headers, status, request); } /** * 异常类的统一处理 */ protected ResponseEntity<BaseResponse<?>> handleException(Exception ex, HttpHeaders headers, WebRequest request) { BaseResponse<?> body = BaseResponse.fail(); HttpStatus status = HttpStatus.INTERNAL_SERVER_ERROR; return this.handleExceptionInternal(ex, body, headers, status, request); } /** * org.springframework.web.servlet.mvc.method.annotation.ResponseEntityExceptionHandler * handleExceptionInternal(java.lang.Exception, java.lang.Object, org.springframework.http.HttpHeaders, * org.springframework.http.HttpStatus, org.springframework.web.context.request.WebRequest) * <p> * A single place to customize the response body of all exception types. * <p>The default implementation sets the {@link WebUtils#ERROR_EXCEPTION_ATTRIBUTE} * request attribute and creates a {@link ResponseEntity} from the given * body, headers, and status. */ protected ResponseEntity<BaseResponse<?>> handleExceptionInternal( Exception ex, BaseResponse<?> body, HttpHeaders headers, HttpStatus status, WebRequest request) { if (HttpStatus.INTERNAL_SERVER_ERROR.equals(status)) { request.setAttribute(WebUtils.ERROR_EXCEPTION_ATTRIBUTE, ex, WebRequest.SCOPE_REQUEST); } return new ResponseEntity<>(body, headers, status); } }
上述在返回String类型,以及Object等类型或者为空时会出现类型转换异常。做以下处理:
1、配置WebMvcConfigurer,将 MappingJackson2HttpMessageConverter
/旧版本 WebMvcConfigurerAdapter spring5弃用了 WebMvcConfigurerAdapter @Configuration public class WebMvcConfig implements WebMvcConfigurer { @Override public void configureMessageConverters(List<HttpMessageConverter<?>> converters) { //提到最前面 ,主要为了处理基础类型时 XXX not cast String type 类似问题,结合请求类型必须为application/json // 提前使用MappingJackson2HttpMessageConverter 处理 避免使用 StringHttpMessageConverter处理 String类型 converters.add(0,new MappingJackson2HttpMessageConverter()); } }
主要作用://提到最前面 ,主要为了处理基础类型时 XXX not cast String type 类似问题,结合请求类型必须为application/json
// 提前使用MappingJackson2HttpMessageConverter 处理 避免使用 StringHttpMessageConverter处理 String类型
2、编写controller级别aop,主要作用处理,对象为null,以及String为null,转换为BaseResponse时的类型转换异常
/** * 统一结果处理切面, 注意返回时 null 时候 处理 */ @Aspect @Component public class ResponseAspect { @Around("execution(* com.aaa.test.controller..*(..))") public Object controllerProcess(ProceedingJoinPoint pjd) throws Throwable { Object result = pjd.proceed(); // 是null特殊处理 if (result == null) { try { MethodSignature signature = (MethodSignature) pjd.getSignature(); Class returnType = signature.getReturnType(); if("java.lang.Object".equals(returnType.getName())){ // object 使用此方式 return BaseResponse.success(result); }else if("java.lang.String".equals(returnType.getName())){ // 字符串 初始化一个新的返回 return returnType.newInstance(); } //其他默认 返回 return result; }catch (Exception ex){ ex.printStackTrace(); } } return result; } }