springboot国际化

ops/2025/1/15 20:18:32/

使用springboot开发程序时,如果有国际市场的需求,一般要考虑国际化,在spring中本身对国际化就有很好的支持,下面介绍如何使用springboot开发国际化服务。
正常来说,引入 spring-boot-starter-web 模块后自动就会包括了国际化支持,所以demo程序引入的依赖包就非常简单:

<parent><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-parent</artifactId><version>3.2.9</version>
</parent><dependencies><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId><version>1.18.30</version></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-validation</artifactId></dependency>
</dependencies>

国际化要根据语言环境的不同返回对应的国际化资源内容,一般会定义多个 properties 结尾的资源文件:messages.properties、messages_en_US.properties、messages_zh_CN.properties,分别是默认的配置、英文配置、中文配置。

中文的信息写在 messages_zh_CN.properties 文件中:

hello=\u4f60\u597d\uff0c\u4e16\u754c\uff01

英文的信息写在 messages_en_US.properties 文件中:

hello=hello,world!

国际化文件路径

上面三个配置文件都放在resources资源目录下的i18n文件夹中,并且指定配置文件的前缀messages,所以在application.yml中指定资源文件位置:

server:port: 7777
spring:application:name: test-i18nmessages:basename: i18n.messagescache-duration: 3600encoding: UTF-8lifecycle:timeout-per-shutdown-phase: 45s    # 关闭服务缓冲时间,默认30sjackson:date-format: yyyy-MM-dd HH:mm:sstime-zone: GMT+08

在springboot中,实现国际化是通过 org.springframework.context.MessageSource 实现的,这个类在不指定情况下会根据当前系统的language确认语言环境。而在真实环境中,与前端交互一般是通过请求头中的Accept-Language确认语言环境,这里定义一个拦截器拦截前端传递过来的请求头中包含的语音环境信息,并将这个信息设置到 org.springframework.web.servlet.LocaleResolver 中,这样在后续处理时就可以在上下文中获取到语言信息。
所以开发国际化项目后端代码编写流程:

1、定义Locale相关的配置信息:

java">import org.springframework.context.MessageSource;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.support.ResourceBundleMessageSource;
import org.springframework.validation.beanvalidation.LocalValidatorFactoryBean;
import org.springframework.web.servlet.i18n.AcceptHeaderLocaleResolver;
import org.springframework.web.servlet.i18n.SessionLocaleResolver;import java.nio.charset.StandardCharsets;
import java.util.Locale;/*** @Author xingo* @Date 2024/12/11*/
@Configuration
public class LocaleConfig {/*** 默认解析器 其中locale表示默认语言,当请求中未包含语种信息,则设置默认语种* 当前默认为简体中文,zh_CN*/@Beanpublic SessionLocaleResolver localeResolver() {
//        AcceptHeaderLocaleResolver localeResolver = new AcceptHeaderLocaleResolver();SessionLocaleResolver localeResolver = new SessionLocaleResolver();localeResolver.setDefaultLocale(Locale.SIMPLIFIED_CHINESE);return localeResolver;}@Beanpublic LocalValidatorFactoryBean localValidatorFactoryBean() {LocalValidatorFactoryBean bean = new LocalValidatorFactoryBean();// 设置消息源bean.setValidationMessageSource(resourceBundleMessageSource());return bean;}@Bean(name = "messageSource")public MessageSource resourceBundleMessageSource() {ResourceBundleMessageSource messageSource = new ResourceBundleMessageSource();messageSource.setDefaultEncoding(StandardCharsets.UTF_8.toString());// 多语言文件messageSource.addBasenames("i18n/messages");// 可以根据业务的不同将国际化信息存放在多个文件中
//        messageSource.addBasenames("i18n/security");
//        messageSource.addBasenames("i18n/oss");
//        messageSource.addBasenames("i18n/excel");return messageSource;}
}

2、定义拦截器处理请求头的语言信息:

java">import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.LocaleResolver;
import org.springframework.web.servlet.i18n.LocaleChangeInterceptor;
import org.springframework.web.servlet.support.RequestContextUtils;import java.util.Locale;/*** @Author xingo* @Date 2024/12/11*/
@Slf4j
@Component
public class LocaleInterceptor extends LocaleChangeInterceptor {private static final String LOCALE = "Accept-Language";@Overridepublic boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) {String newLocale = request.getHeader(LOCALE);if (newLocale != null) {LocaleResolver localeResolver = RequestContextUtils.getLocaleResolver(request);try {localeResolver.setLocale(request, response, parseLocaleValue(newLocale));} catch (Exception e) {log.error("LocaleInterceptor error", e);localeResolver.setLocale(request, response, Locale.SIMPLIFIED_CHINESE);}} else {LocaleResolver localeResolver = RequestContextUtils.getLocaleResolver(request);localeResolver.setLocale(request, response, Locale.SIMPLIFIED_CHINESE);}return true;}}

3、将拦截器注入到springboot中:

