当前位置: 首页 > news >正文

Spring MVC 源码- LocaleResolver 组件

LocaleResolver 组件

LocaleResolver 组件,本地化(国际化)解析器,提供国际化支持

回顾

先来回顾一下在 DispatcherServlet 中处理请求的过程中哪里使用到 LocaleResolver 组件,可以回到《一个请求的旅行过程》中的 DispatcherServletprocessDispatchResult 方法中看看,如下:

private void processDispatchResult(HttpServletRequest request, HttpServletResponse response,@Nullable HandlerExecutionChain mappedHandler, @Nullable ModelAndView mv,@Nullable Exception exception) throws Exception {// ... 省略相关代码// <3> 是否进行页面渲染if (mv != null && !mv.wasCleared()) {// <3.1> 渲染页面render(mv, request, response);// <3.2> 清理请求中的错误消息属性// 因为上述的情况二中 processHandlerException 会通过 WebUtils 设置错误消息属性,所以这里得清理一下if (errorView) {WebUtils.clearErrorRequestAttributes(request);}}// ... 省略相关代码
}protected void render(ModelAndView mv, HttpServletRequest request, HttpServletResponse response) throws Exception {// Determine locale for request and apply it to the response.// <1> 解析 request 中获得 Locale 对象,并设置到 response 中Locale locale = (this.localeResolver != null ? this.localeResolver.resolveLocale(request) : request.getLocale());response.setLocale(locale);// ... 省略相关代码// 获得 View 对象View view;String viewName = mv.getViewName();// ... 省略相关代码view = mv.getView();// ... 省略相关代码try {// <3> 设置响应的状态码if (mv.getStatus() != null) {response.setStatus(mv.getStatus().value());}// <4> 渲染页面view.render(mv.getModelInternal(), request, response);}// ... 省略相关代码
}

在执行完handler处理器后,需要对返回的 ModelAndView 对象进行处理,可能需要调用 render(ModelAndView mv, HttpServletRequest request, HttpServletResponse response) 方法,渲染页面

可以看到需要先通过 LocaleResolver 从请求中解析出 java.util.Locale 对象

LocaleResolver 接口

org.springframework.web.servlet.LocaleResolver,本地化(国际化)解析器,提供国际化支持,代码如下:

public interface LocaleResolver {/*** 从请求中,解析出要使用的语言。例如,请求头的 "Accept-Language"*/Locale resolveLocale(HttpServletRequest request);/*** 设置请求所使用的语言*/void setLocale(HttpServletRequest request, @Nullable HttpServletResponse response, @Nullable Locale locale);
}

LocaleResolver 接口体系的结构如下:

初始化过程

DispatcherServletinitLocaleResolver(ApplicationContext context) 方法,初始化 LocaleResolver 组件,方法如下:

