easyExcel动态应用案例

代码链接:https://download.csdn.net/download/ly1h1/91940299

1.案例说明:

    1.1.导入功能

导入数据实现转换成  List<List<String>> headers和  List<List<String>> datas,后续补充可以与数据模型注解结合,形成类对象集合;

    1.2.导出功能

复合表头、下拉框选择、列宽、表头高度,均引出到业务层进行自定义设置。

2.引入依赖

<dependency><groupId>com.alibaba</groupId><artifactId>easyexcel-core</artifactId><version>3.3.4</version><scope>compile</scope>
</dependency>

2.导入

2.1 Controller接口

2.2  导入工具类-DymaticExcelImportUtil

package com.ruoyi.common.security.utils;
import com.alibaba.excel.EasyExcel;
import com.alibaba.excel.context.AnalysisContext;
import com.alibaba.excel.metadata.Head;
import com.alibaba.excel.metadata.data.ReadCellData;
import com.alibaba.excel.read.listener.ReadListener;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;import java.io.InputStream;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Objects;/*** 修复类型转换异常的Excel导入工具类* 解决:java.lang.String cannot be cast to com.alibaba.excel.metadata.data.ReadCellData*/
public class DymaticExcelImportUtil {private static final Logger log = LoggerFactory.getLogger(DymaticExcelImportUtil.class);/*** 解析Excel输入流为表头和数据列表* @param inputStream Excel文件输入流* @return 包含表头和数据的结果对象*/public static ExcelParseResult importToList(InputStream inputStream) {if (Objects.isNull(inputStream)) {throw new IllegalArgumentException("输入流不能为空");}ExcelReadListener listener = new ExcelReadListener();try {// 关键修复:指定读取原始数据(不自动转换为String)EasyExcel.read(inputStream).registerReadListener(listener).headRowNumber(1) // 指定表头所在行数(默认第一行).doReadAll();} catch (Exception e) {log.error("Excel解析失败: {}", e.getMessage(), e);throw new RuntimeException("Excel导入错误: " + e.getMessage());} finally {try {inputStream.close();} catch (Exception e) {log.warn("输入流关闭失败: {}", e.getMessage());}}return listener.getResult();}/*** 自定义监听器(修复泛型类型匹配问题)*/private static class ExcelReadListener implements ReadListener<Map<Integer, Object>> {private final List<List<String>> headerLists = new ArrayList<>();private final List<List<String>> dataLists = new ArrayList<>();private boolean isHeaderParsed = false;/*** 处理表头数据*/@Overridepublic void invokeHead(Map<Integer, ReadCellData<?>> headMap, AnalysisContext context) {if (!isHeaderParsed) {List<String> headerRow = new ArrayList<>();// 遍历表头单元格并转换为字符串for (int i = 0; i < headMap.size(); i++) {ReadCellData<?> cellData = headMap.get(i);headerRow.add(cellData.getStringValue() != null ? cellData.getStringValue().trim() : "");}headerLists.add(headerRow);isHeaderParsed = true;}}/*** 处理数据行(使用Object接收所有类型,避免强制转换)*/@Overridepublic void invoke(Map<Integer, Object> dataMap, AnalysisContext context) {List<String> dataRow = new ArrayList<>();// 遍历数据单元格,兼容所有类型for (int i = 0; i < dataMap.size(); i++) {Object cellValue = dataMap.get(i);dataRow.add(convertToString(cellValue));}dataLists.add(dataRow);}/*** 解析完成回调*/@Overridepublic void doAfterAllAnalysed(AnalysisContext context) {log.info("Excel解析完成 - 表头行数: {}, 数据行数: {}",headerLists.size(), dataLists.size());}/*** 万能类型转换:将任意单元格值转换为字符串*/private String convertToString(Object value) {if (value == null) {return "";}// 处理ReadCellData类型(原始单元格数据)if (value instanceof ReadCellData<?>) {ReadCellData<?> cellData = (ReadCellData<?>) value;if (cellData.getStringValue() != null) {return cellData.getStringValue().trim();} else if (cellData.getNumberValue() != null) {return cellData.getNumberValue().toString();} else if (cellData.getBooleanValue() != null) {return cellData.getBooleanValue().toString();}}// 处理其他类型(如String、Number等)return value.toString().trim();}public ExcelParseResult getResult() {return new ExcelParseResult(headerLists, dataLists);}}/*** Excel解析结果封装类*/public static class ExcelParseResult {private final List<List<String>> headerLists;private final List<List<String>> dataLists;public ExcelParseResult(List<List<String>> headerLists, List<List<String>> dataLists) {this.headerLists = headerLists;this.dataLists = dataLists;}public List<List<String>> getHeaderLists() {return headerLists;}public List<List<String>> getDataLists() {return dataLists;}}
}

3.导出

3.1 接口

package com.ruoyi.system.controller;import com.ruoyi.common.core.exception.ServiceException;
import com.ruoyi.system.service.IUserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.net.URLEncoder;/*** 用户控制器*/
@RestController
@RequestMapping("/api/user")
public class UserController {@Autowiredprivate IUserService userService;/*** 导出用户Excel*/@GetMapping("/export/excel")public void exportUserExcel(HttpServletResponse response) {try {// 获取Excel字节数组byte[] excelBytes = userService.exportUsersToExcel();// 设置响应头response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");response.setCharacterEncoding("UTF-8");String fileName = URLEncoder.encode("用户数据列表", "UTF-8").replaceAll("\\+", "%20");response.setHeader("Content-Disposition", "attachment;filename*=UTF-8''" + fileName + ".xlsx");// 写入响应流response.getOutputStream().write(excelBytes);response.getOutputStream().flush();} catch (Exception e) {// 异常处理try {response.setContentType("text/html;charset=utf-8");response.getWriter().write("导出失败:" + e.getMessage());} catch (IOException ex) {throw new ServiceException("导出失败!");}}}
}

3.2 Service

package com.ruoyi.system.service.impl;import com.ruoyi.common.core.utils.DateUtils;
import com.ruoyi.common.security.utils.*;
import com.ruoyi.system.api.domain.SysDictData;
import com.ruoyi.system.domain.RpCompanyconfig;
import com.ruoyi.system.domain.User;
import com.ruoyi.system.mapper.RpCompanyconfigMapper;
import com.ruoyi.system.service.IRpCompanyconfigService;
import com.ruoyi.system.service.IUserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;import java.io.IOException;
import java.util.*;import org.springframework.stereotype.Service;import java.util.List;import static com.ruoyi.common.security.utils.ExcelFieldExtractor.extractField;/*** 用户服务实现类*/
@Service
public class UserServiceImpl implements IUserService
{@Overridepublic List<User> listAllUsers() {// 模拟数据库查询return new ArrayList<>(Arrays.asList(new User(1L, "张三", 25, "zhangsan@example.com"),new User(2L, "李四", 30, "lisi@example.com"),new User(3L, "王五", 28, "water"),new User(4L, "赵六", 32, "zhaoliu@example.com")));}@Overridepublic byte[] exportUsersToExcel() throws IOException {// 1. 获取用户数据List<User> userList = listAllUsers();// 2. 构建表头List<List<String>> headList = new ArrayList<>();List<String> H1=  new ArrayList<>();List<String> H2=  new ArrayList<>();List<String> H3=  new ArrayList<>();List<String> H4=  new ArrayList<>();H1.add("用户ID");H1.add("用户ID");H2.add("信息");H2.add("姓名");H3.add("信息");H3.add("年龄");H4.add("邮箱");H4.add("邮箱");headList.add(H1);headList.add(H2);headList.add(H3);headList.add(H4);// 设置下拉框数据(key:列索引,value:下拉选项数组)// 为第4列(性别列,索引从0开始)设置下拉框Map<Integer, String[]> dropdownDataMap = new HashMap<>();dropdownDataMap.put(3, new String[]{"男", "女", "未知"});// 3. 转换数据格式List<List<String>> dataList = new ArrayList<>();for (User user : userList){List<String> row = new ArrayList<>();row.add(String.valueOf(user.getId()));row.add(user.getName());row.add(String.valueOf(user.getAge()));row.add(user.getEmail());dataList.add(row);}// 4. 设置列宽List<Integer> widthList = Arrays.asList(60, 15, 8, 50);List<List<ExceSortModelVO>> list= GenericExcelModelConverter.convertToExcelModelList(userList);for(int i=0;i<list.get(0).size();i++){if (!list.get(0).get(i).getDictType().equals("")){List<String> listItem = new ArrayList<>();List<SysDictData> sysDic =  DictUtils.getDictCache(list.get(0).get(i).getDictType());for (SysDictData item : sysDic){listItem.add(item.getDictLabel());}dropdownDataMap.put(i, listItem.toArray(new String[listItem.size()]));}}List<List<String>> nameList =  ExcelFieldExtractor.extractField(list, ExcelFieldExtractor.FieldType.NAME);List<List<String>> valueList =  ExcelFieldExtractor.extractField(list, ExcelFieldExtractor.FieldType.VALUE);List<List<Integer>> widthList2 =  ExcelFieldExtractor.extractField(list, ExcelFieldExtractor.FieldType.WIDTH);// 表头行高设置(30点,比默认更高,适合显示较长表头)float headerHeight = 30f;// 5. 调用工具类生成Excelreturn DymaticExcelUtil.exportToBytes(headList, valueList, "用户数据列表", widthList,dropdownDataMap,headerHeight);}
}

3.3 下拉框类

package com.ruoyi.common.security.utils;import com.alibaba.excel.write.handler.SheetWriteHandler;
import com.alibaba.excel.write.metadata.holder.WriteSheetHolder;
import com.alibaba.excel.write.metadata.holder.WriteWorkbookHolder;
import org.apache.poi.ss.usermodel.*;
import org.apache.poi.ss.util.CellRangeAddressList;
import org.apache.poi.xssf.usermodel.XSSFDataValidation;import java.util.HashMap;
import java.util.Map;
import java.util.Set;/*** Excel下拉框数据处理器* 支持基于Map配置多列下拉框选项*/
public class DropdownDataHandler implements SheetWriteHandler {// 存储列索引与下拉选项的映射关系 (列索引 -> 下拉选项数组)private final Map<Integer, String[]> dropdownDataMap;/*** 构造方法* @param dropdownDataMap 列索引与下拉选项的映射*/public DropdownDataHandler(Map<Integer, String[]> dropdownDataMap) {this.dropdownDataMap = dropdownDataMap != null ? dropdownDataMap : new HashMap<>();}@Overridepublic void beforeSheetCreate(WriteWorkbookHolder writeWorkbookHolder, WriteSheetHolder writeSheetHolder) {// 工作表创建前无需操作}@Overridepublic void afterSheetCreate(WriteWorkbookHolder writeWorkbookHolder, WriteSheetHolder writeSheetHolder) {Sheet sheet = writeSheetHolder.getSheet();Workbook workbook = writeWorkbookHolder.getWorkbook();// 获取所有需要设置下拉框的列Set<Map.Entry<Integer, String[]>> entries = dropdownDataMap.entrySet();for (Map.Entry<Integer, String[]> entry : entries) {int columnIndex = entry.getKey();String[] options = entry.getValue();if (options == null || options.length == 0) {continue;}// 创建下拉框约束DataValidationHelper helper = sheet.getDataValidationHelper();DataValidationConstraint constraint = helper.createExplicitListConstraint(options);// 设置下拉框作用范围(从第2行到第1000行,可根据实际需求调整)CellRangeAddressList addressList = new CellRangeAddressList(1, // 起始行索引(0表示表头行,1表示数据开始行)1000, // 结束行索引columnIndex, // 起始列索引columnIndex  // 结束列索引);// 创建数据验证并应用到工作表DataValidation dataValidation = helper.createValidation(constraint, addressList);// 设置错误提示if (dataValidation instanceof XSSFDataValidation) {dataValidation.setShowErrorBox(true);dataValidation.setSuppressDropDownArrow(true);} else {dataValidation.setShowErrorBox(true);}sheet.addValidationData(dataValidation);}}
}

3.4  边框类

package com.ruoyi.common.security.utils;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.BorderStyle;
import org.apache.poi.ss.usermodel.CellStyle;
import org.apache.poi.ss.usermodel.IndexedColors;
import com.alibaba.excel.write.style.AbstractCellStyleStrategy;
import org.apache.poi.ss.usermodel.*;
import java.util.List;
import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.CellStyle;
import org.apache.poi.ss.usermodel.Workbook;
import org.apache.poi.ss.usermodel.BorderStyle;
import org.apache.poi.ss.usermodel.IndexedColors;
import org.apache.poi.ss.usermodel.Sheet;public class BorderStyleHandler implements CellWriteHandler {private void setBorderStyle(Cell cell) {if (cell == null) {return;}// 现在可以正确调用 POI Cell 的 getSheet() 方法Sheet sheet = cell.getSheet();if (sheet == null) {return;}Workbook workbook = sheet.getWorkbook();CellStyle cellStyle = workbook.createCellStyle();// 设置边框样式cellStyle.setBorderTop(BorderStyle.THIN);cellStyle.setBorderBottom(BorderStyle.THIN);cellStyle.setBorderLeft(BorderStyle.THIN);cellStyle.setBorderRight(BorderStyle.THIN);// 设置边框颜色cellStyle.setTopBorderColor(IndexedColors.BLACK.getIndex());cellStyle.setBottomBorderColor(IndexedColors.BLACK.getIndex());cellStyle.setLeftBorderColor(IndexedColors.BLACK.getIndex());cellStyle.setRightBorderColor(IndexedColors.BLACK.getIndex());cell.setCellStyle(cellStyle);}// 其他接口方法实现...@Overridepublic void afterCellDispose(WriteSheetHolder writeSheetHolder, WriteTableHolder writeTableHolder,List<WriteCellData<?>> cellDataList, Cell cell, Head head,Integer relativeRowIndex, Boolean isHead) {setBorderStyle(cell);}
}

3.5 列宽设定类

package com.ruoyi.common.security.utils;
import com.alibaba.excel.write.handler.SheetWriteHandler;
import com.alibaba.excel.write.metadata.holder.WriteSheetHolder;
import com.alibaba.excel.write.metadata.holder.WriteWorkbookHolder;
import java.util.ArrayList;
import java.util.List;/*** 正确实现 SheetWriteHandler 接口(而非 WriteHandler 的子接口)* 适配 easyexcel-core:3.3.4 版本*/
public class FixedColumnWidthHandler implements SheetWriteHandler {private static final int DEFAULT_COLUMN_WIDTH = 15;/*** 存储每列宽度(单位:1/256 字符宽度,EasyExcel 底层单位)*/private final List<Integer> columnWidths = new ArrayList<>();/*** 添加列宽配置* @param columnIndex 列索引(从0开始)* @param width 列宽(单位:字符)*/public void addColumnWidth(int columnIndex, int width) {// 确保列表容量足够,避免索引越界while (columnWidths.size() <= columnIndex) {columnWidths.add(DEFAULT_COLUMN_WIDTH * 256); // 默认宽度转底层单位}columnWidths.set(columnIndex, width * 256); // 传入宽度转底层单位}/*** 工作表创建前触发(无需处理)*/@Overridepublic void beforeSheetCreate(WriteWorkbookHolder writeWorkbookHolder, WriteSheetHolder writeSheetHolder) {// 空实现}/*** 工作表创建后触发(核心:设置列宽)*/@Overridepublic void afterSheetCreate(WriteWorkbookHolder writeWorkbookHolder, WriteSheetHolder writeSheetHolder) {// 遍历设置每列宽度for (int i = 0; i < columnWidths.size(); i++) {writeSheetHolder.getSheet().setColumnWidth(i, columnWidths.get(i));}}
}

3.6 表头高度类

package com.ruoyi.common.security.utils;import com.alibaba.excel.write.handler.RowWriteHandler;
import com.alibaba.excel.write.metadata.holder.WriteSheetHolder;
import com.alibaba.excel.write.metadata.holder.WriteTableHolder;
import org.apache.poi.ss.usermodel.Row;/*** 表头行高处理器(在表头行创建后立即设置高度)*/
public class HeaderHeightHandler implements RowWriteHandler {private final float headerHeight; // 表头行高(单位:点)// 构造方法接收表头行高参数public HeaderHeightHandler(float headerHeight) {// 确保行高不小于10点,避免过小导致不可见this.headerHeight = Math.max(headerHeight, 10f);}/*** 行创建后立即设置高度(关键修复:在此处设置表头行高)*/@Overridepublic void afterRowCreate(WriteSheetHolder writeSheetHolder, WriteTableHolder writeTableHolder, Row row, Integer relativeRowIndex, Boolean isHead) {// 只处理表头行(isHead为true时)if (Boolean.TRUE.equals(isHead)) {// 直接设置行高(单位:点),POI会自动转换为内部单位row.setHeightInPoints(headerHeight);}}// 其他接口方法空实现@Overridepublic void beforeRowCreate(WriteSheetHolder writeSheetHolder, WriteTableHolder writeTableHolder, Integer rowIndex, Integer relativeRowIndex, Boolean isHead) {}
}

3.7 导出数据模型类

package com.ruoyi.common.security.utils;public class ExceSortModelVO {private String name;private String value;private int sort;private  int width;private  String dictType;public String getName() {return name;}public void setName(String name) {this.name = name;}public String getValue() {return value;}public void setValue(String value) {this.value = value;}public int getSort() {return sort;}public void setSort(int sort) {this.sort = sort;}public int getWidth() {return width;}public void setWidth(int width) {this.width = width;}public String getDictType() {return dictType;}public void setDictType(String dictType) {this.dictType = dictType;}
}

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

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

相关文章

【数据结构入门】排序算法(5):计数排序

目录 1. 比较排序和非比较排序 2. 计数排序的原理 2.1 计数排序的弊端 3.代码复现 3.1 代码分析 3.2 排序核心 3.3 时间、空间复杂度 1. 比较排序和非比较排序 比较排序是根据排序元素的具体数值比较来进行排序&#xff1b;非比较排序则相反&#xff0c;非比较排序例如&…

输入3.8V~32V 输出2A 的DCDC降压芯片SCT9320

同志们&#xff0c;今天来个降压芯片SCT9320。输入3.8V~32V&#xff0c;输出最高可以达到2A。0.8V的参考电压。500k的开关频率。一共八个引脚&#xff0c;两个NC&#xff08;为什么不做成六个引脚呢&#xff1f;&#xff09;。EN引脚悬空或者接到VIN都可以直接启动&#xff0c;…

C++类和对象详解(2);初识类的默认成员函数

1.类的默认成员函数默认成员函数就是用户没有显示实现&#xff0c;编译器会自动生成的成员函数称为默认成员函数。一个类我们不写的情况下编译器会默认生成以下的6个默认成员函数。&#xff08;1&#xff09;构造函数&#xff1a;主要完成初始化的工作&#xff08;2&#xff09…

PLC通信 Tpc客户端Socket

1.PLC通信 namespace _2.PLC通信 {public partial class Form1 : Form{public Form1(){InitializeComponent();}//连接//1.型号: 跟PLC沟通 使用哪个型号的PLC//2.IP 同上//3.机台号:同上//4.插槽号:同上Plc plc new Plc(CpuType.S71200, "192.168.25.80", 0, 1);pr…

Android 开发实战:从零到一集成 espeak-ng 实现中文离线 TTS(无需账号开箱即用)

简介 在移动应用开发中,语音合成(TTS)技术是提升用户体验的重要工具。然而,许多开发者在集成 TTS 时面临依赖网络、需注册账号、功能受限等问题。本文将带你从零开始,通过开源项目 espeak-ng,实现无需账号、开箱即用的中文离线语音播报。 文章将覆盖以下核心内容: esp…

直播APP集成美颜SDK详解:智能美妆功能的开发实战

在这个“颜值即正义”的时代&#xff0c;用户对直播APP的第一印象&#xff0c;往往来自主播的画面质量。高清的视频固然重要&#xff0c;但如果缺少自然美颜和智能美妆功能&#xff0c;观众体验就会大打折扣。于是&#xff0c;美颜SDK成了直播行业的“标配”。今天&#xff0c;…

C++内存管理:new与delete的深层解析

1. 引言在C的世界里&#xff0c;动态内存管理是一个核心话题。对于从C语言过渡到C的开发者来说&#xff0c;一个常见的困惑是&#xff1a;既然C语言的malloc和free依然可以在C中使用&#xff0c;为什么C还要引入new和delete这两个操作符&#xff1f;本文将深入探讨这两对内存管…

【AI开发】【前后端全栈】[特殊字符] AI 时代的快速开发思维

&#x1f680; AI 时代的快速开发思维 —— 以 Django Vue3 为例的前后端分离快捷开发流程 一、AI 时代的开发新思路 在 AI 的加持下&#xff0c;软件开发不再是“纯体力活”&#xff0c;而是 思维工具自动化 的协作。 过去&#xff1a;需求 → 设计 → 开发 → 测试 → 上…

Day24_【深度学习(3)—PyTorch使用—张量的创建和类型转换】

一、创建张量1.张量基本创建方式torch.tensor 根据指定数据创建张量 &#xff08;最重要&#xff09;torch.Tensor 根据形状创建张量, 其也可用来创建指定数据的张量torch.IntTensor、torch.FloatTensor、torch.DoubleTensor 创建指定类型的张量1.1 torch.tensor# 方式一&…

3-12〔OSCP ◈ 研记〕❘ WEB应用攻击▸利用XSS提权

郑重声明&#xff1a; 本文所有安全知识与技术&#xff0c;仅用于探讨、研究及学习&#xff0c;严禁用于违反国家法律法规的非法活动。对于因不当使用相关内容造成的任何损失或法律责任&#xff0c;本人不承担任何责任。 如需转载&#xff0c;请注明出处且不得用于商业盈利。 …

AI 大模型赋能智慧矿山:从政策到落地的全栈解决方案

矿山行业作为能源与工业原料的核心供给端&#xff0c;长期面临 “安全生产压力大、人工效率低、技术落地难” 等痛点。随着 AI 大模型与工业互联网技术的深度融合&#xff0c;智慧矿山已从 “政策引导” 迈入 “规模化落地” 阶段。本文基于 AI 大模型智慧矿山行业解决方案&…

Node.js 项目依赖包管理

h5打开以查看 一、核心理念&#xff1a;从“能用就行”到“精细化管理” 一个规范的依赖管理体系的目标是&#xff1a; 可复现&#xff1a;在任何机器、任何时间都能安装完全一致的依赖&#xff0c;保证构建结果一致。 清晰可控&#xff1a;明确知道每个依赖为何存在&#x…

洛谷P1835素数密度 详解

题目如下&#xff1a;这里面有部分代码比较有意思&#xff1a;1&#xff0c;为何开始先遍历&#xff0c;最终值小于50000&#xff1f;因为题目要求的右边与左边差小于 10^6 &#xff0c;所以最多有10^3个素数&#xff0c;所以保存里面的素数数量大于1000&#xff0c;而50000的化…

突破限制:FileCodeBox远程文件分享新体验

文章目录【视频教程】1.Docker部署2.简单使用演示3. 安装cpolar内网穿透4. 配置公网地址5. 配置固定公网地址在隐私日益重要的今天&#xff0c;FileCodeBox与cpolar的协同为文件传输提供了安全高效的解决方案。通过消除公网IP限制和隐私顾虑&#xff0c;让每个人都能掌控自己的…

以太网链路聚合实验

一、实验目的掌握使用手动模式配置链路聚合的方法掌握使用静态 LACP 模式配置链路聚合的方法掌握控制静态 LACP 模式下活动链路的方法掌握静态 LACP 的部分特性的配置二、实验环境安装有eNSP模拟器的PC一台&#xff0c;要求PC能联网。三、实验拓扑LSW1与LSW2均为S3700交换机。L…

autMan安装教程

一、安装命令 如果你系统没安装docker&#xff0c;请看往期教程 以下为通用命令 docker run -d --name autman --restart always -p 8080:8080 -p 8081:8081 -v /root/autman:/autMan --log-opt max-size10m --log-opt max-file3 hdbjlizhe/autman:latest解释一下以上命令&…

【无人机】自检arming参数调整选项

检查项目 (英文名)中文含义检查内容四旋翼建议 (新手 → 老手)理由说明All所有检查启用下面所有的检查项目。✅ 强烈建议勾选这是最安全的设置&#xff0c;确保所有关键系统正常。Barometer气压计检查气压计是否健康、数据是否稳定。✅ 必须勾选用于定高模式&#xff0c;数据异…

数字图像处理(1)OpenCV C++ Opencv Python显示图像和视频

Open CV C显示图像#include <iostream> #include <opencv2/opencv.hpp> using namespace cv;//包含cv命名空间 int main() {//imread(path)&#xff1a;从给定路径读取一张图片&#xff0c;储存为Mat变量对象Mat img imread("images/love.jpg");//named…

【芯片设计-信号完整性 SI 学习 1.2.2 -- 时序裕量(Margin)】

文章目录1. 什么是时序裕量&#xff08;Margin&#xff09;1. 背景&#xff1a;为什么需要数字接口时序分析2. 时钟周期方程3. Setup 裕量 (tMARGIN_SETUP)4. Hold 裕量 (tMARGIN_HOLD)5. 设计注意事项6. 实际应用场景2. 时序裕量的来源3. 测试方法(1) 眼图测试 (Eye Diagram)(…

AOP 切面日志详细

在业务方法上打注解package com.lib.service;Service public class BookService {LogExecution(description "查询图书")public Book query(int id) {return repo.findById(id);}LogExecution(description "借阅图书")public void borrow(int id) {// 模…