EasyExcel 导出合并层级单元格

EasyExcel 导出合并层级单元格

一、案例

案例一

  • 1.相同订单号单元格进行合并

image-20250207145806662

合并结果

image-20250207145841217

案例二

  • 1.相同订单号的单元格进行合并
  • 2.相同订单号的总数和总金额进行合并

image-20250207150108895

合并结果

image-20250207150033347

案例三

  • 1.相同订单号的单元格进行合并
  • 2.相同订单号的商品分类进行合并
  • 3.相同订单号的总数和总金额进行合并
  • 4.相同订单号和相同商品分类的分类总数、分类总金额进行合并

image-20250207150213477

合并结果

image-20250207150139989

二、代码实现

相关依赖

<dependency><groupId>com.alibaba</groupId><artifactId>easyexcel</artifactId><version>3.2.1</version>
</dependency><dependency><groupId>cn.hutool</groupId><artifactId>hutool-all</artifactId><version>5.8.16</version>
</dependency><dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId><version>1.18.26</version>
</dependency>
2.1 AbstractMergeStrategy
import com.alibaba.excel.write.handler.CellWriteHandler;
import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.CellType;
import org.apache.poi.ss.usermodel.Sheet;
public abstract class AbstractMergeStrategy implements CellWriteHandler {/*** 最大行索引*/public final static int EXCEL_LAST_INDEX = 1048575;/*** 默认合并起始行*/public final static int DEFAULT_START_ROW_INDEX = 1;/*** 合并抽象方法* @param sheet* @param cell*/public abstract void merge(Sheet sheet, Cell cell);/*** 获取单元格值* @param cell */public Object getCellValue(Cell cell) {return cell.getCellType() == CellType.STRING ? cell.getStringCellValue() : cell.getNumericCellValue();}
}
2.2 ColumnMergeStrategy
import cn.hutool.core.collection.CollUtil;
import com.alibaba.excel.metadata.Head;
import com.alibaba.excel.metadata.data.WriteCellData;
import com.alibaba.excel.write.metadata.holder.WriteSheetHolder;
import com.alibaba.excel.write.metadata.holder.WriteTableHolder;
import com.easy.excel.demo.model.MergeRowColumn;
import lombok.extern.slf4j.Slf4j;
import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.Sheet;
import org.apache.poi.ss.util.CellRangeAddress;import java.util.*;
import java.util.stream.Collectors;/*** 合并单元格策略:适用于列合并*/
@Slf4j
public class ColumnMergeStrategy extends AbstractMergeStrategy {/*** 合并起始行索引*/private int mergeStartRowIndex;/*** 合并结束行索引*/private int mergeEndRowIndex;/*** 待合并的列(如果没有指定,则所有的列都会进行合并)*/private List<Integer> mergeColumnIndexList;/*** 待合并的列父级依赖关系 <需要合并的列索引, 依赖的父级列索引>* key 需要合并的列, value 所依赖的父级列的列表    */private Map<Integer, List<Integer>> mergeColumnIndexMap = new HashMap<>();/*** 合并的行列索引数据(存储每列的数据合并的行列索引范围)*/private Map<Integer, MergeRowColumn> mergeRowColumnMap = new HashMap<>();private Sheet sheet;public ColumnMergeStrategy() {this(DEFAULT_START_ROW_INDEX, EXCEL_LAST_INDEX);}public ColumnMergeStrategy(List<Integer> mergeColumnIndexList) {this(DEFAULT_START_ROW_INDEX, EXCEL_LAST_INDEX, mergeColumnIndexList);}public ColumnMergeStrategy(Map<Integer, List<Integer>> mergeColumnIndexMap) {this.mergeColumnIndexMap = mergeColumnIndexMap;this.mergeColumnIndexList = mergeColumnIndexMap.keySet().stream().collect(Collectors.toList());this.mergeStartRowIndex = DEFAULT_START_ROW_INDEX;this.mergeEndRowIndex = EXCEL_LAST_INDEX;}public ColumnMergeStrategy(int mergeStartRowIndex) {this(mergeStartRowIndex, EXCEL_LAST_INDEX);}public ColumnMergeStrategy(int mergeStartRowIndex, int mergeEndRowIndex) {this(mergeStartRowIndex, mergeEndRowIndex, new ArrayList<>());}public ColumnMergeStrategy(int mergeStartRowIndex, int mergeEndRowIndex, List<Integer> mergeColumnIndexList) {this.mergeStartRowIndex = mergeStartRowIndex;this.mergeEndRowIndex = mergeEndRowIndex;this.mergeColumnIndexList = mergeColumnIndexList;}@Overridepublic void afterCellDispose(WriteSheetHolder writeSheetHolder, WriteTableHolder writeTableHolder, List<WriteCellData<?>> list, Cell cell, Head head, Integer integer, Boolean isHead) {// 头不参与合并if (isHead) {return;}// 初始化 sheetif (sheet == null) {this.sheet = writeSheetHolder.getSheet();}// 如果当前行大于合并起始行则进行合并if (cell.getRowIndex() >= mergeStartRowIndex && cell.getRowIndex() <= mergeEndRowIndex) {// 判断是否是全列合并或者当前列在需要合并列中if (CollUtil.isEmpty(mergeColumnIndexList) || (CollUtil.isNotEmpty(mergeColumnIndexList) && mergeColumnIndexList.contains(cell.getColumnIndex()))) {// 合并单元格this.merge(writeSheetHolder.getSheet(), cell);}}}@Overridepublic void merge(Sheet sheet, Cell cell) {// 当前单元格行、列索引int curRowIndex = cell.getRowIndex();int curColumnIndex = cell.getColumnIndex();// 当前单元格的值为Object curCellValue = this.getCellValue(cell);// 上一行的行索引int aboveRowIndex = curRowIndex - 1;if (aboveRowIndex < 0 || aboveRowIndex < mergeStartRowIndex) {// 初始化当前列的 合并区域范围MergeRowColumn mergeRowColumn = new MergeRowColumn(curRowIndex, curRowIndex, curColumnIndex, curColumnIndex);mergeRowColumnMap.put(curColumnIndex, mergeRowColumn);return;}// 获取上一个单元格Cell aboveCell = sheet.getRow(aboveRowIndex).getCell(curColumnIndex);// 上一个单元格的值Object aboveCellValue = this.getCellValue(aboveCell);// 判断上一个单元格是否能合并if (Objects.equals(curCellValue, aboveCellValue)) {boolean needMerge = true;// 父级列 列表List<Integer> parentColumnIndexList = mergeColumnIndexMap.get(curColumnIndex);if (parentColumnIndexList != null && !parentColumnIndexList.isEmpty()) {for (Integer parentColumnIndex : parentColumnIndexList) {Cell mainCell = sheet.getRow(curRowIndex).getCell(parentColumnIndex);Cell aboveMainCell = sheet.getRow(aboveRowIndex).getCell(parentColumnIndex);Object mainCellValue = this.getCellValue(mainCell);Object aboveMainCellValue = this.getCellValue(aboveMainCell);// 所有主列都需要满足合并条件才能合并副列if (!Objects.equals(mainCellValue, aboveMainCellValue)) {needMerge = false;break;}}}// 允许合并if (needMerge){// 修改当前列的行合并索引范围MergeRowColumn mergeRowColumn = mergeRowColumnMap.get(curColumnIndex);mergeRowColumn.setEndRowIndex(curRowIndex);} else {// 合并已有的单元格,修改行索引指向mergeRowColumnCell(sheet, curRowIndex,curColumnIndex);}} else {// 合并已有的单元格,修改行索引指向mergeRowColumnCell(sheet, curRowIndex,curColumnIndex);}}/*** 检查给定的单元格是否在一个或多个合并区域中。** @return 如果指定单元格是合并区域的一部分,则返回 true;否则返回 false。*/private boolean isMergedRegion(Sheet sheet, Integer rowIndex, Integer columnIndex) {// 获取当前工作表中的所有合并区域数量int numMergedRegions = sheet.getNumMergedRegions();// 遍历所有合并区域for (int i = 0; i < numMergedRegions; i++) {CellRangeAddress region = sheet.getMergedRegion(i);// 检查指定的单元格是否在当前合并区域内if (region.isInRange(rowIndex, columnIndex)) {return true;}}return false;}/*** 合并区域单元格** @param sheet* @param curRowIndex* @param curColumnIndex*/private void mergeRowColumnCell(Sheet sheet, Integer curRowIndex, Integer curColumnIndex) {// 获取当前的列的合并区域索引对象MergeRowColumn mergeRowColumn = mergeRowColumnMap.get(curColumnIndex);// 合并单元格mergeCell(sheet, mergeRowColumn, curRowIndex, curColumnIndex);}/*** 手动合并最后的单元格* (最后一段单元格需要手动合并)*/public void finalMergeCell() {// 遍历所有列的合并索引,合并最后的单元格for (Map.Entry<Integer, MergeRowColumn> entry : mergeRowColumnMap.entrySet()) {Integer columnIndex = entry.getKey();MergeRowColumn mergeRowColumn = entry.getValue();Integer endRowIndex = mergeRowColumn.getEndRowIndex();mergeCell(sheet, mergeRowColumn, endRowIndex, columnIndex);}}/*** 合并单元格** @param sheet* @param mergeRowColumn* @param curRowIndex* @param curColumnIndex*/private void mergeCell(Sheet sheet, MergeRowColumn mergeRowColumn,Integer curRowIndex, Integer curColumnIndex) {// 获取合并的行起始索引Integer startRowIndex = mergeRowColumn.getStartRowIndex();// 获取合并的行结束索引Integer endRowIndex = mergeRowColumn.getEndRowIndex();// 合并单元格(至少有两个单元格以上才能进行合并)if (startRowIndex < endRowIndex) {CellRangeAddress cellAddresses = new CellRangeAddress(startRowIndex, endRowIndex, curColumnIndex, curColumnIndex);// 判断起始单元格是否已经合并过了boolean mergedRegion = isMergedRegion(sheet, startRowIndex, curColumnIndex);if (!mergedRegion) {// 合并指定区域的单元格sheet.addMergedRegion(cellAddresses);}}// 重置合并索引(当前列的行指针下移)mergeRowColumn.setStartRowIndex(curRowIndex);mergeRowColumn.setEndRowIndex(curRowIndex);}
}

源码分析

