添加功能
This commit is contained in:
@@ -0,0 +1,66 @@
|
||||
package com.ruoyi.cms.util.document;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 就业服务Excel工具类,直接使用原始的ExcelUtil类
|
||||
* 提供便捷的方法设置数据列表和工作表名称
|
||||
*/
|
||||
public class ExcelUtil<T> extends com.ruoyi.common.utils.poi.ExcelUtil<T> {
|
||||
|
||||
public ExcelUtil(Class<T> pojoClass) {
|
||||
super(pojoClass);
|
||||
// 不在这里调用init方法,而是在setDataList之后调用
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置数据列表
|
||||
* @param dataList 数据列表
|
||||
* @return 当前实例,支持链式调用
|
||||
*/
|
||||
public ExcelUtil<T> setDataList(List<T> dataList) {
|
||||
try {
|
||||
// 直接使用反射设置父类的list字段
|
||||
java.lang.reflect.Field listField = getClass().getSuperclass().getDeclaredField("list");
|
||||
listField.setAccessible(true);
|
||||
listField.set(this, dataList);
|
||||
// 在设置数据列表后调用init方法
|
||||
this.init();
|
||||
return this;
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException("设置数据列表失败", e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置工作表名称
|
||||
* @param sheetName 工作表名称
|
||||
* @return 当前实例,支持链式调用
|
||||
*/
|
||||
public ExcelUtil<T> setSheetName(String sheetName) {
|
||||
try {
|
||||
// 直接使用反射设置父类的sheetName字段
|
||||
java.lang.reflect.Field sheetNameField = getClass().getSuperclass().getDeclaredField("sheetName");
|
||||
sheetNameField.setAccessible(true);
|
||||
sheetNameField.set(this, sheetName);
|
||||
return this;
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException("设置工作表名称失败", e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 初始化方法,确保对象正确初始化
|
||||
*/
|
||||
private void init() {
|
||||
try {
|
||||
// 调用父类的createExcelField方法创建Excel字段映射
|
||||
Method createExcelFieldMethod = getClass().getSuperclass().getDeclaredMethod("createExcelField");
|
||||
createExcelFieldMethod.setAccessible(true);
|
||||
createExcelFieldMethod.invoke(this);
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException("初始化Excel字段映射失败", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,558 @@
|
||||
package com.ruoyi.cms.util.document;
|
||||
|
||||
import com.ruoyi.common.utils.DateUtils;
|
||||
import com.ruoyi.common.utils.poi.ExcelUtil;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.apache.poi.ss.usermodel.BorderStyle;
|
||||
import org.apache.poi.ss.usermodel.Cell;
|
||||
import org.apache.poi.ss.usermodel.CellStyle;
|
||||
import org.apache.poi.ss.usermodel.DataFormat;
|
||||
import org.apache.poi.ss.usermodel.Font;
|
||||
import org.apache.poi.ss.usermodel.HorizontalAlignment;
|
||||
import org.apache.poi.ss.usermodel.IndexedColors;
|
||||
import org.apache.poi.ss.usermodel.Row;
|
||||
import org.apache.poi.ss.usermodel.Sheet;
|
||||
import org.apache.poi.ss.usermodel.VerticalAlignment;
|
||||
import org.apache.poi.ss.usermodel.Workbook;
|
||||
import org.apache.poi.xssf.streaming.SXSSFWorkbook;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import java.io.IOException;
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.Method;
|
||||
import java.net.URLEncoder;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
/**
|
||||
* 多工作表Excel导出工具类
|
||||
* 支持添加多个ExcelUtil实例,每个实例对应一个工作表
|
||||
*
|
||||
* @author
|
||||
* @date
|
||||
*/
|
||||
@Slf4j
|
||||
@Component
|
||||
public class MultiSheetExcelUtil {
|
||||
|
||||
private final List<ExcelUtil<?>> excelUtilList;
|
||||
private final Workbook workbook;
|
||||
// 临时变量,存储外部指定的文件名
|
||||
private String customFileName;
|
||||
|
||||
// 缓存反射方法,避免重复查找
|
||||
private static final Map<String, Method> METHOD_CACHE = new ConcurrentHashMap<>();
|
||||
// 缓存反射字段,避免重复查找
|
||||
private static final Map<String, Field> FIELD_CACHE = new ConcurrentHashMap<>();
|
||||
|
||||
/**
|
||||
* 构造函数
|
||||
*/
|
||||
public MultiSheetExcelUtil() {
|
||||
this.excelUtilList = new ArrayList<>();
|
||||
// 使用SXSSFWorkbook以支持大数据量导出
|
||||
this.workbook = new SXSSFWorkbook(100); // 100条记录保存在内存中
|
||||
}
|
||||
|
||||
/**
|
||||
* 添加一个ExcelUtil实例(对应一个工作表)
|
||||
*
|
||||
* @param excelUtil ExcelUtil实例
|
||||
* @return 当前实例,支持链式调用
|
||||
*/
|
||||
public MultiSheetExcelUtil addSheet(ExcelUtil<?> excelUtil) {
|
||||
excelUtilList.add(excelUtil);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置外部指定的文件名
|
||||
*
|
||||
* @param customFileName 外部指定的文件名(不包含扩展名)
|
||||
* @return 当前实例,支持链式调用
|
||||
*/
|
||||
public MultiSheetExcelUtil setFileName(String customFileName) {
|
||||
this.customFileName = customFileName;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取工作表名称
|
||||
*
|
||||
* @param excelUtil ExcelUtil实例
|
||||
* @return 工作表名称
|
||||
*/
|
||||
private String getSheetName(ExcelUtil<?> excelUtil) {
|
||||
try {
|
||||
if (excelUtil == null) {
|
||||
return "Sheet"; // 返回默认名称
|
||||
}
|
||||
|
||||
// 使用缓存的方法获取字段
|
||||
String sheetName = (String) getPrivateField(excelUtil, "sheetName");
|
||||
|
||||
// 如果从字段获取的名称为空,则返回默认名称
|
||||
if (sheetName == null || sheetName.trim().isEmpty()) {
|
||||
return "Sheet";
|
||||
}
|
||||
|
||||
// 确保工作表名称不超过Excel限制
|
||||
if (sheetName.length() > 31) {
|
||||
sheetName = sheetName.substring(0, 31);
|
||||
}
|
||||
|
||||
return sheetName;
|
||||
} catch (Exception e) {
|
||||
System.err.println("获取工作表名称时出错: " + e.getMessage());
|
||||
// 如果出错,返回默认名称
|
||||
return "Sheet";
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 导出Excel文件(直接输出到HttpServletResponse)
|
||||
*
|
||||
* @param response HttpServletResponse
|
||||
* @throws IOException IOException
|
||||
*/
|
||||
public void exportExcel(HttpServletResponse response) throws IOException {
|
||||
try {
|
||||
if (excelUtilList.isEmpty()) {
|
||||
throw new IOException("没有要导出的工作表");
|
||||
}
|
||||
|
||||
// 获取第一个ExcelUtil实例
|
||||
ExcelUtil<?> firstExcelUtil = excelUtilList.get(0);
|
||||
|
||||
// 设置所有ExcelUtil实例使用同一个Workbook并重新创建样式
|
||||
for (ExcelUtil<?> excelUtil : excelUtilList) {
|
||||
if (excelUtil != null) {
|
||||
try {
|
||||
// 尝试设置wb字段,如果不存在则忽略错误
|
||||
setPrivateField(excelUtil, "wb", workbook);
|
||||
// 为每个ExcelUtil实例创建新的样式,确保与当前Workbook关联
|
||||
Map<String, CellStyle> styles = createStylesForSheet(workbook);
|
||||
setPrivateField(excelUtil, "styles", styles);
|
||||
} catch (Exception e) {
|
||||
// 如果设置字段失败,继续处理下一个ExcelUtil实例
|
||||
System.err.println("处理ExcelUtil实例时出错: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 为每个ExcelUtil实例创建工作表并填充数据
|
||||
for (int i = 0; i < excelUtilList.size(); i++) {
|
||||
ExcelUtil<?> excelUtil = excelUtilList.get(i);
|
||||
|
||||
// 设置当前工作表对象
|
||||
Sheet newSheet = workbook.createSheet();
|
||||
workbook.setSheetName(i, getSheetName(excelUtil));
|
||||
setPrivateField(excelUtil, "sheet", newSheet);
|
||||
|
||||
// 重置rownum为0,确保每个工作表都从第一行开始
|
||||
setPrivateField(excelUtil, "rownum", 0);
|
||||
|
||||
// 调用createTitle方法创建标题行
|
||||
invokeCachedMethod(excelUtil, "createTitle", new Class<?>[]{});
|
||||
|
||||
// 获取字段列表
|
||||
List<Object[]> fields = (List<Object[]>) getPrivateField(excelUtil, "fields");
|
||||
|
||||
// 获取子字段列表
|
||||
// List<Field> subFields = (List<Field>) getPrivateField(excelUtil, "subFields");
|
||||
|
||||
// 调用createSubHead方法创建子标题行(如果需要)
|
||||
try {
|
||||
invokeCachedMethod(excelUtil, "createSubHead", new Class<?>[]{});
|
||||
} catch (Exception e) {
|
||||
// 如果没有createSubHead方法或调用失败,忽略该异常
|
||||
}
|
||||
|
||||
// 填充每一行数据
|
||||
List<?> dataList = null;
|
||||
try {
|
||||
dataList = (List<?>) getPrivateField(excelUtil, "list");
|
||||
} catch (Exception e) {
|
||||
System.err.println("获取数据列表失败: " + e.getMessage());
|
||||
}
|
||||
|
||||
if (dataList != null && !dataList.isEmpty()) {
|
||||
// 从excelUtil对象中获取sheet字段的值
|
||||
Sheet sheet = (Sheet) getPrivateField(excelUtil, "sheet");
|
||||
if (sheet == null) {
|
||||
continue; // 如果sheet为空,跳过当前工作表
|
||||
}
|
||||
|
||||
// 字段列表已经在第360行定义,直接使用
|
||||
if (fields == null || fields.isEmpty()) {
|
||||
continue; // 跳过没有字段的工作表
|
||||
}
|
||||
|
||||
// 获取当前行号
|
||||
Object rownumObj = getPrivateField(excelUtil, "rownum");
|
||||
int currentRowNum = rownumObj != null ? (int) rownumObj : 0;
|
||||
|
||||
// 遍历数据列表,填充每一行数据
|
||||
for (int j = 0; j < dataList.size(); j++) {
|
||||
// 创建新行
|
||||
Row dataRow = sheet.createRow(currentRowNum++);
|
||||
|
||||
// 获取当前数据对象
|
||||
Object dataObj = dataList.get(j);
|
||||
|
||||
// 遍历字段列表,填充每一列数据
|
||||
int column = 0;
|
||||
for (Object[] os : fields) {
|
||||
if (os.length < 2) {
|
||||
continue;
|
||||
}
|
||||
|
||||
Field field = (Field) os[0];
|
||||
//Excel excel = (Excel) os[1];
|
||||
|
||||
try {
|
||||
// 设置字段可访问
|
||||
field.setAccessible(true);
|
||||
|
||||
// 获取字段值
|
||||
Object fieldValue = field.get(dataObj);
|
||||
|
||||
// 创建单元格
|
||||
Cell cell = dataRow.createCell(column++);
|
||||
|
||||
// 设置单元格值
|
||||
if (fieldValue != null) {
|
||||
cell.setCellValue(fieldValue.toString());
|
||||
} else {
|
||||
cell.setCellValue("");
|
||||
}
|
||||
} catch (Exception e) {
|
||||
System.err.println("填充数据失败: " + e.getMessage());
|
||||
log.error("发生异常", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 更新行号
|
||||
setPrivateField(excelUtil, "rownum", currentRowNum);
|
||||
}
|
||||
|
||||
// 调用addStatisticsRow方法添加统计行(如果需要)
|
||||
try {
|
||||
invokeCachedMethod(excelUtil, "addStatisticsRow", new Class<?>[]{});
|
||||
} catch (Exception e) {
|
||||
// 如果没有addStatisticsRow方法或调用失败,忽略该异常
|
||||
}
|
||||
}
|
||||
|
||||
// 使用第一个ExcelUtil实例的exportExcel方法导出所有工作表
|
||||
// 但需要替换其writeSheet调用,因为我们已经创建了所有工作表
|
||||
exportAllSheetsToResponse(firstExcelUtil, response);
|
||||
} catch (Exception e) {
|
||||
log.error("发生异常", e);
|
||||
throw new IOException("导出Excel失败,请联系管理员", e);
|
||||
} finally {
|
||||
// 确保清理资源
|
||||
dispose();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 导出所有工作表到HttpServletResponse(绕过writeSheet调用)
|
||||
*
|
||||
* @param excelUtil ExcelUtil实例
|
||||
* @param response HttpServletResponse
|
||||
* @throws Exception Exception
|
||||
*/
|
||||
private void exportAllSheetsToResponse(ExcelUtil<?> excelUtil, HttpServletResponse response) throws Exception {
|
||||
// 获取Workbook和工作表名称
|
||||
Workbook wb = (Workbook) getPrivateField(excelUtil, "wb");
|
||||
|
||||
String baseFilename;
|
||||
// 优先使用外部指定的文件名
|
||||
if (customFileName != null && !customFileName.trim().isEmpty()) {
|
||||
baseFilename = customFileName.trim();
|
||||
} else {
|
||||
String sheetName = (String) getPrivateField(excelUtil, "sheetName");
|
||||
baseFilename = (sheetName == null || sheetName.trim().isEmpty()) ? "数据导出" : sheetName;
|
||||
}
|
||||
|
||||
// 编码文件名并设置响应头
|
||||
// 使用格式:名称_时分秒.xlsx,替换原来的UUID格式
|
||||
String filename = baseFilename + "_" + DateUtils.dateTimeNow(DateUtils.YYYYMMDDHHMMSS) + ".xlsx";
|
||||
|
||||
// 设置响应头
|
||||
response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
|
||||
response.setCharacterEncoding(StandardCharsets.UTF_8.name());
|
||||
// 对文件名编码,解决中文乱码
|
||||
String encodedFileName = URLEncoder.encode(filename, StandardCharsets.UTF_8.name()).replaceAll("\\+", "%20");
|
||||
response.setHeader("Content-disposition", "attachment;filename*=utf-8''" + encodedFileName);
|
||||
|
||||
// 将Workbook写入响应流
|
||||
wb.write(response.getOutputStream());
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取缓存的字段
|
||||
*/
|
||||
private Field getCachedField(Class<?> clazz, String fieldName) {
|
||||
String key = clazz.getName() + ":" + fieldName;
|
||||
return FIELD_CACHE.computeIfAbsent(key, k -> {
|
||||
try {
|
||||
// 递归查找父类中的字段
|
||||
Class<?> currentClass = clazz;
|
||||
while (currentClass != null) {
|
||||
try {
|
||||
Field field = currentClass.getDeclaredField(fieldName);
|
||||
field.setAccessible(true);
|
||||
return field;
|
||||
} catch (NoSuchFieldException e) {
|
||||
currentClass = currentClass.getSuperclass();
|
||||
}
|
||||
}
|
||||
return null;
|
||||
} catch (Exception e) {
|
||||
System.err.println("缓存字段失败: " + key + ", 错误: " + e.getMessage());
|
||||
return null;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取缓存的方法
|
||||
*/
|
||||
private Method getCachedMethod(Class<?> clazz, String methodName, Class<?>... parameterTypes) {
|
||||
String key = clazz.getName() + ":" + methodName + ":" + parameterTypes.length;
|
||||
return METHOD_CACHE.computeIfAbsent(key, k -> {
|
||||
try {
|
||||
// 递归查找父类中的方法
|
||||
Class<?> currentClass = clazz;
|
||||
while (currentClass != null) {
|
||||
try {
|
||||
Method method = currentClass.getDeclaredMethod(methodName, parameterTypes);
|
||||
method.setAccessible(true);
|
||||
return method;
|
||||
} catch (NoSuchMethodException e) {
|
||||
currentClass = currentClass.getSuperclass();
|
||||
}
|
||||
}
|
||||
return null;
|
||||
} catch (Exception e) {
|
||||
System.err.println("缓存方法失败: " + key + ", 错误: " + e.getMessage());
|
||||
return null;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取私有字段的值
|
||||
*
|
||||
* @param obj 对象
|
||||
* @param fieldName 字段名
|
||||
* @return 字段值
|
||||
*/
|
||||
private Object getPrivateField(Object obj, String fieldName) {
|
||||
try {
|
||||
if (obj == null || fieldName == null || fieldName.trim().isEmpty()) {
|
||||
System.err.println("参数无效: obj或fieldName为null或空");
|
||||
return null;
|
||||
}
|
||||
|
||||
Class<?> clazz = obj.getClass();
|
||||
Field field = getCachedField(clazz, fieldName);
|
||||
|
||||
if (field == null) {
|
||||
// 如果缓存中没有,递归查找父类中的字段
|
||||
Class<?> currentClass = clazz;
|
||||
while (currentClass != null) {
|
||||
try {
|
||||
field = currentClass.getDeclaredField(fieldName);
|
||||
field.setAccessible(true);
|
||||
break;
|
||||
} catch (NoSuchFieldException e) {
|
||||
currentClass = currentClass.getSuperclass();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (field != null) {
|
||||
return field.get(obj);
|
||||
} else {
|
||||
System.err.println("找不到字段: " + fieldName);
|
||||
return null;
|
||||
}
|
||||
} catch (IllegalAccessException e) {
|
||||
System.err.println("访问字段失败: " + fieldName + ", 错误: " + e.getMessage());
|
||||
log.error("发生异常", e);
|
||||
return null;
|
||||
} catch (Exception e) {
|
||||
System.err.println("获取私有字段失败: " + fieldName + ", 错误: " + e.getMessage());
|
||||
log.error("发生异常", e);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置私有字段的值
|
||||
*
|
||||
* @param obj 对象
|
||||
* @param fieldName 字段名
|
||||
* @param value 值
|
||||
*/
|
||||
private boolean setPrivateField(Object obj, String fieldName, Object value) {
|
||||
try {
|
||||
if (obj == null || fieldName == null || fieldName.trim().isEmpty()) {
|
||||
System.err.println("参数无效: obj或fieldName为null或空");
|
||||
return false;
|
||||
}
|
||||
|
||||
// 先尝试从直接类查找
|
||||
Class<?> clazz = obj.getClass();
|
||||
Field field = null;
|
||||
|
||||
// 递归查找父类中的字段
|
||||
while (clazz != null && field == null) {
|
||||
try {
|
||||
field = clazz.getDeclaredField(fieldName);
|
||||
} catch (NoSuchFieldException e) {
|
||||
clazz = clazz.getSuperclass();
|
||||
}
|
||||
}
|
||||
|
||||
if (field != null) {
|
||||
field.setAccessible(true);
|
||||
field.set(obj, value);
|
||||
return true;
|
||||
} else {
|
||||
// 字段不存在,记录日志但不抛出异常
|
||||
System.err.println("缓存字段失败: " + obj.getClass().getName() + ":" + fieldName + ", 错误: " + fieldName);
|
||||
return false;
|
||||
}
|
||||
} catch (Exception e) {
|
||||
// 捕获所有异常,记录日志但不中断程序
|
||||
System.err.println("设置私有字段失败: " + obj.getClass().getName() + ":" + fieldName + ", 错误: " + e.getMessage());
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 调用缓存的方法
|
||||
*/
|
||||
private Object invokeCachedMethod(Object obj, String methodName, Class<?>[] paramTypes, Object... args) {
|
||||
try {
|
||||
if (obj == null || methodName == null || methodName.trim().isEmpty()) {
|
||||
System.err.println("参数无效: obj或methodName为null或空");
|
||||
return null;
|
||||
}
|
||||
|
||||
Class<?> clazz = obj.getClass();
|
||||
Method method = getCachedMethod(clazz, methodName, paramTypes);
|
||||
|
||||
if (method == null) {
|
||||
// 如果缓存中没有,递归查找父类中的方法
|
||||
Class<?> currentClass = clazz;
|
||||
while (currentClass != null) {
|
||||
try {
|
||||
method = currentClass.getDeclaredMethod(methodName, paramTypes);
|
||||
method.setAccessible(true);
|
||||
break;
|
||||
} catch (NoSuchMethodException e) {
|
||||
currentClass = currentClass.getSuperclass();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (method != null) {
|
||||
return method.invoke(obj, args);
|
||||
} else {
|
||||
System.err.println("找不到方法: " + methodName);
|
||||
return null;
|
||||
}
|
||||
} catch (Exception e) {
|
||||
System.err.println("调用方法失败: " + methodName + ", 错误: " + e.getMessage());
|
||||
log.error("发生异常", e);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 为工作表创建样式,确保样式关联到当前workbook
|
||||
*/
|
||||
private Map<String, CellStyle> createStylesForSheet(Workbook wb) {
|
||||
Map<String, CellStyle> styles = new HashMap<>();
|
||||
|
||||
try {
|
||||
// 创建默认样式
|
||||
CellStyle style = wb.createCellStyle();
|
||||
style.setAlignment(HorizontalAlignment.CENTER);
|
||||
style.setVerticalAlignment(VerticalAlignment.CENTER);
|
||||
Font titleFont = wb.createFont();
|
||||
titleFont.setFontName("Arial");
|
||||
titleFont.setFontHeightInPoints((short) 16);
|
||||
titleFont.setBold(true);
|
||||
style.setFont(titleFont);
|
||||
DataFormat dataFormat = wb.createDataFormat();
|
||||
style.setDataFormat(dataFormat.getFormat("@"));
|
||||
styles.put("title", style);
|
||||
|
||||
// 创建数据样式
|
||||
style = wb.createCellStyle();
|
||||
style.setAlignment(HorizontalAlignment.CENTER);
|
||||
style.setVerticalAlignment(VerticalAlignment.CENTER);
|
||||
style.setBorderRight(BorderStyle.THIN);
|
||||
style.setRightBorderColor(IndexedColors.GREY_50_PERCENT.getIndex());
|
||||
style.setBorderLeft(BorderStyle.THIN);
|
||||
style.setLeftBorderColor(IndexedColors.GREY_50_PERCENT.getIndex());
|
||||
style.setBorderTop(BorderStyle.THIN);
|
||||
style.setTopBorderColor(IndexedColors.GREY_50_PERCENT.getIndex());
|
||||
style.setBorderBottom(BorderStyle.THIN);
|
||||
style.setBottomBorderColor(IndexedColors.GREY_50_PERCENT.getIndex());
|
||||
Font dataFont = wb.createFont();
|
||||
dataFont.setFontName("Arial");
|
||||
dataFont.setFontHeightInPoints((short) 10);
|
||||
style.setFont(dataFont);
|
||||
styles.put("data", style);
|
||||
|
||||
// 创建合计样式
|
||||
style = wb.createCellStyle();
|
||||
style.setAlignment(HorizontalAlignment.CENTER);
|
||||
style.setVerticalAlignment(VerticalAlignment.CENTER);
|
||||
style.setDataFormat(dataFormat.getFormat("######0.00"));
|
||||
Font totalFont = wb.createFont();
|
||||
totalFont.setFontName("Arial");
|
||||
totalFont.setFontHeightInPoints((short) 10);
|
||||
style.setFont(totalFont);
|
||||
styles.put("total", style);
|
||||
|
||||
} catch (Exception e) {
|
||||
System.err.println("创建样式失败: " + e.getMessage());
|
||||
log.error("发生异常", e);
|
||||
}
|
||||
|
||||
return styles;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取工作簿对象
|
||||
*
|
||||
* @return Workbook
|
||||
*/
|
||||
public Workbook getWorkbook() {
|
||||
return workbook;
|
||||
}
|
||||
|
||||
/**
|
||||
* 清理资源
|
||||
*/
|
||||
public void dispose() {
|
||||
if (workbook instanceof SXSSFWorkbook) {
|
||||
((SXSSFWorkbook) workbook).dispose();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user