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;
  }
目录
相关文章
|
6天前
|
Java Maven Docker
gitlab-ci 集成 k3s 部署spring boot 应用
gitlab-ci 集成 k3s 部署spring boot 应用
|
3月前
|
存储 前端开发 Java
SpringBoot使用云端资源url下载文件的接口写法
在Spring Boot中实现从云端资源URL下载文件的功能可通过定义REST接口完成。示例代码展示了一个`FileDownloadController`,它包含使用`@GetMapping`注解的方法`downloadFile`,此方法接收URL参数,利用`RestTemplate`下载文件,并将文件字节数组封装为`ByteArrayResource`返回给客户端。此外,通过设置HTTP响应头,确保文件以附件形式下载。这种方法适用于从AWS S3或Google Cloud Storage等云服务下载文件。
339 7
|
3月前
|
缓存 监控 Java
优化Spring Boot应用的数据库访问性能
优化Spring Boot应用的数据库访问性能
|
24天前
|
Kubernetes Cloud Native Java
当 Quarkus 遇上 Spring Boot,谁才是现代云原生应用的终极之选?究竟哪款能助你的应用傲视群雄?
Quarkus 和 Spring Boot 均为构建现代云原生应用的热门框架,旨在简化开发流程并提升性能。Spring Boot 依托庞大的 Spring 生态系统,提供开箱即用的体验,适合快速搭建应用。Quarkus 由红帽发起,专为 GraalVM 和 HotSpot 设计,强调性能优化和资源消耗最小化,是云原生环境的理想选择。
25 3
|
2月前
|
Java 开发者 Spring
"揭秘SpringBoot魔法SPI机制:一键解锁服务扩展新姿势,让你的应用灵活飞天!"
【8月更文挑战第11天】SPI(Service Provider Interface)是Java的服务提供发现机制,用于运行时动态查找和加载服务实现。SpringBoot在其基础上进行了封装和优化,通过`spring.factories`文件提供更集中的配置方式,便于框架扩展和组件替换。本文通过定义接口`HelloService`及其实现类`HelloServiceImpl`,并在`spring.factories`中配置,结合`SpringFactoriesLoader`加载服务,展示了SpringBoot SPI机制的工作流程和优势。
47 5
|
2月前
|
缓存 Java 数据库连接
Spring Boot 资源文件属性配置,紧跟技术热点,为你的应用注入灵动活力!
【8月更文挑战第29天】在Spring Boot开发中,资源文件属性配置至关重要,它让开发者能灵活定制应用行为而不改动代码,极大提升了可维护性和扩展性。Spring Boot支持多种配置文件类型,如`application.properties`和`application.yml`,分别位于项目的resources目录下。`.properties`文件采用键值对形式,而`yml`文件则具有更清晰的层次结构,适合复杂配置。此外,Spring Boot还支持占位符引用和其他外部来源的属性值,便于不同环境下覆盖默认配置。通过合理配置,应用能快速适应各种环境与需求变化。
36 0
|
2月前
|
NoSQL Java Redis
Spring Boot集成Redis全攻略:高效数据存取,打造性能飞跃的Java微服务应用!
【8月更文挑战第3天】Spring Boot是备受欢迎的微服务框架,以其快速开发与轻量特性著称。结合高性能键值数据库Redis,可显著增强应用性能。集成步骤包括:添加`spring-boot-starter-data-redis`依赖,配置Redis服务器参数,注入`RedisTemplate`或`StringRedisTemplate`进行数据操作。这种集成方案适用于缓存、高并发等场景,有效提升数据处理效率。
366 2
|
2月前
|
监控 Java Serverless
美团 Flink 大作业部署问题之想在Serverless平台上实时查看Spring Boot应用的日志要怎么操作
美团 Flink 大作业部署问题之想在Serverless平台上实时查看Spring Boot应用的日志要怎么操作
|
2月前
|
Java Linux C++
【Azure 应用服务】App Service For Linux 部署Java Spring Boot应用后,查看日志文件时的疑惑
【Azure 应用服务】App Service For Linux 部署Java Spring Boot应用后,查看日志文件时的疑惑
|
3月前
|
存储 Java Serverless
Java Spring Boot应用如何实现推送代码到指定仓库并自动部署
函数计算产品作为一种事件驱动的全托管计算服务,让用户能够专注于业务逻辑的编写,而无需关心底层服务器的管理与运维。你可以有效地利用函数计算产品来支撑各类应用场景,从简单的数据处理到复杂的业务逻辑,实现快速、高效、低成本的云上部署与运维。以下是一些关于使用函数计算产品的合集和要点,帮助你更好地理解和应用这一服务。