java

关注公众号 jb51net

关闭
首页 > 软件编程 > java > SpringBoot文件上传

SpringBoot实现项目文件上传的方法详解

作者:狐狸与小兔的故事

这篇文章主要为大家详细介绍了SpringBoot中实现项目文件上传的相关资料,文中的示例代码讲解详细,具有一定的借鉴价值,感兴趣的小伙伴可以了解一下

一、首先抛出问题

以阿里云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;
    }
}

四、结尾

优雅的文件上传其实只要认真看了我上面的代码,就懂得了。主要是大枚举内存的是数组类,这种写法比较少见,但是却能解决多种不同类型文字限制大小的代码拓展性。

到此这篇关于SpringBoot实现项目文件上传的方法详解的文章就介绍到这了,更多相关SpringBoot文件上传内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

您可能感兴趣的文章:
阅读全文