Java根据excel模版导出Excel(easyexcel、poi)——含项目测试例子拿来即用

news2024/10/2 20:30:23

Java根据excel模版导出Excel(easyexcel、poi)——含项目测试例子拿来即用

  • 1. 前言
    • 1.1 关于Excel的一般导出
    • 2.2 关于easyexcel的根据模版导出
  • 2. 先看效果
    • 2.1 模版
    • 2.2 效果
  • 3. 代码实现(核心代码)
    • 3.1 项目代码结构
    • 3.2 静态填充例子代码
    • 3.3 动态list填充代码
    • 3.4 附核心代码
      • 3.4.1 object转map工具类
      • 3.4.2 根据模版导出Excel程序代码
      • 3.4.3 导出工具类入口代码
  • 4. 附项目
    • 4.1 一般导出项目代码
    • 4.2 根据模版导出项目代码

1. 前言

1.1 关于Excel的一般导出

  • 一般列表导出以及个性化样式设置请看下面的文章:
    • JAVA导出Excel通用工具类——第一篇:详细介绍POI 导出excel的多种复杂情况,包括动态设置筛选、动态合并横向(纵向)单元格等多种复杂情况.
    • JAVA导出Excel通用工具——第二篇:使用EasyExcel导出excel的多种情况的例子介绍.

2.2 关于easyexcel的根据模版导出

  • 如果使用easy Excel的话,下面就不用看了,这个官网关于怎么使用以及例子提供的非常详细,git上还能下载源码,官网如下,使用不再介绍,具体看官网即可:
    Easy Excel 之 填充excel.

2. 先看效果

2.1 模版

  • 静态填充简单模版如下:
    在这里插入图片描述
  • 动态填充简单模版:
    • 单个list:
      在这里插入图片描述
    • 多个list:
      在这里插入图片描述
    • 单个list单条数据:
      在这里插入图片描述

2.2 效果

  • 静态填充效果如下:
    在这里插入图片描述
  • 动态填充效果如下:
    • 单个list:
      在这里插入图片描述
    • 多个list:
      在这里插入图片描述
    • 单个list单条数据:
      在这里插入图片描述

3. 代码实现(核心代码)

3.1 项目代码结构

  • 如下:
    在这里插入图片描述

3.2 静态填充例子代码

  • 工具类代码已封装,所以调用很简单即可实现,如下:
    在这里插入图片描述

3.3 动态list填充代码

  • 单个list:
    在这里插入图片描述
  • 多个list
    在这里插入图片描述
  • 单个list单条数据:
    在这里插入图片描述

3.4 附核心代码

3.4.1 object转map工具类

  • MapObjectUtil.java 如下:
    package com.liu.susu.excel.template.poi.common;
    
    import com.alibaba.fastjson.JSONObject;
    import com.liu.susu.excel.template.poi.example.data.DogEntity2;
    import org.apache.commons.beanutils.BeanMap;
    
    import java.lang.reflect.Field;
    import java.util.ArrayList;
    import java.util.HashMap;
    import java.util.List;
    import java.util.Map;
    
    /**
     * @Description
     * @Author susu
     * @Date 2024/2/19
     */
    public class MapObjectUtil {
    
        /**
        * @description: 将object的list数据 转换成 map的list(如:List<Map<String, Object>>)
        * @param objDataList
        * @return java.util.List<java.util.Map<java.lang.String,java.lang.Object>>
        * @author susu
        */
        public static List<Map<String, Object>> objListToMapList(List<?> objDataList){
            List<Map<String, Object>> dataList = new ArrayList<>();
            if (objDataList==null || objDataList.size()<1){
                return null;
            }
            objDataList.forEach(obj->{
                try {
                    Map<String, Object> map = MapObjectUtil.objectToMap(obj);
                    dataList.add(map);
                } catch (IllegalAccessException e) {
                    throw new RuntimeException(e);
                }
            });
            return dataList;
        }
    
        /**
        * @description: 将object数据转换成map数据
        * @param obj
        * @return java.util.Map<java.lang.String,java.lang.Object>
        * @author susu
        */
        public static Map<String, Object> objectToMap(Object obj) throws IllegalAccessException {
            Map<String, Object> map = new HashMap();
            Class<?> cla = obj.getClass();
            Field[] fields = cla.getDeclaredFields();
            for (Field field : fields) {
                field.setAccessible(true);
                String keyName = field.getName();
                Object value = field.get(obj);
                if (value == null)
                    value = "";
                map.put(keyName, value);
            }
            return map;
        }
    
        /**
        * @description: 使用 JSONObject 将object转换成map
        * @param obj
        * @return java.util.Map<?,?>
        * @author susu
        */
        public static Map<?, ?> objectToMap2(Object obj) {
            if (obj == null)
                return null;
            return JSONObject.parseObject(JSONObject.toJSONString(obj),Map.class);
        }
    
        /**
        * @description: 使用BeanMap将object转换成map
        * @param obj
        * @return java.util.Map<?,?>
        * @author susu
        */
        public static Map<?, ?> objectToMap3(Object obj) {
            if (obj == null)
                return null;
            return new BeanMap(obj);
        }
    
    
        public static void main(String[] args) {
            DogEntity2 dog = new DogEntity2();
            dog.setDogId("A-1001");
            dog.setDogAge(3);
            dog.setDogName("aaa");
    //        Map map = JSONObject.parseObject(JSONObject.toJSONString(dog),Map.class);
            Map map = objectToMap2(dog);
            System.out.println(map);
        }
    
    }
    

