SpringBoot 2 后端通用开发模板搭建(异常处理,请求响应)
目录
一、环境准备
二、新建项目
三、整合依赖
1、MyBatis Plus 数据库操作
2、Hutool 工具库
3、Knife4j 接口文档
4、其他依赖
四、通用基础代码
1、自定义异常
2、响应包装类
3、全局异常处理器
4、请求包装类
5、全局跨域配置
补充:设置新建类/接口文件的类/接口注释模版
一、环境准备
1) 安装的 JDK 版本可以是 8、11 或 17(一般情况下使用 8 也可以了 ,不过具体情况需要根据使用到的中间件的适配性决定最终使用 JDK 多少的版本,如:若后续要用到缓存库 Caffeine ,则要求使用 11 版本 JDK )
2) MySQL数据库最好安装 8.x版本,或者 5.7/ 5.6 版本。(MySQL 可以是5.X ,数据库连接的 xml 配置可以是8 版本的)
3) Maven 仓库 3.6.X 版本即可;
二、新建项目
在 IDEA 中新建项目,选择 Spring Initializr 模板,考虑到稳定性,此处选择创建 Java8 版本项目注意需要替换 阿里云的链接 ,Server URL为 : Cloud Native App Initializerhttps://start.aliyun.com/因为官方的 Server URL 不支持选择 Java 8.配置如图 :
选择 Spring Boot 2.7.6 版本,可以根据自己的需要添加一些依赖,比如 Spring Web、MyBatis、MySQL、Lombok:
当然,后续通过修改 Maven 配置添加依赖也是可以的。点击创建,就得到了一个 Spring Boot 项目,需要等待 Maven 为我们安装依赖。安装完依赖后,先尝试启动一下项目,结果会报错:
因为我们在 Maven 中引入了 MySQL 依赖,但是项目配置文件中并没有填写 MySQL 的配置。修改资源日录下的配置文件为 application.yml (默认的是 application.properties 且.properties优先级会比.yml后缀的优先级要高,但.yml 的格式会更方便,不用写更多重复的代码,且树形结构更清晰,建议使用 application.yml文件格式 ),指定项目启动的端口号和访问地址前缀、项目名称、数据库配置等。 代码如下 :
server:port: 8123servlet:context-path: /api
spring:application:name: backend# 数据库配置datasource:driver-class-name: com.mysql.cj.jdbc.Driverurl: jdbc:mysql://localhost:3306/ss_pictureusername: rootpassword: 123456
更改之后,发现可以正常运行了:
三、整合依赖
接下来我们要整合一些开发项目常用的依赖。
1、MyBatis Plus 数据库操作
MyBatis Plus 是 MyBatis 增强工具,旨在简化开发流程。它提供了开箱即用的 CRUD 方法、动态查询构造器、分页插件和代码生成器等功能,大幅减少重复代码,同时保持与 MyBatis 原生功能的兼容性。例如,通过调用 baseMapper.selectById(id),可以直接查询数据库中的记录,而无需手动编写 SQL。参考官方文档引入:(教程有时效性,一切以官方文档为主)
https://baomidou.com/getting-started/#spring-boot2
在pom文件中引入:
<dependency><groupId>com.baomidou</groupId><artifactId>mybatis-plus-boot-starter</artifactId><version>3.5.9</version>
</dependency>
注意,添加该依赖后,记得移除 MyBatis 相关的依赖!否则很容易导致版本冲突!!!
在项目中新建 mapper包,)后续用于存放操作数据库的 Mapper类,然后在项目启动类中添加扫描 Mapper 的 @MapperScan 注解 :
@SpringBootApplication
@MapperScan("com.ss.picturebackend.mapper")
public class PictureBackendApplication {public static void main(String[] args) {SpringApplication.run(YuPictureBackendApplication.class, args);}
}
在 application.yml 中追加配置,开启日志和逻辑删除功能 :
mybatis-plus:configuration:map-underscore-to-camel-case: false# 仅在开发环境开启日志log-impl: org.apache.ibatis.logging.stdout.StdOutImplglobal-config:db-config:logic-delete-field: isDelete # 全局逻辑删除的实体字段名logic-delete-value: 1 # 逻辑已删除值(默认为 1)logic-not-delete-value: 0 # 逻辑未删除值(默认为 0)
2、Hutool 工具库
Hutool是主流的 java 工具类库,集合了丰富的工具类,涵盖字符串处理、日期操作、文件处理、加解密、反射、正则匹配等常见功能。它的轻量化和无侵入性让开发者能够专注于业务逻辑而不必编写重复的工具代码。例如, Dateuti1.formatDate(new Date())可以快速将当前日期格式化为字符串。
参考官方文档引入:
https://doc.hutool.cn/pages/index/#%F0%9F%8D%8Amaven
在 Maven 的 pom.xm| 中添加依赖:
<dependency><groupId>cn.hutool</groupId><artifactId>hutool-all</artifactId><version>5.8.26</version>
</dependency>
3、Knife4j 接口文档
Knife4j 是基于 swagger 接口文档的增强工具,提供了更加友好的 AP! 文档界面和功能扩展,例如动态参数调试、分组文档等。它适合用于 Spring Boot 项目中,能够通过简单的配置自动生成接口文档,让开发者和前端快速了解和调试接口,提高写作效率。
参考官方文档引入:
https://doc.xiaominfo.com/docs/quick-start#spring-boot-2
由于使用的是 Spring Boot 2.x,注意要选择 OpenAPI 2 的版本。
在 Maven 的 pom.xml 中添加依赖:
<dependency><groupId>com.github.xiaoymin</groupId><artifactId>knife4j-openapi2-spring-boot-starter</artifactId><version>4.4.0</version>
</dependency>
在 application.ym| 中追加接口文档配置,扫描 Controller 包:
# 接口文档配置
knife4j:enable: trueopenapi:title: "接口文档"version: 1.0group:default:api-rule: packageapi-rule-resources:- com.ss.picturebackend.controller
重启项目,访问 http://localhost:8123/api/doc.html 能够看到接口文档,可以测试调用
4、其他依赖
可以按需引入其他依赖,比如 AOP 切面编程:
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-aop</artifactId>
</dependency>
给启动类添加注解(可选):
@EnableAspectJAutoProxy(exposeProxy = true)
exposeProxy =true的作用: 通过 Spring AOP 提供对当前代理对象的访问,使得可以在业务逻辑中访问到当前的代理对象。你可以在方法执行时通过 AopContext.currentProxy() 获取当前的代理对象。 当然随着业务具体的需求,还有更多的依赖,后续随用随装即可。
四、通用基础代码
通用基础代码是指:无论在任何后端项目中,都可以复用的代码。这种代码一般"只用写一次”,了解作用之后复制粘贴即可,无需记忆。
1、自定义异常
自定义错误码,对错误进行收敛,便于前端统一处理。
这里有 2 个小技巧:
① .自定义错误码时,建议跟主流的错误码 (比如 HTTP 错误码) 的含义保持一致,比如“未登录”定义为 40100,和 HTTP 401 错误 (用户需要进行身份认证) 保持一致,会更容易理解。
② .错误码不要完全连续,预留一些间隔,便于后续扩展。
在 exception 包下新建错误码枚举类
@Getter
public enum ErrorCode {SUCCESS(0, "ok"),PARAMS_ERROR(40000, "请求参数错误"),NOT_LOGIN_ERROR(40100, "未登录"),NO_AUTH_ERROR(40101, "无权限"),NOT_FOUND_ERROR(40400, "请求数据不存在"),FORBIDDEN_ERROR(40300, "禁止访问"),SYSTEM_ERROR(50000, "系统内部异常"),OPERATION_ERROR(50001, "操作失败");/*** 状态码*/private final int code;/*** 信息*/private final String message;ErrorCode(int code, String message) {this.code = code;this.message = message;}}
一般不建议直接抛出 Java 内置的 RuntimeException,而是自定义一个业务异常,和内置的异常类区分开,便于定制化输出错误信息 :
@Getter
public class BusinessException extends RuntimeException {/*** 错误码*/private final int code;public BusinessException(int code, String message) {super(message);this.code = code;}public BusinessException(ErrorCode errorCode) {super(errorCode.getMessage());this.code = errorCode.getCode();}public BusinessException(ErrorCode errorCode, String message) {super(message);this.code = errorCode.getCode();}}
为了更方便地根据情况抛出异常,可以封装一个 ThrowUtils,类似断言类,简化抛异常的代码:
public class ThrowUtils {/*** 条件成立则抛异常** @param condition 条件* @param runtimeException 异常*/public static void throwIf(boolean condition, RuntimeException runtimeException) {if (condition) {throw runtimeException;}}/*** 条件成立则抛异常** @param condition 条件* @param errorCode 错误码*/public static void throwIf(boolean condition, ErrorCode errorCode) {throwIf(condition, new BusinessException(errorCode));}/*** 条件成立则抛异常** @param condition 条件* @param errorCode 错误码* @param message 错误信息*/public static void throwIf(boolean condition, ErrorCode errorCode, String message) {throwIf(condition, new BusinessException(errorCode, message));}
}
2、响应包装类
一般情况下,每个后端接口都要返回调用码、数据、调用信息等,前端可以根据这些信息进行相应的处理我们可以封装统一的响应结果类,便于前端统一获取这些信息,通用响应类:
@Data
public class BaseResponse<T> implements Serializable {private int code;private T data;private String message;public BaseResponse(int code, T data, String message) {this.code = code;this.data = data;this.message = message;}public BaseResponse(int code, T data) {this(code, data, "");}public BaseResponse(ErrorCode errorCode) {this(errorCode.getCode(), null, errorCode.getMessage());}
}
但之后每次接口返回值时,都要手动 new 一个 BaseResponse 对象并传入参数,比较麻烦,我们可以新建一个工具类提供成功调用和失败调用的方法,支持灵活地传参,简化调用。
public class ResultUtils {/*** 成功** @param data 数据* @param <T> 数据类型* @return 响应*/public static <T> BaseResponse<T> success(T data) {return new BaseResponse<>(0, data, "ok");}/*** 失败** @param errorCode 错误码* @return 响应*/public static BaseResponse<?> error(ErrorCode errorCode) {return new BaseResponse<>(errorCode);}/*** 失败** @param code 错误码* @param message 错误信息* @return 响应*/public static BaseResponse<?> error(int code, String message) {return new BaseResponse<>(code, null, message);}/*** 失败** @param errorCode 错误码* @return 响应*/public static BaseResponse<?> error(ErrorCode errorCode, String message) {return new BaseResponse<>(errorCode.getCode(), null, message);}
}
3、全局异常处理器
为了防止意料之外的异常,利用 AOP 切面全局对业务异常和 RuntimeException 进行捕获:
@RestControllerAdvice
@Slf4j
public class GlobalExceptionHandler {@ExceptionHandler(BusinessException.class)public BaseResponse<?> businessExceptionHandler(BusinessException e) {log.error("BusinessException", e);return ResultUtils.error(e.getCode(), e.getMessage());}@ExceptionHandler(RuntimeException.class)public BaseResponse<?> runtimeExceptionHandler(RuntimeException e) {log.error("RuntimeException", e);return ResultUtils.error(ErrorCode.SYSTEM_ERROR, "系统错误");}
}
4、请求包装类
对于“分页”、“删除某条数据”这类通用的请求,可以封装统一的请求包装类,用于接受前端传来的参数,之后相同参数的请求就不用专门再新建一个类了。
分页请求包装类,接受页号、页面大小、排序字段、排序顺序参数:
@Data
public class PageRequest {/*** 当前页号*/private int current = 1;/*** 页面大小*/private int pageSize = 10;/*** 排序字段*/private String sortField;/*** 排序顺序(默认降序)*/private String sortOrder = "descend";
}
删除请求包装类,接受要删除数据的id 作为参数
@Data
public class DeleteRequest implements Serializable {/*** id*/private Long id;private static final long serialVersionUID = 1L;
}
5、全局跨域配置
跨域是指浏览器访问的 URL(前端地址)和后端接口地址的域名(或端口号)不一致导致的,浏览器为了安全,默认禁上跨域请求访问 。
为了开发调试方便,我们可以通过全局跨域配置,让整个项目所有的接口支持跨域,解决跨域报错。新建 config 包,用于存放所有的配置相关代码。全局跨域配置代码如下 :
@Configuration
public class CorsConfig implements WebMvcConfigurer {@Overridepublic void addCorsMappings(CorsRegistry registry) {// 覆盖所有请求registry.addMapping("/**")// 允许发送 Cookie.allowCredentials(true)// 放行哪些域名(必须用 patterns,否则 * 会和 allowCredentials 冲突).allowedOriginPatterns("*").allowedMethods("GET", "POST", "PUT", "DELETE", "OPTIONS").allowedHeaders("*").exposedHeaders("*");}
}
编写示例接口,移除 controller 包下的其他代码,让项目干净一些,然后编写一个纯净的 /health 接口用于健康检查:
@RestController
@RequestMapping("/")
public class MainController {/*** 健康检查*/@GetMapping("/health")public BaseResponse<String> health() {return ResultUtils.success("ok");}
}
访问 http://localhost:8123/api/health,看到输出结果,表示后端初始化完成:
补充:设置新建类/接口文件的类/接口注释模版
在设置中输入“File and Code Templates” 或者 “文件和代码模板” 可增加自定义注释
参考:SpringBoot IDEA 开发必备使用小技巧
相关文章:

SpringBoot 2 后端通用开发模板搭建(异常处理,请求响应)
目录 一、环境准备 二、新建项目 三、整合依赖 1、MyBatis Plus 数据库操作 2、Hutool 工具库 3、Knife4j 接口文档 4、其他依赖 四、通用基础代码 1、自定义异常 2、响应包装类 3、全局异常处理器 4、请求包装类 5、全局跨域配置 补充:设置新建类/接…...

【Oracle专栏】sqlplus显示设置+脚本常用显示命令
Oracle相关文档,希望互相学习,共同进步 风123456789~-CSDN博客 1.内容概述 本文主要针对oracle 运维中常用知识点进行整理,包括: 1)sqlplus模式下,为了方便查询设置相应的行宽、列宽、行数。…...

