自定义列Excel导出
自定义列Excel导出
前言: Excel导入导出是再常见不过的业务需求了,三年前刚入行就做过,当时查了不少百度、废了不少脑细胞才搞出来;这两天又遇到了同样的需求发现自己又忘了咋做,鼓捣出来后特此记录一下,以免又忘了咋做。
需求: 自定义列导出Excel,参数为 [{"prop":"属性名", "label":"列名"},{"prop":"属性名", "label":"列名"}...]
的JsonArrary的格式。后台逻辑会根据参数中的属性名从Bean中获取数据,然后写入到对应列名的Excel中。
Pom依赖
<!-- start 处理Excel依赖 -->
<dependency>
<groupId>xerces</groupId>
<artifactId>xercesImpl</artifactId>
<version>2.12.1</version>
</dependency>
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi</artifactId>
<version>5.0.0</version>
</dependency>
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi-ooxml</artifactId>
<version>5.0.0</version>
</dependency>
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi-ooxml-schemas</artifactId>
<version>4.1.2</version>
</dependency>
<!-- end 处理Excel依赖 -->
<!-- fastjson-->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.47</version>
</dependency>
<!-- hutool -->
<dependency>
<groupId>cn.hutool</groupId>
<artifactId>hutool-all</artifactId>
<version>5.7.2</version>
</dependency>
导出Excel的工具类
package com.***.***.***;
import org.apache.poi.hssf.usermodel.*;
import org.apache.poi.ss.usermodel.*;
import org.apache.poi.ss.util.CellRangeAddress;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.List;
public class ExportExcel {
// 导出表的标题
private String title;
// 导出表的列名
private String[] rowName;
// 导出表的数据
private List<Object[]> dataList = new ArrayList<Object[]>();
// 构造函数,传入要导出的数据
public ExportExcel(String title, String[] rowName, List<Object[]> dataList) {
this.dataList = dataList;
this.rowName = rowName;
this.title = title;
}
// 导出数据
public void export(OutputStream out) throws Exception {
try {
//创建一个Excel并设置名称
HSSFWorkbook workbook = new HSSFWorkbook();
HSSFSheet sheet = workbook.createSheet(title);
//生成表格标题行
HSSFRow rowm = sheet.createRow(0);
HSSFCell cellTitle = rowm.createCell(0);
//定义SHEET样式
HSSFCellStyle columnTopStyle = this.getColumnTopStyle(workbook);
HSSFCellStyle style = this.getStyle(workbook);
sheet.addMergedRegion(new CellRangeAddress(0, 1, 0, (rowName.length - 1)));
cellTitle.setCellStyle(columnTopStyle);
cellTitle.setCellValue(title);
//定义所需要的列数
int columnNum = rowName.length;
HSSFRow rowRowName = sheet.createRow(2);
//将列头设置到SHEET的单元格中
for (int n = 0; n < columnNum; n++) {
HSSFCell cellRowName = rowRowName.createCell(n);
cellRowName.setCellType(CellType.STRING);
HSSFRichTextString text = new HSSFRichTextString(rowName[n]);
cellRowName.setCellValue(text);
cellRowName.setCellStyle(style);
}
//将数据设置到SHEET的单元格中
for (int i = 0; i < dataList.size(); i++) {
Object[] obj = dataList.get(i);
HSSFRow row = sheet.createRow(i + 3);
for (int j = 0; j < obj.length; j++) {
HSSFCell cell = null;
if (j == 0) {
cell = row.createCell(j, CellType.NUMERIC);
cell.setCellValue(i + 1);
} else {
cell = row.createCell(j, CellType.STRING);
if (!"".equals(obj[j]) && obj[j] != null) {
cell.setCellValue(obj[j].toString());
} else {
cell.setCellValue(" ");
}
}
cell.setCellStyle(style);
}
}
//让列宽随着导出的列长自动适应
for (int colNum = 0; colNum < columnNum; colNum++) {
int columnWidth = sheet.getColumnWidth(colNum) / 256;
for (int rowNum = 0; rowNum < sheet.getLastRowNum(); rowNum++) {
HSSFRow currentRow;
if (sheet.getRow(rowNum) == null) {
currentRow = sheet.createRow(rowNum);
} else {
currentRow = sheet.getRow(rowNum);
}
if (currentRow.getCell(colNum) != null) {
HSSFCell currentCell = currentRow.getCell(colNum);
if (CellType.STRING.getCode() == currentCell.getCellType().getCode()) {
int length = currentCell.getStringCellValue().getBytes().length;
if (columnWidth < length) {
columnWidth = length;
}
}
}
}
if (colNum == 0) {
sheet.setColumnWidth(colNum, (columnWidth - 2) * 256);
} else {
sheet.setColumnWidth(colNum, (columnWidth + 4) * 256);
}
}
if (workbook != null) {
try {
workbook.write(out);
} catch (Exception e) {
e.printStackTrace();
}
}
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* 表格标题样式
*/
public HSSFCellStyle getColumnTopStyle(HSSFWorkbook workbook) {
// 设置字体
HSSFFont font = workbook.createFont();
// 设置字体大小
font.setFontHeightInPoints((short) 11);
// 设置字体颜色
font.setColor(IndexedColors.WHITE.getIndex());
// 字体加粗
font.setBold(true);
// 设置字体名字
font.setFontName("Courier New");
// 设置样式
HSSFCellStyle style = workbook.createCellStyle();
// 设置标题背景色
style.setFillForegroundColor(IndexedColors.DARK_TEAL.getIndex());
// 设置背景颜色填充样式
style.setFillPattern(FillPatternType.SOLID_FOREGROUND);
// 设置低边框
style.setBorderBottom(BorderStyle.THIN);
// 设置低边框颜色
style.setBottomBorderColor(IndexedColors.ROYAL_BLUE.getIndex());
// 设置右边框
style.setBorderRight(BorderStyle.THIN);
// 设置顶边框
style.setTopBorderColor(IndexedColors.ROYAL_BLUE.getIndex());
// 设置顶边框颜色
style.setTopBorderColor(IndexedColors.ROYAL_BLUE.getIndex());
// 在样式中应用设置的字体
style.setFont(font);
// 设置自动换行
style.setWrapText(false);
// 设置水平对齐的样式为居中对齐;
style.setAlignment(HorizontalAlignment.CENTER);
style.setVerticalAlignment(VerticalAlignment.CENTER);
return style;
}
/**
* 表格数据样式
*/
public HSSFCellStyle getStyle(HSSFWorkbook workbook) {
// 设置字体
HSSFFont font = workbook.createFont();
// 设置字体大小
font.setFontHeightInPoints((short) 10);
// 设置字体名字
font.setFontName("Courier New");
// 设置样式;
HSSFCellStyle style = workbook.createCellStyle();
// 设置底边框;
style.setBorderBottom(BorderStyle.THIN);
// 设置底边框颜色;
style.setBottomBorderColor(IndexedColors.ROYAL_BLUE.getIndex());
// 设置左边框;
style.setBorderLeft(BorderStyle.THIN);
// 设置左边框颜色;
style.setLeftBorderColor(IndexedColors.ROYAL_BLUE.getIndex());
// 设置右边框;
style.setBorderRight(BorderStyle.THIN);
// 设置右边框颜色;
style.setRightBorderColor(IndexedColors.ROYAL_BLUE.getIndex());
// 设置顶边框;
style.setBorderTop(BorderStyle.THIN);
// 设置顶边框颜色;
style.setTopBorderColor(IndexedColors.ROYAL_BLUE.getIndex());
// 在样式用应用设置的字体;
style.setFont(font);
// 设置自动换行;
style.setWrapText(false);
// 设置水平对齐的样式为居中对齐;
style.setAlignment(HorizontalAlignment.CENTER);
// 设置垂直对齐的样式为居中对齐;
style.setVerticalAlignment(VerticalAlignment.CENTER);
return style;
}
}
反射调用get方法获取get方法结果
package com.***.***.***;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
public class ReflectUtils {
/**
* 拼接属性,调用目标Class的get方法
*
* @param c 属性所属实体类
* @param filedName 需要调用的属性名
* @param obj 实体类实例
* @return 返回get方法结果
*/
public static Object invokeGetMethod(Class<?> c, String filedName, Object obj) throws SecurityException, NoSuchMethodException, IllegalArgumentException, IllegalAccessException, InvocationTargetException {
String methodName = "get" + filedName.substring(0, 1).toUpperCase() + filedName.substring(1);
Class<?>[] nullClasses = null;
Method method = c.getMethod(methodName, nullClasses);
Object[] nullObjects = null;
return method.invoke(obj, nullObjects);
}
}
接口层
/**
* @ClassName ********Controller
* @MethodName export******Info
* @Parm [columnTitle, response]
* @Return com***.***.***.ResultResponse
* @Company **********有限公司
* @Dept 研发部
* @Author 曹丞相
* @Date 1145/11/4 19:19
* @Version 1.0
* @Description 导出*******信息接口
*/
@ApiOperation("导出*****信息")
@PostMapping(value = "/export******Info")
@ApiImplicitParams({
@ApiImplicitParam(name = "columnTitle", value = "导出列,示例:[{\"prop\":\"id\",\"label\":\"主键\"},{\"prop\":\"name\",\"label\":\"名称\"},{\"prop\":\"address\",\"label\":\"地址\"}]") })
public ResultResponse export******Info(@RequestParam(value = "columnTitle") String columnTitle, HttpServletResponse response) {
try {
//Excel文件名
String fileName = URLEncoder.encode("******信息数据-" + DateUtils.format(new Date(), "yyyyMMddHHmmss") + ".xls", "UTF-8");
String headStr = "attachment; filename=" + fileName;
response.setContentType("APPLICATION/OCTET-STREAM");
response.setHeader("Content-Disposition", headStr + ";" + "filename*=utf-8''" + fileName);
i******Service.export(response.getOutputStream(), map, columnTitle);
return ResultResponse.success();
} catch (Exception e) {
e.printStackTrace();
return ResultResponse.failure();
}
}
Service实现类
//部分引用的包
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.NumberUtil;
import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson.JSONArray;
import java.util.*;
/**
* @ClassName ******ServiceImpl
* @MethodName export
* @Parm [out 输出流, columnTitle导出列]
* @Return void
* @Company ********有限公司
* @Dept 研发部
* @Author 曹丞相
* @Date 1145/11/4 19:19
* @Version 1.0
* @Description 导出*******信息
*/
@Override
public void export(OutputStream out, String columnTitle) throws IOException {
try {
//获取要导出的Bean数据
List<*****PO> *****POS = list();
//初始化一个空白的List存放处理完后的Excel数据列
List<Object[]> dataList = new ArrayList<Object[]>();
// 把需要展示的列json数据转为List,利用JSONArray中的parseObject方法并指定返回类型来解析json数组字符串
List<Map<String, String>> cols = JSONArray.parseObject(columnTitle, List.class);
// 设置Excel列标题
String[] rowsName = new String[cols.size() + 1];
rowsName[0] = "序号";
for (int i = 0; i < cols.size(); i++) {
rowsName[i + 1] = cols.get(i).get("label").toString();
}
// 设置Excel行数据
for (*****PO *****PO: *****POS) {
Object[] objs = new Object[cols.size() + 1];
objs[0] = "";
for (int j = 0; j < cols.size(); j++) {
//取出属性名
String prop = cols.get(j).get("prop").toString();
//根据属性名反射获取该属性的get方法结果
Object o = ReflectUtils.invokeGetMethod(****PO.class, prop, ****PO);
//非空卫语句
if (o != null && StrUtil.isNotBlank(o.toString())) {
if (prop.equals("createTime")) {
//如果该属性是时间,则进行时间格式处理
objs[j + 1] = DateUtil.format(DateUtil.parse(o.toString()), "yyyy/MM/dd");
} else if (prop.equals("isDelete")) {
//如果该属性是数字,则进行相应的文字替换
objs[j + 1] = NumberUtil.parseInt(o.toString()) == 0 ? "是" : "否";
} else {
objs[j + 1] = o;
}
} else {
objs[j + 1] = "";
}
}
dataList.add(objs);
}
//Excel标题
String title = "****信息数据";
//导出Excel
ExportExcel ex = new ExportExcel(title, rowsName, dataList);
ex.export(out);
} catch (Exception e) {
e.printStackTrace();
} finally {
out.flush();
out.close();
}
}
遇到的问题
在做的时候遇到了无法通过反射调用get方法的问题,忘记后续怎么解决的了,等想起来了再后续补充😅...
原因出在@Accessor(chain = true)注解上;这个注解是lombok里的,方便链式调用set方法。
参考资料
LauSET的CSDN博客:Vue+SpringBoot导出Excel,自定义要导出的表格的列

0 评论