Spring MVC 源码- RequestToViewNameTranslator 组件
RequestToViewNameTranslator 组件
RequestToViewNameTranslator 组件,视图名称转换器,用于解析出请求的默认视图名。就是说当 ModelAndView 对象不为 null,但是它的 View 对象为 null,则需要通过 RequestToViewNameTranslator 组件根据请求解析出一个默认的视图名称。
回顾
先来回顾一下在 DispatcherServlet 中处理请求的过程中哪里使用到 RequestToViewNameTranslator 组件,可以回到《一个请求的旅行过程》中的 DispatcherServlet 的 doDispatch 方法中看看,如下:
protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {HttpServletRequest processedRequest = request;try {ModelAndView mv = null;try {// ... 省略相关代码// <6> 真正的调用 handler 方法,也就是执行对应的方法,并返回视图mv = ha.handle(processedRequest, response, mappedHandler.getHandler());// ... 省略相关代码// <8> 无视图的情况下设置默认视图名称applyDefaultViewName(processedRequest, mv);// ... 省略相关代码}catch (Exception ex) {dispatchException = ex; // <10> 记录异常}// <11> 处理正常和异常的请求调用结果processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);}catch (Exception ex) { // <12> 已完成处理 拦截器 }finally { }
}private void applyDefaultViewName(HttpServletRequest request, @Nullable ModelAndView mv) throws Exception {if (mv != null && !mv.hasView()) {String defaultViewName = getDefaultViewName(request);if (defaultViewName != null) {mv.setViewName(defaultViewName);}}
}@Nullable
protected String getDefaultViewName(HttpServletRequest request) throws Exception {return (this.viewNameTranslator != null ? this.viewNameTranslator.getViewName(request) : null);
}
在上面方法的<8>处,会调用 applyDefaultViewName(HttpServletRequest request, @Nullable ModelAndView mv) 方法,如果返回的 ModelAndView 对象不为 null,但是他的 View 对象为 null,则需要通过 viewNameTranslator 的 getViewName(HttpServletRequest request) 方法,从请求中获取默认的视图名,如果获取到了则设置到 ModelAndView 对象中
applyDefaultViewName(HttpServletRequest request, @Nullable ModelAndView mv) 这个方法还会在处理异常的时候调用,因为处理异常也返回 ModelAndView 对象,所以需要做“类似”的处理
RequestToViewNameTranslator 接口
org.springframework.web.servlet.RequestToViewNameTranslator,视图名称转换器,用于解析出请求的默认视图名,代码如下:
public interface RequestToViewNameTranslator {/*** 根据请求,获得其视图名*/@NullableString getViewName(HttpServletRequest request) throws Exception;
}Spring MVC 就提供一个实现类:org.springframework.web.servlet.view.DefaultRequestToViewNameTranslator
我看了一下,Spring Boot 没有提供其他的实现类

初始化过程
在 DispatcherServlet 的 initRequestToViewNameTranslator(ApplicationContext context) 方法,初始化 RequestToViewNameTranslator 组件,方法如下:
private void initRequestToViewNameTranslator(ApplicationContext context) {try {this.viewNameTranslator =context.getBean(REQUEST_TO_VIEW_NAME_TRANSLATOR_BEAN_NAME, RequestToViewNameTranslator.class);if (logger.isTraceEnabled()) {logger.trace("Detected " + this.viewNameTranslator.getClass().getSimpleName());}else if (logger.isDebugEnabled()) {logger.debug("Detected " + this.viewNameTranslator);}}catch (NoSuchBeanDefinitionException ex) {// We need to use the default./*** 如果未找到,则获取默认的 RequestToViewNameTranslator 对象* {@link org.springframework.web.servlet.view.DefaultRequestToViewNameTranslator}*/this.viewNameTranslator = getDefaultStrategy(context, RequestToViewNameTranslator.class);if (logger.isTraceEnabled()) {logger.trace("No RequestToViewNameTranslator '" + REQUEST_TO_VIEW_NAME_TRANSLATOR_BEAN_NAME +"': using default [" + this.viewNameTranslator.getClass().getSimpleName() + "]");}}
}
获得 Bean 名称为 "viewNameTranslator",类型为 RequestToViewNameTranslator 的 Bean ,将其设置为 viewNameTranslator
如果未获得到,则获得默认配置的 RequestToViewNameTranslator 实现类,调用 getDefaultStrategies(ApplicationContext context, Class<T> strategyInterface) 方法,就是从 DispatcherServlet.properties 文件中读取 RequestToViewNameTranslator 的默认实现类,如下:
org.springframework.web.servlet.RequestToViewNameTranslator=org.springframework.web.servlet.view.DefaultRequestToViewNameTranslator
DefaultRequestToViewNameTranslator
org.springframework.web.servlet.view.DefaultRequestToViewNameTranslator 实现 RequestToViewNameTranslator 接口,默认且是唯一的 RequestToViewNameTranslator 实现类
构造方法
public class DefaultRequestToViewNameTranslator implements RequestToViewNameTranslator {private static final String SLASH = "/";/*** 前缀*/private String prefix = "";/*** 后缀*/private String suffix = "";/*** 分隔符*/private String separator = SLASH;/*** 是否移除开头 {@link #SLASH}*/private boolean stripLeadingSlash = true;/*** 是否移除末尾 {@link #SLASH}*/private boolean stripTrailingSlash = true;/*** 是否移除拓展名*/private boolean stripExtension = true;/*** URL 路径工具类*/private UrlPathHelper urlPathHelper = new UrlPathHelper();
}getViewName
实现 getViewName(HttpServletRequest request) 方法,代码如下:
@Override
public String getViewName(HttpServletRequest request) {// 获得请求路径String lookupPath = this.urlPathHelper.getLookupPathForRequest(request);// 获得视图名return (this.prefix + transformPath(lookupPath) + this.suffix);
}@Nullable
protected String transformPath(String lookupPath) {String path = lookupPath;// 移除开头 SLASHif (this.stripLeadingSlash && path.startsWith(SLASH)) {path = path.substring(1);}// 移除末尾 SLASHif (this.stripTrailingSlash && path.endsWith(SLASH)) {path = path.substring(0, path.length() - 1);}// 移除拓展名if (this.stripExtension) {path = StringUtils.stripFilenameExtension(path);}// 替换分隔符if (!SLASH.equals(this.separator)) {path = StringUtils.replace(path, SLASH, this.separator);}return path;
}通过 urlPathHelper 获取该请求的请求路径
调用 transformPath(String lookupPath) 方法,获得视图名,并添加前后缀(默认都是空的)。实际上就是你的请求 URI
总结
本文对 Spring MVC 的RequestToViewNameTranslator 组件进行了分析,视图名称转换器,用于解析出请求的默认视图名。当 ModelAndView 对象不为 null,但是它的 View 对象为 null,则需要通过 RequestToViewNameTranslator 组件根据请求解析出一个默认的视图名称。默认的 DefaultRequestToViewNameTranslator 实现类返回的就是请求的 URI。
我们目前最常用的 @ResponseBody 注解,对应的 RequestResponseBodyMethodProcessor 返回值处理器,所得到的 ModelAndView 对象为 null,所以不会用到该组件,也不会进行视图渲染,前后端分离嘛~
相关文章:
Spring MVC 源码- RequestToViewNameTranslator 组件
RequestToViewNameTranslator 组件RequestToViewNameTranslator 组件,视图名称转换器,用于解析出请求的默认视图名。就是说当 ModelAndView 对象不为 null,但是它的 View 对象为 null,则需要通过 RequestToViewNameTranslator 组件…...
Linux--TCP编程--0216 17
观前提示:本篇博文的一些接口需要前几篇博文实现的 线程池的实现Liunx--线程池的实现--0208 09_Gosolo!的博客-CSDN博客 线程池的单例模式Linux--线程安全的单例模式--自旋锁--0211_Gosolo!的博客-CSDN博客 1.TCP编程需要用的接口 创建 sock…...
关于设计模式的记录
############### 先弄清楚类模型的关系 ############### 万物的抽象关系 ############### 1.组合 composition实菱形 实线 无填充箭头整体与部分的关系同生共死代码体现:成员变量如:生命体与器官,http请求(请求行,请求…...
Lambda-常见的函数式接口
如果需要使用Lambda接口,就必须要有一个函数式接口 函数式接口是有且仅有一个抽象方法的接口, 对应的注解是FunctionalInterface Java中内置的常见函数式接口如下: 1.Runnable/ Callable /*** The <code>Runnable</code> interface should be implem…...
P1196 [NOI2002] 银河英雄传说 带权并查集
[NOI2002] 银河英雄传说 题目背景 公元 580158015801 年,地球居民迁至金牛座 α\alphaα 第二行星,在那里发表银河联邦创立宣言,同年改元为宇宙历元年,并开始向银河系深处拓展。 宇宙历 799799799 年,银河系的两大军…...
【项目实战】快来入门Groovy的基础语法吧
一、Groovy是什么? 1.1 与Java语言的关系 下一代的Java 语言,增强Java平台的唯一的脚本语言跟java一样,它也运行在 JVM 中。支持Java平台,无缝的集成了Java 的类和库;Groovy是一种运行在JVM上的动态语言,跑在JVM中的另一种语言编译后的.groovy也是以class的形式出现的。1…...
Mybatis中的动态SQL
Mybatis中的动态SQL 当存在多条件查询的SQL时,当用户某个条件的属性没有写时,就会存在问题,在test中则不能很好的运行 所以Mybatis提出了动态SQL。 即判断用户是否输入了某个属性 动态SQL中的一些问题 方法一 这个里的and是为了确保if条…...
VUE常用API
1.$set数据变了,视图没变 this.$set(targe,key,value)2.$nextTick:返回参数[函数]。是一个异步的,功能获得更新后DOM$nextTick(callback){return Promise.resolve().then(()>{callback();}) }3.$refs获取dom4.$el获取当前组件根…...
25 openEuler管理网络-使用nmcli命令配置ip
文章目录25 openEuler管理网络-使用nmcli命令配置ip25.1 nmcli介绍25.2 设备管理25.2.1 连接到设备25.2.2 断开设备连接25.3 设置网络连接25.3.1 配置动态IP连接25.3.1.1 配置IP25.3.1.2 激活连接并检查状态25.3.2 配置静态IP连接25.3.2.1 配置IP25.3.2.2 激活连接并检查状态25…...
如何安装和使用A-ops工具?
一、pip配置 1.配置信任域 pip3 config set global.trusted-host mirrors.tools.huawei.com2.配置pip源的url地址pip3 config set global.index-url http://mirrors.tools.huawei.com/pypi/simple 二、npm安装及配置 npm -v检测系统有无安装npm,如果没有的话需要配置ope…...
MySql数据库环境部署
MySql基础与Sql数据库概述基础环境的建立MYSQL数据库的连接方法MySql的默认数据库数据库端口号数据库概述 数据库(DataBase,DB)∶存储在磁带、磁盘、光盘或其他外存介质上、按定结构组织在一起的相关数据的集合。数据库管理系统〈DataBase Management S…...
极品笔记,阿里P7爆款《K8s+Jenkins》技术笔记,职场必备
前些日子从阿里的朋友那里取得这两份K8sJenkins的爆款技术笔记:《K8S(kubernetes)学习指南》《Jenkins持续集成从入门到精通》,非常高质量的干货,我立马收藏! 而今天咱们文章的主角就是这非常之干货的技术笔记:K8SJenk…...
数据结构:各种排序方法的综合比较
排序方法的选用应视具体场合而定。一般情况下考虑的原则有:(1)待排序的记录个数 n;(2)记录本身的大小;(3)关键字的分布情况:(4)对排序稳定性的要求等。 1.时间性能 (1) 按平均的时间性能来分,有三类排序方法: 时间复杂度为 O(nlogn)的方法有:快速排序、堆排序和归并排序,其中…...
【设计模式】 策略模式介绍及C代码实现
【设计模式】 策略模式介绍及C代码实现 背景 在软件构建过程中,某些对象使用的算法可能多种多样,经常改变,如果将这些算法都编码到对象中,将会使对象变得异常复杂,而且有时候支持不使用的算法也是一个性能负担。 如何…...
【数据库】第二章 关系数据库
第二章 关系数据库 2.1关系数据结构及形式化定义 关系 域(domain) :域是一组具有相同数据类型的值的集合,可以取值的个数叫基数 笛卡尔积 :一个记录叫做一个元组(tuple),元组中每一个属性值,叫一个分量 基数&…...
oracle和mysql的分页
oracle的分页:rownum 注意:: 对 ROWNUM 只能使用 < 或 <, 用 、 >、 > 都不能返回任何数据。 rownum是对结果集的编序排列,始终是从1开始,所以rownum直接使用时不允许使用>、> 所以当查询中间部分的信息时&…...
深拷贝与浅拷贝的理解
浅拷贝的理解浅拷贝的话只会拷贝基本数据类型,例如像string、Number等这些,类似:Object、Array 这类的话拷贝的就是对象的一个指针(通俗来讲就是拷贝一个引用地址,指向的是一个内存同一份数据),也就是说当拷贝的对象数…...
Shell变量
一、变量分类 根据作用域分三种 (一)只在函数内有效,叫局部变量 (二)只在当前shell进程中有效,叫做全局变量 (三)在当前shell进程与子进程中都有效,叫做环境变量 shell进…...
Android 8请求权限时弹窗BUG
弹窗BUG 应用使用requestPermissions申请权限时,系统会弹出一个选择窗口,可进行允许或拒绝, 此窗口中有一个”不再询问“的选择框, ”拒绝”及“允许”的按钮。 遇到一个Bug,单点击“不再询问”,“允许”这个按钮会变…...
路漫漫:网络空间的监管趋势
网络空间是“以相互依存的网络基础设施为基本架构,以代码、信息与数据的流动为环境,人类利用信息通讯技术与应用开展活动,并与其他空间高度融合与互动的空间”。随着信息化技术的发展,网络空间日益演绎成为与现实人类生存空间并存…...
第19节 Node.js Express 框架
Express 是一个为Node.js设计的web开发框架,它基于nodejs平台。 Express 简介 Express是一个简洁而灵活的node.js Web应用框架, 提供了一系列强大特性帮助你创建各种Web应用,和丰富的HTTP工具。 使用Express可以快速地搭建一个完整功能的网站。 Expre…...
多云管理“拦路虎”:深入解析网络互联、身份同步与成本可视化的技术复杂度
一、引言:多云环境的技术复杂性本质 企业采用多云策略已从技术选型升维至生存刚需。当业务系统分散部署在多个云平台时,基础设施的技术债呈现指数级积累。网络连接、身份认证、成本管理这三大核心挑战相互嵌套:跨云网络构建数据…...
【网络安全产品大调研系列】2. 体验漏洞扫描
前言 2023 年漏洞扫描服务市场规模预计为 3.06(十亿美元)。漏洞扫描服务市场行业预计将从 2024 年的 3.48(十亿美元)增长到 2032 年的 9.54(十亿美元)。预测期内漏洞扫描服务市场 CAGR(增长率&…...
Linux相关概念和易错知识点(42)(TCP的连接管理、可靠性、面临复杂网络的处理)
目录 1.TCP的连接管理机制(1)三次握手①握手过程②对握手过程的理解 (2)四次挥手(3)握手和挥手的触发(4)状态切换①挥手过程中状态的切换②握手过程中状态的切换 2.TCP的可靠性&…...
PL0语法,分析器实现!
简介 PL/0 是一种简单的编程语言,通常用于教学编译原理。它的语法结构清晰,功能包括常量定义、变量声明、过程(子程序)定义以及基本的控制结构(如条件语句和循环语句)。 PL/0 语法规范 PL/0 是一种教学用的小型编程语言,由 Niklaus Wirth 设计,用于展示编译原理的核…...
Python如何给视频添加音频和字幕
在Python中,给视频添加音频和字幕可以使用电影文件处理库MoviePy和字幕处理库Subtitles。下面将详细介绍如何使用这些库来实现视频的音频和字幕添加,包括必要的代码示例和详细解释。 环境准备 在开始之前,需要安装以下Python库:…...
拉力测试cuda pytorch 把 4070显卡拉满
import torch import timedef stress_test_gpu(matrix_size16384, duration300):"""对GPU进行压力测试,通过持续的矩阵乘法来最大化GPU利用率参数:matrix_size: 矩阵维度大小,增大可提高计算复杂度duration: 测试持续时间(秒&…...
k8s业务程序联调工具-KtConnect
概述 原理 工具作用是建立了一个从本地到集群的单向VPN,根据VPN原理,打通两个内网必然需要借助一个公共中继节点,ktconnect工具巧妙的利用k8s原生的portforward能力,简化了建立连接的过程,apiserver间接起到了中继节…...
Rapidio门铃消息FIFO溢出机制
关于RapidIO门铃消息FIFO的溢出机制及其与中断抖动的关系,以下是深入解析: 门铃FIFO溢出的本质 在RapidIO系统中,门铃消息FIFO是硬件控制器内部的缓冲区,用于临时存储接收到的门铃消息(Doorbell Message)。…...
关键领域软件测试的突围之路:如何破解安全与效率的平衡难题
在数字化浪潮席卷全球的今天,软件系统已成为国家关键领域的核心战斗力。不同于普通商业软件,这些承载着国家安全使命的软件系统面临着前所未有的质量挑战——如何在确保绝对安全的前提下,实现高效测试与快速迭代?这一命题正考验着…...
