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

 更新时间:2022年11月23日 10:09:20   作者:狐狸与小兔的故事  
这篇文章主要为大家详细介绍了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文件上传内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • JavaWeb中的组件Filter过滤器解析

    JavaWeb中的组件Filter过滤器解析

    这篇文章主要介绍了JavaWeb中的组件Filter过滤器解析,Filter过滤器是一种用于处理和转换数据的工具,常用于Web开发中,它可以在请求到达服务器之前或响应返回给客户端之前对数据进行预处理或后处理,需要的朋友可以参考下
    2023-10-10
  • 微信公众号模板消息接口开发Java实现方法代码

    微信公众号模板消息接口开发Java实现方法代码

    这篇文章主要介绍了微信公众号模板消息接口开发Java实现的相关资料,,该接口可以用于向关注公众号的用户推送消息,包括群发和指定用户发送消息,文章详细介绍了如何获取公众号的测试信息、配置接口信息和获取access_token,需要的朋友可以参考下
    2024-12-12
  • Java基于对象流实现银行系统

    Java基于对象流实现银行系统

    这篇文章主要为大家详细介绍了Java基于对象流实现银行系统,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2022-09-09
  • java对象与json对象之间互相转换实现方法示例

    java对象与json对象之间互相转换实现方法示例

    这篇文章主要介绍了java对象与json对象之间互相转换实现方法,结合实例形式分析了java对象与json对象相互转换实现步骤与相关操作技巧,需要的朋友可以参考下
    2017-10-10
  • Java实现跳跃表(skiplist)的简单实例

    Java实现跳跃表(skiplist)的简单实例

    这篇文章主要介绍了Java编程中跳跃表的概念和实现原理,并简要叙述了它的结构,具有一定参考价值,需要的朋友可以了解下。
    2017-09-09
  • Spring Boot的filter(过滤器)简单使用实例详解

    Spring Boot的filter(过滤器)简单使用实例详解

    过滤器(Filter)的注册方法和 Servlet 一样,有两种方式:代码注册或者注解注册,下面通过实例给大家介绍Spring Boot的filter(过滤器)简单使用,一起看看吧
    2017-04-04
  • java将一个目录下的所有数据复制到另一个目录下

    java将一个目录下的所有数据复制到另一个目录下

    这篇文章主要为大家详细介绍了java将一个目录下的所有数据复制到另一个目录下,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2019-08-08
  • 为什么Spring官方推荐的@Transational还能导致生产事故

    为什么Spring官方推荐的@Transational还能导致生产事故

    在Spring中进行事务管理非常简单,只需要在方法上加上注解@Transactional,那么为什么Spring官方推荐的@Transational还能导致生产事故,本文就详细的介绍一下
    2021-11-11
  • 分析Java中Map的遍历性能问题

    分析Java中Map的遍历性能问题

    随着JDK 1.8 Streams API的发布,使得HashMap拥有了更多的遍历的方式,但应该选择那种遍历方式?反而成了一个问题。本文从几个方面来分析 HashMap各种遍历方式的优势与不足
    2021-06-06
  • MyBatis中resultType和parameterType和resultMap使用总结

    MyBatis中resultType和parameterType和resultMap使用总结

    这篇文章主要介绍了MyBatis中resultType和parameterType和resultMap使用总结,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2022-11-11

最新评论