SpringBoot第十集:i18n与Webjars的应用(2020最新最易懂)
SpringBoot第十集:i18n与Webjars的应用(2020最新最易懂)
一,页面国际化
i18n(其来源是英文单词 internationalization的首末字符i和n,18为中间的字符数)是“国际化”的简称。除了i18n(支持多种语言),L10n(localization),g11n(globalization),还有m17n(multilingualization)
1,什么是国际化
国际化就是可以把页面中的中文变成英文。根据地区使用语言,及浏览器语言使用不同,页面语言也随之而变化。例如阿里巴巴官网,Dubbo的官方网站等

2, 如何实现页面国际化?
A,准备工作
- 确保工作空间编码,和后续新建工程文件编码都是UTF-8(支持语言类型最强大,俗称万国码)
- 新建SpringBoot工程整合Thymeleaf(一切网页交给模板引擎Thymeleaf接管),并提供默认模板。(整合参考:SpringBoot第九集整合模板引擎)
至于页面模板,自己做一个挺麻烦的,可以参考很多后台组件或模板,BootStrap,EazyUI,layUI,Sematic UI,Admin,XAdmin,AdminLet, Light Year Admin等(我用过的都说了,你看着办) - 新增控制器,访问页面模板
1 @Controller
2 public class AdminController {
3
4 /**
5 * @return 跳转去登录
6 */
7 @RequestMapping("/login")
8 public String login() {
9 return "login";
10 }
11
12 }http://localhost:8080/login
访问效果:

注意不要忘记整合Thymeleaf需要加如约束:1 <html class="x-admin-sm" xmlns:th="http://www.thymeleaf.org">
- 新增国际化配置文件properties,抽取页面需要显示的国际化消息定义在不同命名的文件中。
关于配置文件的命名格式:基本名称+“_”+语言简称+“_”+国家简称.properties 注意严格区分大小写(关于语言简称可以在附录中查阅,列举了 部分可供参考)
该案例命名举例:
login.properties:这个用于作为默认显示语言配置(默认访问页面时显示的语言配置)
login_zh_CN.properties:这个用于当指定使用中文时显示的语言配置
login_en_US.properties:这个用于当指定使用英文时显示的语言配置
实现:
a,在src/main/resources目录下新增i18n目录,新增三个配置文件
(当然不同的开发工具,目录结构效果和适配使用效果是不一样的,参考SpringBoot第一集)本次演示使用的工具是Spring Tool Suite
b,内容大概,实际情况根据你的情况而定
key对应value,其中key是自定义的,不一定要添加前缀,但是,几个文件中key一定要相同。1 ###用于默认语言显示的配置文件
2 login.message=管理员登录
3 login.username=用户名
4 login.password=密码
5 login.submit=请登录
6 #########################################
7 ###用于指定英文语言显示的配置文件
8 login.message=Administrator Login
9 login.username=user name
10 login.password=password
11 login.submit=Please Loginc,对应关系

