使用EasyExcel实现Excel单元格保护:自由锁定表头和数据行

使用EasyExcel实现Excel单元格保护:锁定表头和第二行数据

前言

在日常开发中,我们经常需要导出Excel文件,有时还需要对Excel中的某些单元格进行保护,防止用户误修改。本文将介绍如何使用EasyExcel 4.0.3实现锁定Excel表头和第二行数据,同时允许其他单元格自由编辑的功能。

技术背景

EasyExcel是阿里巴巴开源的一个基于Java的简单、省内存的读写Excel工具。它能够帮助我们轻松实现Excel的各种操作,包括单元格样式设置、数据保护等。

实现目标

  • 锁定Excel表头(第一行)
  • 锁定第二行数据
  • 允许第三行及之后的数据自由编辑
  • 允许用户添加新行/列并编辑

Maven依赖

<dependency>
<groupId>com.alibaba</groupId>
<artifactId>easyexcel</artifactId>
<version>4.0.3</version>
</dependency>

核心代码实现

1. 数据模型定义

public static class TestDataModel {
@ExcelProperty("姓名")
private String name;@ExcelProperty("年龄")
private Integer age;@ExcelProperty("城市")
private String city;// 构造方法和getter/setter省略
}

2. 自定义单元格样式策略

static class CustomCellStyleStrategy extends HorizontalCellStyleStrategy {
public CustomCellStyleStrategy(WriteCellStyle headWriteCellStyle, WriteCellStyle contentWriteCellStyle) {
super(headWriteCellStyle, contentWriteCellStyle);
}@Override
public void afterCellDispose(CellWriteHandlerContext context) {
// 表头行处理
if (context.getHead()) {
super.afterCellDispose(context);
return;
}// 数据行处理
if (context.getRowIndex() != null) {
if (context.getRowIndex() == 1) {
// 第二行数据,应用锁定样式
Cell cell = context.getCell();
Workbook workbook = context.getWriteSheetHolder().getSheet().getWorkbook();// 创建新样式(基于当前样式)
CellStyle newStyle = workbook.createCellStyle();
if (cell.getCellStyle() != null) {
newStyle.cloneStyleFrom(cell.getCellStyle());
}
newStyle.setLocked(true); // 设置为锁定
cell.setCellStyle(newStyle);
} else {
// 其他行应用解锁样式
super.afterCellDispose(context);
}
}
}
}

3. 工作表保护处理器

static class SheetProtectionHandler implements SheetWriteHandler {
@Override
public void afterSheetCreate(WriteWorkbookHolder writeWorkbookHolder, WriteSheetHolder writeSheetHolder) {
Sheet sheet = writeSheetHolder.getSheet();
Workbook workbook = writeWorkbookHolder.getWorkbook();// 设置整个工作表的默认样式为可编辑
CellStyle defaultStyle = workbook.createCellStyle();
defaultStyle.setLocked(false);// 设置所有列的默认样式
int maxColumns = 256;
for (int i = 0; i < maxColumns; i++) {
sheet.setDefaultColumnStyle(i, defaultStyle);
}// 启用工作表保护(密码:123)
sheet.protectSheet("123");
}
}

4. 导出Excel主方法

public static void exportExcel(String fileName, List<?> dataList) {
// 定义锁定样式
WriteCellStyle lockedStyle = new WriteCellStyle();
lockedStyle.setLocked(true);// 定义解锁样式
WriteCellStyle unlockedStyle = new WriteCellStyle();
unlockedStyle.setLocked(false);// 创建处理器实例
HorizontalCellStyleStrategy styleStrategy = new CustomCellStyleStrategy(lockedStyle, unlockedStyle);
SheetWriteHandler sheetProtectionHandler = new SheetProtectionHandler();// 写入Excel
EasyExcel.write(fileName, TestDataModel.class)
.registerWriteHandler(styleStrategy)
.registerWriteHandler(sheetProtectionHandler)
.sheet("员工数据")
.doWrite(dataList);
}

完整代码

