【自用】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第五十七节 Router中RouterProvider使用详解及注意事项
前言 在 React Router v6.4 中,RouterProvider 是一个核心组件,用于提供基于数据路由(data routers)的新型路由方案。 它替代了传统的 <BrowserRouter>,支持更强大的数据加载和操作功能(如 loader 和…...
Qt Widget类解析与代码注释
#include "widget.h" #include "ui_widget.h"Widget::Widget(QWidget *parent): QWidget(parent), ui(new Ui::Widget) {ui->setupUi(this); }Widget::~Widget() {delete ui; }//解释这串代码,写上注释 当然可以!这段代码是 Qt …...
鸿蒙中用HarmonyOS SDK应用服务 HarmonyOS5开发一个医院查看报告小程序
一、开发环境准备 工具安装: 下载安装DevEco Studio 4.0(支持HarmonyOS 5)配置HarmonyOS SDK 5.0确保Node.js版本≥14 项目初始化: ohpm init harmony/hospital-report-app 二、核心功能模块实现 1. 报告列表…...
Spring Boot面试题精选汇总
🤟致敬读者 🟩感谢阅读🟦笑口常开🟪生日快乐⬛早点睡觉 📘博主相关 🟧博主信息🟨博客首页🟫专栏推荐🟥活动信息 文章目录 Spring Boot面试题精选汇总⚙️ **一、核心概…...
Rust 异步编程
Rust 异步编程 引言 Rust 是一种系统编程语言,以其高性能、安全性以及零成本抽象而著称。在多核处理器成为主流的今天,异步编程成为了一种提高应用性能、优化资源利用的有效手段。本文将深入探讨 Rust 异步编程的核心概念、常用库以及最佳实践。 异步编程基础 什么是异步…...
网络编程(UDP编程)
思维导图 UDP基础编程(单播) 1.流程图 服务器:短信的接收方 创建套接字 (socket)-----------------------------------------》有手机指定网络信息-----------------------------------------------》有号码绑定套接字 (bind)--------------…...
C#学习第29天:表达式树(Expression Trees)
目录 什么是表达式树? 核心概念 1.表达式树的构建 2. 表达式树与Lambda表达式 3.解析和访问表达式树 4.动态条件查询 表达式树的优势 1.动态构建查询 2.LINQ 提供程序支持: 3.性能优化 4.元数据处理 5.代码转换和重写 适用场景 代码复杂性…...
android RelativeLayout布局
<?xml version"1.0" encoding"utf-8"?> <RelativeLayout xmlns:android"http://schemas.android.com/apk/res/android"android:layout_width"match_parent"android:layout_height"match_parent"android:gravity&…...
LangFlow技术架构分析
🔧 LangFlow 的可视化技术栈 前端节点编辑器 底层框架:基于 (一个现代化的 React 节点绘图库) 功能: 拖拽式构建 LangGraph 状态机 实时连线定义节点依赖关系 可视化调试循环和分支逻辑 与 LangGraph 的深…...
React父子组件通信:Props怎么用?如何从父组件向子组件传递数据?
系列回顾: 在上一篇《React核心概念:State是什么?》中,我们学习了如何使用useState让一个组件拥有自己的内部数据(State),并通过一个计数器案例,实现了组件的自我更新。这很棒&#…...
