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,单点击“不再询问”,“允许”这个按钮会变…...
路漫漫:网络空间的监管趋势
网络空间是“以相互依存的网络基础设施为基本架构,以代码、信息与数据的流动为环境,人类利用信息通讯技术与应用开展活动,并与其他空间高度融合与互动的空间”。随着信息化技术的发展,网络空间日益演绎成为与现实人类生存空间并存…...
uni-app学习笔记二十二---使用vite.config.js全局导入常用依赖
在前面的练习中,每个页面需要使用ref,onShow等生命周期钩子函数时都需要像下面这样导入 import {onMounted, ref} from "vue" 如果不想每个页面都导入,需要使用node.js命令npm安装unplugin-auto-import npm install unplugin-au…...
系统设计 --- MongoDB亿级数据查询优化策略
系统设计 --- MongoDB亿级数据查询分表策略 背景Solution --- 分表 背景 使用audit log实现Audi Trail功能 Audit Trail范围: 六个月数据量: 每秒5-7条audi log,共计7千万 – 1亿条数据需要实现全文检索按照时间倒序因为license问题,不能使用ELK只能使用…...
将对透视变换后的图像使用Otsu进行阈值化,来分离黑色和白色像素。这句话中的Otsu是什么意思?
Otsu 是一种自动阈值化方法,用于将图像分割为前景和背景。它通过最小化图像的类内方差或等价地最大化类间方差来选择最佳阈值。这种方法特别适用于图像的二值化处理,能够自动确定一个阈值,将图像中的像素分为黑色和白色两类。 Otsu 方法的原…...
vue3 定时器-定义全局方法 vue+ts
1.创建ts文件 路径:src/utils/timer.ts 完整代码: import { onUnmounted } from vuetype TimerCallback (...args: any[]) > voidexport function useGlobalTimer() {const timers: Map<number, NodeJS.Timeout> new Map()// 创建定时器con…...
数据库分批入库
今天在工作中,遇到一个问题,就是分批查询的时候,由于批次过大导致出现了一些问题,一下是问题描述和解决方案: 示例: // 假设已有数据列表 dataList 和 PreparedStatement pstmt int batchSize 1000; // …...
dify打造数据可视化图表
一、概述 在日常工作和学习中,我们经常需要和数据打交道。无论是分析报告、项目展示,还是简单的数据洞察,一个清晰直观的图表,往往能胜过千言万语。 一款能让数据可视化变得超级简单的 MCP Server,由蚂蚁集团 AntV 团队…...
Web 架构之 CDN 加速原理与落地实践
文章目录 一、思维导图二、正文内容(一)CDN 基础概念1. 定义2. 组成部分 (二)CDN 加速原理1. 请求路由2. 内容缓存3. 内容更新 (三)CDN 落地实践1. 选择 CDN 服务商2. 配置 CDN3. 集成到 Web 架构 …...
使用LangGraph和LangSmith构建多智能体人工智能系统
现在,通过组合几个较小的子智能体来创建一个强大的人工智能智能体正成为一种趋势。但这也带来了一些挑战,比如减少幻觉、管理对话流程、在测试期间留意智能体的工作方式、允许人工介入以及评估其性能。你需要进行大量的反复试验。 在这篇博客〔原作者&a…...
现有的 Redis 分布式锁库(如 Redisson)提供了哪些便利?
现有的 Redis 分布式锁库(如 Redisson)相比于开发者自己基于 Redis 命令(如 SETNX, EXPIRE, DEL)手动实现分布式锁,提供了巨大的便利性和健壮性。主要体现在以下几个方面: 原子性保证 (Atomicity)ÿ…...
elementUI点击浏览table所选行数据查看文档
项目场景: table按照要求特定的数据变成按钮可以点击 解决方案: <el-table-columnprop"mlname"label"名称"align"center"width"180"><template slot-scope"scope"><el-buttonv-if&qu…...
