拒绝重复造轮子:利用自定义注解封装POI,实现Java通用Excel解析

Java技术变现新路径:基于JVM生态的工程化赚钱模型 Java作为一门成熟语言,其核心价值已从语法特性升维为JVM生态所承载的稳定性、向后兼容性与企业级信任背书。在等保合规、遗留系统现代化和垂直领域工具链等刚性需求驱动下,Java凭借字节码增强、Java Agent、ClassLoader热加载等原生能力,成为构建合规即服务(Compliance-as-a-Service)、遗留系统缝合层及微型SaaS的关键技术底座。它不追求性能极限,而以‘可审计、可验证、零改造集成’满足法务签字、运维背书与终端用户习惯三重决策节点。本文聚焦Java在2025年中小企业技术变 阅读详情

基于 SSM + Vue 的 POI Excel 导入导出全流程实现

本文详细讲解基于 SSM(Spring + SpringMVC + MyBatis)后端与 Vue + Element UI 前端的 Excel 导入导出功能实现。通过自定义注解的方式,实现通用的 POI 操作流程。


1. 环境准备与依赖引入

首先需要在项目的 pom.xml 中引入 Apache POI 及相关工具类的依赖。

<!-- POI 核心依赖(支持 .xls 格式 - Office 2003) -->  
<dependency>  
    <groupId>org.apache.poi</groupId>  
    <artifactId>poi</artifactId>  
    <version>4.1.2</version>  
</dependency>  

<!-- POI OOXML(支持 .xlsx 格式 - Office 2007+,目前主流) -->  
<dependency>  
    <groupId>org.apache.poi</groupId>  
    <artifactId>poi-ooxml</artifactId>  
    <version>4.1.2</version>  
</dependency>  

<!-- Commons BeanUtils:用于简化实体类属性的反射操作 -->  
<dependency>  
    <groupId>commons-beanutils</groupId>  
    <artifactId>commons-beanutils</artifactId>  
    <version>1.9.4</version>  
</dependency>  

<!-- Commons FileUpload:SpringMVC 处理文件上传的核心依赖 -->  
<dependency>  
    <groupId>commons-fileupload</groupId>  
    <artifactId>commons-fileupload</artifactId>  
    <version>1.4</version>  
</dependency>

2. 后端核心架构设计

2.1 自定义注解

通过注解标记实体类与 Excel 表格的映射关系,实现通用解析。

  1. @ExcelField:

    • 作用:标注在实体类的字段上。
    • 功能:定义字段在 Excel 表头中对应的中文名称、排序号、是否参与导入/导出等。
    • 元注解:@Target(ElementType.FIELD)。
    • 图1:ExcelField 注解定义
    • 图2:ExcelField 注解属性
    • 图3:实体类字段使用示例
  2. @ExcelEntity:

    • 作用:标注在实体类上。
    • 功能:定义实体类对应的 Excel 表名(Sheet 名)。
    • 元注解:@Target(ElementType.TYPE)。
    • 图4:ExcelEntity 注解使用示例

2.2 工具类设计

  • ExcelAnnotationUtil:负责解析实体类上的注解,生成“表头-字段”的映射关系。
  • ExcelUtil:核心工具类,负责创建 Workbook、填充数据(导出)以及读取 Workbook、封装实体(导入)。
    • 注:完整工具类代码见文末附录。

3. 业务逻辑层 (Service) 实现

3.1 导入逻辑

思路:Controller 接收文件 -> 调用工具类解析 Excel 为 List<User> -> 调用 Mapper 批量插入数据库。

图5:Service层导入代码示例

3.2 导出逻辑

思路:Mapper 查询所有数据 -> 调用工具类解析注解(获取表头和Sheet名) -> 生成 Excel 二进制流 -> 通过 HttpServletResponse 输出。

图6:Service层导出代码示例


4. SpringMVC 配置与 Controller

4.1 配置文件上传解析器

在 SpringMVC 配置文件中添加 MultipartResolver,否则后端无法接收 MultipartFile。

<!-- 配置文件上传解析器 -->  
<bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver">  
    <!-- 最大上传文件大小:10MB (10 * 1024 * 1024) -->  
    <property name="maxUploadSize" value="10485760"/>  
    <!-- 默认编码格式,防止文件名乱码 -->  
    <property name="defaultEncoding" value="UTF-8"/>  
</bean>

4.2 Controller 编写

定义导入和导出两个接口。

图7:Controller层接口定义


5. 前端实现 (Vue + Element UI)

5.1 界面组件

使用 Element UI 的按钮组件触发操作。

图8:前端界面按钮

