SpringBoot中静态资源访问

本文详细介绍了SpringBoot中静态资源的存放路径、访问方式、源码解析、自定义配置以及解决无法立即访问的问题。重点讲述了如何通过配置`addResourceHandlers`方法来指定静态资源路径,并讨论了SpringBoot的自动配置如何处理静态资源。同时,文章还提出了当添加静态资源后无法立即访问的解决方案,即使用文件系统的绝对路径避免重新编译。
摘要由CSDN通过智能技术生成


1 静态资源到存放路径

实例:
在这里插入图片描述
那么这是如何进行通过链接进行访问,下面是资源配置方法,进行路径拦截之后找到对应的文件路径

package com.ruoyi.framework.config;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.cors.CorsConfiguration;
import org.springframework.web.cors.UrlBasedCorsConfigurationSource;
import org.springframework.web.filter.CorsFilter;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
import com.ruoyi.common.config.RuoYiConfig;
import com.ruoyi.common.constant.Constants;
import com.ruoyi.framework.interceptor.RepeatSubmitInterceptor;

/**
 * 通用配置
 * 
 * @author ruoyi
 */
@Configuration
public class ResourcesConfig implements WebMvcConfigurer
{
    @Autowired
    private RepeatSubmitInterceptor repeatSubmitInterceptor;

    @Override
    public void addResourceHandlers(ResourceHandlerRegistry registry)
    {
        /** 本地文件上传路径 */
        registry.addResourceHandler(Constants.RESOURCE_PREFIX + "/**").addResourceLocations("file:" + RuoYiConfig.getProfile() + "/");

        /** swagger配置 */
        registry.addResourceHandler("swagger-ui.html").addResourceLocations("classpath:/META-INF/resources/");
        registry.addResourceHandler("/webjars/**").addResourceLocations("classpath:/METAINF/resources/webjars/");
        //当时写的好像是上传的路径然后进行访问
        registry.addResourceHandler("/police" + "/**").addResourceLocations("file:" + System.getProperty("user.home")+"/police/fileInfo/");
        registry.addResourceHandler( "/static"+"/**").addResourceLocations("classpath:/static/");
    }

    /**
     * 自定义拦截规则
     */
    @Override
    public void addInterceptors(InterceptorRegistry registry)
    {
        registry.addInterceptor(repeatSubmitInterceptor).addPathPatterns("/**");
    }

    /**
     * 跨域配置
     */
    @Bean
    public CorsFilter corsFilter()
    {
        UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
        CorsConfiguration config = new CorsConfiguration();
        config.setAllowCredentials(true);
        // 设置访问源地址
        config.addAllowedOrigin("*");
        // 设置访问源请求头
        config.addAllowedHeader("*");
        // 设置访问源请求方法
        config.addAllowedMethod("*");
        // 对接口配置跨域设置
        source.registerCorsConfiguration("/**", config);
        return new CorsFilter(source);
    }
}

访问本地文件

    @Override
    public void addResourceHandlers(ResourceHandlerRegistry registry)
    {
        registry.addResourceHandler("/pdf" + "/**").addResourceLocations("file:" + System.getProperty("user.home")+"/lcls/fileInfo/");
    }

C:\Users\Administrator\lcls\fileInfo

在这里插入图片描述
在这里插入图片描述

上面的例子应该可以快速的进行修改,下面进行原理讲解当使用SpringMVC框架访问静态资源时,静态资源会被拦截,需要添加额外配置。搭建SSM环境时,可以通过<mvc:resources />节点来配置不拦截静态资源,代码如下:

<mvc:resources mapping="/js/**" location="/js/"/>
<mvc:resources mapping="/css/**" location="/css/"/>
<mvc:resources mapping="/html/**" location="/html/"/>

