EasyExcel合并相同内容单元格及动态标题功能的实现

一、最初版本
导出的结果:
在这里插入图片描述
对应实体类代码:

import com.alibaba.excel.annotation.ExcelProperty;
import com.alibaba.excel.annotation.write.style.ColumnWidth;
import com.alibaba.excel.annotation.write.style.ContentLoopMerge;
import com.alibaba.excel.annotation.write.style.ContentRowHeight;
import com.alibaba.excel.annotation.write.style.HeadRowHeight;
import lombok.*;

import java.io.Serializable;

@Getter
@Setter
@NoArgsConstructor
@AllArgsConstructor
@Data
@ContentRowHeight(30)
@HeadRowHeight(40)
@ColumnWidth(25)
public class StudentExportVo implements Serializable {

    private static final long serialVersionUID = -5809782578272943999L;

    @ExcelProperty(value = "学校", order = 1)
    @ContentLoopMerge(eachRow = 3)
    private String school;

    @ExcelProperty(value = "姓名", order = 2)
    private String name;

    @ExcelProperty(value = "性别", order = 3)
    private String sex;

    @ExcelProperty(value = "年龄", order = 4)
    private String age;

    @ExcelProperty(value = "城市", order = 5)
    private String city;

    @ExcelProperty(value = "备注", order = 6)
    private String remarks;

    }

对应业务代码:

@ApiOperation(value = "导出学生信息", notes = "导出学生信息")
@PostMapping("/exportStudent")
public void exportStudent(@RequestBody String str, HttpServletResponse response) {
    List<StudentExportVo> list = this.getStudentExportVos();
    ExcelUtils.writeExcel(response, StudentExportVo.class, list, "导出学生信息", "sheet1");
}
//数据制造
private List<StudentExportVo> getStudentExportVos() {
    List<StudentExportVo> list = new ArrayList<>();
    StudentExportVo v1 = new StudentExportVo();
    v1.setSchool("北京大学");
    v1.setName("张三");
    v1.setSex("男");
    v1.setAge("20");
    v1.setCity("北京");
    v1.setRemarks("无");
    list.add(v1);
    StudentExportVo v2 = new StudentExportVo();
    v2.setSchool("北京大学");
    v2.setName("李四");
    v2.setSex("男");
    v2.setAge("22");
    v2.setCity("上海");
    v2.setRemarks("无");
    list.add(v2);
    StudentExportVo v3 = new StudentExportVo();
    v3.setSchool("北京大学");
    v3.setName("王五");
    v3.setSex("女");
    v3.setAge("22");
    v3.setCity("青岛");
    v3.setRemarks("无");
    list.add(v3);
    StudentExportVo v4 = new StudentExportVo();
    v4.setSchool("清华大学");
    v4.setName("赵六");
    v4.setSex("女");
    v4.setAge("21");
    v4.setCity("重庆");
    v4.setRemarks("无");
    list.add(v4);
    StudentExportVo v5 = new StudentExportVo();
    v5.setSchool("武汉大学");
    v5.setName("王强");
    v5.setSex("男");
    v5.setAge("24");
    v5.setCity("长沙");
    v5.setRemarks("无");
    list.add(v5);
    StudentExportVo v6 = new StudentExportVo();
    v6.setSchool("武汉大学");
    v6.setName("赵燕");
    v6.setSex("女");
    v6.setAge("21");
    v6.setCity("深圳");
    v6.setRemarks("无");
    list.add(v6);
    StudentExportVo v7 = new StudentExportVo();
    v7.setSchool("厦门大学");
    v7.setName("陆仟");
    v7.setSex("女");
    v7.setAge("21");
    v7.setCity("广州");
    v7.setRemarks("无");
    list.add(v7);
    return list;
}

二、使用注解的版本
导出的结果:
在这里插入图片描述
对应实体类代码:

@Getter
@Setter
@NoArgsConstructor
@AllArgsConstructor
@Data
@ContentRowHeight(30)
@HeadRowHeight(40)
@ColumnWidth(25)
public class StudentExportVo implements Serializable {

    private static final long serialVersionUID = -5809782578272943999L;

    @ExcelProperty(value = {"学生信息","学校"}, order = 1)
    @ContentLoopMerge(eachRow = 3)
    private String school;

    @ExcelProperty(value = {"学生信息","姓名"}, order = 2)
    private String name;

    @ExcelProperty(value = {"学生信息","性别"}, order = 3)
    private String sex;