5.2 导出功能实现 (Blob 流处理)

核心逻辑:

  1. 调用后端接口,设置响应类型为 blob。
  2. 接收二进制流,创建 Blob 对象。
  3. 创建临时的 <a> 标签触发下载。
  4. 释放 URL 对象。

Axios 封装:
图9:Axios请求封装

业务代码:

handleExport() {
    this.$message.info('正在导出数据,请稍等...');
    exportUserExcel()
        .then(response => {
            // 1. 校验响应是否为有效 blob
            if (!response.data || response.data.size === 0) {
                this.$message.error('导出失败:无数据可导出');
                return;
            }
            
            // 2. 创建 Blob 对象,指定 MIME 类型为 Excel
            const blob = new Blob([response.data], {
                type: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'
            });
            
            // 3. 创建下载链接
            const link = document.createElement('a');
            // 使用 encodeURIComponent 解决中文文件名乱码
            const fileName = encodeURIComponent('用户列表.xlsx');
            link.href = window.URL.createObjectURL(blob);
            link.download = decodeURIComponent(fileName); // 下载属性设为解码后的文件名
            
            // 4. 触发点击并清理
            link.click();
            window.URL.revokeObjectURL(link.href); // 释放内存
            this.$message.success('导出成功');
        })
        .catch(err => {
            // 处理错误信息(注意:Blob 报错时可能需要将 Blob 转回 JSON 才能读取 msg)
            this.$message.error('导出失败:' + (err.response?.data?.msg || err.message));
            console.error(err);
        });
},

5.3 导入功能实现 (FormData 上传)

核心逻辑:

  1. 点击按钮触发隐藏的 <input type="file">。
  2. handleFileChange 捕获文件。
  3. 前端校验文件格式(.xls/.xlsx)和大小(<10MB)。
  4. 使用 FormData 封装文件并发送请求。

图10:文件选择框隐藏逻辑

业务代码:

handleImport() {
    // 触发隐藏的文件输入框
    this.$refs.fileInput.click();
},

handleFileChange(event) {
    const file = event.target.files[0];
    if (!file) return;

    // 1. 前端校验文件类型
    const isExcel = file.type === 'application/vnd.ms-excel' || 
                    file.type === 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet';
    // 2. 前端校验文件大小 (10MB)
    const isLt10M = file.size / 1024 / 1024 < 10;

    if (!isExcel) {
        this.$message.error('只能上传xls/xlsx格式的Excel文件!');
        event.target.value = ''; // 清空选择,允许重复选择同名文件
        return;
    }
    if (!isLt10M) {
        this.$message.error('文件大小不能超过10MB!');
        event.target.value = '';
        return;
    }

    // 3. 调用导入接口
    importUserExcel(file)
        .then(() => {
            this.$message.success('导入成功');
            this.fetchUsers(); // 刷新列表
            event.target.value = ''; 
        })
        .catch(err => {
            this.$message.error('导入失败:' + (err.response?.data?.msg || err.message));
            console.error(err);
            event.target.value = '';
        });
},

API 调用:
图11:导入API封装


6. 效果展示

  • 导出成功:
    图12:导出文件下载
    图13:导出Excel内容

  • 导入成功:
    图14:导入前列表
    图15:导入后列表刷新


7. 常见问题与解决方案

7.1 导出的 Excel 无法打开 (文件损坏)

图16:Excel文件损坏报错

可能原因解决方案
前端未设置 Blob前端 Axios 请求必须添加 responseType: 'blob',否则二进制流会被当做字符串/JSON 解析导致乱码。
后端流未关闭后端 ExcelUtil 中必须执行 os.flush() 和 os.close(),确保缓冲区数据完全写入。
拦截器干扰项目中的全局响应拦截器(Response Interceptor)可能强制解析 JSON。需添加判断:如果是 Blob 类型则直接返回,不进行 JSON 解析。

7.2 导入 Excel 报 500 错误

可能原因解决方案
未配置解析器检查 SpringMVC 配置文件是否包含 CommonsMultipartResolver Bean。
请求头错误前端必须使用 FormData 对象封装文件,浏览器会自动设置 Content-Type: multipart/form-data。
参数名不一致后端 @RequestParam("file") 中的名称必须与前端 formData.append('file', file) 中的 key 保持一致。

8. 附录:核心工具类源码

8.1 ExcelAnnotationUtil.java

用于解析注解,建立映射关系。

/**  
 * @className: ExcelAnnotationUtil  
 * @description: Excel注解解析工具类:解析实体类注解,生成表头/字段映射  
 */  
public class ExcelAnnotationUtil {  
  