这是一种Ant风格的路径匹配符,/**表示可以匹配任意层级的路径,所以上面的代码可以简化为:

<mvc:resources mapping="/**" location="/"/>

上面这种配置是通过xml文件实现的,而且通俗易懂,其实在Java中也可以通过Java代码实现,如果通过Java代码实现,可以自定义一个类,并且让其集成WebMvcConfigurationSupport即可,代码如下:

@Configuration
@ComponentScan(basePackages = "com.mango.javassm")
public class SpringMVCConfig extends WebMvcConfigurationSupport {
    @Override
    protected void addResourceHandlers(ResourceHandlerRegistry registry) {
        registry.addResourceHandler("/**").addResourceLocations("/");
    }
}

上面代码中,其实就是重写了WebMvcConfigurationSupport中的addResourceHandlers方法,并且在该方法中配置静态资源访问路径。上面两种配置方式实现的效果是一样的。

上面介绍的两种方式都是传统的解决方案,在SpringBoot中,配置方式和SSM相同,不同的是SpringBoot是自动化配置。正是这些自动化配置能大大的节省开发人员的代码,自然而然也就降低了出错率。(写的越多,bug越多)

通配符说明
?匹配任意一个字符
*匹配任意字符(包括0个)
**匹配任意层路径(包括0个)

常见Ant风格场景:

  1. Spring资源加载:classpath:/static/
  2. SpringMVC的URL映射:@GetMapping("/hello")
  3. Spring注解扫描:<mvc:resources mapping="/**" location="/"/>

SpringBoot中的配置

创建SpringBoot项目时,通常都是在https://start.spring.io/网站进行创建的,其实通过IDEA来创建也是访问这个网站,创建后项目中默认都会存在resources/static目录,大家也都知道静态资源放到这个目录下,就可以直接进行访问了。除了这个目录还有没有其他目录可以放呢?为什么放在这个目录下就可以直接进行访问了呢?接下来就围绕这个问题进行挖掘。

2 如何访问静态资源

在SpringBoot中,默认情况下,共有5个地方可以放静态资源,分别是:

  1. classpath:/META-INF/resources/
  2. classpath:/resources/
  3. classpath:/static/
  4. classpath:/public/
  5. /

其实前面的四个目录都容易理解,分别是对应resources下不同的目录,但是第5个中的/是啥呢?

我们都知道,在 Spring Boot 项目中,默认是没有 webapp这个目录的,当然我们也可以自己手动进行添加(例如在需要使用jsp的时候),这里第5个/ 其实就是表示 webapp目录中的静态资源也不被拦截。如果同一个文件分别出现在五个目录下,那么优先级也是按照上面列出的顺序来进行访问的。

虽然默认情况下提供了5个访问目录,但第5个目录很少会使用到。由于创建项目时,默认给我们创建了classpath:/static/,一般情况下,我们只需要把我们的静态资源放到该目录下即可,不需要额外创建目录,例如:我在classpath:/static/目录下放了一个hello.js文件,那么访问该js文件的路径是:

http://localhost:8080/hello.js

值得注意的是,请求地址中并不需要 static,如果加上了static反而多此一举会报404错误。很多人会觉得奇怪,为什么不需要添加 static呢?资源明明放在 static 目录下。其实这个效果很好实现,例如:在SSM配置中,我们的静态资源拦截配置如果是下面这样:

<mvc:resources mapping="/**" location="/static/"/>

如果是这样配置的话,我们的请求路径是http://localhost:8080/hello.js,实际上系统会去 /static/hello.js下去查找相关的静态资源。

回到SpringBoot中,既然它的原理和SSM相同,所以这里就不难理解了。

3 源码解读

学习新的东西,最准确的方式莫过于阅读源码了,下面我们通过源码来看看SpringBoot中静态资源是如何配置的。

首先,我们在WebMvcAutoConfiguration类中看到SpringMVC自动化配置的相关内容,找到了静态资源拦截的配置,如下:
在这里插入图片描述

其实从上面这段标出的内容可以看出,这里对静态资源的定义和前面提到的Java配置SSM非常相似。其中,this.mvcProperties.getStaticPathPattern()方法对应的值就是"/**"this.resourceProperties.getStaticLocations()方法返回了一个String[]数组,其中包含了共4个位置,它们分别是:"classpath:/META-INF/resources/""classpath:/resources/""classpath:/static/""classpath:/public/",然后在getResourceLocations方法中的SERVLET_LOCATIONS又添加了"/",因此这里一共返回了5个位置,其中"/"表示webapp目录,即webapp目录下的静态资源也可直接访问。静态资源匹配路径按照定义路径优先级依次降低,前面4个不难理解,至于为什么"/"排在最后,我想大家仔细看下源码就能明白。

如此看来,大家应该明白了为什么SpringBoot中默认支持5个静态资源位置的配置了,同时也明白了为什么访问静态资源的请求路径中不用添加/static了,因为路径映射中已经自动添加了。

4 自定义配置

这里给提供两种方式,一种是通过配置文件实现,另一种是通过Java类来实现,不管是哪种,实现的效果都是相同的。

【application.properties】

spring.resources.static-locations=classpath:/mango
spring.mvc.static-path-pattern=/**

注:上面classpath:/mango中的mango是我在resources下创建的一个目录。

【Java类】

当然,在SpringBoot中也可以通过Java代码来定义,和用Java来配置SSM方式比较类似,如下:

@Configuration
public class WebMvcConfig implements WebMvcConfigurer {

    @Override
    public void addResourceHandlers(ResourceHandlerRegistry registry) {
        registry.addResourceHandler("/**").addResourceLocations("classpath:/mango/");
    }
}

这段代码比较简单,之前也讲过,这里就不再啰嗦了。

5 总结

这里需要注意的是,很多人用了 Thymeleaf 模板引擎之后,会将静态资源也放在 resources/templates 目录下,注意,templates 目录并不是静态资源目录,它是一个放页面模板的位置(你看到的 Thymeleaf 模板虽然后缀为 .html,其实并不是静态资源)。

6 springboot 静态资源无法访问

在一个项目中WebMvcConfigurationSupport只能存在一个,多个的时候,只有一个会生效。(按名称排序后第一个的)

1.SpringBoot 的 @EnableAutoConfiguration 会启用自动配置类

2.WebMvcAutoConfiguration,该类配置了一些默认的静态资源映射

  • 自动映射 localhost:8080/** 为以下路径

    classpath:/resources/
    classpath:/static/
    classpath:/public/
    classpath:/META-INF/resources/
    
    1. 自动映射 localhost:8080/webjars/** 为以下路径
      classpath:/META-INF/resources/webjars/

此时,我们不需要多做什么,只要将静态资源放入 src/main/resources 目录下的 resources、static 或 public 文件夹下,即可通过 url 定位相关资源,例如 localhost:8080/index.html 可定位至 src/main/resources/static/index.html

但是!
一旦使用继承了WebMvcConfigurationSupport或者WebMvcConfigurerAdapter的自定义配置类,即使没有重写addResourceHandlers方法,默认配置都会被不被采用。如果要采用原本默认的配置,则需要webmvc配置类中重写如下方法:

@Configuration
public class GoWebMvcConfigurerAdapter extends WebMvcConfigurerAdapter {

    @Override
    public void addResourceHandlers(ResourceHandlerRegistry registry) {
        //配置静态资源处理
        registry.addResourceHandler("/**")
                .addResourceLocations("resources/", "static/", "public/", 
                "META-INF/resources/")
                .addResourceLocations("classpath:resources/", "classpath:static/", 
                "classpath:public/", "classpath:META-INF/resources/")
                .addResourceLocations("file:///tmp/webapps/");
    }
}

经过试验得证:如果不使用WebMvcConfigurationSupport,则使用application.properties中的默认配置
如果重写了application.properties中的配置,则使用重写后的配置,如:

spring.resources.static-locations=resources/, static/, public/, \ META-INF/resources/, resources/, classpath:static/, public/, classpath:META-INF/resources/, \file:///tmp/webapps/

spring.mvc.static-path-pattern=/**

一旦使用了WebMvcConfigurationSupport(或WebMvcConfigurerAdapter)那么必须要重写addResourceHandlers来配置资源映射,此时application.properties中关于静态资源访问的配置将失效(除非对url写了响应的controller来处理,那是另一回事)

7 当添加了静态资源后,无法立即访问的问题

如果访问项目中的静态资源,访问的所有的东西其实都是target目录中的,这是经过编译的,如果对项目目录下的静态资源进行修改(增删改),由于target下的东西没有受影响,所以没法立即生效,比如往/resouces/static下增加一张图片,通过url无法立即访问到,必须重启项目。其实重启就是让资源文件经过编译(其实资源文件根本不编译)后,加到target中,那么这样就很麻烦,要是想对一个静态资源修改后能立即通过url访问到要如何做呢?
解决办法将静态资源放在非项目类路径下即可,例如 “file:///Users/mytest/inspector/independent_resources/“);,并且在资源处理器中加上路径即可。
file:// 后面跟的必须是文件系统的绝对路径

registry.addResourceHandler("/**”)
//**********/
        .addResourceLocations("resources/", "static/", "public/",
                "META-INF/resources/")
        .addResourceLocations("classpath:resources/", "classpath:static/",
                "classpath:public/", "classpath:META-INF/resources/")
