SpringBoot国际化配置流程(超详细)

news2024/9/23 21:32:38

前言

最新第一次在做SpringBoot的国际化,网上搜了很多相关的资料,都是一些简单的使用例子,达不到在实际项目中使用的要求,因此本次将结合查询的资料以及自己的实践整理出SpringBoot配置国际化的流程。

SpringBoot国际化

"i18n"是国际化(internationalization)的缩写,数字18代表了国际化这个单词中间的字母数量。类似这样的缩写还有k8s(kubernetes)等

Spring Boot国际化是指在Spring Boot应用中实现多语言支持的功能。通过国际化,应用可以根据用户的语言偏好自动切换显示的语言版本,从而提供贴近用户的界面和文本信息。

SpringBoot官方国际化支持文档:7.5. Internationalization(请点击我)

由于SpringBoot默认集成国际化,因此本次实践也是基于SpringBoot的自动配置来进行。

准备环境

本次实践我使用的环境或工具版本如下:

SpringBoot 3.0.6IDEA社区版2023.1OpenJDK 17

引入依赖

<!-- web中提供国际化支持 -->
<dependency>
  <groupId>org.springframework.boot</groupId>
  <artifactId>spring-boot-starter-web</artifactId>
  <version>3.0.6</version>
</dependency>
<!-- 参数校验 -->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-validation</artifactId>
    <version>3.0.6</version>
</dependency>

自定义配置

@AutoConfigureBefore(WebMvcAutoConfiguration.class)
public class LocaleConfig {

    /**
     * 国际化消息源
     */
    @Resource
    private MessageSource messageSource;


    /**
     * 区域解析器,供消息源@MessageSource根据不同的区域@java.util.Locale读取不同的properties文件
     *
     * @return {@code LocaleResolver}
     */
    @Bean
    public LocaleResolver localeResolver() {
        AcceptHeaderLocaleResolver localeResolver = new AcceptHeaderLocaleResolver();
        // 设置默认区域:简体中文
        localeResolver.setDefaultLocale(Locale.SIMPLIFIED_CHINESE);
        return localeResolver;
    }


    /**
     * 使用自定义LocalValidatorFactoryBean,
     * 设置Spring国际化消息源,用户jsr303验证信息实现自定义国际化
     *
     */
    @Bean
    public Validator getValidator() {
        LocalValidatorFactoryBean bean = new LocalValidatorFactoryBean();
        bean.setValidationMessageSource(messageSource);
        return bean;
    }
}

java.util.Locale: Locale对象表示特定的地理、政治或文化区域,用以区分区域。

org.springframework.web.servlet.i18n.AcceptHeaderLocaleResolver:通过请求头Accept-Language的值(zh-CN、en-US等)来改变当前的区域设置

org.springframework.context.MessageSource:用于解析消息的策略接口,支持此类消息的参数化和国际化。根据Locale区域读取不同的properties国际化文件

@AutoConfigureBefore(WebMvcAutoConfiguration.class):由于WebMvcAutoConfiguration会注入一个默认的LocaleResolver,因此自定义的LocaleConfig要在WebMvcAutoConfiguration之前先执行,且beanName是localeResolver,目的就是用我们配置的LocaleConfig替换掉WebMvcAutoConfiguration自动注入的LocaleConfig

以下代码片段是WebMvcAutoConfiguration自动注入LocaleResolver 的方法

/**
* DispatcherServlet.LOCALE_RESOLVER_BEAN_NAME的值就是"localeResolver"
*/
@Override
@Bean
@ConditionalOnMissingBean(name = DispatcherServlet.LOCALE_RESOLVER_BEAN_NAME)
public LocaleResolver localeResolver() {
	if (this.webProperties.getLocaleResolver() == WebProperties.LocaleResolver.FIXED) {
		return new FixedLocaleResolver(this.webProperties.getLocale());
	}
	AcceptHeaderLocaleResolver localeResolver = new AcceptHeaderLocaleResolver();
	localeResolver.setDefaultLocale(this.webProperties.getLocale());
	return localeResolver;
}

国际化文件

在工程resources目录下新建目录i18n,在i18n目录下新建三个国际化文件:
messages.properties
messages_en_US.properties
messages_zh_CN.properties

zh-CN:简体中文
en-US:英语

在这里插入图片描述

在不配置默认的区域情况下,当没有找到匹配的语言文件时,会读取默认的messages.properties

如何快速编辑资源包.properties文件

配置application.yml

spring:
  ## note: ---------------- 国际化配置 ----------------
  messages:
    basename: i18n/messages
    fallback-to-system-locale: false

basename:基名,多个基名以逗号分隔(实质上是完全限定的类路径位置),每个基名都遵循 ResourceBundle 约定,对基于斜杠的位置提供了宽松的支持。如果它不包含包限定符(例如“org.mypackage”),则将从类路径根目录解析它。

