【自用】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…...
React Native在HarmonyOS 5.0阅读类应用开发中的实践
一、技术选型背景 随着HarmonyOS 5.0对Web兼容层的增强,React Native作为跨平台框架可通过重新编译ArkTS组件实现85%以上的代码复用率。阅读类应用具有UI复杂度低、数据流清晰的特点。 二、核心实现方案 1. 环境配置 (1)使用React Native…...

el-switch文字内置
el-switch文字内置 效果 vue <div style"color:#ffffff;font-size:14px;float:left;margin-bottom:5px;margin-right:5px;">自动加载</div> <el-switch v-model"value" active-color"#3E99FB" inactive-color"#DCDFE6"…...
【python异步多线程】异步多线程爬虫代码示例
claude生成的python多线程、异步代码示例,模拟20个网页的爬取,每个网页假设要0.5-2秒完成。 代码 Python多线程爬虫教程 核心概念 多线程:允许程序同时执行多个任务,提高IO密集型任务(如网络请求)的效率…...

AI书签管理工具开发全记录(十九):嵌入资源处理
1.前言 📝 在上一篇文章中,我们完成了书签的导入导出功能。本篇文章我们研究如何处理嵌入资源,方便后续将资源打包到一个可执行文件中。 2.embed介绍 🎯 Go 1.16 引入了革命性的 embed 包,彻底改变了静态资源管理的…...
laravel8+vue3.0+element-plus搭建方法
创建 laravel8 项目 composer create-project --prefer-dist laravel/laravel laravel8 8.* 安装 laravel/ui composer require laravel/ui 修改 package.json 文件 "devDependencies": {"vue/compiler-sfc": "^3.0.7","axios": …...

HashMap中的put方法执行流程(流程图)
1 put操作整体流程 HashMap 的 put 操作是其最核心的功能之一。在 JDK 1.8 及以后版本中,其主要逻辑封装在 putVal 这个内部方法中。整个过程大致如下: 初始判断与哈希计算: 首先,putVal 方法会检查当前的 table(也就…...
智能AI电话机器人系统的识别能力现状与发展水平
一、引言 随着人工智能技术的飞速发展,AI电话机器人系统已经从简单的自动应答工具演变为具备复杂交互能力的智能助手。这类系统结合了语音识别、自然语言处理、情感计算和机器学习等多项前沿技术,在客户服务、营销推广、信息查询等领域发挥着越来越重要…...

视觉slam十四讲实践部分记录——ch2、ch3
ch2 一、使用g++编译.cpp为可执行文件并运行(P30) g++ helloSLAM.cpp ./a.out运行 二、使用cmake编译 mkdir build cd build cmake .. makeCMakeCache.txt 文件仍然指向旧的目录。这表明在源代码目录中可能还存在旧的 CMakeCache.txt 文件,或者在构建过程中仍然引用了旧的路…...

2025年渗透测试面试题总结-腾讯[实习]科恩实验室-安全工程师(题目+回答)
安全领域各种资源,学习文档,以及工具分享、前沿信息分享、POC、EXP分享。不定期分享各种好玩的项目及好用的工具,欢迎关注。 目录 腾讯[实习]科恩实验室-安全工程师 一、网络与协议 1. TCP三次握手 2. SYN扫描原理 3. HTTPS证书机制 二…...

RSS 2025|从说明书学习复杂机器人操作任务:NUS邵林团队提出全新机器人装配技能学习框架Manual2Skill
视觉语言模型(Vision-Language Models, VLMs),为真实环境中的机器人操作任务提供了极具潜力的解决方案。 尽管 VLMs 取得了显著进展,机器人仍难以胜任复杂的长时程任务(如家具装配),主要受限于人…...