springboot使用velocity以及访问j静态资源

访问静态资源
参考文章: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.csdn.net/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

猜你喜欢

转载自blog.csdn.net/zzp448561636/article/details/81002080