项目介绍
项目不是前后端分离,使用的springmvc架构。
其中配置类如下,我们同时配置jsp和freeMarker两种静态页面
@Configuration
@EnableWebMvc
public class AppConfig implements WebMvcConfigurer {
@Bean
public FreeMarkerConfigurer freeMarkerConfigurer() {
FreeMarkerConfigurer freeMarkerConfigurer = new FreeMarkerConfigurer();
freeMarkerConfigurer.setTemplateLoaderPath("classpath:/ftl/");
freeMarkerConfigurer.setDefaultEncoding("UTF-8");
freeMarkerConfigurer.setConfigLocation(applicationContext.getResource("classpath:ftl/ftl.properties"));
return freeMarkerConfigurer;
}
@Override
public void configureViewResolvers(ViewResolverRegistry registry) {
registry.enableContentNegotiation(new MappingJackson2JsonView());
//在代码顺序上,jsp设置得比freeMarker早。
registry.jsp("/jsp/", ".jsp");
registry.freeMarker();
}
}
对应的资源页面如下
控制层如下
@Controller
@RequestMapping("/user")
public class UserController {
@RequestMapping("/ok")
public String ok() {
return "ok";
}
@RequestMapping("/user")
public String user() {
return "user";
}
}
问题场景
访问http://localhost:8080/user/ok,页面跳转正常
访问http://localhost:8080/user/user,页面跳转报错
发现居然要跳转到/jsp/user.jsp
问题分析
在具体分析之前,先提前说明几点。
通过registry.enableContentNegotiation(new MappingJackson2JsonView());
启用了ContentNegotiatingViewResolver
类。
此外,jsp页面对应的InternalResourceResolver
类不会对"页面是否存在"做校验;而freeMarker对应的FreeMarkerViewResolver
会对"页面是否存在"做校验。
- 访问jsp页面
当访问http://localhost:8080/user/ok时,进入ContentNegotiatingViewResolver
类的如下方法
此时candidateViews
中获取的只有jsp对应的InternalResourceView
对象(另外一个是mvc默认加的不用管), FreeMarkerViewResolver
对象会判断页面不存在,所以不会返回FreeMarkerView
。
而经过getBestView
方法筛选后,bestView
也是InternalResourceView
,所以访问没问题。
- 访问freemarker页面
当访问http://localhost:8080/user/user时,进入ContentNegotiatingViewResolver
类
此时candidateViews
中有freeMarker对应的FreeMarkerView
对象,
由于InternalResourceResolver
类不会对"页面是否存在"做校验,所以还会返回InternalResourceView
对象。
而经过getBestView
方法筛选后,bestView
中是InternalResourceView
对象了,而此时根本没有/jsp/user.jsp页面,所以报错。
问题解决
调换jsp和freeMarker设置的顺序
@Override
public void configureViewResolvers(ViewResolverRegistry registry) {
registry.enableContentNegotiation(new MappingJackson2JsonView());
registry.freeMarker();
registry.jsp("/jsp/", ".jsp");
}
这样的话,当访问http://localhost:8080/user/user时,bestView
中就是FreeMarkerView
对象了。