    /**  
     * 解析实体类注解,生成导出用的表头和字段数组  
     * @param clazz 实体类Class  
     * @return 返回数组:[0]headers(表头名称数组),[1]fields(实体类字段名数组)  
     */  
    public static <T> String[][] parseExportAnnotation(Class<T> clazz) {  
        return parseAnnotation(clazz, true);  
    }

    /**  
     * 解析实体类注解,生成导入用的字段数组  
     * @param clazz 实体类Class  
     * @return 返回数组:[0]headers(表头用于校验),[1]fields(实体类字段名用于赋值)  
     */  
    public static <T> String[][] parseImportAnnotation(Class<T> clazz) {  
        return parseAnnotation(clazz, false);  
    }  
  
    /**  
     * 通用注解解析逻辑  
     * @param isExport true为导出模式,false为导入模式(根据注解中的 isExport/isImport 属性过滤)
     */    
    private static <T> String[][] parseAnnotation(Class<T> clazz, boolean isExport){  
        // 获取所有声明的字段
        Field[] declaredFields = clazz.getDeclaredFields();  
        
        // 使用 TreeMap 存储字段信息,key 为 sort 值,实现自动按 sort 升序排列
        Map<Integer, Map<String, String>> fieldMap = new TreeMap<>(); 
        
        for (Field field : declaredFields){  
            ExcelField excelField = field.getAnnotation(ExcelField.class);  
            if (excelField == null){  
                continue; // 跳过无注解的字段  
            }  
            
            // 根据模式过滤字段
            if (isExport && !excelField.isExport()) {  
                continue;  
            }            
            if (!isExport && !excelField.isImport()) {  
                continue;  
            }  
            
            // 封装字段名、表头名
            Map<String, String> fieldInfo = new TreeMap<>();  
            fieldInfo.put("fieldName", field.getName());  
            fieldInfo.put("headerName", excelField.name());  
            
            // 存入 Map 进行排序
            fieldMap.put(excelField.sort(), fieldInfo);  
        }        
        
        // 将 Map 转换为数组返回
        List<String> headers = new ArrayList<>();  
        List<String> fields = new ArrayList<>();  
        for (Map<String, String> info : fieldMap.values()){  
            headers.add(info.get("headerName"));  
            fields.add(info.get("fieldName"));  
        }        
        
        return new String[][]{  
                headers.toArray(new String[0]),  
                fields.toArray(new String[0])  
        };    
    }  
    
    /**  
     * 获取字段的注解类型(用于导入时的类型转换)  
     * 例如:Excel 中是文本,但实体类是 Integer,需要获取该类型进行转换
     */  
    public static <T> Class<?> getFieldType(Class<T> clazz, String fieldName){  
        try {  
            Field field = clazz.getDeclaredField(fieldName);  
            ExcelField excelField = field.getAnnotation(ExcelField.class);  
            // 默认为 String 类型
            return excelField == null ? String.class : excelField.type();  
        } catch (NoSuchFieldException e) {  
            e.printStackTrace();  
            return String.class;  
        }  
    }
}

8.2 ExcelUtil.java

POI 操作核心类,包含样式设置、数据读写、类型转换。

/**  
 * 适配注解的 POI 工具类(支持 .xlsx 和类型转换)  
 */  
public class ExcelUtil {  
  
    // ====================== 导出逻辑 ======================    
    public static <T> void exportExcel(HttpServletResponse response, List<T> dataList,  
                                       String[] headers, String[] fields, String fileName) {  
        // 1. 创建工作簿 (XSSFWorkbook 支持 .xlsx)
        Workbook workbook = new XSSFWorkbook();  
        Sheet sheet = workbook.createSheet("数据列表");  
  
        // 2. 创建表头行并设置样式  
        Row headerRow = sheet.createRow(0);  
        CellStyle headerStyle = getHeaderStyle(workbook);  
        for (int i = 0; i < headers.length; i++) {  
            Cell cell = headerRow.createCell(i);  
            cell.setCellValue(headers[i]);  
            cell.setCellStyle(headerStyle);  
            sheet.autoSizeColumn(i); // 简单的自适应列宽
        }  
        
        // 3. 写入数据行  
        if (dataList != null && !dataList.isEmpty()) {  
            CellStyle contentStyle = getContentStyle(workbook);  
            for (int rowNum = 0; rowNum < dataList.size(); rowNum++) {  
                Row dataRow = sheet.createRow(rowNum + 1);  
                T data = dataList.get(rowNum);  
                
                // 遍历字段数组,通过反射获取值
                for (int colNum = 0; colNum < fields.length; colNum++) {  
                    Cell cell = dataRow.createCell(colNum);  
                    cell.setCellStyle(contentStyle);  
                    try {  
                        // 使用 BeanUtils 获取属性值
                        String value = BeanUtils.getProperty(data, fields[colNum]);  
                        cell.setCellValue(value == null ? "" : value);  
                    } catch (Exception e) {  
                        cell.setCellValue("");  
                        e.printStackTrace();  
                    }                
                }            
            }        
        }  
        
        // 4. 写入响应流  
        try {  
            response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");  
            // 防止中文文件名乱码
            response.setHeader("Content-Disposition", "attachment;filename=" + URLEncoder.encode(fileName, "UTF-8"));  
            
            OutputStream os = response.getOutputStream();  
            workbook.write(os);  
            os.flush(); // 关键:刷新缓冲区
            os.close();  
            workbook.close();  
        } catch (Exception e) {  
            e.printStackTrace();  
        }    
    }  
    