private void initLocaleResolver(ApplicationContext context) {try {// 从上下文中获取Bean名称为'localeResolver'的对象this.localeResolver = context.getBean(LOCALE_RESOLVER_BEAN_NAME, LocaleResolver.class);if (logger.isTraceEnabled()) {logger.trace("Detected " + this.localeResolver);}else if (logger.isDebugEnabled()) {logger.debug("Detected " + this.localeResolver.getClass().getSimpleName());}}catch (NoSuchBeanDefinitionException ex) {// We need to use the default./*** 从配置文件中获取默认的 {@link org.springframework.web.servlet.i18n.AcceptHeaderLocaleResolver}*/this.localeResolver = getDefaultStrategy(context, LocaleResolver.class);if (logger.isTraceEnabled()) {logger.trace("No LocaleResolver '" + LOCALE_RESOLVER_BEAN_NAME +"': using default [" + this.localeResolver.getClass().getSimpleName() + "]");}}
}
  1. 获得 Bean 名称为 "localeResolver",类型为 LocaleResolver 的 Bean ,将其设置为 localeResolver

  1. 如果未获得到,则获得默认配置的 LocaleResolver 实现类,调用 getDefaultStrategies(ApplicationContext context, Class<T> strategyInterface) 方法,就是从 DispatcherServlet.properties 文件中读取 LocaleResolver 的默认实现类,如下:

org.springframework.web.servlet.LocaleResolver=org.springframework.web.servlet.i18n.AcceptHeaderLocaleResolver

我看了一下,Spring Boot 没有提供其他的实现类,默认也是这个

AcceptHeaderLocaleResolver

org.springframework.web.servlet.i18n.AcceptHeaderLocaleResolver,实现 LocaleResolver 接口,通过检验 HTTP 请求的Accept-Language头部来解析区域,默认的实现类

构造方法

public class AcceptHeaderLocaleResolver implements LocaleResolver {private final List<Locale> supportedLocales = new ArrayList<>(4);@Nullableprivate Locale defaultLocale;
}

上面两个属性默认都没有设置值

resolveLocale

实现 resolveLocale(HttpServletRequest request) 方法,从请求中解析出 java.util.Locale 对象,方法如下:

@Override
public Locale resolveLocale(HttpServletRequest request) {// <1> 获取默认的语言环境Locale defaultLocale = getDefaultLocale();// <2> 如果请求头 'Accept-Language' 为空,且默认语言环境不为空,则返回默认的if (defaultLocale != null && request.getHeader("Accept-Language") == null) {return defaultLocale;}// <3> 从请求中获取 Locale 对象 `requestLocale`Locale requestLocale = request.getLocale();// <4> 获取当前支持的 `supportedLocales` 集合List<Locale> supportedLocales = getSupportedLocales();// <5> 如果支持的 `supportedLocales` 集合为空,或者包含请求中的 `requestLocale` ,则返回请求中的语言环境if (supportedLocales.isEmpty() || supportedLocales.contains(requestLocale)) {return requestLocale;}// <6> 从请求中的 Locale 们和支持的 Locale 集合进行匹配Locale supportedLocale = findSupportedLocale(request, supportedLocales);// <7> 如果匹配到了则直接返回匹配结果if (supportedLocale != null) {return supportedLocale;}// <8> 默认的 `defaultLocale` 不为空则直接返回,否则返回请求中获取到的 `requestLocale` 对象return (defaultLocale != null ? defaultLocale : requestLocale);
}
  1. 获取默认的语言环境

  1. 如果请求头 Accept-Language 为空,且默认语言环境不为空,则返回默认对象 defaultLocale

  1. 从请求中获取 Locale 对象 requestLocale

  1. 调用 getSupportedLocales 方法,获取当前支持的 supportedLocales 集合,默认为空

  1. 如果支持的 supportedLocales 集合为空,或者包含请求中的 requestLocale ,则返回请求中的语言环境

  1. 调用 findSupportedLocale(HttpServletRequest request, List<Locale> supportedLocales) 方法,从请求中的 Locale 们和支持的 Locale 集合进行匹配,如下:

@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 matchreturn locale;}}else if (languageMatch == null) {// Let's try to find a language-only match as a fallbackfor (Locale candidate : supportedLocales) {if (!StringUtils.hasLength(candidate.getCountry()) &&candidate.getLanguage().equals(locale.getLanguage())) {languageMatch = candidate;break;}}}}return languageMatch;
}
  1. 如果匹配到了则直接返回匹配结果

  1. 默认的 defaultLocale 不为空则直接返回,否则返回请求中获取到的 requestLocale 对象

默认情况下,supportedLocalesdefaultLocale 属性都是空的,所以 AcceptHeaderLocaleResolver 使用Accept-Language 请求头来构造 Locale 对象

例如请求的请求头中会有zh-CN,zh;q=0.9数据,那么这里解析出来 Locale 对象就对应language="zh" region="CN"数据

总结

本文分析了 LocaleResolver 组件,本地化(国际化)解析器,提供国际化支持。笔者实际上没有接触过该组件,因为目前的项目大多数都已经前后端分离了,这里只是浅显的介绍了该接口.

相关文章:

Spring MVC 源码- LocaleResolver 组件

LocaleResolver 组件LocaleResolver 组件&#xff0c;本地化&#xff08;国际化&#xff09;解析器&#xff0c;提供国际化支持回顾先来回顾一下在 DispatcherServlet 中处理请求的过程中哪里使用到 LocaleResolver 组件&#xff0c;可以回到《一个请求的旅行过程》中的 Dispat…...

Servlet

