Spring Cloud Feign MultipartFile文件上傳踩坑之路總結(jié)
一、前端文件上傳
文件上傳組件用的是ant-design的a-upload組件,我的界面如下所示:
文件上傳請求API:
FileUtils.js
import axios from "axios"
const uploadApi = ({file, URL, onUploadProgress}) => {
const formData = new FormData()
formData.append('file', file)
return axios.post(URL, formData, {headers:{
'Content-type': 'multipart/form-data',
},
onUploadProgress // 上傳進度回調(diào)函數(shù) onUploadProgress(ev))
})
}
export default uploadApi;
需要注意的只有FileUtils.js定義的uploadApi請求函數(shù),其中URL為后端請求接口(“/imageConvert/upload”),文件上傳方法必須定義為POST,在headers加入’Content-type’: ‘multipart/form-data’,后端即可用@RequestParam或者@RequestPart + MultipartFile 來接受文件。
FileUpload.vue(無關(guān)緊要,用法大致相同,看你自己需求,這里只是提供一個參考范例)
// 自定義文件上傳公共函數(shù)
// e - 上傳組件返回的上傳實例,里面包括 file,和一些組件方法
// e.file - 上傳的文件實例對象
const customUpload = e => {
let curFile = fileList.value.filter(item => item.uid == e.file.uid)[0]
curFile.status = 'uploading'
uploadApi({
file: e.file,
URL: '/imageConvert/upload',
// uid: 'admin', // 需要更改為用戶id,待修改
onUploadProgress: ev => {
// ev - axios 上傳進度實例,上傳過程觸發(fā)多次
// ev.loaded 當(dāng)前已上傳內(nèi)容的大小,ev.total - 本次上傳請求內(nèi)容總大小
// console.log(ev);
const percent = (ev.loaded / ev.total) * 100;
// 計算出上傳進度,調(diào)用組件進度條方法
e.onProgress({ percent });
}
})
.then(res => {
let curFile = fileList.value.filter(item => item.uid == e.file.uid)[0]
curFile.response = res.data
if(res.data.code == 400) {
curFile.status = 'error'
curFile['error'] = curFile.response.msg
console.error(`文件${curFile.name}上傳失敗:${res.data.msg}`)
} else {
// 通知組件該文件上傳成功
curFile.status = 'done'
curFile.url = res.data.data
curFile.thumbUrl = res.data.data
console.log(`文件${curFile.name}上傳成功`, curFile.url);
}
})
.catch(err => {
let curFile = fileList.value.filter(item => item.uid == e.file.uid)[0]
curFile.status = 'error'
curFile['error'] = '文件傳輸失敗'
console.log('上傳失敗', err);
})
}
二、后端處理
后端框架我這里使用的是Spring Cloud,將文件處理統(tǒng)一定義為一個單獨模塊,通過Feign為其他業(yè)務(wù)模塊提供服務(wù)。
服務(wù)提供者
Controller
這里注意要在@PostMapping加入MediaType.MULTIPART_FORM_DATA_VALUEMediaType.MULTIPART_FORM_DATA_VALUE,并且參數(shù)使用@RequestPart來接受參數(shù)
@RefreshScope
@RestController
@RequestMapping("/oss/file")
public class OSSFileController {
@Autowired
private IOSSService ossService;
/**
* 文件上傳,入?yún)⒖梢愿鶕?jù)具體業(yè)務(wù)進行添加
* @param file 文件
* @return 響應(yīng)結(jié)果
*/
@PostMapping( value = "/upload", consumes = MediaType.MULTIPART_FORM_DATA_VALUE)
public String uploadFile(@RequestPart("file") MultipartFile file, @RequestParam("storagePath") String storagePath) {
return ossService.uploadFile(file, storagePath);
}
}
Service(文件存儲方式跟Feign沒關(guān)系,可忽略)
收到文件后我們將其保存在aliyun-oss文件服務(wù)器中:
如何將文件保存在aliyun-oss具體請參考:Spring Boot 集成阿里云 OSS 進行文件存儲
或者可以使用file.transferTo(File file)保存至本地
**
* OSS服務(wù)類
* / @Author: ZenSheep
* / @Date: 2023/8/10 16:05
*/
@Service
public class OSSService implements IOSSService {
@Autowired
private OSS ossClient;
@Autowired
private OSSConfiguration ossConfiguration;
/**
* 上傳文件到阿里云 OSS 服務(wù)器
* 鏈接:https://help.aliyun.com/document_detail/oss/sdk/java-sdk/upload_object.html?spm=5176.docoss/user_guide/upload_object
*
* @param file 文件
* @param storagePath 文件存儲路徑
* @return 文件存儲完整路徑
*/
@Override
public String uploadFile(MultipartFile file, String storagePath) {
String url = "";
try {
// UUID生成文件名,防止重復(fù)
String fileName = "";
String baseName = OSSFileUtils.getBaseName(OSSFileUtils.getBaseName(file.getOriginalFilename()));
InputStream inputStream = file.getInputStream();
// 創(chuàng)建ObjectMetadata,設(shè)置用戶自定義的元數(shù)據(jù)以及HTTP頭,比如內(nèi)容長度,ETag等
ObjectMetadata objectMetadata = new ObjectMetadata();
objectMetadata.setContentLength(inputStream.available());
objectMetadata.setCacheControl("no-cache");
objectMetadata.setHeader("Pragma", "no-cache");
objectMetadata.setContentType(OSSFileUtils.getcontentType(file.getOriginalFilename()));
objectMetadata.setContentDisposition("inline;filename=" + baseName);
fileName = storagePath + "/" + UUID.randomUUID().toString() + "/" + file.getOriginalFilename();
// 上傳文件:調(diào)用ossClient的putObject方法完成文件上傳,并返回文件名
ossClient.putObject(ossConfiguration.getBucketName(), fileName, inputStream, objectMetadata);
// 設(shè)置簽名URL過期時間,單位為毫秒。
Date expiration = new Date(new Date().getTime() + 3600 * 1000);
// 生成以GET方法訪問的簽名URL,訪客可以直接通過瀏覽器訪問相關(guān)內(nèi)容。
url = ossClient.generatePresignedUrl(ossConfiguration.getBucketName(), fileName, expiration).toString();
} catch (IOException e) {
e.printStackTrace();
}
return url;
}
}
Feign
引入依賴:
<!-- SpringCloud Openfeign -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
RemoteFileService
這里同樣需要注意:@PostMapping需要加入consumes = MediaType.MULTIPART_FORM_DATA_VALUE,參數(shù)傳遞用@RequestPart(“file”)
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.http.MediaType;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RequestPart;
import org.springframework.web.multipart.MultipartFile;
/**
* File Feign: 提供File的遠程服務(wù)
* / @Author: ZenSheep
* / @Date: 2023/8/14 18:48
*/
@FeignClient(name = "opentool-system", contextId="remote-file")
public interface RemoteFileService {
@PostMapping(value = "/oss/file/upload", consumes = MediaType.MULTIPART_FORM_DATA_VALUE)
String uploadFile(@RequestPart("file") MultipartFile file, @RequestParam("storagePath") String storagePath);
}
服務(wù)消費者
Controller
/**
* 圖像轉(zhuǎn)換控制類
* / @Author: ZenSheep
* / @Date: 2023/8/14 18:59
*/
@RefreshScope
@RestController
@RequestMapping("/imageConvert")
public class ImageConvertController {
@Autowired
IImageConvertService iImageConvertService;
@PostMapping("/upload")
public R<?> uploadFile(@RequestPart("file") MultipartFile file) {
return R.ok(iImageConvertService.uploadFile(file, "ImageConvert/images"));
}
}
Service(在這里調(diào)用feign服務(wù))文章來源:http://www.zghlxwxcb.cn/news/detail-661585.html
/**
* 圖像轉(zhuǎn)換服務(wù)類
* / @Author: ZenSheep
* / @Date: 2023/8/14 18:53
*/
@Service
public class ImageConvertService implements IImageConvertService {
@Autowired
private RemoteFileService remoteFileService;
@Override
public String uploadFile(MultipartFile file, String storagePath) {
return remoteFileService.uploadFile(file, storagePath);
}
}
ok,到這一步我們的工作就完成了,測試一下:
可以看到我們的文件已經(jīng)成功上傳,并成功保存至目標(biāo)服務(wù)器返回了一個文件存儲url,有什么不懂的可以在評論區(qū)問我,哪里講的不對請大佬輕噴,我也是第一次做文件傳輸。文章來源地址http://www.zghlxwxcb.cn/news/detail-661585.html
到了這里,關(guān)于Spring Cloud Feign MultipartFile文件上傳踩坑之路(包含前端文件上傳請求、后端文件保存到aliyun-oss文件服務(wù)器)的文章就介紹完了。如果您還想了解更多內(nèi)容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!