SpringBoot访问静态文件的几种方法

目的

​ 将图片存储在f:\\test文件夹或其子文件夹下,实现访问http://localhost/static/1.jpg网页上展示图片,访问http://localhost/download/1.jpg浏览器下载图片。

方法1

​ 请参考这篇文章的实现, springboot 添加defaultServlet实现更好的文件下载功能,原理是配置一个DefaultServlet来处理所有静态资源请求。

方法2

​ 原理使用Controller拦截掉静态资源的请求,转发到DefaultServlet

​ 配置Controller如下,使用RequestMapping分开配置,处理下载的/download/** 和处理展示的 /static/** 分开。

​ 他们俩的唯一区别是,/download/** 手动设置了响应头,在此设置的content-type,后面就不会被设置了,否则会根据资源类型自适应content-type

​ 调用ServletContextDispatcher做转发。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
@RestController
public class ResourceController implements ServletContextAware {

//拦截资源,设置响应头application/octet-stream,浏览器表现为下载
@RequestMapping("/download/**")
public void download(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
resp.setContentType("application/octet-stream");
RequestDispatcher rd = req.getServletContext().getNamedDispatcher("default");
rd.forward(req, resp);
}

//拦截static/**,不覆盖响应头,根据类型自适应响应头
@RequestMapping("/static/**")
public void staticSource(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
RequestDispatcher rd = req.getServletContext().getNamedDispatcher("default");
rd.forward(req, resp);
}

//继承ServletContextAware,此方法内配置
//文件根目录,需要删除的虚拟路径
@Override
public void setServletContext(ServletContext servletContext) {
WebResourceRoot attribute = (WebResourceRoot) servletContext.getAttribute(Globals.RESOURCES_ATTR);
String basePath = "F:\\test";


//假设请求连接是 http://localhost/static/abc/123.jpg
//则实际查找路径是 F:\\test/abc/123.jpg
//相当于拿path 减去 下面的第二个参数,再拼接在basePath后面
attribute.addPreResources(new DirResourceSet(attribute, "/static", basePath, "/"));
attribute.addPreResources(new DirResourceSet(attribute, "/download", basePath, "/"));
}
}

​ 上面的做法是在Controller里面拦截请求,再请求转发到DefaultServlet上,这样就不用配置DefaultServletServletMapper了,使用SpringMvc来管理路径问题。

​ 这种方法默认defaultServlet被配置(Tomcat环境下是会被配置的)。

方法3

​ 本方法使用Spring的实现,即使底层用的不是TomcatSpring也能将这种差异屏蔽。

SpringBoot默认会按顺序扫描以下目录的静态资源文件,这是SpringBoot默认配置的,默认拦截路径是/**

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

​ 写一个类继承WebMvcConfigurationSupport,实现addResourceHandlers方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
@Configuration
public class WebConfig extends WebMvcConfigurationSupport {

@Override
protected void addResourceHandlers(ResourceHandlerRegistry registry) {
//文件写法
registry.addResourceHandler("/static/**", "/download/**")
.addResourceLocations("file:F:/test/");
//classpath 写法
registry.addResourceHandler("/classpath/**")
.addResourceLocations("classpath:/static/", "classpath:/META-INF/resources/");

}
}

要注意的点:

  • 资源在外部文件夹下的路径写法要以file:开头,以/结尾,如file:D:/test/

  • 访问classpath的资源,路径要以classpath:/开头,以/结尾,如classpath:/static/

  • 访问第三方jar内部的静态文件,配置是classpath:/META-INF/resources/

  • 像下面这样配置两个相同的路径,则后面覆盖前面的。

    • registry.addResourceHandler("/classpath/**").addResourceLocations("file:D:/test")
                                                                       registry.addResourceHandler("/classpath/**").addResourceLocations("file:E:/zz")
      
      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      20
      21
      22
      23
      24
      25

      - **切记不要配置成`classpath:/`,这会导致`resources`文件夹暴露出来,导致配置文件泄露**



      ​ 但是这种方法并不能实现文件下载,能识别出`content-type`的如图片会自动打开在浏览器上,不能识别的资源才会调用浏览器下载。



      # 关于自动配置

      - 自动配置

      ​ 一旦继承了`WebMvcConfigurationSupport`类,即使不重写`addResourceHandlers`类,自动配置的5个路径就失效了。所以就不能访问静态文件了。



      - `swagger-ui`的静态资源

      ​ 在使用`swagger-ui`时,它的原理是将`swagger-ui.html`页面打包到`springfox.swagger-ui`里面了。

      要想访问这个页面需要配置下面的路径来处理。

      ```java
      registry.addResourceHandler("/**").addResourceLocations("classpath:/META-INF/resources/");
  • 方法3搭配方法2

    举个例子:

    ​ 1. 将/static路径进行映射。

    1
    registry.addResourceHandler("/static/**").addResourceLocations("classpath:/static/");

    ​ 2. 将参数中的文件名重新forward,这样也能实现根据参数提供静态文件名。

    1
    2
    3
    4
    @GetMapping("file")
    public void test(HttpServletRequest res, HttpServletResponse resp, String fileName) throws ServletException, IOException {
    res.getServletContext().getRequestDispatcher("/static/"+fileName).forward(res, resp);
    }

SpringBoot访问静态文件的几种方法
https://www.huangchaoyu.com/3775026240.html
作者
hcy
发布于
2020年4月10日
更新于
2024年8月17日
许可协议