阿里easyExcel -- excel单元格自定义下拉选择(升级版)

news2025/1/10 23:42:12

背景

很久很久以前写了一篇类似的文章 阿里easyExcel – excel下载/导出/读取 (单元格自定义下拉选择、不支持图片) ,用了没多久就发现不好用,限制太多(以后遇到你就知道了),然后就有了现在迟到很久的文章,主要懒得写文章。

必看

此篇文章的单元格下拉支持 1级,2级,多级联动下拉等 ,比较复杂,需耐心看一下。
再写之前,先讲几个excel注意的点:

  1. 你的excel必须支持创建 名称管理器 ,如下图所示:
    在这里插入图片描述
  2. excel必须支持 INDIRECTCONCATENATEVLOOKUP 函数,要是excel版本太太太太低,可能没有这些函数,检查方式如下,一般=后面加函数名就会有提示:
    在这里插入图片描述

缺点或限制

  1. 当下拉的数据太多时,会导致创建excel的速度变慢
  2. 下拉的总数据不能超过 1048576 行,不能超过16384列

先简单看下效果

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

下拉的原理,怎么实现的下拉

创建一个sheet,然后把下拉数据放接某一列,如下:
在这里插入图片描述
当然也可以横着放,但是横着最多只能放 16384 列,而竖着可以放 1048576 行。
如果 只有1级下拉 那么不需要创建 名称管理器 ,如果是多级联动下拉,则除了最后1级,其余都要设置 名称管理器名称管理器 怎么设置下拉自己去百度。下面直接放代码,看不懂慢慢看,不想看直接复制使用,不想讲解了哈哈哈。

另外,由于 名称管理器 对name的设置要求很高,有些字符无法设置,为了实现下拉数据的千奇百怪,所以需要做一层转换。下面展示代码。

代码

ExcelUtils 工具:

public class ExcelUtils {
    /**
     * 下载
     *
     * @param writeHandlers 处理器(可自定义,可为null)
     * @param os            输出流
     * @param clazz         操作对象字节
     * @param data          数据
     * @param sheetName     表名
     */
    public static <T> void downLoad(List<WriteHandler> writeHandlers, OutputStream os, Class<T> clazz, List<T> data, String sheetName) {
        ExcelWriterSheetBuilder builder = EasyExcelFactory.write(os, clazz).sheet(sheetName);
        if (!CollectionUtils.isEmpty(writeHandlers)) {
            writeHandlers.forEach(builder::registerWriteHandler);
        }
        builder.doWrite(data);
    }
}

ExcelLinkageDropdown 多级下拉数据:

public class ExcelLinkageDropdown {
    /**
     * 是否允许设置其他的值。false:只能是下拉列表的值;true:允许列表之外的值
     */
    private boolean isAllowOtherValue = false;

    /**
     * 表头名称(为bean对象时传字段名称,为map时且多个头用json:["头1","头2"])
     */
    private String fieldName;

    /**
     * 第几列,为对象自动计算
     */
    private Integer cellIndex;

    /**
     * 下拉内容,<上级,下级列表>,第一级的key为null,只有一级时key也为null
     */
    private Map<String, List<String>> value = new HashMap<>();

    /**
     * 提示信息
     */
    private String message = "只能选择列表中的值!!!";
	//...get set 自己生成
}

DropdownWriteHandler下拉处理器:

/**
 * 下拉处理器:单元格下拉列表格式
 * 最大行:1048576 / 65536
 * 最大列:16384 / 256
 */
public class DropdownWriteHandler extends AbstractVerticalCellStyleStrategy implements SheetWriteHandler {

    private final Map<ExcelLinkageDropdown[], String> dropdowns = new HashMap<>(); //所有下拉值
    private final Class<?> clazz; //操作的类
    private final int headMax; //表头行数

    public DropdownWriteHandler(Class<?> clazz) {
        this.clazz = clazz;
        Field[] fields = clazz.getDeclaredFields();
        // 取表头行数
        this.headMax = Arrays.stream(fields).filter(field -> field.isAnnotationPresent(ExcelProperty.class))
                .map(field -> field.getAnnotation(ExcelProperty.class).value().length).reduce(Integer::max).orElse(0);
    }