基名可以理解为前缀,默认是从classpath根路径下找,配置的路径可以用斜杠/,也可以用.,即i18n/messagesi18n.messages,然后messages就是国际化文件的前缀,messages.properties就是默认国际化文件。

fallback-to-system-locale:如果未找到特定区域设置的文件,是否回退到系统区域设置。如果关闭此功能,则唯一的回退将是默认文件。就是我想要的区域语言文件没有的时候,就从系统中解析系统的区域,以系统的区域再找一次文件,找到就返回系统区域文件,如果找不到,就返回默认的文件。

国际化消息工具类

@Slf4j
@Component
public class LocaleUtil implements ApplicationContextAware {

    private static MessageSource messageSource;

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        LocaleUtil.messageSource = applicationContext.getBean(MessageSource.class);
    }

    /**
     * 获取国际化message
     *
     * @param code           code
     * @param args           占位参数
     * @param defaultMessage 默认值
     * @return 国际化文本
     */
    public static String getMessage(String code, @Nullable Object[] args, @Nullable String defaultMessage) {
        return messageSource.getMessage(code, args, defaultMessage, LocaleContextHolder.getLocale());
    }

    /**
     * 获取国际化message
     *
     * @param code           code
     * @param args           占位参数
     * @param defaultMessage 默认值
     * @param locale         地区
     * @return 国际化文本
     */
    public static String getMessage(String code, @Nullable Object[] args, @Nullable String defaultMessage, Locale locale) {
        return messageSource.getMessage(code, args, defaultMessage, locale);
    }

    /**
     * 获取国际化message
     *
     * @param code           code
     * @param defaultMessage 默认值
     * @return 国际化文本
     */
    public static String getMessage(String code, @Nullable String defaultMessage) {
        return messageSource.getMessage(code, null, defaultMessage, LocaleContextHolder.getLocale());
    }

封装国际化文本的读取接口,主要方便在代码中使用,不需要每次@Autowired注入MessageSource来使用。

国际化使用

异常提示国际化

在业务代码中,业务异常我们通常是抛出异常,由统一异常处理来根据异常codemessage封装成统一的返回对象,国际化这里我们也是一样,code不变,message改成国际化消息的key

  • 定义业务异常对象
public class BussinessException extends RuntimeException {

    private String code;

    public BussinessException (String code, String message) {
        super(message);
        this.code= code;
    }
}
  • 定义异常类型枚举
public enum ErrorCodeEnum {

    DEMO_ERROR(99999, "i18n.user.check.username.err");

    /**
     * 提示
     */
    private final String message;
    /**
     * 状态吗
     */
    private final String code;

    ErrorCodeEnum (String code, String message) {
        this.code = code;
        this.message = message;
    }

    /**
     * 获取国际化错误提示
     *
     * @return 错误提示文本
     */
    public String getMessage() {
        return LocaleUtil.getMessage(message, message);
    }

    /**
     * 获取国际化错误提示
     *
     * @param args 错误提示参数
     * @return 错误提示文本
     */
    public String getMessage(Object[] args) {
        return LocaleUtil.getMessage(message, args, message);
    }

    /**
     * 获取错误code
     *
     * @return 错误code
     */
    public Integer getCode() {
        return code;
    }
}
  • 国际化文件配置

在国际化文件都配置上i18n.user.check.username.err不同语言的翻译

## messages.properties
i18n.user.check.username.err=用户名校验不通过

## messages_en_US.properties
i18n.user.check.username.err=The username does not comply with regulations

## messages_zh_CN.properties
i18n.user.check.username.err=用户名不符合规范

在这里插入图片描述

  • 业务逻辑校验(使用场景之一)
   /**
     * 校验用户名是否符合规范
     *
     * @param userName 用户名
     * @return {@code String}
     */
    public String checkUserName(String userName) {
        if (StringUtils.isBlank(userName)) {
            throw new BussinessException(ErrorCodeEnum.DEMO_ERROR.getCode(), ErrorCodeEnum.DEMO_ERROR.getMessage());
        }
        // check logic code ...
        return userName;
    }

参数校验国际化

SpringBoot项目我们在做参数校验通常会使用JSR303、jakarta.validation参数校验快速失败。

import jakarta.validation.constraints.NotEmpty;
import lombok.Data;

@Data
public class TestReq {

    @NotEmpty
    private String userName;
}

我这里是导入开头的spring-boot-starter-validation依赖就可以使用hibernate-validator给我们提供的常用校验注解的国际化。
在这里插入图片描述

查看@NotEmpty注解源码,message默认就读国际化文件里jakarta.validation.constraints.NotEmpty.message

