Spring MVC-08循序渐进之国际化(AcceptHeaderLocaleResolver)
- 概述
- 概述
- 国际化SpringMVC应用程序
- 将文本元件隔离成属性文件
- 选择和读取正确的属性文件
- 告诉Spring MVC使用哪个语言区域
- 使用message标签
- Demo
- 测试
- 源码
概述
我们之前梳理过Spring相关的国际化的知识点,如下
Spring-国际化信息01-基础知识
Spring-国际化信息02-MessageSource接口
Spring-国际化信息03-容器级的国际化信息资源
在这里,我们将国际化与Spring MVC结合起来,看SpringMVC如何整合国际化(其实03中已经阐述了)。
这里我们来重新看下
概述
概括的来讲,我们需要了解两个术语
国际化,即我们常讲的i18n (internationalization 以i开头n结尾,中间有18个字母)
本地化,即我们常讲的L10N(localization,中间的 10 代表在首字母“L”和尾字母“N”之间省略了 10 个字母) 。这是将国际化应用程序改成支持特定语言区域(locale)的技术。 举个例子:同样是日期,2018年02月27日 , 美国显示为02/27/2018, 澳大利亚则为27/02/2018 , 中国就是2018/02/27。
Java为字符和字符串提供了unicode支持,因此使用Java编写国际化的应用程序是一件很容易的事情。
国际化应用程序的具体方式取决于有多少静态数据需要以不同的语言显示出来,一般来讲
如果大量数据都是静态的,就要针对每一个语言区域单独创建一个资源版本,这种一般适用于带有大量静态HTML页面的Web应用程序。这个很简单,我们不讨论这个.
如果需要国际化的静态数据量有限,就可以将文本元素,比如元件标签和错误消息隔离成文本文件。每个文本文件中都保存着一个语言区域的所有文本元素译文。 随后,应用程序会自动获取每一个元素,这样做的优势是显而易见的。我们这里讨论是这种场景。
国际化SpringMVC应用程序
国际化和本地化应用程序时,需要具备以下条件:
1. 将文本元文件隔离成属性文件
2. 选择和读取正确的属性文件
将文本元件隔离成属性文件
被国际化的应用程序是将每一个语言区域的文本元素都单独保存在一个独立的属性文件中。 每个文件中都包含key/value对,并且每个key都是唯一标示一个特定语言区域的对象 。
key始终是字符串,value则可以是字符串,也可以是其他任意类型的对象。
为了支持美国英语、汉语,就要有2个属性文件,他们都有着相同的key.
比如英语版本
greetings=hello
farewell=goodbye
汉语版本
greetings=\u4F60\u597D
farewell=\u518D\u89C1
汉语中的属性文件value,汉字需要转换为Unicode码, 一般IDE都会自带这种转换功能。我们直接输入汉字,就可以直接得到对应的Unicode码了。
接下来我们要学习java.util.ResourceBundle ,
详见 http://blog.csdn.net/yangshangwei/article/details/76946002#t8
ResourceBundle能够轻松的选择和读取特定用户语言区域的属性,以及查找值。 ResourceBundle是一个抽象类,但它提供了静态的getBundle方法,以返回一个具体子类的实例。
ResourceBundle有一个基准名,它可以是任意名称。 但为了让ResourceBundle正确的选择属性文件,这个文件名中最好必须包含基准名ResourceBundle,后面再接下划线、语言码,还可以选择再加一条下划线和国家码。
basename_languageCode_countryCode
假设基准名为MyResource, 并且定义了2个语言区域
- US-en
- CN-zh
那么,就会得到如下2个属性文件
- MyResource_en_US.properties
- MyResource_zh_CN.properties
选择和读取正确的属性文件
如前所述,虽然ResourceBundle是一个抽象类,但是它提供了静态的getBundle方法来获取一个ResourceBundle实例
比如
如果没有找到合适的属性文件,ResourceBundle对象就会返回到默认的属性文件, 默认的属性文件为基准名加上一个扩展名properties. 如果默认文件也没有找到,则将抛出java.util.MissingResourceException.
随后读取值,利用getString方法即可,如果未找到指定的key,则将抛出java.util.MissingResourceException.
但在SpringMVC中,我们不直接使用ResourceBundle,而是利用messageSource bean来告诉Spring MVC要将属性文件保存在哪里
<bean id="messageSource"class="org.springframework.context.support.ReloadableResourceBundleMessageSource"><property name="basenames" ><list><value>/WEB-INF/resource/messages</value><value>/WEB-INF/resource/labels</value></list></property></bean>
上面的bean定义中用ReloadableResourceBundleMessageSource类作为实现, 另外一个是ResourceBundleMessageSource,但是ResourceBundleMessageSource不能重新加载,这意味着如果有任何属性文件中修改了某一个属性key或者value,并且正在使用ResourceBundleMessageSource,那么要使生效的话,就必须要重启JVM。
<bean id="resource"class="org.springframework.context.support.ReloadableResourceBundleMessageSource"><property name="basenames" ref="resourceList"/><!-- 刷新资源文件的周期,以秒为单位 --><property name="cacheSeconds" value="5"/></bean><util:list id="resourceList"><value>i18n/fmt_resource</value></util:list>
这两个实现之间的另外一区别是: ReloadableResourceBundleMessageSource是在应用程序目录下搜索这些属性文件,而使用ResourceBundleMessageSource,属性文件则必须放在类路径下,即WEB-INF/class目录下。
如果只有一组属性文件,则可以使用basename属性代替basenames
<bean id="messageSource"class="org.springframework.context.support.ReloadableResourceBundleMessageSource"><property name="basename" ><list><value>/WEB-INF/resource/messages</value></list></property></bean>
告诉Spring MVC使用哪个语言区域
为用户选择语言区域时,最常用的方法或许是通过读取用户浏览器的accept-language标题值。 accept-language标题提供了用户偏好哪种语言的信息.
选择语言区域的其他方法还包括读取某个session属性或者cookie。
在Spring MVC中选择语言区域,可以使用语言解析器Bean,它包括几个实现,如下
- AcceptHeaderLocaleResolver
- SessionLocaleResolver
- CookieLocaleResolver
这些实现都是org.springframework.web.servlet.i18n包的组成部分。 AcceptHeaderLocaleResolver或许是最容易使用的一个。
如果使用AcceptHeaderLocaleResolver这个语言区域解析器,Spring MVC将会读取浏览器的accept-language标题,来确定浏览器接受哪个语言区域. 如果与应用程序支持的语言匹配,这就会使用这个语言区域,否则就会使用默认的语言区域。
下面是使用AcceptHeaderLocaleResolver的localeResolver bean定义
<bean id="localeResolver"class="org.springframework.web.servlet.i18n.AcceptHeaderLocaleResolver"></bean>
使用message标签
在Spring MVC中显示本地化消息的最容易方法就是使用Spring的message标签。
为了使用message标签,需要在使用该标签的所有JSP页面最前面声明这个taglib指令
<%@ taglib prefix="spring" uri="http://www.springframework.org/tags" %>
message标签属性如下,均是可选项
属性 | 描述 |
---|---|
arguments | 该标签的参数写成一个有界的字符、一个对象数组或者单个对象 |
argumentSeparator | 用来分隔该标签参数的字符 |
code | 获取消息的key |
htmlEscape | 接受True或者False,表示被渲染文本是否应该进行HTML转义 |
JavaScriptEscape | 接受True或者False,表示被渲染文本是否应该进行JavaScript转义 |
message | MessageSourceResolvable参数 |
scope | 保存var属性中定义的变量的范围 |
text | 如果code属性不存在,或者指定码无法获取消息时,所显示的默认文本 |
var | 用来保存消息的有界变量 |
Demo
Domain类
package com.artisan.domain;
import java.io.Serializable;import javax.validation.constraints.Size;import org.hibernate.validator.constraints.NotBlank;public class Product implements Serializable {private static final long serialVersionUID = 78L;@NotBlank@Size(min=1, max=10)private String name;private String description;private Float price;public String getName() {return name;}public void setName(String name) {this.name = name;}public String getDescription() {return description;}public void setDescription(String description) {this.description = description;}public Float getPrice() {return price;}public void setPrice(Float price) {this.price = price;}
}
控制层
package com.artisan.controller;import javax.validation.Valid;import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.validation.BindingResult;
import org.springframework.validation.FieldError;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.RequestMapping;import com.artisan.domain.Product;@Controller
@RequestMapping("/product")
public class ProductController {private static final Log logger = LogFactory.getLog(ProductController.class);@RequestMapping(value="/product_input")public String inputProduct(Model model) {model.addAttribute("product", new Product());return "ProductForm";}@RequestMapping(value="/product_save")public String saveProduct(@Valid @ModelAttribute Product product, BindingResult bindingResult,Model model) {// 校验if (bindingResult.hasErrors()) {FieldError fieldError = bindingResult.getFieldError();logger.info("Code:" + fieldError.getCode() + " ,field:" + fieldError.getField());return "ProductForm";}// save product heremodel.addAttribute("product", product);return "ProductDetails";}}
Spring MVC配置文件
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:p="http://www.springframework.org/schema/p"xmlns:mvc="http://www.springframework.org/schema/mvc" xmlns:context="http://www.springframework.org/schema/context"xsi:schemaLocation="http://www.springframework.org/schema/beanshttp://www.springframework.org/schema/beans/spring-beans.xsdhttp://www.springframework.org/schema/mvchttp://www.springframework.org/schema/mvc/spring-mvc.xsd http://www.springframework.org/schema/contexthttp://www.springframework.org/schema/context/spring-context.xsd"><!-- 扫描控制层的注解,使其成为Spring管理的Bean --><context:component-scan base-package="com.artisan.controller" /><!-- 静态资源文件 --><mvc:annotation-driven /><mvc:resources mapping="/css/**" location="/css/" /><mvc:resources mapping="/*.jsp" location="/" /><!-- 视图解析器 --><bean id="viewResolver"class="org.springframework.web.servlet.view.InternalResourceViewResolver"><property name="prefix" value="/WEB-INF/jsp/" /><property name="suffix" value=".jsp" /></bean><!-- 国际化资源文件 --><bean id="messageSource"class="org.springframework.context.support.ReloadableResourceBundleMessageSource"><property name="basenames"><list><value>/WEB-INF/resource/messages</value><value>/WEB-INF/resource/labels</value></list></property><!-- 如果在国际化资源文件中找不到对应代码的信息,就用这个代码作为名称 --><property name="useCodeAsDefaultMessage" value="true" /></bean><bean id="localeResolver"class="org.springframework.web.servlet.i18n.AcceptHeaderLocaleResolver"></bean></beans>
这里用到了messageSource 和 localeResolver 这两个bean。 messageSource 声明用两个基准名设置了basenames属性 /WEB-INF/resource/messages 和 /WEB-INF/resource/labels 。 localeResolver 利用 AcceptHeaderLocaleResolver类实现消息的本地化。
我们支持en和zh两种语言区域,因此属性文件都有两个版本,除此之外我们还添加了当两种都找不到时的默认语言区域的版本。
为了实现本地化,JSP页面中的每一段文本都要用message标签代替。
为了方便查看,我们将当前语言区域和accept-language标题显示在页面的最上方
<%@ taglib prefix="form" uri="http://www.springframework.org/tags/form" %>
<%@ taglib prefix="spring" uri="http://www.springframework.org/tags" %>
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
<!DOCTYPE HTML>
<html>
<head>
<title><spring:message code="page.productform.title"/></title>
<style type="text/css">@import url("<c:url value="/css/main.css"/>");</style>
</head>
<body><div id="global"><!-- 为方便查看,这里打印出来当前的语言和accept-language --><!-- 为防止编译报错,pom中需要加入jsp-api依赖-->Current Locale : ${pageContext.response.locale}<br/>accept-language header: ${header["accept-language"]}<br/> <form:form commandName="product" action="product_save" method="post"><fieldset><legend><spring:message code="form.name"/></legend><p><label for="name"><spring:message code="label.productName" text="default text" />:</label><form:input id="name" path="name" cssErrorClass="error"/><form:errors path="name" cssClass="error"/></p><p><label for="description"><spring:message code="label.description"/>: </label><form:input id="description" path="description"/></p><p><label for="price"><spring:message code="label.price" text="default text" />: </label><form:input id="price" path="price" cssErrorClass="error"/></p><p id="buttons"><input id="reset" type="reset" tabindex="4" value="<spring:message code="button.reset"/>"><input id="submit" type="submit" tabindex="5" value="<spring:message code="button.submit"/>"></p></fieldset></form:form>
</div>
</body>
</html>
测试
Accept-Language说明 :https://developer.mozilla.org/zh-CN/docs/Web/HTTP/Headers/Accept-Language
指令
<language>
用含有两到三个字符的字符串表示的语言码。
<locale>
完整的语言标签。除了语言本身之外,还会包含其他方面的信息,显示在中划线("-")后面。最常见的额外信息是国家或地区变种(如"en-US")或者表示所用的字母系统(如"sr-Lat")。其他变种诸如拼字法("de-DE-1996")等通常不被应用在这种场合。
*
任意语言;"*"表示通配符。
;q= (q-factor weighting)
值代表优先顺序,用相对质量价值 表示,又称为权重。
源码
代码已提交到github
https://github.com/yangshangwei/SpringMvcTutorialArtisan
Spring MVC-08循序渐进之国际化(AcceptHeaderLocaleResolver)相关推荐
- Spring MVC基础知识整理➣国际化和异常处理
概述 Spring框架为WEB项目提供了国际化以及异常处理机制.所谓的国际化也就是不同国籍,显示不同国籍的语言与符号.异常处理,也就是能够捕获WEB项目下的所有异常信息,并能处理记录这些异常信息机制. ...
- Spring MVC-08循序渐进之国际化(基于Session-SessionLocaleResolver)
概述 工程结构 测试 源码 概述 在Spring MVC中选择语言区域,可以使用语言解析器Bean,它包括几个实现,如下 AcceptHeaderLocaleResolver SessionLocal ...
- Spring MVC的国际化
Spring MVC 的国际化是建立在 Java 国际化的基础之上的,Spring MVC 框架的底层国际化与 Java 国际化是一致的,作为一个良好的 MVC 框架,Spring MVC 将 Jav ...
- Spring MVC 4.x 知识点
2019独角兽企业重金招聘Python工程师标准>>> 我的博客:http://blog.geekidentity.com/spring/spring_mvc_4.x_action/ ...
- Spring MVC -- 国际化
在全球化的今天,现在比过去更需要编写可以在不同语言国家和地区部署的应用程序.在这方面,需要了解两个术语: 国际化:常常缩写为i18n,因为其单词internationalization以i开始,以n结 ...
- Spring MVC国际化(i18n)和本地化(L10n)示例
Spring MVC国际化(i18n)和本地化(L10n)示例 欢迎来到Spring Internationalization(i18n)教程.任何遍布全球的用户,国际化(i18n)或本地化(L10n ...
- spring mvc国际化_Spring MVC国际化(i18n)和本地化(L10n)示例
spring mvc国际化 Welcome to the Spring Internationalization (i18n) tutorial. Any web application with u ...
- Spring MVC注解、标签库、国际化
本篇文章主要介绍自己在学习Spring MVC常用注解.标签库.国际化遇到的一些问题,分享给大家,希望对你有所帮助. 问题一:指定扫描包的位置 应该将所有控制器类都放在基本包下,并且指定该扫描包,避免 ...
- Spring MVC国际化
一.Spring MVC国际化简介 程序国际化是商业系统的一个基本要求,因为今天的软件系统不再是简单的单机程序,往往都是一个开放的系统,需要面对来自全世界各个地方的访问者,因此,国际化成 ...
最新文章
- 如何让UTF-8能对文档XML编辑
- HDFS组件性能调优:数据平衡
- C#开源类库推荐:拼多多开放平台SDK,开源免费,支持.NET Core!
- jzoj4012-Distinct Paths【搜索】
- linux获取ip地址的接口,获取Linux上接口的IP地址
- 【转】PMO、EPG与QAG职责分工——任甲林
- 如何获取NuGet以安装/更新packages.config中的所有软件包?
- Breakpad Native异常捕获
- JEECG登陆全过程
- 一般纳税人与小规模纳税人有什么区别
- Android app使用TextToSpeech实现文字转换语音
- 读书笔记《能力陷阱》第三章:建立良好的人际关系网络
- 突破KEIL软件编译时 C51中断号最大只能为31限制的补丁,使中断号可以达到256
- vue单页面背景颜色修改
- Linux数据库管理与应用
- 使用weinre调试手机页面
- 内网服务器反弹映射到公网ip去访问
- Scarpy爬取当当网书籍
- 申请美国签证超详细流程
- CSS3字体和字体图标
热门文章
- python实用小技巧
- “AttributeError: ‘str‘ object has no attribute ‘decode‘ “
- c++ 递增一个指针
- pyspark.sql.DataFrame与pandas.DataFrame之间的相互转换
- linux libpath的作用,linux – LD_LIBRARY_PATH似乎不起作用
- 105. Leetcode 121. 买卖股票的最佳时机 (动态规划-股票交易)
- timm 笔记:数据集
- s5pv210 linux内核移植,简单根文件系统制作 - S5PV210 Linux3.8.3内核移植_Linux编程_Linux公社-Linux系统门户网站...
- c语言数字的拆解_C语言解决变态推理题
- Python入门100题 | 第014题