    @Override
    public void beforeSheetCreate(WriteWorkbookHolder writeWorkbookHolder, WriteSheetHolder writeSheetHolder) {
    }

    @Override
    public void afterSheetCreate(WriteWorkbookHolder writeWorkbookHolder, WriteSheetHolder writeSheetHolder) {
        Workbook book = writeWorkbookHolder.getCachedWorkbook();
        Sheet sheet = writeSheetHolder.getSheet();
        // 设置固定区域
        sheet.createFreezePane(0, headMax, 0, headMax);
        DataValidationHelper helper = sheet.getDataValidationHelper();

        // 联动下拉校验
        if (!CollectionUtils.isEmpty(dropdowns)) {
            long l = System.currentTimeMillis();

            for (Map.Entry<ExcelLinkageDropdown[], String> dropdownMap : dropdowns.entrySet()) {
                ExcelLinkageDropdown[] dropdown = dropdownMap.getKey();
                String key = StringUtils.isNotBlank(dropdownMap.getValue()) ? dropdownMap.getValue() :
                        "t_" + Arrays.stream(dropdown).map(t -> t.getCellIndex().toString()).collect(Collectors.joining("_"));

                if (key.length() > 30) {
                    key = "s_" + IdGenerator.getInstance().getId();
                }

                //设置下拉及校验数据
                setDropdownsAndValidationData(book, sheet, helper, dropdown, key);
            }

            long l2 = System.currentTimeMillis();
            System.out.println("下拉耗时" + (l2 - l));
        }
    }

    /**
     * 设置下拉及校验数据
     */
    private void setDropdownsAndValidationData(Workbook book, Sheet sheet, DataValidationHelper helper, ExcelLinkageDropdown[] dropdown, String key) {
        // 设置多级下拉
        if (book.getSheetIndex(key) == -1) {
            buildDropdownSheet(book, dropdown, key);
        }

        //设置一级下拉
        List<String> val = dropdown[0].getValue().get(null);
        if (Objects.nonNull(val) && !val.isEmpty()) {
            String ss = ExcelTools.getRangeByCel(2, 2, val.size()); // A和B被占用,从C开始
            dropdownValidationData(String.format("='%s'!%s", key, ss), helper, this.headMax, 1000000, dropdown[0], sheet);
        }

        //二级及之后的下拉
        for (int i = 1; i < dropdown.length; i++) {
            String ci = CellReference.convertNumToColString(dropdown[i - 1].getCellIndex());
            String format = "INDIRECT(CONCATENATE(\"_\",VLOOKUP($" + ci + (this.headMax + 1) + "," + key + "!A:B,2,0),\"_\",\"" + key + "\"))"; // A:B写死
            dropdownValidationData(format, helper, this.headMax, 1000001, dropdown[i], sheet);
        }
    }

    /**
     * 验证下拉数据
     *
     * @param formula   公式
     * @param firstRow  第一行
     * @param lastRow   最后一行
     * @param dropdown1 下拉数据
     * @param sheet     表
     */
    private static void dropdownValidationData(String formula, DataValidationHelper helper, int firstRow, int lastRow, ExcelLinkageDropdown dropdown1, Sheet sheet) {
        DataValidationConstraint constraint = helper.createFormulaListConstraint(formula);
        DataValidation dataValidation = helper.createValidation(constraint, new CellRangeAddressList(firstRow, lastRow, dropdown1.getCellIndex(), dropdown1.getCellIndex()));
        dataValidation.setSuppressDropDownArrow(false);

        if (dataValidation instanceof XSSFDataValidation) {
            dataValidation.setSuppressDropDownArrow(true);
            dataValidation.setShowErrorBox(!dropdown1.isAllowOtherValue());  // 输入无效值时是否显示错误框
            dataValidation.setShowPromptBox(!dropdown1.isAllowOtherValue());  // 设置无效值时 是否弹出提示框
            dataValidation.createPromptBox("温馨提示", dropdown1.getMessage());   // 设置无效值时的提示框内容
            dataValidation.createErrorBox("温馨提示", dropdown1.getMessage());   // 设置无效值时的提示框内容
        }
        sheet.addValidationData(dataValidation);
    }

