SpringBoot實(shí)現(xiàn)本地上傳文件到resources目錄
需求背景:Java后端項(xiàng)目上傳文件是一個(gè)很常見(jiàn)的需求,一般正式項(xiàng)目中我們上傳文件都是利用第三方阿里云OSS這類的,但是如果只是為了學(xué)習(xí)之用,那我們可能就會(huì)直接上傳到電腦上某個(gè)本地文件夾。
但是上傳到自己電腦上某個(gè)文件夾,那換一臺(tái)電腦就看不到了,還有一般文件上傳之后我們還需要返回給前端文件的下載路徑,如果是電腦上隨便某個(gè)文件夾,那前端很可能是訪問(wèn)不到的。
為了解決前端訪問(wèn)這個(gè)問(wèn)題,我們可以把文件上傳到后端服務(wù)的靜態(tài)資源目錄里,這樣前端就可以直接通過(guò)后端服務(wù)的地址和端口加上資源路徑來(lái)訪問(wèn)了。
實(shí)現(xiàn)思路
上傳文件的路徑我們可以用 ResourceUtils.getURL("classpath:").getPath() 這個(gè)方法來(lái)獲取,拿到的就是編譯后的 target/classes 目錄的絕對(duì)路徑,前端上傳的文件就可以直接存到這個(gè)下面的目錄,比如:target/classes/upload/logo.jpg,給前端返回的下載地址就像這樣的:http://localhost:8080/upload/logo.jpg
。
上面的思路確實(shí)解決了上傳和下載的問(wèn)題,但是 target 目錄是會(huì)變動(dòng)的,而且不會(huì)提交到代碼倉(cāng)庫(kù),如果我們清理后再重新編譯或者換臺(tái)電腦編譯,之前上傳的文件就都沒(méi)了。
這可怎么辦呢?仔細(xì)一想我們項(xiàng)目不是有一個(gè)叫 resources 用來(lái)存放靜態(tài)資源的目錄嗎,這個(gè)目錄正常也會(huì)提交到代碼倉(cāng)庫(kù)進(jìn)行管理的,那我們每次上傳的文件不就可以一塊提交到倉(cāng)庫(kù)里,這部就實(shí)現(xiàn)了永久保存。
說(shuō)干就干,就直接將文件保存到 resources/upload 目錄下,后端一run前端一上傳,文件確實(shí)被保存到了 resources/upload 目錄下。再仔細(xì)一看不對(duì),前端的地址沒(méi)發(fā)訪問(wèn)剛上傳的文件,因?yàn)?target/classes 目錄下壓根沒(méi)有剛上傳的文件,重新點(diǎn)一次 compile 編譯后將 resources 目錄下的文件同步到了 target/classes 目錄下確實(shí)可以實(shí)現(xiàn)訪問(wèn),但是總不能我們每次上傳后都要自己重新點(diǎn)一下編譯重新運(yùn)行吧。
最后一合計(jì),那我把resources和target結(jié)合一下,將文件同時(shí)保存到這兩個(gè)目錄下,是不是就可以實(shí)現(xiàn)永久保存和實(shí)時(shí)訪問(wèn)了呢。
終極方案
用System.getProperty("user.dir")可以獲取到項(xiàng)目的工作目錄,再拼上項(xiàng)目的結(jié)構(gòu)目錄就可以拿到 resources 目錄的絕對(duì)路徑;target/classes 運(yùn)行目錄可以用 ResourceUtils.getURL("classpath:").getPath() 獲取。
注意如果最后上傳的資源目錄訪問(wèn)404,要看下 application.yml 里 spring.mvn 的靜態(tài)資源路徑,pom.xml里的 resources過(guò)濾規(guī)則,還有 WebMvcConfiguration 里配置的 addResourceHandler 靜態(tài)資源攔映射有沒(méi)有攔截掉。
最后前端傳過(guò)來(lái)的是一個(gè) File 文件,但是一個(gè)文件其實(shí)是沒(méi)辦法循環(huán)去保存到多個(gè)目錄下的,第一個(gè)文件夾保存成功后后面的都會(huì)報(bào)錯(cuò),想一下我們平時(shí)在電腦上保存一個(gè)文件也只能保存到一個(gè)目錄下,再要保存到其他目錄則自己復(fù)制一份過(guò)去就好了,這里也是一樣第一個(gè)目錄我們直接保存,第二個(gè)則可以用 spring 提供的 FileCopyUtils.copy 直接復(fù)制文件就可以了。
完整代碼
UploadFileUtil.java
package com.sky.utils; import java.io.File; import java.io.FileNotFoundException; import java.io.IOException; import java.util.ArrayList; import java.util.List; import java.util.UUID; import org.springframework.util.FileCopyUtils; import org.springframework.util.ResourceUtils; import org.springframework.web.multipart.MultipartFile; public class UploadFileUtil { /** * 獲取文件保存路徑 * * @return File * @throws FileNotFoundException */ static List<File> getUploadDirectory() throws FileNotFoundException { // 開(kāi)發(fā)環(huán)境獲取 target/classes 目錄:清理重新編譯后就沒(méi)有了 File targetPath = new File(ResourceUtils.getURL("classpath:").getPath()); // System.out.printf("項(xiàng)目運(yùn)行的絕對(duì)路徑:" + path.getAbsolutePath()); // 輸出 xx/sky-parent/sky-server/target/classes // 生產(chǎn)環(huán)境 不存在 target/classes 目錄 if (!targetPath.exists()) { // 獲取當(dāng)前運(yùn)行目錄 targetPath = new File(""); } // 開(kāi)發(fā)環(huán)境 resources 目錄:可永久保存 String resourcesPath = System.getProperty("user.dir") + "/sky-server/src/main/resources"; // System.out.printf("resources目錄路徑:" + resourcesPath); File path = new File(resourcesPath); File upload = new File(path.getAbsolutePath(), "upload"); File uploadTarget = new File(targetPath.getAbsolutePath(), "upload"); // 不存在則創(chuàng)建 if (!upload.exists()) { upload.mkdirs(); } if (!uploadTarget.exists()) { uploadTarget.mkdirs(); } List<File> files = new ArrayList<File>(); files.add(upload); files.add(uploadTarget); // System.out.printf("當(dāng)前目錄:" + files); return files; } public static String upload(MultipartFile myFile, String dir) throws IOException { String filePath = ""; if (!myFile.isEmpty()) { try { String filename = myFile.getOriginalFilename(); filename = UUID.randomUUID() + filename.substring(filename.lastIndexOf(".")); // 之所以保存到 resources 和 target 兩個(gè)目錄,兼顧開(kāi)發(fā)測(cè)試和永久保存 // 只保存到resources目錄下每次上傳了要重新編譯下,target則清理打包后就沒(méi)有了 List<File> files = getUploadDirectory(); // 注意這里一個(gè)文件不能循環(huán)同時(shí)寫入多個(gè)目錄,保存了第一個(gè),第二個(gè)要復(fù)制過(guò)去 File curFile = new File(files.get(0), filename); myFile.transferTo(curFile); FileCopyUtils.copy(curFile, new File(files.get(1), filename)); //for (File f: files) { //File curFile = new File(f, filename); //myFile.transferTo(curFile); //} filePath = "http://localhost:8080/upload/" + filename; } catch (Exception e) { e.printStackTrace(); } } return filePath; } }
application.yml
server: port: 8080 spring: mvc: static-path-pattern: /upload/**
WebMvcConfiguration
package com.sky.config; import org.springframework.context.annotation.Configuration; import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry; import org.springframework.web.servlet.config.annotation.WebMvcConfigurationSupport; import java.util.List; /** * 配置類,注冊(cè)web層相關(guān)組件 */ @Configuration public class WebMvcConfiguration extends WebMvcConfigurationSupport { /** * 設(shè)置靜態(tài)資源映射 * @param registry */ protected void addResourceHandlers(ResourceHandlerRegistry registry) { // 設(shè)置上傳的文件靜態(tài)資源映射,application 里的 mvc 里也要設(shè)置下靜態(tài)目錄 registry.addResourceHandler("/upload/**") .addResourceLocations("classpath:/upload/", "file:upload/"); } }
使用示例
在 controller 接收前端用表單上傳的 File 文件
package com.sky.controller.common; import com.sky.result.Result; import com.sky.utils.UploadFileUtil; import io.swagger.annotations.Api; import io.swagger.annotations.ApiOperation; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; import org.springframework.web.multipart.MultipartFile; import java.io.IOException; /** * 公共請(qǐng)求 */ @RestController @RequestMapping("/common") @Api(tags = "公共") @Slf4j public class CommonController { @PostMapping("/upload") @ApiOperation("上傳文件") public Result uploadFile(MultipartFile file) throws IOException { log.info("上傳文件:{}", file); String fileUrl = UploadFileUtil.upload(file, ""); if (fileUrl == null || fileUrl == "") { return Result.error("上傳失敗"); } return Result.success(fileUrl); } }
到此這篇關(guān)于SpringBoot實(shí)現(xiàn)本地上傳文件到resources目錄的文章就介紹到這了,更多相關(guān)SpringBoot上傳文件resources目錄內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
- Springboot 項(xiàng)目讀取Resources目錄下的文件(推薦)
- 解決springboot項(xiàng)目找不到resources目錄下的資源問(wèn)題
- 解決@springboottest注解無(wú)法加載src/main/resources目錄下文件
- springboot項(xiàng)目讀取resources目錄下的文件的9種方式
- springboot實(shí)現(xiàn)jar運(yùn)行復(fù)制resources文件到指定的目錄(思路詳解)
- SpringBoot中讀取jar包中的resources目錄下的文件的三種方式
- SpringBoot如何讀取resources目錄下的文件
- Springboot獲取jar包中resources資源目錄下的文件
- Springboot項(xiàng)目啟動(dòng)不加載resources目錄下的文件問(wèn)題
- SpringBoot下獲取resources目錄下文件的常用方法
相關(guān)文章

SpringBoot通過(guò)JSON傳遞請(qǐng)求參數(shù)的實(shí)例詳解

Java在PowerPoint中添加上標(biāo)和下標(biāo)的實(shí)現(xiàn)方法

Springboot實(shí)現(xiàn)多線程注入bean的工具類操作

IDEA感覺(jué)不香了AI智能編程工具Cursor使用圖文教程

創(chuàng)建SpringBoot工程并集成Mybatis的方法