3.4.2 根据模版导出Excel程序代码

  • ExcelTemplateProc.java 如下:
    package com.liu.susu.excel.template.poi.common;
    
    import org.apache.commons.lang3.StringUtils;
    import org.apache.poi.ss.usermodel.CellCopyPolicy;
    import org.apache.poi.ss.usermodel.Workbook;
    import org.apache.poi.xssf.usermodel.XSSFCell;
    import org.apache.poi.xssf.usermodel.XSSFRow;
    import org.apache.poi.xssf.usermodel.XSSFSheet;
    import org.apache.poi.xssf.usermodel.XSSFWorkbook;
    import org.springframework.util.ResourceUtils;
    
    
    import java.io.*;
    import java.util.List;
    import java.util.Map;
    
    /**
     * @Description 根据模版导出Excel程序
     * @Author susu
     * @Date 2024/2/19
     */
    public class ExcelTemplateProc {
    
        /**
         * @param templateFileName
         * @param exportFilePathAndName
         * @param staticDataMap
         * @param dynamicDataMappingList
         * @return void
         * @description: 根据模版导出Excel入口
         * @author susu
         * @date 2024/2/20
         */
        public static void doExportExcelByTemplateProc(String templateFileName, String exportFilePathAndName,
                                                       Map<String, Object> staticDataMap,
                                                       List<DynamicDataMapping> dynamicDataMappingList) throws IOException {
            /**
             * 1. 从resources下加载模板并替换
             *    使用 ResourceUtils 加载文件
             */
            File file = ResourceUtils.getFile("classpath:"+templateFileName);
            InputStream inputStream = new FileInputStream(file);
    
            Workbook workbook = dealFirstSheetByTemplate(inputStream, staticDataMap, dynamicDataMappingList);
            // 2. 保存到本地
            saveExportFile(workbook, exportFilePathAndName);
        }
    
        /**
         * @param workbook
         * @param excelFilePath
         * @return void
         * @description: 保存导出的Excel文件到服务器
         * @author susu
         * @date 2024/2/20
         */
        public static void saveExportFile(Workbook workbook, String excelFilePath) throws IOException {
            FileOutputStream outputStream = new FileOutputStream(excelFilePath);
            executeWorkBookWrite(workbook, outputStream);
        }
    
        /**
         * @param workbook
         * @param outputStream
         * @return void
         * @description: 数据输出
         * @author susu
         * @date 2024/2/20
         */
        public static void executeWorkBookWrite(Workbook workbook, OutputStream outputStream) throws IOException {
            workbook.write(outputStream);
            outputStream.flush();
            outputStream.close();
            workbook.close();
        }
    
        /**
         * @param inputStream
         * @param staticDataMap
         * @param dynamicDataMappingList
         * @return org.apache.poi.ss.usermodel.Workbook
         * @description: 处理只有一个sheet页的模版
         * @author susu
         * @date 2024/2/20
         */
        public static Workbook dealFirstSheetByTemplate(InputStream inputStream,
                                                        Map<String, Object> staticDataMap,
                                                        List<DynamicDataMapping> dynamicDataMappingList) throws IOException {
            XSSFWorkbook workbook = new XSSFWorkbook(inputStream);
            XSSFSheet sheet = workbook.getSheetAt(0);
            // 按模板处理sheet页
            dealSheetDataByTemplate(sheet, staticDataMap, dynamicDataMappingList);
            return workbook;
        }
    
        /**
         * @param sheet
         * @param staticDataMap
         * @param dynamicDataMappingList
         * @return void
         * @description: 按模板处理sheet页里的数据
         * @author susu
         * @date 2024/2/19
         */
        private static void dealSheetDataByTemplate(XSSFSheet sheet, Map<String, Object> staticDataMap, List<DynamicDataMapping> dynamicDataMappingList) {
            // 循环sheet里每一行
            for (int i = sheet.getFirstRowNum(); i <= sheet.getLastRowNum(); i++) {
                XSSFRow row = sheet.getRow(i);
                DynamicDataMapping dynamicDataMapping = getDynamicRowDataByMatch(row, dynamicDataMappingList);
                if (dynamicDataMapping != null) {
                    i = getTemplateLastRowIndexAfterDealTemplate(sheet, i, dynamicDataMapping);
                } else {
                    dealTemplateDataRow(row, null, staticDataMap);
                }
            }
        }
    
        /**
         * @param row
         * @param dataMap
         * @param dataPrefix
         * @return void
         * @description: 循环处理模版中每行的数据
         * @author susu
         * @date 2024/2/20
         */
        private static void dealTemplateDataRow(XSSFRow row, String dataPrefix, Map<String, Object> dataMap) {
            if (dataMap == null) {
                return;
            }
            for (int i = row.getFirstCellNum(); i < row.getLastCellNum(); i++) {
                XSSFCell cell = row.getCell(i);
                fillInTemplateCellDataValue(cell, dataPrefix, dataMap);
            }
        }
    
        /**
         * @param cell
         * @param dataPrefix
         * @param dataMap
         * @return void
         * @description: 填充模版里单元格的值
         * @author susu
         * @date 2024/2/20
         */
        private static void fillInTemplateCellDataValue(XSSFCell cell, String dataPrefix, Map<String, Object> dataMap) {
            if (cell == null) {
                return;
            }
            String cellValue = cell.getStringCellValue();//获取模版里设置的数据
            if (StringUtils.isEmpty(cellValue)) {
                return;
            }
            boolean flag = false;
            dataPrefix = StringUtils.isEmpty(dataPrefix) ? "" : (dataPrefix + ".");
            for (Map.Entry<String, Object> entry : dataMap.entrySet()) {
                // 循环所有,因为可能一行有多个占位符
                String cellTemplateStr = "{{" + dataPrefix + entry.getKey() + "}}";
                if (cellValue.contains(cellTemplateStr)) {
                    // 替换模版中单元格的数据
                    cellValue = cellValue.replace(cellTemplateStr, entry.getValue() == null ? "" : entry.getValue().toString());
                    flag = true;
                }
            }
            if (flag) {
                cell.setCellValue(cellValue);
            }
        }
    
        /**
         * @param row
         * @param dynamicDataMappingList
         * @return com.liu.susu.excel.template.poi.common.DynamicDataMapping
         * @description: 通过模版sheet中的行数据 与 动态数据匹配,获取此行需要填充的动态数据
         * @author susu
         * @date 2024/2/21
         */
        private static DynamicDataMapping getDynamicRowDataByMatch(XSSFRow row, List<DynamicDataMapping> dynamicDataMappingList) {
            if (dynamicDataMappingList == null || dynamicDataMappingList.size() < 1) {
                return null;
            }
            for (int j = row.getFirstCellNum(); j < row.getLastCellNum(); j++) {
                XSSFCell cell = row.getCell(j);
                String value = cell.getStringCellValue();
                if (value != null) {
                    for (DynamicDataMapping dynamicData : dynamicDataMappingList) {
                        if (value.startsWith("{{" + dynamicData.getDataId() + ".")) {
                            return dynamicData;
                        }
                    }
                }
            }
            return null;
        }
    
        /**
         * @param sheet
         * @param rowIndex
         * @param dynamicDataMapping
         * @return int
         * @description: 根据动态数据的条数动态复制模版行,每处理一个类型的list返回最后的行数,进而处理下一个类型的list
         * @author susu
         * @date 2024/2/20
         */
        private static int getTemplateLastRowIndexAfterDealTemplate(XSSFSheet sheet, int rowIndex, DynamicDataMapping dynamicDataMapping) {
            if (dynamicDataMapping == null) {
                return rowIndex;
            }
            int dataRows = dynamicDataMapping.getDataList().size();
            // 需要拷贝的行数(因为模板行本身占1行,所以-1)
            int copyRows = dataRows - 1;
            if (copyRows > 0) {
                /**
                 * shiftRows: 从动态数据模版行(rowIndex)到最后一行,这些全部行都向下移copyRows行
                 *            相当于模版行上面插入n行空行(n=copyRows)
                 */
                sheet.shiftRows(rowIndex, sheet.getLastRowNum(), copyRows, true, false);
                // 拷贝策略
                CellCopyPolicy cellCopyPolicy = makeCellCopyPolicy();
                // 因为从模版行开始向下平移了copyRows行,所以这里 模板行=rowIndex + copyRows,
                int templateDataRow = rowIndex + copyRows;
                // 因为模版行上新增了空行,所以要把模板所在行的模版 拷贝到上面新增的空行
                for (int i = 0; i < copyRows; i++) {
                    //templateDataRow-模版行数据   rowIndex + i循环的当前空行
                    sheet.copyRows(templateDataRow, templateDataRow, rowIndex + i, cellCopyPolicy);
                }
            }
            // 循环模版行:动态替换模版行(将模版行里的模版替换成动态数据)
            for (int j = rowIndex; j < rowIndex + dataRows; j++) {
                Map<String, Object> dataMap = dynamicDataMapping.getDataList().get(j - rowIndex);
                dealTemplateDataRow(sheet.getRow(j), dynamicDataMapping.getDataId(), dataMap);
            }
            return rowIndex + copyRows;
        }
    
        /**
         * @param
         * @return org.apache.poi.ss.usermodel.CellCopyPolicy
         * @description: 拷贝策略
         * @author susu
         * @date 2024/2/20
         */
        public static CellCopyPolicy makeCellCopyPolicy() {
            CellCopyPolicy cellCopyPolicy = new CellCopyPolicy();
            cellCopyPolicy.setCopyCellValue(true);
            cellCopyPolicy.setCopyCellStyle(true);
            return cellCopyPolicy;
        }
    
    
    }
    
    