- 修改网页默认数据区
按照Thymeleaf语法,修改网页,将所有文字信息,替换为properties属性获取的方式。
th:Thymeleaf配置属性语法,Thymeleaf替换值语法th:text,Thymeleaf取值语法#{..........}。详情参考博主模板引擎Thymeleaf常用语法。
1 <div class="login layui-anim layui-anim-up">
2 <!-- th:text的值会替换标签对之间的内容 -->
3 <div class="message" th:text="#{login.message}">x-admin2.0-管理登录</div>
4 <div id="darkbannerwrap"></div>
5
6 <form method="post" class="layui-form" >
7 <input name="username" th:placeholder="#{login.username}" type="text" lay-verify="required" class="layui-input" >
8 <hr class="hr15">
9 <input name="password" lay-verify="required" th:placeholder="#{login.password}" type="password" class="layui-input">
10 <hr class="hr15">
11 <input th:value="#{login.submit}" lay-submit lay-filter="login" style="width:100%;" type="submit">
12 <hr class="hr20" >
13 </form>
14 </div>
B,实现步骤
- 修改yml核心配置文件
1 spring:
2 # 国际化配置
3 messages:
4 # 国际化的文件的存储在src\main\resources 文件夹下的什么位置。注意这是个相对位置
5 basename: i18n/login
6 # 表示 messages 文件的缓存失效时间,如果不配置则缓存一直有效
7 cache-duration: 3600
8 # 配置编码
9 encoding: UTF-8
10 # 如果找不到语言,是不是返回服务器系统语言。
11 fallback-to-system-locale: true - 修改页面前端提交切换参数
th:是Thymeleaf属性设置语法。链接语法@{...uri..}。参数语法(key=value&key=value....)详情参考博主模板引擎Thymeleaf常用语法。
1 <a th:href="@{login(language=zh_CH)}">简体中文</a>
2 <a th:href="@{login(language=en_US)}">English</a> - 编写自定义语言信息解析器
编写普通类实现接口LocaleResolver,仿SpringBoot默认语言解析器实现(至于为什么,可以参考附录SpringBoot国际化源码解析)
1 public class LocaleMessageResolver implements LocaleResolver{
2 /**
3 * 用户可以使用request,根据指定的方式获取一个Locale,如果没有获取到,则使用用户指定的默认的Locale
4 */
5 @Override
6 public Locale resolveLocale(HttpServletRequest request) {
7 // 获取请求数据(切换语言传递的参数)
8 String language = request.getParameter("language");
9 System.out.println("测试获取的语言环境参数:"+language);
10 // 获取Java虚拟机此的默认区域语言环境
11 Locale defaultLocale = Locale.getDefault();
12 // 判断页面是否选择切换了语言
13 if (!StringUtil.isEmpty(language)) {// 如果不为null
14 // 选择了切换语言环境,将语言环境,根据下划线拆分
15 String[] split = language.split("_");// zh CH
16 // 创建新的语言环境,并替换默认语言环境(参数一:语言,参数二:国家,详情参考附录或JDK-API)
17 defaultLocale = new Locale(split[0], split[1]);
18 }
19 // 返回给页面的语言环境(要么系统默认,要么已经选定的)
20 return defaultLocale;
21 }
22
23 /**
24 * 用于实现Locale的切换。及响应(SpringBoot整合无需这个处理方法)
25 */
26 @Override
27 public void setLocale(HttpServletRequest request, HttpServletResponse response, Locale locale) {}
28
29 } - 将自定义加如到Spring IOC
如果不将自定义的语言解析器放入到Spring容器中,那么国际化就是无效的!!!
1 @Configuration // <beans>
2 public class LocaleConfig {
3 /**
4 * 说明:注入语言解析器时,方法名必须交localeResolver
5 */
6 @Bean // 注入bean
7 public LocaleMessageResolver localeResolver() {
8 return new LocaleMessageResolver();
9 }
10
11 } - 重启SpringBoot工程,访问测试

二.SpringBoot整合WebJars
通常对于web开发而言,像js、css、images等静态资源版本管理是比较混乱的,比如Jquery、Bootstrap、Vue.js可能各个前端框架所依赖的自个组件的版本都不尽相同,一不注意就可能引起不同版本的冲突问题。WebJars是将web前端资源(如jQuery & Bootstrap & VUE 等)打成jar包文件。借助版本管理工具(Maven、gradle等)进行版本管理,保证这些Web资源版本唯一性。避免了文件混乱、版本不一致等问题。
开始使用前,我们看下Jquery的webjars,借此来了解下webjars包的目录结构。