DeepSeek 助力 Vue3 开发:打造丝滑的页眉(Header)
前言:哈喽,大家好,今天给大家分享一篇文章!并提供具体代码帮助大家深入理解,彻底掌握!创作不易,如果能帮助到大家或者给大家一些灵感和启发,欢迎收藏关注哦 💕 目录 Deep…...

JVM线程分析详解
java线程状态: 初始(NEW):新创建了一个线程对象,但还没有调用start()方法。运行(RUNNABLE):Java线程中将就绪(ready)和运行中(running)两种状态笼统的称为“运行”。 线程对象创建…...

【备赛】点亮LED
LED部分的原理图 led前面有锁存器,这是为了防止led会受到lcd的干扰(lcd也需要用到这些引脚)。 每次想要对led操作,就需要先打开锁存器,再执行操作,最后关闭锁存器。 这里需要注意的是,引脚配置…...
【音视频】编解码相关概念总结
NALU RTP PS流 三者总体关系 NALU在RTP中的应用:视频流的RTP传输通常将NALU作为基本的单元进行传输。每个RTP包携带一个或多个NALU,这些NALU包含了视频编码数据。RTP协议通过其头部信息(如时间戳、序列号等)帮助接收端重新排列和…...

Python爬虫(四)- Selenium 安装与使用教程
文章目录 前言一、简介及安装1. Selenium 简介2. Selenium 安装 二、Selenium 基本使用1. 导入Selenium2. 启动浏览器3. 打开网页4. 获取页面标题5. 关闭浏览器6. 完整示例代码 三、Selenium WebDriver1. 简介2. 基本操作2.1 启动浏览器2.2 关闭浏览器2.3 打开网页2.4 关闭当前…...