3.4.3 导出工具类入口代码

  • ExportExcelByTemplateUtils.java 如下:
    package com.liu.susu.excel.template.poi.common;
    
    import java.util.HashMap;
    import java.util.List;
    import java.util.Map;
    
    /**
     * @Description 根据模版导出Excel工具类
     * @Author susu
     * @Date 2024/2/19
     */
    public class ExportExcelByTemplateUtils {
    
        /**
        * @description: 根据模版导出Excel入口(单个list数据)
        * @param templateFileName
        * @param exportFilePathAndName
        * @param staticDataMap
        * @param dataId
        * @param originDataList
        * @return void
        * @author susu
        * @date 2024/2/21
        */
        public static void doExportExcelOneListByTemplate(String templateFileName, String exportFilePathAndName,
                                                          Map<String, Object> staticDataMap,
                                                          String dataId,
                                                          List<?> originDataList) throws Exception{
    
            List<Map<String, Object>> exportDataList = MapObjectUtil.objListToMapList(originDataList);
            // 只有一个list数据
            List<DynamicDataMapping> dynamicDataMappingList = DynamicDataMapping.createOneDataList(dataId, exportDataList);
            // 导出
            ExcelTemplateProc.doExportExcelByTemplateProc(templateFileName,exportFilePathAndName,staticDataMap,dynamicDataMappingList);
    
        }
    
        /**
        * @description: 根据模版导出Excel入口(多个list数据)
        * @param templateFileName
        * @param exportFilePathAndName
        * @param staticSource
        * @param originDataMapList
        * @return void
        * @author susu
        * @date 2024/2/20
        */
        public static void doExportExcelMoreListByTemplate(String templateFileName,
                                                   String exportFilePathAndName,
                                                   Map<String, Object> staticSource,
                                                   Map<String, List<?>> originDataMapList) throws Exception{
    
            Map<String,List<Map<String, Object>>> transMap = new HashMap<>();
            originDataMapList.forEach((dataId,originDataList)->{
                List<Map<String, Object>> transDataList = MapObjectUtil.objListToMapList(originDataList);
                transMap.put(dataId,transDataList);
            });
            // 多个list类型数据
            List<DynamicDataMapping> dynamicDataMappingList = DynamicDataMapping.createMorDataList(transMap);
            // 导出
            ExcelTemplateProc.doExportExcelByTemplateProc(templateFileName,exportFilePathAndName,staticSource,dynamicDataMappingList);
    
        }
    
    }
    