@Documented
@Constraint(validatedBy = { })
@Target({ METHOD, FIELD, ANNOTATION_TYPE, CONSTRUCTOR, PARAMETER, TYPE_USE })
@Retention(RUNTIME)
@Repeatable(List.class)
public @interface NotEmpty {

	String message() default "{jakarta.validation.constraints.NotEmpty.message}";

	Class<?>[] groups() default { };

	Class<? extends Payload>[] payload() default { };

	/**
	 * Defines several {@code @NotEmpty} constraints on the same element.
	 *
	 * @see NotEmpty
	 */
	@Target({ METHOD, FIELD, ANNOTATION_TYPE, CONSTRUCTOR, PARAMETER, TYPE_USE })
	@Retention(RUNTIME)
	@Documented
	public @interface List {
		NotEmpty[] value();
	}
}

这里就贴ValidationMessages.propertiesjakarta.validation.constraints.NotEmpty.message,其他文件大家自行查看。

jakarta.validation.constraints.NotEmpty.message        = must not be empty

自定义校验错误提示信息

当我们不想使用hibernate-validator给我们提供的默认提示信息时,我们可以自定义自己的错误提示信息。这里就复用前面配置的i18n.user.check.username.err

@Data
public class TestReq {

    @NotEmpty(message = "{i18n.user.check.username.err}")
    private String userName;
}

如此,在Accept-Language=en-US即我想返回的信息是英文,参数校验不通过时,提示的不是must not be empty,而是我们自定义的The username does not comply with regulations

结语

时间有限,国际化的实践流程截图没提供,大家根据文中的操作步骤也可以完成国际化的demo,后续有时间再完善,大家也期待下一篇的源码解读吧。

文中如有描述不清楚、读者不理解意思的地方,大家评论区打出,我来完善哈。

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

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

相关文章

关于svn安装报错2503问题的解决方法

问题&#xff1a; SVN在安装时&#xff0c;一直报错&#xff0c;安装失败 The installer has encountered an unexpected error installing this package.The error code is 2503 权限问题&#xff0c;右键以管理员权限运行。如果你也是像我一样&#xff0c;右键没有以管理员…

springboot 使用@profiles.active@多配置文件切换

项目配置文件结构&#xff1a; 主配置文件内容&#xff1a; pom配置文件&#xff1a; <profiles><profile><id>dev</id><properties><profiles.active>dev</profiles.active></properties></profile><profile>…

43 带 fixed 列的 el-table 不兼容于 sortablejs

前言 这是一个基于 sortablejs 来实现的 el-table 的拖拽功能的基础实现 然后 这个过程中遇到的一个比较特殊的问题是, 关于 el-table-column 的 fixed 的属性, 对于 sortablejs 这边来定位目标选择列 影响的一个问题 在基础的用例中, 使用 “.el-table__body-wrapper tbo…

数组的常见算法

数组的常见算法 数值型数组特征值统计 这里的特征值涉及到&#xff1a;平均值、最大值、最小值、总和等 举例1&#xff1a;数组统计&#xff1a;求总和、均值 public class TestArrayElementSum {public static void main(String[] args) {int[] arr {4,5,6,1,9};//求总和、…

污水处理迈入3D可视化新时代:智慧环保触手可及

在科技日新月异的今天&#xff0c;环保事业也迎来了前所未有的发展机遇。污水处理作为环保领域的重要组成部分&#xff0c;其技术的革新与进步&#xff0c;对于保护水资源、维护生态平衡具有重要意义。 传统的污水处理机组往往存在着操作复杂、监控困难等问题&#xff0c;使得污…

2024年【熔化焊接与热切割】报名考试及熔化焊接与热切割模拟试题

题库来源&#xff1a;安全生产模拟考试一点通公众号小程序 熔化焊接与热切割报名考试考前必练&#xff01;安全生产模拟考试一点通每个月更新熔化焊接与热切割模拟试题题目及答案&#xff01;多做几遍&#xff0c;其实通过熔化焊接与热切割作业考试题库很简单。 1、【单选题】…

ORA-04031 错误分析及处理方法

一、问题描述 使用普通用户登录数据库报ORA-04031错误 $ sqlplus / as sysdbaSQL*Plus: Release 11.2.0.1.0 Production on Mon Mar 25 09:14:59 2024Copyright (c) 1982, 2009, Oracle. All rights reserved.Connected to: Oracle Database 11g Enterprise Edition Releas…

学点儿Java_Day12_IO流

1 IO介绍以及分类 IO: Input Output 流是一组有顺序的&#xff0c;有起点和终点的字节集合&#xff0c;是对数据传输的总称或抽象。即数据在两设备间的传输称为流&#xff0c;流的本质是数据传输&#xff0c;根据数据传输特性将流抽象为各种类&#xff0c;方便更直观的进行数据…