Node.js项目启动流程以及各个模块执行顺序详解
Node.js项目启动流程以及各个模块执行顺序的问题。首先,我需要仔细阅读并理解我搜索到的资料,从中提取关键信息,然后综合这些信息组织成一个结构化的回答。 首先,根据我搜索到的资料都详细描述了Node.js的启动流程,涉及…...

各种类型网络安全竞赛有哪些 网络安全大赛的简称
本文是对入门学习的一些概念了解和一些常规场景记录 1.CTF(capture the flag)是夺旗赛的意思。 是网络安全技术人员之间进行攻防的比赛。 起源1996年DEFCON全球黑客大会,替代之前真实攻击的技术比拼。 (DEFCON极客大会诞生1993,…...
浅谈人工智能与深度学习的应用案例研究
人工智能与深度学习的应用案例研究 人工智能(AI)与深度学习技术正以惊人的速度渗透到社会生活的各个领域,从医疗健康到艺术创作,从金融风控到城市治理,其应用案例不断突破传统边界。以下是近年来具有代表性的六大应用方向及具体案例: 一、医疗健康:精准诊断与药物研发 医…...

vue2版本elementUI的table分页实现多选逻辑
1. 需求 我们需要在表格页上实现多选要求,该表格支持分页逻辑。 2. 认识属性 表格属性 参数说明类型可选值默认值data显示的数据array——row-key行数据的 Key,用来优化 Table 的渲染;在使用 reserve-selection 功能与显示树形数据时&…...

AI数字人技术源码开发分享:革新短视频营销策略
集星幻影的AI数字人分身系统是一款融合了先进人工智能技术的综合性短视频营销解决方案。该系统整合了形象克隆、声音克隆、AI数字人分身生成、智能剪辑及文案创作等功能,旨在为用户打造虚拟人物资产并提供AI驱动的多模态交互服务。以下是该系统的主要功能概述&#…...

实验环境搭建集锦(docker linux ros2+强化学习环境+linux上单片机串口调试)
为了记住一些实验环境配置开的文章,边配置边记,免得之后忘了。 Docker环境搭建 yay -S docker //下载docker docker info //查看docker配置 sudo systemctl start docker //系统配置打开docker sudo systemctl enable docker //系统配置后台开启d…...
sql调优之数据库开发规范
数据库 数据库开发规范 也可用于PostgreSQL以及兼容PG的数据库 通用命名规则 【强制】 本规则适用于所有对象名,包括:库名、表名、列名、函数名、视图名、序列号名、别名等。 【强制】 对象名务必只使用小写字母,下划线,数字&…...

《Effective Objective-C》阅读笔记(上)
目录 高质量iOS之熟悉OC 了解OC语言的起源 在类的头文件中尽量少引入其他头文件 多用字面语法,少用与之等价的方法 字面数值 字面量数组 字面量字典 局限性 多用类型常量,少用#define预处理指令 用枚举表示状态、选项、状态码 高质量iOS之对象…...

ClkLog里程碑:荣获2024上海开源技术应用创新竞赛三等奖
2024年10月,ClkLog团队参加了由上海计算机软件技术开发中心、上海开源信息技术协会联合承办的2024上海数智融合“智慧工匠”选树、“领军先锋”评选活动——开源技术应用创新竞赛。我们不仅成功晋级决赛,还荣获了三等奖!这一成就不仅是对ClkL…...

【数据结构进阶】哈希表
🌟🌟作者主页:ephemerals__ 🌟🌟所属专栏:数据结构 目录 前言 一、哈希表的概念 二、哈希函数的实现方法 1. 直接定址法 2. 除留余数法 三、哈希冲突 1. 开放定址法(闭散列࿰…...

STM32内存五区及堆栈空间大小设置(启动文件浅析)
前言 嘿,朋友们!今天咱们来聊聊STM32的内存五区和堆栈空间大小设置。这可是嵌入式开发里的“必修课”,要是没整明白,程序说不定就“翻车”了。别担心,我这就带你一步步搞懂这事儿,让你轻松上手,…...

微信小程序调用火山方舟(字节跳动火山引擎)中的DeepSeek大模型
微信小程序的轻量化特性与DeepSeek大模型的AI能力结合,可快速构建智能问答、内容生成等场景化服务。通过火山方舟平台提供的标准化接口,开发者无需深入算法细节即可调用模型能力。 一、注册火山引擎账号,创建API Key和model(接入…...

(八)Java-Collection
一、Collection接口 1.特点 Collection实现子类可以存放多个元素,每个元素可以是Object; 有些Collection的实现类,可以存放重复的元素,有些不可以; 有些Collection的实现类,有些是有序的(Li…...

XML Group端口详解
在XML数据映射过程中,经常需要对数据进行分组聚合操作。例如,当处理包含多个物料明细的XML文件时,可能需要将相同物料号的明细归为一组,或对相同物料号的数量进行求和计算。传统实现方式通常需要编写脚本代码,增加了开…...

第19节 Node.js Express 框架
Express 是一个为Node.js设计的web开发框架,它基于nodejs平台。 Express 简介 Express是一个简洁而灵活的node.js Web应用框架, 提供了一系列强大特性帮助你创建各种Web应用,和丰富的HTTP工具。 使用Express可以快速地搭建一个完整功能的网站。 Expre…...

idea大量爆红问题解决
问题描述 在学习和工作中,idea是程序员不可缺少的一个工具,但是突然在有些时候就会出现大量爆红的问题,发现无法跳转,无论是关机重启或者是替换root都无法解决 就是如上所展示的问题,但是程序依然可以启动。 问题解决…...
vscode里如何用git
打开vs终端执行如下: 1 初始化 Git 仓库(如果尚未初始化) git init 2 添加文件到 Git 仓库 git add . 3 使用 git commit 命令来提交你的更改。确保在提交时加上一个有用的消息。 git commit -m "备注信息" 4 …...

iOS 26 携众系统重磅更新,但“苹果智能”仍与国行无缘
美国西海岸的夏天,再次被苹果点燃。一年一度的全球开发者大会 WWDC25 如期而至,这不仅是开发者的盛宴,更是全球数亿苹果用户翘首以盼的科技春晚。今年,苹果依旧为我们带来了全家桶式的系统更新,包括 iOS 26、iPadOS 26…...

【人工智能】神经网络的优化器optimizer(二):Adagrad自适应学习率优化器
一.自适应梯度算法Adagrad概述 Adagrad(Adaptive Gradient Algorithm)是一种自适应学习率的优化算法,由Duchi等人在2011年提出。其核心思想是针对不同参数自动调整学习率,适合处理稀疏数据和不同参数梯度差异较大的场景。Adagrad通…...

相机Camera日志实例分析之二:相机Camx【专业模式开启直方图拍照】单帧流程日志详解
【关注我,后续持续新增专题博文,谢谢!!!】 上一篇我们讲了: 这一篇我们开始讲: 目录 一、场景操作步骤 二、日志基础关键字分级如下 三、场景日志如下: 一、场景操作步骤 操作步…...
Objective-C常用命名规范总结
【OC】常用命名规范总结 文章目录 【OC】常用命名规范总结1.类名(Class Name)2.协议名(Protocol Name)3.方法名(Method Name)4.属性名(Property Name)5.局部变量/实例变量(Local / Instance Variables&…...

华为OD机试-食堂供餐-二分法
import java.util.Arrays; import java.util.Scanner;public class DemoTest3 {public static void main(String[] args) {Scanner in new Scanner(System.in);// 注意 hasNext 和 hasNextLine 的区别while (in.hasNextLine()) { // 注意 while 处理多个 caseint a in.nextIn…...

从零实现STL哈希容器:unordered_map/unordered_set封装详解
本篇文章是对C学习的STL哈希容器自主实现部分的学习分享 希望也能为你带来些帮助~ 那咱们废话不多说,直接开始吧! 一、源码结构分析 1. SGISTL30实现剖析 // hash_set核心结构 template <class Value, class HashFcn, ...> class hash_set {ty…...