3.0版本:https://github.com/asdfLiang/easy-excel-test
2.0版本:https://github.com/asdfLiang/easyexcel-low-test
一、目标效果
- 导出一个excel表格,如果单元格中有内容,则进行锁定不允许修改;如果没有,则不锁定允许修改;
- 禁止用户复制sheet,防止复制整个sheet到其他excel中进行修改。
最终效果如下:

表头和灰色的文字是导出时就有的,不允许修改;4C、5C这两个单元格导出时是空的,允许修改。其他单元格都不允许修改(包括行>5、列>G的单元格)。整个sheet无法选中,也无法进行复制。
二、依赖
<dependencies>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>easyexcel</artifactId>
<version>3.1.1</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.13.2</version>
<scope>test</scope>
</dependency>
</dependencies>
三、代码实现
测试代码入口
import com.alibaba.excel.EasyExcel;
import excel.CustomSheetWriteHandler;
import excel.StyleWriteHandler;
import org.junit.Test;
import java.io.File;
import java.util.List;
import java.util.stream.Collectors;
import java.util.stream.Stream;
/**
* @author by liangzj
* @since 2022/9/17 15:32
*/
public class EasyExcelTest {
@Test
public void testWriteExcel() {
String pathname = "E:\\liangzj\\Desktop\\test.xlsx";
EasyExcel.write(new File(pathname))
.head(header())
.registerWriteHandler(new StyleWriteHandler())
.registerWriteHandler(new CustomSheetWriteHandler())
.sheet("Sheet1")
.doWrite(data());
}
/**
* 数据是先行后列
*
* @return
*/
public List<List<String>> data() {
List<List<String>> data = getRowColMatrix(3, 5);
data.get(0).set(0, "用户1");
data.get(0).set(1, "1234567890");
data.get(0).set(2, "合同1");
data.get(0).set(3, "文本1");
data.get(0).set(4, "210283202209078615");
data.get(1).set(0, "用户2");
data.get(1).set(1, "1234553478");
data.get(1).set(2, null);
data.get(1).set(3, "文本2");
data.get(1).set(4, "210211202209073951");
data.get(2).set(0, "用户3");
data.get(2).set(1, "8332675567");
data.get(2).set(2, null);
data.get(2).set(3, "文本3");
data.get(2).set(4, "120221202209076790");
return data;
}
/**
* 表头是先列后行
*
* @return
*/
public List<List<String>> header() {
List<List<String>> header = getColRowMatrix(2, 5);
header.get(0).set(0, "姓名");
header.get(0).set(1, "姓名");
header.get(1).set(0, "手机/邮箱");
header.get(1).set(1, "手机/邮箱");
header.get(2).set(0, "合同名称");
header.get(2).set(1, "合同名称");
header.get(3).set(0, "文件1");
header.get(3).set(1, "单行文本");
header.get(4).set(0, "文件1");
header.get(4).set(1, "身份证号");
return header;
}
/**
* 生成一个先行后列的矩阵数组
*
* @param maxRow
* @param maxCol
* @return
*/
private static List<List<String>> getRowColMatrix(int maxRow, int maxCol) {
List<List<String>> header =
Stream.generate(
() ->
Stream.generate(() -> "")
.limit(maxCol)
.collect(Collectors.toList()))
.limit(maxRow)
.collect(Collectors.toList());
return header;
}
/**
* 生成一个先列后行的矩阵数组
*
* @param maxRow
* @param maxCol
* @return
*/
private static List<List<String>> getColRowMatrix(int maxRow, int maxCol) {
return getRowColMatrix(maxCol, maxRow);
}
}
设置保护表格
((SXSSFSheet) writeSheetHolder.getSheet()).lockSelectLockedCells(true);这行代码设置的是"已锁定的单元格不可复制",效果就是别人无法复制整个sheet,这样可以防止别人把内容复制到其他excel表中进行修改。如果允许复制,可以不加,不会影响锁单元格的效果。
package excel;
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.xssf.streaming.SXSSFSheet;
/**
* @author by liangzj
* @since 2022/9/17 16:08
*/
public class CustomSheetWriteHandler implements SheetWriteHandler {
@Override
public void afterSheetCreate(
WriteWorkbookHolder writeWorkbookHolder, WriteSheetHolder writeSheetHolder) {
// 设置保护密码
writeSheetHolder.getSheet().protectSheet("123456");
// 锁定单元格不可选中(防止别人直接复制内容到其他excel修改)
((SXSSFSheet) writeSheetHolder.getSheet()).lockSelectLockedCells(true);
}
}
设置单元格锁定状态
contentStyle和contentStyle2实现的效果是一样的,都是设置指定的单元格是否锁定。contentStyle2方法要注意不能直接cell.getCellStyle().setLocked(true),这么写无法生效。
注意:解锁单元格的关键代码是:cellStyle.setLocked(false),方法1中是writeCellStyle.setLocked(false)。
package excel;
import com.alibaba.excel.util.StringUtils;
import com.alibaba.excel.write.handler.context.CellWriteHandlerContext;
import com.alibaba.excel.write.metadata.style.WriteCellStyle;
import com.alibaba.excel.write.metadata.style.WriteFont;
import com.alibaba.excel.write.style.column.LongestMatchColumnWidthStyleStrategy;
import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.CellStyle;
import org.apache.poi.ss.usermodel.Font;
import org.apache.poi.ss.usermodel.IndexedColors;
/**
* 单元格样式处理器
*
* @author by liangzj
* @since 2022/9/17 16:26
*/
public class StyleWriteHandler extends LongestMatchColumnWidthStyleStrategy {
@Override
public void afterCellDispose(CellWriteHandlerContext context) {
if (context.getHead()) { // 表头属性设置
headerStyle(context);
} else { // 表数据属性设置
// contentStyle(context);
contentStyle2(context.getCell());
}
}
/**
* 解锁没有内容的单元格(方法1)
*
* @param context
*/
private void contentStyle(CellWriteHandlerContext context) {
WriteCellStyle writeCellStyle = context.getFirstCellData().getOrCreateStyle();
/* !! 注意:这行就是解锁单元格的代码,locked == true为锁定,locked == false为不锁定 */
writeCellStyle.setLocked(StringUtils.isNotBlank(context.getCell().getStringCellValue()));
// 如果锁定,置灰(这行只是设置样式,不重要)
if (writeCellStyle.getLocked()) {
WriteFont writeFont = new WriteFont();
writeFont.setColor(IndexedColors.GREY_40_PERCENT.index);
writeCellStyle.setWriteFont(writeFont);
}
}
/**
* 解锁没有内容的单元格(方法2)
*
* @param cell
*/
private void contentStyle2(Cell cell) {
// 创建一个新的单元格样式
CellStyle cellStyle = cell.getSheet().getWorkbook().createCellStyle();
// 复制原来单元格的样式(这样就能保证原来单元格的样式不丢失)
cellStyle.cloneStyleFrom(cell.getCellStyle());
/* !! 注意:这行就是解锁单元格的代码,locked == true为锁定,locked == false为不锁定 */
cellStyle.setLocked(StringUtils.isNotBlank(cell.getStringCellValue()));
// 把新建的样式设置为当前单元格样式
cell.setCellStyle(cellStyle);
// 如果锁定,置灰(样式设置,不重要)
if (cell.getCellStyle().getLocked()) {
Font font = cell.getSheet().getWorkbook().createFont();
font.setColor(IndexedColors.GREY_40_PERCENT.index);
cellStyle.setFont(font);
}
}
/**
* 表头格式处理
*
* @param context
*/
private static void headerStyle(CellWriteHandlerContext context) {
Cell cell = context.getCell();
int colWidth = cell.getStringCellValue().length() * 1500;
boolean needHidden = "requireId".equals(cell.getStringCellValue());
// 根据表头文字设置列宽
cell.getSheet().setColumnWidth(cell.getColumnIndex(), colWidth);
// 冻结表头
cell.getSheet().createFreezePane(1, 2);
// 隐藏指定列
cell.getSheet().setColumnHidden(cell.getColumnIndex(), needHidden);
}
}
2.0版本
如果你用的是2.0版本的EasyExcel,那么写法稍有不同,如下(注意:解锁单元格的关键代码是:cellStyle.setLocked(false)):
package excel;
import com.alibaba.excel.metadata.CellData;
import com.alibaba.excel.metadata.Head;
import com.alibaba.excel.util.StringUtils;
import com.alibaba.excel.write.metadata.holder.WriteSheetHolder;
import com.alibaba.excel.write.metadata.holder.WriteTableHolder;
import com.alibaba.excel.write.style.column.LongestMatchColumnWidthStyleStrategy;
import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.CellStyle;
import org.apache.poi.ss.usermodel.Font;
import org.apache.poi.ss.usermodel.IndexedColors;
import java.util.List;
/**
* @author by liangzj
* @since 2022/9/17 16:26
*/
public class StyleWriteHandler extends LongestMatchColumnWidthStyleStrategy {
@Override
public void afterCellDispose(
WriteSheetHolder writeSheetHolder,
WriteTableHolder writeTableHolder,
List<CellData> cellDataList,
Cell cell,
Head head,
Integer relativeRowIndex,
Boolean isHead) {
super.afterCellDispose(
writeSheetHolder,
writeTableHolder,
cellDataList,
cell,
head,
relativeRowIndex,
isHead);
if (isHead) { // 表头属性设置
headerStyle(cell);
} else { // 表数据属性设置
contentStyle(cell);
}
}
private void contentStyle(Cell cell) {
// 创建一个新的单元格样式
CellStyle cellStyle = cell.getSheet().getWorkbook().createCellStyle();
// 复制原单元格的样式(这样就能保证单元格原有的样式不丢失)
cellStyle.cloneStyleFrom(cell.getCellStyle());
/* !! 注意:这行就是解锁单元格的代码,locked == true为锁定,locked == false为不锁定 */
cellStyle.setLocked(!StringUtils.isEmpty(cell.getStringCellValue()));
// 把新创建的样式设置为当前单元格的样式
cell.setCellStyle(cellStyle);
// 不可编辑的单元格置灰(样式设置,不重要)
if (cell.getCellStyle().getLocked()) {
Font font = cell.getSheet().getWorkbook().createFont();
font.setColor(IndexedColors.GREY_40_PERCENT.getIndex());
cell.getCellStyle().setFont(font);
} else {
cell.setCellValue("可填写");
}
}
private static void headerStyle(Cell cell) {
int colWidth = cell.getStringCellValue().length() * 1500;
// 根据表头文字设置列宽
cell.getSheet().setColumnWidth(cell.getColumnIndex(), colWidth);
// 冻结表头
cell.getSheet().createFreezePane(1, 2);
}
}
四、总结
点击执行最上方的测试代码,即可在指定位置生成一个excel文件。总结一下,这个实现思路是,先锁定sheet的所有单元格,再在对允许修改单元格进行解锁。实现这个效果的关键点:
- 设置保护单元格,没有这个设置,锁定单元格不会生效;
- 设置单元格保护状态,注意一定要生成一个新的cellStyle,不要直接cell.getCellStyle().setLocked(true);
- 创建新的cellStyle后,加上cellStyle.cloneStyleFrom(cell.getCellStyle()),这样可以保证原有的单元格样式不丢失。
1802

被折叠的 条评论
为什么被折叠?