    @ExcelProperty(value = {"学生信息","年龄"}, order = 4)
    private String age;

    @ExcelProperty(value = {"学生信息","城市"}, order = 5)
    private String city;

    @ExcelProperty(value = {"学生信息","备注"}, order = 6)
    private String remarks;

    }

对应业务代码:同上

@ContentLoopMerge(eachRow = 3) 可以合并单元格,但是他是按指定行数合并,并不能实现内容相同的合并

@ExcelProperty(value = {“学生信息”,“备注”},能实现多个标题,但标题是固定的,不是动态的

三、自定义改造
导出的结果:
在这里插入图片描述

对应实体类代码:

@Getter
@Setter
@NoArgsConstructor
@AllArgsConstructor
@Data
@ContentRowHeight(30)
@HeadRowHeight(40)
@ColumnWidth(25)
public class StudentExportVo implements Serializable {

    private static final long serialVersionUID = -5809782578272943999L;

    @ExcelProperty(value = {"学生信息","学校"}, order = 1)
    //@ContentLoopMerge(eachRow = 3)
    private String school;

    @ExcelProperty(value = {"学生信息","姓名"}, order = 2)
    private String name;

    @ExcelProperty(value = {"学生信息","性别"}, order = 3)
    private String sex;

    @ExcelProperty(value = {"学生信息","年龄"}, order = 4)
    private String age;

    @ExcelProperty(value = {"学生信息","城市"}, order = 5)
    private String city;

    @ExcelProperty(value = {"学生信息","备注"}, order = 6)
    private String remarks;

}

对应业务代码:

@ApiOperation(value = "导出学生信息", notes = "导出学生信息")
    @PostMapping("/exportStudent")
    public void exportStudent(@RequestBody String dynamicTitle, HttpServletResponse response) {
        List<StudentExportVo> list = this.getStudentExportVos();
        try {
            String fileName = "学生信息";
            fileName = URLEncoder.encode(fileName, "UTF-8");
            response.setContentType("application/json;charset=utf-8");
            response.setCharacterEncoding("utf-8");
            response.addHeader("Pargam", "no-cache");
            response.addHeader("Cache-Control", "no-cache");
            response.setHeader("Content-Disposition", "attachment;filename=" + fileName + ".xlsx");
            ServletOutputStream output = response.getOutputStream();
            //需要合并的列
            int[] mergeColumeIndex = {0};
            // 从第二行后开始合并
            int mergeRowIndex = 2;
            //设置动态标题
            List<List<String>> headers = this.getHeaders("学生信息" + dynamicTitle);
            // 头的策略
            WriteCellStyle headWriteCellStyle = new WriteCellStyle();
            // 背景设置为白色
            headWriteCellStyle.setFillForegroundColor(IndexedColors.WHITE.getIndex());
            headWriteCellStyle.setHorizontalAlignment(HorizontalAlignment.CENTER);
            /*WriteFont headWriteFont = new WriteFont();
            headWriteFont.setFontHeightInPoints((short)20);
            headWriteCellStyle.setWriteFont(headWriteFont);*/

            // 内容的策略
            WriteCellStyle contentWriteCellStyle = new WriteCellStyle();
            // 这里需要指定 FillPatternType 为FillPatternType.SOLID_FOREGROUND 不然无法显示背景颜色.头默认了 FillPatternType所以可以不指定
            //contentWriteCellStyle.setFillPatternType(FillPatternType.SOLID_FOREGROUND);
            // 背景绿色
            //contentWriteCellStyle.setFillForegroundColor(IndexedColors.WHITE.getIndex());
            //设置 自动换行
            contentWriteCellStyle.setWrapped(true);
            //设置 垂直居中
            contentWriteCellStyle.setVerticalAlignment(VerticalAlignment.CENTER);
            //设置 水平居中
            contentWriteCellStyle.setHorizontalAlignment(HorizontalAlignment.CENTER);
            /*WriteFont contentWriteFont = new WriteFont();
            // 字体大小
            contentWriteFont.setFontHeightInPoints((short)20);
            contentWriteCellStyle.setWriteFont(contentWriteFont);*/
            // 这个策略是 头是头的样式 内容是内容的样式 其他的策略可以自己实现
            HorizontalCellStyleStrategy horizontalCellStyleStrategy =
                    new HorizontalCellStyleStrategy(headWriteCellStyle, contentWriteCellStyle);

            EasyExcel.write(output, StudentExportVo.class)
                    .sheet("学生信息")
                    .head(headers)
                    .registerWriteHandler(new ExcelMergeHandler(mergeRowIndex, mergeColumeIndex))
                    .registerWriteHandler(horizontalCellStyleStrategy)
//                    .registerWriteHandler(new SimpleColumnWidthStyleStrategy(30))
                    .registerWriteHandler(new AbstractColumnWidthStyleStrategy() {
                        @Override
                        protected void setColumnWidth(WriteSheetHolder writeSheetHolder, List<CellData> list, Cell cell, Head head, Integer integer, Boolean aBoolean) {
                            Sheet sheet = writeSheetHolder.getSheet();
                            int columnIndex = cell.getColumnIndex();
                            if(columnIndex == 5){
                                // 列宽100
                                sheet.setColumnWidth(columnIndex, 10000);
                            }else {
                                // 列宽50
                                sheet.setColumnWidth(columnIndex, 5000);
                            }
                            // 行高40
                            sheet.setDefaultRowHeight((short) 4000);
                        }
                    })
                    .doWrite(list);
            output.flush();
        } catch (IOException e) {
            log.error(e.getMessage(), e);
        }
    }


    private List<List<String>> getHeaders(String dynamicTitle) {
        List<List<String>> headers=new ArrayList<>();
        List<String> schoolHead=new ArrayList<>();
        schoolHead.add(dynamicTitle);
        schoolHead.add("学校");
        List<String> nameHead=new ArrayList<>();
        nameHead.add(dynamicTitle);
        nameHead.add("姓名");
        List<String> sexHead=new ArrayList<>();
        sexHead.add(dynamicTitle);
        sexHead.add("性别");
        List<String> ageHead=new ArrayList<>();
        ageHead.add(dynamicTitle);
        ageHead.add("年龄");
        List<String> cityHead=new ArrayList<>();
        cityHead.add(dynamicTitle);
        cityHead.add("城市");
        List<String> remarksHead=new ArrayList<>();
        remarksHead.add(dynamicTitle);
        remarksHead.add("备注");
        headers.add(schoolHead);
        headers.add(nameHead);
        headers.add(sexHead);
        headers.add(ageHead);
        headers.add(cityHead);
        headers.add(remarksHead);
        return headers;
    }

    //数据制造
    private List<StudentExportVo> getStudentExportVos() {
        List<StudentExportVo> list = new ArrayList<>();
        StudentExportVo v1 = new StudentExportVo();
        v1.setSchool("北京大学");
        v1.setName("张三");
        v1.setSex("男");
        v1.setAge("20");
        v1.setCity("北京");
        v1.setRemarks("无");
        list.add(v1);
        StudentExportVo v2 = new StudentExportVo();
        v2.setSchool("北京大学");
        v2.setName("李四");
        v2.setSex("男");
        v2.setAge("22");
        v2.setCity("上海");
        v2.setRemarks("无");
        list.add(v2);
        StudentExportVo v3 = new StudentExportVo();
        v3.setSchool("北京大学");
        v3.setName("王五");
        v3.setSex("女");
        v3.setAge("22");
        v3.setCity("青岛");
        v3.setRemarks("无");
        list.add(v3);
        StudentExportVo v4 = new StudentExportVo();
        v4.setSchool("清华大学");
        v4.setName("赵六");
        v4.setSex("女");
        v4.setAge("21");
        v4.setCity("重庆");
        v4.setRemarks("无");
        list.add(v4);
        StudentExportVo v5 = new StudentExportVo();
        v5.setSchool("武汉大学");
        v5.setName("王强");
        v5.setSex("男");
        v5.setAge("24");
        v5.setCity("长沙");
        v5.setRemarks("无");
        list.add(v5);
        StudentExportVo v6 = new StudentExportVo();
        v6.setSchool("武汉大学");
        v6.setName("赵燕");
        v6.setSex("女");
        v6.setAge("21");
        v6.setCity("深圳");
        v6.setRemarks("无");
        list.add(v6);
        StudentExportVo v7 = new StudentExportVo();
        v7.setSchool("厦门大学");
        v7.setName("陆仟");
        v7.setSex("女");
        v7.setAge("21");
        v7.setCity("广州");
        v7.setRemarks("无");
        list.add(v7);
        return list;
    }

合并单元格相同内容处理类:ExcelMergeHandler

import com.alibaba.excel.metadata.CellData;
import com.alibaba.excel.metadata.Head;
import com.alibaba.excel.write.handler.CellWriteHandler;
import com.alibaba.excel.write.metadata.holder.WriteSheetHolder;
import com.alibaba.excel.write.metadata.holder.WriteTableHolder;
import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.CellType;
import org.apache.poi.ss.usermodel.Row;
import org.apache.poi.ss.usermodel.Sheet;
import org.apache.poi.ss.util.CellRangeAddress;

import java.util.List;
public class ExcelMergeHandler implements CellWriteHandler {
    private int[] mergeColumnIndex;
    private int mergeRowIndex;

    public ExcelMergeHandler() {
    }

    public ExcelMergeHandler(int mergeRowIndex, int[] mergeColumnIndex) {
        this.mergeRowIndex = mergeRowIndex;
        this.mergeColumnIndex = mergeColumnIndex;
    }

    @Override
    public void beforeCellCreate(WriteSheetHolder writeSheetHolder, WriteTableHolder writeTableHolder, Row row, Head head, Integer columnIndex, Integer relativeRowIndex, Boolean isHead) {

    }

    @Override
    public void afterCellCreate(WriteSheetHolder writeSheetHolder, WriteTableHolder writeTableHolder, Cell cell, Head head, Integer relativeRowIndex, Boolean isHead) {

    }

    @Override
    public void afterCellDataConverted(WriteSheetHolder writeSheetHolder, WriteTableHolder writeTableHolder, CellData cellData, Cell cell, Head head, Integer relativeRowIndex, Boolean isHead) {

    }

    @Override
    public void afterCellDispose(WriteSheetHolder writeSheetHolder, WriteTableHolder writeTableHolder, List<CellData> cellDataList, Cell cell, Head head, Integer relativeRowIndex, Boolean isHead) {

        //当前行
        int curRowIndex = cell.getRowIndex();
        //当前列
        int curColIndex = cell.getColumnIndex();

        if (curRowIndex > mergeRowIndex) {
            for (int i = 0; i < mergeColumnIndex.length; i++) {
                if (curColIndex == mergeColumnIndex[i]) {
                    mergeWithPrevRow(writeSheetHolder, cell, curRowIndex, curColIndex);
                    break;
                }
            }
        }
    }



 /**
     * 当前单元格向上合并
     *
     * @param writeSheetHolder
     * @param cell             当前单元格
     * @param curRowIndex      当前行
     * @param curColIndex      当前列
     */
    private void mergeWithPrevRow(WriteSheetHolder writeSheetHolder, Cell cell, int curRowIndex, int curColIndex) {
        Object curData = cell.getCellTypeEnum() == CellType.STRING ? cell.getStringCellValue() : cell.getNumericCellValue();
        Cell preCell = cell.getSheet().getRow(curRowIndex - 1).getCell(curColIndex);
        Object preData = preCell.getCellTypeEnum() == CellType.STRING ? preCell.getStringCellValue() : preCell.getNumericCellValue();
        // 将当前单元格数据与上一个单元格数据比较
        Boolean dataBool = preData.equals(curData);
        //此处需要注意:因为我是按照工程名称确定是否需要合并的,所以获取每一行第二列数据和上一行第一列数据进行比较,如果相等合并,getCell里面的值,是工程名称所在列的下标
        String s1 = cell.getRow().getCell(0).getStringCellValue();
        String s2 = cell.getSheet().getRow(curRowIndex - 1).getCell(0).getStringCellValue();
        /*BigDecimal d1 = new BigDecimal(cell.getRow().getCell(0).getNumericCellValue());
        BigDecimal d2 = new BigDecimal(cell.getSheet().getRow(curRowIndex - 1).getCell(0).getNumericCellValue());*/
        Boolean bool = s1.compareTo(s2) == 0 ? true:false;
        // 原始的
        // Boolean bool =  cell.getRow().getCell(1).getStringCellValue().equals(cell.getSheet().getRow(curRowIndex - 1).getCell(1).getStringCellValue());
        if (dataBool && bool) {
            Sheet sheet = writeSheetHolder.getSheet();
            List<CellRangeAddress> mergeRegions = sheet.getMergedRegions();
            boolean isMerged = false;
            for (int i = 0; i < mergeRegions.size() && !isMerged; i++) {
                CellRangeAddress cellRangeAddr = mergeRegions.get(i);
                // 若上一个单元格已经被合并,则先移出原有的合并单元,再重新添加合并单元
                if (cellRangeAddr.isInRange(curRowIndex - 1, curColIndex)) {
                    sheet.removeMergedRegion(i);
                    cellRangeAddr.setLastRow(curRowIndex);
                    sheet.addMergedRegion(cellRangeAddr);
                    isMerged = true;
                }
            }
            // 若上一个单元格未被合并,则新增合并单元
            if (!isMerged) {
                CellRangeAddress cellRangeAddress = new CellRangeAddress(curRowIndex - 1, curRowIndex, curColIndex, curColIndex);
                sheet.addMergedRegion(cellRangeAddress);
            }
        }
    }
}

总结:

1、使用自定义合并相同内容单元格时,实体类中的注解@ContentLoopMerge需要去掉,要不然会受到影响

2、该段自定义代码中如内容合并、设置动态标题、内容、以及每个列的宽度及字体都是可以根据自定义策略来进行设置的,具体用法可以参考代码注释说明,根据需要进行使用

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

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

相关文章

markdown文档主题颜色修改

目录 1、选择任意想选择的markdown文档主题css文件&#xff1a; 2、修改背景颜色 1、选择任意想选择的markdown文档主题css文件&#xff1a; 使用工具Typora文件主题路径&#xff1a; C:\Users\AppData\Roaming\Typora\themes&#xff0c;此处我这边就是copy了xydark的css文…

Java 自定义注解

Java 自定义注解&#xff0c; 以及interface Target Retention Around Before After ProceedingJoinPoint JoinPoint 等用法 注解应用非常广泛&#xff0c;我们自定义注解能简化开发各种各种业务 一、关键字解释 (1) 定义注解时&#xff0c;关键字 interface 来表示注解类的类…

高级算法设计与分析(二) -- 递归与分治策略

系列文章目录 高级算法设计与分析&#xff08;一&#xff09; -- 算法引论 高级算法设计与分析&#xff08;二&#xff09; -- 递归与分治策略 高级算法设计与分析&#xff08;三&#xff09; -- 动态规划 未完待续【 高级算法设计与分析&#xff08;四&#xff09; -- 贪…

谷歌新款 Pixel 8 更小、更智能!

一、谷歌 Pixel 8 更小、更智能——比去年的 Pixel 7 贵了 100 美元——不是一点点——贵 与 Pixel 7 一样&#xff0c;Pixel同样在今天 8 比正式发布的更大的 Pixel 8 Pro 兄弟产品更小、更便宜。但今年价格有所上涨&#xff0c;128GB 存储型号的 Pixel 8 起售价为 699.99 美…

腾讯云消息队列11月产品月报 | RocketMQ 5.x 国际站上线

2023年 11月动态 消息队列 RocketMQ 版 1、5.x 形态国际站上线 国际站上线 5.x 集群全系列&#xff0c;第一批先开放新加坡和硅谷地域。 控制台链接&#xff1a;https://console.tencentcloud.com/trocketmq 2、 无感迁移能力 支持用户白屏化操作&#xff0c;将自建的 Roc…

夜莺项目发布 v6.5.0 版本,暗黑菜单来了

大家好&#xff0c;夜莺项目发布 v6.5.0 版本&#xff0c;启用新 logo&#xff0c;菜单支持换肤&#xff0c;支持了暗黑版本的菜单&#xff0c;下一步会支持全站暗黑主题&#xff0c;敬请期待&#xff0c;下面是新 logo。 暗黑菜单 页面右上角点击用户名&#xff0c;在下拉框里…

盘点ASO优化过去到现在的进步

ASO优化行业十年老兵报道&#xff01;从以下几个方面总结了ASO优化的一些变化和进步&#xff0c;给大家分享。 一、优化手段&#xff1a; 过去&#xff0c;ASO优化主要依赖于机刷&#xff0c;通过破解苹果的算法&#xff0c;对苹果账号进行一系列的定向操作行为&#xff08;搜…

React Jsx转换成真实DOM过程?

面试官&#xff1a;说说React Jsx转换成真实DOM过程&#xff1f; 一、是什么 react通过将组件编写的JSX映射到屏幕&#xff0c;以及组件中的状态发生了变化之后 React会将这些「变化」更新到屏幕上 在前面文章了解中&#xff0c;JSX通过babel最终转化成React.createElement这…

双碳背景下能耗在线监测系统硬件选型详述

Acrel-5000web建筑能耗分析系统是用户端能源管理分析系统&#xff0c;在电能管理系统的基础上增加了对水、气、煤、油、热(冷)量等集中采集与分析&#xff0c;通过对用户端所有能耗进行细分和统计&#xff0c;以直观的数据和图表向管理人员或决策层展示各类能源的使用消耗情况&…

SpringBoot访问外部接口的常见方式

文章目录 SpringBoot访问外部接口模拟服务接口RestTemplatepom.xmlRestTemplateConfigClientTestRestTemplateController.java结果 WebClientpom.xmlClientTestWebClientController.java结果 HttpClientpom.xmlClientTestHttpClientController.java结果 OkHttppom.xmlClientTes…

《数据结构、算法与应用C++语言描述》- 最小赢者树模板的C++实现

赢者树 完整可编译运行代码见&#xff1a;Github::Data-Structures-Algorithms-and-Applications/_30winnerTree 比赛规则 假定有 n 个选手参加一次网球比赛。比赛规则是“突然死亡法”(sudden-death mode)&#xff1a;一名选手只要输掉一场球&#xff0c;就被淘汰。一对一对…

【Linux 驱动】Linux设备树(四)—— 设备树驱动LED

有了设备树以后&#xff0c;我们可以将寄存器信息保存到设备树&#xff0c;即便是更换了一个设备&#xff0c;我们也无需修改驱动文件&#xff0c;只需要修改设备树文件并重新编译。 下面介绍两种通过设备树驱动 LED 的最简单的方式&#xff0c;这两种方式的主要是设备树中 re…

自营商城与多商户入驻商城功能与开发流程_OctShop

如今互联网以及电子商务的大趋势下&#xff0c;很多企业或商家都意识到自营商城的重要性。当然&#xff0c;要搭建一个属于自己的自营商城并非简单。需要综合考虑众多的因素&#xff0c;如&#xff1a;用户体验、商品管理、在线支付、功能需求、市场分析等等多个方面。如果是自…

dell服务器 R740xd安装windows server 2019过程记录

公司有两台dell服务器型号是R740xd&#xff0c;增加了存储&#xff0c;更新系统到windows server 2019标准版。 查找了网上的系统安装方式&#xff0c;都没有实践成功&#xff0c;做一下工作记录&#xff0c;给大家做参考。 网络搜索到的两种方式&#xff0c;进行安装 &#x…

全都没有问题(二点五)

java 接口默认方法冲突等问题 基础基础基础 子接口覆盖父接口的默认方法 package com.book;interface AA{public abstract void print();public default void ID(){System.out.println("AA");} } interface BB extends AA{ //接口BB继承AAOverridepublic default…

C#线程的定义和使用方法

引言 在C#编程语言中&#xff0c;线程是一种并发执行的机制&#xff0c;允许程序同时执行多个任务。线程的使用使得我们能够利用计算机的多核处理器&#xff0c;实现程序的并行执行&#xff0c;提高系统的性能和响应能力。本文将详细介绍C#中线程的定义和使用方法&#xff0c;涵…

学习体系结构 - AArch64 虚拟化

学习体系结构 - AArch64 虚拟化 Learn the architecture - AArch64 virtualization Version 1.0 借助 Deepl 翻译文档 个人对文档补充的一部分解释&#xff0c; 仅供学习参考 前 3 章为了解内容&#xff0c;引入虚拟化 第 4-7 章为虚拟化比较核心的内容 第 4 章为第二阶段地址…

windows安装、基本使用vim

标题&#xff1a;windows安装、基本使用vim 1.下载并安装GVIM 百度网盘链接 提取码&#xff1a;2apr 进入安装界面&#xff0c;如下&#xff0c;勾选 其它都是默认即可 参考&#xff1b; 2.在powershell中使用vim 参考blog&#xff1a;window10安装vim编辑器 安装好后&…

机器人制作开源方案 | “校园卫士”-智能巡检机器人

作者&#xff1a;程训聪、柳贺凯、赵坤峰、叶智超、高仁伟 单位&#xff1a;黑龙江科技大学 指导老师&#xff1a;邵文冕、李杨 1. 摘要 针对校园巡检需求设计机器人本体结构&#xff0c;借助Arduino作为控制核心的巡检机器人控制系统构建方法研究了巡检机器人在校园环境下的…

数据结构:图解手撕B-树以及B树的优化和索引

文章目录 为什么需要引入B-树&#xff1f;B树是什么&#xff1f;B树的插入分析B树和B*树B树B*树分裂原理 B树的应用 本篇总结的内容是B-树 为什么需要引入B-树&#xff1f; 回忆一下前面的搜索结构&#xff0c;有哈希&#xff0c;红黑树&#xff0c;二分…等很多的搜索结构&a…