Servlet1 简介2 快速入门3 执行流程4 生命周期5 方法介绍6 体系结构7 urlPattern配置8 XML配置1 简介 Servlet是JavaWeb最为核心的内容&#xff0c;它是Java提供的一门动态web资源开发技术。 使用Servlet就可以实现&#xff0c;根据不同的登录用户在页面上动态显示不同内容。 …...

简单的周总结

做一个简单的周总结。 校 OJ 上打了近 7 场比赛&#xff0c;ZR 及其他平台各一两场左右。 头几场打的中规中矩&#xff0c;分数大致在 100-200 左右&#xff0c;与同学分数差别不太大&#xff0c;但也没有很突出。 后面几场比较爆炸&#xff0c;分数一直在 100 以下&#xff0…...

Elasticsearch7.8.0版本进阶——IK中文分词器

目录一、ES 的默认分词器测试示例二、IK 中文分词器2.1、IK 中文分词器下载地址2.2、ES 引入IK 中文分词器2.3、IK 中文分词器测试示例三、ES 扩展词汇测试示例一、ES 的默认分词器测试示例 通过 Postman 发送 GET 请求查询分词效果&#xff0c;在消息体里&#xff0c;指定要分…...

一个阿里P6的说不会接口自动化测试,他不会是自己评的吧...

序 近期和一个阿里的测试工程师交流了一波&#xff0c;他竟然说我不会接口自动化测试&#xff0c;我当场就不服了我说你P6自己评级的吧&#xff0c;今天就带大家好好盘一盘接口自动化&#xff0c;本着以和大家交流如何实现高效的接口测试为出发点&#xff0c;本文包含了我在接…...

规则引擎与风控系统04:风控系统实例(下)

上一节把风控实例的基础代码都撸了出来。接下来再来把核心服务代码和规则文件写出来。 因为有了实体类、Dao,所以接来下就可以写服务类了。之前说过这个实例就是要实现两个目的: 1、一分钟内连续访问三次以上,就会被直接封杀; 2、黑名单用户登录会记录可疑事件。 所以服务类…...

我为什么选择Linux mint 21.1 “Vera“ ? Mint安装优化调教指南(分辨率DPI)

前言&#xff1a;为什么是Mint 笔者算是Linux老用户了&#xff0c;作为一个后端开发&#xff0c;尝试了多种不同发行版。 一开始是Manjaro这种Arch系&#xff0c;但是其对于开发而言实在是太过不稳定&#xff1b;每次滚动更新都要解决很多冲突。不适合当生产力&#xff08;本…...

雅思经验(十四)

剑10 test3 阅读p3这篇阅读比较难做下来&#xff0c;主要是这个题材我们不太熟悉&#xff0c;介绍了一种成为拉皮塔人&#xff0c;他们在太平洋上航行&#xff0c;很多岛屿上都有他们足迹&#xff0c;后来人们发掘、探索他们的历史的故事。1.derelict 与 abandoned 主要是前面的…...

刚来的薪资20k,是我的2倍,我是真的卷不过,真的太变态了

在这个行业爬摸滚打5年了&#xff0c;从最开始点点点的功能测试到现在到现在成为高级测试&#xff0c;工资也翻了几倍&#xff0c;简单的说几句吧 改变的开始 之所以改变的原因很简单&#xff0c;我快被新来的卷死了&#xff0c;新来的本科是某211的&#xff0c;干劲十足&…...

五、DeepWalk、Node2Vec论文精读与代码实战【CS224W】(Datawhale组队学习)

开源内容&#xff1a;https://github.com/TommyZihao/zihao_course/tree/main/CS224W 子豪兄B 站视频&#xff1a;https://space.bilibili.com/1900783/channel/collectiondetail?sid915098 斯坦福官方课程主页&#xff1a;https://web.stanford.edu/class/cs224w 文章目录D…...

学习 Python 之 Pygame 开发魂斗罗(四)

学习 Python 之 Pygame 开发魂斗罗&#xff08;四&#xff09;继续编写魂斗罗1. 创建子弹类2. 根据玩家方向和状态设置子弹发射的位置(1). 站立向右发射子弹(2). 站立向左发射子弹(3). 站立朝上发射子弹(4). 蹲下发射子弹(5). 向斜方发射子弹(6). 奔跑时发射子弹(7). 跳跃时发射…...

