SpringBoot实现项目文件上传的方法详解
狐狸与小兔的故事 人气:1一、首先抛出问题
以阿里云oss文件上传为例,假设我的需求是这样的,我需要发布一条动态,这条动态呢可以是图片、语音、视频,3种类型,每种类型的上传我必须要限制它的文件大小,超过了我就不能让他上传的。如果传统的方式,那就是创建3个上传类型bucket对应图片、语音和视频,其实这种做法是可以的,但是怎么说呢,还不够优雅,如果当这个动态有越来越多种类型,你是不是要建立N个类型对应呢,所以就会使得bucket特别的多,不好维护。
二、解决思路
首先,我们可以区分bucket的上传类型大类,比如动态是一个大类,它的子类呢有:图片、语音、视频,3种,每种的上传文件大小的限制是不一样的。文件上传后的位置统一都是放到大类bucketName文件夹上。我们可以建立一个枚举类,该枚举类比较特殊,是存储子分类数组的。code就是大分类,value是子分类数组。
三、直接看源码就懂了,下面是controller
@ApiOperation(value = "上传文件", notes = "bucketName选择[avatar(头像),file(文件),banner,game(游戏),dynamic(动态),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); /* 流控逻辑处理 - 结束 */ }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)}),//动态 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获取限制大小数组 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; } }
枚举子分类数组,主要把所有上传的类型分为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转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 转 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; } }
四、结尾
优雅的文件上传其实只要认真看了我上面的代码,就懂得了。主要是大枚举内存的是数组类,这种写法比较少见,但是却能解决多种不同类型文字限制大小的代码拓展性。
加载全部内容