    /**
     * 设置单级或多级联动下拉,按顺序(1级,2级,3级...),否则将出错
     * 调用多次将设置多个多级联动
     * 单级或1级的key为null
     *
     * @param head clazz为map时需要传头,否则传null
     */
    public void setLinkageDropdown(List<List<String>> head, String excelName, ExcelLinkageDropdown... dropdowns) throws Exception {
        if (Objects.isNull(dropdowns) || dropdowns.length == 0) {
            throw new Exception("至少设置一个下拉参数");
        }
        boolean isMap = this.clazz.isAssignableFrom(Map.class);
        if (isMap && CollectionUtils.isEmpty(head)) {
            throw new Exception("head参数不能为空");
        }
        if (StringUtils.isNotBlank(excelName) && excelName.length() > 30) {
            throw new Exception("excelName长度不能超过30");
        }

        if (isMap) {
            for (ExcelLinkageDropdown dropdown : dropdowns) {
                if (dropdown.getValue().isEmpty()) {
                    continue;
                }
                List<String> heads = head.stream().map(t -> String.join(",", t)).collect(Collectors.toList());
                int i = heads.indexOf(dropdown.getFieldName());
                dropdown.setCellIndex(i);
            }
            this.dropdowns.put(dropdowns, excelName);
            return;
        }
        List<ExcelLinkageDropdown> ds = new ArrayList<>();
        for (ExcelLinkageDropdown dropdown : dropdowns) {
            if (dropdown.getValue().isEmpty()) {
                continue;
            }
            Field field;
            try {
                field = this.clazz.getDeclaredField(dropdown.getFieldName());
            } catch (Exception e) {
                throw new Exception("填写的字段不存在:" + dropdown.getFieldName() + "," + e.getMessage());
            }
            int index = field.getAnnotation(ExcelProperty.class).index(); // 获取头的位置
            if (index == -1) {
                for (Field f : clazz.getDeclaredFields()) {
                    if (!f.isAnnotationPresent(ExcelProperty.class)) {
                        continue;
                    }
                    index++;
                    if (f.getName().equals(dropdown.getFieldName())) {
                        break;
                    }
                }
            }
            dropdown.setCellIndex(index);
            ds.add(dropdown);
        }
        this.dropdowns.put(ds.toArray(new ExcelLinkageDropdown[0]), excelName);
    }

    /**
     * 设置单级或多级联动下拉,按顺序(1级,2级,3级...),否则将出错
     * 调用多次将设置多个多级联动
     * 单级或1级的key为null
     *
     * @param head clazz为map时需要传头,否则传null
     */
    public void setLinkageDropdown(List<List<String>> head, ExcelLinkageDropdown... dropdowns) throws Exception {
        this.setLinkageDropdown(head, null, dropdowns);
    }

    /**
     * 构建下拉列表sheet页,用于下拉框展示的数据源
     *
     * @param book 工作簿
     */
    private void buildDropdownSheet(Workbook book, ExcelLinkageDropdown[] dropdowns, String hiddenArea) {
        //创建新的隐藏表
        Sheet hideSheet = createNewHideSheet(book, hiddenArea);

        // 设置map的key格式化, 设置一级下拉
        this.setKeyFormat(dropdowns, hideSheet);

        // 第4列开始将具体的数据写入到每一列中
        int col = 3;
        int startRow = 1; //开始行
        CellStyle cellStyle = this.getFixRed(book);
        for (int i = 1; i < dropdowns.length; i++) {
            ExcelLinkageDropdown dropdown = dropdowns[i];
            for (Map.Entry<String, List<String>> entry : dropdown.getValue().entrySet()) {
                int rows = entry.getValue().size();

                //起始行如果超出最大行数,则新增一列,起始行重新计算,当前列总行数重新计算;
                if (startRow >= 1048576 || startRow + rows >= 1048576) {
                    startRow = 1;
                    col++;
                }
                //当前列超出最大列数,报错
                if (col > 16384) {
                    throw new RuntimeException("当前列超出最大列数");
                }

                //设置下拉值和名称管理器
                this.setNameName(book, hideSheet, hiddenArea, col, startRow, cellStyle, entry, rows);

                //重新计算起始行
                startRow = startRow + rows + 2;
            }
        }
    }

