• 有了这个开源工具后,我五点就下班了




    • 💂 个人网站: IT知识小屋
    • 🤟 版权: 本文由【IT学习日记】原创、在CSDN首发、需要转载请联系博主
    • 💬 如果文章对你有帮助、欢迎关注、点赞、收藏(一键三连)和订阅专栏哦
    • 💅 开源项目:【轮子之王


    前言

      一个优秀的开发者,一定是会利用各种工具来提升自己的开发效率。 前段时间,博主在Gitee/Github开源了一个提升开发效率的工具,工具内集成了各种常用工具如csv、excel、ftp、文件系统等等,只需要简单调用API,就可以得到想要的结果,可以极大帮助开发者提升效率,下面来一起看看这款工具如何使用吧。

    image-20220806204935635

    工具介绍

      报表的导出、导入功能、文件上传、下载等在平常业务中是最常见不过的功能了,许多小伙伴在开发的时候才会去网上找之前别人编写过的案例参考,但是许多博客记载的都是时间比较长远或者不完整的代码,这导致在引入的时候还要处理引入的许多未知问题。

      现在博主开源的“轮子之王”包含了这些常见的功能,源码全开发,每种功能都有相应的例子说明,项目会持续更新迭代,有问题还可以及时给项目提issue,相信比大多数网上的博客代码可靠性更高。

      项目地址如下:

      Github:https://github.com/it-learning-diary/it-wheels-king

      Gitee:https://gitee.com/it-learning-diary/it-wheels-king

      项目结构如下:

    image-20220807104023940

    一、excel工具

      该工具实现采用的是开源的easyexcel框架。easyexcel是阿里的开发人员对poi框架进行了优化,解决了poi在大数据量时可能出现OOM异常,并且兼容xls和xlsx两种文件类型的一个开源框架。

      excel工具集成功能如下:

    • excel的导入(可以自定义转换后的excel数据处理的业务逻辑,支持抛出异常、事务回滚、记录解析时的异常数据)
    • 导出(支持固定表头,兼容多sheet页和动态表头,兼容多sheet页)功能。

      excel工具的特点如下:

      使用过easyexcel框架的一些读者知道,每个导入功能都要写一个对应的Listener进行数据转换,在很多时间其实转换的逻辑都是类似的,不同的只不过是转换后数据处理的业务逻辑不一样。

      本开源项目的excel工具则利用Java中的泛型和Java8中的Consumer接口将相同的部分(转换逻辑)抽取出来,不同的部分则单独传入(数据处理的业务逻辑),这样就避免了每个导入都需要创建一个相类似的Listerner,减少了类的创建和提高了开发效率。

      部分源码如下:

     /**
         * 通用导入excel文件方法
         *
         * @param fileStream 导入的文件流
         * @param rowDto 接收excel每行数据的实体
         * @param rowAction 将接收到的实体进行自定义的业务处理逻辑方法
         * @param  实体类型
         */
        public static <T> void importFile(InputStream fileStream, T rowDto, ThrowingConsumer<List<T>> rowAction) {
            // 获取excel通用监听器
            ExcelImportCommonListener<T> commonListener = new ExcelImportCommonListener<>(rowAction);
            // 读取excel文件并导入
            EasyExcel.read(fileStream, rowDto.getClass(), commonListener).sheet().doRead();
        }
        
    /**
         * excel文件导出(可以包含多个sheet页),固定表头(通过实体指定属性的方式)
         * @param response
         * @param fileName   导出文件名
         * @param head       导出表头(多个sheet页就是多个集合元素)
         * @param exportData 需要导出数据
         * @param sheetNames sheet页的名称,为空则默认以:sheet + 数字规则命名
         */
        public static <T> void exportFile(String fileName, List<T> head, List<List<T>> exportData, List<String> sheetNames, HttpServletResponse response) {
            if (Objects.isNull(response) || StrUtil.isBlank(fileName) || CollUtil.isEmpty(head)) {
                log.info("ExcelExportUtil exportFile required param can't be empty");
                return;
            }
            ExcelWriter writer = null;
            try {
                response.setContentType(ExportConstant.EXCEL_CONTENT_TYPE);
                response.setCharacterEncoding(ExportConstant.UTF_8);
                response.setHeader(ExportConstant.CONTENT_DISPOSITION, ExportConstant.ATTACHMENT_FILENAME + fileName + ExportConstant.XLSX_SUFFIX);
                // 设置导出的表格样式
                HorizontalCellStyleStrategy horizontalCellStyleStrategy = getExportDefaultStyle();
                writer = EasyExcel.write(response.getOutputStream()).registerWriteHandler(horizontalCellStyleStrategy).build();
                for (int itemIndex = 0; itemIndex < exportData.size(); itemIndex++) {
                    // 表头数据
                    Object headData = head.get(itemIndex);
                    // sheet页的数据
                    List<T> list = exportData.get(itemIndex);
                    WriteSheet sheet = EasyExcel.writerSheet(itemIndex, CollUtil.isEmpty(sheetNames) ? ExportConstant.SHEET_NAME + itemIndex + 1 : sheetNames.get(itemIndex)).head(headData.getClass()).build();
                    writer.write(list, sheet);
                }
            } catch (Exception e) {
                log.error("ExcelExportUtil exportFile in error:{}", e);
            } finally {
                if (null != writer) {
                    writer.finish();
                }
            }
        }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53

      使用案例如下(在工具中每个项目都有具体的案例,不懂的还可以留言跟博主沟通):

    /**
         * 导入用户数据案例
         *
         * @param file
         */
        @Transactional(rollbackFor = Exception.class)
        public void uploadUserListDemoWithExcel(MultipartFile file, String username) throws Exception {
            // 此处先校验导入的文件类型是否为excel
            String type = FileTypeUtil.getType(file.getInputStream());
            if (StrUtil.isBlank(type) || type.contains(ImportConstant.XLS_TYPE) || type.contains(ImportConstant.XLSX_TYPE)) {
                // 返回校验失败信息
                return;
            }
            User user = new User();
            user.setId(100);
            user.setName("外层");
            user.setPassword("外层");
            userService.save(user);
            // 调用统一导入方法
            ExcelImportUtil.importFile(file.getInputStream(), new UserDto(), UserServiceImpl::saveUserList);
        }
    
     /**
         * 导出案例
         *
         * @param response
         */
        public void exportUserListDemoWithExcel(HttpServletResponse response) {
            // 表头(使用excel中的注解定义,如果表头不固定,请使用ExcelExportUtil.exportWithDynamicData进行导出)
            List<UserExportVo> head = Stream.of(new UserExportVo()).collect(Collectors.toList());
            // 数据(使用两层list为了兼容多个sheet页,如果是不同的sheet页则放在不同的List集合中)
            List<List<UserExportVo>> exportDataList = new ArrayList<>();
            List<UserExportVo> exportItem = new ArrayList<>();
            // 查询数据
            List<User> dbData = userService.list();
            // 将数据转换成导出需要的实际数据格式,此处只是演示
            for (User user : dbData) {
                UserExportVo vo = new UserExportVo();
                BeanUtil.copyProperties(user, vo);
                exportItem.add(vo);
            }
            exportDataList.add(exportItem);
            // sheet页名称-自定义,如果没有则传空
            List<String> sheetNameList = Stream.of("sheet1").collect(Collectors.toList());
            ExcelExportUtil.exportFile("user", head, exportDataList, sheetNameList, response);
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46

    二、csv工具

      Csv即逗号分隔值,也可以称为字符分隔符,与excel等文件相比,excel文件中会包含许多格式信息,占用的空间会更大,所以Csv在很多大数据场景导出、导入场景是非常常见的。该工具实现采用的是开源的univocity-parsers框架实现。

      之前有一篇专门讲解轮子之王项目为何使用univocity-parsers框架集成csv的详细过程,有兴趣的读者可以点击链接查看:集成csv工具的前因后果

      部分源码如下:

     /**
         * 使用实体bean接收csv数据文件并进行数据落盘
         *
         * @param inputStream
         * @param errorList
         * @param rowDtoClass
         * @param rowAction
         * @param 
         */
        public static <T> void importCsvWithBean(InputStream inputStream, List<String> errorList, Class rowDtoClass, ThrowingConsumer<List<T>> rowAction) {
            // 定义bean解析者:用于将csv中数据绑定到实体属性中,然后存储带list集合上
            BeanListProcessor<T> rowProcessor = new BeanListProcessor<>(rowDtoClass);
            CsvParserSettings setting = getDefaultSetting(errorList);
            setting.setProcessor(rowProcessor);
            // 创建csv文件解析
            CsvParser csvParser = new CsvParser(setting);
            csvParser.parse(inputStream);
            // 获取数据映射后的集合
            List<T> dataList = rowProcessor.getBeans();
            // 校验必填字段
            for (T row : dataList) {
                // 校验导入字段
                ImportValid.validRequireField(row, errorList);
            }
            // 执行数据持久化
            persistentBeanDataToDb(dataList, rowAction);
        }
        
       /**
         * 导出csv文件(表头和行都以实体的方式)
         *
         * @param response
         * @param head
         * @param rowDataList
         */
        public static <T> void exportCsvWithBean(HttpServletResponse response, String fileName, T head, List<T> rowDataList) {
            CsvWriter writer = null;
            try {
                // 设置响应头格式
                response.setContentType(ExportConstant.EXCEL_CONTENT_TYPE);
                response.setCharacterEncoding(ExportConstant.UTF_8);
                response.setHeader(ExportConstant.CONTENT_DISPOSITION, ExportConstant.ATTACHMENT_FILENAME + fileName + ExportConstant.CSV_SUFFIX);
    
                // 设置导出格式
                CsvWriterSettings setting = getDefaultWriteSetting();
                // 创见bean处理器,用于处理写入数据
                BeanWriterProcessor<?> beanWriter = new BeanWriterProcessor<>(head.getClass());
                setting.setRowWriterProcessor(beanWriter);
    
                // 导出数据
                writer = new CsvWriter(response.getOutputStream(), setting);
                writer.processRecords(rowDataList);
                writer.flush();
            } catch (Exception e) {
                log.error("CsvExportUtil exportCsvWithBean in error:{}", e);
            } finally {
                if (Objects.nonNull(writer)) {
                    writer.close();
                }
            }
        } 
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62

      使用案例如下:

    /**
         * 导出案例
         *
         * @param response
         */
        public void exportUserListWithCsv(HttpServletResponse response) {
            List<UserExportCsvVo> exportItem = new ArrayList<>();
            // 查询数据
            List<User> dbData = userService.list();
            // 使用字符串数组方式作为表头导出csv数据
            List<Object> head = Stream.of("id", "name", "password").collect(Collectors.toList());
            List<List<Object>> dataList = new ArrayList<>();
            for (User user : dbData) {
                List<Object> row = new ArrayList<>();
                row.add(user.getId());
                row.add(user.getName());
                row.add(user.getPassword());
                dataList.add(row);
            }
            CsvExportUtil.exportCsvWithString(response, "demo", head, dataList);
        }
    
     /**
         * 导入用户数据案例(csv模式)
         *
         * @param file
         */
    @Transactional(rollbackFor = Exception.class)
        public void uploadUserListWithCsv(MultipartFile file) throws Exception {
            // 此处先校验导入的文件类型是否为csv
            String type = FileTypeUtil.getType(file.getInputStream());
            if (StrUtil.isBlank(type) || type.contains(ImportConstant.CSV_TYPE)) {
                // 返回校验失败信息
                return;
            }
            User user = new User();
            user.setId(100);
            user.setName("外层");
            user.setPassword("外层");
            userService.save(user);
            List<String> errorLogList = new ArrayList<>();
            // 调用统一导入方法
            // 方式一:使用csv数据映射到dto实体的方式进行数据导入
            //CsvImportUtil.importCsvWithBean(file.getInputStream(), errorLogList, UserCsvDto.class, UserServiceImpl::saveUserListWithCsv);
    
            // 方式二、使用csv数据映射到字符串数组的方式进行数据导入
            CsvImportUtil.importCsvWithString(file.getInputStream(), errorLogList, UserCsvDto.class, UserServiceImpl::saveUserListWithCsvStringArrDemo);
    
            // 如果存在解析异常,输出解析异常并进行事务回滚
            if (CollUtil.isNotEmpty(errorLogList)) {
                throw new RuntimeException(StrUtil.toString(errorLogList));
            }
        }
        
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54

    三、ftp工具

      Ftp文件上传下载相比excel、csv等出现的场景较少,但是,如果你参与的项目是政府或者涉及到第三方旧系统对接的时候,很多时候就需要使用到它。因为很多旧系统或者政府项目使用的技术比较旧或者有制度限制,一般都是以文件的形式与你进行交互,此时ftp工具就很有效了。

      Ftp工具使用的commons-net开源框架进行实现,具体的集成流程之前单独使用一篇文章进行了非常详细的介绍,有需要的读者可以点击后面链接查看:手把手教你搭建ftp服务器,并用程序完成ftp上传下载功能

      部分源码如下:

    /**
         * 上传
         *
         * @return
         */
        public boolean upload(FtpUploadParam param) {
            boolean flag = false;
            FTPClient ftpClient = new FTPClient();
            //1 测试连接
            if (connect(ftpClient, param.getHostname(), param.getPort(), param.getUsername(), param.getPassword())) {
                try {
                    //2 检查工作目录是否存在,不存在则创建
                    if (!ftpClient.changeWorkingDirectory(param.getWorkingPath())) {
                        ftpClient.makeDirectory(param.getWorkingPath());
                    }
                    // 将文件编码成Ftp服务器支持的编码类型(FTP协议里面,规定文件名编码为iso-8859-1,所以目录名或文件名需要转码。)
                    String fileName = new String(param.getSaveName().getBytes(ftpClientCharset), ftpServerCharset);
                    // 3 上传文件
                    if (ftpClient.storeFile(fileName, param.getInputStream())) {
                        flag = true;
                    } else {
                        log.warn("FtpUtils uploadFile unsuccessfully!!");
                    }
                } catch (IOException e) {
                    log.error("FtpUtils upload in error:{}", e);
                } finally {
                    disconnect(ftpClient);
                }
            }
            return flag;
        }
    /**
         * @description: 下载ftp文件
         * @param:
         * @param: param
         * @param: downloadFileName
         * @return:
         * @date: 2022/7/14 10:56
         */
        public boolean download(FtpDownloadParam param, String downloadFileName) {
            FTPClient ftpClient = new FTPClient();
            FileOutputStream out = null;
            boolean downloadResult = false;
            //1 测试连接
            if (connect(ftpClient, param.getHostname(), param.getPort(), param.getUsername(), param.getPassword())) {
                try {
                    String localPath = param.getDownloadPath() + param.getFileName();
                    out = new FileOutputStream(new File(localPath));
                    //2 检查工作目录是否存在,不存在返回
                    // if (!ftpClient.changeWorkingDirectory(param.getWorkingPath())) {
                    //    return false;
                    // }
                    /*
                     * 打开FTP服务器的PASS模式(不记得FTP协议支持的模式请翻到文章第一阶段)
                     * 这个方法的意思就是每次数据连接之前,ftp client告诉ftp server开通一个端口来传输数据. 因为ftp
                     * server可能每次开启不同的端口来传输数据,但是在linux上,由于安全限制,可能某些端口没有开启,可能出现出现阻塞
                     */
                    ftpClient.enterLocalPassiveMode();
                    // 设置文件的传输方式-二进制
                    ftpClient.setFileType(FTP.BINARY_FILE_TYPE);
                    // 将文件编码成Ftp服务器支持的编码类型(FTP协议里面,规定文件名编码为iso-8859-1,所以目录名或文件名需要转码。)
                    // 缺少编码转换会导致:从FTP服务器下载下来的文件是破损的,无法被打开
                    downloadResult = ftpClient.retrieveFile(new String(downloadFileName
                            .getBytes(ftpClientCharset), ftpServerCharset), out);
                    out.flush();
                } catch (IOException e) {
                    log.error("FtpUtils upload in error:{}", e);
                    return false;
                } finally {
                    try {
                        if (Objects.nonNull(out)) {
                            out.close();
                        }
                    } catch (Exception e) {
                        log.error("FtpUtils upload in error:{}", e);
                    }
                    disconnect(ftpClient);
                }
            }
            return downloadResult;
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81

      具体使用案例如下:

    @PostMapping("/ftp/upload")
        public void upload() {
            try {
                FtpUploadParam param = new FtpUploadParam();
                param.setHostname(ftpConfig.getServerHostname());
                param.setPort(ftpConfig.getServerPort());
                param.setUsername(ftpConfig.getServerUsername());
                param.setPassword(ftpConfig.getServerPassword());
                param.setWorkingPath(ftpConfig.getServerWorkingPath());
                param.setSaveName("xxx.mp3");
                InputStream in = new FileInputStream(new File("D:/uploadfile/like.mp3"));
                param.setInputStream(in);
                ftpUtils.upload(param);
            } catch (Exception e) {
                log.error("TestFtpServerController upload 错误:{}", e);
            }
        }
    
        @PostMapping("/ftp/download")
        public void download() {
            try {
                FtpDownloadParam param = new FtpDownloadParam();
                param.setHostname(ftpConfig.getServerHostname());
                param.setPort(ftpConfig.getServerPort());
                param.setUsername(ftpConfig.getServerUsername());
                param.setPassword(ftpConfig.getServerPassword());
                param.setWorkingPath(ftpConfig.getServerWorkingPath());
                param.setDownloadPath("D:/downloadFile/");
                param.setFileName("xxx.mp3");
                ftpUtils.download(param, "xxxx.mp3");
            } catch (Exception e) {
                log.error("TestFtpServerController download 错误:{}", e);
            }
    
        }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36

    四、分布式文件系统工具

      非结构化数据通常是使用文件的方式进行存储,这时候不可避免地要使用到文件系统进行管理。 分布式文件系统工具使用了第三方开源框架seaweedfs进行搭建,可以实现程序上传,删除、下载、查询,并有文件分布式存储,避免单点故障,节约成本等特点。

      前面也专门通过一篇文章讲解了:为何要使用seaweedfs框架搭建分布式文件系统的,感兴趣的读者可以通过下方链接进行查看:Gitee图床崩溃后,我使用Seaweedfs搭建了文件系统并封装成轮子开源

      部分源码如下:

    /**
         * @description: 上传单个文件到文件服务器
         * @param: file
         * @return: 文件的fid + 文件的请全访问地址
         * @author: it
         */
        public String uploadFile(MultipartFile file) throws Exception {
            FileSource fileSource = getFileSource();
            FileTemplate fileTemplate = new FileTemplate(fileSource.getConnection());
            // 上传文件
            FileHandleStatus handleStatus = fileTemplate.saveFileByStream(file.getOriginalFilename(), file.getInputStream(), contentType);
            // 获取上传文件的访问地址
            String fileUrl = fileTemplate.getFileUrl(handleStatus.getFileId());
            // 关闭当前连接
            fileSource.shutdown();
            return handleStatus.getFileId() + StrUtil.DASHED + fileUrl;
        }
    /**
         * @description: 根据文件下载文件
         * @param: fid
         * @param: response
         * @param: fileName
         * @author: it
         */
        public void downloadFileByFid(HttpServletResponse response, HttpServletRequest request, String fid, String fileName) throws Exception {
            FileSource fileSource = getFileSource();
            FileTemplate fileTemplate = new FileTemplate(fileSource.getConnection());
            StreamResponse fileStream = fileTemplate.getFileStream(fid);
            // 设置响应头
            response.setContentType(CommonConstant.CONTENT_TYPE);
            response.setCharacterEncoding(CommonConstant.UTF_8);
            String encodeFileName = buildingFileNameAdapterBrowser(request, fileName);
            response.setHeader(CommonConstant.CONTENT_DISPOSITION, CommonConstant.ATTACHMENT_FILENAME + encodeFileName);
            // 读取并写入到响应输出
            InputStream inputStream = fileStream.getInputStream();
            byte[] fileByte = new byte[inputStream.available()];
            inputStream.read(fileByte);
            response.getOutputStream().write(fileByte);
            response.getOutputStream().flush();
            fileSource.shutdown();
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41

      具体使用案例如下:

    /**
         * @description: 上传文件
         * @param:
         * @param: file
         * @return:
         * @author: it
         * @date: 2022/7/14 17:01
         */
        @ResponseBody
        @RequestMapping("upload")
        public void uploadFile(MultipartFile file) {
            try {
                String fileUrl = seaweedFsUtil.uploadFile(file);
                System.out.println(fileUrl);
            } catch (Exception e) {
                log.error("TestSeaweedFsController uploadFile in error:{}", e);
            }
        }
    
        /**
         * @description: 下载文件
         * @param:
         * @param: fileId
         * @return:
         * @author: it
         * @date: 2022/7/14 17:01
         */
        @RequestMapping("download")
        public void downloadFile(HttpServletResponse response, HttpServletRequest request, String fileId, String fileName) {
            try {
                seaweedFsUtil.downloadFileByFid(response, request, fileId, fileName);
            } catch (Exception e) {
                log.error("TestSeaweedFsController downloadFile in error:{}", e);
            }
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35

    工具更新

      到此为止,轮子之王已集成的工具就介绍完毕了,后续还会不断更新、集成新的轮子,下面给大家介绍一下下一段时间项目的一些工作(如果读者有想要集成的轮子,欢迎提issue或者这文章下面留言):

    • 集成一个可视化界面,更好地介绍开源工具中各个轮子的引入案例,方便大家使用。
    • 集成word文件导出工具
    • 集成pdf文件导出工具
    • 集成复杂报表的报表导出工具(使用freemaker框架)
    • 待更新…

    集成方案介绍关联文章

    写在最后

      开源之路不容易,开源之心不忘记!如果博主开源的项目对您有所帮助,请给项目star,给博主更多动力,如果阅读文章给您有所帮助,请给博主点赞、关注。

      该开源项目会持续更新和维护,希望有更多读者能够提出建议和想法,如果有需要集成的工具,欢迎给项目提issue或者这文章下面留言,博主看到后会及时回复。

  • 相关阅读:
    PCB多层板生产工艺的起源与发展(一)
    【AI语言模型】阿里推出音视频转文字引擎
    POST_CRC
    计算机学院第五次ACM周赛题解
    Vue源码学习(二):<templete>渲染第一步,模板解析
    Gbase 国产数据库
    [资源推荐] 复旦大学张奇老师科研分享
    Linux【安全 02】OpenSSH漏洞修复(离线升级最新版本流程)网盘分享3个安装包+26个离线依赖
    吗西香豆素,CAS号:17692-56-7
    python自动创建sqlserver表并上传dataframe到创建的表中
  • 原文地址:https://blog.csdn.net/qq_40891009/article/details/126339452