  • mergeRowColumnMap 是进行合并的关键所在,存储了所有需要合并的列的行合并区域索引,在遍历数据过程中,根据情况进行单元格合并然后偏移指针,或者只修改指针,这样就不需要频繁的进行合并操作。
2.3 MergeRowColumn
@NoArgsConstructor
@AllArgsConstructor
@Data
public class MergeRowColumn {/*** 开始行索引*/private Integer startRowIndex;/*** 结束行索引*/private Integer endRowIndex;/*** 开始列索引*/private Integer startColumnIndex;/*** 结束列索引*/private Integer endColumnIndex;
}

三、测试

案例测试代码

import com.alibaba.excel.EasyExcel;
import com.alibaba.excel.ExcelWriter;
import com.alibaba.excel.util.DateUtils;
import com.alibaba.excel.write.metadata.WriteSheet;
import com.easy.excel.demo.handler.ColumnMergeStrategy;
import com.easy.excel.demo.model.OrderDetailEntity;
import lombok.extern.slf4j.Slf4j;
import org.junit.jupiter.api.Test;
import org.springframework.boot.test.context.SpringBootTest;import java.io.File;
import java.math.BigDecimal;
import java.util.*;
import java.util.stream.Collectors;@Slf4j
@SpringBootTest
public class EasyExcelDemoTest2 {/*** 案例一*/@Testpublic void testMerge1(){File file = new File("order1.xlsx");WriteSheet writeSheet = EasyExcel.writerSheet("sheet1").head(OrderDetailEntity.class).registerWriteHandler(new ColumnMergeStrategy(Arrays.asList(0)))// 订单号.build();ExcelWriter excelWriter = EasyExcel.write(file).build();// 写入数据excelWriter.write(data(), writeSheet);// 手动合并最后的单元格(最后的单元格没有办法合并,需要手动进行合并)writeSheet.getCustomWriteHandlerList().stream().filter(handler -> handler instanceof ColumnMergeStrategy).map(handler -> (ColumnMergeStrategy) handler).forEach(handler -> handler.finalMergeCell());excelWriter.finish();}/*** 案例二*/@Testpublic void testMerge2(){// 输出文件路径File file = new File("order2.xlsx");// 初始化列合并列父级依赖关系Map<Integer, List<Integer>> mergeColumnIndexMap = new HashMap<>();mergeColumnIndexMap.put(0, new ArrayList<>());//订单号mergeColumnIndexMap.put(10, Arrays.asList(0));//总数 ==> 订单号mergeColumnIndexMap.put(11, Arrays.asList(0));//总金额 ==> 订单号WriteSheet writeSheet = EasyExcel.writerSheet("sheet1").head(OrderDetailEntity.class).registerWriteHandler(new ColumnMergeStrategy(mergeColumnIndexMap)).build();ExcelWriter excelWriter = EasyExcel.write(file).build();excelWriter.write(data(), writeSheet);// 手动合并最后的单元格(分段数据注入时最后的单元格没有办法合并,需要手动进行合并)writeSheet.getCustomWriteHandlerList().stream().filter(handler -> handler instanceof ColumnMergeStrategy).map(handler -> (ColumnMergeStrategy) handler).forEach(handler -> handler.finalMergeCell());excelWriter.finish();}/*** 案例三*/@Testpublic void testMerge3(){// 输出文件路径File file = new File("order3.xlsx");// 初始化列合并上级依赖关系Map<Integer, List<Integer>> mergeColumnIndexMap = new HashMap<>();mergeColumnIndexMap.put(0, new ArrayList<>());//订单号mergeColumnIndexMap.put(2, Arrays.asList(0));//商品分类 ==> 订单号mergeColumnIndexMap.put(8, Arrays.asList(0, 2));//分类总数 ==> 订单号,商品分类mergeColumnIndexMap.put(9, Arrays.asList(0, 2));//分类总金额 ==> 订单号,商品分类mergeColumnIndexMap.put(10, Arrays.asList(0));//总数 ==> 订单号mergeColumnIndexMap.put(11, Arrays.asList(0));//总金额 ==> 订单号WriteSheet writeSheet = EasyExcel.writerSheet("sheet1").head(OrderDetailEntity.class).registerWriteHandler(new ColumnMergeStrategy(mergeColumnIndexMap)).build();ExcelWriter excelWriter = EasyExcel.write(file).build();// 模拟分页查询数据for (int i = 0; i < 3; i++) {excelWriter.write(data(), writeSheet);}// 手动合并最后的单元格(分段数据注入时最后的单元格没有办法合并,需要手动进行合并)writeSheet.getCustomWriteHandlerList().stream().filter(handler -> handler instanceof ColumnMergeStrategy).map(handler -> (ColumnMergeStrategy) handler).forEach(handler -> handler.finalMergeCell());excelWriter.finish();}/*** 随机生成测试数据* @return*/private Collection<?> data() {Map<String, List<String>> productMap = getProductMap();List<String> statusList = Arrays.asList("待发货", "已发货", "运输中", "待取货", "已完成");List<OrderDetailEntity> dataList = new ArrayList<>();Random random = new Random();int orderCount = random.nextInt(2) + 5;for (int i = 0; i < orderCount; i++) {String orderCode = "PL" + DateUtils.format(new Date(), "yyyyMMddHHmm") + "000" + i;int orderDetailCount = random.nextInt(10) + 1;List<OrderDetailEntity> detailEntities = new ArrayList<>();Map<String, BigDecimal> categoryTotalQuantityMap = new HashMap<>();Map<String, BigDecimal> categoryTotalPriceMap = new HashMap<>();BigDecimal totalQuantity = BigDecimal.ZERO;BigDecimal totalPrice = BigDecimal.ZERO;for (int j = 0; j < orderDetailCount; j++) {String orderDetailCode = UUID.randomUUID().toString();String productCategory = new ArrayList<String>(productMap.keySet()).get(random.nextInt(productMap.size()));List<String> productList = productMap.get(productCategory);String productCode = "SKU" + (random.nextInt(1000)+1000);String productName = productList.get(random.nextInt(productList.size())) + "-A" + random.nextInt(50);BigDecimal price = new BigDecimal(random.nextInt(2000) + 800);BigDecimal quantity = new BigDecimal(random.nextInt(5) + 1);String status = statusList.get(random.nextInt(statusList.size()));String key = orderCode + "-" + productCategory;BigDecimal categoryTotalQuantity = categoryTotalQuantityMap.get(key);if (categoryTotalQuantity == null) {categoryTotalQuantity = quantity;} else {categoryTotalQuantity = categoryTotalQuantity.add(quantity);}categoryTotalQuantityMap.put(key, categoryTotalQuantity);BigDecimal categoryTotalPrice = categoryTotalPriceMap.get(key);if (categoryTotalPrice == null) {categoryTotalPrice = price.multiply(quantity);} else {categoryTotalPrice = categoryTotalPrice.add(price.multiply(quantity));}categoryTotalPriceMap.put(key, categoryTotalPrice);totalQuantity = totalQuantity.add(quantity);totalPrice = totalPrice.add(price.multiply(quantity));detailEntities.add(OrderDetailEntity.builder().orderCode(orderCode).orderDetailCode(orderDetailCode).productCategory(productCategory).productCode(productCode).productName(productName).price(price).quantity(quantity).status(status).build());}for (OrderDetailEntity item : detailEntities) {String key = item.getOrderCode() + "-" + item.getProductCategory();item.setCategoryTotalQuantity(categoryTotalQuantityMap.get(key));item.setCategoryTotalPrice(categoryTotalPriceMap.get(key));item.setTotalQuantity(totalQuantity);item.setTotalPrice(totalPrice);}detailEntities = detailEntities.stream().sorted(Comparator.comparing(OrderDetailEntity::getOrderCode).thenComparing(OrderDetailEntity::getProductCategory)).collect(Collectors.toList());dataList.addAll(detailEntities);}return dataList;}private Map<String, List<String>> getProductMap() {Map<String, List<String>> productMap = new HashMap<>();// 家电List<String> householdList = new ArrayList<>();householdList.add("电视机");householdList.add("冰箱");householdList.add("洗衣机");householdList.add("空调");productMap.put("家电", householdList);// 数码产品List<String> digitalList = new ArrayList<>();digitalList.add("手机");digitalList.add("摄影机");digitalList.add("电脑");digitalList.add("照相机");digitalList.add("投影仪");digitalList.add("智能手表");productMap.put("数码产品", digitalList);// 健身器材List<String> gymEquipmentList = new ArrayList<>();gymEquipmentList.add("动感单车");gymEquipmentList.add("健身椅");gymEquipmentList.add("跑步机");productMap.put("健身器材", gymEquipmentList);return productMap;}
}

OrderDetailEntity

import com.alibaba.excel.annotation.ExcelProperty;
import com.alibaba.excel.annotation.write.style.*;
import com.alibaba.excel.enums.poi.BorderStyleEnum;
import com.alibaba.excel.enums.poi.FillPatternTypeEnum;
import com.alibaba.excel.enums.poi.HorizontalAlignmentEnum;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;import java.math.BigDecimal;@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
// 头背景设置
@HeadStyle(fillPatternType = FillPatternTypeEnum.SOLID_FOREGROUND, horizontalAlignment = HorizontalAlignmentEnum.CENTER, borderLeft = BorderStyleEnum.THIN, borderTop = BorderStyleEnum.THIN, borderRight = BorderStyleEnum.THIN, borderBottom = BorderStyleEnum.THIN)
//标题高度
@HeadRowHeight(30)
//内容高度
@ContentRowHeight(20)
//内容居中,左、上、右、下的边框显示
@ContentStyle(horizontalAlignment = HorizontalAlignmentEnum.CENTER, borderLeft = BorderStyleEnum.THIN, borderTop = BorderStyleEnum.THIN, borderRight = BorderStyleEnum.THIN, borderBottom = BorderStyleEnum.THIN)
public class OrderDetailEntity {@ExcelProperty(value = "订单号")@ColumnWidth(25)private String orderCode;@ExcelProperty(value = "订单明细")@ColumnWidth(40)private String orderDetailCode;@ExcelProperty(value = "商品分类")@ColumnWidth(20)private String productCategory;@ExcelProperty(value = "商品编码")@ColumnWidth(20)private String productCode;@ExcelProperty(value = "商品名称")@ColumnWidth(20)private String productName;@ExcelProperty(value = "单价")@ColumnWidth(10)private BigDecimal price;@ExcelProperty(value = "数量")@ColumnWidth(10)private BigDecimal quantity;@ExcelProperty(value = "状态")@ColumnWidth(10)private String status;@ExcelProperty(value = "分类总数")@ColumnWidth(20)private BigDecimal categoryTotalQuantity;@ExcelProperty(value = "分类总金额")@ColumnWidth(20)private BigDecimal categoryTotalPrice;@ExcelProperty(value = "总数")@ColumnWidth(10)private BigDecimal totalQuantity;@ExcelProperty(value = "总金额")@ColumnWidth(10)private BigDecimal totalPrice;
}

参考文章

https://blog.csdn.net/xhmico/article/details/141814528

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

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

常用的python库-安装与使用

常用的python库函数 yield关键字openslide库openslide对象的常用属性 cv2库numpy库ASAP库-multiresolutionimageinterface库ASAP库的安装ASAP库的使用 concurrent.futures.ThreadPoolExecutorxml.etree.ElementTree库skimage库PIL.Image库 PIL.Image.Imagedetectron2库数据增强…

C++基础系列【8】如何解决编译器报的错误

博主介绍&#xff1a;程序喵大人 35- 资深C/C/Rust/Android/iOS客户端开发10年大厂工作经验嵌入式/人工智能/自动驾驶/音视频/游戏开发入门级选手《C20高级编程》《C23高级编程》等多本书籍著译者更多原创精品文章&#xff0c;首发gzh&#xff0c;见文末&#x1f447;&#x1f…

程序诗篇里的灵动笔触:指针绘就数据的梦幻蓝图<8>

大家好啊&#xff0c;我是小象٩(๑ω๑)۶ 我的博客&#xff1a;Xiao Xiangζั͡ޓއއ 很高兴见到大家&#xff0c;希望能够和大家一起交流学习&#xff0c;共同进步。 今天我们复习前面学习的指针知识 目录 关于指针数组和数组指针的区别指针数组&#xff08;Array of Poi…

UE5.5 PCGFrameWork--GPU CustomHLSL

在上一篇UE5.5 PCGFrameWork使用入门-CSDN博客 大致介绍了UE5 PCG框架的基本使用. 本篇探索PCGFrame的高级应用--GPU点云。也就是利用GPU HLSL编程对点云进行操纵&#xff0c;可以大幅度提升点云生成效率。 目前在UE5 PCG框架中&#xff0c;点云GPU的应用大致分为三类: Point…

Games202 Lecture11 LTC | Disney principled BRDF | NPR

Shading with microfacet BRDFs under polygonal lighting -Linearly Transformed Cosines(LTC)Real-Time PBR Materials cont. -Disney principled BRDFNon-photorealistic rendering(NPR) Linearly Transformed Cosines(LTC) lobe花瓣 BRDF的2d形状 基本思路: 任意BRDF变…

Flink 内存模型各部分大小计算公式

Flink 的运行平台 如果 Flink 是运行在 yarn 或者 standalone 模式的话&#xff0c;其实都是运行在 JVM 的基础上的&#xff0c;所以首先 Flink 组件运行所需要给 JVM 本身要耗费的内存大小。无论是 JobManager 或者 TaskManager &#xff0c;他们 JVM 内存的大小都是一样的&a…

学习数据结构(8)双向链表

1.双向链表的实现 双向链表一般指带头双向循环链表 &#xff08;1&#xff09;双向链表的声明 &#xff08;2&#xff09;双向链表的打印 &#xff08;3&#xff09;向内存申请节点 &#xff08;4&#xff09;初始化双向链表 或 &#xff08;5&#xff09;尾部插入 &#xf…

【漫话机器学习系列】088.常见的输出层激活函数(Common Output Layer Activation Functions)

在神经网络中&#xff0c;输出层&#xff08;Output Layer&#xff09; 的激活函数&#xff08;Activation Function&#xff09;直接决定了模型的输出形式&#xff0c;并影响损失函数的选择及训练效果。不同的任务类型&#xff08;如分类或回归&#xff09;需要使用不同的激活…

Python 鼠标轨迹 - 防止游戏检测

一.简介 鼠标轨迹算法是一种模拟人类鼠标操作的程序&#xff0c;它能够模拟出自然而真实的鼠标移动路径。 鼠标轨迹算法的底层实现采用C/C语言&#xff0c;原因在于C/C提供了高性能的执行能力和直接访问操作系统底层资源的能力。 鼠标轨迹算法具有以下优势&#xff1a; 模拟…

工业相机在工业生产制造过程中的视觉检测技术应用

随着技术不断发展以及工业4.0时代的到来&#xff0c;利用工业相机进行视觉检测技术已经成为制造业不可或缺的一部分。通过结合先进的计算机视觉、AI算法和自动化设备&#xff0c;工业视觉检测为生产线质量控制和效率提升提供了革命性的解决方案。 一、什么是工业视觉检测技术 …

了解网络层

目录 一、IP协议 二、地址管理 IP地址 概念 作用 格式 网段划分 三、路由选择 网络层要做的事情主要是两个方面&#xff1a; 地址管理&#xff1a;制定一系列的规则&#xff0c;通过地址&#xff0c;描述出网络上一个设备的位置。路由选择&#xff1a;网络环境比较复杂…

NO.11十六届蓝桥杯备战|if-else语句|嵌套if|悬空else|练习4道(C++)

if-else语句 if语句 if语句的语法形式如下&#xff1a; if ( 表达式 ) 语句;表达式成⽴&#xff08;为真&#xff09;&#xff0c;则语句执⾏&#xff0c;表达式不成⽴&#xff08;为假&#xff09;&#xff0c;则语句不执⾏ 0为假&#xff0c;⾮0表⽰真&#xff0c;也就是…

Json-RPC框架项目(一)

目录 1. 项目介绍: 2. 技术选择; 3. 第三方库介绍; 4. 项目功能; 5. 模块功能; 6. 项目实现: 1. 项目介绍: RPC是远程过程调用, 像调用本地接口一样调用远程接口, 进行完成业务处理, 计算任务等, 一个完整的RPC包括: 序列化协议, 通信协议, 连接复用, 服务注册, 服务发…

Discourse 创建和配置用户自定义字段

用户自定义字段能够让你在用户注册的是要求用户提供更多的信息。这些用户提供的信息可以在用户名片&#xff0c;用户摘要页面下显示&#xff0c;甚至还可以通过 Data Explorer plugin 插件进行查询。 本文能够帮助你对这些字段进行配置和设置。 添加一个用户字段 进入 Admin…

从零到一:我的元宵灯谜小程序诞生记

缘起&#xff1a;一碗汤圆引发的灵感 去年元宵节&#xff0c;我正捧着热腾腾的汤圆刷朋友圈&#xff0c;满屏都是"转发锦鲤求灯谜答案"的动态。看着大家对着手机手忙脚乱地切换浏览器查答案&#xff0c;我突然拍案而起&#xff1a;为什么不做一个能即时猜灯谜的微信…

【C++11】lambda和包装器

1.新的类功能 1.1默认的移动构造和移动赋值 原来C类中&#xff0c;有6个默认成员函数&#xff1a;构造函数/析构函数/拷⻉构造函数/拷⻉赋值重载/取地址重 载/const 取地址重载&#xff0c;最后重要的是前4个&#xff0c;后两个⽤处不⼤&#xff0c;默认成员函数就是我们不写…

Java企业电子招投标系统:Spring Cloud微服务架构-强化企业招采竞争力:电子化招投标平台助力效率与成本控制-支持二次开发

​在当今激烈的市场竞争环境下&#xff0c;企业规模的持续扩大使得招采管理变得日益重要&#xff0c;已成为企业提升核心竞争力的关键一环。为了实现更高效、更高质量的招采成果&#xff0c;我们设计了一套基于电子化平台的解决方案&#xff0c;旨在通过电子化招投标系统&#…

计算机毕业设计Spark+大模型知网文献论文推荐系统 知识图谱 知网爬虫 知网数据分析 知网大数据 知网可视化 预测系统 大数据毕业设计 机器学习

温馨提示&#xff1a;文末有 CSDN 平台官方提供的学长联系方式的名片&#xff01; 温馨提示&#xff1a;文末有 CSDN 平台官方提供的学长联系方式的名片&#xff01; 温馨提示&#xff1a;文末有 CSDN 平台官方提供的学长联系方式的名片&#xff01; 作者简介&#xff1a;Java领…

打家劫舍3

今天和打家讲一下打家劫舍3 题目&#xff1a; 题目链接&#xff1a;337. 打家劫舍 III - 力扣&#xff08;LeetCode&#xff09; 小偷又发现了一个新的可行窃的地区。这个地区只有一个入口&#xff0c;我们称之为root。 除了 root 之外&#xff0c;每栋房子有且只有一个“父“…

指定路径安装Ollama

通过鼠标双击安装&#xff0c;默认会安装到C盘下&#xff0c;如果需要更换默认路径则可以通过命令的方式将Ollama安装到其他盘的某个目录下。 OllamaSetup.exe /DIR"D:\Ollama" #DIR指定安装路径 执行上述命令后&#xff0c;会弹出OllamaSetup.exe安装窗体界面&…