java">import lombok.RequiredArgsConstructor;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.CorsRegistry;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;/*** @Author xingo* @Date 2024/12/11*/
@Configuration
@RequiredArgsConstructor
public class WebMvcConfiguration implements WebMvcConfigurer {private final LocaleInterceptor localeInterceptor;@Overridepublic void addInterceptors(InterceptorRegistry registry) {registry.addInterceptor(localeInterceptor).addPathPatterns("/**");    // 所有的请求都要拦截}@Overridepublic void addCorsMappings(CorsRegistry registry) {registry // 允许所有路径.addMapping("/**")// 允许携带凭证.allowCredentials(true)// 允许所有请求方法.allowedMethods("*")// 允许所有请求域名.allowedOriginPatterns("*")// 允许所有请求头.allowedHeaders("*")// 允许所有响应头.exposedHeaders("*");}
}

以上步骤完成后,就实现了一个国际化系统的基本框架,为了使用方便,还需要定义一个工具类用于获取国际化信息:

java">import lombok.Builder;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.MessageSource;
import org.springframework.context.i18n.LocaleContextHolder;
import org.springframework.stereotype.Component;import java.util.List;
import java.util.Locale;/*** @Author xingo* @Date 2024/12/11*/
@Slf4j
@Component
public class I18NUtils {public static final List<String> LOCALES = List.of("zh_CN", "en_US");private static MessageSource messageSource;public I18NUtils(MessageSource messageSource) {I18NUtils.messageSource = messageSource;}public static String get(String key) {String i18n = key;try {i18n = messageSource.getMessage(key, null, LocaleContextHolder.getLocale());} catch (Exception ex) {log.warn("[I18NUtils]WithoutArg:{}|{}", key, ex.getMessage());}return i18n;}public static String getCustomLocale(String key, Locale locale) {String i18n = null;try {i18n = messageSource.getMessage(key, null, locale);} catch (Exception ex) {log.error("[I18NUtils]WithoutArgWithLocale:{}", ex.getMessage());}return i18n;}public static String get(String key, Object... arg) {String i18n = null;try {i18n = messageSource.getMessage(key, arg, LocaleContextHolder.getLocale());} catch (Exception ex) {log.error("[I18NUtils]WithoutArg:{}", ex.getMessage());}return i18n;}
}

大功告成!写一个测试接口看看是否符合预期:

java">import org.springframework.context.i18n.LocaleContextHolder;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import org.xingo.config.I18NUtils;/*** @Author xingo* @Date 2024/12/11*/
@RestController
public class TestController {@GetMapping("/hello")public String hello() {System.out.println(LocaleContextHolder.getLocale());return I18NUtils.get("hello");}
}

使用postman请求接口,通过调整请求头中的 Accept-Language 观察返回值!
zh_CN返回值

en_US返回值


http://www.ppmy.cn/ops/149992.html

相关文章

【计算机网络】深入浅出计算机网络

第一章 计算机网络在信息时代的作用 计算机网络已由一种通信基础设施发展成一种重要的信息服务基础设施 CNNIC 中国互联网网络信息中心 因特网概述 网络、互联网和因特网 网络&#xff08;Network&#xff09;由若干结点&#xff08;Node&#xff09;和连接这些结点的链路…

《2025 CES 国际消费电子展:科技狂潮,未来已来》

一、2025 CES 盛大启幕&#xff0c;全球科技共襄盛举 当地时间 1 月 7 日&#xff0c;备受瞩目的 2025CES&#xff08;国际消费电子展&#xff09;在美国拉斯维加斯盛大开幕。作为全球规模最大、影响力最深远的消费技术产业盛会&#xff0c;CES 自 1967 年举办以来&#xff0c…

Docker-compose Prometheus Grafana 安装

环境准备 #要在 Vim 中默认启用 set paste 和 set number&#xff0c; vim ~/.vimrc #在 .vimrc 文件中添加以下内容&#xff1a; set paste set number 安装 Docker Compose sudo curl -L "https://github.com/docker/compose/releases/download/2.31.1/docker-compos…

docker run一个镜像如何指定最大可使用的内存大小、cpu大小

在 Docker 中&#xff0c;你可以通过 --memory 和 --cpus 参数来指定容器的最大内存和 CPU 限制。这样可以确保容器不会超出特定的资源限制&#xff0c;从而避免影响主机的其他进程。 1. 限制内存&#xff08;--memory&#xff09; 通过 --memory 或 -m 参数&#xff0c;你可…

Linux系统编程之线程优先级

概述 在Linux系统中&#xff0c;线程优先级是影响多线程应用程序性能和响应速度的关键因素之一。通过合理设置线程优先级&#xff0c;可以确保关键任务得到及时处理&#xff0c;同时避免低优先级任务过度占用系统资源。 线程优先级是指操作系统根据一定的规则分配给每个线程的一…

超大规模分类(三):KNN softmax

传统的分类损失计算输入数据和每个类别中心的距离&#xff0c;来优化模型的训练。KNN softmax通过选择和输入数据最相关的top-K个类别&#xff0c;仅计算输入数据和top-K个类别中心的距离&#xff0c;以减小计算量。 KNN softmax首次诞生于达摩院机器智能技术实验室发表的SIGKD…

拉依达的嵌入式\驱动面试宝典》—Linux篇(四)_Linux驱动编程

《拉依达的嵌入式\驱动面试宝典》—Linux篇(四)_Linux驱动编程 你好,我是拉依达。 感谢所有阅读关注我的同学支持,目前博客累计阅读 27w,关注1.5w人。其中博客《最全Linux驱动开发全流程详细解析(持续更新)-CSDN博客》已经是 Linux驱动 相关内容搜索的推荐首位,感谢大家支…

怎么用python写个唤醒睡眠电脑的脚本?

环境&#xff1a; win10 python3.12 问题描述&#xff1a; 怎么用python写个唤醒睡眠电脑的脚本&#xff1f; 解决方案&#xff1a; 1.唤醒处于睡眠状态的电脑通常不是通过编程直接实现的&#xff0c;而是依赖于硬件和操作系统提供的特性。对于Windows系统&#xff0c;可…