目录
- SpringMVC的视图解析器
-
- 问题:
- 解决:
- 实现:
- 本质:
- 内容:
- 回顾没有学视图解析器之前,我们如何实现转发和重定向
- 视图解析器代码实现
-
- 使用View接口完成请求转发|重定向
- SpringMVC视图解析器升级:ModelAndView
- SpringMVC视图解析器再次升级:
- SpringMVC的自定义视图解析器
-
- 问题
- 解决:
- 实现:
- 概念:
- 使用:
- SpringMVC自定义视图解析器的使用
-
- 目前项目资源的声明位置和访问中存在的问题
-
- 问题:
- 实现方案:
- 项目密室:
- 使用自定义视图解析器优化资源跳转路径
-
- 问题:
- 解决:
- 代码实现
- 使用restful声明公共单元方法请求转发WEB-INF下的资源
-
- 问题:
- 解决:
- 实现:
- 代码
- 重新配置springmvc.xml文件中的资源放行
SpringMVC的视图解析器
问题:
我们在使用了SpringMVC后,对于请求的处理由以前我们自己声明
Servlet处理,变为声明单元方法来处理。请求处理完成之后,需要将
处理结果响应给浏览器 ,响应方式有直接响应,请求转发,重定向。对于
请求转发和重定向,我们在单元方法中是通过返回值来告诉 DispatcherServlet如何进行此次请求的响应。而方法的返回值只有一个,所 以,我们就需要在返回值值中声明指定的关键字,让DispatcherServlet可以
通过关键字来区分是请求转发还是重定向,那么DispactherServlet底层是
如何来实现请求转发和重定向的区分的呢?
解决:
在DispatcherServlet的底层,增加逻辑代码,根据单元方法的返回值
将其返回值中的forward或者redirect关键字拆分出来,然后根据关键字
以及资源路径,最终完成资源的请求转发或者重定向。而这段逻辑代码
就是根据单元方法的返回值来完成最终的资源的处理,为了让Dispatcher
Servlet的代码结构层次更加清晰,我们可以将这段逻辑代码专门封装
起来,然后在DispatcherServlet中进行调用即可。也就意味着单元方法的
返回值被DispatcherServlet接收后,作为实参传递给了这段封装好的逻辑
代码。
实现:
视图解析器
本质:
视图解析器就是SpringMVC官方封装好的,根据单元方法的返回值
完成对应的请求转发或者重定向的对象。
**由DisatcherServlet来调用。**把返回值作为参数给DisatcherServlet。DisatcherServlet里面会创建一个处理返回值类的对象,这个对象调用里面 的方法就可以处理 返回值了
内容:
InternalResourceView:请求转发
RedirectView:重定向
ModelAndView:请求转发和重定向
回顾没有学视图解析器之前,我们如何实现转发和重定向
使用关键字实现的,使用forward关键字完成响应,使用redirect关键字完成响应。
具体不清楚这些关键字的,看之前的文章
深度学习springMVC(四)springmvc如何实现数据的响应,SpringMVC中使用作用域对象完成数据的流转(看不懂你打我)
每次我们自己写关键字,springmvc框架也想到了,比较的麻烦,所以人家把这些关键字封装到类里面,返回值作为参数给了这些类对象,就可以实现转发或者重定向。
视图解析器代码实现
使用View接口完成请求转发|重定向
代码语言:javascript复制 //声明单元方法:使用View接口的子类对象完成请求转发或者重定向
/**
* 使用View接口完成请求转发|重定向
* 解释:
* SpringMVC的官方,提供了一个叫做View的接口,告诉开发人员
* DispatcherServlet底层会调用View接口的实例化对象中的逻辑方法
* 来完成对应的请求转发和重定向。
* 使用:
* 1. 单元方法的返回值为View接口类型
* 2.真实return的为View接口的实例化对象(视图解析器)。
* 官方提供的实现了View接口的视图解析器:
* InternalResourceView:请求转发
* RedirectView:重定向
* @return
*/
@RequestMapping("demoView")
public View demoView(HttpServletRequest request){
//处理请求
System.out.println("MyController.demoView:View接口实例化对象完成请求转发|重定向");
//响应结果
//请求转发
//return new InternalResourceView("/req.jsp");
//重定向
return new RedirectView(request.getContextPath() "/redirect.jsp");
}
SpringMVC视图解析器升级:ModelAndView
代码语言:javascript复制 /**
* SpringMVC视图解析器升级:ModelAndView
* 问题:
* 在原有的View接口的视图解析器中需要自己在单元方法中根据响应方式
* 来创建对应的视图解析器对象返回给DispatcherServlet使用,过于麻烦。
* 解决:
* 从根据响应方式的不同创建不同的视图解析器对象,变为只创建一个
* 视图解析器对象,该对象内部自动根据参数来实现请求转发或者重定向。
* 实现:
* ModelAndView
* 注意:
* 升级后也就意味着DispatcherServlet使用ModelAndView来接收
* 单元方法的返回值,为了兼容早期版本,让ModelAndView可以接收
* View接口的实例化对象。
* 特点:
* ModelAndView对象是Model和View对象的结合体。既可以作为视图解析器使用
* 又可以作为数据流转的载体使用。
*/
@RequestMapping("md")
public ModelAndView demoModelAndView(){
//处理请求
System.out.println("MyController.demoModelAndView:ModelAndView视图解析器");
//响应结果
//创建ModelAndView对象
ModelAndView modelAndView=new ModelAndView();
modelAndView.addObject("str","我是流转的数据");
//请求转发
//modelAndView.setViewName("forward:/mdReq.jsp");
//重定向
modelAndView.setViewName("redirect:/mdRedirect.jsp");
return modelAndView;
}
SpringMVC视图解析器再次升级:
代码语言:javascript复制 /**
* SpringMVC视图解析器再次升级:
* 问题:
* 在使用了ModelAndView对象后,已经很爽了。但是在单元方法中
* 我们还需要创建ModelAndView对象并将请求转发或者重定向的
* 路径存储进入,返回给DispatcherServlet使用,而我们真正
* 想写的是资源路径以及响应方式
* 解决:
* 我们在单元方法中直接返回字符串资源路径及其响应方式关键字。
* 由DispatcherServlet底层帮我们创建ModelAndView来接收
* 单元方法的返回值。
* 注意:
* 虽然我们在单元方法中直接返回的字符串数据,但是DispatcherServlet
* 并不是直接使用字符串数据而是仍然调用ModelAndView视图解析器完成请求转发或者重定向。
*/
@RequestMapping("demoString")
public String demoString(){
//处理请求
System.out.println("目前的请求转发或者重定向的方式");
//响应结果
//请求转发
//return "forward:/req.jsp";
//重定向
return "redirect:/redirect.jsp";
}
SpringMVC的自定义视图解析器
问题
目前我们在SpringMVC的响应中,虽然我们直接在单元方法中返回字符串数据来
表明请求转发或者重定向的资源,但是DispatcherServlet的底层默认使用 ModelAndView来完成视图资源的解析和跳转。但是ModelAndView这个视图 解析器比较死板,ModelAndView会将单元方法返回的字符串,根据关键拆分后
来完成资源的跳转,比如:”forward:/index.jsp”,那么ModelAndView就会直接
请求转发index.jsp资源。但是我们在实际生产环境中往往会有很多特殊的需求,
这样ModelAndView就无法满足了,比如,我们在项目下创建一个a文件夹,在
a文件夹下创建b子文件夹,在b下创建一个c子文件夹,然后将项目的页面资 源全部放到c文件夹下,这样我们如果在单元方法中请求转发c文件夹中的资源,
返回值路径就会很麻烦:
”forward:/a/b/c/index.jsp”
”forward:/a/b/c/page.jsp”
“forward:/a/b/c/sel.jsp”…
而且后期一旦资源路径的文件夹名字发生变更,修改起来也会非常的麻烦。
自己写的路径太长,太麻烦
**核心问题:**官方视图 解析器比较死板,只会转发重定向,我们需要灵活 的视图解析器,自己写的路径太长,太麻烦
解决:
使用自定义视图解析器,而我们自定义的视图解析器除了可以让我们根据需求
配置一些路径上的常量参数以外,还需具备ModelAndView的逻辑。所以,
我们自己需要从头创建一个新的视图解析器,在我们自己创建的视图解析器中
声明ModelAndView中的原有逻辑代码,以及我们自己需要的部分常量参数。
但是ModelAndView的逻辑我们是不知道的,那么能不能让SpringMVC官方
提供一个支持部分数据自定义的视图解析器呢,答案是可以的。我们可以通过配置 文件来配置一些我们在视图解析器中的常量数据。
实现:
代码语言:javascript复制 InternalResourceViewResolver
概念:
因为InternalResourceViewResolver可以让我们通过配置文件来设置一些常量
参数,所以我们将该视图解析器称为自定义视图解析器。
使用:
1.在springmvc.xml文件中进行配置
2.在单元方法中按照指定的格式返回资源路径
代码语言:javascript复制 <!--配置自定义视图解析器-->
<bean id="viewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<!--配置资源路径的前缀-->
<property name="prefix" value="/a/b/c/"></property>
<!--配置资源路径的后缀-->
<property name="suffix" value=".jsp"></property>
</bean>
代码语言:javascript复制@Controller
public class MyControllerView {
//声明单元方法:使用默认的ModelAndView视图解析器
@RequestMapping("mv")
public String demoMv(){
System.out.println("MyControllerView.demoMv:测试使用默认的ModelAndView视图解析器");
return "forward:/a/b/c/c.jsp";
}
返回的字符串里面带了forward这些关键字,就调用ModelAndView视图解析器。不带,就使用自定义视图解析器
//声明单元方法:使用默认的ModelAndView视图解析器
@RequestMapping("myView")
public String demoInternalResourceViewResolver(){
System.out.println("MyControllerView.demoInternalResourceViewResolver:测试使用自定义视图解析器");
return "c";
}
}
SpringMVC自定义视图解析器的使用
目前项目资源的声明位置和访问中存在的问题
问题:
目前我们在完成功能开发时,会将项目相关的页面资源及静态资源直接声明
在web目录下,或者web目录下的子文件夹中。而web目录及其声明的子
目录中的资源,在浏览器中是可以直接被访问到的。也就是说,只要我们知道
某个资源的URL地址,在浏览器中是可以直接发起请求访问该资源的,极不安全。
实现方案:
在我们的web项目中造一间密室,将重要的资源放到密室中。而密室是对外不开 放的,也就说密室中的资源必须通过tomcat服务器的内部转发才能进行访问。就 算浏览器听说项目有这样密室,并且密室中也有浏览器想要的资源,浏览器发起的 请求地址是正确的,但是我们可以在服务器端死不承认,我们没有这个资源,在后 台给浏览器响应404.如果是我们觉得靠谱的请求,我们就在服务器端请求转发资 源给浏览器使用。
项目密室:
其实我们的web项目在创建的时候就自动的在web目录下创建了密室,就是
WEB-INF文件夹。也就是说WEB-INF文件夹下的资源浏览器是无法直接访问
的,必须通过内部请求转发才能访问。
代码语言:javascript复制 //声明单元方法:检查请求,是否给密室中的资源
@RequestMapping("getJsp")
public String getJsp(){
//处理请求
System.out.println("MyController.getJsp:检查密室资源请求是否合理");
//响应结果
return "forward:/WEB-INF/jsp/cc.jsp";
}
使用自定义视图解析器优化资源跳转路径
问题:
我们在将重要的项目资源放在WEB-INF文件夹中后,只能通过内部的请求转发来
访问资源。如果WEB-INF下的资源较多,造成请求转发的路径书写麻烦,而且后 期一旦资源的目录发生变更,修改起来会非常的麻烦,怎么办?
解决:
我们真正想在单元方法中想写的是资源的名字,而请求转发WEB-INF下的资源路 径是公共的,每次都要写。而刚好我们的自定义视图解析器就是专门用来进行请求
转发的,而且可以设置转发资源的公共前缀和后缀信息。所以,我们可以使用自定 义视图解析器来完成WEB-INF下的资源的请求转发。
代码实现
代码语言:javascript复制 <!--配置自定义视图解析器-->
<bean id="viewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix" value="/WEB-INF/jsp/"></property>
<property name="suffix" value=".jsp"></property>
</bean>
代码语言:javascript复制 //声明单元方法:使用自定义视图解析器请求转发WEB-INF下的资源
@RequestMapping("getJsp2")
public String getJsp2(){
//处理请求
System.out.println("MyController.getJsp2:使用自定义视图解析器访问");
//响应结果
return "dd";
}
使用restful声明公共单元方法请求转发WEB-INF下的资源
问题:
在项目中使用了自定义视图解析器后,可以在单元方法中简单的返回一个 WEB-INF下的资源的名字就可以完成资源的请求转发了,美滋滋。但是我们的资 源是非常多的,但是我们的单元方法的返回值只能有一个。总不能我们给WEB-INF
下的每个资源都声明一个对应的单元方法来完成请求转发吧,太麻烦了。
解决:
根据请求,请求转发WEB-INF下的资源的单元方法是肯定要声明的。我们可以
声明一个公共的单元方法,该单元方法不参与请求的逻辑处理,只负责根据请求
转发WEB-INF下的资源。
实现:
使用restful完成
代码
代码语言:javascript复制 <!--配置自定义视图解析器-->
<bean id="viewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix" value="/WEB-INF/jsp/"></property>
<property name="suffix" value=".jsp"></property>
</bean>
代码语言:javascript复制//声明公共单元方法:请求转发WEB-INF下的资源
@RequestMapping("{url}")
public String getJsp3(@PathVariable String url){
//处理请求
System.out.println("MyController.getJsp3:公共单元方法,请求转发WEB-INF下的资源");
//响应结果
return url;
}
重新配置springmvc.xml文件中的资源放行
如果把静态资源放到 web-inf 下,我们需要资源放行
代码语言:javascript复制 <!--配置静态资源放行-->
<mvc:resources mapping="/js/**" location="/WEB-INF/js/"></mvc:resources>
<mvc:resources mapping="/css/**" location="/WEB-INF/css/"></mvc:resources>
<mvc:resources mapping="/images/**" location="/WEB-INF/images/"></mvc:resources>