Linux 基础知识:指令与shell

目录一、操作系统二、指令三、shell一、操作系统 什么是操作系统&#xff1f; 单纯的操作系统应该是指操作系统内核。内核的作用就是管理计算机的软硬件资源&#xff0c;让计算机在合适的时候干合适的事情。 但是有一个问题&#xff0c;并不是人人都会直接通过内核来操作计算机…...

【数通网络交换基础梳理1】二层交换机、以太网帧、MAC地址数据帧转发原理详解

一、网络模型 万年不变&#xff0c;先从模型结构分析&#xff0c;现在大家熟知的网络模型有两种。第一种是&#xff0c;OSI七层模型&#xff0c;第二种是TCP/IP模型。在实际运用中&#xff0c;参考更多的是TCP/IP模型。 OSI七层模型 TCP/IP模型 不需要全部理解&#xff0c;…...

《分布式技术原理与算法解析》学习笔记Day22

哈希与一致性哈希 在分布式系统中&#xff0c;哈希和一致性哈希是数据索引或者数据分布的常见实现方式。 数据分布设计原则 在分布式数据存储系统中&#xff0c;做存储方案选型时&#xff0c;一般会考虑以下因素&#xff1a; 数据均匀数据稳定节点异构性隔离故障域性能稳定…...

[MySQL]MySQL数据类型

文章目录数据类型分类数值类型tinyint类型bit类型float类型decimal类型字符串类型char类型varchar类型char和varchar对比日期和时间类型enum和set类型数据类型分类 MySQL中&#xff0c;支持各种各样的类型&#xff0c;比如表示数值的整型浮点型&#xff0c;文本、二进制类型、…...

利用steam搬砖信息差赚钱,单账号200+,小白也能轻松上手!

现在很多人在做互联网而且也赚到钱了&#xff0c;但还是有很多人赚不到钱&#xff0c;这是为什么&#xff1f; 这里我不得不说一个词叫做赛道&#xff0c;也就是选择&#xff0c;选择大于努力&#xff0c;项目本身大于一切&#xff0c;90%的人都觉得直播带货赚钱&#xff0c;但…...

树与二叉树与森林的相关性质

文章目录树的度树的性质二叉树的性质二叉树与森林树的度 树的度指的是树内所有节点的度数的最大值。 节点的度&#xff1a;节点所拥有的子树的数量。简单来说&#xff0c;我们直接数分支即可&#xff0c;例如下图&#xff1a; 在这颗二叉树中&#xff0c;节点2的度为2&#…...

MySQL面试题

文章目录MySQL索引Mysql索引分类InnDB索引与MyISAM索引实现有什么区别一个表中如果没有创建索引&#xff0c;那么还会创建B树么&#xff1f;B树原理B树怎么来的B树 叶子节点和非叶子节点B树能存储多少数据&#xff1f;MySQL索引 Mysql索引分类 mysql 索引分为三类&#xff1a…...

【蓝桥OJ—C语言】高斯日记、马虎的算式、第39级台阶

文章目录高斯日记马虎的算式第39级台阶总结高斯日记 题目&#xff1a; 大数学家高斯有个好习惯&#xff1a;无论如何都要记日记。 他的日记有个与众不同的地方&#xff0c;他从不注明年月日&#xff0c;而是用一个整数代替&#xff0c;比如&#xff1a;4210。 后来人们知道&am…...

基于深度学习的三维重建网络PatchMatchNet(二):dtu数据集介绍及PatchMatchNet中加载数据部分代码解析

目录 1.dtu数据集介绍 2. PatchMatchNet中数据加载模块详解(dtu_yao_eval.py) 1.dtu数据集介绍 dtu数据集下载地址:dtu...

Kandinsky-5.0-I2V-Lite-5s后端集成:Node.js环境下的高性能API服务构建

Kandinsky-5.0-I2V-Lite-5s后端集成&#xff1a;Node.js环境下的高性能API服务构建 1. 引言 想象一下&#xff0c;你正在开发一个创意设计平台&#xff0c;用户上传一张图片&#xff0c;几秒钟后就能看到它变成了一段生动的视频。这种从静态图像到动态视频的转换能力&#xf…...