    // ====================== 导入逻辑 ======================    
    public static <T> List<T> importExcel(MultipartFile file, Class<T> clazz) {  
        List<T> dataList = new ArrayList<>();  
        if (file.isEmpty()) {  
            return dataList;  
        }  
        
        // 1. 解析导入注解,获取表头和字段映射  
        String[][] annotationData = ExcelAnnotationUtil.parseImportAnnotation(clazz);  
        String[] headers = annotationData[0]; // Excel表头(用于校验)  
        String[] fields = annotationData[1]; // 实体类字段名  
  
        try {  
            // WorkbookFactory 自动识别 xls 或 xlsx
            Workbook workbook = WorkbookFactory.create(file.getInputStream());  
            Sheet sheet = workbook.getSheetAt(0);  
            if (sheet == null) {  
                return dataList;  
            }  
            
            // 2. 校验 Excel 表头(可选,确保导入文件格式正确)  
            Row headerRow = sheet.getRow(0);  
            if (headerRow == null) {  
                throw new RuntimeException("Excel无表头行");  
            }            
            for (int i = 0; i < headers.length; i++) {  
                Cell cell = headerRow.getCell(i);  
                String cellValue = getCellValue(cell);  
                if (!headers[i].equals(cellValue)) {  
                    throw new RuntimeException("Excel表头错误:第" + (i+1) + "列应为【" + headers[i] + "】,实际为【" + cellValue + "】");  
                }            
            }  
            
            // 3. 逐行解析数据 + 类型转换  
            int lastRowNum = sheet.getLastRowNum();  
            for (int rowNum = 1; rowNum <= lastRowNum; rowNum++) {  
                Row row = sheet.getRow(rowNum);  
                if (row == null) continue;  
                
                T data = clazz.newInstance(); // 实例化对象
                for (int colNum = 0; colNum < fields.length; colNum++) {  
                    Cell cell = row.getCell(colNum);  
                    String cellValue = getCellValue(cell);  
                    if (cellValue.isEmpty()) continue; // 空值跳过  
  
                    // 核心:根据注解指定的类型转换值  
                    String fieldName = fields[colNum];  
                    Class<?> fieldType = ExcelAnnotationUtil.getFieldType(clazz, fieldName);  
                    // 使用 ConvertUtils 进行类型转换 (String -> Integer/Date等)
                    Object convertValue = ConvertUtils.convert(cellValue, fieldType);  
  
                    // 赋值给实体类  
                    BeanUtils.setProperty(data, fieldName, convertValue);  
                }                
                dataList.add(data);  
            }            
            workbook.close();  
        } catch (Exception e) {  
            e.printStackTrace();  
            throw new RuntimeException("导入失败:" + e.getMessage());  
        }        
        return dataList;  
    }  
    
    // ====================== 私有工具方法 (样式与单元格读取) ======================    
    
    /** 获取表头样式(加粗、居中、浅灰背景、边框) */  
    private static CellStyle getHeaderStyle(Workbook workbook) {  
        CellStyle style = workbook.createCellStyle();  
        style.setAlignment(HorizontalAlignment.CENTER);  
        style.setVerticalAlignment(VerticalAlignment.CENTER);  
        style.setBorderTop(BorderStyle.THIN);  
        style.setBorderBottom(BorderStyle.THIN);  
        style.setBorderLeft(BorderStyle.THIN);  
        style.setBorderRight(BorderStyle.THIN);  
        
        Font font = workbook.createFont();  
        font.setBold(true);  
        font.setFontName("微软雅黑");  
        font.setFontHeightInPoints((short) 12);  
        style.setFont(font);  
        
        style.setFillForegroundColor(IndexedColors.GREY_25_PERCENT.getIndex());  
        style.setFillPattern(FillPatternType.SOLID_FOREGROUND);  
        return style;  
    }  
    
