基于mybatis-plus的多语言扩展

概览

对于表中字段,需要实现多语言的方案探讨:

1.表中横向扩展多个字段分别存储中文,英文,俄语等语言字段,查询时,根据需要查询的语言,进行查询

2.增加一张多语言表,存储多语言信息,如图,同时基于mybatis-plus扩展插入更新查询等功能,完成代码无侵入的多语言功能


一、组件的开发

1.自定义重写sql注入器ZlxSqlInjector

  @Overridepublic void inspectInject(MapperBuilderAssistant builderAssistant, Class<?> mapperClass) {Class<?> modelClass = ReflectionKit.getSuperClassGenericType(mapperClass, Mapper.class, 0);if (modelClass != null) {String className = mapperClass.toString();Set<String> mapperRegistryCache = GlobalConfigUtils.getMapperRegistryCache(builderAssistant.getConfiguration());if (!mapperRegistryCache.contains(className)) {List<AbstractMethod> methodList = this.getMethodList(mapperClass);if (CollectionUtils.isNotEmpty(methodList)) {ZlxTableInfo tableInfo = ZlxTableInfoHelper.initTableInfo(builderAssistant, modelClass,className);// 循环注入自定义方法methodList.forEach(m -> m.inject(builderAssistant, mapperClass, modelClass, tableInfo));} else {log.debug(mapperClass.toString() + ", No effective injection method was found.");}mapperRegistryCache.add(className);}}}@Overridepublic List<AbstractMethod> getMethodList(Class<?> mapperClass) {return Stream.of(new com.zenglx.multilanguage.method.Insert(),new Delete(),new DeleteByMap(),new DeleteById(),new DeleteBatchByIds(),new Update(),new UpdateById(),new com.zenglx.multilanguage.method.SelectById(),new com.zenglx.multilanguage.method.SelectBatchByIds(),new SelectByMap(),new com.zenglx.multilanguage.method.SelectOne(),new com.zenglx.multilanguage.method.SelectCount(),new SelectMaps(),new SelectMapsPage(),new SelectObjs(),new com.zenglx.multilanguage.method.SelectList(),new com.zenglx.multilanguage.method.SelectPage()).collect(toList());}

2.自定义元数据和方法

@Getter
@Setter
public class ZlxTableInfo extends TableInfo {private String condition = SqlCondition.EQUAL;/*** 多语言字段*/private Set<TableFieldInfo> multiLanguageColumns = new HashSet<>();/*** 实体类 => 主键信息*/private Set<TableFieldInfo> entityClassPkColumns = new HashSet<>();/*** 实体类 => 全部列*/private Set<TableFieldInfo> entityClassColumns = new HashSet<>();/*** 是否多语言*/private boolean multiLanguage;public ZlxTableInfo(Class<?> entityType) {super(entityType);}public List<String> multiLanguageColumns() {return multiLanguageColumns.stream().map(TableFieldInfo::getColumn).collect(Collectors.toList());}/*** 获取所有的查询的 sql 片段** @param ignoreLogicDelFiled 是否过滤掉逻辑删除字段* @param withId              是否包含 id 项* @param prefix              前缀* @return sql 脚本片段*/@Overridepublic String getAllSqlWhere(boolean ignoreLogicDelFiled, boolean withId, final String prefix) {final String newPrefix = prefix == null ? EMPTY : prefix;String filedSqlScript = super.getFieldList().stream().filter(i -> {if (ignoreLogicDelFiled) {return !(isWithLogicDelete() && i.isLogicDelete());}return true;}).map(i -> getSqlWhere(newPrefix,i)).filter(Objects::nonNull).collect(joining(NEWLINE));if (!withId || StringUtils.isBlank(super.getKeyProperty())) {return filedSqlScript;}String newKeyProperty = newPrefix + super.getKeyProperty();String keySqlScript = super.getKeyColumn() + EQUALS + SqlScriptUtils.safeParam(newKeyProperty);return SqlScriptUtils.convertIf(keySqlScript, String.format("%s != null", newKeyProperty), false)+ NEWLINE + filedSqlScript;}private String convertIfProperty(String prefix, String property) {return StringUtils.isNotBlank(prefix) ? prefix.substring(0, prefix.length() - 1) + "['" + property + "']" : property;}/*** 获取 查询的 sql 片段** @param prefix 前缀* @return sql 脚本片段*/public String getSqlWhere(final String prefix,TableFieldInfo tableFieldInfo) {final String newPrefix = prefix == null ? EMPTY : prefix;// 默认:  AND column=#{prefix + el}String sqlScript = " AND " + String.format(condition, tableFieldInfo.getColumn(), newPrefix + tableFieldInfo.getEl());if(this.getMultiLanguageColumns().contains(tableFieldInfo)) {sqlScript = " AND " + String.format(condition, "t."+tableFieldInfo.getColumn(), newPrefix + tableFieldInfo.getEl());}// 查询的时候只判非空return convertIf(sqlScript, convertIfProperty(newPrefix, convertIfProperty(newPrefix, tableFieldInfo.getProperty())), tableFieldInfo);}/*** 转换成 if 标签的脚本片段** @param sqlScript     sql 脚本片段* @param property      字段名* @param tableFieldInfo 验证策略* @return if 脚本片段*/private String convertIf(final String sqlScript, final String property, TableFieldInfo tableFieldInfo) {if (tableFieldInfo.getWhereStrategy() == FieldStrategy.NEVER) {return null;}if (tableFieldInfo.isPrimitive() || tableFieldInfo.getWhereStrategy() == FieldStrategy.IGNORED) {return sqlScript;}if (tableFieldInfo.getWhereStrategy() == FieldStrategy.NOT_EMPTY && tableFieldInfo.isCharSequence()) {return SqlScriptUtils.convertIf(sqlScript, String.format("%s != null and %s != ''", property, property),false);}return SqlScriptUtils.convertIf(sqlScript, String.format("%s != null", property), false);}}
public class SelectById extends com.baomidou.mybatisplus.core.injector.methods.SelectById {@Overridepublic MappedStatement injectMappedStatement(Class<?> mapperClass, Class<?> modelClass, TableInfo tableInfo) {ZlxTableInfo zlxTableInfo = (ZlxTableInfo)tableInfo;if(zlxTableInfo.isMultiLanguage()) {SqlMethod sqlMethod = SqlMethod.SELECT_BY_ID;String scriptSql = "<script>SELECT %s FROM %s WHERE %s \n</script>";String sql = String.format(scriptSql, SqlHelper.getAllColumns(tableInfo), SqlHelper.selectFromTableTl(tableInfo),sqlWhereEntityWrapper(true, tableInfo));SqlSource sqlSource = languageDriver.createSqlSource(configuration, sql, modelClass);return this.addSelectMappedStatementForTable(mapperClass, getMethod(sqlMethod), sqlSource, tableInfo);} else {return super.injectMappedStatement(mapperClass, modelClass, tableInfo);}}@Overrideprotected String sqlWhereEntityWrapper(boolean newLine, TableInfo tableInfo) {ZlxTableInfo zlxTableInfo = (ZlxTableInfo)tableInfo;if(zlxTableInfo.isMultiLanguage()) {StringBuilder sb = new StringBuilder();sb.append("b.").append(zlxTableInfo.getKeyColumn()).append("=#{id}");return sb.toString();} else {return super.sqlWhereEntityWrapper(newLine, tableInfo);}}
}

3.自定义拦截器

 public class ZlxMultiLanguageInterceptor extends PaginationInnerInterceptor {@Overridepublic void beforeUpdate(Executor executor, MappedStatement statement, Object parameter) throws SQLException {ZlxTableInfo tableInfo = ZlxTableInfoHelper.getTableByMapper(getMapperClassName(statement.getId()));if (tableInfo != null && tableInfo.isMultiLanguage()) {Connection connection = executor.getTransaction().getConnection();switch (statement.getSqlCommandType()) {case INSERT:insertMultiLanguage(tableInfo, parameter, connection);break;case UPDATE:List<String> columnNameList = tableInfo.getEntityClassColumns().stream().map(TableFieldInfo::getColumn).collect(Collectors.toList());updateMultiLanguage(tableInfo, parameter, connection, new HashSet<>(columnNameList));break;case DELETE:proceedDeleteMultiLanguage(tableInfo, parameter, connection);break;default:break;}}}}

二、组件的使用

1.新建表

原表t_user,多语言表t_user_tl

2.引入库

<dependency><groupId>com.zenglx.multilanguage</groupId><artifactId>multilanguage-spring-boot-starter</artifactId><version>1.0-SNAPSHOT</version>
</dependency>

3.demo验证测试

 

@RequestMapping("/v1/demo")
public class DemoController {@Autowiredprivate UserService userService;/*** 新增用户** @return*/@PostMappingpublic ResponseEntity add(@RequestBody User user) {userService.save(user);return ResponseEntity.ok("成功");}/*** 用户详情** @return*/@GetMappingpublic ResponseEntity<User> get(@RequestParam("id") Long id) {return ResponseEntity.ok(userService.getById(id));}/*** 查询用户列表** @return*/@GetMapping("/list")public ResponseEntity<List<User>> list() {return ResponseEntity.ok(userService.list());}/*** 更新用户** @return*/@PutMappingpublic ResponseEntity update(@RequestBody User user) {userService.update(user,null);return ResponseEntity.ok("成功");}/*** 删除用户** @return*/@DeleteMappingpublic ResponseEntity delete(@RequestParam("id") Long id) {userService.removeById(id);return ResponseEntity.ok("成功");}@GetMapping("/page")public ResponseEntity<Page<User>> page(@RequestParam(required = false, value = "name") String name,@RequestParam(defaultValue = "1", value = "page") Integer page,@RequestParam(defaultValue = "10", value = "pageSize") Integer pageSize) {Page<User> param = new Page<>(page,pageSize);LambdaQueryWrapper<User> lambdaQueryWrapper = new LambdaQueryWrapper<>();lambdaQueryWrapper.like(StringUtils.hasText(name),User::getName,name);Page<User> userPage = userService.page(param,lambdaQueryWrapper);return ResponseEntity.ok(userPage);}

   a.用户添加

b.用户查询


总结

可运行源码

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/pingmian/17363.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

IC开发——VCS基本用法

1. 简介 VCS是编译型verilog仿真器&#xff0c;处理verilog的源码过程如下&#xff1a; VCS先将verilog/systemverilog文件转化为C文件&#xff0c;在linux下编译链接生成可执行文件&#xff0c;在linux下运行simv即可得到仿真结果。 VCS使用步骤&#xff0c;先编译verilog源…

STM32--ADC

一、简介 *ADC&#xff08;Analog-Digital Converter&#xff09;模拟-数字转换器 *ADC可以将引脚上连续变化的模拟电压转换为内存中存储的数字变量&#xff0c;建立模拟电路到数字电路的桥梁 *12位逐次逼近型ADC&#xff0c;1us转换时间 *输入电压范围&#xff1a;0~3.3V&…

redisson 释放分布式锁 踩坑

java.lang.IllegalMonitorStateException: attempt to unlock lock, not locked by current thread by node id: 48c213c9-1945-4c1b-821e-6d32e347eb44 thread-id: 69 出错代码&#xff1a; private void insertHourLog(Timestamp lastHourStartTimeStamp) {RLock lock red…

leetcode 1241每个帖子的评论数(postgresql)

需求 编写 SQL 语句以查找每个帖子的评论数。 结果表应包含帖子的 post_id 和对应的评论数 number_of_comments 并且按 post_id 升序排列。 Submissions 可能包含重复的评论。您应该计算每个帖子的唯一评论数。 Submissions 可能包含重复的帖子。您应该将它们视为一个帖子。…

BI工具如何为金融行业带来变革?金融行业营销管理策略大揭秘

当今数字化时代&#xff0c;金融行业正经历着前所未有的变革。随着大数据、人工智能、区块链等新兴技术的兴起&#xff0c;金融机构正面临着重新定义服务模式、风险管理和客户体验的挑战。商业智能&#xff08;BI&#xff09;作为这一变革的关键驱动力&#xff0c;已经成为金融…

ComfyUI工作流网站

https://openart.ai/home https://comfyworkflows.com/ https://civitai.com/

claude3国内API接口对接

众所周知&#xff0c;由于地理位置原因&#xff0c;Claude3不对国内开放&#xff0c;而国内的镜像网站使用又贵的离谱&#xff01; 因此&#xff0c;团队萌生了一个想法&#xff1a;为什么不创建一个一站式的平台&#xff0c;让用户能够通过单一的接口与多个模型交流呢&#x…

视频营销的智能剪辑:Kompas.ai如何塑造影响力视频内容

引言&#xff1a; 在当今数字化的营销领域&#xff0c;视频内容已经成为品牌吸引用户注意力、建立品牌形象和提升用户参与度的重要方式。然而&#xff0c;要想制作出具有影响力的视频内容&#xff0c;并不是一件容易的事情。这就需要借助先进的技术和工具&#xff0c;如人工智能…

2024开放式蓝牙耳机推荐,五款性价比最高的耳机推荐

在我们的日常生活中&#xff0c;无论是上下班通勤还是锻炼身体&#xff0c;耳机都是我们放松心情、驱散无聊的好伙伴。不过&#xff0c;面对市场上不断涌现的开放式蓝牙耳机&#xff0c;挑选一款既符合个人喜好又满足需求的产品&#xff0c;确实需要一些技巧。今天&#xff0c;…

springboot实现多开发环境匹配置

首先logbok-spring.xml里面的内容 <?xml version"1.0" encoding"UTF-8"?> <configuration><!-- 开发、测试环境 --><springProfile name"dev,test"><include resource"org/springframework/boot/logging/log…

【国信华源:以专业服务,协助水利厅抵御强暴雨】

5月18日-19日&#xff0c;广西出现入汛以来最强暴雨天气过程&#xff0c;钦州、防城港、北海、南宁等地出现特大暴雨&#xff0c;多地打破降雨量极值。国信华源技术团队积极行动驻守一线&#xff0c;为打好山洪灾害防御的提前战、主动战提供了技术支撑。 5月17日18时&#xff0…

六.逼格拉满-Prometheus+Grafana微服务监控告警

前言 微服务架构是一个分布式系统&#xff0c;由多个独立的服务组成&#xff0c;每个服务可能运行在不同的容器、虚拟机或物理机上&#xff0c;那么在生产环境中我们需要随时监控服务的状态&#xff0c;以应对各种突发情况&#xff0c;比如&#xff1a;内存爆满&#xff0c;CP…

【全开源】Java养老护理助浴陪诊小程序医院陪护陪诊小程序APP源码

打造智慧养老服务新篇章 一、引言&#xff1a;养老护理的数字化转型 随着老龄化社会的到来&#xff0c;养老护理需求日益凸显。为了更好地满足老年人及其家庭的需求&#xff0c;我们推出了养老护理助浴陪诊小程序系统源码。该系统源码旨在通过数字化技术&#xff0c;优化养老…

Apache Doris 基础 -- 数据表设计(数据模型)

Versions: 2.1 1、模型概览 本主题从逻辑角度介绍了Doris中的数据模型&#xff0c;以便您可以在不同的业务场景中更好地使用Doris。 基本概念 本文主要从逻辑的角度描述Doris的数据模型&#xff0c;旨在帮助用户在不同的场景更好地利用Doris。 在Doris中&#xff0c;数据在…

基于Android Studio图书管理,图书借阅系统

目录 项目介绍 图片展示 运行环境 获取方式 项目介绍 用户 书架&#xff1a;搜索书籍&#xff0c;查看书籍&#xff0c;借阅书籍&#xff0c;收藏书籍&#xff0c;借阅书籍必须在一个月之内还书&#xff1b; 我的&#xff1a;可以修改密码&#xff0c;退出登录&#xff…

Fwknop:单包授权与端口试探工具

介绍 fwknop实现了一种称为单包授权&#xff08;SPA&#xff09;的授权方案&#xff0c;用于隐藏服务。SPA将单个数据包经过加密&#xff0c;不可重放&#xff0c;并通过HMAC进行身份验证&#xff0c;以便在传达到隐藏在防火墙后面的服务。 SPA的主要应用场景是防火墙来过滤一…

ssm球场计费管理系统-计算机毕业设计源码77275

摘 要 大数据时代下&#xff0c;数据呈爆炸式地增长。为了迎合信息化时代的潮流和信息化安全的要求&#xff0c;利用互联网服务于其他行业&#xff0c;促进生产&#xff0c;已经是成为一种势不可挡的趋势。在球馆计费管理的要求下&#xff0c;开发一款整体式结构的球场计费管理…

三品软件:打造高效安全的图文档管理体系

在数字化转型的浪潮中&#xff0c;工程设计单位和企业设计部门面临着电子图文档管理的巨大挑战。随着电子图纸和文档数量的激增&#xff0c;如何有效组织、管理和共享这些资源&#xff0c;成为提升工作效率和保障信息安全的关键。本文将探讨当前图文档管理面临的问题&#xff0…

KEIL5鼠标右键查找定义或声明选项变灰色不可选

原因&#xff1a;我直接点的KEIL图标打开了昨天的工程 解决办法&#xff1a;关掉工程&#xff0c;重新从文件夹的路径打开 其他原因导致试试以下方法&#xff1a; 1.快捷键F12导航到目标位置 2.路径不能含有中文&#xff0c;改好后&#xff0c;shiftAltf12&#xff0c;更新搜索…