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

背景

很久很久以前写了一篇类似的文章 阿里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多级联动下拉");
    }

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

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

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

相关文章

《Linux运维总结:ARM64架构CPU基于docker-compose一离线部署rabbitmq 3.10.25容器版镜像模式集群工具》

总结&#xff1a;整理不易&#xff0c;如果对你有帮助&#xff0c;可否点赞关注一下&#xff1f; 更多详细内容请参考&#xff1a;《Linux运维篇&#xff1a;Linux系统运维指南》 一、部署背景 由于业务系统的特殊性&#xff0c;我们需要面向不通的客户安装我们的业务系统&…

【git】.gitignore 个人总结

文章目录 1. 简介2. 格式3. 参考1. 文件名2. *.后缀3. ?.后缀4. []5. \6. **7. /8. ! 1. 简介 .gitignore是一个用于指定Git版本控制系统忽略特定文件或文件夹的配置文件。当我们在项目中添加文件并想要将它们纳入到版本控制中时&#xff0c;有时我们也会有一些不希望纳入版本…

浪子易支付 最新版本源码 增加杉德、付呗支付插件 PayPal、汇付、虎皮椒插件

内容目录 一、详细介绍二、效果展示1.部分代码2.效果图展示 三、学习资料下载 一、详细介绍 2024/05/01&#xff1a; 1.更换全新的手机版支付页面风格 2.聚合收款码支持填写备注 3.后台支付统计新增利润、代付统计 4.删除结算记录支持直接退回商户金额 2024/03/31&#xff1a…

五一 大项目

Docker 中的 Nginx 服务为什么要启用 HTTPS 一安装容器 1 安装docker-20.10.17 2 安装所需的依赖 sudo yum install -y yum-utils device-mapper-persistent-data lvm23 添加Docker官方仓库 sudo yum-config-manager --add-repo https://download.docker.com/linux/centos…

【C++】命名空间和IO流

一切都从这个代码开始&#xff01;&#xff01;&#xff01; #include<iostream>using namespace std;int main() {cout << "Hello world!" << endl;return 0; } 命名空间 当我们写了这么一段代码的时候... Ctrl F5运行&#xff0c;发现报错了..…

C++算法题 - 二叉树层次遍历

目录 199. 二叉树的右视图637. 二叉树的层平均值102. 二叉树的层序遍历103. 二叉树的锯齿形层序遍历 199. 二叉树的右视图 LeetCode_link 给定一个二叉树的 根节点 root&#xff0c;想象自己站在它的右侧&#xff0c;按照从顶部到底部的顺序&#xff0c;返回从右侧所能看到的节…

一文搞懂前端跨页面通信的那些方案们

前端开发逃避不开跨页面通信这项工作&#xff0c;跨页面通信&#xff0c;就好比A页面要和B页面说话&#xff0c;可能只是说一句话&#xff0c;不需要回话&#xff0c;可能是要给一些东西&#xff0c;希望得到回复&#xff0c;并频繁进行沟通&#xff0c;接下来我们说说这些跨页…

HKT x Microsoft 365 Copilot 助力企业提升工作效率

人工智能&#xff08;AI&#xff09;在工作场所的应用和整合日益增多&#xff0c;更成为塑造未来工作模式的革新趋势之一。AI不仅简化和改进了许多任务和流程&#xff0c;还为协作、沟通和创新开辟了新的机遇。不久前&#xff0c;微软新推出AI驱动的生成式生产力工具— Microso…

【Elasticsearch运维系列】Elasticsearch7.12.1启动指定版本JDK:你学废了吗?

一、背景 一套生ES集群&#xff0c;版本为7.12.1&#xff0c;近期频繁告警&#xff0c;频繁出现索引分片异常&#xff0c;索引状态异常&#xff0c;导致应用无法正常写入ES&#xff0c;另外&#xff0c;也经常出现节点掉问题。通过分析相关ES日志&#xff0c;显示和当前JAVA G…

【LAMMPS学习】八、基础知识(5.8)LAMMPS 中热化 Drude 振荡器教程

