首先,当准备看这个博客的时候,就默认大家已经会使用spring进行javaweb开发以及使用poi导出excel。相信大家在进行excel导出的时候都会发现,代码冗余较多,如果每导出一个excel文件就写一段代码的话,代码重复量巨大,出了问题也难以定位问题的所在。那么自己封装一个导出excel的工具类就显得十分有意义了。
那么我们可以通过什么方式来构建这个工具类呢?
相信大家在使用spring开发项目的时候都使用过hibernate、mybatis来查询处理数据库中的数据,而这类框架的名称叫做ORM(Object Relational Mapping)框架,即对象关系映射框架。ORM的思想是将数据库中的每一个关系(即表)映射到一个实体类上,用类代表表、对象代表一条条记录、类的属性代表表中的字段。
大家也都知道,数据库通常分为关系型数据库和非关系型数据库,而关系型数据库中数据的存储展示方式与excel表格十分相似,那我们为什么不能模仿ORM来进行excel导出辅助工具类的设计呢?
在生成excel之前我们首先要知道一个excel文件的结构以及一个excel文件通常是什么样的。
首先我们来看一个简单的例子,这是关于学生信息统计的excel表格。
在图中我们可以发现一个excel文件结构是:一个excel文件(A对应的xxx.xls)包含多个sheet(C对应的部分),而一个sheet包含多个单元格(cell)(B对应的部分)。
通常我们将一个sheet分成四个模块:标题、表头、数据和标尾。
但是我们知道,一个excel表格中,只有表头和数据部分是必须出现的,少了任何一个便不能成为一个完整的数据呈现载体。而标题和标尾不能强求,说不定别人一个文件想要,另一个就不想要了,所以表头和数据部分是必须的,而标题和标尾应该可以供用户选择,留出扩展实现的接口。
我们使用自底向上的思路,从cell开始,直到excel文件。
我们知道,在spring-data-jpa中是使用@Entity来标明这个类这是一个实体,需要映射到某张表;而用@Column标明这个属性需要映射到表中的一个字段。那我们是不是也可以通过注解的方式来标注实体的映射信息呢?
我们可以分别用两个注解,一个类注解来表明这个实体类对应一个sheet,一个属性注解来表明这个属性对应一个表头。(由于时间原因这里只实现了后者)
话不多说,直接贴一下代码:
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface ExcelColumn {
/**
* 该字段出现在 excel 表格的顺序
*
* @return
*/
int order();
/**
* 该字段在表头的名称
*
* @return
*/
String description();
/**
* 标题字体大小
*
* @return
*/
short titleFontSize() default (short) 10;
/**
* 标题字体粗细
*
* @return
*/
short titleFontWeight() default HSSFFont.BOLDWEIGHT_NORMAL;
/**
* 标题字体颜色
*
* @return
*/
short titleFontColor() default Font.COLOR_NORMAL;
/**
* 正文字体大小
*
* @return
*/
short contentFontSize() default (short) 10;
/**
* 正文字体粗细
*
* @return
*/
short contentFontWeight() default HSSFFont.BOLDWEIGHT_NORMAL;
/**
* 正文字体颜色
*
* @return
*/
short contentFontColor() default Font.COLOR_NORMAL;
/**
* 是否对这一列上锁
*
* @return
*/
boolean columnLocked() default true;
}
这里除了字体格式、颜色、大小以及是否对该列上锁等基本信息,需要注意的两个属性是order和description,这两个属性不能为空,也是格式构造必不可少的两个部分:
order:order是这个属性对应的权重,越小,该属性对应的列就越靠前,就像最开始学生信息表,order:学号 < 姓名 < 性别 < 住址。
description:description是该属性对应的列的表头,如最开始学生信息表的学号、姓名、性别和住址。
使用方式如下:
class Student{
@ExcelColumn(order = 1, description = "学号")
private String id;
@ExcelColumn(order = 2, description = "姓名")
private String name;
@ExcelColumn(order = 4, description = "住址")
private String address;
@ExcelColumn(order = 3, description = "性别")
private String sex;
// 构造方法和getter、setter方法省略
}
现在单元格的载体已经设计好,可以设计单元格的载体sheet了,其实大家也都熟悉sheet,所以这里直接放上代码:
public class Sheet {
private String sheetName; // sheet的名称
private List<String> orderedTitles; // 排好序的每一列的表头
private List<?> data; // 具体的数据
private Class targetClass; // 承载数据的类,如:Student
private List<Field> orderedFields; // 排好序的属性
private List<HSSFCellStyle> titleStyle; // 表头的格式
private List<HSSFCellStyle> contentStyle; // 正文数据的格式
private HSSFWorkbook hssfWorkbook; // 所属的excel文件
private ExcelProcessor excelProcessor = new StandardExcelProcessor(); // 处理器(这里默认是标准处理器)
private boolean customMode = false; // 是否为自定义模式
// 构造方法和getter、setter方法省略
}
这里将要利用反射机制对属性进行排序,具体代码如下:
private void initExcelAssistBean() {
Field[] fields = targetClass.getDeclaredFields();
orderedFields = new ArrayList<>();
for (Field temp : fields) {
if (temp.getAnnotation(ExcelColumn.class) != null) {
orderedFields.add(temp);
}
}
orderedFields.sort(Comparator.comparingInt(field -> field.getAnnotation(ExcelColumn.class).order()));
orderedTitles = new ArrayList<>();
for (Field temp : orderedFields) {
orderedTitles.add(temp.getAnnotation(ExcelColumn.class).description());
}
//如果开启自定义模式
if (customMode) {
titleStyle = new ArrayList<>();
contentStyle = new ArrayList<>();
HSSFCellStyle currentCellStyle;
Font font;
for (Field temp : orderedFields) {
currentCellStyle = hssfWorkbook.createCellStyle();
font = hssfWorkbook.createFont();
font.setFontHeightInPoints(temp.getAnnotation(ExcelColumn.class).titleFontSize());
font.setBoldweight(temp.getAnnotation(ExcelColumn.class).titleFontWeight());
font.setColor(temp.getAnnotation(ExcelColumn.class).titleFontColor());
currentCellStyle.setLocked(false); // 表头均不能修改
currentCellStyle.setFont(font);
titleStyle.add(currentCellStyle);
currentCellStyle = hssfWorkbook.createCellStyle();
font = hssfWorkbook.createFont();
font.setFontHeightInPoints(temp.getAnnotation(ExcelColumn.class).contentFontSize());
font.setBoldweight(temp.getAnnotation(ExcelColumn.class).contentFontWeight());
font.setColor(temp.getAnnotation(ExcelColumn.class).contentFontColor());
currentCellStyle.setLocked(temp.getAnnotation(ExcelColumn.class).columnLocked());
currentCellStyle.setFont(font);
contentStyle.add(currentCellStyle);
}
}
}
该类的每个构造方法都会调用这个初始化方法,而这个方法主要是对属性进行排序(通过order),以及设置表头和正文各种格式样式。
虽说可以专门抽象出一个类来描述一个excel文件,可转念一想,一个excel文件其实包含的属性比较少,所以就和工厂类抽象成同一个就好了,下面是代码:
public class ExcelWorkBookCreator {
private String excelFileName; // 文件名称
private List<Sheet> sheets; // 文件包含的sheets
private HSSFWorkbook hssfWorkbook; // 文件载体
private final String EXCEL_SHEET_PASSWORD = "123321"; // 文件密码
// 构造方法和getter、setter方法省略
}
在这个类中可以获取ExcelWorkBookCreator,以及一些简单的通用操作:
public class ExcelUtil {
/**
* 获取 excel 文件创造器
*
* @param excelFileName -> excel 文件的名字
* @return
*/
public static ExcelWorkBookCreator getExcelWorkBookCreator(String excelFileName) {
return new ExcelWorkBookCreator(excelFileName);
}
}
大家是否还记着之前说的:通常我们将一个sheet分成四个模块:标题、表头、数据和标尾。而标题和标尾不是必须不可的,而在上面我们也没有给这两个模块留有相应的余地。不光如此,一个封装工具无论怎样设计都难做到满足所有需求,所以我们必须留给自己足够的余地。这个时候就很需要处理器了。这里我们模仿spring中ioc容器的PostProcessor,在绘制表头和正文之前(自定义标题)和之后(自定义标尾以及处理一些特殊数据)让用户进行自定义的处理。
public interface ExcelProcessor {
/**
* 在正式注入数据之前的自定义操作,可以自己设计标题等
*
* @param sheet -> 当前 sheet 信息
* @param currentSheet -> 当前 sheet
* @return 想要正式注入表头及数据的行数
*/
Integer customOperationBeforeInvokeData(Sheet sheet, HSSFSheet currentSheet);
/**
* 在注入完数据后的自定义操作,如:在表格最后落上日期、对某些数据进行修改等
* 可以通过 currentSheet..getLastRowNum() 获取最后一行的行标,从 0 开始
*
* @param sheet -> 当前 sheet 信息
* @param currentSheet -> 当前 sheet
*/
void customOperationAfterInvokeData(Sheet sheet, HSSFSheet currentSheet, int firstRowNum);
}
通过实现这个接口,我们便可以进行一些扩展的操作。
ExcelWorkBookCreator(层级:文件):保存所有sheet,可以导出文件。
Sheet(层次:sheet):保存sheet信息,可以注入数据。
ExcelUtil:进行一些通用操作。
ExcelProcessor:在文件构造前后进行自定义处理。
<dependency>
<groupId>org.apache.poigroupId>
<artifactId>poiartifactId>
<version>3.12version>
dependency>
由于从想到要创建这个工具类到实现只用了一两天的时间,所以有许多设计其实并不是特别合理。而且这个工具类也没有使用过,所以可能会出现很多bug。但这里其实我只是提供一种思路,实现还是自己来的好,毕竟用自己实现的才安心。另外这些代码仅供学习,如果在实际环境中使用出现问题,请自负责任。
**这里是所有内容的代码,仅供学习!真实环境中使用出现问题,这里不负责!**如果嫌麻烦,可以去空间下载。
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface ExcelColumn {
/**
* 该字段出现在 excel 表格的顺序
*
* @return
*/
int order();
/**
* 该字段在表头的名称
*
* @return
*/
String description();
/**
* 标题字体大小
*
* @return
*/
short titleFontSize() default (short) 10;
/**
* 标题字体粗细
*
* @return
*/
short titleFontWeight() default HSSFFont.BOLDWEIGHT_NORMAL;
/**
* 标题字体颜色
*
* @return
*/
short titleFontColor() default Font.COLOR_NORMAL;
/**
* 正文字体大小
*
* @return
*/
short contentFontSize() default (short) 10;
/**
* 正文字体粗细
*
* @return
*/
short contentFontWeight() default HSSFFont.BOLDWEIGHT_NORMAL;
/**
* 正文字体颜色
*
* @return
*/
short contentFontColor() default Font.COLOR_NORMAL;
/**
* 是否对这一列上锁
*
* @return
*/
boolean columnLocked() default true;
}
public class Sheet {
private String sheetName;
private List<String> orderedTitles;
private List<?> data;
private Class targetClass;
private List<Field> orderedFields;
private List<HSSFCellStyle> titleStyle;
private List<HSSFCellStyle> contentStyle;
private HSSFWorkbook hssfWorkbook;
private ExcelProcessor excelProcessor = new StandardExcelProcessor();
private boolean customMode = false;
public Sheet() {
}
public Sheet(HSSFWorkbook hssfWorkbook, String sheetName, List<?> data, Class targetClass) {
this.hssfWorkbook = hssfWorkbook;
this.sheetName = sheetName;
this.data = data;
this.targetClass = targetClass;
initExcelAssistBean();
}
public Sheet(HSSFWorkbook hssfWorkbook, String sheetName, List<?> data, Class targetClass, ExcelProcessor excelProcessor) {
this.hssfWorkbook = hssfWorkbook;
this.sheetName = sheetName;
this.data = data;
this.targetClass = targetClass;
this.excelProcessor = excelProcessor;
initExcelAssistBean();
}
public Sheet(HSSFWorkbook hssfWorkbook, String sheetName, List<?> data, Class targetClass, boolean customMode) {
this.hssfWorkbook = hssfWorkbook;
this.sheetName = sheetName;
this.data = data;
this.targetClass = targetClass;
this.customMode = customMode;
initExcelAssistBean();
}
public Sheet(HSSFWorkbook hssfWorkbook, String sheetName, List<?> data, Class targetClass, ExcelProcessor excelProcessor, boolean customMode) {
this.hssfWorkbook = hssfWorkbook;
this.sheetName = sheetName;
this.data = data;
this.targetClass = targetClass;
this.excelProcessor = excelProcessor;
this.customMode = customMode;
initExcelAssistBean();
}
private void initExcelAssistBean() {
Field[] fields = targetClass.getDeclaredFields();
orderedFields = new ArrayList<>();
for (Field temp : fields) {
if (temp.getAnnotation(ExcelColumn.class) != null) {
orderedFields.add(temp);
}
}
orderedFields.sort(Comparator.comparingInt(field -> field.getAnnotation(ExcelColumn.class).order()));
orderedTitles = new ArrayList<>();
for (Field temp : orderedFields) {
orderedTitles.add(temp.getAnnotation(ExcelColumn.class).description());
}
//如果开启自定义模式
if (customMode) {
titleStyle = new ArrayList<>();
contentStyle = new ArrayList<>();
HSSFCellStyle currentCellStyle;
Font font;
for (Field temp : orderedFields) {
currentCellStyle = hssfWorkbook.createCellStyle();
font = hssfWorkbook.createFont();
font.setFontHeightInPoints(temp.getAnnotation(ExcelColumn.class).titleFontSize());
font.setBoldweight(temp.getAnnotation(ExcelColumn.class).titleFontWeight());
font.setColor(temp.getAnnotation(ExcelColumn.class).titleFontColor());
currentCellStyle.setLocked(false); // 表头均不能修改
currentCellStyle.setFont(font);
titleStyle.add(currentCellStyle);
currentCellStyle = hssfWorkbook.createCellStyle();
font = hssfWorkbook.createFont();
font.setFontHeightInPoints(temp.getAnnotation(ExcelColumn.class).contentFontSize());
font.setBoldweight(temp.getAnnotation(ExcelColumn.class).contentFontWeight());
font.setColor(temp.getAnnotation(ExcelColumn.class).contentFontColor());
currentCellStyle.setLocked(temp.getAnnotation(ExcelColumn.class).columnLocked());
currentCellStyle.setFont(font);
contentStyle.add(currentCellStyle);
}
}
}
public void titleCellStyleInvoke(HSSFRow row) {
HSSFCell titleCell;
for (int titleIndex = 0; titleIndex < orderedTitles.size(); titleIndex++) {
titleCell = row.createCell(titleIndex);
titleCell.setCellStyle(titleStyle.get(titleIndex));
titleCell.setCellValue(orderedTitles.get(titleIndex));
}
}
public void contentCellStyleInvoke(HSSFSheet hssfSheet, int firstRowNum) throws Exception {
HSSFRow currentRow;
for (int rowIndex = firstRowNum + 1; rowIndex < data.size(); rowIndex++) {
currentRow = hssfSheet.createRow(rowIndex);
HSSFCell currentCell;
Object obj = data.get(rowIndex);
for (int cellIndex = 0; cellIndex < orderedFields.size(); cellIndex++) {
currentCell = currentRow.createCell(cellIndex);
currentCell.setCellStyle(contentStyle.get(cellIndex));
if (!orderedFields.get(cellIndex).isAccessible()) {
orderedFields.get(cellIndex).setAccessible(true);
if (orderedFields.get(cellIndex).get(obj) != null) {
currentCell.setCellValue(orderedFields.get(cellIndex).get(obj).toString());
}
orderedFields.get(cellIndex).setAccessible(false);
} else {
if (orderedFields.get(cellIndex).get(obj) != null) {
currentCell.setCellValue(orderedFields.get(cellIndex).get(obj).toString());
}
}
}
}
}
public String getSheetName() {
return sheetName;
}
public void setSheetName(String sheetName) {
this.sheetName = sheetName;
}
public List<String> getOrderedTitles() {
return orderedTitles;
}
public void setOrderedTitles(List<String> orderedTitles) {
this.orderedTitles = orderedTitles;
}
public List<?> getData() {
return data;
}
public void setData(List<?> data) {
this.data = data;
}
public Class getTargetClass() {
return targetClass;
}
public void setTargetClass(Class targetClass) {
this.targetClass = targetClass;
}
public List<Field> getOrderedFields() {
return orderedFields;
}
public void setOrderedFields(List<Field> orderedFields) {
this.orderedFields = orderedFields;
}
public ExcelProcessor getExcelProcessor() {
return excelProcessor;
}
public void setExcelProcessor(ExcelProcessor excelProcessor) {
this.excelProcessor = excelProcessor;
}
public boolean isCustomMode() {
return customMode;
}
public void setCustomMode(boolean customMode) {
this.customMode = customMode;
}
public List<HSSFCellStyle> getTitleStyle() {
return titleStyle;
}
public void setTitleStyle(List<HSSFCellStyle> titleStyle) {
this.titleStyle = titleStyle;
}
public List<HSSFCellStyle> getContentStyle() {
return contentStyle;
}
public void setContentStyle(List<HSSFCellStyle> contentStyle) {
this.contentStyle = contentStyle;
}
public HSSFWorkbook getHssfWorkbook() {
return hssfWorkbook;
}
public void setHssfWorkbook(HSSFWorkbook hssfWorkbook) {
this.hssfWorkbook = hssfWorkbook;
}
}
public interface ExcelProcessor {
/**
* 在正式注入数据之前的自定义操作,可以自己设计标题等
*
* @param sheet -> 当前 sheet 信息
* @param currentSheet -> 当前 sheet
* @return 想要正式注入表头及数据的行数
*/
Integer customOperationBeforeInvokeData(Sheet sheet, HSSFSheet currentSheet);
/**
* 在注入完数据后的自定义操作,如:在表格最后落上日期、对某些数据进行修改等
* 可以通过 currentSheet..getLastRowNum() 获取最后一行的行标,从 0 开始
*
* @param sheet -> 当前 sheet 信息
* @param currentSheet -> 当前 sheet
*/
void customOperationAfterInvokeData(Sheet sheet, HSSFSheet currentSheet, int firstRowNum);
}
public class StandardExcelProcessor implements ExcelProcessor {
@Override
public Integer customOperationBeforeInvokeData(Sheet sheet, HSSFSheet currentSheet) {
return 0;
}
@Override
public void customOperationAfterInvokeData(Sheet sheet, HSSFSheet currentSheet, int firstRowNum) {
ExcelUtil.RowWidthAutoFix(sheet, currentSheet, firstRowNum);
}
}
public class ExcelUtil {
/**
* 获取 excel 文件创造器
*
* @param excelFileName -> excel 文件的名字
* @return
*/
public static ExcelWorkBookCreator getExcelWorkBookCreator(String excelFileName) {
return new ExcelWorkBookCreator(excelFileName);
}
/**
* 列宽自适应,可以在 ExcelProcessor 的实现类的后置处理中使用
*
* @param sheet
* @param currentSheet
* @param firstRowNum
*/
public static void RowWidthAutoFix(Sheet sheet, HSSFSheet currentSheet, int firstRowNum) {
int columnNum = sheet.getOrderedTitles().size();
int columnLength = currentSheet.getLastRowNum() + 1;
System.out.println(columnLength);
int[] columnWidth = new int[columnNum];
for (int index = 0; index < columnNum; index++) {
columnWidth[index] = 0;
}
HSSFRow currentRow;
for (int currentRowNum = firstRowNum; currentRowNum < columnLength; currentRowNum++) {
currentRow = currentSheet.getRow(currentRowNum);
HSSFCell currentCell;
if (currentRow != null) {
for (int currentColumnNum = 0; currentColumnNum < columnNum; currentColumnNum++) {
currentCell = currentRow.getCell(currentColumnNum);
if (currentCell != null && currentCell.getStringCellValue().getBytes().length > columnWidth[currentColumnNum]) {
columnWidth[currentColumnNum] = currentCell.getStringCellValue().getBytes().length;
}
}
}
}
for (int index = 0; index < columnNum; index++) {
currentSheet.setColumnWidth(index, columnWidth[index] * 300);
}
}
}
public class ExcelWorkBookCreator {
private String excelFileName;
private List<Sheet> sheets;
private HSSFWorkbook hssfWorkbook;
private final String EXCEL_SHEET_PASSWORD = "123321";
public ExcelWorkBookCreator(String excelFileName) {
this.excelFileName = excelFileName;
hssfWorkbook = new HSSFWorkbook();
sheets = new ArrayList<>();
}
public void addOneSheet(String sheetName, List<?> data, Class targetClass) {
sheets.add(new Sheet(hssfWorkbook, sheetName, data, targetClass));
}
public void addOneSheet(String sheetName, List<?> data, Class targetClass, boolean customMode) {
sheets.add(new Sheet(hssfWorkbook, sheetName, data, targetClass, customMode));
}
public void addOneSheet(String sheetName, List<?> data, Class targetClass, ExcelProcessor excelProcessor) {
sheets.add(new Sheet(hssfWorkbook, sheetName, data, targetClass, excelProcessor));
}
public void addOneSheet(String sheetName, List<?> data, Class targetClass, ExcelProcessor excelProcessor, boolean customMode) {
sheets.add(new Sheet(hssfWorkbook, sheetName, data, targetClass, excelProcessor, customMode));
}
/**
* 导出 excel
*
* @param response
* @return
* @throws Exception
*/
public void excelExport(HttpServletResponse response) throws Exception {
//设置文件名
response.setContentType("multipart/form-data");
response.setHeader("Content-Disposition", "attachment;fileName=" + URLEncoder.encode((excelFileName + ".xls"), "UTF-8"));
OutputStream os = response.getOutputStream();
//开始注入数据
for (int sheetIndex = 0; sheetIndex < sheets.size(); sheetIndex++) {
Sheet currentSheetMsg = sheets.get(sheetIndex);
HSSFSheet currentSheet = hssfWorkbook.createSheet(currentSheetMsg.getSheetName());
currentSheet.protectSheet(EXCEL_SHEET_PASSWORD);
ExcelProcessor excelProcessor = currentSheetMsg.getExcelProcessor();
int firstRowNum = excelProcessor.customOperationBeforeInvokeData(currentSheetMsg, currentSheet);
if (currentSheetMsg.isCustomMode()) {
invokeDataUnderCustomModel(currentSheetMsg, currentSheet, firstRowNum);
} else {
invokeData(currentSheetMsg, currentSheet, firstRowNum);
}
excelProcessor.customOperationAfterInvokeData(currentSheetMsg, currentSheet, firstRowNum);
}
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
hssfWorkbook.write(outputStream);
outputStream.flush();
hssfWorkbook.close();
outputStream.close();
InputStream inputStream = new ByteArrayInputStream(outputStream.toByteArray());
int b = 0;
byte[] buffer = new byte[512];
while (b != -1) {
b = inputStream.read(buffer);
if (b != -1) {
os.write(buffer, 0, b);
}
}
if (os != null) {
os.close();
os.flush();
}
}
/**
* 不开启自定义文本模式下注入正文
*
* @param currentSheet
* @param hssfSheet
* @param firstRowNum
* @throws Exception
*/
private void invokeData(Sheet currentSheet, HSSFSheet hssfSheet, int firstRowNum) throws Exception {
//设置表头
HSSFRow firstRow = hssfSheet.createRow(firstRowNum);
HSSFCellStyle cellStyle = hssfWorkbook.createCellStyle();
Font titleFont = hssfWorkbook.createFont();
//加粗标题字体
titleFont.setBoldweight(HSSFFont.BOLDWEIGHT_BOLD);
cellStyle.setFont(titleFont);
cellStyle.setLocked(true);
HSSFCell titleCell;
for (int titleIndex = 0; titleIndex < currentSheet.getOrderedTitles().size(); titleIndex++) {
titleCell = firstRow.createCell(titleIndex);
titleCell.setCellValue(currentSheet.getOrderedTitles().get(titleIndex));
titleCell.setCellStyle(cellStyle);
}
//注入数据
List<?> currentData = currentSheet.getData();
List<Field> fields = currentSheet.getOrderedFields();
cellStyle = hssfWorkbook.createCellStyle();
cellStyle.setLocked(true);
HSSFRow currentRow;
for (int rowIndex = 0; rowIndex < currentData.size(); rowIndex++) {
currentRow = hssfSheet.createRow(rowIndex + firstRowNum + 1);
HSSFCell currentCell;
Object obj = currentData.get(rowIndex);
for (int cellIndex = 0; cellIndex < fields.size(); cellIndex++) {
currentCell = currentRow.createCell(cellIndex);
currentCell.setCellStyle(cellStyle);
if (!fields.get(cellIndex).isAccessible()) {
fields.get(cellIndex).setAccessible(true);
if (fields.get(cellIndex).get(obj) != null) {
currentCell.setCellValue(fields.get(cellIndex).get(obj).toString());
}
fields.get(cellIndex).setAccessible(false);
} else {
if (fields.get(cellIndex).get(obj) != null) {
currentCell.setCellValue(fields.get(cellIndex).get(obj).toString());
}
}
}
}
}
/**
* 开启自定义文本模式下注入正文
*
* @param currentSheet
* @param hssfSheet
* @param firstRowNum
* @throws Exception
*/
private void invokeDataUnderCustomModel(Sheet currentSheet, HSSFSheet hssfSheet, int firstRowNum) throws Exception {
//设置表头
HSSFRow firstRow = hssfSheet.createRow(firstRowNum);
currentSheet.titleCellStyleInvoke(firstRow);
//注入数据
currentSheet.contentCellStyleInvoke(hssfSheet, firstRowNum);
}
public String getExcelFileName() {
return excelFileName;
}
public void setExcelFileName(String excelFileName) {
this.excelFileName = excelFileName;
}
public List<Sheet> getSheets() {
return sheets;
}
public void setSheets(List<Sheet> sheets) {
this.sheets = sheets;
}
}
@Controller
@RequestMapping("/test")
public class TestController {
@ResponseBody
@RequestMapping(value = "/getExcel", method = RequestMethod.GET)
public String getExcel(HttpServletResponse response){
try {
List<Student> students = new ArrayList<>();
this.injectData(students);
ExcelWorkBookCreator creator = ExcelUtil.getExcelWorkBookCreator("学生信息汇总");
creator.addOneSheet("学生信息", students, Student.class);
creator.excelExport(response);
return "success";
} catch (Exception e) {
e.printStackTrace();
return "error";
}
}
private void injectData(List<Student> students){
students.add(new Student("1", "张三", "xx1小区", "男"));
students.add(new Student("2", "李四", "xx2小区", "男"));
students.add(new Student("3", "王五", "xx3小区", "女"));
students.add(new Student("4", "小明", "xx4小区", "男"));
students.add(new Student("5", "小红", "xx5小区", "女"));
}
class Student{
@ExcelColumn(order = 1, description = "学号")
private String id;
@ExcelColumn(order = 2, description = "姓名")
private String name;
@ExcelColumn(order = 4, description = "住址")
private String address;
@ExcelColumn(order = 3, description = "性别")
private String sex;
public Student() {
}
public Student(String id, String name, String address, String sex) {
this.id = id;
this.name = name;
this.address = address;
this.sex = sex;
}
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getAddress() {
return address;
}
public void setAddress(String address) {
this.address = address;
}
public String getSex() {
return sex;
}
public void setSex(String sex) {
this.sex = sex;
}
}
}
poi简单封装excel导出的工具类