# treasure **Repository Path**: manong99898/treasure ## Basic Information - **Project Name**: treasure - **Description**: Treasure是一个Java技术生态项目,涵盖了单体、微服务、DDD等架构实践,以兴趣、学习目的、技术积累为理念,逐步完善迭代。主要包含学习成长过程中一些技术点、工作中积累的一些心得,面试中一些业务场景模拟及解决方案一些常见、通用业务的解决方案、合理应用设计模式进行一些业务代码的重构优化、常用小轮子的积累、一些更优雅的编码实现、通用场景封装等内容。 - **Primary Language**: Java - **License**: Apache-2.0 - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 61 - **Created**: 2023-12-07 - **Last Updated**: 2023-12-07 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README

Treasure

2020-05-05~至今

## 初衷 积累,成长 ## 分支规划 > 目前分支规划存在一定的不合理性,将在后期进行完善优化.所有的架构都是基于业务进行演化的. > > 工具类 > 工具包 > 功能模块 > 场景启动器 > 功能服务 > 分布式 + `master` 微服务架构 业务场景模拟,学习案例 + `SpringBoot 2.3.2.RELEASE` + `SpringCloud Hoxton.SR8` + `Nacos` + `OpenFeign 2.2.5.RELEASE` + `Hystrix 2.2.5.RELEASE ` + `gateway` + `study` 单体架构、学习案例 + `SpringBoot 2.3.12.RELEASE` + `scene` 单体架构、最佳实践、插件化、模块化、配置化 + `SpringBoot 2.3.12.RELEASE` + `cloud` 规划中 + `SpringBoot 2.4.2` + `SpringCloud 2020.0.6` + `eureka 3.0.6` + `hystrix 2.2.10.RELEASE` + `openfeign 3.0.7` + `ribbon 2.2.10.RELEASE` + `cloud alibaba` 规划中 + `nacos` + `gateway` + `sentinel` ## 简介 `Treasure`是一个`Java`技术生态项目 + 架构 + 单体 + 微服务 + DDD + 开源可免费商用 + 为兴趣而开源为、学习而开源、为技术而开源 + 学习成长过程中一些技术点、整合工作中积累的一些心得 + 面试中一些业务场景模拟及解决方案一些常见、通用业务的解决方案 + 合理应用设计模式进行一些业务代码的重构优化 + 常用小轮子的积累、一些更优雅的编码实现 + 常用、通用业务场景`Starter`封装、日常使用自研小工具(同步更新阿里云制品仓库) ## 模块 ### `scene`分支 > 为了方便随取随用,没有做过多的聚合,各个模块相对独立 ~~~ com.dingwen ├── scene // 综合场景启动器使用示例 │ └── pom.xml // Maven依赖 ├── starter // 启动器集 │ └── base-spring-boot-starter // 基础场景启动器 │ └── api-docs-spring-boot-starter // API文档再封装场景启动器 │ └── screw-spring-boot-starter // 数据库文档生成场景启动器 │ └── webplus-spring-boot-starter // Web再封装场景启动器 │ └── redis-spring-boot-starter // Redis场景启动器 │ └── caffeine-spring-boot-starter // 本地缓存启动器 │ └── async-spring-boot-starter // 异步场景启动器 │ └── enums-spring-boot-starter // 枚举场景启动器 │ └── mybatisplus-spring-boot-starter // MybatisPlus场景启动器 │ └── log-spring-boot-starter // 日志场景启动器 │ └── logv-spring-boot-starter // 日志查看启动器 │ └── email-spring-boot-starter // 电子邮件场景启动器 │ └── mongo-spring-boot-starter // MongoDB场景启动器 │ └── xxl-job-spring-boot-starter // xxljob场景启动器 │ └── translate-spring-boot-starter // 翻译场景启动器 │ └── oss-spring-boot-starter // 文件存储场景启动器 │ └── pipeline-spring-boot-starter // 责任链Pipeline场景启动器 │ └── bar-spring-boot-starter // 进度条场景启动器 │ └── dic-spring-boot-starter // 字典场景启动器 │ └── excel-spring-boot-starter // Excel场景启动器 │ └── config-spring-boot-starter // 系统配置场景启动器 │ └── quartz-spring-boot-starter // Quartz定时任务场景启动器 │ └── file-spring-boot-starter // 文件场景启动器 │ └── // 数据脱敏场景启动器 │ └── // JWT场景启动器 │ └── // Security场景启动器 │ └── // 文件预览场景启动器 │ └── // 监控场景启动器 │ └── // 审核场景启动器 │ └── // Flowable启动器 │ └── // Camunda启动器 │ └── // 微信公众号开发启动器 │ └── // 钉钉开发启动器 │ └── // 重要表单变更日志启动器 │ └── // elasticsearch启动器 │ └── // ... ├── pom.xml // Maven依赖 ~~~ ### `study`分支 ~~~ com.dingwen ├── treasure-canal-client // canal客户端 [80] ├── treasure-kettle // kettle集成企业级解决方案 [9999] ├── treasure-websocket // websocket方案 [8081] [8080] ├── treasure-sms4j // 通用短信解决方案 [8080] ├── treasure-poi-tl // word模板渲染解决方案 [8080] ├── treasure-jimu-report // 开源报表解决方案 [8080] ├── treasure-dingtalk-ger // 钉钉,企业微信预警机器人解决方案 [8080] ├── // 认证解决方案 [8080] ├── // 单点登录解决方案 [8080] ├── // 动态表单解决方案 [8080] ├── treasure-gof // 大话设计模式 ├── // ... ├── pom.xml // Maven依赖 ~~~ ### `master`分支 ~~~ com.cdn com.dingwen ├── treasure-auth // 认证服务 [20902] ├── treasure-business // 业务服务 [20903] ├── treasure-admin // 监控服务 [20901] ├── treasure-common // 通用模块 │ └── common-pom // 依赖管理模块 │ └── common-base // 基础模块 │ └── common-beansearcher // 对象搜索 │ └── common-config // 基础配置 │ └── common-core // 核心模块 │ └── common-jpa // 持久层JPA │ └── common-jwt // JWT令牌 │ └── common-knifej // 接口文档 │ └── common-model // 通用MODEL │ └── common-mongodb // MongoDB │ └── common-mybatisplus // 持久层Mybatisplus │ └── common-rabbitmq // RabbitMQ │ └── common-redis // Redis │ └── common-security // 安全模块 │ └── common-sensitive // 自定义注解实现数据脱敏 │ └── common-web // WEB模块 │ └── common-tkmybatis // tkmybatis模块 │ └── common-minio // minio文件存储 │ └── common-easyexcel // excel 文件导入导出 │ └── common-influxdb // 时序数据库案例 │ └── common-open-api // open api 案例 │ └── open-api-baidu-map // 百度地图 │ └── open-api-sms // 阿里云短信 │ └── open-api-tx // 天行数据基础服务 │ └── open-api-wechat-pub // 微信公众号 │ └── open-api-baidu-map // 百度地图 │ └── open-api-tianxing-rainbow // 天行数据彩虹屁 ├── treasure-gateway // 网关服务 [20904] ├── treasure-log // 日志服务 [20905] ├── treasure-manage // 后台管理 [20906] ├── treasure-file-generate // 文件生成服务 [20907] ├── treasure-task-quartz // 定时任务(Quarzt实现) [20908] ├── treasure-file // 文件服务 [20909] ├── treasure-code-generate // 代码生成服务 [20910] ├── treasure-slow-sql // 慢SQL [20911] ├── treasure-xxl-job-admin // xxl-job-admin [20933] ├── logs // 日志 ├── sql // sql ├── img // 图片 ├── pom.xml // 公共依赖 ~~~ ### `cloud` > SpringCloud 实践 ### `alibaba_cloud` > 阿里系微服务生态实践 ### `ddd` > DDD架构实践 ## 架构图 > 参考若依 ![若依架构图](./img/若依架构图.png) ## 概览
### API文档 [在线文档](https://www.apifox.cn/apidoc/shared-2d9191fd-dfd4-45a3-bc29-57500b3a5f1b) ## 技术点 | | | | | | | | | | | | ----------- | --------------------- | --------------- | ----------------- | -------------- | --------------- | ------- | --- | --- | ---------------- | | `Redis` | `Mysql` | `MongoDB` | `Canal` | `Postgresql` | `ElasticSearch` | | | | Alibaba Druid | | `Spring` | `SpringMVC` | `SpringBoot` | `Spring Security` | `Spring-retry` | | | | | SpringBoot Admin | | `Mybatis` | `MybatisPlus` | `TK Mybatis` | | | | | | | JPA | | `Mapstruct` | `MapstructPlus` | `Hutool` | `Screw` | `BeanSearcher` | `EasyExcel` | knife4j | | | p6spy | | `ip2region` | `Guava` | `commons-lang3` | `Lombok` | | | | | | Maven | | `xxl-job` | | | | | | | | | Quartz | | `Nacos` | `SpringCloud Alibaba` | `GateWay` | `Feign` | `Hystrix` | | | | | Ribbon | | `RabbitMQ` | `RocketMQ` | | | | | | | | Kafka | | `Kettle` | | | | | | | | | ELK | | `Thymeleaf` | | | | | | | | | Layui | | `Minio` | `Aliyun OSS` | | | | | | | | JWT | | `Websocket` | | | | | | | | | sms4j | | `Bistoury` | `poi-tl` | `jimu-report` | | | | | | | Arthas | ## 通用应用场景Starter封装 > Maven增加一下配置即可 ``` rdc-releases 62c3e2f6a908b6a4db54fa26 5V8N7KJ]rvtt rdc-snapshots 62c3e2f6a908b6a4db54fa26 5V8N7KJ]rvtt mirror central,jcenter,!rdc-releases,!rdc-snapshots mirror https://maven.aliyun.com/nexus/content/groups/public rdc rdc-releases::default::https://packages.aliyun.com/maven/repository/2380560-release-WXL1gl/ rdc-snapshots::default::https://packages.aliyun.com/maven/repository/2380560-snapshot-vKCASA/ rdc ``` ### 基础场景启动器 > 基于`SpringBoot2.1.7`和`JDK1.8`封装的基础场景启动器 #### 核心功能 + 基础异常 + 通用工具类 + `logback`配置优化,异步日志优化 #### 使用 ##### 引入依赖 ```xml com.dingwen base-spring-boot-starter 1.0.0-SNAPSHOT ``` ##### 启动项配置 > 在启动类上添加`@EnableBase`注解以开启基础场景功能 ``` @EnableBase ``` #### 核心工具类 + `AspectUtils`: 切面工具类 + `BeanCopyUtils`: bean深拷贝工具(基于 cglib 性能优异) + `CheckerUtils`: Lambda形式对象校验包 + `DateUtils`: 日期工具类 + `LaExUtils`: Lambdas受检异常封装处理 + `AddressUtils`: 地址工具类 + `RegionUtils`: IP离线定位 + `MessageUtils`: 国际化消息 + `ReflectUtils`: 反射工具 + `SqlUtils`: sql操作工具类 + `StringUtils`: 字符串操作工具 + `StreamUtils`: stream工具类 + `IdUtils`: ID工具类 + `Validatetils`: 编程式灵活校验工具 + `SpringUtils`: Spring工具类(基于Hutool拓展,获取代理对象) + `OptimizeUtils` 优化工具类 + `PinYin4jUtils`文字转汉语拼音 #### 使用案例 ##### `CheckerUtils` ``` Checker checker = Checkers.lambdaCheck() .notNull(SysUser::getName) .ne(SysUser::getAge, 0) .custom(item -> item.getAge() > queryByDb(item.getId()), "年龄异常"); checker.check(sysUser); ``` ##### `OptimizeUtils` > 参考Spring StopWatch 的拓展优化,精确计算执行耗时,执行次数,方便进行优化 > `OptimizeUtilController` ```java /** *  OptimizeUtilController: 优化工具测试 *  @author dingwen *  @since 2022/8/28 */ @Api(tags = "优化工具API") @RestController @Slf4j @RequestMapping("optimize") @RequiredArgsConstructor public class OptimizeUtilController { @ApiOperation(value = "API使用测试") @GetMapping public void test() { optimizeApi(); } @SneakyThrows(Throwable.class) private void optimizeApi() { OptimizeUtil.start("任务1"); TimeUnit.SECONDS.sleep(1); OptimizeUtil.stop("任务1"); for (int i = 0; i < 100; i++) { OptimizeUtil.start("任务2"); for (int j = 0; j < 1000; j++) { OptimizeUtil.start("任务2-1"); OptimizeUtil.stop("任务2-1"); } OptimizeUtil.stop("任务2"); } OptimizeUtil.print("任务2"); OptimizeUtil.print(); } } ``` ![优化工具类](./img/OptimizeUtil.png) ### web场景启动器 > `SpringBoot Web`的二次封装 #### 核心功能 + 序列化反序列化配置 + `Date` + `LocalDateTime` + `Long` 解决大数字前端精度丢失问题 + `Debug`方法级别调试日志 + 静态资源映射配置化实现 + `Xss`防护配置化实现 + 构建可重复读取inputStream的request + 分页工具 `PageUtils` + 支持国际化的统一异常处理 `GlobalExceptionHandler` + 支持国际化的统一接口返回 `ResultVOGenerator` + 增加`tranceId`返回: 实现每次请求可溯源 + 优雅校验实现 + 允许的值集校验 `AllowableValues` + 禁止的值集校验 `BanValues` + 分组校验 `ValidGroup` + 编程式灵活校验 `ValidateUtils` + `ServletUtils` 若依拓展`Servlet`工具 + `Controller`基础接口抽象 + `BaseCrudController` + `BaseViewController` + TODO 基础查询对象封装,支持数据权限 #### 使用 ##### 引入依赖 ```xml com.dingwen webplus-spring-boot-starter 1.0.0-SNAPSHOT ``` ##### 启动项配置 > 在启动类上添加`@EnableWebplus`注解以开启web场景功能场景功能 ``` @EnableWebplus ``` > 配置webplus ```yml dingwen: treasure: # webplus webplus: # 开启Debug debug: true # 静态资源映射处理 handlers: - handler: "doc.html" locations: "classpath:/META-INF/resources/" - handler: "swagger-ui.html" locations: "classpath:/META-INF/resources/" - handler: "/webjars/**" locations: "classpath:/META-INF/resources/webjars/" ``` #### 概览
#### 链路追踪日志 > 基于过滤器+AOP+`InheritableThreadLocal`实现的可配置的链路追踪日志方案,后期可对接ELK加工处理
#### 全局异常优雅处理 > 区分不同的环境,通过全局异常捕获,统一返回国际化的友好的异常消息.
### API文档场景启动器 > 基于`Knif4j`封装的API文档场景启动器 #### 使用 ##### 引入依赖 ```xml com.dingwen api-docs-spring-boot-starter 1.0.0-SNAPSHOT ``` ##### 启动项配置 > 在启动类上添加`@EnableApiDocs`注解,以开启接口文档功能 ``` @EnableApiDocs ``` > 配置 ```yml dingwen: treasure: # API接口文档生成 api: docs: # 标题 title: "Ding Wen Service Api" # 描述 description: "This is Interface Desc" # 服务地址 url: "http://127.0.0.1" # 版本号 version: "1.0.0" # 分组名称 group: prod # 内部API请求头值 headervalue: "DINGWEN-API-VALUE" # 内部APi请求名称 headername: "DINGWEN-API-NAME" # 文档联系人名称 contactname: "dingwen" # 文档联系人站点 contacturl: "https://treasure.dingwen.top" # 文档联系人邮箱 contactemail: "dingwen0314@163.com" ``` #### 概览 + [协议://IP:端口/doc.html](协议://IP:端口/doc.html)
### 异步通用场景启动器 > 实现SpringBoot中线程池动态化配置 #### 核心功能 + 线程池参数详细动态化配置 + 实时执行日志可配置打印 #### 使用 ##### 引入依赖 ```xml com.dingwen async-spring-boot-starter 1.0.0-SNAPSHOT ``` ##### 启动项配置 > 在启动类上添加`@EnableApiDocs`注解,以开启异步场景功能,注意: 包名称是:`com.dingwen.treasure.async.annotation`下的 ``` @EnableAsync ``` > 配置线程池 ```yml dingwen: treasure: # async async: # 是否开启线程池实时日志打印 logPrint: true pool: # 核心线程数 - core: 8 # 最大线程数 max: 16 # 线程空闲时间 keepAliveTime: 60 # 缓冲队列大小 queueCapacity: 2000 # 线程池前缀 poolNamePrefix: treasure-async- # 线程池对象名称 poolBeanName: logvExecutor # 线程池拒绝策略 poolPolicy: CallerRunsPolicy ``` ##### 代码片段 ``` // 注解式 @Resource(name = "fileExecutor") @Lazy private ThreadPoolTaskExecutor fileExecutor; // 编程式 ThreadPoolTaskExecutor logVExecutor = SpringUtil.getBean("logvExecutor", ThreadPoolTaskExecutor.class); ``` ### 日志通用场景启动器 > 实现方法级别的日志,请求级别的日志,业务级别的日志配置化,拓展化,可视化以及代码定位 #### 核心功能 ##### 方法日志 > 方法日志细分为整体日志`MeLog`,参数日志`ParamMeLog`,返回结果日志`ResultMeLog`,方法异常日志`ThrowingMeLog`可灵活配置实现 > 可基于日志格式化接口定制实现,已提供默认实现 > 提供回调接口可灵活拓展处理日志 + 方法日志 + 参数日志 + 返回结果日志 + 异常日志 ##### 请求日志 > 可整体配置所有请求的日志记录规则,提供回调接口可进行定制化 ##### 操作日志 > 基于注解实现的操作日志,依附与Spring事件监听机制解耦,监听对应日志实现及可实现定制化 #### 使用 ##### 引入依赖 ```xml com.dingwen log-spring-boot-starter 1.0.0-SNAPSHOT ``` ##### 启动项配置 > 在启动类上添加`@EnableLog`注解以开启日志通用场景功能 ``` @EnableLog ``` > 日志配置 ```yml dingwen: treasure: # 请求日志 log: request: # 是否开启请求日志 reEnable: true # 是否记录请求体内容 reEnableBody: false method: global-log-level: debug # 全局综合日志代码定位 global-log-position: unknown # 全局综合日志格式化 global-log-formatter: com.dingwen.treasure.log.method.format.DefaultMeLogFormatter # 全局综合日志回调 global-log-callback: com.dingwen.treasure.log.method.callback.DefaultMeLogCallback # 全局参数日志级别 global-param-log-level: debug # 全局参数日志代码定位 global-param-log-position: unknown # 全局参数日志格式化 global-param-log-formatter: com.dingwen.treasure.log.method.format.DefaultMeParamLogFormatter # 全局参数日志回调 global-param-log-callback: com.dingwen.treasure.log.method.callback.DefaultMeLogCallback # 全局结果日志级别 global-result-log-level: debug # 全局结果日志代码定位 global-result-log-position: unknown # 全局结果日志格式化 global-result-log-formatter: com.dingwen.treasure.log.method.format.DefaultMeResultLogFormatter # 全局结果日志回调 global-result-log-callback: com.dingwen.treasure.log.method.callback.DefaultMeLogCallback # 全局异常日志回调 global-throwing-log-callback: com.dingwen.treasure.log.method.callback.DefaultMeLogCallback ``` ##### 代码片段 ``` /** * 测试方法日志 * * @param name 名字 * @return {@link ResultVO}<{@link String}> */ @GetMapping("/method-test") @ApiOperation(value = "测试方法日志") @ApiImplicitParam(name = "name", value = "名称", dataTypeClass = String.class) @MeLog(value = "方法日志测试业务") public ResultVO testMeLog(@RequestParam String name) { return success(); } /** * 测试操作日志 * * @param name 名称 * @return {@link ResultVO}<{@link String}> */ @GetMapping("/operate-test") @ApiOperation(value = "测试操作日志") @ApiImplicitParam(name = "name", value = "名称", dataTypeClass = String.class) @OperateLogAnnotation(module = "场景", desc = "test") public ResultVO testOperateLog(@RequestParam String name) { return success(); } ``` #### 概览
### 日志文件查看启动器 > 基于Websocket、SpringBoot2.x、layui实现的可配置的Web版日志查看器 #### 核心功能 + 可选基础目录生成文件树 + 日志文件编码配置化 + 追加新日志自动滚动 #### 优化点 + 日志查看页增加文件下载 + 文件树按照创建时间降序 + 大量的日志输出导致内存飙升 + 大量的客户端链接导致CPU飙高 + UI美化 + 异常提示完善 #### 使用 ##### 引入依赖 ```xml com.dingwen logv-spring-boot-starter 1.0.0-SNAPSHOT ``` ##### 启动项配置 > 在启动类上添加`@EnableLogv`注解以开启日志查看场景功能 ``` @EnableLogv ``` > 配置接口文档放行、线程池、监控项 ```yml dingwen: treasure: # webplus webplus: debug: true handlers: - handler: "doc.html" locations: "classpath:/META-INF/resources/" - handler: "swagger-ui.html" locations: "classpath:/META-INF/resources/" - handler: "/webjars/**" locations: "classpath:/META-INF/resources/webjars/" # async async: logPrint: true pool: - core: 8 max: 16 keepAliveTime: 60 queueCapacity: 2000 poolNamePrefix: treasure-async- poolBeanName: logvExecutor poolPolicy: CallerRunsPolicy # 监控项 management: endpoints: web: exposure: include: "*" endpoint: health: show-details: always shutdown: enabled: true ``` #### 访问地址 > 默认启动端口: `2023` + [首页](http://127.0.0.1:2023/common/logv/manager.html) + [接口文档](http://127.0.0.1:2023/doc.htm) #### 概览
### 高效的通用枚举处理启动器 > 从前端到服务乃至数据库到枚举解决方案,零代码,开箱即用 > 已加本地缓存,速度杆杆滴 #### 主要功能 + 统一枚举实现 + 统一枚举响应 + 统一枚举MVC转换 + 统一枚举序列化 + 统一枚举反序列化 + 统一枚举接口实现 + 获取所有枚举时支持分页 + 统一异常处理 #### 内置接口 + 获取服务端所有枚举 `/common/enums` + 分页查询枚举 `/common/enums/page` + 指定枚举类全路径查询执行枚举 `/common/enums/{enumClassName}` #### 使用 > 枚举持久化依赖各自持久层实现。 > MybatisPlus 3.5.2后版本只需要在实体类中存储数据库值的字段标注 > `@EnumValue`即可 #### 引入依赖 ```xml com.dingwen enums-spring-boot-starter 1.0.0-SNAPSHOT ``` #### 开启功能 > 在启动类上添加`@EnableEnums`注解以开启枚举功能 #### 创建自己的枚举 ```java /** *  逻辑删除 *  @author dingwen *  @since 2022/6/14 */ @Getter @AllArgsConstructor public enum LogicDelete implements IBaseEnum { /** * 已删除 */ DELETED(0, "删除"), /** *存在 */ EXISTED(1, "存在"); /** * 状态值 */ @EnumValue private final Integer code; /** * 状态描述 */ private final String desc; } ``` #### 配置项 ```yml dingwen: treasure: # enums enums: # 枚举类扫描包 packagepath: "com.dingwen" # 枚举类所在类路径 classpath: "/**/*.class" ``` #### 注意点 > IBaseEnum中已提供枚举比较方法以及转换方法可直接使用 #### 概览
#### 更高效的获取枚举 > 以空间换时间的方式实现. > > 枚举场景初始化时会将所有枚举缓存到`map`,使用时再通过`key`获取即可,省去了循环查找的过程.在枚举数量较多的场景下效率较高.
### 数据库文档生成启动器 > 基于Screw、Freemarker实现的支持word,markdown,html文件生成的数据库文档生器 #### 核心功能 + 包含可配置的详细注释生成 + 表名称,前缀,后缀等细粒度可配置化 + 文档名称,标题可配置化 + 同时支持work,markdown,html版本数据库设计文档 #### 使用 ##### 引入依赖 ```xml com.dingwen screw-spring-boot-starter 1.0.0-SNAPSHOT ``` ##### 启动项配置 > 在启动类上添加`@EnableScrew`注解以开启数据库表文档生成功能 ``` @EnableScrew ``` > 配置文档参数 ```yml dingwen: treasure: # 数据库文档生成 screw: # 数据源连接地址 jdbcUrl: ${spring.datasource.dynamic.datasource.master.url} # 数据源用户名 username: ${spring.datasource.dynamic.datasource.master.username} # 数据源连接密码 password: ${spring.datasource.dynamic.datasource.master.password} # 驱动类名称 driverClassName: ${spring.datasource.dynamic.datasource.master.driver-class-name} # 是否读取表注释信息 tableRemark: true # 文档版本号 docVersion: 1.0.0 # 文件输出目录 fileOutputDir: @project.name@/src/main/resources/static ``` #### 访问地址 + [首页](http://127.0.0.1:8080/treasure_doc_1.0.0.html) #### 概览
### MongoDB场景启动器 > 基于`MongoTemplate`分装的类似`MybatisPLus`的`lambda`形式的增删改查API #### 核心功能 + 复杂条件灵活构造查询 + 分页查询 + 模糊查询 + 排序 + 集合查询 + 新增 + 修改 + 删除 #### 使用 ##### 引入依赖 ```xml com.dingwen mongo-spring-boot-starter 1.0.0-SNAPSHOT ``` ##### 启动项配置 > 在启动类上添加`@EnableScrew`注解以开启mongo场景功能 ``` @EnableMongo ``` ##### 编写实体类 ```java /** * 请求日志 * * @author dingwen * @since 2023/7/24 13:12 */ @ApiModel(value = "RequestLog", description = "请求日志实体") @Document("tre_c_request_log") @Data @AllArgsConstructor @NoArgsConstructor @Builder @EqualsAndHashCode(callSuper = true) public class RequestLog extends BaseMongoEntity { @ApiModelProperty(value = "请求日志id") @Id private String reLogId; @ApiModelProperty(value = "请求时间") @Field("reTime") private LocalDateTime reTime; @ApiModelProperty(value = "请求IP") @Field("reIp") @Indexed private String reIp; @ApiModelProperty(value = "IP属地") @Field("reAddress") private String reAddress; @ApiModelProperty(value = "耗时") @Field("consumeTime") private Long consumeTime; @ApiModelProperty(value = "请求体信息") @Field("resBody") private String resBody; @ApiModelProperty(value = "响应体信息") @Field("respBody") private String respBody; @ApiModelProperty(value = "请求地址") @Field("reUrl") @Indexed private String reUrl; @ApiModelProperty(value = "请求头信息") @Field("reqHeaders") private String reqHeaders; } ``` ##### 编写接口 ```java /** * 请求日志服务 * * @author dingwen * @since 2023/7/24 13:36 */ public interface IRequestLogService extends MongoService { } ``` ##### 编写实现类 ```java /** * 请求日志服务 * * @author dingwen * @since 2023/7/24 13:38 */ @Service public class RequestLogServiceImpl extends MongoServiceImpl implements IRequestLogService { } ``` ##### 调用 ```java /** * MongoAPI * * @author dingwen * @since 2023/7/24 13:42 */ @Api(tags = "MongoDB API") @RestController @Slf4j @RequestMapping("common/mongo") public class MongoController implements BaseViewController { @Resource private IRequestLogService requestLogService; /** * 请求日志列表 * */ @ApiOperation(value = "请求日志列表") @ApiImplicitParams({ @ApiImplicitParam(name = "reIp", value = "请求IP", dataTypeClass = String.class), @ApiImplicitParam(name = "reAddress", value = "IP属地", dataTypeClass = String.class), @ApiImplicitParam(name = "reUrl", value = "请求地址", dataTypeClass = String.class) }) @GetMapping("request-logs") public ResultVO> getRequestLogPage(@RequestParam(required = false) String reIp, @RequestParam(required = false) String reAddress, @RequestParam(required = false) String reUrl) { LambdaQueryWrapper query = Wrappers.lambdaQuery() .like(StrUtil.isNotBlank(reIp), RequestLog::getReIp, reIp) .like(StrUtil.isNotBlank(reAddress), RequestLog::getReAddress, reAddress) .like(StrUtil.isNotBlank(reUrl), RequestLog::getReUrl, reUrl) .orderByDesc(RequestLog::getCreateTime); Page page = requestLogService.page(query, PageUtils.getPageNum(), PageUtils.getPageSize()); return page(page.getRecords(), Convert.toInt(page.getTotal())); } } ``` #### 支持的条件类型 + `eq`: 等于 + `ne`: 不等于 + `le`: 小于等于 + `lt`: 小于 + `ge`: 大于等于 + `gt`: 大于 + `bw`: 在...之间 + `in`: 包含 + `nin`: 不包含 + `like`: 全模糊查询 + `left_like`: 左模糊查询 + `right_like`: 右模糊查询 #### 概览
### xxl-job定时人场景启动器 > 基于`xxl-job`v2.4.0版本的执行器封装,实现配置化、插件化使用 #### 核心功能 参考官网 [xxl-job](https://github.com/xuxueli/xxl-job) #### 使用 ##### 引入依赖 ```xml com.dingwen xxl-job-spring-boot-starter 1.0.0-SNAPSHOT ``` ##### 启动项配置 > 在启动类上添加`@EnableXxlJob`注解以开启`xxl-job`定时任务场景功能 ``` @EnableXxlJob ``` > 配置xxl-job参数 ```yml dingwen: treasure: #xxl-job定时任务场景 xxljob: # 执行器开关 enabled: true adminAddresses: http://127.0.0.1:8003 #调度中心应用名 adminAppName: treasure-xxl-job-admin # 执行器通讯TOKEN accessToken: xxl-job-access-token # 执行器配置 executor: appName: scene #执行器日志文件保存天数:大于3生效 logRetentionDays: 10 # 执行器运行日志文件存储磁盘路径 【注意不要和项目本身log路径冲突】 logPath: logs/xxljob # 执行器端口号 port: 9999 ``` #### 概览
### 本地缓存启动器 > 基于`caffeine`实现的配置化的本地缓存 #### 核心功能 + 配置化实现,无需反锁的整合配置 + 基于`Spring cache`实现 + `@Cacheable`: 将方法的结果缓存起来,下一次方法执行参数相同时,将不执行方法,返回缓存中的结果 + `@CacheEvict`: 移除指定缓存 + `@CachePut`: 更新缓存 + `@Caching`: 可以指定相同类型的多个缓存注解,例如根据不同的条件 + `@CacheConfig`: 类级别注解,可以设置一些共通的配置,@CacheConfig(cacheNames=""), 代表该类下的方法均使用这个cacheNames + 提供丰富的API,可供前端页面展示 + 获取所有的缓存 + 获取所有的缓存项 + 获取缓存详情 + 清楚缓存 #### 使用 ##### 引入依赖 ```xml com.dingwen caffeine-spring-boot-starter 1.0.0-SNAPSHOT ``` ##### 启动项配置 > 在启动类上添加`@EnableCaffeine`注解以开启`caffeine`本地缓存场景功能 ```java @EnableCaffeine ``` ##### 缓存配置项 ```yml dingwen: treasure: # caffeine caffeine: caches: # 缓存Spring Bean名称 - name: testCache # 有效时间,单位秒 invalidTime: 60 # 最大缓存数量 maximumSize: 100 - name: fileCache invalidTime: 60 maximumSize: 1000 ``` ##### 使用 ```java package com.dingwen.treasure.scene.controller.caffeine; /** * Caffeine * * @author dingwen * @since 2023/5/22 16:20 */ @Api(tags = "本地缓存API") @RestController @Slf4j @RequestMapping("common/caffeine") @CacheConfig(cacheManager = "caffeineCacheManager") public class CaffeineController implements BaseViewController { @Resource(name = "testCache") @Lazy private CaffeineCache testCache; /** * 缓存测试 * * @return {@link ResultVO}<{@link String}> */ @ApiOperation("本地缓存测试") @Cacheable(cacheNames = "testCache") @GetMapping("/test") public ResultVO cache() { testCache.putIfAbsent("test", "test"); String test = testCache.get("test", String.class); log.info("test:{}", test); return success(test); } ``` #### 概览
### Redis启动器 > 基于`RedisTemplate`封装的启动器 #### 核心功能 + 常用API + 对象缓存 + 过期时间 + 缓存是否存在 + 删除缓存 + `List`,`Set`,`Map`缓存操作 + 发布订阅 + 自增自减 + 常用功能 + 通用逻辑轻松缓存 + 限流 + 防重 + 分布式锁 + 监控信息 + `Redis`信息 + 缓存信息 + 缓存预热统一封装 `RedisCache` + 分布式锁组件 `RedisShareLockComponent` + 基于`zset`实现延迟队列 #### 使用 ##### 引入依赖 ```xml com.dingwen redis-spring-boot-starter 1.0.0-SNAPSHOT ``` ##### 启动项配置 > 在启动类上添加`@EnableRedis`注解以开启`redis`场景功能 ```java @EnableRedis ``` ##### 配置项 ```yml dingwen: treasure: # redis redis: easy: # 开启easy cache cache: true rate: # 开启限流 limiter: true re: # 开启防重复提交 submit: true # 缓存项配置 caches: - keyPrefix: "re_submit:" remark: "防止重复提交" - keyPrefix: "common_lock:" remark: "通用锁" ``` ##### 使用案例 ```java package com.dingwen.treasure.scene.controller.redis; /** * Redis场景API * * @author dingwen * @since 2023/5/22 11:11 */ @Api(tags = "Redis缓存API") @RestController @Slf4j @RequestMapping("common/redis") public class RedisController implements BaseViewController { /** * redis 服务 */ @Resource private RedisService redisService; @Resource private RedisProperties redisProperties; /** * 得到Redis信息 * * @return {@link ResultVO} */ @ApiOperation("获取Redis信息") @GetMapping("/info") public ResultVO getInfo() { return success(redisService.getInfo()); } /** * 获取缓存项 * * @return {@link ResultVO}<{@link List}<{@link CacheVO}>> */ @ApiOperation(value = "获取缓存项") @GetMapping public ResultVO> getCaches() { List caches = redisProperties.getCaches(); List cacheVOS = BeanCopyUtils.copyList(caches, CacheVO.class); return success(cacheVOS); } /** * 获取指定前缀的所有key * * @param keyPrefix 关键前缀 * @return {@link ResultVO}<{@link Collection}<{@link String}>> */ @ApiOperation(value = "获取指定前缀的所有key") @ApiImplicitParam(name = "keyPrefix", value = "key前缀", dataTypeClass = String.class) @GetMapping("/{keyPrefix}") public ResultVO> getKeys(@PathVariable("keyPrefix") String keyPrefix) { return success(redisService.getKeys(keyPrefix + RedisConstant.KEY_ALL)); } /** * 获取缓存值 * * @param keyPrefix 关键前缀 * @param key 关键 * @return {@link ResultVO}<{@link CacheVO}> */ @ApiOperation(value = "获取指定key的缓存值") @ApiImplicitParams({ @ApiImplicitParam(name = "keyPrefix", value = "key前缀", dataTypeClass = String.class), @ApiImplicitParam(name = "key", value = "key", dataTypeClass = String.class) }) @GetMapping("/{keyPrefix}/{key}") public ResultVO getCache(@PathVariable("keyPrefix") String keyPrefix, @PathVariable("key") String key) { String cacheValue = redisService.getCacheObject(key); CacheVO cacheVO = CacheVO.builder() .keyPrefix(keyPrefix) .cacheKey(key) .cacheValue(cacheValue) .build(); return success(cacheVO); } /** * 清除指定key前缀的所有缓存 * * @param keyPrefix 关键前缀 * @return {@link ResultVO}<{@link String}> */ @ApiOperation(value = "清除指定key前缀的所有缓存") @ApiImplicitParam(name = "keyPrefix", value = "key前缀", dataTypeClass = String.class) @PutMapping("/{keyPrefix}") public ResultVO cleanCaches(@PathVariable("keyPrefix") String keyPrefix) { redisService.removeKeys(keyPrefix + RedisConstant.KEY_ALL); return success(); } /** * 清除指定key的缓存 * * @param key 关键 * @return {@link ResultVO}<{@link String}> */ @ApiOperation(value = "清除指定key的缓存") @ApiImplicitParam(name = "key", value = "key", dataTypeClass = String.class) @DeleteMapping("/{key}") public ResultVO cleanCache(@PathVariable("key") String key) { redisService.deleteObject(key); return success(); } /** * 清洗所有缓存 * * @return {@link ResultVO}<{@link String}> */ @ApiOperation(value = "清除所有缓存") @DeleteMapping public ResultVO cleanAllCache() { redisService.removeKeys(RedisConstant.KEY_ALL); return success(); } /** * 轻松缓存 * * @param easyCacheSubmitVO 轻松缓存提交内容 * @return {@link ResultVO}<{@link String}> */ @PostMapping("/easy-cache") @ApiOperation("轻松缓存测试") @EasyCache(keyParams = { "#easyCacheSubmitVO.getId()", "#easyCacheSubmitVO.getName()"}, time = 100, returnType = ResultVO.class) public ResultVO easyCache(@RequestBody EasyCacheSubmitVO easyCacheSubmitVO) { return success(easyCacheSubmitVO); } /** * 速率限制 * * @return {@link ResultVO}<{@link String}> */ @ApiOperation("redis限流测试") @GetMapping("/rate-limit") @RateLimiter(time = 1, count = 2) public ResultVO rateLimit() { return success(); } /** * 防止重复提交测试 */ @ApiOperation("防止重复提交测试") @GetMapping("/re-submit") @ReSubmit(message = "登录重复提交请求", isDeleteKey = false, time = 90) public void resubmit() { } /** * 锁
* redisson方案;... * * @return {@link ResultVO}<{@link String}> */ @ApiOperation("lock测试") @GetMapping("/lock") public ResultVO lock() { boolean ifAbsent = redisService.setIfAbsent(RedisKeyConstant.LOCK_PREFIX.concat("test"), "lock test", 1L, TimeUnit.MINUTES); // 剩余时间 long expire = redisService.getExpire(RedisKeyConstant.LOCK_PREFIX.concat("test"), TimeUnit.SECONDS); if (ObjectUtil.isNotNull(ifAbsent) && ifAbsent) { return success(); } String message = StrUtil.format("频繁的操作,请{}秒后重试", expire); return failure(message); } } ``` #### 缓存预热 > 继承抽象类`AbstractRedisCache`完成自身预热逻辑,由统一预热组件进行调用
#### 分布式锁组件 `RedisShareLockComponent` ```java /** * redis 分布式锁组件 * * @author dingwen * @since 2023/12/5 14:57 */ @Component @Slf4j public class RedisShareLockComponent { @Resource private RedisProperties redisProperties; @Resource private RedisService redisService; /** * 加锁å * * @param lockKey 锁key * @param requestId 请求id * @param time 时间 * @param timeUnit 时间单位 * @return boolean */ public boolean lock(String lockKey, String requestId, Long time, TimeUnit timeUnit) { // 参数检查 lockParamsCheck(lockKey, requestId, time, timeUnit); // 当前时间 long currentTime = System.currentTimeMillis(); // 超时时间 long outTime = currentTime + redisProperties.getShareLockTimeOut(); boolean lockResult = false; // 加锁 while (currentTime < outTime) { lockResult = redisService.setIfAbsent(lockKey, requestId, time, timeUnit); if (lockResult) { log.info("[Redis模块]\t[分布式锁],加锁成功:lockKey:{},requestId:{},time:{},timeUnit:{}", lockKey, requestId, time, timeUnit); return true; } ThreadUtil.sleep(100); currentTime = System.currentTimeMillis(); } return lockResult; } /** * 加锁参数检查 * * @param lockKey lock key * @param requestId request id * @param time time * @param timeUnit time unit */ private void lockParamsCheck(String lockKey, String requestId, Long time, TimeUnit timeUnit) { if (StrUtil.isBlank(lockKey) || StrUtil.isBlank(requestId) || time <= 0 || Objects.isNull(timeUnit)) { log.error("[Redis模块]\t[分布式锁],加锁参数错误:lockKey:{},requestId:{},time:{},timeUnit:{}", lockKey, requestId, time, timeUnit); throw new ShareLockException("加锁参数异常"); } } /** * 解锁 * * @param lockKey 锁keu * @param requestId 请求id * @return boolean */ public boolean unLock(String lockKey, String requestId) { if (StrUtil.isBlank(lockKey) || StrUtil.isBlank(requestId)) { throw new ShareLockException("解锁参数异常"); } try { String cacheRequestId = redisService.getCacheObject(lockKey); if (requestId.equals(cacheRequestId)) { redisService.deleteObject(cacheRequestId); return true; } } catch (Exception e) { log.error("[Redis模块]\t[分布式锁],解锁失败。lockKey:{},requestId:{}", lockKey, requestId, e); } return false; } /** * 尝试加锁方法 * * @param lockKey 锁key * @param requestId 请求id * @param time 时间 * @param timeUnit 时间单位 * @return boolean */ public boolean tryLock(String lockKey, String requestId, Long time, TimeUnit timeUnit) { // 参数检查 lockParamsCheck(lockKey, requestId, time, timeUnit); return redisService.setIfAbsent(lockKey, requestId, time, timeUnit); } } ``` #### 基于`zset`实现延迟队列 > 当我们有期望一个任务再某一个时间点再去执行,此时业务相对比较简单,不想引入Mq组件时可以考虑实用Redis实现延迟队列。 > 基于redis的zset实现,zset天生具有score的特性。可以根据score放入,而且可以通过range进行排序获取,以及删除指定的值。从业务上,我们可以再新增任务的时候放入,再通过定时任务进行拉取,要注意的一点就是拉取的时候要有分布式锁,保证不进行重复拉取就可以了。
#### 概览
### 电子邮件启动器 > 基于`sun.mail`实现的可配置的电子邮件使用场景 #### 使用 ##### 引入依赖 ```xml com.dingwen email-spring-boot-starter 1.0.0-SNAPSHOT ``` ##### 启动项配置 > 在启动类上添加`@EnableEmail`注解以开启电子邮件场景功能 ``` @EnableEmail ``` #### 配置项 ```yml dingwen: treasure: # 电子邮件 email: enabled: true # SMTP服务器域名 host: smtp.163.com port: 465 # 是否需要用户名密码验证 auth: true # 发送方,遵循RFC-822标准 from: dingwen0314@163.com # 用户名(注意:如果使用foxmail邮箱,此处user为qq号) user: dingwen0314@163.com # 密码(注意,某些邮箱需要为SMTP服务单独设置密码,详情查看相关帮助) pass: TODO # 使用 STARTTLS安全连接,STARTTLS是对纯文本通信协议的扩展。 starttlsEnable: true # 使用SSL安全连接 sslEnable: true # SMTP超时时长,单位毫秒,缺省值不超时 timeout: 0 # Socket连接超时值,单位毫秒,缺省值不超时 connectionTimeout: 0 ``` #### 使用 ```java /** * 发送电子邮件 */ @Test public void sendEmail() { String messageId = MailUtils.sendText("1981723769@qq.com", "test", "测试邮件内容"); System.out.println(messageId); } ``` #### API概览
### 进度条启动器 > 基于`Redis`实现的多线程任务调度的进度条任务场景 #### 核心功能 + 提供模板类,封装通用逻辑 + 提供丰富API接口 + 任务提交 + 查询进度 #### 使用 ##### 引入依赖 ```xml com.dingwen bar-spring-boot-starter 1.0.0-SNAPSHOT ``` ##### 启动项配置 > 在启动类上添加`@EnableBar`注解以开启进度条场景功能 ``` @EnableBar ``` #### 概览
### PipeLine启动器 > 工厂模式 + 策略模式 + 门面模式 + 模板方法 实现的定制化配置化规则引擎 #### 核心功能 + 抽象上下文,实现通用逻辑`PipelineContext` + 异步执行管道支持 + 外部配置化的管道流 + 注解式的管道前后进行过滤操作 + 详尽的日志追踪 + 提供测试案例 #### 使用 ##### 引入依赖 ```xml com.dingwen pipeline-spring-boot-starter 1.0.0-SNAPSHOT ``` ##### 启动项配置 > 在启动类上添加`@EnablePipeline`注解以开启`pipeLine`场景功能 ```java @EnablePipeline ``` #### 配置项 ```yaml dingwen: treasure: # pipeline pipeline: routes: # 管道上下文名称 key testContext: # 第一个执行的管道 - onePipeLine # 第二个执行的管道 - twoPipeLine ``` ```java // 配置管道过滤器 @PipeFilters(filters = { @PipeFilter(beanName = "beforeOneFilter",exePoint = PipelineFilterExePoint.ALL), @PipeFilter(beanName = "beforeTwoFilter",exePoint = PipelineFilterExePoint.BEFORE), }) ``` #### 核心类 + `PipelineContext`管道上下文 + `Pipeline`管道接口 + `PipelineFilter`管道过滤器接口 + `@PipeFilter`过滤器注解 + `PipelineFactory`管道执行工厂 + `PipelineExecutor`管道执行器 #### 概览
### OSS启动器 > 基于亚马逊`S3`封装的支持阿里云,`Minio`等多种存储方式的对象存储通用业务场景启动器 #### 使用 ##### 引入依赖 ```xml com.dingwen oss-spring-boot-starter 1.0.0-SNAPSHOT ``` ##### 启动项配置 > 在启动类上添加`@EnableOss`注解以开启`oss`场景功能 ``` @EnableOss ``` #### 配置项 ```yml dingwen: treasure: # oss oss: # 对象存储服务的URL endpoint: http://127.0.0.1:9000 # key access-key: admin # 密钥 secret-key: 1234567890 # 路径风格 path-style-access: true # 最大线程数 max-connections: 100 # 区域 region: ``` #### `OssTemplate`操作API
### mybatis-plus启动器 > 基于`MybatisPlus`的二次封装 #### 核心功能 + 统一实体 + 统一查询对象 + 场景异常封装处理 + 逻辑删除 + 枚举处理 + 通用字段填充 + 创建人 + 创建时间 + 修改人 + 修改时间 + 多租户 + 数据权限 + 通用选项查询组件 + 完整`SQL`日志打印 + `SQL`执行耗时 + 通用字符串字段长度校验组件 + 同一数据唯一性校验组件 #### 使用 ##### 引入依赖 ```xml com.dingwen mybatisplus-spring-boot-starter 1.0.0-SNAPSHOT ``` ##### 启动项配置 > 在启动类上添加`@EnableMybatisPlus`注解以开启`mybatisplus`场景功能 ``` @EnableMybatisPlus ``` #### 选项查询通用组件 > 当你需要查询某个数据作为下拉选项时可使用此组件,支持四级选项、数据权限、中间表关联。已实现本地缓存优化。 ##### 三级关联查询 ```java @Test void testOpForLevel3() { List opParams = new ArrayList<>(); OpParam unitOpParam = OpParam .builder() .labelField("unit_name") .valueField("unit_id") .tableName("hom_u_unit") .build(); OpParam deptOpParam = OpParam .builder() .labelField("t1.dept_name") .valueField("t1.dept_id") .tableName("sys_dept t1") .leftJoinField(", t2.dept_id") .leftJoinSql("left join hom_u_unit_lnk_dept t2 on t1.dept_id = t2.dept_id") .parentField("t2.unit_id") .build(); OpParam usertOpParam = OpParam .builder() .labelField("user_name") .valueField("user_id") .tableName("sys_user") .parentField("dept_id") .build(); opParams.add(unitOpParam); opParams.add(deptOpParam); opParams.add(usertOpParam); List