POI下载excel通用方法

news2024/11/16 11:28:15

POI下载excel通用方法

最近遇到一个业务是需要下载excel,使用POI,这里记录一下实现过程

1、导包

  <dependency>
            <groupId>org.apache.poi</groupId>
            <artifactId>poi</artifactId>
            <version>3.9</version>
        </dependency>
        <dependency>
            <groupId>org.apache.poi</groupId>
            <artifactId>poi-ooxml</artifactId>
            <version>3.9</version>
        </dependency>

2.公共方法的编写

package com.pingan.esbx.cassandra.util;

import org.apache.commons.io.FileUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.math.NumberUtils;
import org.apache.poi.hssf.usermodel.*;
import org.apache.poi.ss.usermodel.CellStyle;
import org.apache.poi.ss.usermodel.IndexedColors;
import org.apache.poi.ss.util.CellRangeAddress;
import org.springframework.util.CollectionUtils;

import javax.servlet.http.HttpServletResponse;
import java.io.*;
import java.lang.reflect.Method;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.List;
import java.util.Objects;

public class ExcelDonload {
    /**
     * 26个英文字母表
     **/
    public static final String[] letters = {"A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z"};
    /**
     * 创建excel的行数(随描述 标题等的增加而增加)
     **/
    public static int rowNum = NumberUtils.INTEGER_ZERO;
    /**
     * 指定时间格式
     */
    public static DateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");

    /**
     * 下载
     *
     * @param title 标题
     * @param resultList 数据
     * @param fileName 文件名
     * @param tableTitles 表头
     * @param titlesInfoKey 表头对应的字段
     * @param subtitle      副标题
     * @param desc 描述
     * @param response
     */
    public static <T> void donloadExcel(
            String title,
            List<T> resultList,
            String fileName,
            String[] tableTitles,
            String[] titlesInfoKey,
            String subtitle,
            String[] desc,
            HttpServletResponse response

    ) {
        //1.参数校验
        if (CollectionUtils.isEmpty(resultList)
                || tableTitles.length <= NumberUtils.INTEGER_ZERO) {
            throw new RuntimeException("请求参数不正确!");
        }
        if (resultList.size() > 60000) {
            throw new RuntimeException("到处数据超过6w,不能导出!");
        }
        //2.创建Excel工作簿
        HSSFWorkbook workbook = new HSSFWorkbook();
        HSSFSheet sheet = workbook.createSheet();
        //3.设置excel的 描述、标题、副标题、表头
        setExcelTitle(workbook, sheet, title, tableTitles, subtitle, desc);
        //4.写入数据
        for (int i = 0; i < resultList.size(); i++) {
            T clazz = resultList.get(i);
            insertDataToCell(workbook, sheet, rowNum, clazz, titlesInfoKey);
        }
        //5.返回数据量
        File file = returnExcelDataStream(fileName, workbook);
        //6.导出
        buildResponseExcelFile(file, response);

    }