    /**
     * 设置下拉值和名称管理器
     */
    private void setNameName(Workbook book, Sheet hideSheet, String hiddenArea, int col, int startRow, CellStyle cellStyle, Map.Entry<String, List<String>> entry, int rows) {
        Row row0 = Objects.isNull(hideSheet.getRow(startRow - 1)) ? hideSheet.createRow(startRow - 1) : hideSheet.getRow(startRow - 1);
        Cell cell = row0.createCell(col);
        cell.setCellValue(ExcelTools.replaceAscii(entry.getKey()));
        cell.setCellStyle(cellStyle); //设置样式,区分下拉值

        for (int j = 0; j < rows; j++) {
            int r = j + startRow;
            Row row = Objects.isNull(hideSheet.getRow(r)) ? hideSheet.createRow(r) : hideSheet.getRow(r);
            row.createCell(col).setCellValue(entry.getValue().get(j));
        }

        // 添加名称管理器
        String range = ExcelTools.getRangeByCel(col, startRow + 1, rows);
        String nameName = "_" + ExcelTools.replaceAscii(entry.getKey()) + "_" + hiddenArea;
        Name name = book.createName();
        name.setNameName(nameName); // key不可重复

        String formula = hiddenArea + "!" + range;
        name.setRefersToFormula(formula);
    }

    /**
     * 设置map的key格式化
     */
    private void setKeyFormat(ExcelLinkageDropdown[] dropdowns, Sheet hideSheet) {
        // 第1-2列设置匹配表
        int rowId = 0;  // 设置区域的头行
        for (int i = 1; i < dropdowns.length; i++) {
            ExcelLinkageDropdown d = dropdowns[i];
            for (Map.Entry<String, List<String>> kv : d.getValue().entrySet()) {
                // 原始key-第一列
                Row row0 = hideSheet.createRow(rowId);
                row0.createCell(0).setCellValue(kv.getKey()); // 第一列
                row0.createCell(1).setCellValue(ExcelTools.replaceAscii(kv.getKey())); // 处理后的key-第二列
                rowId++;
            }
        }

        // 设置第1级
        List<String> dropdownVal = dropdowns[0].getValue().get(null); // 得到第一级

        Row r1 = Objects.isNull(hideSheet.getRow(0)) ? hideSheet.createRow(0) : hideSheet.getRow(0);
        r1.createCell(2).setCellValue(dropdowns[0].getFieldName());
        for (int i = 0; i < dropdownVal.size(); i++) {
            Row r1_ = Objects.isNull(hideSheet.getRow(i + 1)) ? hideSheet.createRow(i + 1) : hideSheet.getRow(i + 1);
            r1_.createCell(2).setCellValue(dropdownVal.get(i));
        }
    }

    /**
     * 创建新的隐藏表
     */
    private Sheet createNewHideSheet(Workbook book, String hiddenArea) {
        // 创建一个专门用来存放下拉的隐藏sheet页
        Sheet hideSheet = book.createSheet(hiddenArea);
        // 这一行作用是将此sheet隐藏
        book.setSheetHidden(book.getSheetIndex(hideSheet), true);

        //如果是SXSSFWorkbook类型,转XSSFWorkbook类型,否则sheet.getRow()可能为空
        if (book instanceof SXSSFWorkbook) {
            SXSSFWorkbook sxssfWorkbook = (SXSSFWorkbook) book;
            hideSheet = sxssfWorkbook.getXSSFWorkbook().getSheetAt(book.getSheetIndex(hideSheet));
        }
        return hideSheet;
    }

    /**
     * 红色固定样式
     */
    private CellStyle getFixRed(Workbook book) {
        CellStyle style = book.createCellStyle();
        Font font = book.createFont();
        font.setBold(true);
        font.setColor(IndexedColors.RED.getIndex());
        style.setFont(font);
        return style;
    }
}

工具:

public class ExcelTools {
    /**
     * 计算formula:纵向
     *
     * @param offset   偏移量,如果给0,表示从A列开始,1,就是从B列
     * @param rowId    第几行开始
     * @param rowCount 一共多少行
     * @return 如果给入参 0,2,10. 表示从A2-A11。最终返回 $A$2:$A$11
     */
    public static String getRangeByCel(int offset, int rowId, int rowCount) {
        String columnLetter1 = CellReference.convertNumToColString(offset);
        return String.format("$%s$%s:$%s$%s", columnLetter1, rowId, columnLetter1, rowId + rowCount - 1);
    }
    
