From 91325c062b1f9d3032f1e82c66c686286cd0b53e Mon Sep 17 00:00:00 2001 From: clay <20932067@zju.edu.cn> Date: Wed, 10 May 2023 23:56:56 +0800 Subject: [PATCH] =?UTF-8?q?clay=20commit=20:=20=E6=96=B0=E5=86=85=E5=AE=B9?= =?UTF-8?q?=E7=BC=96=E5=86=99?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/module/common/README.md | 331 ++++++++++++++++++++++++----------- docs/module/common/img.png | Bin 0 -> 27400 bytes 2 files changed, 225 insertions(+), 106 deletions(-) create mode 100644 docs/module/common/img.png diff --git a/docs/module/common/README.md b/docs/module/common/README.md index 298bf40..09bfff2 100644 --- a/docs/module/common/README.md +++ b/docs/module/common/README.md @@ -1,8 +1,9 @@ # 系统公共模块 -系统公共模块主要对集群中的基础公共工具进行封装,现阶段对如需模块进行封装: +系统公共模块主要对集群中的基础公共工具进行封装,提供更加高效的开发效率 -## common-core 基础核心组件 -对系统中的基础服务实体进行定义,基础的工具类进行定义.例如: +## common-core +### 简介 +对系统中的基础服务实体进行定义,基础的工具类进行定义.例如:list转Tree工具类,反射方式获取到用户信息等 ### TreeUtil 自定义树形结构实体转换,可以将A对象结构具有树形关系的list转换成B对象的树形结构, 可以自定义A B两个对象之间的映射关系例如: @@ -61,10 +62,22 @@ List optionTreeList = TreeUtil.build(deptList,OptionTree.class,(conf - exclude排除字段 ## common-dubbo -对dubbo的基础依赖 +### 简介 +对dubbo的基础依赖进行引入,后期进行全局的dubbo功能封装 ## common-log -自定义操作日志模块,完成使用自定义注解实现操作日志的记录 +### 简介 +自定义操作日志模块,完成使用自定义注解`@Log`实现操作日志的记录 +`@Log`注解参数说明 + +| 参数 | 类型 | 默认 | 描述| +| :-- | :-- | :-- | :-- | +| title | String | 空 | 日志记录名称 | +| businessType | BusinessType | OTHER | 功能,具体操作有 OTHER,INSERT,UPDATE,DELETE,GRANT,EXPORT,IMPORT,FORCE,GENCODE,CLEAN,BIND | +| operatorType | OperateType | MANAGE | 操作人类别 | +| isSaveRequestData | boole | 空 | 是否保存请求的参数 | + +### 使用 ```javascript @ApiOperation("新增部门") @PostMapping @@ -80,116 +93,68 @@ public Result add(@RequestBody @Validated Dept dept){ ``` 通过LogAspect实现当前注解的apo切面,切面中将操作的日志封装成一个操作日志对象,然后使用spring的事件发布机制发布这个日志操作对象,再使用OperationLogListener异步监听到发布的事件,再通过rpc远程调用到umps中的日志存储接口,将当前对象落地到数据库 -`@Log`注解参数说明 -|参数 | 类型 | 默认 | 描述| -| :-- | :-- | :-- | :-- | -| title | String | 空 | 日志记录名称 | -| businessType | BusinessType | OTHER | 功能,具体操作有 OTHER,INSERT,UPDATE,DELETE,GRANT,EXPORT,IMPORT,FORCE,GENCODE,CLEAN,BIND | -| operatorType | OperateType | MANAGE | 操作人类别 | -| isSaveRequestData | boole | 空 | 是否保存请求的参数 | + ## common-mybatis -为了更加方便的使用系统分页,我们对mybatis的pageHelper做了一些封装 -### PageUtils类 -```javascript -/** - * 分页工具类 - * - * @author Clay - * @date 2022/10/30 - */ -public class PageUtils extends PageHelper { +### 简介 +对mybatis的分页插件进行封装,使用注解+aop+mybatis拦截器实现自动注入用户信息或者时间 - /** - * 设置请求分页 - */ - public static void startPage() { - Page page = TableSupport.buildPageRequest(); - Integer pageNum = page.getPageNum(); - Integer pageSize = page.getPageSize(); - String orderBy = SqlUtil.escapeOrderBySql(page.getOrderBy()); - Boolean reasonable = page.getReasonable(); - PageHelper.startPage(pageNum, pageSize, orderBy).setReasonable(reasonable); - } - - /** - * 开始的Size - * - * @param page - * @return - */ - public static Integer getStartSize(Page page) { - return (page.getPageNum() - 1) * page.getPageNum(); - } - - public static Integer getStartSize() { - Page page = TableSupport.buildPageRequest(); - return (page.getPageNum() - 1) * page.getPageSize(); - } - - /** - * 获取到分页后的数据信息 - * - * @param list - * @param - * @return - */ - public static TableDataInfo getDataTable(List list) { - if (null == list) { - return new TableDataInfo<>(new ArrayList<>(), 0); - } - TableDataInfo tableDataInfo = new TableDataInfo<>(); - tableDataInfo.setRows(list); - tableDataInfo.setTotal(getTotal(list)); - return tableDataInfo; - } - - /** - * 获取到分页的总数 - * - * @param list - * @return - */ - public static Long getTotal(List list) { - long total = new PageInfo<>(list).getTotal(); - clearPage(); - return total; - } - - /** - * 转换为TableDataInfo对象 - * - * @param list - * @param count - * @param - * @return - */ - public static TableDataInfo convertDataTable(List list, Long count) { - if (null == list) { - return new TableDataInfo<>(new ArrayList<>(), 0); - } - TableDataInfo tableDataInfo = new TableDataInfo<>(); - tableDataInfo.setRows(list); - tableDataInfo.setTotal(count); - return tableDataInfo; - } - - - /** - * 清理分页的线程变量 - */ - public static void clearPage() { - PageHelper.clearPage(); - } -} -``` ### 分页操作 只需要在执行SQL的Mapper之前调用`PageUtils.startPage()`方法,然后调用SQL执行方法,再使用获取到的数组调用PageUtils.getDataTable(list)方法获取到封装好的返回结果对象即。 +- 代码演示 +```java +@Override +public TableDataInfo searchDemoList(DemoQuery query) { + PageUtils.startPage(); + List list = demoMapper.selectDemoList(query); + Long total = PageUtils.getTotal(list); + List convertList = list.stream().map(DemoVo::toDemoVo).collect(Collectors.toList()); + return PageUtils.convertDataTable(convertList, total); +} +``` +> 注意,上方代码为需要将Demo 转换为 DemoVo 如果无需转换,则可直接调用`PageUtils.getDataTable(list)`方法 + +### 自动注入能力 +自动注入使用场景为,当实体累中在特定的时间或者业务之下,需要设置一些固定的参数时,可以使用到此功能,列如当实体类中存在createBy,createTime,updateBy,updateTime等固定字段,在创建和更新的时候都需要固定的设置参数时,可以使用到此功能 + +- `@EnableAutoField` 开启mybatis的自动注入能力 +- `@GenerateId` 自动生成id并注入 +- `@AutoUser` 自动注入一些用户信息 +- `@AutoTime` 自动注入时间 + +#### `@GenerateId`注解参数说明 +|参数 | 类型 | 默认 | 描述| +| :-- | :-- | :-- | :-- | +| idType | GenIdEnum | UUID | 需要生成的id类型 | + +`@GenerateId`为实现需要指定id时候使用,可以自动生成指定类型的id,并注入其中,支持UUID的生成 + +#### `@AutoUser`注解参数说明 +|参数 | 类型 | 默认 | 描述| +| :-- | :-- | :-- | :-- | +| value | AutoUserEnum | USER_NAME | 需要注入的用户信息 | +| method | MethodEnum | 空 | 指定SQL执行方法下进行自动注入 | +`@AutoUser`可以根据用户需要设置那种用户信息和具体SQL执行的那种类型的方法情况下自动注入需要的信息 + +#### `@AutoTime`注解参数说明 +|参数 | 类型 | 默认 | 描述| +| :-- | :-- | :-- | :-- | +| method | MethodEnum | 空 | 指定SQL执行方法下进行自动注入 | +`@AutoTime`可以根据SQL执行的方法类型进行匹配,自动创建时间对象并注入 ## common-file +### 简介 在集群环境下,文件不能够单独放置在某一个单一节点执行,需要集中存储起来,我们提供了阿里云的oss,自建服务的minio以及轻量化的ftp三种模式 ### 使用 1. 将依赖引入到对应的pom.xml中 +```xml + + + cn.odliken + common-file + +``` + 2. 在yml文件中配置好信息 ```yml file: @@ -219,20 +184,174 @@ file: # 需要保密的文件资源 prifiles: prifiles ``` +3. 注入`FileStoreService`接口,需要指定使用那种类型的文件储存,也可以直接注入具体的实现类 + +```java +/** + * 文件存储服务接口类 + * + * @author Clay + * @date 2023-02-16 + */ +public interface FileStoreService { + + /** + * 创建文件桶 + * + * @param bucketName 桶名 + * @return 创建结果 + */ + Boolean createBucket(String bucketName); + + /** + * 删除文件桶 + * + * @param bucketName 桶名 + * @return 删除结果 + */ + Boolean deleteBucket(String bucketName); + + /** + * 上传文件 + * + * @param file 文件对象 + * @return FileInfo对象 + */ + FileInfo upload(MultipartFile file); + + /** + * 上传文件 + * + * @param bucket 文件桶名 + * @param file 文件对象 + * @return FileInfo对象 + */ + FileInfo upload(String bucket, MultipartFile file); + + /** + * 下载文件 + * + * @param fileUri 文件的资源定位符 + * @return 文件流 + */ + InputStream download(String fileUri); + + /** + * 下载文件 + * + * @param bucket 文件桶名 + * @param fileUri 文件的资源定位符 + * @return 文件流 + */ + InputStream download(String bucket, String fileUri); + + /** + * 删除文件 + * + * @param fileUri 文件的资源定位符 + * @return 删除状态 + */ + Boolean delete(String fileUri); + + /** + * 删除文件 + * + * @param bucket 文件桶名 + * @param fileUri 文件的资源定位符 + * @return 删除状态 + */ + Boolean delete(String bucket, String fileUri) throws IOException; +} +``` + +4. `FileStoreCombinationService`类可以直线多种对象存储混合使用,只需要在方法上添加上需要指定的储存类型枚举即可 + ## common-redis -使redis使用FastJson序列化,对RedisTemplate进行进一步的函数封装 +### 简介 +对redis中`RedisTemplate`进行了fastjson序列化的封装,也保留了原本的Java序列化方式 + +对fastjson序列化封装的`RedisTemplate`进行了进一步的封装实现了`RedisService`,让开发者更方便的使用 ## common-security +### 简介 集群中最核心的部分,spring security 安全校验封装,自定义PermissionService实现spring security自定校验方法,实现自定义校验逻辑,使用Inner注解实现集群内rpc远程调用接口的区分 ## common-swagger +### 简介 swagger接口文档配置,通过SwaggerConfig类从nacos中获取到当前服务对应的swagger配置信息,生成当前服务的swagger接口文档数据,配合gateway swagger聚合生成集群的swagger聚合文档 +解决swagger聚合文档请求/v3/doc-api接口时,swaggerui无法发起请求的bug +### 使用 +1. 引入配置 +```xml + + + cn.odliken + common-swagger + +``` +2. 在yml中填写好配置信息 +```yaml +swagger: + title: 演示api文档 + description: 演示api文档 +``` +## common-email +### 简介 +为系统提供最基础的邮件发送功能,其中实现同步邮件发送和异步邮件发送两种功能实现 +### 使用 +1. 引入依赖 +```xml + + + cn.odliken + common-email + +``` +2. 在yml中填写好配置信息 +```yaml +email: + sender: 发送人邮箱 + personal: 发送人名称 + email-smtp-host: 邮件服务器 + email-smtp-port: 邮件服务器端口 + username: 发送人用户名 + password: 发送人密码 + encryption: 加密协议 +``` +3. 使用 +注入`EmailService`后,使用`EmailService`中的同步发送邮件或者异步发送邮件即可进行邮件发送 +## common-lock +### 简介 +为系统提供分布式锁的能力,采用的是redisson实现,其中使用注解+aop+反射实现防重复提交和接口的分布式锁访问两大功能,并对提供封装好的分布式锁服务类 +### 防重复提交 +防重复提交是指在进行数据提交的过程中,防止用户重复提交相同的数据或者重复执行同一操作的一种技术手段。这种技术手段的主要目的是避免数据的重复录入或者重复操作所带来的不必要的麻烦和风险,同时也可以提高应用程序的稳定性和可靠性。系统使用后端校验+分布式锁的方式实现 +### 使用 +1. 引入依赖 +```xml + + cn.odliken + common-lock + +``` +2. 在接口上添加注解 +```java +@PostMapping +@ResubmitLock +public Result login(@Validated @RequestBody LoginBody login) { + return Result.ok("操作成功"); +} +``` +3. 拦截效果 +![img.png](img.png) + +### 通用分布式锁 +通用分布式锁主要通过 diff --git a/docs/module/common/img.png b/docs/module/common/img.png new file mode 100644 index 0000000000000000000000000000000000000000..1fc9cd2763847cd441399700daa5dac70af8b471 GIT binary patch literal 27400 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%0D@HBli7P!P>vY>o!#qqo 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%0AK?BJQa>JHsHLjTzT7x)=oHAecI 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 aK~;G_ns}Y)^bOL|-hYIC#QNai=l=vcaw(?( literal 0 HcmV?d00001