基于EasyExcel实现通用版一对一、一对多、多层嵌套结构数据导出并支持自动合并单元格
接口功能
通用
支持一对一数据结构导出
支持一对多数据结构导出
支持多层嵌套数据结构导出
支持单元格自动合并
原文来自:https://blog.csdn.net/qq_40980205/article/details/136564176
新增及修复
基于我自己的使用场景,新增并能修复一下功能:
- 修复了只有单条一对一数据无法导出问题;
- 修复了多层嵌套数据结构中存在某个嵌套集合为空无法导出问题;
- 修复了只有一条一对多数据导出时报错问题;
完整源码解析
- @MyExcelProperty 作用到导出字段上面,表示这是Excel的一列
- @MyExcelCollection 表示一个集合,主要针对一对多的导出,比如一个老师对应多个科目,科目就可以用集合表示
- @MyExcelEntity 表示一个还存在嵌套关系的导出实体
property为基本数据类型的注解类
package com.example.excel.annotation;import java.lang.annotation.*;@Inherited
@Target({ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
public @interface MyExcelProperty {String name() default "";int index() default Integer.MAX_VALUE;}
property为集合的注解类
package com.example.excel.annotation;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 MyExcelCollection {String name();
}
property为实体对象的注解类
package com.example.excel.annotation;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 MyExcelEntity {String name() default "";
}
导出参数类
package com.example.excel.excel;import lombok.Data;
import lombok.experimental.Accessors;@Data
@Accessors(chain = true)
public class ExportParam {private String fieldName;private String columnName;private Integer order;
}
导出实体类
package com.example.excel.excel;import lombok.Data;import java.util.List;
import java.util.Map;@Data
public class ExportEntity {/*** 导出参数*/private List<ExportParam> exportParams;/*** 平铺后的数据*/private List<Map<String,Object>> data;/*** 每列的合并行数组*/private Map<String, List<Integer[]>> mergeRowMap;
}
导出工具类
package com.example.excel.excel;import com.alibaba.excel.EasyExcel;
import com.example.excel.annotation.MyExcelCollection;
import com.example.excel.annotation.MyExcelEntity;
import com.example.excel.annotation.MyExcelProperty;
import com.google.common.base.Preconditions;
import com.google.common.collect.Lists;
import jakarta.servlet.http.HttpServletResponse;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;import java.io.IOException;
import java.lang.reflect.Field;
import java.lang.reflect.ParameterizedType;
import java.net.URLEncoder;
import java.util.*;
import java.util.stream.Collectors;public class MyExcelUtil {private final String DELIMITER = ".";/*** @param sourceData 导出数据源* @param fileName 导出文件名* @param response*/public void exportData(Collection<Object> sourceData, String sheetName, HttpServletResponse response) {if (CollectionUtils.isEmpty(sourceData)) return;ExportEntity exportEntity = flattenObject(sourceData);List<String> columnList = exportEntity.getExportParams().stream().sorted(Comparator.comparing(ExportParam::getOrder)).map(ExportParam::getFieldName).collect(Collectors.toList());List<List<Object>> exportDataList = new ArrayList<>();//导出数据集for (Map<String, Object> objectMap : exportEntity.getData()) {List<Object> data = new ArrayList<>();columnList.stream().forEach(columnName -> {data.add(objectMap.get(columnName));});exportDataList.add(data);}List<List<String>> headList = columnList.stream().map(Lists::newArrayList).collect(Collectors.toList());try {response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");response.setCharacterEncoding("utf-8");EasyExcel.write(response.getOutputStream()).sheet(sheetName).head(headList).registerWriteHandler(new MergeStrategy(exportEntity)).registerWriteHandler(new HeadHandler(exportEntity)).doWrite(exportDataList);} catch (IOException e) {e.printStackTrace();}}public ExportEntity flattenObject(Collection<Object> sourceData) {Map<String, List<Integer[]>> mergeMap = new HashMap<>();Class aClass = sourceData.stream().findFirst().get().getClass();List<ExportParam> exportParams = getAllExportField(aClass, "");Preconditions.checkArgument(!exportParams.isEmpty(), "export field not found !");List<Map<String, Object>> target = new ArrayList<>();Integer startRow = 0;for (Object sourceDataLine : sourceData) {List<Map<String, Object>> flatData = flattenObject(sourceDataLine, "", startRow, mergeMap);startRow += flatData.size();target.addAll(flatData);}ExportEntity exportEntity = new ExportEntity();exportEntity.setExportParams(exportParams);exportEntity.setData(target);exportEntity.setMergeRowMap(mergeMap);return exportEntity;}/*** @param data 数据行* @param preNode 上一层级字段名* @param startRow 当前数据行所在行数* @param mergeMap 各字段合并行数组* @return*/private List<Map<String, Object>> flattenObject(Object data, String preNode, Integer startRow, Map<String, List<Integer[]>> mergeMap) {List<Map<String, Object>> flatList = new ArrayList<>();if (null == data) return flatList;Class<?> aClass = data.getClass();//获取不为null的excel导出字段List<Field> collectionFields = new ArrayList<>();List<Field> entityFields = new ArrayList<>();List<Field> propertyFields = new ArrayList<>();for (Field field : aClass.getDeclaredFields()) {Object value = getFieldValue(field, data);if (null == value) continue;if (isCollection(field)) {collectionFields.add(field);} else if (isEntity(field)) {entityFields.add(field);} else if (isProperty(field)) {propertyFields.add(field);}}List<Map<String, Object>> entityFlatData = flattenEntityFields(entityFields, data, preNode, startRow, mergeMap);List<List<Map<String, Object>>> collectionFlatData = flattenCollectionFields(collectionFields, data, preNode, startRow, mergeMap);Map<String, Object> objectMap = Collections.emptyMap();if (collectionFields.isEmpty() && entityFields.isEmpty()) {objectMap = flattenPropertyFields(propertyFields, data, preNode);}if (collectionFlatData.isEmpty() && entityFlatData.isEmpty()) {objectMap = flattenPropertyFields(propertyFields, data, preNode);}if (!objectMap.isEmpty()) {flatList.add(objectMap);}//当前层级所有平铺列表List<List<Map<String, Object>>> allFlatData = Lists.newArrayList();if (!entityFlatData.isEmpty()) {allFlatData.add(entityFlatData);}if (!collectionFlatData.isEmpty()) {allFlatData.addAll(collectionFlatData);}List<Map<String, Object>> mergeList = mergeList(data, allFlatData, propertyFields, preNode, startRow, mergeMap);if (!mergeList.isEmpty()) {flatList.addAll(mergeList);}return flatList;}/*** @param preNode 上一层级字段名* @param fieldName 当前字段名* @return*/private String buildPreNode(String preNode, String fieldName) {StringBuffer sb = new StringBuffer();return StringUtils.isEmpty(preNode) ? fieldName : sb.append(preNode).append(DELIMITER).append(fieldName).toString();}/*** @param mergeFields 需要合并的字段* @param preNode 上一层级字段名* @param mergeStartRow 合并开始行* @param mergeEndRow 合并结束行* @param mergeMap 各字段合并行数组*/private void buildMerge(List<Field> mergeFields, String preNode, Integer mergeStartRow, Integer mergeEndRow, Map<String, List<Integer[]>> mergeMap) {for (int k = 0; k < mergeFields.size(); k++) {String fieldName = buildPreNode(preNode, mergeFields.get(k).getName());List<Integer[]> list = mergeMap.get(fieldName);if (null == list) {mergeMap.put(fieldName, new ArrayList<>());}Integer[] rowInterval = new Integer[2];//合并开始行rowInterval[0] = mergeStartRow;//合并结束行rowInterval[1] = mergeEndRow;mergeMap.get(fieldName).add(rowInterval);}}private List<Map<String, Object>> flattenEntityFields(List<Field> entityFields, Object data, String preNode, Integer startRow, Map<String, List<Integer[]>> mergeMap) {List<Map<String, Object>> entityFlatData = Lists.newArrayList();for (Field entityField : entityFields) {entityFlatData = flattenObject(getFieldValue(entityField, data), buildPreNode(preNode, entityField.getName()), startRow, mergeMap);}return entityFlatData;}private List<List<Map<String, Object>>> flattenCollectionFields(List<Field> collectionFields, Object data, String preNode, Integer startRow, Map<String, List<Integer[]>> mergeMap) {List<List<Map<String, Object>>> collectionFlatData = Lists.newArrayList();for (Field collectionField : collectionFields) {Collection collectionValue = (Collection) getFieldValue(collectionField, data);//当前集合字段平铺而成的数据列表List<Map<String, Object>> collectionObjectValue = new ArrayList<>();//间隔行数Integer row = 0;for (Object value : collectionValue) {List<Map<String, Object>> flatData = flattenObject(value, buildPreNode(preNode, collectionField.getName()), startRow + row, mergeMap);if (!flatData.isEmpty()) {collectionObjectValue.addAll(flatData);//下条数据的起始间隔行row += flatData.size();}}if (!collectionObjectValue.isEmpty()) {collectionFlatData.add(collectionObjectValue);}}return collectionFlatData;}private Map<String, Object> flattenPropertyFields(List<Field> propertyFields, Object data, String preNode) {Map<String, Object> flatMap = new HashMap<>();for (Field field : propertyFields) {flatMap.put(buildPreNode(preNode, field.getName()), getFieldValue(field, data));}return flatMap;}private List<Map<String, Object>> mergeList(Object data, List<List<Map<String, Object>>> allFlatData, List<Field> propertyFields, String preNode, Integer startRow, Map<String, List<Integer[]>> mergeMap) {List<Map<String, Object>> flatList = new ArrayList<>();//当前层级下多个集合字段的最大长度即为当前层级其他字段的合并行数Integer maxSize = 0;for (List<Map<String, Object>> list : allFlatData) {maxSize = Math.max(maxSize, list.size());}//记录集合同层级其他字段的合并行数if (maxSize > 0) {buildMerge(propertyFields, preNode, startRow, startRow + maxSize, mergeMap);}//需要合并if (maxSize > 1) {//重新构建平铺的listList<Map<String, Object>> mergeFlatData = new ArrayList<>(maxSize);for (int i = 0; i < maxSize; i++) {mergeFlatData.add(new HashMap<>());}for (List<Map<String, Object>> flatData : allFlatData) {for (int i = 0; i < flatData.size(); i++) {Map<String, Object> flatMap = new HashMap<>();flatMap.putAll(flatData.get(i));//添加同层级字段值if (CollectionUtils.isNotEmpty(propertyFields)) {for (Field field : propertyFields) {flatMap.put(buildPreNode(preNode, field.getName()), getFieldValue(field, data));}}mergeFlatData.get(i).putAll(flatMap);}}flatList.addAll(mergeFlatData);} else {for (List<Map<String, Object>> list : allFlatData) {flatList.addAll(list);}}return flatList;}/*** @param clazz 导出类* @param preNode 上一层级字段名* @return*/private List<ExportParam> getAllExportField(Class<?> clazz, String preNode) {List<ExportParam> exportFields = new ArrayList<>();for (Field declaredField : clazz.getDeclaredFields()) {MyExcelProperty myExcelProperty = declaredField.getDeclaredAnnotation(MyExcelProperty.class);MyExcelEntity myExcelEntity = declaredField.getDeclaredAnnotation(MyExcelEntity.class);MyExcelCollection myExcelCollection = declaredField.getDeclaredAnnotation(MyExcelCollection.class);String fieldName = buildPreNode(preNode, declaredField.getName());if (null != myExcelProperty) {ExportParam exportParam = new ExportParam().setFieldName(fieldName).setColumnName(myExcelProperty.name()).setOrder(myExcelProperty.index());exportFields.add(exportParam);} else if (null != myExcelEntity) {exportFields.addAll(getAllExportField(declaredField.getType(), fieldName));} else if (null != myExcelCollection) {boolean isCollection = Collection.class.isAssignableFrom(declaredField.getType());if (!isCollection) continue;ParameterizedType pt = (ParameterizedType) declaredField.getGenericType();Class<?> clz = (Class<?>) pt.getActualTypeArguments()[0];exportFields.addAll(getAllExportField(clz, fieldName));}}return exportFields;}private boolean isProperty(Field field) {return null != field.getDeclaredAnnotation(MyExcelProperty.class) ? true : false;}private boolean isEntity(Field field) {return null != field.getDeclaredAnnotation(MyExcelEntity.class) ? true : false;}private boolean isCollection(Field field) {boolean isCollection = Collection.class.isAssignableFrom(field.getType());return isCollection && null != field.getAnnotation(MyExcelCollection.class) ? true : false;}private Object getFieldValue(Field field, Object sourceObject) {Object fieldValue;try {field.setAccessible(true);fieldValue = field.get(sourceObject);} catch (IllegalAccessException e) {throw new RuntimeException(e);}return fieldValue;}}
单元格合并策略
```java
package com.example.excel.excel;import com.alibaba.excel.metadata.Head;
import com.alibaba.excel.write.merge.AbstractMergeStrategy;
import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.Sheet;
import org.apache.poi.ss.util.CellRangeAddress;
import org.springframework.util.CollectionUtils;import java.util.List;public class MergeStrategy extends AbstractMergeStrategy {private ExportEntity exportEntity;public MergeStrategy(ExportEntity exportEntity) {this.exportEntity = exportEntity;}@Overrideprotected void merge(Sheet sheet, Cell cell, Head head, Integer relativeRowIndex) {//mergeMap需要加上head的行数String fieldName = head.getHeadNameList().get(0);List<Integer[]> mergeRow = exportEntity.getMergeRowMap().get(fieldName);if (CollectionUtils.isEmpty(mergeRow)) return;int currentColumnIndex = cell.getColumnIndex();int currentRowIndex = cell.getRowIndex();//表头所占行数int headHeight = head.getHeadNameList().size();for (int i = 0; i < mergeRow.size(); i++) {if (currentRowIndex == mergeRow.get(i)[1] + headHeight - 1) {sheet.addMergedRegion(new CellRangeAddress(mergeRow.get(i)[0] + headHeight, mergeRow.get(i)[1] + headHeight - 1,currentColumnIndex, currentColumnIndex));}}}}
表头导出处理
```java
package com.example.excel.excel;import com.alibaba.excel.metadata.Head;
import com.alibaba.excel.metadata.data.WriteCellData;
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 java.util.List;
import java.util.Map;
import java.util.stream.Collectors;public class HeadHandler implements CellWriteHandler {private ExportEntity exportEntity;public HeadHandler(ExportEntity exportEntity) {this.exportEntity = exportEntity;}@Overridepublic void afterCellDispose(WriteSheetHolder writeSheetHolder, WriteTableHolder writeTableHolder,List<WriteCellData<?>> cellDataList, Cell cell, Head head, Integer relativeRowIndex, Boolean isHead) {if (!isHead) return;List<String> headNameList = head.getHeadNameList();Map<String, String> collect = exportEntity.getExportParams().stream().collect(Collectors.toMap(ExportParam::getFieldName, ExportParam::getColumnName));cell.setCellValue(collect.get(headNameList.get(0)));}
}
导出示例
被导出实体
public class CompanyConfigEnntity{@MyExcelProperty(name = "公司名称")private String companyName;@MyExcelCollection(name = "线路配置")private List<LineConfigEntity> lineConfigs;}public class LineConfigEntity{@MyExcelProperty(name = "线路号")private String lineNumber;@MyExcelCollection(name = "消息配置")private List<MsgConfigEntity> msgConfigs;}public class MsgConfigEntity{@MyExcelProperty(name = "消息类型")private String msgType;@MyExcelCollection(name = "子类型配置")private List<SubTypeConfigEntity> subTypeConfigs;}public class SubTypeConfigEntity{@MyExcelProperty(name = "子类型")private String subType;@MyExcelCollection(name = "集中站配置")private List<RtuConfigEntity> rtuConfigs;}
public class RtuConfigEntity{@MyExcelProperty(name = "集中站号")private String rtuNumber;}
接口调用
@RestController
@ReqeutMapping("/companyConfig/companyConfig")
public class CompanyConfigController{@AutoWiredprivate CompanyConfigService companyConfigService;@PostMappinng("/export")public void expooort(HttpServletResponse response){List<CompanyConfigEnityt> list = companyConfigService.queryAll();new MyExcelUtil().exportData(list, "公司配置内容数据", resposne);}
}
效果展示
相关文章:

基于EasyExcel实现通用版一对一、一对多、多层嵌套结构数据导出并支持自动合并单元格
接口功能 通用 支持一对一数据结构导出 支持一对多数据结构导出 支持多层嵌套数据结构导出 支持单元格自动合并 原文来自:https://blog.csdn.net/qq_40980205/article/details/136564176 新增及修复 基于我自己的使用场景,新增并能修复一下功能&#x…...
Java堆内存分析
(一)、线上查看堆内存统计 # 命令用于打印堆内存中每个类的实例数量及其占用的内存,并且只包括活动对象(即存活的对象) jmap -histo:live <pid># 输出到文件方便查看 jmap -histo:live 12345 > aaa.txt(二)、下载dump文件࿰…...

maven高级(day15)
Maven 是一款构建和管理 Java 项目的工具 分模块设计与开发 所谓分模块设计,顾名思义指的就是我们在设计一个 Java 项目的时候,将一个 Java 项目拆分成多 个模块进行开发。 分模块设计我们在进行项目设计阶段,就可以将一个大的项目拆分成若干…...
计算机组成原理(九):乘法器
乘法器原理 乘法器的工作原理可以用二进制乘法来说明。二进制乘法和十进制乘法类似,通过部分积的累加得到结果。 部分积的生成 在二进制乘法中,每一位的乘积是两个二进制数位的 与运算(0 0 0,1 0 0,0 1 0&…...
python【输入和输出】
Python 有三种输出值的方式: 表达式语句print() 函数使用文件对象的 write() 方法,标准输出文件可以用 sys.stdout 引用。 ① 将输出的值转成字符串,可以使用 repr() 或 str() 函数来实现: str(): 函数返回一个用户易…...
2024年华为OD机试真题-判断一组不等式是否满足约束并输出最大差-Python-OD统一考试(E卷)
最新华为OD机试考点合集:华为OD机试2024年真题题库(E卷+D卷+C卷)_华为od机试题库-CSDN博客 每一题都含有详细的解题思路和代码注释,精编c++、JAVA、Python三种语言解法。帮助每一位考生轻松、高效刷题。订阅后永久可看,发现新题及时跟新。 题目描述: 给定一组不等式…...

【json】
JSON JSON是一种轻量级的,按照指定的格式去组织和封装数据的数据交互格式。 本质上是一个带有特定格式的字符串(py打印json时认定为str类型) 在各个编程语言中流通的数据格式,负责不同编程语言中的数据传递和交互,类似于计算机普通话 python与json关系及相互转换…...

基于单片机的无线智能窗帘控制器的设计
摘 要 : 本文以单片机为控制核心 , 基于 PT2262/ 2272 无线收发模块 , 实现了窗帘的无线远程智能控制 . 该控制器通过高频无线收发模块实现了遥控窗帘的开合控制; 根据外部光线强弱实现自动开关窗帘 ; 根据设定时间自动完成开关过程; 通过语音播报当前环境温湿度信息以…...

磁盘满造成业务异常问题排查
最近遇到一个因为磁盘满导致的问题,分享一下,希望能够帮助到以后遇到同样问题的朋友。 早上突然收到业务老师反馈说:上传文件不能正常上传了。 想想之前都好好的,最近又没有更新,为什么突然不能使用了呢?…...
C++例程:使用I/O模拟IIC接口(6)
完整的STM32F405代码工程I2C驱动源代码跟踪 一)myiic.c #include "myiic.h" #include "delay.h" #include "stm32f4xx_rcc.h" //初始化IIC void IIC_Init(void) { GPIO_InitTypeDef GPIO_InitStructure;RCC_AHB1PeriphCl…...

58.在 Vue 3 中使用 OpenLayers 绘制点、线、圆、多边形
前言 在现代 Web 开发中,地图功能已经成为许多应用的重要组成部分。OpenLayers 是一个强大的开源地图库,支持多种地图源和地图操作。结合 Vue 3 的响应式特性,我们可以轻松实现地图的交互功能。本文将详细介绍如何在 Vue 3 中使用 OpenLayer…...

如何快速上手一个鸿蒙工程
作为一名鸿蒙程序猿,当你换了一家公司,或者被交接了一个已有的业务。前辈在找你之前十分钟写了一个他都看不懂的交接文档,然后把一个鸿蒙工程交接给你了,说以后就是你负责了。之后几天你的状态大概就是下边这样的,一堆…...

c++入门之 命名空间与输入输出
1、命名空间 1.1使用命名空间的原因 先看一个例子: #include <iostream>int round 0;int main() {printf("%d", round);return 0; }请问,这个程序能跑起来吗? 答案是否定的 原因是,当我们想创建一个全局变量 …...
GRE技术的详细解释
GRE(Generic Routing Encapsulation,通用路由封装)是一种隧道协议,主要用于在不同网络之间封装和传输其他网络层协议的数据包。它最常用于在IP网络上建立虚拟点到点的隧道连接,是实现VPN的一项关键技术。 下面从原理、…...

Mysql--基础篇--多表查询(JOIN,笛卡尔积)
在MySQL中,多表查询(也称为联表查询或JOIN操作)是数据库操作中非常常见的需求。通过多表查询,你可以从多个表中获取相关数据,并根据一定的条件将它们组合在一起。MySQL支持多种类型的JOIN操作,每种JOIN都有…...
Java 泛型的用法
1. 泛型类 泛型类是指在类定义时使用类型参数来指定类的类型。这样可以在类的内部使用这些类型参数来定义字段、方法的返回类型和参数类型。 public class Box<T> {private T t;public void set(T t) {this.t t;}public T get() {return t;} }在这个例子中,…...

人工智能与物联网:智慧城市的未来
引言 清晨6点,智能闹钟根据你的睡眠状态和天气情况,自动调整叫醒时间;窗帘缓缓打开,阳光洒满房间;厨房里的咖啡机已经为你准备好热饮,而无人驾驶公交车正按时抵达楼下站点。这不是科幻电影的场景ÿ…...

Python标准库之SQLite3
包含了连接数据库、处理数据、控制数据、自定义输出格式及处理异常的各种方法。 官方文档:sqlite3 --- SQLite 数据库的 DB-API 2.0 接口 — Python 3.13.1 文档 官方文档SQLite对应版本:3.13.1 SQLite主页:SQLite Home Page SQL语法教程&a…...

力扣 二叉树的最大深度
树的遍历,dfs与bfs基础。 题目 注意这种题要看根节点的深度是0还是1。 深度优先遍历dfs,通过递归分别计算左子树和右子树的深度,然后返回左右子树深度的最大值再加上 1。递归会一直向下遍历树,直到达到叶子节点或空节点。在回溯…...

Linux_进程间通信_共享内存
什么是共享内存? 对于两个进程,通过在内存开辟一块空间(操作系统开辟的),进程的虚拟地址通过页表映射到对应的共享内存空间中,进而实现通信;物理内存中的这块空间,就叫做共享内存。…...

第19节 Node.js Express 框架
Express 是一个为Node.js设计的web开发框架,它基于nodejs平台。 Express 简介 Express是一个简洁而灵活的node.js Web应用框架, 提供了一系列强大特性帮助你创建各种Web应用,和丰富的HTTP工具。 使用Express可以快速地搭建一个完整功能的网站。 Expre…...

TDengine 快速体验(Docker 镜像方式)
简介 TDengine 可以通过安装包、Docker 镜像 及云服务快速体验 TDengine 的功能,本节首先介绍如何通过 Docker 快速体验 TDengine,然后介绍如何在 Docker 环境下体验 TDengine 的写入和查询功能。如果你不熟悉 Docker,请使用 安装包的方式快…...
Leetcode 3577. Count the Number of Computer Unlocking Permutations
Leetcode 3577. Count the Number of Computer Unlocking Permutations 1. 解题思路2. 代码实现 题目链接:3577. Count the Number of Computer Unlocking Permutations 1. 解题思路 这一题其实就是一个脑筋急转弯,要想要能够将所有的电脑解锁&#x…...
CRMEB 框架中 PHP 上传扩展开发:涵盖本地上传及阿里云 OSS、腾讯云 COS、七牛云
目前已有本地上传、阿里云OSS上传、腾讯云COS上传、七牛云上传扩展 扩展入口文件 文件目录 crmeb\services\upload\Upload.php namespace crmeb\services\upload;use crmeb\basic\BaseManager; use think\facade\Config;/*** Class Upload* package crmeb\services\upload* …...

网络编程(UDP编程)
思维导图 UDP基础编程(单播) 1.流程图 服务器:短信的接收方 创建套接字 (socket)-----------------------------------------》有手机指定网络信息-----------------------------------------------》有号码绑定套接字 (bind)--------------…...
大学生职业发展与就业创业指导教学评价
这里是引用 作为软工2203/2204班的学生,我们非常感谢您在《大学生职业发展与就业创业指导》课程中的悉心教导。这门课程对我们即将面临实习和就业的工科学生来说至关重要,而您认真负责的教学态度,让课程的每一部分都充满了实用价值。 尤其让我…...

mysql已经安装,但是通过rpm -q 没有找mysql相关的已安装包
文章目录 现象:mysql已经安装,但是通过rpm -q 没有找mysql相关的已安装包遇到 rpm 命令找不到已经安装的 MySQL 包时,可能是因为以下几个原因:1.MySQL 不是通过 RPM 包安装的2.RPM 数据库损坏3.使用了不同的包名或路径4.使用其他包…...

力扣热题100 k个一组反转链表题解
题目: 代码: func reverseKGroup(head *ListNode, k int) *ListNode {cur : headfor i : 0; i < k; i {if cur nil {return head}cur cur.Next}newHead : reverse(head, cur)head.Next reverseKGroup(cur, k)return newHead }func reverse(start, end *ListNode) *ListN…...
深度剖析 DeepSeek 开源模型部署与应用:策略、权衡与未来走向
在人工智能技术呈指数级发展的当下,大模型已然成为推动各行业变革的核心驱动力。DeepSeek 开源模型以其卓越的性能和灵活的开源特性,吸引了众多企业与开发者的目光。如何高效且合理地部署与运用 DeepSeek 模型,成为释放其巨大潜力的关键所在&…...

Python训练营-Day26-函数专题1:函数定义与参数
题目1:计算圆的面积 任务: 编写一个名为 calculate_circle_area 的函数,该函数接收圆的半径 radius 作为参数,并返回圆的面积。圆的面积 π * radius (可以使用 math.pi 作为 π 的值)要求:函数接收一个位置参数 radi…...