【源码解析】RuoYi-Vue-Plus翻译功能 Translation 源码分析

news2024/10/7 18:20:33
说明功能
Translation通用翻译注解标注需要翻译的字段,用于实体类字段上
TranslationType翻译类型注解标注翻译字段的实现类型,用于实现类上标注
TransConstant翻译常量TranslationType 类型常量
TranslationConfig翻译模块配置类配置初始化,设置序列化修改器
TranslationBeanSerializerModifierBean 序列化修改器解决序列化过程中 Null 被单独处理问题
TranslationHandler翻译处理器对标注了 @Translation 注解的字段进行翻译
TranslationInterface翻译接口提供翻译接口用于自定义翻译扩展
*TranslationImpl翻译实现类根据 TranslationType 提供不同的翻译数据

初始化

  1. 获取所有实现了TranslationInterface接口的Bean实例,根据对应的注解TranslationType存放到TranslationHandler.TRANSLATION_MAPPER。修改序列化器TranslationBeanSerializerModifier
@Slf4j
@Configuration
public class TranslationConfig {

    @Autowired
    private List<TranslationInterface<?>> list;

    @Autowired
    private ObjectMapper objectMapper;

    @PostConstruct
    public void init() {
        Map<String, TranslationInterface<?>> map = new HashMap<>(list.size());
        for (TranslationInterface<?> trans : list) {
            if (trans.getClass().isAnnotationPresent(TranslationType.class)) {
                TranslationType annotation = trans.getClass().getAnnotation(TranslationType.class);
                map.put(annotation.type(), trans);
            } else {
                log.warn(trans.getClass().getName() + " 翻译实现类未标注 TranslationType 注解!");
            }
        }
        TranslationHandler.TRANSLATION_MAPPER.putAll(map);
        // 设置 Bean 序列化修改器
        objectMapper.setSerializerFactory(
            objectMapper.getSerializerFactory()
                .withSerializerModifier(new TranslationBeanSerializerModifier()));
    }

}

TranslationBeanSerializerModifier处理空值。

public class TranslationBeanSerializerModifier extends BeanSerializerModifier {

    @Override
    public List<BeanPropertyWriter> changeProperties(SerializationConfig config, BeanDescription beanDesc,
                                                     List<BeanPropertyWriter> beanProperties) {
        for (BeanPropertyWriter writer : beanProperties) {
            // 如果序列化器为 TranslationHandler 的话 将 Null 值也交给他处理
            if (writer.getSerializer() instanceof TranslationHandler) {
                writer.assignNullSerializer(writer.getSerializer());
            }
        }
        return beanProperties;
    }

}

使用序列化器

Translation注解,指定字段使用TranslationHandler序列化器。

/**
 * 通用翻译注解
 *
 * @author Lion Li
 */
@Inherited
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.FIELD, ElementType.METHOD})
@Documented
@JacksonAnnotationsInside
@JsonSerialize(using = TranslationHandler.class)
public @interface Translation {

    /**
     * 类型 (需与实现类上的 {@link com.ruoyi.common.annotation.TranslationType} 注解type对应)
     * <p>
     * 默认取当前字段的值 如果设置了 @{@link Translation#mapper()} 则取映射字段的值
     */
    String type();

    /**
     * 映射字段 (如果不为空则取此字段的值)
     */
    String mapper() default "";

    /**
     * 其他条件 例如: 字典type(sys_user_sex)
     */
    String other() default "";

}

TranslationHandler,针对Translation的序列化器。序列化的时候,根据类型获取TranslationInterface,获取mapper字段的数据,查询数据

@Slf4j
public class TranslationHandler extends JsonSerializer<Object> implements ContextualSerializer {

    /**
     * 全局翻译实现类映射器
     */
    public static final Map<String, TranslationInterface<?>> TRANSLATION_MAPPER = new ConcurrentHashMap<>();

    private Translation translation;

    @Override
    public void serialize(Object value, JsonGenerator gen, SerializerProvider serializers) throws IOException {
        TranslationInterface<?> trans = TRANSLATION_MAPPER.get(translation.type());
        if (ObjectUtil.isNotNull(trans)) {
            // 如果映射字段不为空 则取映射字段的值
            if (StringUtils.isNotBlank(translation.mapper())) {
                value = ReflectUtils.invokeGetter(gen.getCurrentValue(), translation.mapper());
            }
            // 如果为 null 直接写出
            if (ObjectUtil.isNull(value)) {
                gen.writeNull();
                return;
            }
            Object result = trans.translation(value, translation.other());
            gen.writeObject(result);
        } else {
            gen.writeObject(value);
        }
    }