详细分析Linux中的core dump异常(附 Demo排查)

目录 1. 基本知识2. 进阶知识3. Demo4. 彩蛋 1. 基本知识 Core dump 是指在程序异常终止时&#xff0c;操作系统将程序的内存映像保存到磁盘上的一种机制。 在 Linux 系统中&#xff0c;core dump 提供了一种调试程序错误的重要方式&#xff0c;它记录了程序在崩溃时的内存状态…

文献学习(自备)

收官大作&#xff0c;多组学融合的新套路发NC&#xff01;&#xff01; - 知乎 (zhihu.com) Hofbauer cell function in the term placenta associates with adult cardiovascular and depressive outcomes | Nature Communications 病理性胎盘炎症会增加几种成人疾病的风险&a…

CAD自动轻量化,工业仿真动画快速制作

随着现代工业的蓬勃发展&#xff0c;制造业企业在产品宣传展示、工作流程讲解、机械维修维护等方面对展示形式提出了更高的要求。工业动画以其直观、生动的特点&#xff0c;能够深入剖析产品的结构、工作原理和操作流程&#xff0c;为企业带来了全新的宣传展示方式。 但是由于…

Obsidian插件-高亮块(Admonition)

在插件市场里面搜索Admonition并安装插件&#xff0c;就可以使用高亮块了。 添加高亮块 用法稍微有一些不同。按照下面的格式&#xff0c;输入Markdown就可以创建一个高亮块。 内容内容内容输入*ad-*会出现相应的类型可以选择

【QGIS从shp文件中筛选目标区域导出为shp】

文章目录 1、写在前面2、QGIS将shp文件中目标区域输出为shp2.1、手动点选2.2、高级过滤 3、上述shp完成后&#xff0c;配合python的shp文件&#xff0c;即可凸显研究区域了 1、写在前面 利用shp文件制作研究区域mask&#xff0c;Matlab版本&#xff0c;请点击 Matlab利用shp文…

超分之SwinIR官方代码解读

文章目录 一、解读SwinIR模型文件&#xff1a;network_swinir.py1. 带有相对为位置偏置的(W-MSA)2. STL(Swin Transformer)3. RSTB&#xff08;Residual Swin Transformer Block&#xff09;4. SwinIR&#xff08;主框架网络&#xff09; 二、解读SwinIR测试主文件&#xff1a;…

企业员工培训考试系统开发方案

一、引言 在当今知识经济时代&#xff0c;企业对员工的综合素质和专业技能有着越来越高的要求。为了适应这一趋势&#xff0c;构建一个全面而高效的企业员工培训考试系统变得尤为重要。该系统旨在通过提供多样化的培训课程和全面的考核机制&#xff0c;促进员工持续学习和能力…

结构体,联合体,枚举( 1 )

目录 前言 1.结构体 1.1结构体的声明 1.2结构体变量的创建和初始化 1.3结构体成员的访问字符 1.4结构体的内存大小 1.4.1对齐规则 1.5结构体传参 前言 在编程的世界里&#xff0c;数据结构的选择对于程序的效率和可读性有着至关重要的影响。不同的数据结构适用于不同的…

手写SpringBoot(二)之动态切换Servlet容器

系列文章目录 手写SpringBoot&#xff08;一&#xff09;之简易版SpringBoot 手写SpringBoot&#xff08;二&#xff09;之动态切换Servlet容器 手写SpringBoot&#xff08;二&#xff09;之动态切换Servlet容器 文章目录 系列文章目录手写SpringBoot&#xff08;二&#xff…

面向图像分类的视觉Transformer

一种面向对象分类的视觉Transformer&#xff0c;即ViT。该模型避免了卷积带来的归纳偏置&#xff0c;弥补了卷积神经网络在超长周期建模的不足。 1、DeiT&#xff08;data-efficient image transformer&#xff09;采用了知识蒸馏策略&#xff08;将大型模型的复杂知识&#xf…

工厂数据分析系统用这个开源库准没错

ScottPlot是一款简单易用、高度定制、性能卓越的.NET绘图库&#xff0c;支持跨平台操作。除提供标准图表类型外&#xff0c;还支持交互式操作&#xff0c;呈现生动的数据展示。在工厂数字化系统中&#xff0c;可用于生产数据可视化、设备监测和质量控制。无论用于科学研究、数据…

蓝桥杯 2022 省A 选数异或

一种比较无脑暴力点的方法&#xff0c;时间复杂度是(nm)。 (注意的优先级比^高&#xff0c;记得加括号(a[i]^a[j])x&#xff09; #include <iostream> #include <vector> #include <bits/stdc.h> // 包含一些 C 标准库中未包含的特定实现的函数的头文件 usi…