如上图,可以看到资源文件地址:META-INF/resources/webjars/jquery/3.5.1/jquery.js
使用方式
1.修改pom文件引入webjars依赖。
例如:当前引入JQuery测试(注意,虽然已经讲过热部署,但新增依赖依然可能需要重启服务)。查找更多依赖
1 <dependency>
2 <groupId>org.webjars</groupId>
3 <artifactId>jquery</artifactId>
4 <version>3.5.1</version>
5 </dependency>
2.页面引入JQueyr核心文件测试
webjars文件如何引入呢?参考SpringBoot第八集静态资源地址源码解析。
1 <script src="webjars/jquery/3.5.1/jquery.js" type="text/javascript" charset="utf-8"></script>
2 <script type="text/javascript">
3 $(function(){
4 alert("测试webjars是否引入JQuery可用....");
5 });
6 </script>
当访问:webjars/jquery/3.5.1/jquery.js 时,实际加载地址:META-INF/resources/webjars/jquery/3.5.1/jquery.js(资源原地址)
3.webjars应用扩展
当前状态:页面引入依赖文件时,访问路径地址加上版本号,总的来说一切都很正常!但时,一旦pom依赖引入的webjars版本更新了,我们就被迫必须更新前台代码。即当前的状态是,前端硬编码,不便于灵活使用和更新。所以官方提供了一个webjars-locator包,就是来解决此问题的。
- 在maven仓库搜索依赖,并引入到当前项目下
1 <!-- webjars优化版更新本问题 -->
2 <dependency>
3 <groupId>org.webjars</groupId>
4 <artifactId>webjars-locator</artifactId>
5 <version>0.40</version>
6 </dependency> - 修改页面引入路径问题
将页面引入路径版本号去除,此后,即使pom依赖更新版本,页面也无需更改了。(当然除非官方有特大改动,名字包名都更新了)
<script src="webjars/jquery/jquery.js" type="text/javascript" charset="utf-8"></script>
- 页面测试访问

