POI用来导出excel是工作当中经常用到的,但是如果每次导出都要自己写,会显得比较麻烦,代码基本上都是重复的。所以最近花了点时间,学习了一下,自己根据注解,基于反射技术,写了一个POI导出excel的工具类。基本能实现一级和二级表头两种情况的导出。
这次写的这个例子,是一个简单的SpringBoot工程,关于SpringBoot不了解的,自行学习下。
补充一下工具类,这个类比下面的更完善:
import util.annotation.ExcelColumn;
import org.apache.poi.hssf.usermodel.HSSFBorderFormatting;
import org.apache.poi.hssf.usermodel.HSSFCell;
import org.apache.poi.hssf.usermodel.HSSFCellStyle;
import org.apache.poi.hssf.usermodel.HSSFFont;
import org.apache.poi.hssf.usermodel.HSSFRichTextString;
import org.apache.poi.hssf.usermodel.HSSFRow;
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
import org.apache.poi.ss.usermodel.*;
import org.apache.poi.ss.util.CellRangeAddress;
import org.apache.poi.ss.util.RegionUtil;
import org.apache.poi.xssf.streaming.SXSSFWorkbook;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.net.URLEncoder;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
/**
* excel导出工具类
*/
@SuppressWarnings("all")
public class ExcelExpUtil {
private Logger log = LoggerFactory.getLogger(ExcelExpUtil.class);
private Class clazz;//导出目标类的Class对象
private int colNum;//总列数
private int startRowIndex;//导出内容开始的行号,不包括表头
private Field[] fields;//所有是属性数组
private String titleName;//标题内容
private String[] headerArr;//要合并的表头数组
private String[] headers;// 列名集合
private Short[] columnWidth ;// 列宽集合
private Integer[] alignList ;// 内文样式位置集合,左对齐,居中或右对齐
private Boolean[] boderList ;// 是否需要边框 集合
private Integer[] fontColorList;// 字体颜色集合
private String[] fontNameList ;// 字体集合
private Short[] fontSizeList;// 字号集合
private Integer[] styleColorList ;// 单元格背景色 集合
private Field[] excelFileds ;//存放有注解的字段 也就是需要导出的字段 无注解字段排除
/**
* 没有合并表头的构造方法
* @param clazz 导出类的CLass对象
* @param titleName 标题名称
* @param colNum 总列数
* @param startRowIndex 导出内容开始的行号,不包括表头
*/
public ExcelExpUtil(Class clazz,String titleName, int colNum, int startRowIndex){
this.clazz=clazz;
this.titleName = titleName;
this.colNum = colNum;
this.startRowIndex = startRowIndex-1;//从0开始的,所以减1
this.fields = clazz.getDeclaredFields();
this.headers = new String[colNum];
this.columnWidth = new Short[colNum];
this.alignList = new Integer[colNum];
this.boderList = new Boolean[colNum];
this.fontColorList = new Integer[colNum];
this.fontNameList = new String[colNum];
this.fontSizeList = new Short[colNum];
this.styleColorList = new Integer[colNum];
this.excelFileds = new Field[colNum];
}
/**
* 有一行合并表头的构造方法
* @param clazz 导出类的CLass对象
* @param titleName 标题名称
* @param colNum 总列数
* @param startRowIndex 导出内容开始的行号,不包括表头
* @param headerArr 要合并的表头数组
*/
public ExcelExpUtil(Class clazz,String titleName, int colNum, int startRowIndex,String[] headerArr){
this(clazz,titleName,colNum,startRowIndex);//调用另一个构造方法
this.headerArr = headerArr;
}
/**
* 导出excel的方法
* @param dataList 导出的业务数据
* @param response 浏览器下载的流
* @param fileName 导出的文件名
* @param ext 导出的文件的扩展名,.xls .xlsx
*/
public void excelExp(List dataList,HttpServletRequest request, HttpServletResponse response, String fileName, String ext){
//根据后缀名得到工作簿对象
Workbook workbook = getWorkBook(ext);
if(workbook != null){
creatSheet(workbook, dataList);//创建sheet页
//下载文件
this.downloadFile(workbook,request,response,fileName,ext);
}else{
log.error("创建工作簿失败");
}
}
//创建sheet
private void creatSheet(Workbook workbook, List dataList) {
if(dataList==null || dataList.size()<=0){
return;
}
Sheet sheet = workbook.createSheet();//sheet对象
Row row =null;//行对象
Cell cell = null;//列对象
ExcelColumn excelColumn = null;
int j=0;//相当于是列号,从0开始的
for(short i = 0; i < fields.length; i++){
Field field = fields[i];//得到属性
//判断属性上面是否有注解:ExcelColumn
if(field.isAnnotationPresent(ExcelColumn.class)){
excelColumn = (ExcelColumn)field.getAnnotation(ExcelColumn.class);//得到注解信息
j = excelColumn.sort()-1;
excelFileds[j] = field;//放入到要导出字段的集合中
headers[j] = excelColumn.title();//把列名放入到列名集合中
columnWidth[j]=excelColumn.width();//把宽度放入到宽度集合中
alignList[j]=excelColumn.alignment().getValue();
boderList[j]=excelColumn.boder();
fontColorList[j]=excelColumn.fontColor().getValue();
fontNameList[j]=excelColumn.fontName();
fontSizeList[j]=excelColumn.fontSize();
styleColorList[j]=excelColumn.styleColor().getValue();
}
}
// 循环设置列宽
int length = columnWidth.length;
for (int i = 0; i < length; i++) {
sheet.setColumnWidth(i, columnWidth[i] * 256);
}
// 产生表格标题行,标题行是第一行
this.createTitle(workbook,sheet,row);
// 合并表头行设置
if(this.headerArr!=null){
this.createHeBinHeader(workbook,sheet,row,cell);
}
//生成二级表头行
this.createHeader(workbook,sheet,row,cell);
// 遍历集合数据,产生数据行
this.setDataToSheet(workbook,sheet,row,cell,dataList);
}
//根据表头数组信息合并行
private void createHeBinHeader(Workbook workbook, Sheet sheet, Row row, Cell cell) {
row = sheet.createRow(1);//第二行是合并表头的行,行号为1
row.setHeightInPoints(30);//设置行高
CellStyle boderStyle = workbook.createCellStyle();//创建一个样式
Font font = workbook.createFont();// 生成一个字体 默认字体微软雅黑
font.setFontName("宋体");
font.setFontHeightInPoints((short)10);// 设置字体大小
font.setBoldweight(Font.BOLDWEIGHT_BOLD);//字体加粗
boderStyle.setFont(font);// 把字体应用到当前的样式
//设置边框
//boderStyle.setFillPattern(CellStyle.SOLID_FOREGROUND);
boderStyle.setBorderBottom(CellStyle.BORDER_THIN);
boderStyle.setBorderLeft(CellStyle.BORDER_THIN);
boderStyle.setBorderRight(CellStyle.BORDER_THIN);
boderStyle.setBorderTop(CellStyle.BORDER_THIN);
//垂直居中
boderStyle.setVerticalAlignment(CellStyle.VERTICAL_CENTER);
boderStyle.setAlignment(CellStyle.ALIGN_CENTER); // 创建一个居中格式
boderStyle.setWrapText(true);// 自动换行
String[] zuoBiaoArr = null;
int colIndex = 0;//列起始行号
for(int i = 0; i dataList) {
Iterator it = dataList.iterator();
while (it.hasNext()) {
row = sheet.createRow(startRowIndex++);//从第几行开始
T t = (T) it.next();
// 利用反射,根据javabean属性的先后顺序,动态调用getXxx()方法得到属性值
for (int i = 0; i < excelFileds.length; i++) {
cell = row.createCell(i);
Field field = excelFileds[i];//获取属性
field.setAccessible(true);//忽略检查,不加这个写入不了数据
//调用方法进行样式设置
this.setCellStyle(workbook, cell, alignList[i], boderList[i],styleColorList[i],
fontColorList[i], fontNameList[i],fontSizeList[i],false);
String fieldName = field.getName();//得到属性名称
//得到属性的get方法名称
String getMethodName = "get" + fieldName.substring(0, 1).toUpperCase() + fieldName.substring(1);
try {
cell.setCellValue(field.get(t)==null?"":field.get(t).toString());
//另外一种手动拼get方法的方式获取值
//得到对应的方法
/*Method getMethod = this.clazz.getMethod(getMethodName, new Class[] {});
//执行方法,得到返回值
Object value = getMethod.invoke(t, new Object[] {});
String textValue = value.toString();
if (textValue != null) {
RichTextString richString = new HSSFRichTextString(textValue);
cell.setCellValue(richString);
}*/
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
//生成表头行
private void createHeader(Workbook workbook, Sheet sheet,Row row,Cell cell) {
row = sheet.createRow(this.startRowIndex-1);//内容开始行的上一行是表头行
for (int i = 0; i < headers.length; i++) {
cell = row.createCell(i);
//调用方法设置样式
this.setCellStyle(workbook, cell, alignList[i], boderList[i],styleColorList[i],
fontColorList[i], fontNameList[i],fontSizeList[i],true);
HSSFRichTextString text = new HSSFRichTextString(headers[i]);//获取该列的值
cell.setCellValue(text);//把值设置到单元格中
}
}
/**
* 创建标题行的方法
* @param workbook
* @param sheet
* @param row
*/
private void createTitle(Workbook workbook,Sheet sheet,Row row){
row = sheet.createRow(0);//标题行
row.setHeightInPoints(60);//设置行高
Cell titleCell = row.createCell(0);//得到标题列
CellStyle cellStyle = workbook.createCellStyle();
// 生成一个字体 默认字体微软雅黑
Font font = workbook.createFont();
// 设置字体大小
font.setFontHeightInPoints((short)12);
// 字体加粗
font.setBoldweight(Font.BOLDWEIGHT_BOLD);
// 把字体应用到当前的样式
cellStyle.setFont(font);
//垂直居中
cellStyle.setVerticalAlignment(CellStyle.VERTICAL_CENTER);
cellStyle.setAlignment(CellStyle.ALIGN_CENTER); // 创建一个居中格式
titleCell.setCellStyle(cellStyle);//设置样式
titleCell.setCellValue(this.titleName);//设置内容
sheet.addMergedRegion(new CellRangeAddress(row.getRowNum(),
row.getRowNum(), row.getRowNum(), this.colNum-1));//设置合并
}
/**
* @Title: 设置单元格样式的方法
* @param workbook 工作簿
* @param cell 要配置的单元格
* @param alignment 单元格内文样式
* @param needBoder 是否需要环绕边框
* @param sytleColor 单元格背景色
* @param fontColor 文字颜色
* @param fontName 字体
* @param fontSize 字号
* @param isBold 表头是否加粗
* @Description: 设置单元格以及字体的整体样式
*/
private void setCellStyle(Workbook workbook, Cell cell, int alignment, Boolean needBoder, int sytleColor,int fontColor,
String fontName,short fontSize,boolean isBold) {
// 生成一个通用样式 默认背景为白色
CellStyle style = workbook.createCellStyle();
style.setFillForegroundColor((short)sytleColor);
// 单元格内容样式
style.setAlignment((short) alignment);
style.setVerticalAlignment(CellStyle.VERTICAL_CENTER);//垂直居中
style.setAlignment(CellStyle.ALIGN_CENTER); // 水平居中
style.setWrapText(true);// 自动换行
// 单元格是否需要边框
if (needBoder) {
style.setFillPattern(CellStyle.SOLID_FOREGROUND);
style.setBorderBottom(CellStyle.BORDER_THIN);
style.setBorderLeft(CellStyle.BORDER_THIN);
style.setBorderRight(CellStyle.BORDER_THIN);
style.setBorderTop(CellStyle.BORDER_THIN);
}
// 生成一个字体 默认字体微软雅黑
Font font = workbook.createFont();
font.setFontName(fontName);
font.setColor((short) fontColor);
// 设置字体大小
font.setFontHeightInPoints(fontSize);
// 字体是否加粗
if (isBold) {
font.setBoldweight(Font.BOLDWEIGHT_BOLD);
}
// 把字体应用到当前的样式
style.setFont(font);
cell.setCellStyle(style);
}
//根据后缀名得到工作簿对象
private Workbook getWorkBook(String ext){
if(".xls".equals(ext)){
return new HSSFWorkbook();
}
if(".xlsx".equals(ext)){
return new SXSSFWorkbook();
}
log.error("扩展名只能为【.xls】或【.xlsx】");
return null;
}
/**
* 文件下载的方法
* @param workbook 工作簿
* @param request 请求
* @param response 响应
* @param filename 文件名称
* @param ext 文件扩展名
*/
private static void downloadFile(Workbook workbook,HttpServletRequest request, HttpServletResponse response,String filename,String ext){
filename = filename+ext;//文件名+扩展名
//调用其他下载方法
downloadFile(workbook,request,response,filename);
}
private static void downloadFile(Workbook workbook,HttpServletRequest request, HttpServletResponse response,String filename){
try {
//从请求头中获取User-Agent判断当前使用的是否是火狐浏览器
String agent = request.getHeader("User-Agent");
//根据不同浏览器进行不同的编码
String realFilename = "";
if (agent.contains("MSIE")) {
// IE浏览器
realFilename = URLEncoder.encode(filename, "utf-8");
realFilename = realFilename.replace("+", " ");
} else if (agent.contains("Firefox")) {
// 火狐浏览器,此处使用java8
realFilename = "=?utf-8?B?" + org.apache.commons.codec.binary.Base64.encodeBase64String(filename.getBytes("utf-8"))+"?=";
} else {
// 其它浏览器
realFilename = URLEncoder.encode(filename, "utf-8");
}
//设置要被下载的文件名
response.setHeader("Content-Disposition","attachment;filename="+realFilename);
response.setContentType("application/octet-stream");
response.setHeader("filename", filename);
workbook.write(response.getOutputStream());
} catch (Exception e) {
e.printStackTrace();
}
}
}
4.0.0
org.example
POI_SpringBoot
1.0-SNAPSHOT
org.springframework.boot
spring-boot-starter-parent
2.0.1.RELEASE
org.springframework.boot
spring-boot-starter-web
org.springframework.boot
spring-boot-starter-test
test
org.springframework.boot
spring-boot-devtools
true
true
org.apache.poi
poi
3.9
org.apache.poi
poi-ooxml
3.9
org.apache.commons
commons-lang3
3.3.2
com.google.collections
google-collections
1.0
org.springframework.boot
spring-boot-maven-plugin
true
package com.poi;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class PoiApplication {
public static void main(String[] args) {
SpringApplication.run(PoiApplication.class,args);
}
}
我这里的配置就只配置了端口号,其他都没进行设置,有需要的可以自己进行设置。
server:
port: 9000
在进行excel导出的时候,我们需要设置一些excel的单元格样式,比如:行高,列宽、字体和字体颜色等等属性。为了能灵活的设置,所以需要先定义一个注解,通过注解来设置每一列的属性。
package com.poi.annotation;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Target(ElementType.FIELD)//表示这个注解只能用到属性
@Retention(RetentionPolicy.RUNTIME)//表示这个注解在运行时会存在,自定义注解一般设置为这个值
public @interface ExcelColumn {
/**
* @Title: title
* @Description: 表头列名 必填
*/
public String title();
/**
* 列的序号,意思就是把添加这个注解的属性要放到excel的第几列,从1开始
* 需要注意的是:这个值必须连续,比如:各个属性的sort必须是:1,3,2,4,6,5(可以乱序)
但是不能出现:1,3,4,6,5(少了2)
*/
public int sort();
/**
* @Title: width
* @Description: 列宽 默认15
*/
public short width() default 15;
public enum Alignment {
LEFT(0x1), CENTER(0x2), RIGHT(0x3);
private int value;
private Alignment(int value) {
this.value = value;
}
public int getValue() {
return value;
}
};
/**
* @Title: alignment
* @Description: 文字样式 默认居中(Alignment.CENTER)
*/
public Alignment alignment() default Alignment.CENTER;
/**
* @Title: boder
* @Description: 单元格是否需要边框 环绕包围 默认true
*/
public boolean boder() default true;
public enum StyleColor {
WHITE(0x9), BLACK(0x8), BLUE(0xc), RED(0xa), YELLOW(0xd);
private int value;
private StyleColor(int value) {
this.value = value;
}
public int getValue() {
return value;
}
};
/**
* @Title: styleColor
* @Description: 单元格背景色 默认白色
*/
public StyleColor styleColor() default StyleColor.WHITE;
public enum FontColor {
BLACK(0x8), BLUE(0xc), RED(0xa), YELLOW(0xd);
private int value;
private FontColor(int value) {
this.value = value;
}
public int getValue() {
return value;
}
};
/**
* @Title: fontColor
* @Description: 文字颜色 默认黑色(FontColor.BLACK) 暂支持 BLACK BLUE RED YELLO
*/
public FontColor fontColor() default FontColor.BLACK;
/**
* @Title: fontSize
* @Description: 字号大小 默认12
*/
public short fontSize() default 12;
/**
* @Title: fontName
* @Description: 字体 默认微软雅黑
*/
public String fontName() default "微软雅黑";
}
工具类中,用到了反射技术来获取类的属性以及注解,所以需要对反射有一定了解。
工具类直接进行excel文件的下载,而且下载不会出现中文乱码的问题,因为里面也做了相应的处理。
package com.poi.util;
import com.poi.annotation.ExcelColumn;
import org.apache.poi.hssf.usermodel.HSSFBorderFormatting;
import org.apache.poi.hssf.usermodel.HSSFRichTextString;
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
import org.apache.poi.ss.usermodel.*;
import org.apache.poi.ss.util.CellRangeAddress;
import org.apache.poi.ss.util.RegionUtil;
import org.apache.poi.xssf.streaming.SXSSFWorkbook;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.net.URLEncoder;
import java.util.ArrayList;
import java.util.Base64;
import java.util.Iterator;
import java.util.List;
/**
* excel导出工具类
*/
@SuppressWarnings("all")
public class ExcelExpUtil {
private Logger log = LoggerFactory.getLogger(ExcelExpUtil.class);//日志记录
private Class clazz;//导出目标类的Class对象
private int colNum;//总列数
private int startRowIndex;//导出内容开始的行号,不包括表头
private Field[] fields;//所有是属性数组
private String titleName;//标题内容
private String[] headerArr;//要合并的表头数组
private String[] headers;// 列名集合
private Short[] columnWidth ;// 列宽集合
private Integer[] alignList ;// 内文样式位置集合,左对齐,居中或右对齐
private Boolean[] boderList ;// 是否需要边框 集合
private Integer[] fontColorList;// 字体颜色集合
private String[] fontNameList ;// 字体集合
private Short[] fontSizeList;// 字号集合
private Integer[] styleColorList ;// 单元格背景色 集合
private Field[] excelFileds ;//存放有注解的字段 也就是需要导出的字段 无注解字段排除
/**
* 没有合并表头的构造方法
* @param clazz 导出类的CLass对象,通过它来反射获取对应的属性和注解
* @param titleName 标题名称
* @param colNum 总列数,在导出之前我们应该已经知道总共的列数了
* @param startRowIndex 导出内容开始的行号,不包括表头
*/
public ExcelExpUtil(Class clazz,String titleName, int colNum, int startRowIndex){
this.clazz=clazz;
this.titleName = titleName;
this.colNum = colNum;
this.startRowIndex = startRowIndex-1;//从0开始的,所以减1
this.fields = clazz.getDeclaredFields();//通过发射获取类的所有属性,包括私有属性
this.headers = new String[colNum];
this.columnWidth = new Short[colNum];
this.alignList = new Integer[colNum];
this.boderList = new Boolean[colNum];
this.fontColorList = new Integer[colNum];
this.fontNameList = new String[colNum];
this.fontSizeList = new Short[colNum];
this.styleColorList = new Integer[colNum];
this.excelFileds = new Field[colNum];
}
/**
* 有一行合并表头的构造方法
* @param clazz 导出类的CLass对象
* @param titleName 标题名称
* @param colNum 总列数
* @param startRowIndex 导出内容开始的行号,不包括表头
* @param headerArr 要合并的表头数组
*/
public ExcelExpUtil(Class clazz,String titleName, int colNum, int startRowIndex,String[] headerArr){
this(clazz,titleName,colNum,startRowIndex);//调用另一个构造方法
this.headerArr = headerArr;
}
/**
* 导出excel的方法
* @param dataList 导出的业务数据
* @param response 浏览器下载的流
* @param fileName 导出的文件名
* @param ext 导出的文件的扩展名,.xls .xlsx
*/
public void excelExp(List dataList,HttpServletRequest request, HttpServletResponse response, String fileName, String ext){
//根据后缀名得到工作簿对象
Workbook workbook = getWorkBook(ext);
if(workbook != null){
creatSheet(workbook, dataList);//创建sheet页
//下载文件
this.downloadFile(workbook,request,response,fileName,ext);
}else{
log.error("创建工作簿失败");
}
}
//创建sheet
private void creatSheet(Workbook workbook, List dataList) {
if(dataList==null || dataList.size()<=0){
return;
}
Sheet sheet = workbook.createSheet();//sheet对象
Row row =null;//行对象
Cell cell = null;//列对象
ExcelColumn excelColumn = null;
int j=0;//相当于是列号,从0开始的
for(short i = 0; i < fields.length; i++){//遍历属性的集合,得到有注解的属性的集合
Field field = fields[i];//得到属性
//判断属性上面是否有注解:ExcelColumn
if(field.isAnnotationPresent(ExcelColumn.class)){
excelColumn = (ExcelColumn)field.getAnnotation(ExcelColumn.class);//通过属性获取指定的注解信息
j = excelColumn.sort()-1;//属性上注解的列号是从1开始的,其实poi中的列号是从0开始的,所以这里减1
excelFileds[j] = field;//放入到要导出字段的集合中
headers[j] = excelColumn.title();//把列名放入到列名集合中
columnWidth[j]=excelColumn.width();//把宽度放入到宽度集合中
alignList[j]=excelColumn.alignment().getValue();
boderList[j]=excelColumn.boder();
fontColorList[j]=excelColumn.fontColor().getValue();
fontNameList[j]=excelColumn.fontName();
fontSizeList[j]=excelColumn.fontSize();
styleColorList[j]=excelColumn.styleColor().getValue();
}
}
// 循环设置列宽
int length = columnWidth.length;
for (int i = 0; i < length; i++) {
sheet.setColumnWidth(i, columnWidth[i] * 256);
}
// 产生表格标题行,标题行是第一行
this.createTitle(workbook,sheet,row);
// 合并表头行设置
if(this.headerArr!=null){
this.createHeBinHeader(workbook,sheet,row,cell);
}
//生成表头行,用的header中的数据
this.createHeader(workbook,sheet,row,cell);
// 遍历集合数据,产生数据行
this.setDataToSheet(workbook,sheet,row,cell,dataList);
}
//根据表头数组信息合并行
private void createHeBinHeader(Workbook workbook, Sheet sheet, Row row, Cell cell) {
row = sheet.createRow(1);//第二行是合并表头的行,行号为1
row.setHeightInPoints(25);//设置行高
CellStyle boderStyle = workbook.createCellStyle();//创建一个样式
Font font = workbook.createFont();// 生成一个字体 默认字体微软雅黑
font.setFontHeightInPoints((short)20);// 设置字体大小
font.setBoldweight(Font.BOLDWEIGHT_BOLD);//字体加粗
boderStyle.setFont(font);// 把字体应用到当前的样式
//设置边框
//boderStyle.setFillPattern(CellStyle.SOLID_FOREGROUND);
/*boderStyle.setBorderBottom(CellStyle.BORDER_THIN);
boderStyle.setBorderLeft(CellStyle.BORDER_THIN);
boderStyle.setBorderRight(CellStyle.BORDER_THIN);
boderStyle.setBorderTop(CellStyle.BORDER_THIN);*/
//垂直居中
boderStyle.setVerticalAlignment(CellStyle.VERTICAL_CENTER);
boderStyle.setAlignment(CellStyle.ALIGN_CENTER); // 创建一个居中格式
String[] zuoBiaoArr = null;
int colIndex = 0;//列起始行号
for(int i = 0; i dataList) {
Iterator it = dataList.iterator();
while (it.hasNext()) {
row = sheet.createRow(startRowIndex++);//从第几行开始
T t = (T) it.next();
// 利用反射,根据javabean属性的先后顺序,动态调用getXxx()方法得到属性值
for (int i = 0; i < excelFileds.length; i++) {
cell = row.createCell(i);
Field field = excelFileds[i];//获取属性
field.setAccessible(true);//忽略检查,不加这个写入不了数据
//调用方法进行样式设置
this.setCellStyle(workbook, cell, alignList[i], boderList[i],styleColorList[i],
fontColorList[i], fontNameList[i],fontSizeList[i],false);
String fieldName = field.getName();//得到属性名称
//得到属性的get方法名称
String getMethodName = "get" + fieldName.substring(0, 1).toUpperCase() + fieldName.substring(1);
try {
cell.setCellValue(field.get(t).toString());
//另外一种手动拼get方法的方式获取值
//得到对应的方法
/*Method getMethod = this.clazz.getMethod(getMethodName, new Class[] {});
//执行方法,得到返回值
Object value = getMethod.invoke(t, new Object[] {});
String textValue = value.toString();
if (textValue != null) {
RichTextString richString = new HSSFRichTextString(textValue);
cell.setCellValue(richString);
}*/
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
//生成表头行
private void createHeader(Workbook workbook, Sheet sheet,Row row,Cell cell) {
row = sheet.createRow(this.startRowIndex-1);//内容开始行的上一行是表头行
for (int i = 0; i < headers.length; i++) {
cell = row.createCell(i);
//调用方法设置样式
this.setCellStyle(workbook, cell, alignList[i], boderList[i],styleColorList[i], fontColorList[i], fontNameList[i],fontSizeList[i],true);
HSSFRichTextString text = new HSSFRichTextString(headers[i]);//获取该列的值
cell.setCellValue(text);//把值设置到单元格中
}
}
/**
* 创建标题行的方法
* @param workbook
* @param sheet
* @param row
*/
private void createTitle(Workbook workbook,Sheet sheet,Row row){
row = sheet.createRow(0);//标题行
row.setHeightInPoints(50);//设置行高
Cell titleCell = row.createCell(0);//得到标题列
CellStyle cellStyle = workbook.createCellStyle();
// 生成一个字体 默认字体微软雅黑
Font font = workbook.createFont();
// 设置字体大小
font.setFontHeightInPoints((short)30);
// 字体加粗
font.setBoldweight(Font.BOLDWEIGHT_BOLD);
// 把字体应用到当前的样式
cellStyle.setFont(font);
//垂直居中
cellStyle.setVerticalAlignment(CellStyle.VERTICAL_CENTER);
cellStyle.setAlignment(CellStyle.ALIGN_CENTER); // 创建一个居中格式
titleCell.setCellStyle(cellStyle);//设置样式
titleCell.setCellValue(this.titleName);//设置内容
sheet.addMergedRegion(new CellRangeAddress(row.getRowNum(),
row.getRowNum(), row.getRowNum(), this.colNum-1));//设置合并
}
/**
* @Title: 设置单元格样式的方法
* @param workbook 工作簿
* @param cell 要配置的单元格
* @param alignment 单元格内文样式
* @param needBoder 是否需要环绕边框
* @param sytleColor 单元格背景色
* @param fontColor 文字颜色
* @param fontName 字体
* @param fontSize 字号
* @param isBold 表头是否加粗
* @Description: 设置单元格以及字体的整体样式
*/
private void setCellStyle(Workbook workbook, Cell cell, int alignment, Boolean needBoder, int sytleColor,int fontColor,
String fontName,short fontSize,boolean isBold) {
// 生成一个通用样式 默认背景为白色
CellStyle style = workbook.createCellStyle();
style.setFillForegroundColor((short)sytleColor);
// 单元格内容样式
style.setAlignment((short) alignment);
// 单元格是否需要边框
if (needBoder) {
style.setFillPattern(CellStyle.SOLID_FOREGROUND);
style.setBorderBottom(CellStyle.BORDER_THIN);
style.setBorderLeft(CellStyle.BORDER_THIN);
style.setBorderRight(CellStyle.BORDER_THIN);
style.setBorderTop(CellStyle.BORDER_THIN);
}
// 生成一个字体 默认字体微软雅黑
Font font = workbook.createFont();
font.setFontName(fontName);
font.setColor((short) fontColor);
// 设置字体大小
font.setFontHeightInPoints(fontSize);
// 字体是否加粗
if (isBold) {
font.setBoldweight(Font.BOLDWEIGHT_BOLD);
}
// 把字体应用到当前的样式
style.setFont(font);
cell.setCellStyle(style);
}
//根据后缀名得到工作簿对象
private Workbook getWorkBook(String ext){
if(".xls".equals(ext)){
return new HSSFWorkbook();
}
if(".xlsx".equals(ext)){
return new SXSSFWorkbook();
}
log.error("扩展名只能为【.xls】或【.xlsx】");
return null;
}
/**
* 文件下载的方法
* @param workbook 工作簿
* @param request 请求
* @param response 响应
* @param filename 文件名称
* @param ext 文件扩展名
*/
private void downloadFile(Workbook workbook,HttpServletRequest request, HttpServletResponse response,String filename,String ext){
filename = filename+ext;//文件名+扩展名
//调用其他下载方法
downloadFile(workbook,request,response,filename);
}
private void downloadFile(Workbook workbook,HttpServletRequest request, HttpServletResponse response,String filename){
try {
//从请求头中获取User-Agent判断当前使用的是否是火狐浏览器
String agent = request.getHeader("User-Agent");
//根据不同浏览器进行不同的编码
String realFilename = "";
if (agent.contains("MSIE")) {
// IE浏览器
realFilename = URLEncoder.encode(filename, "utf-8");
realFilename = realFilename.replace("+", " ");
} else if (agent.contains("Firefox")) {
// 火狐浏览器,此处使用java8
realFilename = "=?utf-8?B?" + Base64.getEncoder().encodeToString(filename.getBytes("utf-8")) + "?=";
} else {
// 其它浏览器
realFilename = URLEncoder.encode(filename, "utf-8");
}
//设置要被下载的文件名
response.setHeader("Content-Disposition","attachment;filename="+realFilename);
response.setContentType("application/octet-stream");
response.setHeader("filename", filename);
workbook.write(response.getOutputStream());
} catch (Exception e) {
e.printStackTrace();
}
}
}
package com.poi.pojo;
import com.poi.annotation.ExcelColumn;
import java.util.Date;
public class User {
//如果这个属性需要导出,那么就在上面添加注解信息
@ExcelColumn(title = "姓名",width = 20,alignment = ExcelColumn.Alignment.CENTER,sort=2)
private String name;
@ExcelColumn(title = "用户ID",width = 10,alignment = ExcelColumn.Alignment.LEFT,styleColor = ExcelColumn.StyleColor.RED,sort=1)
private String id;
@ExcelColumn(title = "年龄",width = 10,alignment = ExcelColumn.Alignment.CENTER,sort=4)
private int age;
//@ExcelColumn(title = "出生日期",width = 20,alignment = ExcelColumn.Alignment.LEFT,sort=4)
private Date birthday;
@ExcelColumn(title = "家庭住址",width = 50,alignment = ExcelColumn.Alignment.LEFT,fontColor = ExcelColumn.FontColor.BLUE,sort=5)
private String address;
@ExcelColumn(title = "身高",width = 10,alignment = ExcelColumn.Alignment.CENTER,sort=3)
private double high;
public User() {
}
public User(String id, String name, int age, Date birthday, String address, double high) {
this.id = id;
this.name = name;
this.age = age;
this.birthday = birthday;
this.address = address;
this.high = high;
}
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 int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public Date getBirthday() {
return birthday;
}
public void setBirthday(Date birthday) {
this.birthday = birthday;
}
public String getAddress() {
return address;
}
public void setAddress(String address) {
this.address = address;
}
public double getHigh() {
return high;
}
public void setHigh(double high) {
this.high = high;
}
}
package com.poi.controller;
import com.poi.pojo.User;
import com.poi.util.ExcelExpUtil;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
@Controller
@RequestMapping("/excel")
public class UserExcelController {
@RequestMapping("/userList")
public void expUserList(HttpServletRequest request,HttpServletResponse response){
//查询业务数据,实际工程中应该是从数据库中查询的
List userList = this.getDataList();
//调用工具类方法进行导出
new ExcelExpUtil(User.class,"用户列表",5,3)
.excelExp(userList,request,response,"用户列表",".xlsx");
}
private List getDataList() {
List userList = new ArrayList<>();
User user1 = new User("1001","老庞",38,new Date(System.currentTimeMillis()-1000*60*60*24*365),"湖南省长沙市岳麓区岳麓书院1",180.5);
User user2 = new User("1002","老王",38,new Date(System.currentTimeMillis()-1000*60*60*24),"湖南省长沙市岳麓区岳麓书院2",170.5);
User user3 = new User("1003","老李",38,new Date(System.currentTimeMillis()-1000*60*60*24*365*2),"湖南省长沙市岳麓区岳麓书院3",160.5);
User user4 = new User("1004","老周",38,new Date(System.currentTimeMillis()-1000*60*60*24*365*10),"湖南省长沙市岳麓区岳麓书院4",190.5);
User user5 = new User("1005","老赵",38,new Date(System.currentTimeMillis()-1000*60*60*24*365*20),"湖南省长沙市岳麓区岳麓书院5",150.5);
userList.add(user1);
userList.add(user2);
userList.add(user3);
userList.add(user4);
userList.add(user5);
return userList;
}
}
启动工程,访问:http://127.0.0.1:9000/excel/userList就可以进行excel文件的下载了,下载打开后的效果如下:
package com.poi.pojo;
import com.poi.annotation.ExcelColumn;
public class Dog {
@ExcelColumn(title = "宠物ID",sort = 2,width = 10)
private int id;
@ExcelColumn(title = "宠物名称",sort = 1,width = 20)
private String name;
@ExcelColumn(title = "宠物的颜色",sort = 3,width = 20)
private String color;
@ExcelColumn(title = "宠物主人ID",sort = 5,width = 10)
private String userId;
@ExcelColumn(title = "宠物喜欢吃的食物",sort = 4,width = 30)
private String eat;
@ExcelColumn(title = "宠物主人名称",sort = 6,width = 20)
private String userName;
public Dog(int id, String name, String color,String eat, String userId, String userName) {
this.id = id;
this.name = name;
this.color = color;
this.eat = eat;
this.userId = userId;
this.userName = userName;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getColor() {
return color;
}
public void setColor(String color) {
this.color = color;
}
public String getEat() {
return eat;
}
public void setEat(String eat) {
this.eat = eat;
}
public String getUserId() {
return userId;
}
public void setUserId(String userId) {
this.userId = userId;
}
public String getUserName() {
return userName;
}
public void setUserName(String userName) {
this.userName = userName;
}
}
package com.poi.controller;
import com.poi.pojo.Dog;
import com.poi.util.ExcelExpUtil;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.ArrayList;
import java.util.List;
@Controller
@RequestMapping("/excel")
public class DogController {
@RequestMapping("/dogList")
public void excelExport(HttpServletRequest request, HttpServletResponse response){
//构造合并的表头行信息
String[] headerArr = new String[3];
headerArr[0] = "宠物信息1#1,1,0,1";
headerArr[1] = "宠物信息2#1,1,2,3";
headerArr[2] = "主人信息#1,1,4,5";
List dogList = new ArrayList<>();
Dog dog1 = new Dog(1,"小坏猫咪","五颜六色的好好看","就是喜欢吃死老鼠","1001","老庞");
Dog dog2 = new Dog(1,"小乖兔兔","纯白纯白的好漂亮","就是喜欢吃胡萝卜","1001","老庞");
dogList.add(dog1);
dogList.add(dog2);
//这里调用的是可以合并表头的构造方法
new ExcelExpUtil(Dog.class,"宠物列表",6,4,headerArr)
.excelExp(dogList,request,response,"宠物列表",".xlsx");
}
}
运行工程,请求:http://127.0.0.1:9000/excel/dogList,效果如下: