# leo-springboot
**Repository Path**: wangss3/leo-springboot
## Basic Information
- **Project Name**: leo-springboot
- **Description**: No description available
- **Primary Language**: Unknown
- **License**: Apache-2.0
- **Default Branch**: master
- **Homepage**: None
- **GVP Project**: No
## Statistics
- **Stars**: 0
- **Forks**: 0
- **Created**: 2020-09-17
- **Last Updated**: 2021-11-15
## Categories & Tags
**Categories**: Uncategorized
**Tags**: None
## README
# springboot项目脚手架
[](https://gitee.com/wangss3/leo-springboot) [](https://gitee.com/wangss3/leo-springboot)
>本专栏是作者leo使用```SpringBoot```、```Mysql```等技术栈和偏向于DDD领域驱动设计方式,搭建的springboot模板项目。如果本项目能为您提供帮助,请给予支持(关注、点赞、分享)!
> **作者:** leo,Java Developer,[:leo: CSDN 李白与孟浩然](https://blog.csdn.net/wang521qian/)
**如何支持:**
- 点击右上角Star :star: 给予关注
- 赏个鸡腿🍗
---
雨后天晴写下、年华,
巫山云景彩霞、如画。
心似平远走**码**、飞驾,
整装年少风华、正恰。
搭建基础脚手架,方便后续快速开发,框架中主要集成springboot、常用jar、封装的工具类
## 一、工程源码
**源码地址**:
- [https://gitee.com/wangss3/leo-springboot](https://gitee.com/wangss3/leo-springboot)
## 二、项目架构
**目录结构**:
- src/main/java 项目的源代码所在的目录
- src/main/resources 项目的资源文件所在的目录
- 其他目录结构见名知意
**引入功能**:
- springboot 2.3.3
- commons-lang3 常用工具类、commons-io io操作工具类
- druid 数据库连接池
- spring-boot-starter-log4j2 日志组件
## 三、引入组件
**log4j2日志组件引入**:
springboot默认是使用logback来进行日志记录,本项目使用log4j2来记录日志,为避免冲突,需要在pom中排除logback。
```
org.springframework.boot
spring-boot-starter
spring-boot-starter-logging
org.springframework.boot
```
也要注意其他jar中是否有引入。
引入log4j2依赖:
```
org.springframework.boot
spring-boot-starter-log4j2
```
在src/main/resources/添加配置文件log4j2.xml,项目启动时log4j2会自动到这个目录加载。
也可以在application.properties中配置路径:```logging.config=classpath:log4j2.xml```
使用案例:
- @Slf4j
- private static final org.slf4j.Logger LOGGER = org.slf4j.LoggerFactory.getLogger(***.class);
---
异步日志的配置方式:
- 引入disruptor并发包
```
com.lmax
disruptor
3.4.2
```
- 增加log4j2.component.properties配置文件,启用异步属性
- 在application.properties文件中指定使用的日志文件为:log4j2-async.xml ```logging.config=classpath:log4j2-async.xml```
- 使用```log.info("是否为异步日志:{}", AsyncLoggerContextSelector.isSelected());``` 语句判断是否开启异步日志
---
**springboot-javafx-support组件引入**:
```
de.roskenet
springboot-javafx-support
${springboot-javafx-support.version}
```
使用方法:
```
@SpringBootApplication
@Slf4j
public class LeoSpringbootJavafxApplication extends AbstractJavaFxApplicationSupport {
public static void main(String[] args) {
// DemoStageView视图类,CustomSplash启动动画类
launch(LeoSpringbootJavafxApplication.class, DemoStageView.class, new CustomSplash(), args);
}
@Override
public void start(Stage stage) throws Exception {
super.start(stage);
}
}
```
**druid连接池引入**:
本项目采用阿里的druid连接池进行数据库连接管理,引入jar如下:其中需要注意的是剔除springboot默认连接池HikariCP
```
org.mybatis.spring.boot
mybatis-spring-boot-starter
2.1.3
HikariCP
com.zaxxer
com.alibaba
druid-spring-boot-starter
1.1.23
mysql
mysql-connector-java
5.1.46
com.oracle
ojdbc6
6.0
```
druid配置数据库和参数设置:
```
# Spring Boot的数据源配置的默认类型是org.apache.tomcat.jdbc.pool.Datasource
#配置druid连接池
#mysql数据源
spring.datasource.druid.mysql.type=com.alibaba.druid.pool.DruidDataSource
spring.datasource.druid.mysql.driver-class-name=com.mysql.cj.jdbc.Driver
spring.datasource.druid.mysql.url=jdbc:mysql://localhost:3306/test?useUnicode=true&characterEncoding=UTF-8&useSSL=false&serverTimezone=GMT%2B8
spring.datasource.druid.mysql.username=root
spring.datasource.druid.mysql.password=root
#oracle数据源
spring.datasource.druid.oracle.type=com.alibaba.druid.pool.DruidDataSource
spring.datasource.druid.oracle.driver-class-name=oracle.jdbc.OracleDriver
spring.datasource.druid.oracle.url=jdbc:oracle:thin:@localhost:1521:ORCL
spring.datasource.druid.oracle.username=test
spring.datasource.druid.oracle.password=test
# 连接池配置
spring.datasource.druid.initial-size=5
spring.datasource.druid.min-idle=5
spring.datasource.druid.max-active=20
# 连接等待超时时间
spring.datasource.druid.max-wait=30000
# 配置检测可以关闭的空闲连接间隔时间
spring.datasource.druid.time-between-eviction-runs-millis=60000
# 配置连接在池中的最小生存时间
spring.datasource.druid.min-evictable-idle-time-millis=300000
#用来检测连接是否有效的sql 必须是一个查询语句
#mysql中为 select 'x'
#oracle中为 select 1 from dual
spring.datasource.druid.validation-query=select 'x'
spring.datasource.druid.test-while-idle=true
spring.datasource.druid.test-on-borrow=false
spring.datasource.druid.test-on-return=false
#当数据库抛出不可恢复的异常时,抛弃该连接
spring.datasource.druid.exception-sorter=true
# 打开PSCache,并且指定每个连接上PSCache的大小
#是否缓存preparedStatement,mysql5.5+建议开启
spring.datasource.druid.pool-prepared-statements=true
spring.datasource.druid.max-open-prepared-statements=20
spring.datasource.druid.max-pool-prepared-statement-per-connection-size=20
# 配置监控统计拦截的filters, 去掉后监控界面sql无法统计, 'wall'用于防火墙
spring.datasource.druid.filters=stat,wall
#通过connectProperties属性来打开mergeSql功能;慢SQL记录
spring.datasource.druid.connection-properties=druid.stat.mergeSql=true;druid.stat.slowSqlMillis=500
#合并多个DruidDataSource的监控数据
spring.datasource.druid.use-global-data-source-stat=true
# Spring监控AOP切入点,如x.y.z.service.*,配置多个英文逗号分隔
#spring.datasource.druid.aop-patterns=com.leo.servie.*
# WebStatFilter配置
#spring.datasource.druid.web-stat-filter.enabled=true
# 添加过滤规则
#spring.datasource.druid.web-stat-filter.url-pattern=/*
# 忽略过滤的格式
#spring.datasource.druid.web-stat-filter.exclusions=*.js,*.gif,*.jpg,*.png,*.css,*.ico,/druid/*
# StatViewServlet配置
#spring.datasource.druid.stat-view-servlet.enabled=true
# 访问路径为/druid时,跳转到StatViewServlet
#spring.datasource.druid.stat-view-servlet.url-pattern=/druid/*
# 是否能够重置数据
#spring.datasource.druid.stat-view-servlet.reset-enable=false
# 需要账号密码才能访问控制台
#spring.datasource.druid.stat-view-servlet.login-username=druid
#spring.datasource.druid.stat-view-servlet.login-password=druid123
# IP白名单
#spring.datasource.druid.stat-view-servlet.allow=127.0.0.1
# IP黑名单(共同存在时,deny优先于allow)
# spring.datasource.druid.stat-view-servlet.deny=192.168.1.218
# 配置StatFilter
spring.datasource.druid.filter.stat.log-slow-sql=true
```
在启动类中排除druid自动加载的bean,否则项目启动会报错:```@SpringBootApplication(exclude = {DruidDataSourceAutoConfigure.class})``
增加配置类,加载创建数据库连接,可参考:com.leo.base.db.config.DynamicDataSourceConfig.java
高版本druid需要配置@Configuration文件才能打开监控界面,例如:com/leo/base/config/DruidConfig.java
将spring监控也加入到druid中,例如:com/leo/base/config/SpringMonitoringConfig.java
mysql-connector-java:8.0.21 和 mysql-connector-java:5.xx.xx 不同:
- 驱动变为:com.mysql.cj.jdbc.Driver
- 需要关闭:useSSL=false
- 需要指定:serverTimezone=GMT%2B8
**集成redis功能**:
项目中数据的使用遵循28定律,大部分时间只有20%的数据被使用到,所以我们应该将热点数据进行缓存,以减轻数据库压力,redis功能jar引入:
```
org.springframework.boot
spring-boot-starter-data-redis
org.apache.commons
commons-pool2
```
增加配置文件:application-redis.properties
```
spring.redis.host=127.0.0.1
spring.redis.port=6379
#Redis 索引(0~15,默认为 0)
spring.redis.database=0
#Redis 密码,如果没有就默认不配置此参数
spring.redis.password=
#Redis 连接的超时时间
spring.redis.timeout=30s
#连接池中的最小空闲连接
spring.redis.lettuce.pool.min-idle=5
#连接池中的最大空闲连接
spring.redis.lettuce.pool.max-idle=10
#连接池最大连接数(使用负值表示没有限制)
spring.redis.lettuce.pool.max-active=20
#连接池最大阻塞等待时间(使用负值表示没有限制)
spring.redis.lettuce.pool.max-wait=1ms
spring.redis.lettuce.shutdown-timeout=100ms
#缓存失效时间(毫秒)
spring.cache.redis.time-to-live=10000
```
正常来说,引入jar,配置完参数以后,就可以通过RedisTemplate和StringRedisTemplate两个类直接使用。但是为了方便使用,我们配置一个类RedisConfig,
重新生成一个RedisTemplate的bean,改写key和value的序列化方式。为了方便对redis进行操作,我们还要实现一个RedisUtil工具类,用来操作redis。
使用redis作为缓存,在启动类中加上@EnableCaching注解,就会开启缓存,springboot会自动生成一个RedisCacheManager,但是我们需要对RedisCacheManager进行
一些更改,所以会在配置类RedisConfig中进行重写,更方便使用。
针对缓存,我们主要介绍几个注解的使用:
- @CacheConfig 这个注解在类上使用,用来描述该类中所有方法使用的缓存名称,当然也可以不使用该注解,直接在具体的缓存注解上配置名称
- @Cacheable 这个注解一般加在查询方法上,表示将一个方法的返回值缓存起来,默认情况下,缓存的key就是方法的参数,缓存的value就是方法的返回值。这个方法的查询情况为:
如果先从缓存获取数据,如果有数据直接返回,没有数据在查询数据库。

- @CachePut 这个注解一般加在更新方法上,当数据库中的数据更新后,缓存中的数据也要跟着更新,使用该注解,可以将方法的返回值自动更新到已经存在的key上。还可以加条件:```@CachePut(key = "#sno", condition = "#result != null")```
- @CacheEvict 这个注解一般加在删除方法上,当数据库中的数据删除后,相关的缓存数据也要自动清除,该注解在使用的时候也可以配置按照某种条件删除(condition属性)或者或者配置清除所有缓存(allEntries属性)
- @Caching 组合注解
待补充。。。
异常处理,缓存雪崩等问题,不在整理。
**集成邮件发送功能**:
项目日常使用中,会需要使用到发送邮件进行通知,系统集成邮件功能引入jar:
```
org.springframework.boot
spring-boot-starter-mail
org.springframework.boot
spring-boot-starter-freemarker
```
因为涉及到文件上传,所以需要引入jar commons-fileupload 作为实现类:
```
commons-fileupload
commons-fileupload
1.4
```
- 首先配置文件上传实现类,指定上传文件得属性设置,请参考文件applicationContext-file.xml和文件application-file.properties
- 其次配置mail属性,参考文件application-mail.properties
```
# 163
# 邮箱主机
spring.mail.host=smtp.163.com
spring.mail.port=465
# 发送者的邮箱
spring.mail.username=18616345762@163.com
# 邮箱秘钥
spring.mail.password=wangss123
# 开启qq邮箱的安全认证
spring.mail.properties.mail.smtp.ssl.enable=true
spring.mail.properties.mail.smtp.auth=true
spring.mail.properties.mail.smtp.starttls.enable=true
spring.mail.properties.mail.smtp.starttls.required=true
# 模板邮件路径
spring.mail.template=/mail/template.html
```
- 指定邮件模板templates/mail/templates.html,并进行配置
邮件发送demo请参考:com/leo/controller/MailTestController.java
存在bug:异步发送带附件得邮件时,因为springboot机制,在controller执行完成以后就会将缓存
得上传文件删除,所以导致异步线程执行得时候,找不到附件,从而发送失败。 ---- 已修复
## 四、功能概述
**自路由功能**:
根据业务不同,数据体量不同,目前市面上多使用多数据源:
- 主从分离
- 既有oracle数据库也有mysql数据库
- 多数据源
等情况,所以自己实现了动态路由功能,在包com.leo.base.db下实现,其中包含五个注解,如有需要可以自行修改增加:
- @DynamicDataSource 动态路由,指定数据源,适用于增删改查,使用方式在方法上增加注解,并指定数据源:```@DynamicDataSource(value = "mysql")```
- @GlobalDataSource 全局路由,适用于全局表,用于查询,例如一些字典表等,使用方式在方法上增加注解,并指定表名:```@GlobalDataSource(tableName = "globalStudent")```,任取一个数据源进行指定
- @RandomDataSource 随机路由,用来搞笑的,适用于增删改查,使用方式:```@RandomDataSource(tableName = "randomStudent")```
- @ShardingDataSource 分片路由,根据表名获取分片字段,根据分片字段获取分片值,进行hash计算,得出要存入的数据源,适用于增删改查,使用方式:```@ShardingDataSource(tableName = "shardingStudent")```
- @UnionDataSource 广播路由(聚合路由),根据配置获取所有的数据源进行查询,如果返回结果是对象,则取第一个值,如果返回结果是集合,则进行合并返回,只用于查询```@UnionDataSource(tableName = "unionStudent")```
- @ReadWriteSeparationDataSource 读写分离路由,不在细讲,适用于增删改查,如果不需要复杂版的可以简化
结合配置文件,示例如下:applicationContext-routers.xml
```
```
分片路由算法说明:length总和为1024,count为分几片,每片占1024的多少比例,dataSourceKey要和count总和保持一致,
```
```
**处理指定请求后缀**:(如果没有需要,则可以移除)
请参考文件:```com/leo/base/config/CustomWebMvcConfigurer.java```
**springboot的事件监听机制**:
涉及事件回调机制的几个类:
- ApplicationContextInitializer
- SpringApplicationRunListener
- CommandLineRunner 常用
- ApplicationRunner 常用

案例位置:com/leo/base/initialize/*
**springboot集成eventbus事件监听**:
- 自定义注解 @EventBusListener
- 启动完成以后,获取使用@EventBusListener注解的类,并注册到监听中
- 当事件触发以后,通知各个监听者
这里有一点需要注意:EventBus有同步和AsyncEventBus异步之分,异步时传入的线程池要注意,也可以使用@EnableAsync和@Async注解
使同步事件变成异步。推荐使用注解的方式
## 五、项目演示
## 六、专栏学习(自愿支持)
## 七、与我联系
## 八、参与贡献
1. 如果您对本项目有任何建议或发现文中内容有误的,欢迎提交 issues 进行指正。
2. 对于文中我没有涉及到知识点,欢迎提交 PR。