    @Override
    public JsonSerializer<?> createContextual(SerializerProvider prov, BeanProperty property) throws JsonMappingException {
        Translation translation = property.getAnnotation(Translation.class);
        if (Objects.nonNull(translation)) {
            this.translation = translation;
            return this;
        }
        return prov.findValueSerializer(property.getType(), property);
    }
}

OssUrlTranslationImpl定义了根据key获取数据的接口。

@Component
@AllArgsConstructor
@TranslationType(type = TransConstant.OSS_ID_TO_URL)
public class OssUrlTranslationImpl implements TranslationInterface<String> {

    private final OssService ossService;

    @Override
    public String translation(Object key, String other) {
        return ossService.selectUrlByIds(key.toString());
    }
}

使用demo

使用Translation注解

@Data
@ExcelIgnoreUnannotated
public class TestDemoVo {

    private static final long serialVersionUID = 1L;

    /**
     * 部门id
     */
    private Long deptId;
    
    @Translation(type = TransConstant.DEPT_ID_TO_NAME,mapper = "deptId")
    private String deptName;
}

在这里插入图片描述

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

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

相关文章

深度学习基础入门篇[9.2]:卷积之1*1 卷积(残差网络)、2D/3D卷积、转置卷积数学推导、应用实例

【深度学习入门到进阶】必看系列&#xff0c;含激活函数、优化策略、损失函数、模型调优、归一化算法、卷积模型、序列模型、预训练模型、对抗神经网络等 专栏详细介绍&#xff1a;【深度学习入门到进阶】必看系列&#xff0c;含激活函数、优化策略、损失函数、模型调优、归一化…

一文了解customRef 自定义ref使用

概念 按照文档中的说明&#xff1a;customRef 可以用来创建一个自定义的 ref&#xff0c;并对其依赖项跟踪和更新触发进行显式控制。它需要一个工厂函数&#xff0c;该函数接收 track 和trigger函数作为参数&#xff0c;并且应该返回一个带有 get 和 set 的对象。 其实大致意思…

公有云——阿里云ECS服务器入门精通(IaaS)(2)

作者简介&#xff1a;一名云计算网络运维人员、每天分享网络与运维的技术与干货。 座右铭&#xff1a;低头赶路&#xff0c;敬事如仪 个人主页&#xff1a;网络豆的主页​​​​​​ 目录 一.ECS 实例规格族介绍 1.实例的架构类型、规格分类&#xff0c;详细信息 2.企业…

网络互联与互联网 - IP 子网划分详解

文章目录 1 概述1.1 划分目的1.2 划分原则1.3 子网掩码 2 IP 子网划分示例3 网工软考真题3.1 判断网络号和主机号3.2 计算可容纳的主机数3.3 子网划分 1 概述 IP 子网划分&#xff1a;实际上就是设计 子网掩码 的过程。原因&#xff1a;由于在五类的IP地址中&#xff0c;网络号…

【SpringBoot】数据校验API

个人简介&#xff1a;Java领域新星创作者&#xff1b;阿里云技术博主、星级博主、专家博主&#xff1b;正在Java学习的路上摸爬滚打&#xff0c;记录学习的过程~ 个人主页&#xff1a;.29.的博客 学习社区&#xff1a;进去逛一逛~ 数据校验API SpringBoot数据校验数据校验API的…

智能电动「唱主角」,哪些供应商在「领跑」智驾域控制器赛道

新势力&#xff0c;从哪里突围&#xff1f; 造车新势力在过去几年的成绩&#xff0c;已经代表了未来趋势&#xff1a;新能源汽车&#xff0c;尤其是纯电动。而对于智能化软硬件供应商&#xff0c;尤其是新势力供应商来说&#xff0c;亦是如此。 高工智能汽车研究院监测数据显…

深度学习框架-Tensorflow2:特点、架构、应用和未来发展趋势

引言 深度学习是一种新兴的技术&#xff0c;已经在许多领域中得到广泛的应用&#xff0c;如计算机视觉、自然语言处理、语音识别等。在深度学习中&#xff0c;深度学习框架扮演着重要的角色。Tensorflow是一种广泛使用的深度学习框架&#xff0c;已经成为深度学习的事实标准。…

全民拼购为什么能躺赢

大家好&#xff01;我叫小鱼 新商业&#xff0c;新模式 新机会&#xff01; 我们在拼购过程中 往往都觉得商家在亏钱 事实如此吗&#xff1f; 随着全球经济下行&#xff0c;党中央、国务院 高度重视发展流通扩大消费。 为推动流通创新发展&#xff0c;促进商业繁荣&#xff0c;…

回文子串问题

一&#xff1a;最长回文子串&#xff08;leetcode 5&#xff09; 给你一个字符串 s&#xff0c;找到 s 中最长的回文子串。 如果字符串的反序与原始字符串相同&#xff0c;则该字符串称为回文字符串。 示例 1&#xff1a; 输入&#xff1a;s "babad" 输出&#x…