4. 附项目

4.1 一般导出项目代码

  • 如下:
    Java导出excel工具详细介绍(POI 和 EasyExcel),各种复杂需求情况的导出(包括动态设置合并单元格等).

4.2 根据模版导出项目代码

  • 如下:
    Java根据自定义模版导出各种需求的Excel(使用POI).

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

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

相关文章

数学建模【GM(1, 1)灰色预测】

一、GM(1, 1)灰色预测简介 乍一看&#xff0c;这个名字好奇怪&#xff0c;其实是有含义的 G&#xff1a;Grey&#xff08;灰色&#xff09;M&#xff1a;Model&#xff08;模型&#xff09;(1, 1)&#xff1a;只含有一个变量的一阶微分方程模型 提到灰色&#xff0c;就得先说…

【已解决】解决Win11忘记开机密码(不用重装系统)

问题起因 因为在实验室的电脑从过年就没有用过&#xff0c;也不知道为什么记性这么差&#xff0c;就把电脑密码忘了&#xff0c;但是又不想用系统盘重装电脑。于是从网上整理一些文章&#xff0c;最后写了下面一篇解决方法 解决方法 1.首先在登录界面&#xff08;输入密码那…

深入探索 JS 的提升机制、函数与块作用域以及函数表达式和声明(下)

