Spring Boot学习系列(七)------国际化实现
前言
基本上了解了SpringBoot的项目使用之后,也需要自己动手来多练习,因此这篇文章,来写一个很简单的Demo,使用SpringBoot来实现国际化.
正文
1. 创建项目,实现首页的默认访问
首先我们使用IDEA来创建一个SpringBoot项目,仅仅添加了Web模块,项目结构如下:
接下来我们引入要用的页面:
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
<meta name="description" content="">
<meta name="author" content="">
<title>Signin Template for Bootstrap</title>
<!-- Bootstrap core CSS -->
<link href="asserts/css/bootstrap.min.css" rel="stylesheet">
<!-- Custom styles for this template -->
<link href="asserts/css/signin.css" rel="stylesheet">
</head>
<body class="text-center">
<form class="form-signin" action="dashboard.html" th:action="@{/user/login}" method="post">
<img class="mb-4" src="asserts/img/bootstrap-solid.svg" alt="" width="72" height="72">
<h1 class="h3 mb-3 font-weight-normal" th:text="#{login.tip}">Please sign in</h1>
<!--判断-->
<p style="color: red" th:text="${msg}" th:if="${not #strings.isEmpty(msg)}"></p>
<label class="sr-only" >Username</label>
<input type="text" name="username" class="form-control" placeholder="Username" th:placeholder="#{login.username}" required="" autofocus="">
<label class="sr-only" >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"/> Remember Me
</label>
</div>
<button class="btn btn-lg btn-primary btn-block" type="submit" th:text="#{login.btn}">Sign in</button>
<p class="mt-5 mb-3 text-muted">© 2017-2018</p>
<a class="btn btn-sm" >中文</a>
<a class="btn btn-sm" >English</a>
</form>
</body>
</html>
可以看到,在页面中引入了一些css样式,还有bootstrap的样式,这里我们使用webjars的方式来引入jar文件.,打开https://www.webjars.org/
,我们引入Bootstrap的pom坐标"
<dependency>
<groupId>org.webjars</groupId>
<artifactId>bootstrap</artifactId>
<version>4.1.3</version>
</dependency>
可以看到依赖中已经存在了:
接着引入Thymeleaf
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring‐boot‐starter‐thymeleaf</artifactId>
</dependency>
因为SpringBoot已经帮我们控制版本,所以我们不需要指定版本,版本的切换查看我的其他博文即可.
引入了对应的文件以后,我们先来写个controller:
@Controller
public class IndexController {
@RequestMapping({"/", "/index.html"})
public String login() {
return "login";
}
}
OK,现在我们访问http://localhost:8080/
,可以成功访问页面了:
如果没有修改login.html中的图片路径,图片是看不到的,要修改一下:
<img class="mb-4" src="asserts/img/bootstrap-solid.svg" th:src="@{asserts/img/bootstrap-solid.svg}" alt="" width="72" height="72">
还要修改页面中的js文件的引用路径
现在,我们使用的controller增加方法的方式来跳转到登录页面的,我们知道,SpringBoot为我们自动配置了很多的东西,其实,我们可以直接自定义一个配置类,直接在配置类中增加页面的跳转映射:
这里需要注意,我们前面的博文中讲到,要实现自己的配置,需要继承类WebMvcConfigurerAdapter
,但是在SpringBoot2.0中,这个方法已经过时了,但是我们可以直接实现接口WebMvcConfigurer
,得益于java1.8的新特性,现在接口的方法可以选择实现,不用全部实现,因此我们可以实现以下方法来增加:
@Configuration//这个自定义的配置要继承
public class MyConfig implements WebMvcConfigurer {
@Override
public void addViewControllers(ViewControllerRegistry registry) {
registry.addViewController("/login").setViewName("login");
}
}
这里需要注意,如果我们使用了注解@Configuration,就不必使用@Bean注解来注册这个配置类
,这样,当我们访问http://localhost:8080/login
的时候,页面也会跳转到登录页面,使用这样的方式可以不用写controller层的方法.
2.实现页面国际化
目前我们的页面是这样的:
可以看到,页面上有五个地方需要国际化转化,目前没有完成的情况下,点击页面中的中文
和English
是没有效果的.
下面我们来实现国际化页面:
- 编写国际化配置文件,抽取页面需要格式化的信息
如图,在resource目录下创建一个目录用来保存国际化属性文件,创建对应的页面属性文件,文件中的五个属性分别对应login页面中需要国际化的信息.
-
使用SpringBoot的国际化管理组件
在以前使用SpringMVC的时候,我们要自己写一个国际化信息管理组件,现在使用了SpringBoot以后,我们直接使用即可,查看SpringBoot的代码可以看到有一个组件:
MessageSourceAutoConfiguration
,这是SpringBoot帮我们配置好的,我们可以看一下这个类"public class MessageSourceAutoConfiguration { private static final Resource[] NO_RESOURCES = new Resource[0]; public MessageSourceAutoConfiguration() { } @Bean @ConfigurationProperties( prefix = "spring.messages" ) @Bean public MessageSource messageSource() { MessageSourceProperties properties = this.messageSourceProperties(); ResourceBundleMessageSource messageSource = new ResourceBundleMessageSource(); if (StringUtils.hasText(properties.getBasename())) { messageSource.setBasenames(StringUtils.commaDelimitedListToStringArray(StringUtils.trimAllWhitespace(properties.getBasename()))); } if (properties.getEncoding() != null) { messageSource.setDefaultEncoding(properties.getEncoding().name()); } messageSource.setFallbackToSystemLocale(properties.isFallbackToSystemLocale()); Duration cacheDuration = properties.getCacheDuration(); if (cacheDuration != null) { messageSource.setCacheMillis(cacheDuration.toMillis()); } messageSource.setAlwaysUseMessageFormat(properties.isAlwaysUseMessageFormat()); messageSource.setUseCodeAsDefaultMessage(properties.isUseCodeAsDefaultMessage()); return messageSource; }
**可以看到,SpringBoot自动装配的国际化组件使用的属性名是message,如果我们的属性文件命名为message,就可以直接在页面使用.**在这里我们使用了自己的,所以需要在配置文件中定义一个属性:
spring.messages.basename=international.login
属性值指向国际化文件,这样我们就可以取值了.
-
在页面获取国际化的值
在Thymeleaf中,可以使用
#{}
来获取国际化的值,所以我们修改一下html文件:<!DOCTYPE html> <html lang="en" xmlns:th="http://www.thymeleaf.org"> <head> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no"> <meta name="description" content=""> <meta name="author" content=""> <title>Signin Template for Bootstrap</title> <!-- Bootstrap core CSS --> <link href="asserts/css/bootstrap.min.css" th:href="@{/webjars/bootstrap/4.1.3/css/bootstrap.css}" rel="stylesheet"> <!-- Custom styles for this template --> <link href="asserts/css/signin.css" th:href="@{/asserts/css/signin.css}" rel="stylesheet"> </head> <body class="text-center"> <form class="form-signin" action="dashboard.html" method="post"> <img class="mb-4" src="asserts/img/bootstrap-solid.svg" th:src="@{asserts/img/bootstrap-solid.svg}" alt="" width="72" height="72"> <h1 class="h3 mb-3 font-weight-normal" th:text="#{login.tip}">Please sign in</h1> <!--判断--> <p style="color: red" ></p> <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"/> Remember Me [[#{login.remember}]] </label> </div> <button class="btn btn-lg btn-primary btn-block" type="submit" th:text="#{login.btn}">Sign in</button> <p class="mt-5 mb-3 text-muted">© 2017-2018</p> <a class="btn btn-sm" >中文</a> <a class="btn btn-sm" >English</a> </form> </body> </html>
启动项目,可以看到,页面已经变成了中文,需要注意的是,SpringBoot的国际化是按照浏览器的默认语言来设置的,如果我们修改了浏览器的语言为英语,刷新一下以后,页面会自动切换成英语的.
4.根据点击按钮来实现语言切换
现在页面有两个按钮,我们要实现点击不同的按钮,切换不同的语言,就要明白SpringBoot实现国际化的原理:
当一个请求到达服务端以后,SpringBoot会有一个区域信息解析器LocaleResolver
来解析请求头中的区域信息,根据不同的请求内容,响应不同的国际化内容,我们可以查看WebMvcAutoConfiguration类
:
@Bean
@ConditionalOnMissingBean
@ConditionalOnProperty(
prefix = "spring.mvc",
name = {"locale"}
)
public LocaleResolver localeResolver() {
if (this.mvcProperties.getLocaleResolver() == org.springframework.boot.autoconfigure.web.servlet.WebMvcProperties.LocaleResolver.FIXED) {
return new FixedLocaleResolver(this.mvcProperties.getLocale());
} else {
AcceptHeaderLocaleResolver localeResolver = new AcceptHeaderLocaleResolver();
localeResolver.setDefaultLocale(this.mvcProperties.getLocale());
return localeResolver;
}
}
可以看到,默认情况下,SpringBoot使用自己的区域信息解析器来解析国家化信息的,我们要实现这个需求,只需要自己创建一个解析器,并添加到容器中即可:
package com.xiaojian.springboot.international.component;
import org.springframework.context.annotation.Configuration;
import org.springframework.util.StringUtils;
import org.springframework.web.servlet.LocaleResolver;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.Locale;
/**
* 自定义的国际化区域对象
*/
public class MyLocaResolver implements LocaleResolver {
@Override
public Locale resolveLocale(HttpServletRequest request) {
System.out.println("区域信息解析器~~~~~~~~~~");
String local = request.getParameter("local");
Locale locale = Locale.getDefault();
if (!StringUtils.isEmpty(local)) {
String[] split = local.split("_");
locale = new Locale(split[0], split[1]);
}
return locale;
}
@Override
public void setLocale(HttpServletRequest request, HttpServletResponse response, Locale locale) {
}
}
然后在配置类中注册bean:
@Bean
public LocaleResolver localeResolver() {
return new MyLocaResolver();
}
然后更改页面中两个按钮的连接地址:
<a class="btn btn-sm" th:href="@{/login(local='zh_CN')}">中文</a>
<a class="btn btn-sm" th:href="@{/login(local='en_US')}">English</a>
启动项目以后,点击按钮就可以实现不同的语言切换.
总结
至此,国际化的功能初步实现了,回头看来,SpringBoot在初始化以后,为我们配置了很多的组件来方便我们的开发,我们要自己定制化,就要写好自己的组件并注册使用.