避开这3个坑,你的软考数据库设计题至少多拿10分:从E-R图合并冲突到SQL约束实战

软考数据库设计题避坑指南&#xff1a;从E-R图到SQL约束的实战技巧 每次软考结束&#xff0c;总有一批考生捶胸顿足——"那道数据库设计题明明会做&#xff0c;怎么又丢分了&#xff1f;"作为参加过三次软考阅卷的数据库讲师&#xff0c;我发现90%的失分都集中在几个…...

解锁知识:9种突破信息壁垒的创新方案

解锁知识&#xff1a;9种突破信息壁垒的创新方案 【免费下载链接】bypass-paywalls-chrome-clean 项目地址: https://gitcode.com/GitHub_Trending/by/bypass-paywalls-chrome-clean 在信息爆炸的数字时代&#xff0c;高效的"信息获取"与"资源解锁"…...

Phi-3-Mini-128K实战JavaScript:构建前端智能代码提示插件

Phi-3-Mini-128K实战JavaScript&#xff1a;构建前端智能代码提示插件 最近在折腾前端项目时&#xff0c;我总在想&#xff0c;要是写代码时能有个更懂我的助手就好了。现有的代码补全工具虽然不错&#xff0c;但很多时候还是停留在语法层面&#xff0c;对于业务逻辑、复杂函数…...

深入解析DDR3与AXI接口:基于7035开发板的实战笔记

1. DDR3基础概念与7035开发板适配 第一次接触DDR3时&#xff0c;我也被那些专业术语搞得晕头转向。直到在7035开发板上实际调试后&#xff0c;才发现理解DDR3的关键在于抓住几个核心特性。DDR3全称Double Data Rate 3&#xff0c;顾名思义&#xff0c;它在时钟上升沿和下降沿都…...

OpenClaw创始人加入OpenAI:这不是跳槽新闻,是整个AI行业换挡的信号

OpenClaw创始人加入OpenAI&#xff1a;这不是跳槽新闻&#xff0c;是整个AI行业换挡的信号摘要OpenClaw创始人Peter Steinberger正式加入OpenAI&#xff0c;项目移交开源基金会。Sam Altman亲自官宣&#xff0c;称他是"天才"。这件事的真正意义不在人事变动&#xff…...

JIT热路径识别失效?手撕Python 3.14 _pyjitsymbol.c源码,定位3个未文档化的profile阈值陷阱(内附补丁POC)

第一章&#xff1a;JIT热路径识别失效&#xff1f;手撕Python 3.14 _pyjitsymbol.c源码&#xff0c;定位3个未文档化的profile阈值陷阱&#xff08;内附补丁POC&#xff09;Python 3.14 引入的 _pyjitsymbol JIT 框架在实际压测中频繁出现热路径“失焦”现象&#xff1a;高频率…...

大厂Agent开发工程师亲授!这份核心技术学习路线助你轻松拿下高薪Offer!

结合个人实际的工作内容和招聘市场对于Agent开发的能力要求&#xff08;阅读汇总了大量大厂的Agent开发招聘面经&#xff09;&#xff0c;我总结了一份核心技术学习路线。 这个学习路线由浅到深&#xff0c;基本覆盖了现在大厂对于Agent开发的技术要求&#xff0c;技术栈完全可…...

BGE-Reranker-v2-m3为何必须用?RAG幻觉过滤入门必看

BGE-Reranker-v2-m3为何必须用&#xff1f;RAG幻觉过滤入门必看 如果你正在搭建RAG系统&#xff0c;或者已经搭建了但总觉得回答质量时好时坏&#xff0c;经常出现“幻觉”——也就是模型一本正经地胡说八道——那你很可能遇到了一个核心问题&#xff1a;向量检索“搜不准”。…...

[Android] 鲁迅全集 7.2.0

[Android] 鲁迅全集 7.2.0 链接&#xff1a;https://pan.xunlei.com/s/VOp2ylhHGYlTTbQ2rTOhsk3RA1?pwdh6tu# 鲁迅作品全集&#xff01;&#xff01;&#xff01;...