SpringBoot實現(xiàn)項目文件上傳的方法詳解
一、首先拋出問題
以阿里云oss文件上傳為例,假設(shè)我的需求是這樣的,我需要發(fā)布一條動態(tài),這條動態(tài)呢可以是圖片、語音、視頻,3種類型,每種類型的上傳我必須要限制它的文件大小,超過了我就不能讓他上傳的。如果傳統(tǒng)的方式,那就是創(chuàng)建3個上傳類型bucket對應圖片、語音和視頻,其實這種做法是可以的,但是怎么說呢,還不夠優(yōu)雅,如果當這個動態(tài)有越來越多種類型,你是不是要建立N個類型對應呢,所以就會使得bucket特別的多,不好維護。
二、解決思路
首先,我們可以區(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)雅的文件上傳其實只要認真看了我上面的代碼,就懂得了。主要是大枚舉內(nèi)存的是數(shù)組類,這種寫法比較少見,但是卻能解決多種不同類型文字限制大小的代碼拓展性。
到此這篇關(guān)于SpringBoot實現(xiàn)項目文件上傳的方法詳解的文章就介紹到這了,更多相關(guān)SpringBoot文件上傳內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Spring利用@Validated注解實現(xiàn)參數(shù)校驗詳解
這篇文章主要為大家詳細介紹了在?Spring?項目中使用?@Validated?進行參數(shù)校驗的方法和常見應用場景,感興趣的小伙伴可以跟隨小編一起學習一下2023-05-05解析Java的JNI編程中的對象引用與內(nèi)存泄漏問題
這篇文章主要介紹了Java的JNI編程中的對象引用與內(nèi)存泄漏問題,重點講述了局部和全局引用時一些值得注意的地方,需要的朋友可以參考下2015-11-11ThreadLocal使用案例_動力節(jié)點Java學院整理
這篇文章主要介紹了ThreadLocal使用案例分析,需要的朋友可以參考下2017-08-08詳解如何在Spring?Security中自定義權(quán)限表達式
這篇文章主要和大家詳細介紹一下如何在Spring?Security中自定義權(quán)限表達式,文中的示例代碼講解詳細,感興趣的小伙伴可以跟隨小編一起學習一下2022-07-07