访问静态资源
参考文章:https://www.jianshu.com/p/d127c4f78bb8
参考文章已经写得很详细了,这里就不再赘述
使用velocity
参考文章:https://zhuanlan.zhihu.com/p/28251412
我遇到的问题和参考文章一样,springboot版本是高于1.5的,但是1.5以后由不支持vm,改成freemarker或者其他要重新学语法,比较麻烦。根据参考文章可以使用vm,我自己测试下来中间有点不一样,记录如下:
1、maven引用,不引用和主springboot一样的版本
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-velocity</artifactId>
<version>1.4.7.RELEASE</version>
</dependency>
2、/src/resources路径下创建一个velocityConfig.xml,配置如下
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd">
<bean id="mvcVelocityEngine" class="org.springframework.web.servlet.view.velocity.VelocityConfigurer">
<property name="resourceLoaderPath" value="/static/" /><!-- 模板存放的路径 -->
<!--原文有个加载配置文件的配置,我自己测下来没用-->
<property name="velocityProperties"><!--这个不加,加载出来的页面是乱码-->
<props>
<prop key="input.encoding">utf-8</prop>
<prop key="output.encoding">utf-8</prop>
</props>
</property>
</bean>
<bean id="viewResolver" class="org.springframework.web.servlet.view.velocity.VelocityViewResolver">
<property name="cache" value="false" />
<property name="prefix" value="/static/" /><!-- 视图文件的前缀,即存放的路径 -->
<property name="suffix" value=".vm" /><!-- 视图文件的后缀名 -->
<property name="dateToolAttribute" value="date" /><!--日期函数名称-->
<property name="numberToolAttribute" value="number" /><!--数字函数名称-->
<property name="contentType" value="text/html;charset=UTF-8" />
<property name="exposeSpringMacroHelpers" value="true" /><!--是否使用spring对宏定义的支持-->
<property name="exposeRequestAttributes" value="true" /><!--是否开放request属性-->
<property name="requestContextAttribute" value="rc"/><!--request属性引用名称-->
<!--<property name="toolboxConfigLocation" value="/WEB-INF/toolbox.xml"/>--><!--这个没用到,vm页面内自定义的函数也可以使用-->
</bean>
</beans>
在启动文件Application.java中引用xml
@ImportResource({"classpath:velocityConfig.xml"})
3、静态资源加载
我用的是继承WebMvcConfigurerAdapter,所以重写addResourceHandlers方法
registry.addResourceHandler("/**")
.addResourceLocations("classpath:/static/");
registry.addResourceHandler("/resources/**")
.addResourceLocations("classpath:/resources/");
vm文件放在/src/resources/static路径下
4、异常问题查询。
问题描述:访问localhost:9070,拦截器中有拦截,如果访问路径是/,会跳转首页。但是拦截器拦截到的始终是访问/error,返回的视图一直是errorHtml。日志也没有任何报错。
异常处理过程。
1)刚开始想着,既然报错了,那就搞个modelAndView,返回error界面好了。
@RequestMapping(value = { "/error"})
public ModelAndView error() {
return new ModelAndView("error");
}
结果报错了,说urlmapping的时候有冲突,重复定义了,出现了一个没见过的controller。BasicErrorController。看了下,这个应该是spring boot自带的异常处理的controller,以下写的是我自己的异常查找和处理过程,有兴趣的可以看下参考链接https://blog.youkuaiyun.com/lh87270202/article/details/79925951
2)源码异常跟踪
debug跟踪到以下地方,我没有配置无路径的mapping,本来是想在拦截器中,如果拦截到地址是/ 的,做登录首页跳转的,但是因为没有配置,spring boot表示404,找不到啊。所以在BasicErrorController中走到了errorHtml方法里。
@RequestMapping(value = { "/"})
public ModelAndView index() {
return new ModelAndView("index");
}
@RequestMapping(produces = "text/html")
public ModelAndView errorHtml(HttpServletRequest request,
HttpServletResponse response) {
HttpStatus status = getStatus(request);
Map<String, Object> model = Collections.unmodifiableMap(getErrorAttributes(
request, isIncludeStackTrace(request, MediaType.TEXT_HTML)));
response.setStatus(status.value());
ModelAndView modelAndView = resolveErrorView(request, response, status, model);
return (modelAndView == null ? new ModelAndView("error", model) : modelAndView);
}
debug可以发现status 是404,根据404去查找错误视图,但是我没有找到怎么配置this.errorViewResolvers,也可能是我没仔细找,后续找到了再补充。总之走了默认的错误视图查找。AbstractErrorController中代码如下
protected ModelAndView resolveErrorView(HttpServletRequest request,
HttpServletResponse response, HttpStatus status, Map<String, Object> model) {
for (ErrorViewResolver resolver : this.errorViewResolvers) {
ModelAndView modelAndView = resolver.resolveErrorView(request, status, model);
if (modelAndView != null) {
return modelAndView;
}
}
return null;
}
在默认错误视图查找,先拼接了页面的相对路径 error/404.html。然后在资源路径中查找视图,视图定死是html界面,所以我原先的vm界面要改成html界面。
DefaultErrorViewResolver中代码如下
private ModelAndView resolveResource(String viewName, Map<String, Object> model) {
for (String location : this.resourceProperties.getStaticLocations()) {
try {
Resource resource = this.applicationContext.getResource(location);
resource = resource.createRelative(viewName + ".html");
if (resource.exists()) {
return new ModelAndView(new HtmlResourceView(resource), model);
}
}
catch (Exception ex) {
}
}
return null;
}
其中this.resourceProperties.getStaticLocations()并不是我们在上文中配置的
registry.addResourceHandler("/**")
.addResourceLocations("classpath:/static/");
registry.addResourceHandler("/resources/**")
.addResourceLocations("classpath:/resources/");
而是默认的资源路径,所以只要将error界面放在某一个路径下就好了。
private static final String[] CLASSPATH_RESOURCE_LOCATIONS = {
"classpath:/META-INF/resources/", "classpath:/resources/",
"classpath:/static/", "classpath:/public/" }
5、升级jdk,升级springboot2.0.3(20180717更新)
升级jdk没什么问题,升级springboot就有问题了,1.5至少在
org.springframework:spring-webmvc:jar:4.3.14.RELEASE包里面还是有velocity的相关类,当时2.0之后,至少在2.0.3里面,org.springframework:spring-webmvc:jar:5.0.7.RELEASE,连velocity的相关类都没有了,所以前面的velocityConfig.xml文件是会报错的
最终解决方案是去4.3.14版本里面,把velocity的相关类copy出来到自己的项目中(org.springframework.web.servlet.view.velocity),然后修改xml文件。
但是呢,在启动的时候,会自动加载一个spring.vm,默认值是找不到的
private static final String SPRING_MACRO_LIBRARY = "org/springframework/web/servlet/view/velocity/spring.vm";
这个时候要修改VelocityConfigurer类,改成类路径private static final String SPRING_MACRO_LIBRARY = "static/spring.vm";
然后把spring.vm文件放到resources/static/路径下就完美了
本地启动ok,然后服务器启动又又又出错了,类版本冲突了
Factory method 'requestMappingHandlerAdapter' threw exception; nested exception is java.lang.NoClassDefFoundError: com/fasterxml/jackson/databind/exc/InvalidDefinitionException
又把org.springframework.ui.velocity这包下的类copy出来,然后修改VelocityConfigurer的继承关系
然后启动又又又又报错了,ByteArrayFeeder是jackson-core 2.9以后出现的,所以要把jackson-core升级一下
Factory method 'requestMappingHandlerAdapter' threw exception; nested exception is java.lang.NoClassDefFoundError: com/fasterxml/jackson/core/async/ByteArrayFeeder
另外使用springboot2,jdk要1.8以上,tomcat相关的包要升级到8.5以上,我的是8.5.31
项目不大呢最好还是vm给替换了吧,官方推荐是Thymeleaf