&#x1f90d; 前端开发工程师、技术日更博主、已过CET6 &#x1f368; 阿珊和她的猫_CSDN博客专家、23年度博客之星前端领域TOP1 &#x1f560; 牛客高级专题作者、打造专栏《前端面试必备》 、《2024面试高频手撕题》 &#x1f35a; 蓝桥云课签约作者、上架课程《Vue.js 和 E…

合并3D线条模型怎样进行调整长度---模大狮模型网

在3D建模软件中合并3D线条模型后&#xff0c;要调整线条的长度可以通过以下步骤进行&#xff1a; 选择线条模型&#xff1a;首先&#xff0c;在3D建模软件中选择您要调整长度的线条模型。这通常涉及使用选择工具或者鼠标点击线条模型来进行选择。 使用拉伸工具&#xff1a;大多…

采访影视行业艺术指导“Sora入局,或将改变游戏规则?”

自OpenAI发布Sora已经过去了半个月&#xff0c;人们对于这个新兴的“文生视频”&#xff08;text-to-video&#xff09;大模型工具都已经有了初步的认识&#xff0c;经过半个月的沉淀&#xff0c;他们也陆续发布了一些更加令人震惊的demo&#xff0c;话不多说&#xff0c;我们先…

大厂性能测试监控指标及分析调优指南

一、哪些因素会成为系统的瓶颈 CPU&#xff1a;如果存在大量的计算&#xff0c;他们会长时间不间断的占用CPU资源&#xff0c;导致其他资源无法争夺到CPU而响应缓慢&#xff0c;从而带来系统性能问题&#xff0c;例如频繁的FullGC&#xff0c;以及多线程造成的上下文频繁的切换…

Jqgrid入门

最近要用Jqgrid做项目&#xff0c;之前都没怎么接触过&#xff0c;看了看官网有一个小demo&#xff0c;于是下下来后&#xff0c;发现这个demo有点问题&#xff0c;度娘了一下&#xff0c;发现有的博主直接贴官网的代码&#xff0c;截了个图&#xff0c;我真是***&#xff0c;还…

【Java程序设计】【C00313】基于Springboot的物业管理系统(有论文)

基于Springboot的物业管理系统&#xff08;有论文&#xff09; 项目简介项目获取开发环境项目技术运行截图 项目简介 这是一个基于Springboot的物业管理系统&#xff0c;本系统有管理员、物业、业主以及维修员四种角色权限&#xff1b; 管理员进入主页面&#xff0c;主要功能包…

protobuf简单使用(二)

介绍 上一节中&#xff0c;我们介绍了protobuf&#xff0c;简单来说&#xff0c;它是一种消息数据格式&#xff0c;其作用类似于json&#xff0c;但是比json的使用效率要高。 除此以外&#xff0c;我们介绍了protobuf的简单使用&#xff0c;也就是如何可以像使用json一样&…

