河南 网站建设sem竞价托管
文章目录
- 全局Json序列化
- Controller日志切面
- 全局异常拦截
- GlobalExceptionHandler
- ApiResult
- BusinessException
- ResponseEntityUtil
- 全局返回体包装
- MP自动填充
- 接口文档配置类
- 自定义Async异步线程池
本文主要整理各类项目中通用的配置类、工具类,便于复查自用。
全局Json序列化
@Configuration
public class JacksonConfig {/*** null → ''*/@Bean@Primary@ConditionalOnMissingBean(ObjectMapper.class)public ObjectMapper jacksonObjectMapper(Jackson2ObjectMapperBuilder builder) {ObjectMapper objectMapper = builder.createXmlMapper(false).build();SerializerProvider serializerProvider = objectMapper.getSerializerProvider();serializerProvider.setNullValueSerializer(new JsonSerializer<Object>() {@Overridepublic void serialize(Object o, JsonGenerator jsonGenerator, SerializerProvider serializerProvider) throws IOException {jsonGenerator.writeString("");}});return objectMapper;}}
Controller日志切面
@Slf4j
@Aspect
@Component
public class ControllerLogAspect {@Around("@within(org.springframework.web.bind.annotation.RequestMapping)")public Object intoControllerLog(ProceedingJoinPoint pjp) throws Throwable {// 记录请求开始执行时间long beginTime = System.currentTimeMillis();// 请求类名、方法名String methodName = pjp.getSignature().getName();String clazzName = pjp.getTarget().getClass().getSimpleName();// 获取请求参数MethodSignature ms = (MethodSignature) pjp.getSignature();// 获取请求参数类型String[] parameterNames = ms.getParameterNames();// 获取请求参数值Object[] parameterValues = pjp.getArgs();StringBuilder param = new StringBuilder();// 组合请求参数,进行日志打印if (parameterNames != null && parameterNames.length > 0) {for (int i = 0; i < parameterNames.length; i++) {if ((parameterValues[i] instanceof HttpServletRequest) || (parameterValues[i] instanceof HttpServletResponse)) {param.append("[").append(parameterNames[i]).append("=").append(parameterValues[i]).append("]");} else {param.append("[").append(parameterNames[i]).append("=").append(new ObjectMapper().writeValueAsString(parameterValues[i])).append("]");}}}Object result;try {result = pjp.proceed();} catch (Throwable throwable) {// 请求操纵失败,记录错误日志log.error("切面处理请求错误!" + " 请求控制器类->:【{}】 请求方法->:【{}】 " + " 请求参数->:【{}】", clazzName, methodName, param);throw throwable;}// 请求操作成功String resultString = "";if (result != null) {if (result instanceof ResponseEntity) {resultString = new ObjectMapper().writeValueAsString(((ResponseEntity<?>) result).getBody());} else {resultString = String.valueOf(result);}}// 记录请求完成执行时间long endTime = System.currentTimeMillis();long usedTime = endTime - beginTime;// 记录日志log.info("请求控制器类【{}】 请求方法 ->:【{}】 " + "请求参数【{}】", clazzName, methodName, param);log.info("请求操作成功! 请求耗时:【{}ms】 " + "请求控制器类【{}】 请求方法 ->:【{}】" + "返回值 ->:【{}】", usedTime, clazzName, methodName, resultString);return result;}}
全局异常拦截
GlobalExceptionHandler
@Slf4j
@RestControllerAdvice
public class GlobalExceptionHandler {@ExceptionHandlerpublic ResponseEntity<?> exceptionHandler(Exception exception) {String message = "系统访问异常,请稍后再试:" + e;log.error("data:{},message:{}", null, message, e);return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(ApiResult.of(HttpStatus.INTERNAL_SERVER_ERROR.value(), message, null));}@ExceptionHandlerpublic ResponseEntity<?> businessExceptionHandler(BusinessException exception) {return ResponseEntityUtil.createResponseEntity(exception.getCode(), exception.getMessage(), null, exception, false);}@ExceptionHandlerpublic ApiResult<Object> missingServletRequestPartExceptionHandler(MissingServletRequestPartException exception) {log.warn("multiPartNpeException: file is null", exception);return new ApiResult<>(ApiResult.ResultCode.PARAMETER_ERROR.getCode(), "文件不能为空");}@ExceptionHandlerpublic ApiResult<Object> methodArgumentNotValidExceptionHandler(MethodArgumentNotValidException exception) {log.warn("MethodArgumentNotValidExceptionHandler", exception);FieldError fieldError = exception.getBindingResult().getFieldError();assert fieldError != null;return new ApiResult<>(ApiResult.ResultCode.PARAMETER_ERROR.getCode(), fieldError.getDefaultMessage());}@ExceptionHandlerpublic ResponseEntity<?> illegalArgumentExceptionHandler(IllegalArgumentException exception) {return ResponseEntityUtil.createResponseEntity(ApiResult.ResultCode.PARAMETER_ERROR.getCode(), exception.getMessage(), null, exception, false);}@ExceptionHandlerpublic ApiResult<Object> constraintViolationExceptionHandler(ConstraintViolationException exception) {log.warn("ConstraintViolationException", exception);String message = exception.getConstraintViolations().stream().map(ConstraintViolation::getMessage).collect(Collectors.joining());return new ApiResult<>(ApiResult.ResultCode.PARAMETER_ERROR.getCode(), message);}@ExceptionHandlerpublic ResponseEntity<?> missingServletRequestParameterExceptionHandler(MissingServletRequestParameterException exception) {return ResponseEntityUtil.createResponseEntity(ApiResult.ResultCode.PARAMETER_ERROR.getCode(), ApiResult.ResultCode.PARAMETER_ERROR.getDesc(), null, exception, false);}@ExceptionHandlerpublic ResponseEntity<?> httpMessageNotReadableExceptionHandler(HttpMessageNotReadableException exception) {return ResponseEntityUtil.createResponseEntity(ApiResult.ResultCode.PARAMETER_ERROR.getCode(), ApiResult.ResultCode.PARAMETER_ERROR.getDesc(), null, exception, false);}@ExceptionHandlerpublic ResponseEntity<?> methodArgumentTypeMismatchException(MethodArgumentTypeMismatchException exception) {return ResponseEntityUtil.createResponseEntity(ApiResult.ResultCode.PARAMETER_ERROR.getCode(), ApiResult.ResultCode.PARAMETER_ERROR.getDesc(), null, exception, false);}@ExceptionHandlerpublic ResponseEntity<?> noSuchElementException(NoSuchElementException e) {return ResponseEntityUtil.createResponseEntity(ApiResult.ResultCode.DATA_NOT_EXIST.getCode(), e.getMessage(), null, e, false);}}
ApiResult
@ApiModel
public class ApiResult<T> implements Serializable {private static final long serialVersionUID = -9122598292287970890L;@ApiModelProperty("状态码:与http状态码保持一致,200成功 其他失败")private int code;@ApiModelProperty("返回消息:code不为200时,代表出错信息")private String message;@ApiModelProperty("数据")private T data;@ApiModelProperty("是否成功")private boolean success;public ApiResult() {super();this.setCode(ResultCode.OK.getCode());}public ApiResult(T data) {super();this.setCode(ResultCode.OK.getCode());this.data = data;}public ApiResult(int code, String message) {super();this.setCode(code);this.message = message;}public ApiResult(ResultCode code, String message) {super();this.setCode(code.getCode());this.message = message;}public ApiResult(boolean success, String message) {super();this.setSuccess(success);this.message = message;}public ApiResult(int code, String message, T data) {super();this.setCode(code);this.message = message;this.data = data;}public ApiResult(ResultCode code, String message, T data) {super();this.setCode(code.getCode());this.message = message;this.data = data;}public ApiResult(boolean success, String message, T data) {super();this.setSuccess(success);this.message = message;this.data = data;}public ApiResult(int code, String msg, T data, boolean success) {super();this.setCode(code);this.success = success;this.message = msg;this.data = data;}public static <T> ApiResult<T> of(int code, String msg, T data) {return new ApiResult<>(code, msg, data);}public static <T> ApiResult<T> of(int code, String msg, T data, boolean success) {return new ApiResult<>(code, msg, data, success);}public static <T> ApiResult<T> of(ResultCode code, String msg, T data) {return new ApiResult<>(code, msg, data);}public int getCode() {return code;}public void setCode(int code) {this.code = code;this.setSuccessByInt(code);}public String getMessage() {return message;}public void setMessage(String message) {this.message = message;}public T getData() {return data;}public void setData(T data) {this.data = data;}private void setSuccessByInt(int code) {this.success = code == ResultCode.OK.getCode();}public boolean isSuccess() {return success;}public void setSuccess(boolean success) {this.success = success;if (this.success) {this.code = ResultCode.OK.getCode();} else {// 向下兼容,不成功的时候,如果code是"OK(200)" 或者 0,则将其置值为 "内部错误(500)"的状态if (this.code == ResultCode.OK.getCode() || this.code == 0) {this.code = ResultCode.INTERNAL_SERVER_ERROR.getCode();}}}@Overridepublic String toString() {return JSONUtil.toJsonStr(this);}/*** 接口返回值代码枚举*/@Getter@AllArgsConstructorpublic enum ResultCode {/*** <tt>200 OK</tt> (HTTP/1.0 - RFC 1945)*/OK(200, ""),/*** <tt>400 Bad Request</tt> (HTTP/1.1 - RFC 2616)*/BAD_REQUEST(400, ""),/*** 未授权 用户未登陆或者没传接口授权码 <tt>401 Unauthorized</tt> (HTTP/1.0 - RFC 1945)*/UNAUTHORIZED(401, "请先登录"),/*** 服务器拒绝请求 已经鉴权成功,但是无权调用此接口 <tt>403 Forbidden</tt> (HTTP/1.0 - RFC 1945)*/FORBIDDEN(403, "权限不足"),/*** 请求的资源不存在 <tt>404 Not Found</tt> (HTTP/1.0 - RFC 1945)*/NOT_FOUND(404, ""),/*** 数据冲突 <tt>409 Conflict</tt> (HTTP/1.1 - RFC 2616)*/CONFLICT(409, ""),/*** 请求次数过多 <tt>429 Too Many Requests</tt>*/TOO_MANY_REQUESTS(429, ""),/*** 服务器错误 <tt>500 Server Error</tt> (HTTP/1.0 - RFC 1945)*/INTERNAL_SERVER_ERROR(500, "服务器错误"),/*** 服务不可用 <tt>503 Service Unavailable</tt> (HTTP/1.0 - RFC 1945)*/SERVICE_UNAVAILABLE(503, ""),USERNAME_PASSWORD_ERROR(5001, "用户名或密码错误"),TOKEN_EXPIRED(5002, "token已过期,请重新登录"),TOKEN_PARSE_ERROR(5002, "token解析失败,请尝试重新登录"),USERNAME_NOTFOUND(5005, "未找到用户信息"),PARAMETER_ERROR(10004, "请求参数错误"),DATA_NOT_EXIST(10005, "数据不存在"),;private final Integer code;private final String desc;}}
BusinessException
@Data
@EqualsAndHashCode(callSuper = false)
@AllArgsConstructor
public class BusinessException extends RuntimeException {private static final long serialVersionUID = -7609250728471344151L;/*** 错误码*/private Integer code;/*** 附加消息*/private String message;public BusinessException(ApiResult.ResultCode code) {this.code = code.getCode();this.message = code.getDesc();}}
ResponseEntityUtil
@Slf4j
@UtilityClass
public class ResponseEntityUtil {public <T> ResponseEntity<ApiResult<T>> createResponseEntity(int code, String message, T data, Exception e, boolean success) {message = StringUtils.defaultIfEmpty(message, "系统访问异常,请稍后再试:" + e);log.info("data:{},message:{}", data, message, e);return ResponseEntity.status(HttpStatus.OK).body(ApiResult.of(code, message, data, success));}}
全局返回体包装
@RestControllerAdvice
public class ResponseBodyHandler implements ResponseBodyAdvice<Object> {@Overridepublic boolean supports(MethodParameter returnType, Class converterType) {// 当response为ResponseEntity类型,或注释了NotControllerResponseAdvice的都不调用beforeBodyWrite进行增强return !returnType.getParameterType().isAssignableFrom(ResponseEntity.class);}@Overridepublic Object beforeBodyWrite(Object body, MethodParameter returnType, MediaType selectedContentType, Class selectedConverterType, ServerHttpRequest request, ServerHttpResponse response) {// String类型不能直接包装if (returnType.getGenericParameterType().equals(String.class)) {// 将数据包装到VO后转换为json串返回return JSONUtil.toJsonStr(ApiResult.of(ApiResult.ResultCode.OK, "成功", body));}return ApiResult.of(ApiResult.ResultCode.OK, "成功", body);}}
MP自动填充
@Slf4j
@Component
public class MyMetaObjectHandler implements MetaObjectHandler {/*** 插入元对象字段填充(用于插入时对公共字段的填充)** @param metaObject 元对象*/@Overridepublic void insertFill(MetaObject metaObject) {log.info("---------------------------------------- MP insertFill:{} ----------------------------------------", metaObject.getOriginalObject());}/*** 更新元对象字段填充(用于更新时对公共字段的填充)** @param metaObject 元对象*/@Overridepublic void updateFill(MetaObject metaObject) {log.info("---------------------------------------- MP updateFill:{} ----------------------------------------", metaObject.getOriginalObject());}}
接口文档配置类
需要引入相关依赖,Knife4j或Swagger。
@Configuration
@EnableSwagger2
public class Knife4jConfig {@Beanpublic Docket defaultApi2() {return new Docket(DocumentationType.SWAGGER_2).apiInfo(new ApiInfoBuilder().description("文档描述").version("版本号").build()).select().apis(RequestHandlerSelectors.withClassAnnotation(RequestMapping.class)).paths(PathSelectors.any()).build();}}
自定义Async异步线程池
@Configuration
public class AsyncConfig implements AsyncConfigurer {@Overridepublic Executor getAsyncExecutor() {ThreadPoolTaskExecutor threadPool = new ThreadPoolTaskExecutor();threadPool.setCorePoolSize(4);threadPool.setMaxPoolSize(8);threadPool.setWaitForTasksToCompleteOnShutdown(true);threadPool.setAwaitTerminationSeconds(60 * 10);threadPool.setThreadNamePrefix("MyAsyncTaskExecutor-");threadPool.initialize();return threadPool;}}