SpringBoot下资源国际化应用实践

简介: SpringBoot下资源国际化应用实践

【1】SpringBoot的自动配置

SpringBoot自动配置好了管理国际化资源文件的组件:

@Configuration
@ConditionalOnMissingBean(value = MessageSource.class, search = SearchStrategy.CURRENT)
@AutoConfigureOrder(Ordered.HIGHEST_PRECEDENCE)
@Conditional(ResourceBundleCondition.class)
@EnableConfigurationProperties
@ConfigurationProperties(prefix = "spring.messages")
public class MessageSourceAutoConfiguration {
  private static final Resource[] NO_RESOURCES = {};
  /**
   * Comma-separated list of basenames (essentially a fully-qualified classpath
   * location), each following the ResourceBundle convention with relaxed support for
   * slash based locations. If it doesn't contain a package qualifier (such as
   * "org.mypackage"), it will be resolved from the classpath root.
   */
  private String basename = "messages";
  //我们的配置文件可以直接放在类路径下叫messages.properties;
  /**
   * Message bundles encoding.
   */
  private Charset encoding = Charset.forName("UTF-8");
  /**
   * Loaded resource bundle files cache expiration, in seconds. When set to -1, bundles
   * are cached forever.
   */
  private int cacheSeconds = -1;
  /**
   * Set whether to fall back to the system Locale if no files for a specific Locale
   * have been found. if this is turned off, the only fallback will be the default file
   * (e.g. "messages.properties" for basename "messages").
   */
  private boolean fallbackToSystemLocale = true;
  /**
   * Set whether to always apply the MessageFormat rules, parsing even messages without
   * arguments.
   */
  private boolean alwaysUseMessageFormat = false;
  //为容器添加了ResourceBundleMessageSource 组件
  @Bean
  public MessageSource messageSource() {
    ResourceBundleMessageSource messageSource = new ResourceBundleMessageSource();
    if (StringUtils.hasText(this.basename)) {
      //设置国际化资源文件的基础名(去掉语言国家代码的)
      messageSource.setBasenames(StringUtils.commaDelimitedListToStringArray(
          StringUtils.trimAllWhitespace(this.basename)));
    }
    if (this.encoding != null) {
      messageSource.setDefaultEncoding(this.encoding.name());
    }
    messageSource.setFallbackToSystemLocale(this.fallbackToSystemLocale);
    messageSource.setCacheSeconds(this.cacheSeconds);
    messageSource.setAlwaysUseMessageFormat(this.alwaysUseMessageFormat);
    return messageSource;
  }

还可以在SpringBoot的配置文件中使用spring.messages前缀配置国际化:

# 国际化配置文件(包名.基础名)
spring.messages.basename=i18n.login

【2】编写国际化资源文件

抽取页面需要显示的国际化消息,编写国际化资源文件。

login.properties


如图所示,idea会自动切换到国际化视图。另外,在编写properties时,除了传统的使用key:value在properties中编写外,还可以如下所示:


【3】页面示例

如下所示,在页面中使用properties的属性:

<label class="sr-only" th:text="#{login.username}">Username</label>
<input type="text"  name="username" class="form-control" placeholder="Username" th:placeholder="#{login.username}" required="" autofocus="">
<label class="sr-only" th:text="#{login.password}">Password</label>
<input type="password" name="password" class="form-control" placeholder="Password" th:placeholder="#{login.password}" required="">
<div class="checkbox mb-3">
<label>
<input type="checkbox" value="remember-me"/> [[#{login.remember}]]
//这里使用行内写法,input是自结束标签,没有标签体
</label>
</div>
<button class="btn btn-lg btn-primary btn-block" type="submit" th:text="#{login.btn}">Sign in</button>

注意这里使用的是#{...}语法,可以参考Thymeleaf中第四章Standard Expression Syntax中4.1Messages讲解,如下图.


测试结果:

浏览器设置英文:



浏览器设置中文:


【4】SpringBoot对资源国际化解析原理

首先明白两个组件:国际化Locale(区域信息对象);LocaleResolver(获取区域信息对象)。


① WebMVCAutoConfiguration中对LocaleResolver 配置

@Bean
@ConditionalOnMissingBean
@ConditionalOnProperty(prefix = "spring.mvc", name = "locale")
public LocaleResolver localeResolver() {
  if (this.mvcProperties
      .getLocaleResolver() == WebMvcProperties.LocaleResolver.FIXED) {
    return new FixedLocaleResolver(this.mvcProperties.getLocale());
  }
  AcceptHeaderLocaleResolver localeResolver = new AcceptHeaderLocaleResolver();
  localeResolver.setDefaultLocale(this.mvcProperties.getLocale());
  return localeResolver;
}


如果spring.mvc.locale没有指定,那么就返回一个AcceptHeaderLocaleResolver 。如果指定了spring.mvc.locale,那么就返回FixedLocaleResolver。


② 查看AcceptHeaderLocaleResolver

@Override
public Locale resolveLocale(HttpServletRequest request) {
  Locale defaultLocale = getDefaultLocale();
  if (defaultLocale != null && request.getHeader("Accept-Language") == null) {
    return defaultLocale;
  }
  Locale requestLocale = request.getLocale();
  if (isSupportedLocale(requestLocale)) {
    return requestLocale;
  }
  Locale supportedLocale = findSupportedLocale(request);
  if (supportedLocale != null) {
    return supportedLocale;
  }
  return (defaultLocale != null ? defaultLocale : requestLocale);
}

**从请求头里面解析Locale!**这也就是为什么浏览器切换语言显示不同资源的原理。


【5】中英切换

如下图所示,通过点击中文英文按钮切换不同资源显示:



① 页面修改如下:

<a class="btn btn-sm" th:href="@{/index.html(l='zh_CN')}">中文</a>
<a class="btn btn-sm" th:href="@{/index.html(l='en_US')}">English</a>


这里使用的是Thymeleaf模板引擎中链接参数的写法(key=value),也可以使用原始写法如下:

<a class="btn btn-sm" th:href="@{/index.html?l=zh_CN}">中文</a>
<a class="btn btn-sm" th:href="@{/index.html?l=en_US}">English</a>

② 编写自定义区域信息解析器

/**
 * 可以在连接上携带区域信息
 */
public class MyLocaleResolver implements LocaleResolver {
    @Override
    public Locale resolveLocale(HttpServletRequest request) {
        String l = request.getParameter("l");
        Locale locale = Locale.getDefault();
        if(!StringUtils.isEmpty(l)){
            String[] split = l.split("_");
            locale = new Locale(split[0],split[1]);
        }
        return locale;
    }
    @Override
    public void setLocale(HttpServletRequest request, HttpServletResponse response, Locale locale) {
    }
}

将其添加到容器中:

@Configuration
public class MyMvcConfig extends WebMvcConfigurerAdapter {
  @Bean
    public LocaleResolver localeResolver(){
        return new MyLocaleResolver();
    }
}

③ Locale.getDefault()

该方法根据系统环境拿到Locale,如本机上如果没有传 l 参数,那么就会返回defaultLocale。此时无论浏览器语言设置什么,都显示中文。

 /**
  * Gets the current value of the default locale for this instance
   * of the Java Virtual Machine.
   * <p>
   * The Java Virtual Machine sets the default locale during startup
   * based on the host environment. It is used by many locale-sensitive
   * methods if no locale is explicitly specified.
   * It can be changed using the
   * {@link #setDefault(java.util.Locale) setDefault} method.
   *
   * @return the default locale for this instance of the Java Virtual Machine
   */
  public static Locale getDefault() {
      // do not synchronize this method - see 4071298
      return defaultLocale;
  }
目录
相关文章
|
JSON 前端开发 Java
深入理解 Spring Boot 中日期时间格式化:@DateTimeFormat 与 @JsonFormat 完整实践
在 Spring Boot 开发中,日期时间格式化是前后端交互的常见痛点。本文详细解析了 **@DateTimeFormat** 和 **@JsonFormat** 两个注解的用法,分别用于将前端传入的字符串解析为 Java 时间对象,以及将时间对象序列化为指定格式返回给前端。通过完整示例代码,展示了从数据接收、业务处理到结果返回的全流程,并总结了解决时区问题和全局配置的最佳实践,助你高效处理日期时间需求。
2262 0
|
存储 Java 数据库
Spring Boot 注册登录系统:问题总结与优化实践
在Spring Boot开发中,注册登录模块常面临数据库设计、密码加密、权限配置及用户体验等问题。本文以便利店销售系统为例,详细解析四大类问题:数据库字段约束(如默认值缺失)、密码加密(明文存储风险)、Spring Security配置(路径权限不当)以及表单交互(数据丢失与提示不足)。通过优化数据库结构、引入BCrypt加密、完善安全配置和改进用户交互,提供了一套全面的解决方案,助力开发者构建更 robust 的系统。
560 0
|
10月前
|
JavaScript Java Maven
【SpringBoot(二)】带你认识Yaml配置文件类型、SpringMVC的资源访问路径 和 静态资源配置的原理!
SpringBoot专栏第二章,从本章开始正式进入SpringBoot的WEB阶段开发,本章先带你认识yaml配置文件和资源的路径配置原理,以方便在后面的文章中打下基础
675 4
|
SQL Java 数据库
解决Java Spring Boot应用中MyBatis-Plus查询问题的策略。
保持技能更新是侦探的重要素质。定期回顾最佳实践和新技术。比如,定期查看MyBatis-Plus的更新和社区的最佳做法,这样才能不断提升查询效率和性能。
866 1
|
安全 Java API
Spring Boot 功能模块全解析:构建现代Java应用的技术图谱
Spring Boot不是一个单一的工具,而是一个由众多功能模块组成的生态系统。这些模块可以根据应用需求灵活组合,构建从简单的REST API到复杂的微服务系统,再到现代的AI驱动应用。
1769 8
|
JSON 前端开发 Java
深入理解 Spring Boot 中日期时间格式化:@DateTimeFormat 与 @JsonFormat 完整实践
在 Spring Boot 开发中,处理前后端日期交互是一个常见问题。本文通过 **@DateTimeFormat** 和 **@JsonFormat** 两个注解,详细讲解了如何解析前端传来的日期字符串以及以指定格式返回日期数据。文章从实际案例出发,结合代码演示两者的使用场景与注意事项,解决解析失败、时区偏差等问题,并提供全局配置与局部注解的实践经验。帮助开发者高效应对日期时间格式化需求,提升开发效率。
4325 2
|
前端开发 Java Nacos
🛡️Spring Boot 3 整合 Spring Cloud Gateway 工程实践
本文介绍了如何使用Spring Cloud Alibaba 2023.0.0.0技术栈构建微服务网关,以应对微服务架构中流量治理与安全管控的复杂性。通过一个包含鉴权服务、文件服务和主服务的项目,详细讲解了网关的整合与功能开发。首先,通过统一路由配置,将所有请求集中到网关进行管理;其次,实现了限流防刷功能,防止恶意刷接口;最后,添加了登录鉴权机制,确保用户身份验证。整个过程结合Nacos注册中心,确保服务注册与配置管理的高效性。通过这些实践,帮助开发者更好地理解和应用微服务网关。
2661 0
🛡️Spring Boot 3 整合 Spring Cloud Gateway 工程实践
|
Java 应用服务中间件 API
【潜意识Java】javaee中的SpringBoot在Java 开发中的应用与详细分析
本文介绍了 Spring Boot 的核心概念和使用场景,并通过一个实战项目演示了如何构建一个简单的 RESTful API。
543 5
|
负载均衡 Java 开发者
深入探索Spring Cloud与Spring Boot:构建微服务架构的实践经验
深入探索Spring Cloud与Spring Boot:构建微服务架构的实践经验
992 5
|
安全 Java 数据安全/隐私保护
如何使用Spring Boot进行表单登录身份验证:从基础到实践
如何使用Spring Boot进行表单登录身份验证:从基础到实践
617 5