SpringBoot视图解析问题
controller代码如下:
@RequestMapping("/view/{page}")
public ModelAndView showPage(@PathVariable("page") String page){
ModelAndView modelAndView = new ModelAndView();
modelAndView.setViewName(page);
System.out.println("来了");
return modelAndView;
}
freemarker配置模板路径是/static/
问题是这样的:如果请求一个/static/下不存在视图名hahaha,比如/view/hahaha,就会出现Circular view path问题。
按理说FreemarkerViewResolver找不到该视图,也不会造成循环请求啊。
于是打断点,在DispatcherServlet的render方法里找到这段代码
view.render(mv.getModelInternal(),request, response);
一路跟着AbstractView.render() —> InternalResourceView.renderMergedOutputModel() --> prepareForRendering()
protected String prepareForRendering(HttpServletRequest request, HttpServletResponse response)
throws Exception {
String path = getUrl();
Assert.state(path != null, "'url' not set");
if (this.preventDispatchLoop) {
String uri = request.getRequestURI();
if (path.startsWith("/") ? uri.equals(path) : uri.equals(StringUtils.applyRelativePath(uri, path))) {
throw new ServletException("Circular view path [" + path + "]: would dispatch back " +
"to the current handler URL [" + uri + "] again. Check your ViewResolver setup! " +
"(Hint: This may be the result of an unspecified view, due to default view name generation.)");
}
}
return path;
}
发现Springmvc会把当前视图path(hahaha) 和当前请求的uri(/view/hahaha)做比较。
关键的在于,如果视图path没有以"/“开头,就会先把path与/view拼接变成/view/hahaha 与 uri /view/hahaha相比,相等就会判定Circular view path。
OK,视图路径加个”/"前缀解决
@RequestMapping("/view/{page}")
public ModelAndView showPage(@PathVariable("page") String page){
ModelAndView modelAndView = new ModelAndView();
modelAndView.setViewName("/"+page);
System.out.println("来了");
return modelAndView;
}
所以为什么要拼接成相对路径进行比对?
在DispatcherServlet的render方法中,进行渲染之前,SpringMvc先尝试使用ViewResolver解析视图。其中有个自带的基本ViewResolver——InternalResourceViewResolver,会默认把不带“/”的视图解析到相对路径下(默认优先级最低,前面几个Resolver解析失败才会使用这个)。
所以在判断是否需要抛Cirular view path异常时,根据相对路径判断是有必要的。