SpringBoot 项目初始模板
SpringBoot 项目初始模板
基于 Java SpringBoot 的项目初始模板,整合了常用框架和主流业务的示例代,进而可以在此基础上快速开发自己的项目,避免重复造轮子
参考springboot-init项目
[toc]
模板特点
主流框架 & 特性
- Spring Boot 2.7.x(贼新)
- Spring MVC
- MyBatis + MyBatis Plus 数据访问(开启分页)
- Spring Boot 调试工具和项目处理器
- Spring AOP 切面编程
- Spring Scheduler 定时任务
- Spring 事务注解
数据存储
- MySQL 数据库
- Redis 内存数据库
- Elasticsearch 搜索引擎
- 腾讯云 COS 对象存储
工具类
- Easy Excel 表格处理
- Hutool 工具库
- Apache Commons Lang3 工具类
- Lombok 注解
业务特性
- Spring Session Redis 分布式登录
- 全局请求响应拦截器(记录日志)
- 全局异常处理器
- 自定义错误码
- 封装通用响应类
- Swagger + Knife4j 接口文档
- 自定义权限注解 + 全局校验
- 全局跨域处理
- 长整数丢失精度解决
- 多环境配置
业务功能
- 提供示例 SQL(用户、帖子、帖子点赞、帖子收藏表)
- 用户登录、注册、注销、更新、检索、权限管理
- 帖子创建、删除、编辑、更新、数据库检索、ES 灵活检索
- 帖子点赞、取消点赞
- 帖子收藏、取消收藏、检索已收藏帖子
- 帖子全量同步 ES、增量同步 ES 定时任务
- 支持微信开放平台登录
- 支持微信公众号订阅、收发消息、设置菜单
- 支持分业务的文件上传
单元测试
- JUnit5 单元测试
- 示例单元测试类
架构设计
- 合理分层
快速上手
项目引入
IDEA中导入项目:File->New Project from Existing Sources,选择对应项目文件所在位置构建maven项目,随后配置JDK环境以及maven配置(如果pom.xml文件飘红则相应检查maven配置是否正常加载,重新刷新等待下载,如果还是出现同样的问题则考虑项目引用组件兼容问题,在maven仓库中排查)
对于每个功能项可以进行架构梳理,理解其流程和配置以及开发技巧等内容,虽然开发模板提供了一些基础业务的配置和应用,但是具体实践过程中技术栈的结合使用还是需要参考具体的环境配置和应用,只有了解框架的核心和操作流程再结合业务场景应用才会更加得心应手,而不是仅仅局限于业务逻辑的CRUD。这个项目侧重于开发应用,具体每个功能如何实现和相应的逻辑还是需要额外进行梳理
1.模块说明
框架说明
框架说明
# com.noob.springbootinit包配置说明
annotation # 自定义注解
aop # 请求日志和权限校验
common # 通用类(常用通用类)
config # 配置类
constant # 常量类
controller # 控制层
esdao # es操作类
exception # 异常处理
job # 定时任务、增量备份
manager # 管理类:AI模型、GuaVa限流器
mapper # mapper层:用于封装复杂sql(数据库交互)
model # 实体类:可包含DTO\VO\Domain等
service # service层:用于封装业务逻辑,接口和实现类,用于注入
utils # 工具类
wxmp # 微信工具类
MainApplication.java # Springboot启动类
# resources 相关配置说明
mapper # mapper对应xml文件
META-INF # 该文件夹为Springboot自动配置
application.yml/application-xxx.yml # 对应环境配置:其中application.yml为开发环境配置,通过后缀区分prod生产环境、test测试环境等
banner.txt # Springboot项目启动展示banner.txt中设置的内容
重点模块讲解
【1】全局项目配置
application.yml
主要配置mysql数据库、redis等相关配置,如果需要切入微信平台等也需相应配置
mysql数据库配置:修改用户名密码、访问数据库名
redis数据库:放开redis数据库配置、解除Springboot启动类中exclude注解忽略的内容(RedisAutoConfiguration.class)
MainApplication:项目启动入口
@SpringBootApplication:一个复合注解,用于标记一个Spring Boot应用程序的主类。它包括了@Configuration、@EnableAutoConfiguration、@ComponentScan等注解,用于自动配置Spring应用程序上下文和启动自动配置的功能。
@MapperScan("com.noob springbootinit mapper"):这是MyBatis框架的注解,用于扫描指定包下的Mapper接口,将其注册为Spring的Bean,并提供给MyBatis进行数据库访问操作。
@EnableScheduling: 这个注解启用了Spring的定时任务调度功能。使用该注解后,你可以定义定时任务的方法,并通过表达式或固定时间间隔来调度任务的执行。
@EnableAspectJAutoProxy(proxy TargetClass = true, exposeProxy= true): 这个注解启用了Spring的AOP (面向切面编程)功能。proxyTargetClass = true表示使用CGLIB代理来创建代理对象,exposeProxy = true表示将代理对象暴露给AOP代理链中的其他切面。
【2】全局请求、鉴权拦截器
对应aop文件夹中的AuthInterceptor.java、LogInterceptor.java,此处涉及了Spring的AOP概念
AuthInterceptor:权限校验机制
主要用于校验用户角色(一般情况下可以为管理员、用户、ban封号三种情况),结合@AuthCheck注解使用设定只有满足特定角色的人才能访问该方法。
功能流程说明:
【1】声明了一个AuthInterceptor类,并使用@Aspect注解将其声明为切面类,使用@Component注解将其声明为Spring组件。
【2】在AuthInterceptor类中,使用@Resource注解注入了一个UserService对象。
【3】实现了一个doInterceptor方法,使用@Around注解定义拦截器的切入点,即拦截使用了@AuthCheck注解的方法。该方法的参数是一个ProceedingJoinPoint对象, 包含了被拦截方法的信息和一个AuthCheck注解对象,包含了必须的角色信息,返回值为被拦截方法的执行结果,可能会抛出异常。
【4】在doInterceptor方法中,首先获取必须的角色信息和当前请求的HttpServletRequest对象。然后获取当前登录用户的信息,并根据必须的角色信息进行权限校验。如果必须的角色信息不合法,或者当前用户不满足必须的角色要求,就会抛出权限异常。否则,将会放行,执行被拦截的方法,并返回执行结果。
像创建用户这个方法就是只有管理员能够使用,用@AuthCheck自定义注解,然后写上使用该方法要有的权限即可。权限校验器因为是@Around环绕通知并且表明在有authCheck注解的方法周围执行如下逻辑。@Around环绕通知在也就是在方法执行前后额外添加的逻辑。(具体可以了解Spring的AOP机制)
通过在主入口类中添加@EnableAspectJAutoProxy注解启用Spring的AOP功能,使得拦截器可以被识别并应用到目标方法
借助自定义注解@AuthCheck对方法进行标注,用于标记需要进行权限校验的方法。该注解只能用于方法上,并在运行时保留。该注解包含一个名为mustRole的属性,表示必须的角色信息,默认为空字符串。其中@Target(ElementType.METHOD)表示这个注解只能应用到方法上。@Retention(RetentionPolicy RUNTIME)表示这个注解在程序运行时仍然有效。
LogInterceptor:请求日志拦截器
请求日志拦截器,用于输出请求日志。通过这个日志拦截器可以在控制台或者日志文件中看到每个请求的请求路径、请求参数、执行时间等信息,以便于日常开发中进行问题排查和性能优化
@Around是环绕通知,用了切入点表达式,要拦截哪个包或者哪些包下面的哪个方法或者是全部方法。这段切入点表达式的功能就是对com.noob.springbootinit.controller中所有方法进行拦截。也就是说控制层执行方法就会打印日志进行输出,有利用异常信息的捕获和后端调试debug。
其功能流程梳理如下:
【1】声明了一个LogInterceptor类,并使用@Aspect注解将其声明为切面类,使用@Component注解将其声明为Spring组件,使用@SIf4j注解使用L ombok的日志功能。
【2】实现了一个doInterceptor方法,使用@Around注解定义拦截器的切入点,即拦截指定包下的所有方法。该方法的参数是一个ProceedingJoinPoint对象,包含了被拦截方法的信息,返回值为被拦截方法的执行结果,可能会抛出异常。 【3】在doInterceptor方法中,首先创建了一个StopWatch对象, 用于计时。然后获取当前请求的HttpServletRequest对象,性成一个唯一的请求标识符。 接着获取被拦截方法的参数,将其转换为字符串,并输出请求日志。 【4】执行被拦截的方法,并记录执行时间。最后输出响应日志,并返回被拦截方法的执行结果。
【3】通用响应类
common包下的BaseResponse、ResultUtils、ErrorCode,三者结合构建了响应数据封装,可以给业务场景使用
BaseResponse:通用返回类,其中code为响应状态码、data存放返回的数据、message定义成功或者失败的额外信息
ResultUtils:主要用于简化BaseResponse的封装操作,将一些通用的方法(例如响应成功、响应失败)进行静态方法封装,业务处理可以直接调用传入参数进而得到处理后的响应数据。
比如调用success方法,响应状态码就是0,然后会将data封装到BaseResponse的data属性,message为"ok"。如果前端想要响应状态吗为200,那么将这里的0改成200就可以,这边的message为固定消息"ok"。
可以再设置一个静态方法,进行方法重构,success形参为(T data,String message),然后可以动态定义成功的时候的返回消息。
Errorcode:ErrorCode配合ResultUtils使用,可以定义枚举类将常规的响应状态码和响应信息进行封装。
比如:无权限访问(40300)、服务器内部异常(50000)等常见状态
还可以通过添加自定义的一些专属项目的响应状态码,例如: API项目接口调用失败可以是INTERFACE _ERROR(50003,"接口调用失败")。
【4】配置类
config包下的CorsConfig、CosClientConfig、JsonConfig、MyBatisPlusConfig、WxOpenConfig(还有其他参考配置Knife4jConfig)
CorsConfig
CorsConfig用来解决全局跨域配置问题,可以指定请求方法、是否允许发送Cookie、放行哪些特定域名或ip允许哪些请求头。
CosClientConfig
CosClientConfig为cos对象云存储客户端配置,此处需要设定accessKey、secretKey、 region、 bucket, 在application.yml中做替换, 然后配合工具类即可使用对象云存储的功能。
application.yml中配置cos
# 对象存储
cos:
client:
accessKey: xxx
secretKey: xxx
region: xxx
bucket: xxx
JsonConfig
@JsonComponent作用:自定义序列化和反序列JSON数据,Spring Boot默认使用JackSon进行序列化和反序列化。
怎么防止丢失?:用@Bean覆盖组件后,重写逻辑代码,将包装类Long和基础数据类型long转化成字符串序列化成字符串防止在序列化的时候丢失精度。
精度丢失场景: id在数据库是BigInteger 类型,雪花算法生成id大于17位, 因此在序列化的时候会产生精度丢失。
MyBatisPlusConfig
@MapperScan用于指定扫描的路径,如果项目的基础包名路径不同,需要修改。此处用@Bean进行组件的注入,添加了分页插件。此外MyBatisPlus还有很多插件,例如:乐观锁插件、多租户插件、动态表明插件、数据权限插件等等,可以去官网查看。
WxOpenConfig
在微信开放平台获取相应的appId、appSercet等配置之后,在application.yml中进行配置
application.yml:
# 微信开放平台
open:
appId: xxx
appSecret: xxx
Knife4jConfig
配置1:自定义类配置
@Profile用于指定在什么环境配置,这个和配置文件中的spring.profiles.active是联动的,图中组合设定只在dev开发、test测试环境中生效
basePackage:用于指定要扫描的controller包
配置2:为了适配不同环境中的配置,可以直接在application.yml系列配置文档中直接配置knife4j相关内容
【5】全局异常处理
exception包下的BusinessException、GlobalExceptionHandler、ThrowUtils,主要用于构建全局异常处理的通用方法
BusinessException:自定义异常类
BusinessException为自定义异常类,继承RuntimeException(继承了message属性),通过自定义code错误码用于适配不同的异常业务场景。结合ErrorCode进行使用,通过构造参数封装不同的异常信息
GlobalExceptionHandler:全局异常处理器
@RestControllerAdvice注解是@ControllerAdvie和@ResponseBody注解的组合,先捕获整个应用程序中抛出的异常,然后将异常处理方法的返回值将自动转换为HTTP响应的主体。
@ExceptionHandler注解用于指定什么异常需要被捕获。
ThrowUtils:自定义异常抛出类
ThrowUtils:自定义异常抛出类用于定义一些常用的业务校验异常;例如请求参数的校验,如果请求参数为空则直接抛出业务异常,并知名错误码errorCode和message错误信息
【6】数据库和ES同步
job包下的IncSyncPostToEs、FullSyncPostToEs:用于实现数据库和ES同步,结合定时任务控制的注解使用,定时同步数据
IncSyncPostToEs:实现增量同步帖子到es
@Component注解:如果取消注解,就将这个定时任务加入到Spring容器中,Spring Boot启动类启动后将会开启这个定时任务。
@Scheduled: Spring Boot的定时任务控制的注解,这里用于每分钟执行同步帖子的逻辑。
应用场景:
【1】想要统计Top10的接口调用次数(API接口),在数据库量大后,每个用户去发送请求获取Top10的接口调用次数会造成数据库请求压力过大,此时可以写个定时任务,可以定时24小时,每天将Top10的接口调用次数同步到Redis存储,以接口名称和键以接[门调用次数为值保存即可。实时性要求不太强的功能,可以采用定时任务。 【2】某个API接口不用用户传参,而且大多数时间回复的调用结果都是相通的,那么就可以采取定时任务,将这些不用用户传参,并且调用结果都是相同的接口定时同步到Redis存储,相对于数据库的I0读取, Redis存储会大大提升这些接口的QPS,可以自己进行量化处理。
FullSyncPostToEs:实现全量同步帖子到es
【7】工具类
utils包下的NetUtils、SpringContextUtils、SqlUtils
NetUtils:用于获取客户端的IP地址
该工具类的作用是从HttpServletRequest对象中提取客户端的真实IP地址。由于在实际的网络环境中,可能存在代理、负载均衡等中间层,因此通过request.getRemoteAddr()方法获取的IP地址可能不准确。为了获取真实的客户端IP地址,该方法通过检查一系列的请求头信息来确定IP地址。
SpringContextUtils:通过名称、类型、名称&类型获取Spring上下文的容器
作用是用于提供了静态方法通过名称、类型、名称和类型来获取Spring应用程序上下文中的Bean实例,通过依赖注入SpringContextUtils类,其他组件可以方便地获取所需的Bean实例。
SqlUtils:用于检查SQL注入问题
用于检验SQL中是否包含特定符号等,防止通过SQL对数据库进行攻击
【8】自定义业务模块
1、创建好规范的包: model层、controller层、 service层 (MVC)
2、使用mybatisX生成与数据库对应的pojo实体类, mapper文件,service类, 移动到对应的包里
3、在Controller层里定义好接口访问路径,然后将需要service注入进来,写方法的时候确定好前端传的参数,然后去调用service里具体业务逻辑实现的方法
4、在service接口层里定义好需要实现的方法、在servicelmpl里具体实现接口里对应的方法
2.功能配置说明
所有项目开发中需要修改的地方标记
todo
,以便于开发时定位修改位置
MySQL 数据库
1)修改 application.yml
的数据库配置:
spring:
datasource:
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://localhost:3306/my_db
username: root
password: 123456
2)执行 sql/create_table.sql
中的数据库语句,自动创建库表
3)启动项目,访问 http://localhost:8101/api/doc.html
即可打开接口文档,不需要写前端就能在线调试接口
Redis 分布式登录
1)修改 application.yml
的 Redis 配置为你自己的:
spring:
redis:
database: 1
host: localhost
port: 6379
timeout: 5000
password: 123456
2)修改 application.yml
中的 session 存储方式:
spring:
session:
store-type: redis
3)移除 MainApplication
类开头 @SpringBootApplication
注解内的 exclude 参数:
修改前:
@SpringBootApplication(exclude = {RedisAutoConfiguration.class})
修改后:
@SpringBootApplication
Elasticsearch 搜索引擎
1)修改 application.yml
的 Elasticsearch 配置为你自己的:
spring:
elasticsearch:
uris: http://localhost:9200
username: root
password: 123456
2)复制 sql/post_es_mapping.json
文件中的内容,通过调用 Elasticsearch 的接口或者 Kibana Dev Tools 来创建索引(相当于数据库建表)
PUT post_v1
{
参数见 sql/post_es_mapping.json 文件
}
这步不会操作的话需要补充下 Elasticsearch 的知识,或者自行百度一下~
3)开启同步任务,将数据库的帖子同步到 Elasticsearch
找到 job 目录下的 FullSyncPostToEs
和 IncSyncPostToEs
文件,取消掉 @Component
注解的注释,再次执行程序即可触发同步:
// todo 取消注释开启任务
//@Component