持续学习&持续更新中…
守破离
【Java从零到架构师第③季】【31】SpringMVC-InternalResourceViewResolver_自定义InternalResourceView
InternalResourceViewResolver
注意:
-
InternalResourceViewResolver
影响的是没有带forward:
、redirect:
的viewName,而不带forward:
、redirect:
的viewName默认就是转发,因此InternalResourceViewResolver只会影响转发。 -
配置了
InternalResourceViewResolver
后,受InternalResourceViewResolver
影响的viewName,SpringMVC在解析它时,就会变为:prefix + viewName + suffix
。
基本使用
<mvc:view-controller path="/jsp6" view-name="/jsp6"/>
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix" value="/WEB-INF/page/jsp"/>
<property name="suffix" value=".jsp"/>
</bean>
@Controller
@RequestMapping("/IRVR")
public class JspController1 {
@GetMapping("/jsp1")
public String jsp1() {
return "/jsp1";
}
@GetMapping("/jsp6")
public ModelAndView jsp6() {
return new ModelAndView("/jsp6");
}
}
配置多个
虽然说order属性的值越小,优先级就越高。
但是SpringMVC并不会像我们想象的那样:如果在优先级高的里面找不到,就会去从优先级较低的里面去找。
而是在优先级高的里面找不到就直接报404了。
此时,order属性就是一个摆设。
但转换角度思考一下,这儿的order可以起到一个开关的作用:你想使用哪个InternalResourceViewResolver,就将它的order值设为最小,让它的优先级最高,这样的话,其他比它优先级低的InternalResourceViewResolver,就永远不会被使用,SpringMVC只会使用优先级最高的那个。
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="order" value="1"/>
<property name="prefix" value="/WEB-INF/page/jsp"/>
<property name="suffix" value=".jsp"/>
</bean>
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="order" value="0"/>
<property name="prefix" value="/public"/>
<property name="suffix" value=".jsp"/>
</bean>
忽略InternalResourceViewResolver
方法一
写清楚:是"redirect:"
还是"forward:"
。
一旦写清楚是"redirect:"
还是"forward:"
之后,就不会受InternalResourceViewResolver
的影响了。
<mvc:view-controller path="/jsp6" view-name="forward:/WEB-INF/page/jsp/jsp6.jsp"/>
<mvc:view-controller path="/jsp6-redirect" view-name="redirect:/public/jsp6.jsp"/>
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix" value="/WEB-INF/page/jsp"/>
<property name="suffix" value=".jsp"/>
</bean>
@Controller
@RequestMapping("/IRVR")
public class JspController1 {
@GetMapping("/jsp1")
public String jsp1() {
// 没有写清楚是forward:还是redirect:的viewName,会受InternalResourceViewResolver的影响
return "/jsp1";
}
@GetMapping("/jsp6")
public String jsp6() {
return "redirect:/public/jsp6.jsp";
}
}
方法二
InternalResourceView
:转发JstlView
:转发(JSP中使用到了JSTL、国际化相关、…)RedirectView
:重定向
@Controller
@RequestMapping("/IRVR2")
public class JspController2 {
@GetMapping("/forward")
public ModelAndView forward() {
ModelAndView mv = new ModelAndView();
mv.setView(new InternalResourceView("/WEB-INF/page/jsp/jsp1.jsp"));
return mv;
}
@GetMapping("/redirect")
public ModelAndView redirect(HttpServletRequest request) {
ModelAndView mv = new ModelAndView();
// 使用RedirectView,必须写上context_path
mv.setView(new RedirectView(request.getContextPath() + "/public/jsp6.jsp"));
return mv;
}
}
自定义InternalResourceView
为什么要自定义InternalResourceView?
我们知道,SpringMVC内部会根据我们的viewName
去创建对应的View
对象。
我们也知道会创建哪三种View对象:
- InternalResourceView
- JstlView
- RedirectView
在applicationContext.xml中配置的InternalResourceViewResolver,其实还有一个属性,叫做viewClass,该属性的值就可以是:
org.springframework.web.servlet.view.InternalResourceView
org.springframework.web.servlet.view.JstlView
org.springframework.web.servlet.view.RedirectView
这三个View的父类都是AbstractUrlBasedView
:
在AbstractUrlBasedView
类中,我们可以找到一个方法checkResource
:
那么,这个方法checkResource
方法是用来干嘛的呢?
-
当SpringMVC创建View对象时,这个
checkResource
是用来告诉SpringMVC,viewName
是否存在的。 -
但是我们发现,这个方法始终返回的是
true
(它的三个子View也都没有覆盖该方法),也就是说,不管我们配置的viewName是否存在,它都会认为该viewName是存在的。 -
那么,也就解释了,为什么之前order属性不起作用了:因为你不管
viewName
是否存在,每次返回的都是true
,你每次都告诉SpringMVC,这个viewName
是存在的,那么SpringMVC肯定不会去其他优先级的InternalResourceViewResolver
中去寻找了。 -
为了解决这个问题,我们就需要自定义一个
InternalResourceView
了。
自定义InternalResourceView
MyView:
public class MyView extends InternalResourceView {
// 根据实际情况来返回
// 存在:返回true
// 不存在:返回false
@Override
public boolean checkResource(Locale locale) throws Exception {
// 拿到打包部署项目之后的真实路径
String path = getServletContext().getRealPath("/") + getUrl();
File file = new File(path);
return file.exists();
}
}
使用:
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<!-- 优先级最低的InternalResourceViewResolver可以不用加:
<property name="viewClass" value="programmer.lp.view.MyView"/>
-->
<property name="order" value="2"/>
<property name="prefix" value="/WEB-INF/page/html"/>
<property name="suffix" value=".html"/>
</bean>
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="viewClass" value="programmer.lp.view.MyView"/>
<property name="order" value="1"/>
<property name="prefix" value="/WEB-INF/page/jsp"/>
<property name="suffix" value=".jsp"/>
</bean>
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="viewClass" value="programmer.lp.view.MyView"/>
<property name="order" value="0"/>
<property name="prefix" value="/public"/>
<property name="suffix" value=".jsp"/>
</bean>
通过自定义的InternalResourceView
—MyView
,重写其checkResource
方法之后,将其设置给InternalResourceViewResolver
的viewClass
属性,就可以使order属性生效了:在优先级较高的InternalResourceViewResolver
中如果找不到某个viewName
的话,就去优先级较低的InternalResourceViewResolver
去寻找。
参考
小码哥-李明杰: Java从0到架构师③进阶互联网架构师.
本文完,感谢您的关注支持!