     /**
     * 把非(中文、英文、下划线、点)替换为 ascii码,因为excel不支持其他字符设置名称管理器
     * 如:”审核订单(一级)(1)“ 替换为 ”审核订单.40.一级.41..40.1.41.“
     */
    public static String replaceAscii(String str) {
        if (StringUtils.isBlank(str)) {
            return str;
        }
        StringBuilder sb = new StringBuilder();
        for (String s : str.split("")) {
            if (s.matches("[^\\d\\u4e00-\\u9fa5.a-zA-Z_]")) {
                s = "." + (int) s.charAt(0) + ".";
            }
            sb.append(s);
        }
        return sb.toString();
    }
}

测试

@HeadStyle(fillForegroundColor = 1)
public class User implements Serializable {
    private static final long serialVersionUID = 1L;
    @ExcelProperty(value = {"一级"})
    private String borth;

    @ExcelProperty(value = {"二级"})
    @HeadStyle(fillForegroundColor = 29)
    private String name;

    @ExcelProperty(value = {"三级"})
    private String url;

    @ExcelProperty(value = {"性别"})
    private String sex;

    // 日期校验
    @ExcelProperty(value = "图片")
    private WriteCellData<Void> imgs;

    // 日期校验
    @ExcelProperty(value = "字节图片")
    private byte[] byteArray;
}
	//测试excel多级联动下拉
    @GetMapping("/test4")
    public void test4(HttpServletResponse response, int n) throws Exception {
        long l = System.currentTimeMillis();

        Map<String, List<String>> m1 = new HashMap<>();
        m1.put(null, new ArrayList<>());
        for (int i = 0; i < n; i++) {
            m1.get(null).add("A" + (i == 0 ? "" : i));
            m1.get(null).add("AA" + (i == 0 ? "" : i));
            m1.get(null).add("AAA" + (i == 0 ? "" : i));
            m1.get(null).add("AAAA" + (i == 0 ? "" : i));
        }

        Map<String, List<String>> m2 = new HashMap<>();
        for (String s : m1.get(null)) {
            List<String> a = new ArrayList<>();
            for (int i = 1; i < 11; i++) {
                a.add(s + "-" + i + "B");
            }
            m2.put(s, a);
        }

        List<String> v2 = m2.values().stream().flatMap(List::stream).collect(Collectors.toList());
        Map<String, List<String>> m3 = new HashMap<>();
        for (String s : v2) {
            int t = 50001;
            List<String> a = new ArrayList<>();
            for (int i = 1; i < t; i++) {
                a.add(s + "-" + i + "C");
                if (i > 1) {
                    t = 1;
                }
            }
            m3.put(s, a);
            System.out.println(s);
        }

        DropdownWriteHandler handler = new DropdownWriteHandler(User.class);

        ExcelLinkageDropdown dropdown11 = new ExcelLinkageDropdown();
        dropdown11.setFieldName("borth");
        dropdown11.setValue(m1);
        ExcelLinkageDropdown dropdown111 = new ExcelLinkageDropdown();
        dropdown111.setFieldName("name");
        dropdown111.setValue(m2);
        ExcelLinkageDropdown dropdown1111 = new ExcelLinkageDropdown();
        dropdown1111.setFieldName("url");
        dropdown1111.setValue(m3);

        Map<String, List<String>> sexMap = new HashMap<>();
        sexMap.put(null, m3.values().stream().flatMap(List::stream).collect(Collectors.toList()));
        ExcelLinkageDropdown sex = new ExcelLinkageDropdown();
        sex.setFieldName("sex");
        sex.setValue(sexMap);

        long l2 = System.currentTimeMillis();
        System.out.println("设置耗时" + (l2 - l));

        handler.setLinkageDropdown(null, dropdown11, dropdown111, dropdown1111);
        handler.setLinkageDropdown(null, sex);

        long l3 = System.currentTimeMillis();
        System.out.println("设置耗时" + (l3 - l2));

        ExcelUtils.downLoad(Lists.newArrayList(handler), ExcelTools.getOutputStream("测试excel多级联动下拉", response), User.class, null, "测试excel多级联动下拉");
    }

