springboot-项目获取resources下文件碰到的问题(classPath下找不到文件和文件名乱码)

时间:2024-03-12 17:16:36

项目是spring-boot + spring-cloud 并使用maven 管理依赖。在springboot+maven项目下怎么读取resources下的文件实现文件下载?

  • 怎么获取resources目录下的文件?(相对路径)
方法一:

File sourceFile = ResourceUtils.getFile("classpath:templateFile/test.xlsx"); //这种方法在linux下无法工作
方法二:

Resource resource = new ClassPathResource("templateFile/test.xlsx"); File sourceFile = resource.getFile();

我使用的是第二种。
 1  @PostMapping("/downloadTemplateFile")
 2     public JSONData downloadTemplateFile(HttpServletResponse response) {
 3         String filePath = "templateFile/test.xlsx";
 4         Resource resource = new ClassPathResource(filePath);//用来读取resources下的文件
 5         InputStream is = null;
 6         BufferedInputStream bis = null;
 7         OutputStream os = null;
 8         try {
 9             File file = resource.getFile();
10             if (!file.exists()) {
11                 return new JSONData(false,"模板文件不存在");
12             }
13             is = new FileInputStream(file);
14             os = response.getOutputStream();
15             bis = new BufferedInputStream(is);
16             //设置响应头信息
17             response.setCharacterEncoding("UTF-8");
18             this.response.setContentType("application/octet-stream; charset=UTF-8");
19             StringBuffer contentDisposition = new StringBuffer("attachment; filename=\"");
20             String fileName = new String(file.getName().getBytes(), "utf-8");
21             contentDisposition.append(fileName).append("\"");
22             this.response.setHeader("Content-disposition", contentDisposition.toString());
23             //边读边写
24             byte[] buffer = new byte[500];
25             int i;
26             while ((i = bis.read(buffer)) != -1) {
27                 os.write(buffer, 0, i);
28             }
29             os.flush();
30         } catch (FileNotFoundException e) {
31             e.printStackTrace();
32             return new JSONData(false,"模板文件不存在");
33         } catch (IOException e) {
34             e.printStackTrace();
35         } finally {
36             try {
37                 if(os != null) os.close();
38                 if(bis != null) bis.close();
39                 if(is != null) is.close();
40             } catch (IOException e) {
41                 e.printStackTrace();
42             }
43         }
44         return new JSONData("模板文件下载成功");
45     }

高高兴兴的启动项目后发现还是找不到文件,错误日志:

 1 java.io.FileNotFoundException: class path resource [templateFile/test.xlsx] cannot be resolved to URL because it does not exist
 2     at org.springframework.core.io.ClassPathResource.getURL(ClassPathResource.java:195)
 3     at org.springframework.core.io.AbstractFileResolvingResource.getFile(AbstractFileResolvingResource.java:129)
 4     at com.citycloud.parking.support.controller.operate.OperateBusinessUserController.downloadTemplateFile(OperateBusinessUserController.java:215)
 5     at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
 6     at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
 7     at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
 8     at java.lang.reflect.Method.invoke(Method.java:498)
 9     at org.springframework.web.method.support.InvocableHandlerMethod.doInvoke(InvocableHandlerMethod.java:209)
10     at org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:136)
11     at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:102)
12     at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java:877)
13     at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:783)
14     at org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:87)
15     at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:991)
16     at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:925)
17     at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:974)
18     at org.springframework.web.servlet.FrameworkServlet.doPost(FrameworkServlet.java:877)
19     at javax.servlet.http.HttpServlet.service(HttpServlet.java:661)
20     at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:851)
21     at javax.servlet.http.HttpServlet.service(HttpServlet.java:742)
22     at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:231)
23     at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
24     at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:52)
25     at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
26     at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
27     at org.springframework.boot.actuate.metrics.web.servlet.WebMvcMetricsFilter.filterAndRecordMetrics(WebMvcMetricsFilter.java:158)
28     at org.springframework.boot.actuate.metrics.web.servlet.WebMvcMetricsFilter.filterAndRecordMetrics(WebMvcMetricsFilter.java:126)
29     at org.springframework.boot.actuate.metrics.web.servlet.WebMvcMetricsFilter.doFilterInternal(WebMvcMetricsFilter.java:111)
30     at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
31     at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)

 

因为我知道Resource resource = new ClassPathResource("templateFile/test.xlsx");就是到classPath*(注意这里有个*)下去找,然后就去项目本地的目录下找classPath下是否有这个文件(maven的classPath在 “target\classes”目录下),就发现并没有这个文件在。

后面仔细想想这是Maven项目啊,所以就找pom.xml文件去看看,突然想起:springboot的maven默认只会加载classPath同级目录下文件(配置那些),其他的需要配置<resources>标签:

 1 <build>
 2   <resources>
 3       <resource>
 4         <directory>src/main/java</directory>
 5         <includes>
 6           <include>**/*.properties</include>
 7           <include>**/*.xml</include>
 8         </includes>
 9         <!--是否替换资源中的属性-->
10         <filtering>false</filtering>
11       </resource>
12       <resource>
13         <directory>src/main/resources</directory>
14         <includes>
15           <include>**/*.properties</include>
16           <include>**/*.xml</include>
17           <include>**/*.yml</include>
18           <include>**/Dockerfile</include>
19           <include>**/*.xlsx</include>
20         </includes>
21         <!--是否替换资源中的属性-->
22         <filtering>false</filtering>
23       </resource>
24   </resources>
25 </build>

 

重新启动,再到classPath下看,发现有了这个文件了,同时也能获取了。如果文件名为中文的话就会出现乱码的情况。

 

  • 怎么解决文件名中文乱码?

 

1 Access-Control-Allow-Origin →*
2 Access-Control-Allow-Credentials →true
3 Access-Control-Allow-Headers →accessToken,Access-Control-Allow-Origin,Content-Type,X-Requested-With,accept,Origin,Access-Control-Request-Method,Access-Control-Request-Headers
4 Access-Control-Allow-Methods →POST,GET,PUT,PATCH,DELETE,OPTIONS,HEAD
5 Access-Control-Max-Age →360
6 Content-disposition →attachment; filename="????????-??????????.xlsx"
7 Content-Type →application/octet-stream;charset=UTF-8
8 Transfer-Encoding →chunked
9 Date →Fri, 19 Apr 2019 06:47:34 GMT

上面是使用postman测试中文乱码response响应头相关信息。

后面怎么改都乱码,然后我就试着到浏览器中请求试试,结果发现只是postman的原因,只要文件名编码跟返回内容编码一致("Content-disposition"和“ContentType”)就行:

 

1 this.response.setContentType("application/octet-stream; charset=iso-8859-1");
2 StringBuffer contentDisposition = new StringBuffer("attachment; filename=\"");
3 String fileName = file.getName();
4 contentDisposition.append(fileName).append("\"");
5 //设置文件名编码
6 String contentDispositionStr = new String(contentDisposition.toString().getBytes(), "iso-8859-1");
7 this.response.setHeader("Content-disposition", contentDispositionStr);

 

 

 

到此全部结束!