目录
前言
参考:《Spring4.x 企业应用开发实战》
一般情况下,web应用根据浏览器的设置来判断客户端的本地化类型。用户可以在浏览器中修改本地化类型。
浏览器中设置的本地化类型通过请求报文头中的"Accept-Language"参数的设置发送给服务端,服务端以此判断客户端本地化类型。也可以通过session、cookie或者请求参数的方式即可切换本地化类型。Spring MVC在收到请求时,会寻找LocaleResolver,然后找到后使用它来获取请求所对应的本地化类型信息。除此之外呢,还可以装配一个动态修改本地化类型的拦截器,这样的话,通过指定一个参数就可以控制单个请求的本地化类型。
一. LocaleResolver
/**
* 基于网络的本地语言解析策略,针对本地请求策略和请求、响应的本地语言的修改
*/
public interface LocaleResolver {
/**
* 解析当前给定请求的本地语言。
*/
Locale resolveLocale(HttpServletRequest request);
/**
* 设置当前的locale
*/
void setLocale(HttpServletRequest request, @Nullable HttpServletResponse response, @Nullable Locale locale);
}
二. AcceptHeaderLocaleResolver
根据HTTP报文头的"Accept-Language"参数确定本地化类型。如果没有显示定义本地化解析器,Spring MVC默认使用AcceptHeaderLocaleResolver。
/**
*
* LocaleResolver的实现类,简单地使用HTTP请求头的"accept-language"指定的基础locale。
* locale,是由客户端浏览器发送的本地语言,正常情况下,是客户端操作系统的本地语言。
*
* 注意: 别去使用setLocale去设置locale,因为accept-header只能通过改变客户端的本地语言设置。
*
*/
public class AcceptHeaderLocaleResolver implements LocaleResolver {
private final List<Locale> supportedLocales = new ArrayList<>(4);
@Nullable
private Locale defaultLocale;
/**
* 配置支持的本地语言集合
*/
public void setSupportedLocales(List<Locale> locales) {
this.supportedLocales.clear();
this.supportedLocales.addAll(locales);
}
/**
* 获取配置的支持的本地语言集合
*/
public List<Locale> getSupportedLocales() {
return this.supportedLocales;
}
/**
* 如果请求没有“Accept-Language”头,配置一个固定不变的默认的本地语言。
*/
public void setDefaultLocale(@Nullable Locale defaultLocale) {
this.defaultLocale = defaultLocale;
}
/**
* 默认的本地语言
*/
@Nullable
public Locale getDefaultLocale() {
return this.defaultLocale;
}
@Override
public Locale resolveLocale(HttpServletRequest request) {
Locale defaultLocale = getDefaultLocale();
// 设置了默认的本地语言 && 请求头中没有“Accept-Language”
if (defaultLocale != null && request.getHeader("Accept-Language") == null) {
return defaultLocale;
}
Locale requestLocale = request.getLocale();
List<Locale> supportedLocales = getSupportedLocales();
if (supportedLocales.isEmpty() || supportedLocales.contains(requestLocale)) {
return requestLocale;
}
Locale supportedLocale = findSupportedLocale(request, supportedLocales);
if (supportedLocale != null) {
return supportedLocale;
}
return (defaultLocale != null ? defaultLocale : requestLocale);
}
/**
* 找到支持给定请求的本地语言
*/
@Nullable
private Locale findSupportedLocale(HttpServletRequest request, List<Locale> supportedLocales) {
Enumeration<Locale> requestLocales = request.getLocales();
Locale languageMatch = null;
while (requestLocales.hasMoreElements()) {
Locale locale = requestLocales.nextElement();
if (supportedLocales.contains(locale)) {
if (languageMatch == null || languageMatch.getLanguage().equals(locale.getLanguage())) {
// Full match: language + country, possibly narrowed from earlier language-only match
return locale;
}
}
else if (languageMatch == null) {
// Let's try to find a language-only match as a fallback
for (Locale candidate : supportedLocales) {
if (!StringUtils.hasLength(candidate.getCountry()) &&
candidate.getLanguage().equals(locale.getLanguage())) {
languageMatch = candidate;
break;
}
}
}
}
return languageMatch;
}
/**
* 上文有说道,不要通过setLocale的方式设置locale,这里呢,直接抛出一个运行时异常。
*/
@Override
public void setLocale(HttpServletRequest request, @Nullable HttpServletResponse response, @Nullable Locale locale) {
throw new UnsupportedOperationException(
"Cannot change HTTP accept header - use a different locale resolution strategy");
}
}
三. AbstractLocaleResolver
/**
* LocaleResolver的抽象基础实现类,提供了一个默认的本地语言的支持
*/
public abstract class AbstractLocaleResolver implements LocaleResolver {
@Nullable
private Locale defaultLocale;
/**
* 设置默认本地语言
*/
public void setDefaultLocale(@Nullable Locale defaultLocale) {
this.defaultLocale = defaultLocale;
}
/**
* 返回默认本地语言
*/
@Nullable
protected Locale getDefaultLocale() {
return this.defaultLocale;
}
}
/**
* LocaleResolver的拓展,添加了对locale context的支持
*/
public interface LocaleContextResolver extends LocaleResolver {
/**
* 解析给定请求的当前的本地语言上下文
*/
LocaleContext resolveLocaleContext(HttpServletRequest request);
/**
* 设置当前的本地语言上下文
*/
void setLocaleContext(HttpServletRequest request, @Nullable HttpServletResponse response,
@Nullable LocaleContext localeContext);
}
/**
* LocaleContextResolver的抽象基础实现类,提供了对默认本地语言和默认时区的支持
*/
public abstract class AbstractLocaleContextResolver extends AbstractLocaleResolver implements LocaleContextResolver {
@Nullable
private TimeZone defaultTimeZone;
/**
* 设置默认的time zone
*/
public void setDefaultTimeZone(@Nullable TimeZone defaultTimeZone) {
this.defaultTimeZone = defaultTimeZone;
}
/**
* 获取默认的time zone
*/
@Nullable
public TimeZone getDefaultTimeZone() {
return this.defaultTimeZone;
}
@Override
public Locale resolveLocale(HttpServletRequest request) {
Locale locale = resolveLocaleContext(request).getLocale();
return (locale != null ? locale : request.getLocale());
}
@Override
public void setLocale(HttpServletRequest request, @Nullable HttpServletResponse response, @Nullable Locale locale) {
setLocaleContext(request, response, (locale != null ? new SimpleLocaleContext(locale) : null));