好了,又不想写了,就到此为止吧,有问题评论留言,看到能回就回。

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

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

相关文章

从U盘到云端:企业数据泄露的那些事

在企业的日常运营中&#xff0c;数据安全无疑是极为关键的一环。无论是U盘还是云&#xff0c;数据泄露事件的发生都可能导致企业的核心机密被窃取&#xff0c;甚至损害企业的商业利益和声誉。以下是关于从U盘到云端&#xff0c;企业数据泄露的一些常见情况和应对策略。 U盘&…

数据结构-线性表-应用题-2.2-12

1&#xff09;算法的基本设计思想&#xff1a;依次扫描数组的每一个元素&#xff0c;将第一个遇到的整数num保存到c中&#xff0c;count记为1&#xff0c;若遇到的下一个整数还是等于num,count,否则count--,当计数减到0时&#xff0c;将遇到的下一个整数保存到c中&#xff0c;计…

Android 终端查看CPU信息源码分析

代码如下&#xff1a; 终端获取信息&#xff08;左为H9&#xff0c;右为H5&#xff09; 觉得本文对您有用&#xff0c;麻烦点赞、关注、收藏&#xff0c;您的肯定是我创作的无限动力&#xff0c;谢谢&#xff01;&#xff01;&#xff01;

DOTA-Gly-Asp-Tyr-Met-Gly-Trp-Met-Asp-Phe-NH2,1306310-00-8,是一种重要的多肽化合物

一、试剂信息 名称&#xff1a;DOTA-Gly-Asp-Tyr-Met-Gly-Trp-Met-Asp-Phe-NH2CAS号&#xff1a;1306310-00-8结构式&#xff1a; 二、试剂内容 DOTA-Gly-Asp-Tyr-Met-Gly-Trp-Met-Asp-Phe-NH2是一种重要的多肽化合物&#xff0c;其CAS号为1306310-00-8。该多肽包含一个DO…

微火全域外卖系统是什么?为什么市场占有率这么高?

近日&#xff0c;全域外卖领域又出现了新变动&#xff0c;一个名为微火的品牌凭借着其全域外卖系统&#xff0c;在短短几个月的时间里&#xff0c;就占领了大部分市场。截止发稿日期前&#xff0c;微火全域外卖系统的市场占有率已经超过48%。 据了解&#xff0c;所谓的全域外卖…

怿星 × NI丨联合成功打造行业领先的L4自动驾驶数据回灌系统

怿星NI 联合成功打造行业领先的L4自动驾驶数据回灌系统&#xff08;终版&#xff09; 怿星与于NI&#xff08;恩艾&#xff09;公司联合打造的L4自动驾驶数据回灌系统&#xff0c;在支持多种数据同步回灌、实时模拟故障、高带宽数据传输的同时&#xff0c;具有视频链路扩展性高…

IST——In-System-Test

1、背景 安全性是自动驾驶平台的关键特性之一&#xff0c;而这些架构中使用的半导体芯片必须保证ISO 26262标准所要求的功能安全方面。为了监控由于现场缺陷导致的故障&#xff0c;在启动和/或关闭期间会自动运行系统内结构测试。当系统内测试&#xff08;IST&#xff0c;In-Sy…

跨界探索:在苹果系统M系列处理器上安装Windows 11系统的实践经历

