開發必備!Spring Boot 項目中 resources 文件讀取的九大方案詳解
在 Spring Boot 項目中,resources 目錄承載著大量的關鍵資源,如配置文件、模板文件、腳本資源、數據文件等。而如何以合適的方式高效、安全地讀取這些資源,往往是開發者繞不過的關鍵環節。
不同的資源加載方式有不同的適用場景和底層機制,如果使用不當,不僅可能導致資源讀取失敗,還可能影響程序的可移植性和擴展性。
本文將為你系統性地講解 Spring Boot 中讀取 resources 文件的 9 種主流方式,并在最后附上一套完整的控制器 Demo 示例,集中展示這些方式在實際項目中的統一實現,幫助你在開發中快速定位最適合的資源加載方案。
資源讀取的 9 大方式概覽
我們先逐一列出每種方式的核心思路與適用場景。
1、ClassLoader.getResourceAsStream() —— 通用類加載器讀取方式
說明:以類加載器為起點,查找資源路徑。
InputStream inputStream = getClass().getClassLoader().getResourceAsStream("config/sample.txt");
- 不依賴 Spring,適用于任意 Java 項目;
- 路徑從 classpath 根路徑開始,不需要加 /。
2、Class.getResourceAsStream() —— 相對于類路徑加載資源
說明:當前類對象的路徑定位方式,適合讀取與類位于同一包下的資源。
InputStream inputStream = getClass().getResourceAsStream("/config/sample.txt");
- 以 / 開頭則從根路徑定位;
- 相對路徑時以類的包路徑為基準。
3、使用 Spring 的 ResourceLoader
說明:借助 Spring 提供的通用資源加載抽象,可讀取 classpath、file、http 等協議資源。
@Resource
private ResourceLoader resourceLoader;
4、使用 ResourceUtils.getFile()
說明:用于將 classpath 路徑資源轉為 File 對象,適合需要文件路徑的場景。
File file = ResourceUtils.getFile("classpath:config/sample.txt");
5、使用 ApplicationContext.getResource()
說明:通過上下文注入加載資源,與 ResourceLoader 類似。
@Resource
private ApplicationContext context;
6、使用 ServletContext.getResourceAsStream()
說明:用于傳統 Servlet 模型,從 Web 路徑中獲取資源文件。
@Resource
private ServletContext servletContext;
7、使用 Java IO 的 File
說明:適用于讀取項目中的真實文件,路徑為實際操作系統路徑。
File file = new File("src/main/resources/config/sample.txt");
8、使用 Java NIO 的 Paths 和 Files
說明:使用 Java 8 的現代化文件操作接口,線程安全且效率更高。
Path path = Paths.get("src/main/resources/config/sample.txt");
9、使用 Spring 的 ClassPathResource
說明:Spring 原生支持 classpath 路徑加載,簡單快捷。
ClassPathResource resource = new ClassPathResource("config/sample.txt");
統一完整代碼實現示例
我們將在一個 Spring Boot 控制器中統一實現這 9 種方式,以 /resource/read/{method} 接口形式暴露,讓你一目了然。
文件路徑準備
請在 src/main/resources/config/sample.txt 文件中放置如下測試內容:
這是一個用于演示讀取 resources 文件的示例文本。
控制器實現:com.icoderoad.resources.controller.ResourceReadController.java
package com.icoderoad.resources.controller;
import jakarta.annotation.Resource;
import jakarta.servlet.ServletContext;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.core.io.ClassPathResource;
import org.springframework.core.io.ResourceLoader;
import org.springframework.stereotype.Controller;
import org.springframework.util.FileCopyUtils;
import org.springframework.util.ResourceUtils;
import org.springframework.web.bind.annotation.*;
import java.io.*;
import java.nio.file.*;
import java.util.HashMap;
import java.util.Map;
@RestController
@RequestMapping("/resource/read")
public class ResourceReadController {
@Autowired
private ResourceLoader resourceLoader;
@Autowired
private ApplicationContext applicationContext;
@Autowired
private ServletContext servletContext;
private final String filePath = "config/sample.txt";
@GetMapping("/{method}")
public Map<String, Object> readFile(@PathVariable String method) {
Map<String, Object> result = new HashMap<>();
try {
String content = switch (method) {
case "classloader" -> readByClassLoader();
case "class" -> readByClass();
case "loader" -> readByResourceLoader();
case "utils" -> readByResourceUtils();
case "context" -> readByApplicationContext();
case "servlet" -> readByServletContext();
case "file" -> readByFile();
case "nio" -> readByNio();
case "classpath" -> readByClassPathResource();
default -> "Unsupported method!";
};
result.put("method", method);
result.put("content", content);
} catch (Exception e) {
result.put("error", e.getMessage());
}
return result;
}
private String readByClassLoader() throws IOException {
try (InputStream in = getClass().getClassLoader().getResourceAsStream(filePath)) {
return streamToString(in);
}
}
private String readByClass() throws IOException {
try (InputStream in = getClass().getResourceAsStream("/" + filePath)) {
return streamToString(in);
}
}
private String readByResourceLoader() throws IOException {
org.springframework.core.io.Resource resource = resourceLoader.getResource("classpath:" + filePath);
try (InputStream in = resource.getInputStream()) {
return streamToString(in);
}
}
private String readByResourceUtils() throws IOException {
File file = ResourceUtils.getFile("classpath:" + filePath);
try (InputStream in = new FileInputStream(file)) {
return streamToString(in);
}
}
private String readByApplicationContext() throws IOException {
org.springframework.core.io.Resource resource = applicationContext.getResource("classpath:" + filePath);
try (InputStream in = resource.getInputStream()) {
return streamToString(in);
}
}
private String readByServletContext() throws IOException {
// 僅適用于傳統部署模式,如 war 包放入 Tomcat 時
try (InputStream in = servletContext.getResourceAsStream("/WEB-INF/classes/" + filePath)) {
return streamToString(in);
}
}
private String readByFile() throws IOException {
File file = new File("src/main/resources/" + filePath);
try (InputStream in = new FileInputStream(file)) {
return streamToString(in);
}
}
private String readByNio() throws IOException {
Path path = Paths.get("src/main/resources/" + filePath);
try (InputStream in = Files.newInputStream(path)) {
return streamToString(in);
}
}
private String readByClassPathResource() throws IOException {
ClassPathResource resource = new ClassPathResource(filePath);
try (InputStream in = resource.getInputStream()) {
return streamToString(in);
}
}
private String streamToString(InputStream in) throws IOException {
return new String(FileCopyUtils.copyToByteArray(in));
}
}
使用方式說明
請求路徑 | 對應加載方式 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
總結
在本文中,我們不僅系統講解了 Spring Boot 項目中讀取 resources 目錄下文件的 9 大方式,還構建了一個完整的統一控制器 Demo,集中展示它們在實際項目中的使用方式。你可以根據以下建議進行選擇:
- 推薦方式(通用性 + 簡潔性):
ClassLoader.getResourceAsStream()
ClassPathResource
ResourceLoader
- 特定場景方式(依賴文件路徑、Web環境):
- File / Paths / ServletContext
理解并熟練掌握這些方式,將極大提高你在 Spring Boot 項目中處理靜態資源的靈活性與穩定性,特別是在構建插件機制、配置中心、文件服務等系統中。