盛元广通疾病预防控制中心检测管理信息系统

近些年&#xff0c;在疾病预防控制领域&#xff0c;公共卫生事件的发生都是通过信息化手段在日常工作中加以应用以及广泛深入的探索&#xff0c;加快疾控实验室信息化建设进程&#xff0c;可以有效把控不同类型检测任务中的每个节点&#xff0c;严防不同系统填报多次出现信息误…

SpringBoot——热部署

简单介绍&#xff1a; 在之前我们的项目中&#xff0c;当我们在编写了一个新的类并且要应用的时候&#xff0c;需要手动重启服务器重新部署一下&#xff0c;这个过程需要我们手动去完成&#xff0c;但是很多时候&#xff0c;比如我们在做测试&#xff0c;需要反复的修改代码&a…

第14章_视图

第14章_视图 1. 常见的数据库对象 对象描述表(TABLE)表是存储数据的逻辑单元&#xff0c;以行和列的形式存在&#xff0c;列就是字段&#xff0c;行就是记录数据字典就是系统表&#xff0c;存放数据库相关信息的表。系统表的数据通常由数据库系统维护&#xff0c;程序员通常不…

【Http协议②】http协议格式,请求格式,常见请求方法,请求报文,请求正文

前言: 大家好,我是良辰丫,上一篇文章我们已经了解过了http协议,这篇文章我将带领大家去学习http协议的一些属性,http协议格式,请求格式,常见请求方法,请求报文,请求正文.跟随我的脚步,一起遨游http的海洋.&#x1f49e;&#x1f49e; &#x1f9d1;个人主页&#xff1a;良辰针不…

第14届蓝桥杯省赛真题剖析-2023年5月7日Scratch编程初级组

[导读]&#xff1a;超平老师的《Scratch蓝桥杯真题解析100讲》已经全部完成&#xff0c;后续会不定期解读蓝桥杯真题&#xff0c;这是Scratch蓝桥杯真题解析第135讲。 第14届蓝桥杯Scratch省赛真题&#xff0c;这是2023年5月7日举办的省赛&#xff0c;比赛仍然采取线上形式。试…

Spring Boot 的 Starter 以及实现一个自定义Starter

一、了解 Spring Boot Starter Spring Boot Starter 是 Spring Boot 中一个重要概念&#xff0c;它是一种提供依赖项的方式&#xff0c;简化 Spring 应用程序依赖管理&#xff0c;将一组相关的依赖项打包在一起&#xff0c;并提供一个依赖项描述文件&#xff0c;使开发人员可以…

视觉-激光融合SLAM :LVI - SAM与LIO - SAM的环境配置

目录 1.LIO-SAM配置 1.1 ROS 安装 1.2 安装gtsam 4.0.2 1.3 安装LIO-SAM 1.4 运行LIO-SAM 2. LVI - SAM安装 2.1 一些依赖库的安装 2.2 安装ceres1.1.14 2.3 安装LVI-SAM 1.LIO-SAM配置 机器&#xff1a;Ubuntu 18.04 内存&#xff1a;>16G CPU&#xff1a;Intel &…

电脑看不了视频?这样做,可以快速解决!

案例&#xff1a;我的电脑播放不了视频&#xff0c;这是什么原因。如何才能在电脑上播放视频&#xff1f;有没有解决的办法&#xff1f; 【我工作和学习都离不开电脑&#xff0c;今天工作的时候&#xff0c;我用电脑打开一个视频&#xff0c;却发现视频无法播放&#xff0c;怎…

擎创动态 | 来自华为的深度认可,擎创再获华为鲲鹏技术认证

在数字中国的信息技术应用国产化进程中&#xff0c;擎创科技除持续投入自主产品研发外&#xff0c;还深度适配了涵盖芯片、服务器、操作系统、数据库、中间件、云服务、应用等领域的国产化产品&#xff0c;与华为的合作适配便是其中重要的一环。近期&#xff0c;擎创夏洛克智能…

Install Prometheus Monitoring On Kubernetes Cluster

目录 Node & Software & Docker Images Lists ​Prometheus introduction Download Kubernetes Prometheus Manifest Files Install Prometheus Monitoring Kubernetes Create a Namespace Create a Cluster Role And Binding It Create a Config Map Create…

lwIP更新记05:核心应用文件移动

从 lwIP-2.0.0 开始&#xff0c;lwIP 开发者将一些核心应用从 contrib 仓库移动到 lwIP 仓库的 src/apps 文件夹。 对比版本 lwIP-1.4.1 和 lwIP-2.1.2 的 src 文件夹内容&#xff0c;可以发现 lwIP 2.1.2 版本多了一个 apps 文件夹。 最开始&#xff0c;也就是 2015 年 10 …