SpringBoot實(shí)現(xiàn)項(xiàng)目文件上傳的方法詳解
一、首先拋出問(wèn)題
以阿里云oss文件上傳為例,假設(shè)我的需求是這樣的,我需要發(fā)布一條動(dòng)態(tài),這條動(dòng)態(tài)呢可以是圖片、語(yǔ)音、視頻,3種類(lèi)型,每種類(lèi)型的上傳我必須要限制它的文件大小,超過(guò)了我就不能讓他上傳的。如果傳統(tǒng)的方式,那就是創(chuàng)建3個(gè)上傳類(lèi)型bucket對(duì)應(yīng)圖片、語(yǔ)音和視頻,其實(shí)這種做法是可以的,但是怎么說(shuō)呢,還不夠優(yōu)雅,如果當(dāng)這個(gè)動(dòng)態(tài)有越來(lái)越多種類(lèi)型,你是不是要建立N個(gè)類(lèi)型對(duì)應(yīng)呢,所以就會(huì)使得bucket特別的多,不好維護(hù)。
二、解決思路
首先,我們可以區(qū)分bucket的上傳類(lèi)型大類(lèi),比如動(dòng)態(tài)是一個(gè)大類(lèi),它的子類(lèi)呢有:圖片、語(yǔ)音、視頻,3種,每種的上傳文件大小的限制是不一樣的。文件上傳后的位置統(tǒng)一都是放到大類(lèi)bucketName文件夾上。我們可以建立一個(gè)枚舉類(lèi),該枚舉類(lèi)比較特殊,是存儲(chǔ)子分類(lèi)數(shù)組的。code就是大分類(lèi),value是子分類(lèi)數(shù)組。
三、直接看源碼就懂了,下面是controller
@ApiOperation(value = "上傳文件", notes = "bucketName選擇[avatar(頭像),file(文件),banner,game(游戲),dynamic(動(dòng)態(tài)),room_bg_img(房間背景圖)],文件上傳按分類(lèi)管理,其他類(lèi)型請(qǐng)通知添加") @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()); //驗(yàn)證是否是可上傳的分類(lèi) if (!BucketNameLimitSizeEnum.isValidEnum(bucketName)) { responseResult.setError(ResponseMessage.BUCKET_NAME_NOT_EXIST); return responseResult; } //獲取文件限制大小 FileLimitItem[] items = BucketNameLimitSizeEnum.getLimitItemByCode(bucketName); //判斷文件屬于什么類(lèi)型 Integer typeNum = FileTypeUtil.getContentType(file.getOriginalFilename()); //判斷該上傳類(lèi)型是哪種類(lèi)型,并判斷是否超過(guò)限制 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) { /* 流控邏輯處理 - 開(kāi)始 */ 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; }
大分類(lèi)枚舉類(lèi)
/** * @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)}),//活動(dòng)類(lèi)圖片,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)}),//動(dòng)態(tài) USER_REPORT("user_report",new FileLimitItem[]{FileLimitItem.genFileItem(20 * 1024)}), // 舉報(bào)個(gè)人 ; 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; } //通過(guò)code獲取限制大小數(shù)組 public static FileLimitItem[] getLimitItemByCode(String code){ for (BucketNameLimitSizeEnum bucketNameLimitSizeEnum : BucketNameLimitSizeEnum.values()){ if (bucketNameLimitSizeEnum.getCode().equals(code)) { return bucketNameLimitSizeEnum.getLimitItems(); } } return null; } //判斷是否存在該上傳類(lèi) public static boolean isValidEnum(String code) { for (BucketNameLimitSizeEnum typeEnum : BucketNameLimitSizeEnum.values()) { if (typeEnum.getCode().equals(code)) { return true; } } return false; } }
枚舉子分類(lèi)數(shù)組,主要把所有上傳的類(lèi)型分為4大類(lèi):圖片、音頻、視頻、文件
/** * @Author huanxinLee * @Date 2021/10/18 21:08 * @description : 文件上傳 分類(lèi) */ 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; } }
判斷文件大小是否超的工具類(lèi)
/** * @Author huanxinLee * @Date 2021/10/18 20:44 * @description : 文件上傳限制大小工具類(lèi) */ public class MultipartFileUtil { /** * @param len 文件長(zhǎng)度 * @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")臨時(shí)目錄+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)雅的文件上傳其實(shí)只要認(rèn)真看了我上面的代碼,就懂得了。主要是大枚舉內(nèi)存的是數(shù)組類(lèi),這種寫(xiě)法比較少見(jiàn),但是卻能解決多種不同類(lèi)型文字限制大小的代碼拓展性。
到此這篇關(guān)于SpringBoot實(shí)現(xiàn)項(xiàng)目文件上傳的方法詳解的文章就介紹到這了,更多相關(guān)SpringBoot文件上傳內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
- SpringBoot文件上傳的原理解析
- SpringBoot+ruoyi框架文件上傳和下載的實(shí)現(xiàn)
- tdesign的文件上傳功能實(shí)現(xiàn)(微信小程序+idea的springboot)
- SpringBoot中的文件上傳和異常處理詳解
- SpringBoot中的文件上傳與下載詳解
- Springboot文件上傳功能的實(shí)現(xiàn)
- SpringBoot文件上傳同時(shí)接收復(fù)雜參數(shù)的過(guò)程詳解
- SpringBoot文件上傳與下載功能實(shí)現(xiàn)詳解
- SpringBoot簡(jiǎn)單實(shí)現(xiàn)文件上傳
- SpringBoot整合Hutool實(shí)現(xiàn)文件上傳的使用示例
相關(guān)文章
Spring利用@Validated注解實(shí)現(xiàn)參數(shù)校驗(yàn)詳解
這篇文章主要為大家詳細(xì)介紹了在?Spring?項(xiàng)目中使用?@Validated?進(jìn)行參數(shù)校驗(yàn)的方法和常見(jiàn)應(yīng)用場(chǎng)景,感興趣的小伙伴可以跟隨小編一起學(xué)習(xí)一下2023-05-05解析Java的JNI編程中的對(duì)象引用與內(nèi)存泄漏問(wèn)題
這篇文章主要介紹了Java的JNI編程中的對(duì)象引用與內(nèi)存泄漏問(wèn)題,重點(diǎn)講述了局部和全局引用時(shí)一些值得注意的地方,需要的朋友可以參考下2015-11-11ThreadLocal使用案例_動(dòng)力節(jié)點(diǎn)Java學(xué)院整理
這篇文章主要介紹了ThreadLocal使用案例分析,需要的朋友可以參考下2017-08-08詳解如何在Spring?Security中自定義權(quán)限表達(dá)式
這篇文章主要和大家詳細(xì)介紹一下如何在Spring?Security中自定義權(quán)限表達(dá)式,文中的示例代碼講解詳細(xì),感興趣的小伙伴可以跟隨小編一起學(xué)習(xí)一下2022-07-07Springboot如何通過(guò)路徑映射獲取本機(jī)圖片資源
項(xiàng)目中對(duì)圖片的處理與查看是必不可少的,本文將講解如何通過(guò)項(xiàng)目路徑來(lái)獲取到本機(jī)電腦的圖片資源,本文通過(guò)示例代碼給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友參考下吧2023-08-08