轻松实现Springboot国际化动态配置,有点干

本文详细介绍了如何在Springboot应用中通过JPA和数据库实现动态国际化信息配置,包括引入依赖、表结构设计、JPA配置、实体类和Repository的实现,以及自定义动态国际化信息源和测试过程。
摘要由CSDN通过智能技术生成

前些天发现了一个巨牛的人工智能学习网站,通俗易懂,风趣幽默,忍不住分享一下给大家。点击跳转到网站。

上篇文章我们介绍了Springboot静态国际化的使用,实际工作中使用静态配置文件的形式的国际化不够灵活,扩展起来也相对麻烦,如果需要修改其中的国际化信息就要重新加载对应的配置文件或者是重启项目,很不友好,所以我们需要实现动态配置国际化信息。
最直接的方式就是通过数据库将国际化信息进行持久化,可以随时更新国际化信息。本文将介绍如何动态配置国际化信息。

动态配置国际化信息

引入依赖

为了方便,这里使用JPA、MySQL进行数据库方面的操作,引入相关依赖:

<dependency>
  <groupId>org.springframework.boot</groupId>
   <artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>

<dependency>
    <groupId>mysql</groupId>
    <artifactId>mysql-connector-java</artifactId>
    <version>8.0.23</version>
</dependency>

<dependency>
   <groupId>org.projectlombok</groupId>
   <artifactId>lombok</artifactId>
   <scope>provided</scope>
</dependency>

表结构及数据

新建一张表i18n_msg表结构如下:

CREATE TABLE `i18n_msg` (
  `id` bigint(20) NOT NULL AUTO_INCREMENT,
  `locale` varchar(255) COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '语言类型',
  `code` varchar(255) COLLATE utf8mb4_unicode_ci NOT NULL,
  `msg` varchar(255) COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '消息,可以使用{}占位符',
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=5 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci

先添加4条数据,方便后面使用:
数据

JPA配置

配置文件application.properties 配置:

spring.datasource.url=jdbc:mysql://localhost:3306/springboot_practice?serverTimezone=UTC&useUnicode=true&characterEncoding=utf-8&useSSL=false
spring.datasource.username=root
spring.datasource.password=123456
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
## 每次启动项目,数据库中没有表会新建一张表,如果有表表内有数据不会清空,只会更新
spring.jpa.hibernate.ddl-auto=update
# 打印SQL语句
spring.jpa.show-sql=true

JPA实体类:

@Entity
@Table(name = "i18n_msg")
@Data
public class I18nMsgEntity {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    @Column(name = "locale",length = 50)
    private String locale;

    @Column(name = "code",length = 50)
    private String code;

    @Column(name = "msg",length = 50)
    private String msg;
}

JpaRepository实现类,进行CRUD操作:

/**
 * @author 公众号-索码理(suncodernote)
 * @date 2024/2/1 23:00
 */
public interface I18nMsgRepository extends JpaRepository<I18nMsgEntity,Long> {

    I18nMsgEntity findByCodeAndLocale(String code, String locale);
}
/**
 * @author 公众号-索码理(suncodernote)
 */
public interface I18nMsgService {

    I18nMsgEntity findByCodeAndLocale(String code, String locale);
}
@Service
public class I18nMsgServiceImpl implements I18nMsgService {

    @Resource
    private I18nMsgRepository i18nMsgRepository;

    @Override
    public I18nMsgEntity findByCodeAndLocale(String code, String locale) {
        return i18nMsgRepository.findByCodeAndLocale(code, locale);
    }
}

动态国际化信息提供类

创建一个接口I18nDynamicMsgProvider,该接口用于提供动态国际化信息。

/**
 * 动态国际化接口
 * @author 公众号-索码理(suncodernote)
 */
public interface I18nDynamicMsgProvider {

    /**
     * 获取动态国际化信息
     * @param locale 指定区域
     * @param code 国际化code
     * @return
     */
    I18DynamicMessage getDynamicMsg(Locale locale, String code);
}

I18nDynamicMsgProvider接口实现类,在该类中通过区域和国际化信息code获取对应的国际化信息。

@Component
public class MyI18nDynamicMsgProvider implements I18nDynamicMsgProvider{

    @Autowired
    private I18nMsgService i18nMsgService;

    @Override
    public I18DynamicMessage getDynamicMsg(Locale locale, String code) {
        I18DynamicMessage i18DynamicMessage = new I18DynamicMessage();
        I18nMsgEntity i18nMsgEntity = i18nMsgService.findByCodeAndLocale(code, locale.toString());
        if (i18nMsgEntity != null) {
            String msg = i18nMsgEntity.getMsg();
            i18DynamicMessage.setMsg(msg);
            i18DynamicMessage.setCode(code);
            i18DynamicMessage.setLocale(locale.toString());
        }
        return i18DynamicMessage;
    }
}

自定义动态国际化信息源

要自定义动态国际化信息源需要实现AbstractMessageSource抽象类,重写resolveCode(String , Locale)方法即可。

@Component
public class DynamicMessageSource extends AbstractMessageSource {

    private final I18nDynamicMsgProvider i18nMessageProvider;

    public DynamicMessageSource(I18nDynamicMsgProvider i18nMessageProvider) {
        this.i18nMessageProvider = i18nMessageProvider;
    }

    @Override
    protected MessageFormat resolveCode(String code, Locale locale) {
        I18DynamicMessage i18nMessage = i18nMessageProvider.getDynamicMsg(locale, code);
        if (i18nMessage != null) {
            return createMessageFormat(i18nMessage.getMsg() , locale);
        }
        return null;
    }
}

测试

@SpringBootTest
class SpringbootPracticeApplicationTests {
    @Autowired
    private DynamicMessageSource dynamicMessageSource;

    @Test
    public void testDynamicMessageSource(){
        String code = "dynamic.hello";
        Locale locale = Locale.CHINA;

        String message = dynamicMessageSource.getMessage(code, null, locale);
        System.out.println(message);
        System.out.println();

		//占位符替换
        code = "dynamic.welcome";
        message = dynamicMessageSource.getMessage(code, new String[]{"索码理"}, locale);
        System.out.println(message);
        System.out.println();

        locale = Locale.ENGLISH;
        message = dynamicMessageSource.getMessage(code, new String[]{"suncodernote"}, locale);
        System.out.println(message);
    }
}

测试结果:

Hibernate: select i1_0.id,i1_0.code,i1_0.locale,i1_0.msg from i18n_msg i1_0 where i1_0.code=? and i1_0.locale=?
动态国际化配置,你好

Hibernate: select i1_0.id,i1_0.code,i1_0.locale,i1_0.msg from i18n_msg i1_0 where i1_0.code=? and i1_0.locale=?
欢迎关注公众号,索码理

Hibernate: select i1_0.id,i1_0.code,i1_0.locale,i1_0.msg from i18n_msg i1_0 where i1_0.code=? and i1_0.locale=?
Welcome to follow WeChat Public Number, suncodernote!

从测试结果看到不管是有没有占位符,中文还是英文,国际化信息都能很好的展示,也说明了动态国际化配置的成功。

总结

本文只是简单介绍动态国际化信息的配置,有待优化,比如将国际化信息放入到缓存中,感兴趣的可以参考上面的示例,写一个自己的动态国际化配置。

  • 19
    点赞
  • 18
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 7
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 7
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

索码理

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值