java使用poi读写excel(处理上下标和科学计数法)

Background

  • 要读写如下图所示的excel,符号和单位中包含上下标,在读写时需要特殊处理;
  • 取值列中是科学计数法,读写时需要特殊处理;
  • excel中包含多个sheet,读的时候把所有sheet的数据读出来,写的时候把所有sheet的数据写进去;

在这里插入图片描述

1、读取所有sheet数据

readFromSheet方法,使用对象接收每个sheet的数据,返回每个sheet对应的数据集合

2、写入所有sheet数据

write2Sheet方法,传入每个sheet对应的数据集合,把所有sheet的数据写入到excel中,并且是基于模板写入

3、写数据时处理上下标

richTextString方法,写数据时把有上下标信息字符串处理成富文本

4、读数据时处理上下标

getCellValue方法,读数据时给有上下标信息字符串添加tag信息

5、数值科学计数法处理

scientificNotationString方法,返回处理后的科学计数法字符串

源码

在这里插入图片描述

  • Const.java
package com.yunlu.groundwater.constants;

import com.yunlu.groundwater.gwParameters.entities.*;

import java.util.HashMap;
import java.util.Map;

public class Const {

    // 模型参数文件导入路径
    public static final String IMPORT_MODEL_PARAM_FILEPATH = "excel-import/inputTable.xlsx";
    // 模型参数模板文件路径
    public static final String TPL_MODEL_PARAM_FILEPATH = "model/tpl/inputTable-tpl.xlsx";
    // 模型计算时输入模型参数文件路径
    public static final String INPUT_MODEL_PARAM_FILEPATH = "model/input/inputTable.xlsx";

    // excel模板解析跳过行数
    public static final Map<String, Class<?>> EXCEL_SHEET_OBJ = new HashMap<String, Class<?>>() {{
        put("3_地下水理化毒性报表", GWBPhysicalChemicalToxicity.class);
        put("4_受体暴露参数", GWBReceptorExpose.class);
        put("5_土壤性质参数", GWBSoilNature.class);
        put("6_地下水性质参数", GWBWaterNature.class);
        put("7_建筑物特征参数", GWBBuildingFeature.class);
        put("8_空气特征参数", GWBAirFeature.class);
        put("9_离场迁移参数", GWBFieldMoving.class);
    }};

    // 字符串
    public static final String S_UID = "serialVersionUID";
    // 上标
    public static final String TAG_SUB_START = "<sub>";
    public static final String TAG_SUB_END = "</sub>";
    // 下标
    public static final String TAG_SUP_START = "<sup>";
    public static final String TAG_SUP_END = "</sup>";

    // punctuation[ptn][标点]
    public static final String PTN_EMPTY = "";
    public static final String PTN_BAR_MID = "-";

    // tpl
    public static final String TPL_TAG = "%s%s%s";
    public static final String TPL_E1 = "%s+%s";

    // fmt
    public static final String FMT_DOUBLE = "0.00E00";
}

  • ExcelCol.java
