SpringBoot實現(xiàn)項目文件上傳的方法詳解
一、首先拋出問題
以阿里云oss文件上傳為例,假設(shè)我的需求是這樣的,我需要發(fā)布一條動態(tài),這條動態(tài)呢可以是圖片、語音、視頻,3種類型,每種類型的上傳我必須要限制它的文件大小,超過了我就不能讓他上傳的。如果傳統(tǒng)的方式,那就是創(chuàng)建3個上傳類型bucket對應(yīng)圖片、語音和視頻,其實這種做法是可以的,但是怎么說呢,還不夠優(yōu)雅,如果當(dāng)這個動態(tài)有越來越多種類型,你是不是要建立N個類型對應(yīng)呢,所以就會使得bucket特別的多,不好維護(hù)。
二、解決思路
首先,我們可以區(qū)分bucket的上傳類型大類,比如動態(tài)是一個大類,它的子類呢有:圖片、語音、視頻,3種,每種的上傳文件大小的限制是不一樣的。文件上傳后的位置統(tǒng)一都是放到大類bucketName文件夾上。我們可以建立一個枚舉類,該枚舉類比較特殊,是存儲子分類數(shù)組的。code就是大分類,value是子分類數(shù)組。
三、直接看源碼就懂了,下面是controller
@ApiOperation(value = "上傳文件", notes = "bucketName選擇[avatar(頭像),file(文件),banner,game(游戲),dynamic(動態(tài)),room_bg_img(房間背景圖)],文件上傳按分類管理,其他類型請通知添加")
@PostMapping("/uploadFile")
public ResponseResult<UploadFileDto> uploadFile(@RequestParam MultipartFile file, @RequestParam String bucketName) {
ResponseResult responseResult = ResponseResult.error();
Entry entry = null;
try {
//限流
entry = SphU.entry("uploadFile", EntryType.IN, 1, SessionUtil.getUserId());
//驗證是否是可上傳的分類
if (!BucketNameLimitSizeEnum.isValidEnum(bucketName)) {
responseResult.setError(ResponseMessage.BUCKET_NAME_NOT_EXIST);
return responseResult;
}
//獲取文件限制大小
FileLimitItem[] items = BucketNameLimitSizeEnum.getLimitItemByCode(bucketName);
//判斷文件屬于什么類型
Integer typeNum = FileTypeUtil.getContentType(file.getOriginalFilename());
//判斷該上傳類型是哪種類型,并判斷是否超過限制
for (FileLimitItem item : items){
if (typeNum == item.getType()){
if (!MultipartFileUtil.checkFileSize(file.getSize(),item.getNum(),"K")){
responseResult.setError(ResponseMessage.FILE_SIZE_BIG);
return responseResult;
}
break;
}
}
UploadFile entity = uploadFileService.upload(file, bucketName);
UploadFileDto uploadFileDto = new UploadFileDto();
BeanUtils.copyProperties(entity,uploadFileDto);
responseResult = ResponseResult.success(uploadFileDto);
}catch (BlockException e1) {
/* 流控邏輯處理 - 開始 */
log.warn("上傳文件限流!");
return ResponseResult.error(ResponseMessage.SENTINEL_ERROR);
/* 流控邏輯處理 - 結(jié)束 */
}catch (ApiException apiException){
return ResponseResult.error(apiException.getResponseMessage());
}catch (Exception e) {
responseResult.setMessage(e.getMessage());
log.error("上傳文件異常",e);
}finally {
if (entry != null) {
entry.exit();
}
}
return responseResult;
}大分類枚舉類
/**
* @Author huanxinLee
* @Date 2021/10/18 20:25
* @description : 單位 KB
*/
public enum BucketNameLimitSizeEnum {
AVATAR("avatar",new FileLimitItem[]{FileLimitItem.genImageItem(300)}), // 頭像
SCREENSHOTS("screenshots",new FileLimitItem[]{FileLimitItem.genImageItem(1536)}),//截屏,1.5M * 1024 = 1536KB
ACTIVITY_IMG("activity_img",new FileLimitItem[]{FileLimitItem.genImageItem(1536)}),//活動類圖片,1.5M * 1024 = 1536KB
FILE("file",new FileLimitItem[]{FileLimitItem.genFileItem(20 * 1024)}), // 文件,20M
BANNER("banner",new FileLimitItem[]{FileLimitItem.genImageItem(1536)}), // banner,1.5M
GAME("game",new FileLimitItem[]{FileLimitItem.genFileItem(20 * 1024)}), // 游戲
DYNAMIC("dynamic",new FileLimitItem[]{FileLimitItem.genImageItem(1536),FileLimitItem.genAudioItem(10 * 1024),FileLimitItem.genVideoItem(20 * 1024)}),//動態(tài)
USER_REPORT("user_report",new FileLimitItem[]{FileLimitItem.genFileItem(20 * 1024)}), // 舉報個人
;
private String code;
private FileLimitItem[] limitItems;
BucketNameLimitSizeEnum(String code, FileLimitItem[] limitItems) {
this.code = code;
this.limitItems = limitItems;
}
public String getCode() {
return code;
}
public void setCode(String code) {
this.code = code;
}
public FileLimitItem[] getLimitItems() {
return limitItems;
}
public void setLimitItems(FileLimitItem[] limitItems) {
this.limitItems = limitItems;
}
//通過code獲取限制大小數(shù)組
public static FileLimitItem[] getLimitItemByCode(String code){
for (BucketNameLimitSizeEnum bucketNameLimitSizeEnum : BucketNameLimitSizeEnum.values()){
if (bucketNameLimitSizeEnum.getCode().equals(code)) {
return bucketNameLimitSizeEnum.getLimitItems();
}
}
return null;
}
//判斷是否存在該上傳類
public static boolean isValidEnum(String code) {
for (BucketNameLimitSizeEnum typeEnum : BucketNameLimitSizeEnum.values()) {
if (typeEnum.getCode().equals(code)) {
return true;
}
}
return false;
}
}枚舉子分類數(shù)組,主要把所有上傳的類型分為4大類:圖片、音頻、視頻、文件
/**
* @Author huanxinLee
* @Date 2021/10/18 21:08
* @description : 文件上傳 分類
*/
public class FileLimitItem {
public static final int TYPE_IMAGE = 1;//圖片
public static final int TYPE_AUDIO = 2;//音頻
public static final int TYPE_VIDEO = 3;//視頻
public static final int TYPE_FILE = 4;//文件
private int type;
private int num;
FileLimitItem() {
}
FileLimitItem(int type, int num) {
this.type = type;
this.num = num;
}
// image
public static FileLimitItem genImageItem(int num){
return new FileLimitItem(TYPE_IMAGE,num);
}
// audio
public static FileLimitItem genAudioItem(int num){
return new FileLimitItem(TYPE_AUDIO,num);
}
// video
public static FileLimitItem genVideoItem(int num){
return new FileLimitItem(TYPE_VIDEO,num);
}
// file
public static FileLimitItem genFileItem(int num){
return new FileLimitItem(TYPE_FILE,num);
}
public int getType() {
return type;
}
public void setType(int type) {
this.type = type;
}
public int getNum() {
return num;
}
public void setNum(int num) {
this.num = num;
}
}判斷文件大小是否超的工具類
/**
* @Author huanxinLee
* @Date 2021/10/18 20:44
* @description : 文件上傳限制大小工具類
*/
public class MultipartFileUtil {
/**
* @param len 文件長度
* @param size 限制大小
* @param unit 限制單位(B,K,M,G)
* @描述 判斷文件大小
*/
public static boolean checkFileSize(Long len, int size, String unit) {
double fileSize = 0;
if ("B".equalsIgnoreCase(unit)) {
fileSize = (double) len;
} else if ("K".equalsIgnoreCase(unit)) {
fileSize = (double) len / 1024;
} else if ("M".equalsIgnoreCase(unit)) {
fileSize = (double) len / 1048576;
} else if ("G".equalsIgnoreCase(unit)) {
fileSize = (double) len / 1073741824;
}
return !(fileSize > size);
}
/**
* file轉(zhuǎn)multipartFile
*/
public static MultipartFile fileToMultipartFile(File file) {
FileItemFactory factory = new DiskFileItemFactory(16, null);
FileItem item=factory.createItem(file.getName(),"text/plain",true,file.getName());
int bytesRead = 0;
byte[] buffer = new byte[8192];
try {
FileInputStream fis = new FileInputStream(file);
OutputStream os = item.getOutputStream();
while ((bytesRead = fis.read(buffer, 0, 8192)) != -1) {
os.write(buffer, 0, bytesRead);
}
os.close();
fis.close();
} catch (IOException e) {
e.printStackTrace();
}
return new CommonsMultipartFile(item);
}
/**
* inputStream 轉(zhuǎn) File
*/
public static File inputStreamToFile(InputStream ins, String name) throws Exception{
//System.getProperty("java.io.tmpdir")臨時目錄+File.separator目錄中間的間隔符+文件名
File file = new File(System.getProperty("java.io.tmpdir") + File.separator + name);
// if (file.exists()) {
// return file;
// }
OutputStream os = new FileOutputStream(file);
int bytesRead;
int len = 8192;
byte[] buffer = new byte[len];
while ((bytesRead = ins.read(buffer, 0, len)) != -1) {
os.write(buffer, 0, bytesRead);
}
os.close();
ins.close();
return file;
}
}四、結(jié)尾
優(yōu)雅的文件上傳其實只要認(rèn)真看了我上面的代碼,就懂得了。主要是大枚舉內(nèi)存的是數(shù)組類,這種寫法比較少見,但是卻能解決多種不同類型文字限制大小的代碼拓展性。
到此這篇關(guān)于SpringBoot實現(xiàn)項目文件上傳的方法詳解的文章就介紹到這了,更多相關(guān)SpringBoot文件上傳內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Spring利用@Validated注解實現(xiàn)參數(shù)校驗詳解
這篇文章主要為大家詳細(xì)介紹了在?Spring?項目中使用?@Validated?進(jìn)行參數(shù)校驗的方法和常見應(yīng)用場景,感興趣的小伙伴可以跟隨小編一起學(xué)習(xí)一下2023-05-05
解析Java的JNI編程中的對象引用與內(nèi)存泄漏問題
這篇文章主要介紹了Java的JNI編程中的對象引用與內(nèi)存泄漏問題,重點講述了局部和全局引用時一些值得注意的地方,需要的朋友可以參考下2015-11-11
ThreadLocal使用案例_動力節(jié)點Java學(xué)院整理
這篇文章主要介紹了ThreadLocal使用案例分析,需要的朋友可以參考下2017-08-08
詳解如何在Spring?Security中自定義權(quán)限表達(dá)式
這篇文章主要和大家詳細(xì)介紹一下如何在Spring?Security中自定義權(quán)限表達(dá)式,文中的示例代碼講解詳細(xì),感興趣的小伙伴可以跟隨小編一起學(xué)習(xí)一下2022-07-07
Springboot如何通過路徑映射獲取本機(jī)圖片資源
項目中對圖片的處理與查看是必不可少的,本文將講解如何通過項目路徑來獲取到本機(jī)電腦的圖片資源,本文通過示例代碼給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友參考下吧2023-08-08