//**********/
        //如果要让添加的静态资源立即生效,则不能把它放到项目资源里面,应该放在外面,比如下面的目录
        //这样一旦静态资源添加到这个目录,则直接从该位置获取,而不是从编译的target位置获取
        .addResourceLocations("file:///Users/mytest/inspector/independent_resources/");

/**********之间的是项目类的路径,不用管,最下面的是非项目类的路径
这样的话,在项目运行时,往/Users/mytest/inspector/independent_resources/目录下添加一个111.png后,在浏览器中通过localhost:8080/111.png就可访问到这个图片了。
如果不添加这个,在项目运行时,往项目的src/main/resources 下添加一个111.png后,不能立即通过浏览器访问到这个图片,因为项目类的所有资源和文件必须编译为target版本后才对外服务,而添加资源后不重启项目无法重新编译,target中的东西没有更新。

因此,需要修改后立即生效的文件,尤其是非代码文件(除去html,css这种)最好是放在项目类的外部,放在文件系统的绝对路径下。如果文件必须放在项目中,但又必须得立即生效,
那么对项目中的同一个资源目录,即添加其相对路径,又添加其绝对路径:

如果文件必须放在项目中,但又必须得立即生效,那么用下面的方法:
对项目中的同一个资源目录,即添加其相对路径,又添加其绝对路径:

registry.addResourceHandler("/**")
        .addResourceLocations("classpath:static/")
 .addResourceLocations("file:///Users/mytest/inspector/src/main/resources/static/");

上面两个路径其实是同一个,但通过上面相对路径访问的是target中的东西。在运行时添加一个文件后,target没有更新,通过相对路径就访问不到,但实际上文件系统是更新了,所以用下面的绝对路径直接访问文件系统中的文件就可。

  • 2
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 3
    评论
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

赵广陆

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值