import com.alibaba.excel.EasyExcel;
import com.alibaba.excel.annotation.ExcelProperty;
import com.alibaba.excel.write.handler.SheetWriteHandler;
import com.alibaba.excel.write.handler.context.CellWriteHandlerContext;
import com.alibaba.excel.write.metadata.holder.WriteSheetHolder;
import com.alibaba.excel.write.metadata.holder.WriteWorkbookHolder;
import com.alibaba.excel.write.metadata.style.WriteCellStyle;
import com.alibaba.excel.write.style.HorizontalCellStyleStrategy;
import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.CellStyle;
import org.apache.poi.ss.usermodel.Sheet;
import org.apache.poi.ss.usermodel.Workbook;import java.util.ArrayList;
import java.util.List;public class ExcelExporter {public static void main(String[] args) {// 创建测试数据List<TestDataModel> dataList = new ArrayList<>();dataList.add(new TestDataModel("张三", 25, "北京"));dataList.add(new TestDataModel("李四", 30, "上海"));dataList.add(new TestDataModel(null, 28, "广州"));dataList.add(new TestDataModel("赵六", 35, null));// 导出ExcelexportExcel("test_output.xlsx", dataList);System.out.println("Excel文件已生成: test_output.xlsx");}public static void exportExcel(String fileName, List<?> dataList) {// 1. 定义锁定样式(用于表头和第二行)WriteCellStyle lockedStyle = new WriteCellStyle();lockedStyle.setLocked(true); // 设置单元格锁定// 2. 定义解锁样式(用于第三行及之后的数据)WriteCellStyle unlockedStyle = new WriteCellStyle();unlockedStyle.setLocked(false); // 设置单元格可编辑// 3. 创建自定义样式策略HorizontalCellStyleStrategy styleStrategy = new CustomCellStyleStrategy(lockedStyle, unlockedStyle);// 4. 创建工作表保护处理器SheetWriteHandler sheetProtectionHandler = new SheetProtectionHandler();// 5. 写入ExcelEasyExcel.write(fileName, TestDataModel.class).registerWriteHandler(styleStrategy).registerWriteHandler(sheetProtectionHandler).sheet("员工数据").doWrite(dataList);}/*** 自定义单元格样式策略*/static class CustomCellStyleStrategy extends HorizontalCellStyleStrategy {public CustomCellStyleStrategy(WriteCellStyle headWriteCellStyle, WriteCellStyle contentWriteCellStyle) {super(headWriteCellStyle, contentWriteCellStyle);}/*** 重写方法,根据行号应用不同样式** @param context*/@Overridepublic void afterCellDispose(CellWriteHandlerContext context) {// 表头行(isHead=true)直接使用父类方法,即应用锁定样式if (context.getHead()) {super.afterCellDispose(context);return;}// 数据行处理,数据行的格式是解锁还是锁定,要看创建时传参if (context.getRowIndex() != null) {if (context.getRowIndex() == 1) {// 获取当前单元格Cell cell = context.getCell();Workbook workbook = context.getWriteSheetHolder().getSheet().getWorkbook();// 1. 创建新样式(基于当前样式)CellStyle newStyle = workbook.createCellStyle();// 2. 复制当前样式(如果存在)if (cell.getCellStyle() != null) {newStyle.cloneStyleFrom(cell.getCellStyle());}// 3. 设置为锁定newStyle.setLocked(true);// 4. 应用新样式cell.setCellStyle(newStyle);} else {super.afterCellDispose(context);}}}}/*** 工作表保护处理器*/static class SheetProtectionHandler implements SheetWriteHandler {@Overridepublic void afterSheetCreate(WriteWorkbookHolder writeWorkbookHolder, WriteSheetHolder writeSheetHolder) {Sheet sheet = writeSheetHolder.getSheet();Workbook workbook = writeWorkbookHolder.getWorkbook();// 1. 设置整个工作表的默认样式为可编辑CellStyle defaultStyle = workbook.createCellStyle();defaultStyle.setLocked(false); // 解锁所有单元格// 设置所有列的默认样式(假设最大列数为256)int maxColumns = 256;for (int i = 0; i < maxColumns; i++) {sheet.setDefaultColumnStyle(i, defaultStyle);}// 3. 启用工作表保护(使用空密码)sheet.protectSheet("123");}}// 测试数据模型public static class TestDataModel {@ExcelProperty("姓名")private String name;@ExcelProperty("年龄")private Integer age;@ExcelProperty("城市")private String city;public TestDataModel() {// 无参构造函数}public TestDataModel(String name, Integer age, String city) {this.name = name;this.age = age;this.city = city;}// Getters and Setterspublic String getName() {return name;}public void setName(String name) {this.name = name;}public Integer getAge() {return age;}public void setAge(Integer age) {this.age = age;}public String getCity() {return city;}public void setCity(String city) {this.city = city;}}
}

关键点解析

  1. 样式继承机制
  • 表头行直接应用锁定样式
  • 第二行显式创建并应用锁定样式
  • 其他行应用解锁样式
  1. 工作表保护
  • 设置所有列默认可编辑
  • 启用工作表保护(密码保护)
  • 只有锁定样式的单元格受到保护
  1. 单元格处理流程
  • 每个单元格独立处理
  • 样式应用是逐个单元格进行的
  • 显式设置覆盖所有默认行为

效果验证

生成的Excel文件将具有以下特性:

  1. 锁定区域
  • 第一行(表头):完全锁定
  • 第二行(第一行数据):完全锁定
  1. 可编辑区域
  • 第三行及之后的数据行
  • 工作表的空白区域
  • 新添加的行/列
  1. 保护机制
  • 需要密码"123"才能修改受保护区域
  • 可编辑区域可以直接修改

总结

通过EasyExcel的样式策略和工作表保护机制,我们实现了灵活控制Excel单元格编辑权限的功能。这种方案具有以下优点:

  1. 精确控制:可以精确锁定特定行/列
  2. 灵活性:不影响用户在其他区域的编辑
  3. 兼容性:适用于各种数据模型
  4. 易扩展:可以轻松调整锁定策略

这种实现方式特别适用于需要保护表头和示例数据,同时允许用户自由编辑其他数据的场景,如数据模板导出等。

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

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

相关文章

dify docker知识库topk最大值参数配置

1 问题说明 dify构建RAG知识库过程中&#xff0c;通过会遇到一些默认配置不能解决的问题。 比如topk&#xff0c;topk默认最大10&#xff0c;对语义模糊的检索&#xff0c;目标文档可能没进前10&#xff0c;出现在10-30区间。 所以&#xff0c;需要调整topk最大值参数。 # T…

SRE命令行兵器谱之一:精通top/htop - 从性能“体检”到瓶颈“解剖”

SRE命令行兵器谱之一:精通top/htop - 从性能“体检”到瓶颈“解剖” SRE的“战场”:真实故障场景 下午三点,监控系统告警:“核心API服务响应时间(P99)飙升至5秒”。用户已经开始在群里抱怨接口超时。这是一个典型的线上性能问题,每一秒的延迟都在影响用户体验和公司收…

一、Git与Gitee常见问题解答

Git与Gitee常见问题解答 Git相关问题 Q1: 什么是Git&#xff1f; A: Git是一个分布式版本控制系统&#xff0c;由Linux之父Linus Torvalds开发。它能够跟踪文件的变更历史&#xff0c;支持多人协作开发&#xff0c;是现代软件开发中不可或缺的工具。 Q2: Git的三个区域是什么&a…

kubernetes服务质量之QoS类

一、QoS类 Kubernetes的QoS&#xff08;Quality of Service&#xff09;类别允许您指定可用于应用程序的可用资源数量&#xff0c;以便更好地控制应用程序的可用性。它还允许您限制特定应用程序的资源使用率&#xff0c;以帮助保护系统的稳定性和性能。 Kubernetes 创建 Pod 时…

Redis--Lua脚本以及在SpringBoot中的使用

前言、为什么要用 Lua&#xff1f;多步操作合并为一步&#xff0c;保证原子性。减少网络通信次数。下推逻辑到 Redis&#xff0c;提高性能。一、Redis 使用 Lua 脚本的两种方式方式一&#xff1a;使用 --eval 执行脚本文件这种方式 需要先写一个 Lua 文件。&#x1f4cc; 示例&…

基于 C 语言的网络单词查询系统设计与实现(客户端 + 服务器端)

一、项目概述本文将介绍一个基于 C 语言开发的网络单词查询系统&#xff0c;该系统包含客户端和服务器端两部分&#xff0c;支持用户注册、登录、单词查询及历史记录查询等功能。系统采用 TCP socket 实现网络通信&#xff0c;使用 SQLite 数据库存储用户信息、单词数据及查询记…

《JAVA EE企业级应用开发》第一课笔记

《JAVA EE企业级应用开发》第一课笔记 文章目录《JAVA EE企业级应用开发》第一课笔记课程主题&#xff1a;三层架构与SSM框架概述一、核心架构&#xff1a;三层架构 (MVC)1. 表现层 (Presentation Layer)2. 业务逻辑层 (Business Logic Layer)3. 数据持久层 (Data Persistence …

RT-DETR网络结构

1.前言 本章主要来介绍下RT-DETR的网络结构,参考的依旧是ultralytics实现的RT-DETR-L,代码如下: ultralytics/ultralytics: Ultralytics YOLO 🚀 首先谈谈我对RT-DETR的浅显认识,他不像是YOLOv8这种纯CNN实现的网络,也不像是Vit这种以Transformer实现的网络,他是前一…

Python 文件复制实战指南:从基础操作到高效自动化的最佳实践

Python 文件复制实战指南:从基础操作到高效自动化的最佳实践 1. 引言:文件复制为何是自动化的核心能力? 在日常开发与运维工作中,文件复制是一项基础却至关重要的操作。无论是备份日志、同步配置、部署代码,还是批量迁移数据,都离不开对文件的精准复制与路径管理。而 Py…

WebSocket的基本使用方法

一. 与HTTP对比WebSocket 是一种在单个 TCP 连接上实现全双工&#xff08;双向&#xff09;通信的网络协议&#xff0c;它解决了传统 HTTP 协议 “请求 - 响应” 模式的局限性&#xff0c;让客户端&#xff08;如浏览器&#xff09;和服务器能建立持久连接&#xff0c;实现实时…

架构选型:为何用对象存储替代HDFS构建现代数据湖

在过去十余年的大数据浪潮中&#xff0c;Hadoop及其核心组件HDFS&#xff08;Hadoop分布式文件系统&#xff09;无疑是整个技术生态的基石。它开创性地解决了海量数据的分布式存储难题&#xff0c;支撑了无数企业从数据中挖掘价值。然而&#xff0c;随着数据规模的指数级增长以…

智能养花谁更优?WebIDE PLOY技术与装置的结合及实践价值 —— 精准养护的赋能路径

一、WebIDEPLOY 技术支撑下的智能养花系统核心构成在 WebIDEPLOY 技术的框架下&#xff0c;智能养花装置形成了一套精准协同的闭环系统&#xff0c;其核心在于通过技术整合实现 “监测 - 决策 - 执行 - 远程交互” 的无缝衔接&#xff0c;让植物养护更贴合城市居民的生活节奏。…

基于llama.cpp在CPU环境部署Qwen3

大家好,我是奇文王语,NLP爱好者,长期分享大模型实战技巧,欢迎关注交流。 最近两天在研究如何使用小规模参数的模型在CPU环境上进行落地应用,比如模型Qwen3-0.6B。开始使用Transformers库能够正常把模型服务进行部署起来,但是通过测试速度比较慢,用户的体验会比较差。 …

‌NAT穿透技术原理:P2P通信中的打洞机制解析‌

要说网络世界里的 “幕后功臣”&#xff0c;NAT 绝对得算一个&#xff0c;大家伙儿有没有琢磨过&#xff0c;为啥家里的电脑、手机&#xff0c;还有公司那一堆设备&#xff0c;都能同时连上网&#xff0c;还不打架呢&#xff1f; NAT 这东西&#xff0c;全名叫网络地址转换&am…

工业 5G + AI:智能制造的未来引擎

工业 5G AI&#xff1a;智能制造的未来引擎 文章目录工业 5G AI&#xff1a;智能制造的未来引擎摘要一、为什么工业需要 5G&#xff1f;二、工业 5G 的典型应用场景1. 智能制造工厂2. 远程控制与运维3. 智慧物流与仓储4. 能源、电力、矿山5. 智慧港口与交通三、成功案例解析1…

边缘计算设备 RK3576芯片

RK3576是瑞芯微&#xff08;Rockchip&#xff09;公司专为人工智能物联网&#xff08;AIoT&#xff09;市场精心设计的一款高算力、高性能及低功耗的国产化应用处理器。该处理器采用了先进的ARM架构&#xff0c;集成了四个ARM Cortex-A72高性能核心与四个ARM Cortex-A53高效能核…

ROS1系列学习笔记之T265的Python数据订阅显示、串口输出到凌霄飞控,以及开机自启动设置等一些问题处理方法(持续更新)

前言 关于T265的环境配置与安装&#xff0c;在前两期的ROS笔记中已经提及&#xff0c;包括英特尔本家的SDK安装&#xff0c;以及对应支持版本的ROS支持开发工具包。 ROS1系列学习笔记之Linux&#xff08;Ubuntu&#xff09;的环境安装、依赖准备、踩坑提示&#xff08;硬件以…

UART控制器——ZYNQ学习笔记14

UART 控制器是一个全双工异步收发控制器&#xff0c; MPSoC 内部包含两个 UART 控制器&#xff0c; UART0 和 UART1。每一个 UART 控制器支持可编程的波特率发生器、 64 字节的接收 FIFO 和发送 FIFO、产生中断、 RXD 和TXD 信号的环回模式设置以及可配置的数据位长度、停止位和…

C++ 登录状态机项目知识笔记

C 登录状态机项目知识笔记 1. 项目源码 1.1 login_state_machine.h #pragma once#include <string>// 登录状态枚举 enum class LoginState { IDLE, AUTHENTICATING, SUCCESS, FAILURE, LOCKED };// 登录事件枚举 enum class LoginEvent { REQUEST, SUCCESS, FAILURE, RE…

docker-nacos-v3

nacos官网&#xff1a; Redirecting to: https://nacos.io/ 服务发现和服务健康监测 Nacos 支持基于 DNS 和基于 RPC 的服务发现。服务提供者使用 原生SDK、OpenAPI、或一个独立的Agent TODO注册 Service 后&#xff0c;服务消费者可以使用DNS TODO 或HTTP&API查找和发现服…