以阿里云oss文件上传为例,假设我的需求是这样的,我需要发布一条动态,这条动态呢可以是图片、语音、视频,3种类型,每种类型的上传我必须要限制它的文件大小,超过了我就不能让他上传的。如果传统的方式,那就是创建3个上传类型bucket对应图片、语音和视频,其实这种做法是可以的,但是怎么说呢,还不够优雅,如果当这个动态有越来越多种类型,你是不是要建立N个类型对应呢,所以就会使得bucket特别的多,不好维护。
首先,我们可以区分bucket的上传类型大类,比如动态是一个大类,它的子类呢有:图片、语音、视频,3种,每种的上传文件大小的限制是不一样的。文件上传后的位置统一都是放到大类bucketName文件夹上。我们可以建立一个枚举类,该枚举类比较特殊,是存储子分类数组的。code就是大分类,value是子分类数组。
- @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;
- }
- }
- 复制代码
优雅的文件上传其实只要认真看了我上面的代码,就懂得了。主要是大枚举内存的是数组类,这种写法比较少见,但是却能解决多种不同类型文字限制大小的代码拓展性。
结语:以往都是看别人的博客进行学习技术,其中不乏有精华博客也有吊儿郎当的CV大法文章,所以决定将自己所学所用所整理的知识分享给大家,主要还是想为了后浪们少走些弯路,多些正能量的博客,如有错漏,欢迎指正,仅希望大家能在我的博客中学到知识,解决到问题,那么就足够了。谢谢大家!(转载请注明原文出处)