package com.yunlu.groundwater.resume.mapper;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Target({ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
public @interface ExcelCol {
    int index() default 0;
    boolean scientificNotation() default false;
}
  • GWBSoilNature.java
package com.yunlu.groundwater.gwParameters.entities;

import com.yunlu.groundwater.resume.mapper.ExcelCol;
import lombok.Data;

@Data
public class GWBSoilNature {
	
	private static final long serialVersionUID = 1L;
	
    @ExcelCol(index = 0)
    private String paramName;

    @ExcelCol(index = 1)
    private String sign;
	
    @ExcelCol(index = 2)
    private String unit;
	
    @ExcelCol(index = 3)
    private Double value;
}
  • ExcelHandler.java
package com.yunlu.groundwater.resume.controller;

import com.yunlu.groundwater.constants.Const;
import com.yunlu.groundwater.resume.mapper.ExcelCol;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.Row;
import org.apache.poi.ss.usermodel.Sheet;
import org.apache.poi.xssf.usermodel.*;

import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.lang.reflect.Field;
import java.text.DecimalFormat;
import java.util.*;

@Slf4j
public class ExcelHandler {

    public static void main(String[] args) throws Exception {
        // 从excel读取数据
        String file = Const.IMPORT_MODEL_PARAM_FILEPATH;
        Map<String, List<Object>> sheetValues = readFromSheet(file);
        for (String sheetName : sheetValues.keySet()) {
            System.out.println(sheetName);
            for (Object o : sheetValues.get(sheetName)) {
                System.out.println(o);
            }
            System.out.println();
        }

        // 向excel写入数据
        file = Const.INPUT_MODEL_PARAM_FILEPATH;
        write2Sheet(file, sheetValues);
    }

    /**
     * 从excel文件读取所有sheet数据(有上下标信息字符串自动处理成富文本)
     *
     * @param filename 文件名称
     * @return 返回所有sheet数据对象集合
     */
    public static Map<String, List<Object>> readFromSheet(String filename) {
        Map<String, List<Object>> res = new HashMap<>();
        try (
                FileInputStream in = new FileInputStream(filename);
                XSSFWorkbook workbook = new XSSFWorkbook(in);
        ) {
            Iterator<Sheet> sheetIterator = workbook.sheetIterator();
            while (sheetIterator.hasNext()) {
                List<Object> objects = new ArrayList<>();
                int startRowIndex = 3;
                Sheet sheet = sheetIterator.next();
                String sheetName = sheet.getSheetName();
                Class<?> tClass = Const.EXCEL_SHEET_OBJ.get(sheetName);
                Map<Integer, Field> fieldMap = getFieldMap(tClass);
                for (int rowIndex = startRowIndex; rowIndex <= sheet.getLastRowNum(); rowIndex++) {
                    Row row = sheet.getRow(rowIndex);
                    Object t = tClass.newInstance();
                    for (Integer colIndex : fieldMap.keySet()) {
                        Field field = fieldMap.get(colIndex);
                        boolean scientificNotation = getColScientificNotation(field);
                        Cell cell = row.getCell(colIndex);
                        if (cell != null) {
                            String cellValue = getCellValue(cell, scientificNotation, workbook);
                            setFieldValue(field, cellValue, t);
                        }
                    }
                    if (!isAllFieldNull(t)) {
                        objects.add(t);
                    }
                }
                res.put(sheetName, objects);
            }
        } catch (Exception e) {
            log.error("readFromSheet error", e);
            e.printStackTrace();
        }
        return res;
    }

    /**
     * 把数据写入到excel文件中,指定sheet、起始行索引和起始列索引(有上下标信息字符串自动处理成富文本)
     *
     * @param filename    文件名称
     * @param sheetValues <sheet名称,数据>
     */
    public static void write2Sheet(String filename, Map<String, List<Object>> sheetValues) {
        String tplFile = Const.TPL_MODEL_PARAM_FILEPATH;
        try (
                FileOutputStream fos = new FileOutputStream(filename);
                FileInputStream fis = new FileInputStream(tplFile);
                XSSFWorkbook workbook = new XSSFWorkbook(fis);
        ) {
            for (String sheetName : sheetValues.keySet()) {
                int startRowIndex = 3;
                List<Object> values = sheetValues.get(sheetName);
                if (values.size() > 0) {
                    Class<?> tClass = values.get(0).getClass();
                    Map<Integer, Field> fieldMap = getFieldMap(tClass);
                    XSSFSheet sheet = workbook.getSheet(sheetName);
                    for (Object t : values) {
                        XSSFRow row = sheet.getRow(startRowIndex);
                        for (Integer colIndex : fieldMap.keySet()) {
                            Field field = fieldMap.get(colIndex);
                            boolean scientificNotation = getColScientificNotation(field);
                            String content;
                            try {
                                content = fieldMap.get(colIndex).get(t).toString();
                            } catch (Exception e) {
                                content = Const.PTN_EMPTY;
                            }
                            List<List<int[]>> tagIndexArr = new ArrayList<>();
                            if (containTag(content)) {
                                content = getIndexes(content, tagIndexArr);
                            }
                            XSSFCell cell = row.getCell(colIndex);
                            if (null == cell) {
                                cell = row.createCell(colIndex);
                            }
                            if (tagIndexArr.size() > 0) {
                                cell.setCellValue(richTextString(workbook, content, tagIndexArr));
                            } else {
                                if (scientificNotation && !StringUtils.isEmpty(content) && !Const.PTN_BAR_MID.equals(content)) {
                                    cell.setCellValue(Double.parseDouble(content));
                                } else {
                                    cell.setCellValue(content);
                                }
                            }
                        }
                        startRowIndex++;
                    }
                }
            }
            workbook.write(fos);
        } catch (Exception e) {
            log.error("write2Sheet error", e);
            e.printStackTrace();
        }
    }

    /**
     * @param val 数值
     * @return 返回科学计数法字符串
     */
    public static String scientificNotationString(Double val) {
        String res = new DecimalFormat(Const.FMT_DOUBLE).format(val);
        if (val >= 1) {
            int length = res.length();
            String prefix = res.substring(0, length - 2);
            String suffix = res.substring(length - 2, length);
            res = String.format(Const.TPL_E1, prefix, suffix);
        }
        return res;
    }

    /**
     * 获取字段集合信息
     */
    private static Map<Integer, Field> getFieldMap(Class<?> tClass) {
        Map<Integer, Field> fieldMap = new HashMap<>();
        for (Field field : tClass.getDeclaredFields()) {
            ExcelCol col = field.getAnnotation(ExcelCol.class);
            if (null != col) {
                field.setAccessible(true);
                fieldMap.put(col.index(), field);
            }
        }
        return fieldMap;
    }

    /**
     * 获取字段是否需要科学计数法表示
     */
    private static boolean getColScientificNotation(Field field) {
        return field.getAnnotation(ExcelCol.class).scientificNotation();
    }

    /**
     * 判断对象的所有字段值是否为空
     */
    private static <T> boolean isAllFieldNull(T t) {
        boolean res = true;
        Class<?> tClass = t.getClass();
        for (Field field : tClass.getDeclaredFields()) {
            field.setAccessible(true);
            try {
                Object fieldValue = field.get(t);
                if (!Const.S_UID.equals(field.getName()) && null != fieldValue) {
                    res = false;
                }
            } catch (Exception ignored) {
            }
        }
        return res;
    }

    /**
     * 设置字段值
     */
    private static <T> void setFieldValue(Field field, String value, T t) throws Exception {
        if (null != field) {
            String type = field.getType().toString();
            if (StringUtils.isBlank(value)) {
                field.set(t, null);
            } else if (type.endsWith("String")) {
                field.set(t, value);
            } else if (type.endsWith("long") || type.endsWith("Long")) {
                field.set(t, Long.parseLong(value));
            } else if (type.endsWith("double") || type.endsWith("Double")) {
                field.set(t, Double.parseDouble(value));
            } else {
                field.set(t, value);
            }
        }
    }

    /**
     * @param cell cell
     * @return 返回cell内容(有上下标信息字符串自动处理成富文本)
     */
    private static String getCellValue(Cell cell, boolean scientificNotation, XSSFWorkbook workbook) {
        switch (cell.getCellType()) {
            case NUMERIC:
                double cellValue = cell.getNumericCellValue();
                return scientificNotation ? scientificNotationString(cellValue) : String.valueOf(cellValue);
            case STRING:
                XSSFFont font;
                XSSFRichTextString rts = (XSSFRichTextString) cell.getRichStringCellValue();
                StringBuilder value = new StringBuilder();
                if (rts.numFormattingRuns() > 1) {
                    for (int i = 0; i < rts.numFormattingRuns(); i++) {
                        int runLength = rts.getLengthOfFormattingRun(i);
                        int runIndex = rts.getIndexOfFormattingRun(i);
                        String temp = rts.toString().substring(runIndex, (runIndex + runLength));
                        try {
                            font = rts.getFontOfFormattingRun(i);
                            font.getTypeOffset();
                        } catch (NullPointerException e) {
                            font = workbook.getFontAt(XSSFFont.DEFAULT_CHARSET);
                            font.setTypeOffset(XSSFFont.SS_NONE);
                        }
                        temp = addTagInfo(temp, font.getTypeOffset());
                        value.append(temp);
                    }
                } else {
                    value.append(cell.getStringCellValue());
                }
                return value.toString();
            default:
                return Const.PTN_EMPTY;
        }
    }

    /**
     * 处理有上下标的字符串
     */
    private static String addTagInfo(String str, short typeOffset) {
        if (typeOffset == XSSFFont.SS_SUPER) {
            str = String.format(Const.TPL_TAG, Const.TAG_SUP_START, str, Const.TAG_SUP_END);
        }
        if (typeOffset == XSSFFont.SS_SUB) {
            str = String.format(Const.TPL_TAG, Const.TAG_SUB_START, str, Const.TAG_SUB_END);
        }
        return str;
    }

    /**
     * 有上下标信息字符串处理成富文本
     *
     * @param str 字符串
     * @return 处理后的富文本
     */
    private static XSSFRichTextString richTextString(XSSFWorkbook workbook, String str, List<List<int[]>> tagIndexArr) {
        XSSFRichTextString richTextString = new XSSFRichTextString(str);
        List<int[]> subs = tagIndexArr.get(0);
        List<int[]> sups = tagIndexArr.get(1);
        if (subs.size() > 0) {
            XSSFFont font = workbook.createFont();
            font.setTypeOffset(XSSFFont.SS_SUB);
            for (int[] pair : subs) {
                richTextString.applyFont(pair[0], pair[1], font);
            }
        }
        if (sups.size() > 0) {
            XSSFFont font = workbook.createFont();
            font.setTypeOffset(XSSFFont.SS_SUPER);
            for (int[] pair : sups) {
                richTextString.applyFont(pair[0], pair[1], font);
            }
        }
        return richTextString;
    }

    /**
     * 获取下一对标签的index,不存在这些标签就返回null
     *
     * @param str 字符串
     * @param tag SUB_START或者SUP_START
     * @return int[]中有两个元素,第一个是开始标签的index,第二个元素是结束标签的index
     */
    private static int[] getNextTagsIndex(String str, String tag) {
        int firstStart = str.indexOf(tag);
        if (firstStart > -1) {
            int firstEnd = 0;
            if (tag.equals(Const.TAG_SUB_START)) {
                firstEnd = str.indexOf(Const.TAG_SUB_END);
            } else if (tag.equals(Const.TAG_SUP_START)) {
                firstEnd = str.indexOf(Const.TAG_SUP_END);
            }
            if (firstEnd > firstStart) {
                return new int[]{firstStart, firstEnd};
            }
        }
        return new int[]{};
    }

    /**
     * 移除下一对sub或者sup或者u或者strong或者em标签
     *
     * @param str 字符串
     * @param tag SUB_START或者SUP_START
     * @return 返回移除后的字符串
     */
    private static String removeNextTags(String str, String tag) {
        str = str.replaceFirst(tag, Const.PTN_EMPTY);
        if (tag.equals(Const.TAG_SUB_START)) {
            str = str.replaceFirst(Const.TAG_SUB_END, Const.PTN_EMPTY);
        } else if (tag.equals(Const.TAG_SUP_START)) {
            str = str.replaceFirst(Const.TAG_SUP_END, Const.PTN_EMPTY);
        }
        return str;
    }

    /**
     * 判断是不是包含sub、sup标签
     *
     * @param str 字符串
     * @return 返回是否包含
     */
    private static boolean containTag(String str) {
        return (str.contains(Const.TAG_SUB_START) && str.contains(Const.TAG_SUB_END)) || (str.contains(Const.TAG_SUP_START) && str.contains(Const.TAG_SUP_END));
    }

    /**
     * 处理字符串,得到每个sub、sup标签的开始和对应的结束的标签的index,方便后面根据这个标签做字体操作
     *
     * @param str          字符串
     * @param tagIndexList 传一个新建的空list进来,方法结束的时候会存储好标签位置信息。
     *                     <br>tagIndexList.get(0)存放的sub
     *                     <br>tagIndexList.get(1)存放的是sup
     * @return 返回sub、sup处理完之后的字符串
     */
    private static String getIndexes(String str, List<List<int[]>> tagIndexList) {
        List<int[]> subs = new ArrayList<>(), sups = new ArrayList<>();
        while (true) {
            int[] sub_pair = getNextTagsIndex(str, Const.TAG_SUB_START), sup_pair = getNextTagsIndex(str, Const.TAG_SUP_START);
            boolean subFirst = false, supFirst = false;
            List<Integer> a = new ArrayList<>();
            if (sub_pair.length > 0) {
                a.add(sub_pair[0]);
            }
            if (sup_pair.length > 0) {
                a.add(sup_pair[0]);
            }
            Collections.sort(a);
            if (sub_pair.length > 0) {
                if (sub_pair[0] == Integer.parseInt(a.get(0).toString())) {
                    subFirst = true;
                }
            }
            if (sup_pair.length > 0) {
                if (sup_pair[0] == Integer.parseInt(a.get(0).toString())) {
                    supFirst = true;
                }
            }
            if (subFirst) {
                str = removeNextTags(str, Const.TAG_SUB_START);
                // <sub>标签被去掉之后,结束标签需要相应往前移动
                sub_pair[1] = sub_pair[1] - Const.TAG_SUB_START.length();
                subs.add(sub_pair);
                continue;
            }
            if (supFirst) {
                str = removeNextTags(str, Const.TAG_SUP_START);
                // <sup>标签被去掉之后,结束标签需要相应往前移动
                sup_pair[1] = sup_pair[1] - Const.TAG_SUP_START.length();
                sups.add(sup_pair);
                continue;
            }
            if (sub_pair.length == 0 && sup_pair.length == 0) {
                break;
            }
        }
        tagIndexList.add(subs);
        tagIndexList.add(sups);
        return str;
    }

}

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

分割掩模 VS 掩膜

掩膜 Mask分割掩模 Segmentation Mask总结示例 掩膜 Mask “掩膜” 是指一种用于 标识或遮蔽图像中特定区域 的 图像。 在图像处理中&#xff0c;掩膜通常是一个 二值图像&#xff0c;其中的 像素值为 0 或 1。binary Mask 叫做二元掩膜&#xff0c;如下图所示&#xff1a; 这…

Airtest进阶使用篇!提高脚本稳定性 + 批量运行脚本!

一、背景 今天彭于晏为大家分享Airtest进阶使用篇&#xff0c;主要包含两块的内容&#xff1a; 提高脚本稳定性批量运行脚本生成测试报告 二、提高脚本稳定性 1、添加全局配置: #全局设置 ST.FIND_TIMEOUT10 #设置隐式等待时长,默认识别图片时间是30秒&#xff0c;可改为…

[黑皮系列] 计算机网络:自顶向下方法(第8版)

文章目录 《计算机网络&#xff1a;自顶向下方法&#xff08;第8版&#xff09;》简介作者目录前言配套公开课 《计算机网络&#xff1a;自顶向下方法&#xff08;第8版&#xff09;》 出版信息&#xff1a; 原作名: Computer Networking: A Top-Down Approach 作者: [美] Jame…

运维知识点-SQLServer/mssql

SQLServer/mssql Microsoft structed query language常见注入提权 技术点&#xff1a;0x00 打点前提 0x01 上线CS0x02 提权0x03 转场msf0x04 抓取Hash0x05 清理痕迹 Microsoft structed query language 常见注入 基于联合查询注入 order by 判断列数&#xff08;对应数据类型…

从0开始学习JavaScript--JavaScript 单例模式

单例模式是一种常见的设计模式&#xff0c;它保证一个类仅有一个实例&#xff0c;并提供一个全局访问点。在 JavaScript 中&#xff0c;单例模式通常用于创建唯一的对象&#xff0c;以确保全局只有一个实例。本文将深入探讨单例模式的基本概念、实现方式&#xff0c;以及在实际…

const 和 constexpr 深入学习

在 C 中&#xff0c;const 和 constexpr 都可以用来修饰对象和函数。修饰对象时&#xff0c;const 表示它是常量&#xff0c;而 constexpr 表示它是一个常量表达式。常量表达式必须在编译时期被计算1。修饰函数时&#xff0c;const 只能用于非静态成员的函数&#xff0c;而 con…

Secure Software Lifecycle Management (SSLM)安全软件生命周期管理

文章目录 前言一、现代理念二、安全的软件生命周期管理总结 前言 The concept of integrating security into the software development process is not new. While I cannot definitively assert that Microsoft was the pioneer of this concept, the Secure Development Li…

清理docker Build Cache缓存文件

使用docker构建镜像&#xff0c;发现docker的overlay2文件会越来越大。 使用命令查看docker系统占用资源&#xff1a; docker system df 可以看到已经占用了26.7GB&#xff0c;清理这个缓存 docker builder prune 再次查看&#xff0c;已经没有缓存了&#xff0c;清理成功。 …

【UE】中文字体 发光描边材质

效果 步骤 1. 先将我们电脑中存放在“C:\Windows\Fonts”路径下的字体导入UE 点击“全部选是” 导入成功后如下 2. 打开导入的“SIMSUN_Font”&#xff0c;将字体缓存类型设置为“离线” 点击“是” 这里我选择&#xff1a;宋体-常规-20 展开细节面板中的导入选项 勾选“使用距…

Redis缓存淘汰策略

Redis缓存淘汰策略 1、各种面试题 生产上你们的redis内存设置多少?如何配置、修改redis的内存大小如果内存满了你怎么办&#xff1f;redis清理内存的方式?定期删除和惰性删除了解过吗&#xff1f;redis缓存淘汰策略有哪些?分别是什么?你用哪个?redis的LRU了解过吗?请手…

FastApi接收不到Apifox发送的from-data字符串_解决方法

接收不到Apifox发送的from-data字符串_解决方法 问题描述解决方法弯路总结弯路描述纵观全局小结 问题描述 这里写了一个接口&#xff0c;功能是上传文件&#xff0c;接口参数是file文件和一个id字符串 gpt_router.post("/uploadfiles") async def create_upload_fi…

基于ora2pg迁移Oracle19C到postgreSQL14

&#x1f4e2;&#x1f4e2;&#x1f4e2;&#x1f4e3;&#x1f4e3;&#x1f4e3; 哈喽&#xff01;大家好&#xff0c;我是【IT邦德】&#xff0c;江湖人称jeames007&#xff0c;10余年DBA及大数据工作经验 一位上进心十足的【大数据领域博主】&#xff01;&#x1f61c;&am…

linux socket套接字

文章目录 socket流socket&#xff08;TCP&#xff09;数据报socket&#xff08;UDP&#xff09; 讨论 socket 所谓套接字&#xff0c;就是对网络中不同主机上的应用程序之间进行双向通信的端点的抽象。一个套接字就是网络上进程通信的一端&#xff0c;套接字提供了应用层进程利…

AI - FlowField(流场寻路)

FlowField流场寻路&#xff0c;利用网格存储每个点对目标点的推力&#xff0c;网格上的单位根据对于推力进行移动。用于大量单位进行寻路对于同一目的地的寻路&#xff0c;常用于rts游戏等。 对应一张网格地图(图中黑块是不可行走区域) 生成热度图 计算所有网格对于目标点(…

【Flutter】graphic图表实现tooltip一段时间后自动隐藏

概述 graphic图表中提供了自定义tooltip的事件&#xff0c;可通过selections中on和clear配置手势选项和可识别设备&#xff0c;默认情况下tooltip需要双击隐藏&#xff0c;但这并不符合我们的需求。通过调研发现&#xff0c;若想实现tooltip隔几秒后隐藏&#xff0c;可通过Str…

西工大网络空间安全学院计算机系统基础实验一(9, 10, 11, 12, 13)

还是那句话&#xff0c;专心做好你自己的&#xff0c;老老实实把基础打好&#xff0c;不要被其他人带跑节奏&#xff0c;不要跟他打&#xff0c;跟着这系列博客&#xff0c;稳扎稳打一步一步来。即使你VMware workstation没下载好&#xff0c;即使你Ubuntu虚拟机没配好&#xf…

【数据挖掘】国科大刘莹老师数据挖掘课程作业 —— 第三次作业

Written Part 1. 基于表 1 1 1 回答下列问题&#xff08;min_sup40%, min_conf75%&#xff09;&#xff1a; Transaction IDItems Bought0001{a, d, e}0024{a, b, c, e}0012{a, b, d, e}0031{a, c, d, e}0015{b, c, e}0022{b, d, e}0029{c, d}0040{a, b, c}0033{a, d, e}0038…

【计算机网络笔记】交换机

系列文章目录 什么是计算机网络&#xff1f; 什么是网络协议&#xff1f; 计算机网络的结构 数据交换之电路交换 数据交换之报文交换和分组交换 分组交换 vs 电路交换 计算机网络性能&#xff08;1&#xff09;——速率、带宽、延迟 计算机网络性能&#xff08;2&#xff09;…

Vue3依赖注入

适用场景 尤其针对一个变量需要从顶层组件开始透传&#xff0c;途径很多个子组件最后在第n代子组件使用的时候。对于这些途经的子组件而言&#xff0c;它们不但不使用而且完全不关心该变量具体是什么&#xff0c;只是作为一个传递工具罢了。这种情况下&#xff0c;使用依赖注入…