附录
1.国际化配置文件语言命名
格式说明(严格区分大小写):语言_国家
命名下划线之前是:语言简称
命名下划线之后是:国家简称
| 语言 | 简称 |
|---|---|
| 简体中文(中国) | zh_CN |
| 繁体中文(中国台湾) | zh_TW |
| 繁体中文(中国香港) | zh_HK |
| 英语(中国香港) | en_HK |
| 英语(美国) | en_US |
| 英语(英国) | en_GB |
| 英语(全球) | en_WW |
| 英语(加拿大) | en_CA |
| 英语(澳大利亚) | en_AU |
| 英语(爱尔兰) | en_IE |
| 英语(芬兰) | en_FI |
| 芬兰语(芬兰) | fi_FI |
| 英语(丹麦) | en_DK |
| 丹麦语(丹麦) | da_DK |
| 英语(以色列) | en_IL |
| 希伯来语(以色列) | he_IL |
| 英语(南非) | en_ZA |
| 英语(印度) | en_IN |
| 英语(挪威) | en_NO |
| 英语(新加坡) | en_SG |
| 英语(新西兰) | en_NZ |
| 英语(印度尼西亚) | en_ID |
| 英语(菲律宾) | en_PH |
| 英语(泰国) | en_TH |
| 英语(马来西亚) | en_MY |
| 英语(阿拉伯) | en_XA |
| 韩文(韩国) | ko_KR |
| 日语(日本) | ja_JP |
| 荷兰语(荷兰) | nl_NL |
| 荷兰语(比利时) | nl_BE |
| 葡萄牙语(葡萄牙) | pt_PT |
| 葡萄牙语(巴西) | pt_BR |
| 法语(法国) | fr_FR |
| 法语(卢森堡) | fr_LU |
| 法语(瑞士) | fr_CH |
| 法语(比利时) | fr_BE |
| 法语(加拿大) | fr_CA |
| 西班牙语(拉丁美洲) | es_LA |
| 西班牙语(西班牙) | es_ES |
| 西班牙语(阿根廷) | es_AR |
| 西班牙语(美国) | es_US |
| 西班牙语(墨西哥) | es_MX |
| 西班牙语(哥伦比亚) | es_CO |
| 西班牙语(波多黎各) | es_PR |
| 德语(德国) | de_DE |
| 德语(奥地利) | de_AT |
| 德语(瑞士) | de_CH |
| 俄语(俄罗斯) | ru_RU |
| 意大利语(意大利) | it_IT |
| 希腊语(希腊) | el_GR |
| 挪威语(挪威) | no_NO |
| 匈牙利语(匈牙利) | hu_HU |
| 土耳其语(土耳其) | tr_TR |
| 捷克语(捷克共和国) | cs_CZ |
| 斯洛文尼亚语 | sl_SL |
| 波兰语(波兰) | pl_PL |
| 瑞典语(瑞典) | sv_SE |
| 西班牙语(智利) | es_CL |
2.SpringBoot国际化源码解析
springboot国际化的时候,是通过interface LocaleResolver 接口的实现类的bean来确定是哪种语言的。这个接口有2个方法: 1、resolveLocale 用来获取当前语言环境。 2、setLocale 修改语言环境。(针对Cookie、Session这种有状态的请求。)
LocaleResolver的实现类只有4个:
- AcceptHeaderLocaleResolver(主要解析看这个源码)
- CookieLocaleResolver
- FixedLocaleResolver
- SessionLocaleResolver 默认使用AcceptHeaderLocaleResolver实现。
1 public class AcceptHeaderLocaleResolver implements LocaleResolver {
2 /**略其他源码
3 * 语言解方法
4 */
5 @Override
6 public Locale resolveLocale(HttpServletRequest request) {
7 // 每次请求的时候,获取http的名字叫Accept-Language的header参数,当Accept-Language==null时,使用系统默认Locale;
8 Locale defaultLocale = getDefaultLocale();
9 if (defaultLocale != null && request.getHeader("Accept-Language") == null) {
10 return defaultLocale;
11 }
12 // 从当前请求中获取Locale
13 Locale requestLocale = request.getLocale();
14 // 从配置中获取支持的Locale集合
15 List<Locale> supportedLocales = getSupportedLocales();
16 // Locale集合为null或者Locale集合中包括请求语言,则直接使用客户请求Locale
17 if (supportedLocales.isEmpty() || supportedLocales.contains(requestLocale)) {
18 return requestLocale;
19 }
20 // 找到设置的Locale集合中是否有请求的Locale
21 Locale supportedLocale = findSupportedLocale(request, supportedLocales);
22 if (supportedLocale != null) {
23 return supportedLocale;
24 }
25 return (defaultLocale != null ? defaultLocale : requestLocale);
26 }
27 // 略其他源码
28 }
总结:AcceptHeaderLocaleResolver实现了国际化解析器接口LocaleResolver,当每次请求发出后,都会执行resolveLocale方法,并通过获取请求头"Accept-Language"来判断用户是否使用国际化语言切换,没有选择切换语言,则直接使用默认语言,当有切换并定义国际化语言时,直接返回指定切换的语言。
SpringBoot第十集:i18n与Webjars的应用(2020最新最易懂)的更多相关文章
- SpringBoot第二集:注解与配置(2020最新最易懂)
2020最新SpringBoot第二集:基础注解/基础配置(2020最新最易懂) 一.Eclipse安装SpringBoot插件 Eclipse实现SpringBoot开发,为便于项目的快速构建,需要 ...
- SpringBoot第十二集:度量指标监控与异步调用(2020最新最易懂)
SpringBoot第十二集:度量指标监控与异步调用(2020最新最易懂) Spring Boot Actuator是spring boot项目一个监控模块,提供了很多原生的端点,包含了对应用系统的自 ...
- SpringBoot第一集:入门(2020最新最易懂)
2020最新SpringBoot第一集:入门(2020最新最易懂) 学习思路: 是什么?为什么要学,有什么用?有什么特点?简单明了的总结一句话! SpringBoot推荐开发工具: Spring To ...
- SpringBoot第四集:静态资源与首页定(2020最新最易懂)
SpringBoot第四集:静态资源与首页定(2020最新最易懂) 问题 SpringBoot构建的项目结构如下:没有webapp目录,没有WEB-INF等目录,那么如果开发web项目,项目资源放在那 ...
- SpringBoot第三集:热部署与单元测试(2020最新最易懂)
SpringBoot第三集:热部署与单元测试(2020最新最易懂) 有兴趣的可以先参考附录简单了解SpringBoot自动装配流程. 一.SpringBoot开发热部署 项目开发中,你是否也遇到更新配 ...
- SpringBoot第五集:整合监听器/过滤器和拦截器(2020最新最易懂)
SpringBoot第五集:整合监听器/过滤器和拦截器(2020最新最易懂) 在实际开发过程中,经常会碰见一些比如系统启动初始化信息.统计在线人数.在线用户数.过滤敏/高词汇.访问权限控制(URL级别 ...
- SpringBoot第四集:整合JdbcTemplate和JPA(2020最新最易懂)
SpringBoot第四集:整合JdbcTemplate和JPA(2020最新最易懂) 当前环境说明: Windows10_64 Maven3.x JDK1.8 MySQL5.6 SpringTool ...
- SpringBoot第五集:整合Druid和MyBatis(2020最新最易懂)
SpringBoot第五集:整合Druid和MyBatis(2020最新最易懂) 1.SpringBoot整合Druid Druid是阿里巴巴的一个开源项目,是一个数据库连接池的实现,结合了C3P0. ...
- SpringBoot第九集:整合JSP和模板引擎Freemarker/Thymeleaf(2020最新最易懂)
SpringBoot第九集:整合JSP和模板引擎(2020最新最易懂) 当客户通过前端页面提交请求后,我们以前是怎么做的?后端接收请求数据,处理请求,把响应结果交给模板引擎JSP,最后将渲染后的JSP ...
随机推荐
- volatile型变量语义讲解一 :对所有线程的可见性
volatile型变量语义讲解一 :对所有线程的可见性 一.volatile变量语义一的概念 当一个变量被定义成volatile之后,具备两个特性: 特性一:保证此变量对所有线程的可见性.这里的&qu ...
- javascript里面的this指向问题
1:一般情况下this最终指向调用它的那个对象. 2:全局作用域或者普通函数中的this都会指向window. 例1:console.log(this); // 在控制台输出的是BOM顶级对象 wi ...
- 关于ptype_all和pypte_base中的pt_prev的说明[转]
不知道原帖,我是从这里看到了,解决了迷惑我很久的疑问,抄过来. 看见noble_shi兄弟"关于net_rx_action函数的若干问题"贴中关于pt_prev的问题, 本来想在论 ...
- MarkDown语法记录,还在用word,txt编写项目文档吗?
开始之前 是不是在github上看项目的时候第一眼就要看项目介绍? 是不是经常在某些项目的代码里面看到一个README.MD文档 却不知道怎么写? 你是不是不知道,反正我是的. 作为一个程序员,可能写 ...
- 如何从0到1的构建一款Java数据生成器-第二章
前提 在上一章我们提到了并且解决了几只拦路虎,承上启下,下面我们一起来实现一款数据生成器. 对外API /** * @description: 本地数据生成API * @author: peter * ...
- 如何写好 C语言 main 函数!你准备好编写 C 程序了吗?
学习如何构造一个 C 文件并编写一个 C main 函数来成功地处理命令行参数. 我知道,现在孩子们用 Python 和 JavaScript 编写他们的疯狂"应用程序".但是 ...
- 【ST表】SCOI2016 萌萌哒
题目内容 洛谷链接 一个长度为\(n\)的大数,用\(S_1S_2S_3...S_n\)表示,其中\(S_i\)表示数的第\(i\)位,\(S_1\)是数的最高位,告诉你一些限制条件,每个条件表示为四 ...
- kafka-伪集群搭建
一.简介 Apache Kafka是一个快速.可扩展的.高吞吐的.可容错的分布式"发布-订阅"消息系统,使用Scala与Java语言编写,能够将消息从一个端点传递到另一个端点, ...
- JavaSE学习笔记01注释、标识符与基本类型
1. HelloWorld 编写代码 public class Hello{ public static void main(String[] args){ System.out.println(&q ...
- MySQL安装版本介绍
MySQL安装 源码安装 二进制格式的程序包 程序包管理器安装 yum dnf MySQL在CentOS上的情况 6上只有mySQL 7上只有mariadb 8上既有mysql也有mariadb Ce ...