matplotlib plt.show()却弹出空白框并之后自动退出程序的原因及解决方法

运行下列代码并使用plt.show()进行展示时候&#xff0c;cmd输出如下&#xff1a; 先弹出空白框&#xff1a; 而后直接退出程序&#xff1a; 之前遇到过很多次&#xff0c;由于不输出Traceback&#xff0c;完全不知道什么原因。结果发现是因为没有导入torch导致的。 解决办法就…

电商平台商品详情api数据一键采集

批量采集电商平台商品详情API数据的步骤如下&#xff1a; 1. 了解目标电商平台&#xff1a;首先&#xff0c;你需要了解目标电商平台的API文档和规则。不同的电商平台可能有不同的API接口和限制&#xff0c;需要熟悉这些信息。 2. 获取API访问权限&#xff1a;在采集数据之前…

【C++】类与对象——友元,内部类,匿名对象

类与对象 1 友元1.1 概念&#xff1a;1.2 友元函数1.3 友元类 2 内部类概念&#xff1a;特性&#xff1a;举例&#xff1a; 3 匿名对象Thanks♪(&#xff65;ω&#xff65;)&#xff89;谢谢阅读&#xff01;&#xff01;&#xff01;下一篇文章见&#xff01;&#xff01;&am…

基于Java的艺培管理解决方案

✍✍计算机毕业编程指导师 ⭐⭐个人介绍&#xff1a;自己非常喜欢研究技术问题&#xff01;专业做Java、Python、微信小程序、安卓、大数据、爬虫、Golang、大屏等实战项目。 ⛽⛽实战项目&#xff1a;有源码或者技术上的问题欢迎在评论区一起讨论交流&#xff01; ⚡⚡ Java、…

Canvas动画之豌豆射手

&#x1f339;作者主页&#xff1a;青花锁 &#x1f339;简介&#xff1a;Java领域优质创作者&#x1f3c6;、Java微服务架构公号作者&#x1f604; &#x1f339;简历模板、学习资料、面试题库、技术互助 &#x1f339;文末获取联系方式 &#x1f4dd; 往期热门专栏回顾 专栏…

多线程基础说明【基础篇】

目录 &#x1f32d;1.相关概念 &#x1f37f;2.创建和启动线程 &#x1f95e;3.线程安全 &#x1f9c8;4.死锁 &#x1f953;5.线程通信的方法 1.相关概念 1.1程序 为完成特定任务&#xff0c;用某种语言编写的一组指令的集合。即指一段静态的代码&#xff0c;静态对象…

Flask基础学习3

参考视频&#xff1a;41-【实战】答案列表的渲染_哔哩哔哩_bilibili flask 实现发送短信功能 pip install flask-mail # 安装依赖 我这里用登录的网易邮箱获取的授权码&#xff08;登录QQ邮箱的授权码总是断开收不到邮件&#xff09;&#xff0c; # config # config mail MAI…

vue3 实现 el-pagination页面分页组件的封装以及调用

示例图 一、组件代码 <template><el-config-provider :locale"zhCn"><el-pagination background class"lj-paging" layout"prev, pager, next, jumper" :pager-count"5" :total"total":current-page"p…

LeetCode二叉树中的第 K 大层和

题目描述 给你一棵二叉树的根节点 root 和一个正整数 k 。 树中的 层和 是指 同一层 上节点值的总和。 返回树中第 k 大的层和&#xff08;不一定不同&#xff09;。如果树少于 k 层&#xff0c;则返回 -1 。 注意&#xff0c;如果两个节点与根节点的距离相同&#xff0c;则…

SocketWeb实现小小聊天室

SocketWeb实现小小聊天室 消息推送的常见方式轮询长轮询SSE&#xff08;server-sent event&#xff09;&#xff1a;服务器发送事件WebSocketWebSocket简介WebSocket API 实现小小聊天室实现流程消息格式客户端-->服务端服务端-->客户端 消息推送的常见方式 轮询 浏览器…

C# TesseractOCR识别身份证号

https://github.com/tesseract-ocr/tessdata 新建控制台项目并添加包 Tesseract和Tesseract.Drawing 下载训练的模型 地址 代码实现 using Tesseract;var filePath "F:\\Desktop\\韦小宝.png"; var exePath AppDomain.CurrentDomain.BaseDirectory; var …