    /**
     * 下载文件流
     *
     * @param file
     * @param response
     */
    private static void buildResponseExcelFile(File file, HttpServletResponse response) {
        InputStream in = null;
        OutputStream out = null;

        try {
            in = new FileInputStream(file.getPath());
            response.reset();
            response.setHeader("Content-disposition", "attachment;filename=" + new String(file.getName().getBytes(), "iso-8859-1"));
            response.setContentType("application/octet-stream");
            response.addHeader("Context-Length", "" + file.length());
            response.setCharacterEncoding("utf-8");

            out = response.getOutputStream();
            int b;
            while ((b = in.read()) != -1) {
                out.write(b);
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            if (in != null) {
                try {
                    in.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            if (out != null) {
                try {
                    out.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }

        file.delete();
    }

    /**
     * 返回文件流
     *
     * @param fileName
     * @param workbook
     * @return
     */
    private static File returnExcelDataStream(String fileName, HSSFWorkbook workbook) {

        File file = null;
        try {

            String tempExcelPath = null;
            if (StringUtils.isNotBlank(fileName)) {
                tempExcelPath = File.separator + fileName + ".xls";
            } else {
                tempExcelPath = File.separator + "report.xls";
            }
            file = new File(tempExcelPath);
            file.deleteOnExit();
            file.createNewFile();
            FileOutputStream fileOutputStream = FileUtils.openOutputStream(file);
            workbook.write(fileOutputStream);
            fileOutputStream.close();
        } catch (Exception e) {
            e.printStackTrace();
        }
        return file;

    }


    /**
     * 通过反射获取字段值
     *
     * @param sheet
     * @param rowNum
     * @param clazz
     * @param titlesInfoKey
     * @param <T>
     */
    private static <T> void insertDataToCell(HSSFWorkbook workbook, HSSFSheet sheet, int rowNum, T clazz, String[] titlesInfoKey) {
        HSSFRow row = sheet.createRow(rowNum);
        row.setHeight((short) (15 * 20));
        for (int j = 0; j < titlesInfoKey.length; j++) {
            HSSFCell cell = row.createCell(j);
            HSSFCellStyle style5 = workbook.createCellStyle();
            style5.setAlignment(HSSFCellStyle.ALIGN_CENTER);
            style5.setVerticalAlignment(HSSFCellStyle.VERTICAL_CENTER);
            cell.setCellStyle(style5);

            //反射获取对象的值
            Object fieldValue = getValueByReflect(titlesInfoKey[j], clazz);

            String cellResult = null;
            //时间类型 Date 转换为字符串
            if (fieldValue instanceof Date) {
                cellResult = getStringTime((Date) fieldValue);
            } else {
                cellResult = Objects.isNull(fieldValue) ? "" : String.valueOf(fieldValue);
            }

            cell.setCellValue(cellResult);
        }
    }


    /**
     * 设置excel的 描述、标题、副标题、表头
     *
     * @param workbook
     * @param sheet
     * @param title
     * @param tableTitles
     * @param subtitle
     * @param desc
     */
    private static void setExcelTitle(HSSFWorkbook workbook,
                                      HSSFSheet sheet,
                                      String title,
                                      String[] tableTitles,
                                      String subtitle,
                                      String[] desc) {
        //合并单元格的行数 desc描述的数组项数+(beginTime && endTime)+title标题
        //$A$1:$I$1" 的含义是 第1行的A列到第1行的I列合并
        //计算要合并的行数
        int cellMergedRegionNm = 0;
        //描述的长度
        int descLength = 0;
        //当前要创建的excel的行数
        rowNum = 0;
        if (desc != null) {
            descLength = desc.length;
            cellMergedRegionNm += descLength;
            rowNum = descLength;
        }
        //统计时间栏
        if (StringUtils.isNotBlank(subtitle)) {
            cellMergedRegionNm += NumberUtils.INTEGER_ONE;
        }
        //标题栏
        if (StringUtils.isNotBlank(title)) {
            cellMergedRegionNm += NumberUtils.INTEGER_ONE;
        }
        //获取表头的数量(他决定了合并单元格的列数)
        int tableTitleLength = tableTitles.length;
        //获取表头的长度对应的字母
        String letter = getLetterByNum(tableTitleLength);
        //设置需合并的行数与列数(循环次数是行数 ,$A$1:$I$1中的A代表第一列,I代表列的最后一列)
        for (int i = 0; i < cellMergedRegionNm; i++) {
            sheet.addMergedRegion(CellRangeAddress.valueOf("$A$" + (i + 1) + ":$" + letter + "$" + (i + 1)));
        }
        //设置颜色
        HSSFPalette palette = workbook.getCustomPalette();
        palette.setColorAtIndex((short) 9, (byte) 240, (byte) 240, (byte) 240);
        palette.setColorAtIndex((short) 10, (byte) 255, (byte) 153, (byte) 102);
        palette.setColorAtIndex((short) 11, (byte) 100, (byte) 149, (byte) 137);
        palette.setColorAtIndex((short) 12, (byte) 176, (byte) 196, (byte) 222);
        //字体
        HSSFFont workbookFont = workbook.createFont();
        workbookFont.setFontName("仿宋");
        workbookFont.setFontHeightInPoints((short) 14);
        //字体
        HSSFFont titleFont = workbook.createFont();
        titleFont.setFontName("黑体");
        titleFont.setFontHeightInPoints((short) 18);
        titleFont.setColor(IndexedColors.WHITE.index);
        //单元格的风格1
        HSSFCellStyle descStyleLong = workbook.createCellStyle();
        descStyleLong.setFont(workbookFont);
        descStyleLong.setFillForegroundColor((short) 9);
        descStyleLong.setFillPattern(CellStyle.SOLID_FOREGROUND);
        //单元格的风格2
        HSSFCellStyle descStyleShort = workbook.createCellStyle();
        descStyleShort.setFont(workbookFont);
        descStyleShort.setFillForegroundColor((short) 10);
        descStyleShort.setFillPattern(CellStyle.SOLID_FOREGROUND);
        //单元格的风格3
        HSSFCellStyle titleStyle = workbook.createCellStyle();
        titleStyle.setFont(titleFont);
        titleStyle.setFillForegroundColor((short) 11);
        titleStyle.setFillPattern(CellStyle.SOLID_FOREGROUND);
        titleStyle.setAlignment(HSSFCellStyle.ALIGN_CENTER);
        titleStyle.setVerticalAlignment(HSSFCellStyle.VERTICAL_CENTER);
        //描述:设置描述,没有就不传
        HSSFRow row = null;
        HSSFCell cell = null;
        if (descLength > 0) {
            for (int i = 0; i < descLength; i++) {
                row = sheet.createRow(i);
                row.setHeight((short) (23 * 20));
                cell = row.createCell(0);
                cell.setCellValue(desc[i]);
                if (i >= 4) {
                    row.setHeight((short) (40 * 20));
                    cell.setCellStyle(descStyleShort);
                } else {
                    cell.setCellStyle(descStyleLong);
                }
            }
        }

        //设置标题:没有就不传
        if (StringUtils.isNoneBlank(title)) {

            row = sheet.createRow(rowNum);
            row.setHeight((short) (60 * 20));
            cell = row.createCell(0);
            cell.setCellValue(title);
            cell.setCellStyle(titleStyle);

            rowNum += NumberUtils.INTEGER_ONE;
        }
        HSSFCellStyle styleTimeRange = workbook.createCellStyle();
        styleTimeRange.setFont(titleFont);
        styleTimeRange.setFillForegroundColor((short) 11);
        styleTimeRange.setFillPattern(CellStyle.FINE_DOTS);
        styleTimeRange.setAlignment(HSSFCellStyle.ALIGN_CENTER);
        styleTimeRange.setVerticalAlignment(HSSFCellStyle.VERTICAL_CENTER);
        //设置时间范围
        if (StringUtils.isNotBlank(subtitle)) {

            row = sheet.createRow(rowNum);
            row.setHeight((short) (30 * 20));
            cell = row.createCell(0);
            cell.setCellValue(subtitle);
            cell.setCellStyle(styleTimeRange);
            rowNum += NumberUtils.INTEGER_ONE;
        }
        //设置表头字体
        HSSFFont tableTitleFont = workbook.createFont();
        tableTitleFont.setFontName("仿宋");
        tableTitleFont.setFontHeightInPoints((short) 14);
        tableTitleFont.setBoldweight(HSSFFont.BOLDWEIGHT_BOLD);
        //表头风格
        HSSFCellStyle tableTitleStyle = workbook.createCellStyle();
        tableTitleStyle.setFont(tableTitleFont);
        tableTitleStyle.setFillForegroundColor((short) 12);
        tableTitleStyle.setFillPattern(CellStyle.SOLID_FOREGROUND);
        tableTitleStyle.setAlignment(HSSFCellStyle.ALIGN_CENTER);
        tableTitleStyle.setVerticalAlignment(HSSFCellStyle.VERTICAL_CENTER);
        tableTitleStyle.setLeftBorderColor(IndexedColors.WHITE.index);
        tableTitleStyle.setRightBorderColor(IndexedColors.WHITE.index);
        tableTitleStyle.setTopBorderColor(IndexedColors.WHITE.index);
        tableTitleStyle.setBottomBorderColor(IndexedColors.WHITE.index);
        tableTitleStyle.setBorderLeft(HSSFCellStyle.BORDER_THIN);
        tableTitleStyle.setBorderTop(HSSFCellStyle.BORDER_THICK);
        tableTitleStyle.setBorderRight(HSSFCellStyle.BORDER_THICK);
        tableTitleStyle.setBorderBottom(HSSFCellStyle.BORDER_THICK);

        if (tableTitles != null && tableTitles.length > 0) {
            row = sheet.createRow(rowNum);

            row.setHeight((short) (41.2 * 20));

            for (int i = 0; i < tableTitles.length; i++) {
                cell = row.createCell(i);
                String tableTitle = tableTitles[i];
                cell.setCellValue(tableTitle);
                cell.setCellStyle(tableTitleStyle);
                //根据标题长短设置单元格的宽窄
                sheet.setColumnWidth(i, (tableTitle.length() * 5) * 256);

            }
            rowNum += NumberUtils.INTEGER_ONE;
        }
    }

    private static String getLetterByNum(int tableTitleLength) {
        return letters[tableTitleLength - NumberUtils.INTEGER_ONE];
    }

    /**
     * 返回指定时间的指定字符串格式 yyyy-MM-dd HH:mm:ss
     * SimpleDateFormat 线程不安全 所以枷锁
     */
    public synchronized static String getStringTime(Date date) {
        String format = dateFormat.format(date);
        return format;
    }

    /**
     * 通过反射获取字段值(通过get方法)
     *
     * @param fieldName
     * @param t
     * @param <T>
     * @return
     */
    public static <T> Object getValueByReflect(String fieldName, T t) {
        String methodName = "get" + fieldName.substring(0, 1).toUpperCase() + fieldName.substring(1);
        try {
            Method method = t.getClass().getMethod(methodName);
            Object fieldValue = method.invoke(t);
            return fieldValue;
        } catch (Exception e) {
            return null;
        }
    }
}

3.调用示例

@RestController
@RequestMapping("/excel")
public class ExcelController {
    private static final String[] TITLES_NONEXP_INFO_KEY = {
            "time",
            "consumerCompany",
            "consumerSystem",
            "consumerCode",
            "providerCompany",
            "providerSystem",
            "providerCode",
            "failCount",
            "failRatio",
            "totalCount"
    };
    private static final String[] TITLES_NONEXP_INFO = {
            "时  间", "消费方公司", "消费方系统",
            "消费方编码", "服务方公司",
            "服务方系统", "服务方编码", "失败次数", "失败率", "总数"
    };


    @GetMapping("/exportExcel")
    public void exportExcel(HttpServletRequest request, HttpServletResponse response) {
        String title = "INVALID 月报表";
        List<ReportDTO> list = new ArrayList<>();
        String inputParams = "111111";

        ReportDTO reportDTO = new ReportDTO();
        reportDTO.setTime(new Date());
        reportDTO.setConsumerCompany("集团总部");
        reportDTO.setConsumerSystem("文件处理系统");
        reportDTO.setConsumerCode("EIP_DPS");
        reportDTO.setProviderCompany("中国科技");
        reportDTO.setProviderSystem("中国智者统一搜索平台");
        reportDTO.setProviderCode("PA011-ZHIZHE-USP-SE_PZHIZHE_ESG");
        reportDTO.setFailCount(100);
        reportDTO.setFailRatio(0.34);
        reportDTO.setTotalCount(340);

        list.add(reportDTO);
        String fileName = "我的测试";
        String[] desc = {
                "报表中数据排序方法:",
                "1.选中待排序的数据区域",
                "2.excel菜单栏:【开始】->【格式】->【设置单元格】->【对齐】->【文本控制】:取消\"合并单元格\"选项\"",
                "3.excel菜单栏:【开始】->【排序和筛选】->【自定义排序】",
                "查询条件:",
                JSON.toJSONString("这里可以写自己的查询条件")
        };
        String beginTime = "2023-7-6";
        String endTime = "2023-7-7";
        String subtitle = "统计时间范围【" + beginTime + "," + endTime + "】";
        ExcelDonload.donloadExcel(
                title,
                list,
                fileName,
                TITLES_NONEXP_INFO,
                TITLES_NONEXP_INFO_KEY,
                subtitle,
                desc,
                response);

    }
}

4.实体类

@Data
public class ReportDTO implements Serializable {
    private Date time;
    private String consumerCompany;
    private String consumerSystem;
    private String consumerCode;
    private String providerCompany;
    private String providerSystem;
    private String providerCode;
    private Integer failCount;
    private Double failRatio;
    private Integer totalCount;
}

5.下载效果

在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/734856.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

本周大新闻|传微软曾考虑收购Niantic;腾讯引进Quest挑战重重

本周XR大新闻&#xff0c;AR方面&#xff0c;传微软曾考虑收购AR头部公司Niantic&#xff1b;Q-PIXEL公布5000PPI可调色Micro LED&#xff1b;三星智能眼镜商标曝光&#xff1b;Humane公布首款产品Ai Pin&#xff1b;空客推企业级AR解决方案。 VR方面&#xff0c;Vision Pro销…

边缘计算那些事儿-漫谈网络切片关键技术

0、背景 网络切片作为一种比较前沿的技术&#xff0c;当前并没有太多系统的资料可以学习&#xff0c;很多的技术资料都是比较分散地分布在论文和一些技术博客中&#xff0c;笔者当前是通过论文的解读获取相关的技术信息&#xff0c;在过程中笔者总结了相关的技术栈&#xff0c;…

pytorch多分类问题 CrossEntropyLoss()函数的输入size/shape不一致问题

在使用pytorch实现一个多分类任务的时候&#xff0c;许多多分类任务在训练过程中都会有如下的代码&#xff1a; criterion nn.CrossEntropyLoss() loss criterion(output, target) # output.size : [batch_size, class_num] # target.size : [batch_size]许多的初学者会卡在…

Kubernetes 容器类型 Init - pause - sidecar - app容器

目录 Kubernetes 的容器类型 Init 初始化容器 参考文档&#xff1a;Init 容器 | Kubernetes 使用 Init 容器的情况 案例&#xff1a;定义了一个具有 2 个 Init 容器的简单 Pod 你通过运行下面的命令启动 Pod&#xff1a; 发现两个Init容器都没有运行成功 查看更多详细…

一些行业报告--From 艾瑞咨询

一些行业报告--From 艾瑞咨询 1 介绍2 机械臂行业研究 [From 艾瑞咨询 -- 中国工业机器人行业研究报告&#xff08;2023&#xff09;2.1 发展历程2.2 中国工业机器人相关政策2.3 产业链2.4 三大部分六大系统2.5 伺服&控制器 主要玩家 及 关键指标及难点2.6 减速机 主要玩家…

mysql中根据已有的表来创建新表的三种方式

mysql根据现有表创建新表 1、语法1&#xff1a;CREATE TABLE new_tbl LIKE orig_tbl; 1、1 根据departments表创建新表departments1 departments 表结果和表数据库如下 创建departments1如下 使用命令&#xff1a; CREATE TABLE departments1 LIKE departments; 这种语法&…

GEE:在地图上添加时间滑动条,以交互式可视化不同年份影像

作者:CSDN @ _养乐多_ 本文将介绍在Google Earth Engine(GEE)平台上的地图显示区域创建一个交互式界面,可以为用户添加一个时间滑动条,通过滑动条可以选择显示不同年份的遥感影像。 结果如下图所示, 文章目录 一、代码二、代码链接一、代码 // 使用滑块从图像集合中选…

Auto-Rig Pro 手指控制器骨骼(IK-FK)

选中手指控制器骨骼,在tool面板里看到snap IK-FK, IK-FK,还有snap all to IK 和 FK: 这些都是Auto-Rig Pro提供的一些工具&#xff0c;可以让您在IK&#xff08;反向动力学&#xff09;和FK&#xff08;正向动力学&#xff09;之间切换和同步。IK和FK是两种不同的绑定方式&…

43. 间断连续登录用户问题

文章目录 题目需求思路一实现一题目来源 题目需求 现有各用户的登录记录表&#xff08;login_events&#xff09;如下&#xff0c;表中每行数据为&#xff1a;一个用户何时登录了平台。 现要求统计各用户最长的连续登录天数&#xff0c;间断一天也算作连续&#xff0c;例如&a…

git安装及初步使用

git的安装 &#xff1a; 在CentOS 7.6环境下可以使用一条语句就能安装git yum -y install git如果上面命令包以下错误&#xff0c;说明权限不够 [leijiefl ~]$ yum -y install git Loaded plugins: fastestmirror You need to be root to perform this command.可以转换成ro…

神经网络学习小记录74——Pytorch 设置随机种子Seed来保证训练结果唯一

神经网络学习小记录74——Pytorch 设置随机种子Seed来保证训练结果唯一 学习前言为什么每次训练结果不同什么是随机种子训练中设置随机种子 学习前言 好多同学每次训练结果不同&#xff0c;最大的指标可能会差到3-4%这样&#xff0c;这是因为随机种子没有设定导致的&#xff0…

电源频率检测器/采用555时基电路的过流检测器电路设计

电源频率检测器 对于某些电子仪器和电气设备&#xff0c;对见六电源的频率有着一定的要求&#xff0c;电源频率高于或低于 50Hz&#xff0c;都会影响设备的正常工作&#xff0c;甚至造成仪器和设备的损坏。因此&#xff0c;对于此类设备需要装设电源频率检测装置&#xff0c;当…

Linux开发工具之【vim】

Linux开发工具之【vim】 文章目录&#xff1a; Linux开发工具之【vim】1. Linux软件包管理器yum1.1 查看软件1.2. 下载软件1.3 卸载软件 2. vim编辑器的使用2.1 vim常用模式2.2 vim基本操作2.3 vim命令模式命令集2.3.1 移动光标2.3.2 删除文字2.3.3 复制文本内容2.3.4 替换文本…

Openpose原理总结

Openpose是一种开源的实时多人姿态估计库&#xff0c;由卡耐基梅隆大学开发。它通过分析图像或视频中的人体关键点来估计人体的姿态&#xff0c;识别身体的各个部分&#xff0c;并推断出人体的姿势信息。 Openpose能够同时检测和跟踪多个人的姿态&#xff0c;可以用于人机交互、…

二.《泽诺尼亚》明文CALL

了解发包函数 1.一款网络游戏,必定是会发包的,对于PC端而言,想要进行网络通讯,就拿最简单的CS架构而言势必会调用win32 API函数或底层函数 2.这里列举出常用的API如:send sendto wsasend wspsend 3.有一些正向开发经验的同学,肯定是见过这几个函数的 4.接下来我们来看看这款…

JavaEE——介绍并简单使用线程池

文章目录 一、 什么是线程池二、Java中线程池的运用1. 创建线程池中的问题2. 标准库中线程池的使用 三、自主实现一个简单的线程池 一、 什么是线程池 所谓线程池&#xff0c;其实和字符串常量池&#xff0c;数据库连接池十分相似&#xff0c;就是设定一块区域&#xff0c;提前…

打印机常见故障解决参考方法

1、首先检查打印机电源线连接是否可靠或电源指示灯是否点亮&#xff0c;然后再次打印文件&#xff0c;仍不能打印&#xff0c;请看下一步。 2、检查打印机与计算机之间的信号传输线是否可靠连接&#xff0c;检查并重新连接&#xff0c;如果打印机仍不能打印&#xff0c;请看下一…

Java线程Thread类常用方法

文章目录 1. start()&#xff1a;启动线程&#xff0c;使其执行run()方法中的代码。2. run()&#xff1a;线程的执行逻辑&#xff0c;需要在该方法中定义线程要执行的代码。3. sleep(long millis)&#xff1a;使当前线程暂停指定的毫秒数&#xff0c;进入阻塞状态。4. join()&a…

【C++】红黑树封装map和set

文章目录 一、map和set源码剖析二、红黑树的迭代器1.begin()与end()2.operator()与operator--() 三、set的模拟实现四、map的模拟实现五、完整代码实现1.RBTree.h2.set.h3.map.h5.Test.cpp 一、map和set源码剖析 我们知道&#xff0c;map和set的底层是红黑树&#xff0c;但是我…

如何用Python快速搭建一个文件传输服务

当我的朋友需要把他电脑上面的文件从他的电脑传递到我电脑上的时候&#xff0c;我只需要启动服务 启动服务&#xff01; 他打开web界面 就能把文件传递到我电脑上&#xff08;还能够实时显示进度&#xff09; 文件就已经在我电脑上的uploads文件夹里面了 项目结构如下 templat…