[ 知识是人生的灯塔&#xff0c;只有不断学习&#xff0c;才能照亮前行的道路。] 大家好&#xff0c;我是【WeiyiGeek/唯一极客】一个正在向全栈工程师(SecDevOps)前进的技术爱好者 作者微信&#xff1a;WeiyiGeeker 公众号/知识星球&#xff1a;全栈工程师修炼指南 主页博…

uni-app 从vue3项目创建到Pinia管理数据全局使用 持久化存储数据 详细教程

1、使用 HBuilderX 创建一个 vue3的新项目 点击左上角的文件 --> 选择新建 --> 项目 3、查看当前项目的版本 4、把项目可以先跑起来----我这里是运行在谷歌浏览器 也可以运行在微信小程序开发者工具上 5、看运行结果 2、在项目中配置Pinia --> Pinia 官网---&…

3. 分布式链路追踪的链路日志设计

前言 分布式链路追踪的客户端实现中&#xff0c;我们会通过各种手段和规则得到一个又一个的Span&#xff0c;得到这些Span后&#xff0c;需要在分布式链路追踪的服务端这边汇总这些Span并拼接出一条请求链路&#xff0c;那么这里就存在一个问题&#xff0c;客户端得到的Span如…

揭秘全网热门话题:抖音快速涨粉方法,巨量千川投流助你日增10000粉

在当今社交媒体的时代( 千川投流&#xff1a;hzzxar&#xff09;抖音成为了年轻人分享自己才华和生活的平台。然而&#xff0c;要在抖音上快速获得关注和粉丝&#xff0c;却不是一件容易的事情。今天&#xff0c;我们将揭秘全网都在搜索的抖音快速涨1000粉的秘籍&#xff0c;带…

彩色 Bitmap转换HObject图像

彩色 Bitmap转换HObject图像 之前已有的代码是这样的 public static HImage Bitmap2HImage_24(Bitmap bImage){lock (m_lock){Bitmap bImage24;BitmapData bmData null;Rectangle rect;IntPtr pBitmap;IntPtr pPixels;HImage hImage new HImage();rect new Rectangle(0, 0,…

搭建Springboot的基础开发框架-01

本系列专题虽然是按教学的深度来定稿的&#xff0c;但在项目结构和代码组织方面是按公司系统的要求来书定的。在本章中主要介绍下基础开发框架的功能。后续所有章节的项目全是在本基础框架的基础上演进的。 工程结构介绍 SpringbootSeries&#xff1a;父工程&#xff0c;定义一…

嵌入式RTOS面试题目

用过哪些嵌入式操作系统&#xff1f;使⽤RTOS和裸机代码开发有什么区别&#xff08;优缺点&#xff09;&#xff1f; 之前的⼀个项⽬是采⽤裸机代码开发的&#xff0c;写起来还⾏&#xff0c;通过状态机来管理业务逻辑和各种外设。 但是随着外设的增加&#xff0c;任务之间的…

泛域名SSL证书购买攻略!

购买泛域名证书&#xff08;也称为通配符证书&#xff09;通常涉及以下几个步骤&#xff1a; 1. 选择证书提供商&#xff1a; 首先&#xff0c;你需要选择一个信誉良好的SSL证书提供商&#xff0c;如 Sectigo、GlobalSign、DigiCert 或者JoySSL。部分云服务提供商如华为云也提供…

windows11获取笔记本电脑电池健康报告

笔记本电脑的电池关系到我们外出时使用的安全&#xff0c;如果电池健康有问题需要及时更换&#xff0c;windows系统提供了检查电池健康度的方法。 1、打开命令行 1&#xff09;键入 winR 2&#xff09;键入 cmd 打开命令行。 2、在命令行运行如下指令&#xff0c;生成电池健…

直播产品实习生实习体验报告,笔灵AI生成模版分享

实习体验报告&#xff1a;直播产品实习生 如果有不同的岗位需要写的话可以去笔灵生成一下 网址&#xff1a;https://ibiling.cn/scene/inex?fromcsdnsx 一、实习背景我是XXX&#xff0c;作为一名直播产品实习生&#xff0c;我在XX公司进行了为期X个月的实习。在这段时间里&…

【Java基础】Java异常处理机制超简单的!!

程序在运行时出现的不正常情况 java把程序运行时出现的各种不正常情况提取属性和行为进行描述&#xff0c;从而出现了各种异常类&#xff0c;也就是异常被面向对象了。 异常名称、异常信息、异常发生的位置 Exception in thread "main" java.lang.ArrayIndexOutOf…

Saving Environment to FAT... Card did not respond to voltage select!

在移植uboot到全志H3时&#xff0c;出现了错误&#xff1a; Saving Environment to FAT… Card did not respond to voltage select! 判定与MMC有关。 同时还有报错&#xff1a; Error: ethernet1c30000 address not set. No ethernet found. 查看源码发现这与环境变量有关&am…

01-xss基本原理

核心:攻击的是前端&#xff0c; 一、课程引入 1、开发一个简单的PHP页面&#xff0c;代码如下&#xff1a; <?php // xss 基础演示代码&#xff1a;从浏览器中接受一个URL地址参数名为content if(isset($_GET[content])){$content$_GET[content];echo "你输入的内容…