目录
- 前言
- 实现思路
- 技术确定
- 食用方式
- 效果
- 使用样例
- 项目中使用
- 第一步 复制包
- 第二步 实现LoadDictDatabase并将其注入容器
- 第三步 标识需要翻译的字段
- 第四步 标识需要翻译的方法
- 第五步 调用需要翻译的方法
- 实现细节
- TODO
前言
字典,即在存储介质中进行存储时,为了避免业务上对其名称的调整,所以存储其编码,在进行展示时,将其中文展示出来.我了解到,早期还有中可能是: 存储中文时,有编码问题. 不过我觉得这种说法无法成立,如果面向的用户是中国用户,系统就不可能不存中文.
我的这种实现方式,不仅帮组实现了字典翻译的业务, 还用到了设计模式和一些技术,二次拓展方便,值得一学.
实现思路
技术确定
在展示时,将字典翻译成显示值,那什么时候翻译呢? 有一种说法是将字典对应的编码返回到前端,让前端展示的时候再翻译. 但是这样我想到了两个问题
- 后端在业务上中有可能也需要使用中文名称的, 比如生成文件,根据业务信息生成Word文件、PDF文件等等
- 字典的缓存处理,前端如何存储系统的字典,如何刷新缓存呢?我对前端不太了解,但是后端显而易见的处理方式是用redis
在我一步一步的尝试和完善下,最终落地的方案是:
-
后端翻译
-
AOP+自定义注解: 精确指定需要翻译的字段和方法
-
动态三级缓存: 模拟经典的 '高速缓存-内存-硬盘’三级缓存,实现了’内存-redis-数据库’三级缓存链,并且redis不是必须的,可以根据项目中是否引入,来动态的组装缓存链.当redis未使用时,会自动组装成’内存-数据库’两层缓存链
-
多种转换方式: 有三种: 指定数据库(或redis或程序内存)中的字典、指定程序中已有的枚举类、手动指定
-
责任链: 在这小小枚举翻译中,有两处用到了责任链: 命中的缓存和翻译的方式
- 命中的缓存: 根据缓存链构建的顺序,如果当前级别命中不到,会丢给下一级缓存,如果在下一级找到了,还会缓存到本级. 下一级的处理逻辑也是如此,直到找到了缓存, 或者全都没找到缓存,返回源字典编码
食用方式
效果
先上效果图,在实体上配置如下
最后翻译出的结果如下
使用样例
源码地址: gitee源码
源码中的spring-ordinary项目,有字典翻译的源码和使用样例,
字典源码: com.ql.ordinary.common.dict包中
使用样例: com.ql.ordinary.rest.DictConvertTestController
如果需要需要查看样例效果,需要以下步骤
- 拉取源代码
- 更改配置文件中的mysql配置和redis配置
- 在mysql指定的库中执行spring-ordinary/db/sys-dict.sql脚本
- 启动服务
- 调用接口: http://localhost:6660/dict/convert/student/list
如果以上步骤都能成功,那么将看到效果图的的样子
项目中使用
在自己项目中使用,需要如下步骤
第一步 复制包
拉取源代码并复制包. 源码地址: gitee源码
现在只有一种使用方式: 将 com.ql.ordinary.common.dict整个包中的类复制到自己的项目中, 后续会考虑做成starter或者放到maven公共仓库中
如果没有使用redis,
- 删除项目中引用的redis相关类
- 取消RedisDictCache的注入
第二步 实现LoadDictDatabase并将其注入容器
com.ql.ordinary.common.dict.service.LoadDictDatabase接口中定义了从数据库中获取字典的方法, 不关心你是怎么从数据库中获取, 也不关心是从什么数据库中获取的. 只需要通过这个接口获取结果
第三步 标识需要翻译的字段
Dict 注解用来标识需要翻译的字段,有多种翻译方式. 详见类上的注释
第四步 标识需要翻译的方法
DictMethod注解用来标识需要翻译的方法,如果没有标识方法,只标识字段,也是没用的.
第五步 调用需要翻译的方法
调用被DictMethod标识的方法,拿到的结果就是被翻译了的结果
实现细节
待补充
TODO
- 做成一个starter或者放到公共的maven仓库中
- 支持对map的翻译,