spring篇:【RequestToViewNameTranslator】

RequestToViewNameTranslator这个类,出现在springMVC的DispatcherServlet类中,作为DispatcherServlet的initStrategies方法中的9大init方法之一的initRequestToViewNameTranslator方法中,就会初始化一个RequestToViewNameTranslator。

那么下面我们就来看看这到底是是个什么东东,它是做什么的?怎么用?什么时候被调用?让我们一起玩转RequestToViewNameTranslator。

一.来看一下这个类的出处
 


当用tomact启动你的程序时,便会进入到DispatcherServlet来初始化一些内容。自然就包括了我们今天的猪脚。如图中的源码所示,首先从容器中找对应的名为viewNameTranslator的RequestToViewNameTranslator实现类,如果找不到,就用DispatcherServlet.properties中指定的translator来生成一个(为什么从这个文件,可参其他文章【DispatcherServlet篇】)。

二. 这个类主要作用是什么以及从在哪里被调用?
在网上看过很多关于这个类的说明,基本都是讲的源码的执行过程,这对于初学者也许有点抽象,下面我通过一个例子,来说明它的作用。
相信看这个文章的人应该明白springmvc的作用,说白了就是,我发起一个请求,然后controller中的方法来处理这个请求,然后通过return "jsp页面的路径" 来显示我们的jsp页面(此处不考虑返回json等其他情况,只考虑最简单的返回jsp页面)。例如下面代码,当我们浏览器访问http://localhost:8088/view/hellojsp时,便会将hello.jsp的内容显示在浏览器上, 如下:

@Controller
@RequestMapping("/view")
public class ViewController {
	@RequestMapping("/hellojsp")
	public String toHelloJsp(){
        // 跳转到hello.jsp
		return "hello";
	}
}

这里,我们返回的这个hello,在springmvc中就叫做viewName(至于为什么返回的字符串会最终变为页面来显示,这里不做介绍。看参考其他的文章),有了这个名字,springmvc就可以从我们存放jsp页面的目录下去寻找与之名字相同的jsp文件,来显示了。
那么现在来想这么一个问题,如果现在我们这里不返回值了,如下图所示,那么浏览器请求的结果是什么?springmvc他还怎么去找对应的jsp文件呢?

@Controller
@RequestMapping("/view")
public class ViewController {
	@RequestMapping("/hellojsp")
	public void toHelloJsp(){
        // 访问这个url,按理说应该显示hello.jsp页面,但是我现在这里给注释掉了,返回值改为了void
        // return "hello";
	}
}

相信大家都会说,肯定是404了。对,没错,结果肯定是404,如下图:

但是大家知不知道,在显示404错误之前,springmvc还为我们做了一步操作,就是使用我们今天的猪脚RequestToViewNameTranslator,然后用它的实现类的解析方式去解析了我们的请求,从请求中来的出一个字符串,来代替我们controller中的return的字符串(jsp文件的名字),然后在jsp文件目录中找名字与这个字符串相同的jsp文件,如果找到了,就显示这个jsp,如果找不到就显示我们上面的404。

所以说,RequestToViewNameTranslator就是一个请求解析器,他的每个实现有各自的一个解析请求的算法,经过这个算法,从请求的url中获得一个字符串,将这个字符串作为要显示的jsp的名字,去jsp文件目录中查找,找到就显示,找不到才最终显示404.
在springmvc中默认使用的是一个名字为DefaultRequestToViewNameTranslator(默认也只有这一个实现类),他解析请求的算法是将我们的请求直接解析为jsp的名字,然后从存放jsp的目录中去找,比如我们上面的请求是/view/hellojsp,那么经过这个实现类的解析后得到的便是/view/hellojsp这个字符串,有了这个值后,就会在执行一次就等同于在controller中return "/view/viewjsp"一样的效果,也就是去jsp目录下的view文件夹下去找viewjsp.jsp文件,如果找到就显示,找不到就404,因为我们没有这个文件,所以就最终404了。

那么这个RequestToViewNameTranslator是在什么时候被调用的呢?下面通过一次请求的代码跟踪来看一下,controller用的是上面那个没有返回值的。
第一步:浏览器发送请求:http://localhost:8088/view/hellojsp
第二步:通过DispatcherServlet中的doDispatch方法调用controller中的toHelloJsp方法处理请求。如下:


第三步:调用完controller的方法后,便通过判断来看是否使用RequestToViewNameTranslator来生成默认的viewname

第四步:因为没有返回值,所以mv(ModelAndView)中就没有view,所以就要使用RequestToViewNameTranslator来生成默认的viewname

第五步:调用RequestToViewNameTranslator默认实现类DefaultRequestToViewNameTranslator的getDefaultViewName方法来获取默认的viewname

 

第六步:下面就是DefaultRequestToViewNameTranslator中将请求变为viewname的具体算法了

第七步:将这个返回的path作为view赋值给mv,有了mv后,springmvc便会根据mv的内容去找对应的jsp,因为此时mv的view为view/hellojsp,所以便会到jsp目录下的view目录下去找hellojsp,因为我们还没有这个文件,所以就显示404了。
到此整个请求就结束。

上面虽然给大家展示了并讲述了RequestToViewNameTranslator是在哪,并且是如何被使用的,但最终因为没有找到默认生成的viewname所对应jsp,还是显示了404,那么现在我们为了让使用默认viewname生成的ModelAndView生效,最终能通过这个默认的viewname显示出页面,而不是404,我们就新建view文件夹,然后新建一个hellojsp.jsp,看看最终是否能显示。


然后,我们再次浏览器发起http://localhost:8088/view/hellojsp ,下面看看结果如何,如下:

怎么样,是不是用默认的DefaultRequestToViewNameTranslator获取的viewname,成功显示出来了吧,这个时候404没有了。
这也正如作者在开头说的那样,页面在显示404之前,其实springmvc还帮我们通过RequestToViewNameTranslator获取一个默认的viewname,然后用这个viewname又去jsp的目录中找了一次是否有与之同行的jsp文件。

 

三.自定义RequestToViewNameTranslator
我们现在自己自定义一个实现类,然后实现这样的效果:controller我们依旧没有返回值,然后在我们自定义的实现类中,我们通过返回一个hello字符串的viewname,然后页面显示hello.jsp。下面开始:
第一步:编写RequestToViewNameTranslator实现类,MyRequestToViewNameTranslator

public class MyRequestToViewNameTranslator implements RequestToViewNameTranslator {
	@Override
	public String getViewName(HttpServletRequest request) throws Exception {
		// 直接返回hello,然后让springmvc去帮我们显示jsp目录下的hello.jsp
		return "hello";
	}
}

第二步:通过spring-mvc.xml文件声明这个类,放到容器中(也可以使用java configuration形式)

	<!-- 注意id必须为viewNameTranslator -->
	<bean id="viewNameTranslator" class="com.lhb.MyRequestToViewNameTranslator"/> 

第三步:启动程序,启动时在初始化DispatcherServlet时,我们得到的不再是默认的DefaultRequestToViewNameTranslator,而是从容器中获取的我们自定义的类,如下图红框

第四步:浏览器发起http://localhost:8088/view/hellojsp 请求
此时在运行完controller的方法后,因为没有返回值,所以便会调用我们自定义的类中,来通过算法从请求中解析出一个默认的viewname来使用,作为将来查找的jsp文件的名字,因为是例子,所以我们直接就返回hello了,如下:

最后,springmvc去jsp目录下找到了hello.jsp页面,就显示出来了,如下:

-----------------------------------------------------------------------------------------------------------------------------------------------------------------------
到此,整个文章完了,下面做一下总结:

  1. 什么是RequestToViewNameTranslator?
    就是将请求的url解析成一个viewname的解析器。具体怎么个算法解析,可以自定义,也可以使用默认的实现类
  2. 什么时候这个实现类会被调用?
    当我们的controller的方法中,没有返回值时(只考虑返回值为jsp页面的名字,不考虑直接输出字符串到浏览器),那么便会调用Translator来获取一个默认的viewname,然后使用这个viewname的值,去jsp目录中找与之同名的jsp页面,如果还找不到,那就显示404了。
  3. 注意,在spring-mvc.xml中声明我们的自定义实现类时,bean的名字一定为viewNameTranslator,否则会使用默认的实现类。
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章