【自用】SpringBoot项目通用类整理
文章目录
- 全局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;}}
相关文章:
【自用】SpringBoot项目通用类整理
文章目录全局Json序列化Controller日志切面全局异常拦截GlobalExceptionHandlerApiResultBusinessExceptionResponseEntityUtil全局返回体包装MP自动填充接口文档配置类自定义Async异步线程池本文主要整理各类项目中通用的配置类、工具类,便于复查自用。 全局Json序…...
动态规划法(总述)多阶段决策最优化问题
动态规划: 研究最优控制问题提出的 该问题有n个输入,问题的解由这n个输入组成,这个子集必须满足事先给定的条件,这些条件称为约束条件,满足约束条件的可行解可能不只有一个为了衡量可行解的优劣,通常以一些函数的形式&…...
MySQL跨服务器数据映射
MySQL跨服务器数据映射环境准备1. 首先是要查看数据库的federated引擎 开启/关闭 状态2. 打开任务管理器,并重启mysql服务3. 再次查看FEDERATED引擎状态,引擎已启动映射实现问题总结在日常的开发中经常进行跨数据库进行查询数据。 同服务器下跨数据库进…...
利用反射实现通过读取配置文件对类进行实例化-课后程序(JAVA基础案例教程-黑马程序员编著-第十二章-课后作业)
【案例12-3】:利用反射实现通过读取配置文件对类进行实例化 【案例介绍】 1.案例描述 现在有一个项目,项目中创建了一个Person类,在Person类中定义了一个sleep()方法。在工程中还定义了一个Student类继承Person类,在Student类中…...
1.2 CSS文本属性
CSS Text(文本)属性: 定义文本外观,颜色,装饰,缩进,行间距来修饰文本 文本样式 文本缩进 text-indent文本水平对齐方式:text-align文本修饰:text-decoration行高 line-height CSS文本颜色属性…...
SpringCloud之认识微服务
文章目录一、传统项目转型二、走进 SpringCloud三、微服务项目搭建3.1 创建一个 SpringBoot 项目3.2 创建三个 Maven 子工程3.3 为子工程创建 application.yml3.4 引入依赖3.5 数据库 建库建表3.6 编写业务提示:以下是本篇文章正文内容,SpringCloud系列学…...
【go语言之thrift协议二之server端分析】
go语言之thrift协议二serverthrift.TProtocolFactoryTTransportReadWriteCloserContextFlusherReadSizeProviderTProtocolrunServerNewTServerSocketNewCalculatorHandlerNewCalculatorProcessorNewTSimpleServer4server.ServeListenAcceptLoopprocessRequests在上一篇文章分析…...
【办公类05-03】Python批量修改文件名前面的序号(已有的序号错了,需要改成正确的号码)
背景需求下载教程,手动输入编号,有一个编号错误,导致后面所有编号都错了。30实际是29,以此类推怎样才能快速修改编号数字?前期考虑到可能要改编号,所以在每个编号后面加“ ”(空格)&…...
定向模糊测试工具Beacon基本用法
Beacon是一个定向模糊测试工具,给定行号,能够定向探索行号附近的代码区域。主要思想是采用静态分析的方法获取到与目标有关的变量的最弱前置条件(weakest precondition)的信息,并在相关位置插入断言,来提前…...
《程序员面试金典(第6版)》面试题 02.01. 移除重复节点
题目描述 编写代码,移除未排序链表中的重复节点。保留最开始出现的节点。 示例1: 输入:[1, 2, 3, 3, 2, 1] 输出:[1, 2, 3] -示例2: 输入:[1, 1, 1, 1, 2] 输出:[1, 2] 提示: 链表长度在[0, 20000]范…...
如何对web系统开展无障碍测试
Accessibility test(无障碍测试)是一种测试方法,旨在评估软件、网站或其他数字产品的可访问性,以确保它们能够被身体残障或其他特殊需求的用户使用。这些测试通常包括使用辅助技术,如屏幕阅读器和放大器,以…...
使用vite+vue3.0 创建一个cesium基础应用 ----01 项目搭建
使用vitevue3.0 创建一个cesium基础应用 ----01 项目搭建 1.使用yarn创建一个vite项目 我们可以在vite官网找到vite创建项目的命令 https://cn.vitejs.dev/ 可以使用yarn创建项目选择使用vue3.0框架,语言使用js 创建完成后结构如下: 2.找到vite社区中的…...
【Python学习笔记】第二十七节 Python 多线程
一、进程和线程进程:是程序的一次执行,每个进程都有自己的地址空间、内存、数据栈及其他记录运行轨迹的辅助数据。线程:所有的线程都运行在同一个进程当中,共享相同的运行环境。线程有开始、顺序执行和结束三个部分, …...
【id:18】【20分】B. DS顺序表--连续操作
题目描述建立顺序表的类,属性包括:数组、实际长度、最大长度(设定为1000)该类具有以下成员函数:构造函数:实现顺序表的初始化。插入多个数据的multiinsert(int i, int n, int item[])函数,实现在…...
vi编辑器操作指令分享
vi编辑器是所有Unix及Linux系统下标准的编辑器,它的强大不逊色于任何最新的文本编辑器,这里只是简单地介绍一下它的用法和一小部分指令。由于对Unix及Linux系统的任何版本,vi编辑器是完全相同的,因此您可以在其他任何介绍vi的地方…...
OSPF与BFD联动配置
13.1.1BFD概念 BFD提供了一个通用的、标准化的、介质无关的、协议无关的快速故障检测机制,有以下两大优点: 对相邻转发引擎之间的通道提供轻负荷、快速故障检测。 用单一的机制对任何介质、任何协议层进行实时检测。 BFD是一个简单的“Hello”协议。两个系统之间建立BFD会…...
jQuery基础
> 🥲 🥸 🤌 🫀 🫁 🥷 🐻❄️🦤 🪶 🦭 🪲 🪳 🪰 🪱 🪴 🫐 🫒 …...
day39|139.单词拆分 背包问题ending
139.单词拆分 给你一个字符串 s 和一个字符串列表 wordDict 作为字典。请你判断是否可以利用字典中出现的单词拼接出 s 。 注意:不要求字典中出现的单词全部都使用,并且字典中的单词可以重复使用。 示例 1: 输入: s "leetcode",…...
Shell脚本编程
Shell编程 视频地址https://www.bilibili.com/video/BV1hW41167NW/?p1&vd_source977d52a6b92ce8b6ae67c16fc61f0428 第一章 Shell概述 大数据程序员为什么要学习Shell呢? 需要看懂运维人员编写的Shell程序偶尔会编写一些简单的Shell程序来管理集群…...
ChatGPT解答:JavaScript保存当前网页页面图片为pdf文件或者word文件,前端用vue2,给出详细的方案和代码
ChatGPT解答:JavaScript保存当前网页页面图片为pdf文件或者word文件,前端用vue2,给出详细的方案和代码 ChatGPTDemo Based on OpenAI API (gpt-3.5-turbo). JavaScript保存当前网页页面图片为pdf文件或者word文件,前端用vue2&am…...
观成科技:隐蔽隧道工具Ligolo-ng加密流量分析
1.工具介绍 Ligolo-ng是一款由go编写的高效隧道工具,该工具基于TUN接口实现其功能,利用反向TCP/TLS连接建立一条隐蔽的通信信道,支持使用Let’s Encrypt自动生成证书。Ligolo-ng的通信隐蔽性体现在其支持多种连接方式,适应复杂网…...
Qwen3-Embedding-0.6B深度解析:多语言语义检索的轻量级利器
第一章 引言:语义表示的新时代挑战与Qwen3的破局之路 1.1 文本嵌入的核心价值与技术演进 在人工智能领域,文本嵌入技术如同连接自然语言与机器理解的“神经突触”——它将人类语言转化为计算机可计算的语义向量,支撑着搜索引擎、推荐系统、…...
Mac软件卸载指南,简单易懂!
刚和Adobe分手,它却总在Library里给你写"回忆录"?卸载的Final Cut Pro像电子幽灵般阴魂不散?总是会有残留文件,别慌!这份Mac软件卸载指南,将用最硬核的方式教你"数字分手术"࿰…...
在鸿蒙HarmonyOS 5中使用DevEco Studio实现录音机应用
1. 项目配置与权限设置 1.1 配置module.json5 {"module": {"requestPermissions": [{"name": "ohos.permission.MICROPHONE","reason": "录音需要麦克风权限"},{"name": "ohos.permission.WRITE…...
Maven 概述、安装、配置、仓库、私服详解
目录 1、Maven 概述 1.1 Maven 的定义 1.2 Maven 解决的问题 1.3 Maven 的核心特性与优势 2、Maven 安装 2.1 下载 Maven 2.2 安装配置 Maven 2.3 测试安装 2.4 修改 Maven 本地仓库的默认路径 3、Maven 配置 3.1 配置本地仓库 3.2 配置 JDK 3.3 IDEA 配置本地 Ma…...
安卓基础(aar)
重新设置java21的环境,临时设置 $env:JAVA_HOME "D:\Android Studio\jbr" 查看当前环境变量 JAVA_HOME 的值 echo $env:JAVA_HOME 构建ARR文件 ./gradlew :private-lib:assembleRelease 目录是这样的: MyApp/ ├── app/ …...
逻辑回归暴力训练预测金融欺诈
简述 「使用逻辑回归暴力预测金融欺诈,并不断增加特征维度持续测试」的做法,体现了一种逐步建模与迭代验证的实验思路,在金融欺诈检测中非常有价值,本文作为一篇回顾性记录了早年间公司给某行做反欺诈预测用到的技术和思路。百度…...
实战设计模式之模板方法模式
概述 模板方法模式定义了一个操作中的算法骨架,并将某些步骤延迟到子类中实现。模板方法使得子类可以在不改变算法结构的前提下,重新定义算法中的某些步骤。简单来说,就是在一个方法中定义了要执行的步骤顺序或算法框架,但允许子类…...
加密通信 + 行为分析:运营商行业安全防御体系重构
在数字经济蓬勃发展的时代,运营商作为信息通信网络的核心枢纽,承载着海量用户数据与关键业务传输,其安全防御体系的可靠性直接关乎国家安全、社会稳定与企业发展。随着网络攻击手段的不断升级,传统安全防护体系逐渐暴露出局限性&a…...
归并排序:分治思想的高效排序
目录 基本原理 流程图解 实现方法 递归实现 非递归实现 演示过程 时间复杂度 基本原理 归并排序(Merge Sort)是一种基于分治思想的排序算法,由约翰冯诺伊曼在1945年提出。其核心思想包括: 分割(Divide):将待排序数组递归地分成两个子…...