8. 基础知识 此部分描述了如何使用 LAMMPS 为用户和开发人员执行各种任务。术语表页面还列出了 MD 术语&#xff0c;以及相应 LAMMPS 手册页的链接。 LAMMPS 源代码分发的 examples 目录中包含的示例输入脚本以及示例脚本页面上突出显示的示例输入脚本还展示了如何设置和运行各…

DDD架构学习

文章目录 领域建模事件风暴四色建模法 DDD名称解析领域子域核心域通用域支撑域限界上下文战术设计实体值对象聚合和聚合根工厂资源库领域服务领域事件 DDD代码的分层名词解析实体值对象聚合根领域服务领域事件 VO&DTO&DO&PO博客 领域建模 领域驱动设计的核心在于领…

【设计模式】——专栏概述

&#x1f4bb;博主现有专栏&#xff1a; C51单片机&#xff08;STC89C516&#xff09;&#xff0c;c语言&#xff0c;c&#xff0c;离散数学&#xff0c;算法设计与分析&#xff0c;数据结构&#xff0c;Python&#xff0c;Java基础&#xff0c;MySQL&#xff0c;linux&#xf…

智慧校园与学生成长

当时间追溯到2018年&#xff0c;技术的前进已经逾越了人们的幻想&#xff0c;很多先进的设备也投入到了大众的日子中去&#xff0c;为信息化的推进带来了全新的改动。与此同时&#xff0c;校园也不甘落后&#xff0c;将教育与信息化得到一个完美的融合&#xff0c;为学生的未来…

想要买到心仪的旋转式孔板流量计吗?

选择旋转式孔板流量计可不能云里雾里的乱选择呀&#xff0c;煤矿对产品质量要求很严格的。所以我们要先了解产品的再决定才是对的选择。 旋转式孔板流量计技术参数【1--5--9】 规格&#xff1a;DN15&#xff5e;DN1000 孔径比(βd/D)&#xff1a;β0&#xff0e;2—0&#xff…

Web前端三大主流框架是什么?

Web前端开发领域的三大主流框架分别是Angular、React和Vue.js。它们在Web开发领域中占据着重要的地位&#xff0c;各自拥有独特的特点和优势。 Angular Angular是一个由Google开发的前端框架&#xff0c;最初版本称为AngularJS&#xff0c;后来升级为Angular。它是一个完整的…

MySQL迁移data目录

MYSQL数据库有时候安装好了&#xff0c;想移动一下data目录&#xff0c;但是又不想重新安装一下&#xff0c;就只能想办法把这个目录迁移一下。 先找到my.ini配置文件&#xff0c;可以全局搜索一下&#xff0c; 找到之后&#xff0c;把这个地方修改一下&#xff0c;就把data目…

IP协议全解析:网络层通信的基石

⭐小白苦学IT的博客主页⭐ ⭐初学者必看&#xff1a;Linux操作系统入门⭐ ⭐代码仓库&#xff1a;Linux代码仓库⭐ ❤关注我一起讨论和学习Linux系统❤ 前言 在数字化时代的浪潮中&#xff0c;网络通信无处不在&#xff0c;它连接着世界的每一个角落&#xff0c;承载着信息的高…

评估Transitions

Stateflow使用图表中的转换从一种OR状态移动到另一种OR状态。对于图表执行的输入和执行工作流,Stateflow评估转换以确定它们是否有效。有效转换是条件标签为true且路径以状态结束的转换。如果转换有效,则Stateflow将从源状态退出并进入目标状态。 评估Transitions的工作流 T…

Java八股文3

3.垃圾回收 1.对象什么时候可以被垃圾器回收 1.垃圾回收的概念 为了让程序员更专注于代码的实现&#xff0c;而不用过多的考虑内存释放的问题&#xff0c;所以&#xff0c; 在Java语言中&#xff0c;有了自动的垃圾回收机制&#xff0c;也就是我们熟悉的GC(Garbage Collection)…

代码随想录算法训练营第四十二天| 01背包问题理论基础,416. 分割等和子集

理论基础&#xff1a; 带你学透0-1背包问题&#xff01;| 关于背包问题&#xff0c;你不清楚的地方&#xff0c;这里都讲了&#xff01;| 动态规划经典问题 | 数据结构与算法_哔哩哔哩_bilibili很多同学对背包问题的理解程度都处于一种黑盒的状态&#xff0c;及时这道题目在力…