    /** 获取内容样式(居中、边框) */  
    private static CellStyle getContentStyle(Workbook workbook) {  
        CellStyle style = workbook.createCellStyle();  
        style.setAlignment(HorizontalAlignment.CENTER);  
        style.setVerticalAlignment(VerticalAlignment.CENTER);  
        style.setBorderTop(BorderStyle.THIN);  
        style.setBorderBottom(BorderStyle.THIN);  
        style.setBorderLeft(BorderStyle.THIN);  
        style.setBorderRight(BorderStyle.THIN);  
        
        Font font = workbook.createFont();  
        font.setFontName("微软雅黑");  
        font.setFontHeightInPoints((short) 11);  
        style.setFont(font);  
        return style;  
    }  
    
    /** 统一获取单元格值(适配 String, Numeric, Boolean, Formula) */  
    private static String getCellValue(Cell cell) {  
        if (cell == null) return "";  
        
        CellType cellType = cell.getCellType();  
        switch (cellType) {  
            case STRING:  
                return cell.getStringCellValue().trim();  
            case NUMERIC:  
                // 处理日期格式
                if (DateUtil.isCellDateFormatted(cell)) {  
                    return cell.getDateCellValue().toString();  
                } else {  
                    // 防止数字变成科学计数法,这里简单转 String
                    return String.valueOf(cell.getNumericCellValue()).trim();  
                }            
            case BOOLEAN:  
                return String.valueOf(cell.getBooleanCellValue());  
            case FORMULA:  
                // 递归获取公式计算后的值
                return getCellValue(cell.getCachedFormulaResultType(), cell);  
            default:  
                return "";  
        }    
    }  
    
    /** 处理公式单元格的结果 */  
    private static String getCellValue(CellType cellType, Cell cell) {  
        if (cellType == CellType.NUMERIC) {  
            return String.valueOf(cell.getNumericCellValue()).trim();  
        } else if (cellType == CellType.STRING) {  
            return cell.getStringCellValue().trim();  
        } else {  
            return "";  
        }    
    }
}
技术人十年成长三重认知跃迁:从能跑、均衡到长期能力 在软件工程实践中,‘技术成长’并非知识的线性堆砌,而是认知结构的持续重构——它始于对代码背后假设的质疑(能跑≠正确),进阶于对系统各维度资源消耗的全局权衡(单点最优≠系统稳定),最终落脚于构建可演进、可验证、可协作的长期能力单元(功能交付≠价值沉淀)。这一过程深刻关联着‘技术生涯’的真实演进逻辑:每一次架构决策、团队协作或文档沉淀,都是对技术价值的重新定义。本文基于十年一线实战,解析工程师如何跨越三道关键分水岭,在真实业务压力下完成从执行者到建设者的质变。 阅读详情

相关推荐

TOGAF 10如何驱动企业敏捷性:从架构方法论到数字韧性系统

企业架构(EA)是支撑组织数字化转型的基础性技术范式,其核心在于建立业务战略、IT能力与数据资产之间的可执行映射关系。TOGAF作为全球主流EA框架,历经版本演进,尤其TOGAF 10已从静态蓝图工具升级为动态价值引擎,通过能力驱动规划(Capability-Based Planning)、架构治理框架(AGF)和架构决策记录(ADR)等机制,系统性提升响应敏捷性、探索敏捷性与韧性敏捷性。它不替代SAFe等规模化敏捷实践,而是为其提供变化锚点与协作契约;不追求技术堆叠,而聚焦‘能力-服务-组件’三级语义化拆

dicha7140的博客 304

Java实现Excel的导入以及导出,极其简单

1、我这里使用的是Spring Boot开发的,创建工程自行创建 2、导入相关依赖 3、yml配置数据库 4、导入Excel相关工具类 如下四个 ExcelClassField ExcelExport ExcelImport ExcelUtils 5、Excel表格数据,这里简单测试,所以属性都较简单 6、User类,对应Excel表 二、Excel的导入测试 1、Controller 2请求,用ApiPost请求 测试结果: 3、导入解析为对象(字段自动映射) 对于有的枚举数据,通常我们导入的时候,表

m0_52789121的博客 665

SpringBoot课程设计选题系统开发:从需求到高并发实战

在高校信息化建设中,管理系统是提升教务效率、优化师生体验的核心工具。其基本原理是通过前后端分离架构,将业务逻辑、数据存储与用户界面解耦,实现数据的集中管理与流程的自动化。从技术价值看,一个设计良好的系统不仅能规范业务流程、保障数据一致性,更能通过高并发处理应对瞬时流量高峰,是教学管理数字化转型的关键支撑。典型的应用场景包括课程设计选题、毕业设计管理、实验预约等需要多角色协同、资源分配与过程跟踪的环节。本文以课程设计选题这一具体场景为例,深入探讨了如何运用SpringBoot、MyBatis-Plus、Red

weixin_34221654的博客 325

【Java】基于easy-poi实现Excel表导入与导出

【Java】基于easy-poi实现Excel表导入与导出

weixin_47201411的博客 1435

SpringBoot+Vue+MySQL 高校学科竞赛平台 完整可运行版(源码+文档)

本项目基于SpringBoot+Vue+MySQL构建高校学科竞赛管理平台,覆盖学生、教师、领队教师、管理员四大角色,实现竞赛发布、报名、刷题、评分、公示等全流程闭环管理。系统架构清晰,技术主流,配套完整源码、数据库脚本、万字论文、开题报告、答辩PPT及部署文档,支持一键运行,适用于毕业设计、课程设计及院系二次开发,真正实现“开箱即用”。

招风的黑耳优快云 173

手把手教你用STM32F103实现CAN总线双机通信(基于CubeMX+HAL库)

本文详细介绍了基于STM32F103和STM32CubeMX工具实现CAN总线双机通信的完整流程。文章重点解析了CAN总线在嵌入式物联网应用中的优势,并深入讲解了波特率计算、过滤器配置、接收中断处理等关键细节,提供了实用的代码框架和可靠传输方案,帮助开发者规避常见陷阱,构建稳定的工业级通信系统。

weixin_29193259的博客 481

java导入导出excel数据之表头中文问题——@Alias、 reader.addHeaderAlias

由于数据库与实体类之间的字段映射问题所谓实体类与数据库之间的映射,其实就是在java中创建一个类,用来存放数据库里的某一张表。但是,如果只是在纯粹的桌面端与web端开发中,没有使用到框架的化,其实字段与属性之间的映射要求并没有那么严格。但是,使用MyBatis框架之后,对于字段与属性之间的关系,是十分严格的。所以excel 表头出现中文就会导致导入数据库中的数据为null。

qq_52474580的博客 1898

CTS实战:如何用set_sense优化时钟树平衡(附ICC2避坑指南)

本文深入探讨了在时钟树综合(CTS)中,如何正确使用`set_sense`命令优化时钟树平衡,并对比了其与`set_disable_timing`的本质区别。通过实战案例详细解析了`-stop_propagation`和`-clock_leaf`参数的应用场景,并提供了ICC2工具中的关键避坑指南,帮助后端工程师精准控制时钟拓扑,避免时序分析漏洞。

weixin_28933797的博客 460

poi之----esaypoi 模板导出循环指令fe 合并单元格时格式错乱问题

话不多说直接干饭,我的esaypoi使用的是4.3.0 1.加载模板数据导出语句 Workbook book = ExcelExportUtil.exportExcel(params, valueXbx); @Test public void xbx() throws Exception { //养护方案全部 Map<String, Object> valueXbx = new HashMap<String, Object>(); // List<Ma

徐本锡的专栏 39万+

【CASS精品教程】035:南方CASS7.1台阶画法案例大全

摘要:本文详细介绍了南方CASS7.1软件中5种台阶工具的使用方法,包括普通台阶、有边台阶、L型台阶、U型台阶和不规则台阶。重点说明各类台阶的绘制步骤和注意事项,如绘制方向(从右下角逆时针连接4个点)、台阶方向标识(白色边为下边)、台阶数自动生成不可更改等特性。同时指出高版本CASS可能存在操作差异,并配以多张示意图直观展示各类台阶的绘制过程和效果,为使用CASS7.1绘制建筑台阶提供了实用指导。(148字)

智慧空间实验室 2923

【DeepSeek应用实践】手把手教程:用 AnythingLLM + Ollama + DeepSeek-R1 搭建本地企业知识库

在众多的技术方案中,我们选择了 AnythingLLM、Ollama 和 DeepSeek-R1 这一组合来搭建本地知识库。Ollama 作为一个轻量级的本地化大语言模型部署工具,支持多种模型,易于安装和使用,能够快速在本地运行强大的语言模型。DeepSeek-R1 是一个专为知识库问答设计的检索增强生成(RAG)模型,它结合了检索和生成的优势,能够快速从知识库中检索相关信息并生成精准答案。而 AnythingLLM 则是一个用户友好的界面工具,可以方便地连接 Ollama 和 DeepSeek-R1

寻道AI,探索AI无限可能! 2569

LLM嵌入软件开发流程的实操路径与Prompt工程方法论

大语言模型(LLM)正重塑软件开发生命周期(SDLC),其核心并非替代编码,而是重构人机协作中的‘意图对齐’机制。理解LLM作为新型协作者的本质,需从其输入敏感性、上下文依赖性与输出不可预测性出发;技术价值体现在将模糊需求转化为可验证契约,从而提升交付确定性;典型应用场景包括基础设施即代码生成、测试用例扩写与文档同步更新等高契约性任务;而真正落地的关键,在于建立以规格说明书(Spec)、结构化Prompt和人工验证为支柱的‘黄金三角’实践体系——本文即基于真实项目沉淀的Prompt工程方法论与渐进式嵌入路径

weixin_34265814的博客 329

深入详解DICOM医学影像定位线相关知识:理解定位线的概念、定位线的作用以及定位线显示和计算原理

深入详解DICOM医学影像定位线相关知识:理解定位线的概念、定位线的作用以及定位线显示和计算原理

编程技术探索者,分享C/C++、C#、Java、数据库等开发经验,聚焦实战技巧与AI兴趣,助力编程爱好者成长。 2052

AI写代码时代,软件团队如何重构交付能力

AI编程不是替代程序员,而是重新定义‘交付价值’的技术范式。其底层原理在于将业务需求转化为AI可理解的结构化上下文,通过Prompt工程、可审计生成与多层校验机制,实现从需求到生产代码的闭环。技术价值体现在大幅提升CRUD类任务效率、降低胶水代码维护成本、加速遗留系统现代化;典型应用场景包括微服务模块生成、规则引擎编译、API对接脚本开发及测试桩自动化。当团队聚焦于‘定义可生成性’而非‘手写代码量’,便真正迈入AI原生协作阶段——本文即围绕AI写代码、团队能力重构两大核心热词,展开可落地的工程实践路径。

weixin_30372371的博客 308

Claude Code 从入门到精通,通过实战项目穿插 Agent Skills、MCP、Hooks、子代理、插件等十五个知识点

本文介绍了Claude Code的高级使用技巧,通过一个个人简历网站实战项目,详细讲解了15个核心知识点。主要内容包括:三种权限模式(默认/编辑/计划)的使用与切换;历史会话管理(/resume、/rename、/clear命令);会话回滚功能(/rewind);以及危险参数--dangerously-skip-permissions的注意事项。文章还演示了如何通过计划模式拆分代码文件,并强调了在复杂任务中仔细检查规划步骤的重要性。这些技巧能帮助开发者更高效地使用Claude Code完成项目开发。

1788

实时多目标跟踪(MOT):SORT与DeepSORT优化

实时多目标跟踪(MOT):SORT与DeepSORT优化​ ,人工智能,计算机视觉,大模型,AI,本文围绕实时多目标跟踪中的 SORT 与 DeepSORT 算法展开,阐述了两者原理、实现及优化。SORT 结合卡尔曼滤波和匈牙利算法,依赖目标检测,实时性好但复杂场景表现欠佳。DeepSORT 在其基础上引入外观特征,采用级联匹配,提升了跟踪精度和鲁棒性。还探讨了两种算法在检测、运动模型、外观特征等方面的优化方向,以及应用场景与选择建议,为相关应用和研究提供参考。

不踩坑,不知道坑有多深;不总结,踩过的坑白踩。 20万+

InnoDB 内存结构总览:Change Buffer、AHI 与 Log Buffer

本文系统梳理InnoDB内存结构中的ChangeBuffer、Adaptive Hash Index(AHI)与LogBuffer。ChangeBuffer缓存二级索引页不在内存时的变更,减少随机IO,仅在页加载时合并;聚簇索引修改立即执行,因数据本身不可延后。AHI基于高频等值查询自动构建哈希索引,加速定位,仅支持等值操作。LogBuffer为redo log内存缓冲,配合磁盘日志实现崩溃恢复。三者均服务于性能优化,其中ChangeBuffer与AHI共享BufferPool空间,而LogBuffer独立

bksczm的博客 293

手把手教你学simulink--永磁同步电机场景实例:使用Simulink进行PMSM的矢量控制仿真

矢量控制的重要性提高效率:通过精确控制磁场方向,可以优化电机的工作状态,减少损耗。增强动态性能:矢量控制能够快速响应负载变化,提供更好的调速性能。简化设计:将复杂的交流电机控制问题转化为类似直流电机的控制问题,便于设计和实现。通过上述步骤,我们简要介绍了如何基于Simulink实现PMSM的矢量控制仿真。

MHD0815的博客 421

信创环境下PageOffice文档控件适配与实践

信创适配做到文档控件这一层,拼的已经不是"有没有国产版本",而是同一个功能在两类终端上是否真的等价。等价的标准很具体:同一次点击能得到同样的结果,同一份公文能得到同样的版式,同一个项目不需要维护两套代码。这背后是三件并不轻松的工作:服务端用一套接口同时支撑两类终端,客户端把两种系统与四种芯片的安装包分发清楚,文档内核层由产品侧跟着 WPS 的版本走。浏览器这一层的压力,则被收进了产品自己的窗口里——升级节奏由产品掌握,不再交给运气。

zi_wu_xian的专栏 320

Outlook Express 6 (OE6) for Win7/Win8/Win10

英文版 Outlook Express6.0, 兼容Win7/Win10/WinXP,解压就可用。

RU DOS版、EFI版32bit/64bit BIOS常用工具

DOS版、EFI版的RU工具,可用来查看IO、MEM、PCI、SMBIOS等资源。亲测在EFI SHELL下可用。

V8 机制、手写核心函数与 TypeScript 类型体操

或固定初始化(如数组先定长、对象先给全字段)保持类型与形状稳定;这些都比"换框架"更基础。只能处理纯数据(丢函数、Date、RegExp、循环引用报错)。生产级深拷贝要处理:原始值短路、循环引用、V8(Chrome / Node 的 JS 引擎)不是"解释一行跑一行"那么简单,它用。图:V8 执行流程——解释执行 + 热点优化,优化失败会 Deopt 回退。JS 内存自动管理,但"自动"不等于"不会漏"。是"固定间隔最多执行一次"。手写 Promise 是"懂异步"的试金石。是"停下后才执行最后一次",

qq_38468358的博客 350

OV9734 DATASHEET,完整规格书

OV9734完整规格书,包括电气参数,尺寸规格,寄存器配置表等

第三篇 第 6 课

前置:第三篇第 1 课(stdx 引入),第二篇第 1 课(std.regex)。环境:仓颉 SDK 1.2.0。本文所有代码与输出均逐行实测。

weixin_41618057的博客 506

VB摄像头监控

该VB模块可对摄像头捕获的画面进行录像等,可在创建的窗口进行控制

【从零理解 Spring AI · 12】MCP 的两种角色:做客户端还是做服务端

上一篇讲了 MCP 的概念:标准协议、三大角色、M+N 替代 M×N。

nice_lcj520的博客 521

Java 集合容器高频面试题全解:HashMap 树化阈值、1.7 死循环与 ConcurrentHashMap 演进(2026 招聘 JD 真题复盘)

HashMap 树化阈值 8 的泊松分布依据、退化阈值 6 的防抖设计、JDK 1.7 头插成环死循环的排查与修复、1.8 尾插后为何仍线程不安全、ConcurrentHashMap 放弃分段锁的原因与 ForwardingNode 协作扩容、computeIfAbsent 死锁陷阱、大集合找重复的场景题选型,附三层追问链自测。题目来源为 38 期公开招聘 JD 样本与字节、拼多多、建行、美团、快手公开面经。

蒙眼过河 414

spdlog 同步日志库使用详解

spdlog是一个轻量级 C++ 日志库,支持同步日志、异步日志、多线程日志、日志文件轮转和自定义日志格式。对于嵌入式 Linux 应用开发,我建议先使用。它可以帮我们完成:日志级别过滤。时间戳和线程 ID 输出。日志格式化。终端和文件输出。多线程安全写入。日志文件按大小或时间轮转。我们不需要自己实现互斥锁、文件写入、日志格式化和轮转等底层功能。

zengjiajun2006的博客 995

JavaEE通关手册:数据类型与变量

代码无需额外处理,编译时编译器自动完成转换。

xys_678的博客 76

Java 多态 学习笔记

多态是面向对象编程的重要特性,指同一操作作用于不同对象时产生不同行为。其核心在于“父类引用指向子类对象”,结合方法重写实现运行时动态绑定。多态使代码更灵活、可扩展,如用Person p = new Student();统一处理各类人员注册,无需修改调用逻辑。但多态无法直接调用子类特有方法,需通过instanceof判断并强制转换。编译时看左边(类型),运行时看右边(实际对象),实现解耦与维护便利。

AA_AA114514的博客 367
上一篇: 详解Spring AOP五大通知类型:从零搭建企业级操作日志系统
下一篇: 实测分享:AI 生成 Python 科技海报时,如何避免文字乱码问题
Ahtacca
博客等级 码龄1年 55粉丝 31原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值