package com.example.demo.exportExcel;
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
import org.apache.poi.ss.usermodel.*;
import org.apache.poi.ss.util.CellRangeAddress;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.lang.reflect.Field;
import java.nio.charset.StandardCharsets;
import java.util.*;
/**
* Copyright © 2018 Shanghai
*
* @Description Excel 导入工具辅助类
* @Author zhaoweijiang
* @Date 2019/3/29 11:11
*
* Excel_2003 支持最大导出65536行
* Excel_2007 支持最大导出1048576行
* 详情查看SpreadsheetVersion.class
*
*/
public class ExportExcelUtil {
//注释换行符
public static final String NEWLINE = "\r\n";
//工作簿
private Workbook wb;
//工作表
private Sheet sheet;
//样式
private CellStyle cellStyle;
//工作簿类型 .xls/.xlsx
private String extension;
/**
* 默认模板工作表名称
*/
private String sheetName = "";
/*
* 默认模板名称字体大小为36
*/
private int typeFontSize = 36;
/*
* 默认模板注释字体大小为11
*/
private int annotationFontSize = 11;
/*
* 默认模板标题字体大小为11
*/
private int titleFontSize = 11;
/*
* 默认模板示例字体大小为11
*/
private int exampleFontSize = 11;
/**
* 对外提供set方法,可修改默认字体大小
*/
public void setSize(int typeFontSize) {
this.typeFontSize = typeFontSize;
}
public void setAnnotationFontSize(int annotationFontSize) {
this.annotationFontSize = annotationFontSize;
}
public void setTitleFontSize(int titleFontSize) {
this.titleFontSize = titleFontSize;
}
public void setSheetName(String sheetName) {
this.sheetName = sheetName;
}
/**
* 构造函数初始化
* ExcelTypeTl 自定义的一个枚举类,该枚举类是工作簿格式 .xls/.xlsx
*/
public ExportExcelUtil(ExcelTypeTl excelTypeTl){
String type = excelTypeTl.getType();
if (".xls".equals(type)){
this.wb = new HSSFWorkbook();
}else if (".xlsx".equals(type)){
this.wb = new XSSFWorkbook();
}else {
throw new IllegalArgumentException("Illegal parameter type");
}
//传递给私有属性,下面的其他方法还需要
this.extension = type;
}
/**
* 创建工作表
* 创建样式
* 注:表名称不可用特殊符号
*/
private void createSheet(){
this.sheet = wb.createSheet(this.sheetName.length() > 0 ? sheetName : "sheet1");
this.cellStyle = wb.createCellStyle();
}
/**
* 说明: excel的字体大小 * 20 = 设置值 例; excel 字体是 13 * 20 = 260
* 你需要设置字体大小为260.导出的excel才会是13的字体大小 ,,,同行高,具体源码里有
*
* row.setHeight( (short)( 20 * Math.round( (this.typeFontSize/0.69) ) )); //设置行高
* 我设置的行高,根据字体大小自己调试的我认为最佳行高
*
* 创建Excel模板名称 / 第一行
* @param titleLenght 标题长度
* @param description 模板名称 同工作簿名称
*/
private void createTlType(int titleLenght , String description){
CellRangeAddress region = new CellRangeAddress(0, 0, 0, titleLenght - 1);
sheet.addMergedRegion(region); //设置第一行合并单元格
CellStyle style = wb.createCellStyle(); //创建单元格样式
Font font = wb.createFont(); //创建字体
font.setFontHeight( (short)(this.typeFontSize * 20) ); //字体大小
style.setFont(font);
style.setVerticalAlignment(VerticalAlignment.CENTER); //单元格内容居中
style.setAlignment(HorizontalAlignment.CENTER); //单元格左右居中
style.setFillForegroundColor(IndexedColors.ROSE.getIndex()); //LIGHT_GREEN色
style.setFillPattern(FillPatternType.SOLID_FOREGROUND); //全部填充
Row row = sheet.createRow(0); //创建第一行
row.setHeight( (short)( 20 * Math.round( (this.typeFontSize/0.69) ) )); //设置行高
Cell cell = row.createCell(0); //创建第一个单元格
cell.setCellValue(description); //给单元格加载数据
cell.setCellStyle(style); //设置单元格样式
}
/**
* 创建Excel模板注释 / 第二行
* @param titleLenght 标题长度
* @param list 注释文本
*/
private void createTlAnnotation(int titleLenght , ArrayList<String> list){
CellRangeAddress region = new CellRangeAddress(1, 1, 0, titleLenght - 1);
sheet.addMergedRegion(region); //设置第二行合并单元格
CellStyle style = wb.createCellStyle();
Font font = wb.createFont();
font.setFontHeight( (short)(this.annotationFontSize * 20) ); //字体大小
style.setFont(font);
style.setAlignment(HorizontalAlignment.LEFT);//文字居左
style.setVerticalAlignment(VerticalAlignment.CENTER); //单元格内容居中
style.setFillForegroundColor(IndexedColors.ORANGE.getIndex()); //ORANGE色
style.setFillPattern(FillPatternType.SOLID_FOREGROUND); //全部填充
style.setWrapText(true);//自动换行
Row row = sheet.createRow(1);
Cell cell = row.createCell(0);
int lenght = list.size(); //数据长度
String data = null;
if (lenght > 0){
row.setHeight((short) ( 20 * Math.round((list.size() * this.annotationFontSize)/0.69))); //行高随着字体的行数和大小自动适配
data = list.get(0);
for (int i = 1 ; i < lenght ; i++){
data += NEWLINE + list.get(i);
}
}else{
row.setHeight((short) ( 20 * Math.round((3 * this.annotationFontSize)/0.69))); // 默认适配3行字体大小行高
}
cell.setCellValue(data);
cell.setCellStyle(style);
}
/**
* 创建Excel模板标题 / 第三行
* @param title 标题数据
*/
private void createTitle(String[] title ){
/*
*前三列样式
*/
//设置字体
Font font1 = wb.createFont();
//加粗
font1.setBold(true);
//字体大小
font1.setFontHeight((short) (this.titleFontSize * 20));
//字体颜色
font1.setColor(IndexedColors.RED.getIndex());
//设置样式
CellStyle style1 = wb.createCellStyle();
//左右居中
style1.setAlignment(HorizontalAlignment.CENTER);
//单元格居中
style1.setVerticalAlignment(VerticalAlignment.CENTER);
style1.setFont(font1);
/*
* 后边的列 样式
*/
//设置字体
Font font = wb.createFont();
//加粗
font.setBold(true);
//字体大小
font.setFontHeight((short) (this.titleFontSize * 20));
//设置样式
CellStyle style = wb.createCellStyle();
//居中
style.setAlignment(HorizontalAlignment.CENTER);
//单元格居中
style.setVerticalAlignment(VerticalAlignment.CENTER);
style.setFont(font);
/*
* 全局设置
* 所有有数据的列单元格为文本格式
*/
CellStyle contextStyle = wb.createCellStyle();
DataFormat format = wb.createDataFormat();
//文本格式
contextStyle.setDataFormat(format.getFormat("@"));
//创建唯一表头行,默认为第一行
Row row = sheet.createRow(2);
//行高
row.setHeight((short) ( 20 * Math.round( this.titleFontSize / 0.69) ));
for (int i = 0; i < title.length; i++) {
//全局列宽
sheet.setColumnWidth(i, 256 * 20 + 185);
//加载全局列样式
sheet.setDefaultColumnStyle(i, contextStyle);
//创建单元格
Cell cell = row.createCell(i);
//单元格值
cell.setCellValue(title[i]);
//单元格加载样式
cell.setCellStyle(i < 3 ? style1 : style);
}
}
/**
* 创建Excel模板示例数据 / 第四行
* @param example 示例数据
*/
private void createExample(String[] example ){
//全局变量
// 该行高未*20,因为源码已经帮我们做了这个动作
sheet.setDefaultRowHeightInPoints((short)( this.exampleFontSize / 0.69 ));
Row row = sheet.createRow(3);
CellStyle style = wb.createCellStyle();
//设置字体
Font font = wb.createFont();
//字体大小
font.setFontHeight((short) (this.exampleFontSize * 20));
style.setFont(font);
style.setDataFormat((short) 49 );
//当前行高
row.setHeight((short) ( 20 * Math.round( this.exampleFontSize /0.69 ) ));
for (int i = 0; i < example.length; i++) {
Cell cell = row.createCell(i);
cell.setCellValue(example[i]);
cell.setCellStyle(style);
}
}
/**
* 创建Excel模板导入数据 / 第五行
* @param listData 数据
*/
private void createData(List<Object> listData) {
for (int i = 0; i < listData.size(); i++) {
//从第四行开始插入数据
Row row = this.sheet.createRow(i + 3);
//获取集合对象
Object o = listData.get(i);
//反射获取字段
Field[] fields = o.getClass().getDeclaredFields();
for (int j = 0; j < fields.length; j++) {
Field field = fields[j];
//暴力访问/取消检查机制
field.setAccessible(true);
String data = null;
try {
data = (String)field.get(o);
} catch (IllegalAccessException e) {
e.printStackTrace();
}
Cell cell = row.createCell(j);
cell.setCellValue(data);
this.cellStyle.setDataFormat((short) 49); //文本格式
cell.setCellStyle(cellStyle);
}
}
}
/**
* 导出excel模板
* @param response 响应
* @param bookName 工作簿名称
* @param annotations 注释
* @param title 标题
* @param example 示例
* @throws IOException
*/
public void exportFileTemplate(HttpServletResponse response , String bookName , ArrayList<String> annotations,
String[] title ,String[] example ) throws IOException {
response.setContentType("application/force-download");
response.setHeader("Content-Disposition", "attachment;fileName=" +
new String(bookName.getBytes(StandardCharsets.UTF_8), "ISO8859-1") + extension);
if (title == null || title.length == 0 || title.length != example.length){
throw new IllegalArgumentException("the title&example of Unequal length");
}
//1,创建表
createSheet();
//2,创建第一行模板名称
createTlType(title.length , bookName);
//3,创建第二行模版注释
createTlAnnotation(title.length , annotations);
//4,创建第三行模板标题
createTitle(title);
//5,创建第四行模板示例数据
createExample(example);
ServletOutputStream out = response.getOutputStream();
wb.write(out);
out.flush();
out.close();
wb.close();
}
/**
* 导出excel文本数据
* @param response 响应
* @param bookName 工作簿名称
* @param annotations 注释
* @param title 标题
* @param arrayList 导出数据 可传空集合
* @throws IOException
*/
public void exportFile(HttpServletResponse response , String bookName , ArrayList<String> annotations,
String[] title ,ArrayList<Object> arrayList) throws IOException {
response.setContentType("application/force-download");
response.setHeader("Content-Disposition", "attachment;fileName=" +
new String(bookName.getBytes(StandardCharsets.UTF_8), "ISO8859-1") + extension);
if (title == null || title.length == 0 ){
throw new IllegalArgumentException("the title & arrayList of Unequal length");
}
if ( extension == ExcelTypeTl.EXCEL_2003.getType() && arrayList.size() >= 65536){
throw new IllegalArgumentException("Invalid row number (" + arrayList.size() + ") outside allowable range (0.." + 65536 + ")");
}else if (extension == ExcelTypeTl.EXCEL_2007.getType() && arrayList.size() >= 1048576 ){
throw new IllegalArgumentException("Invalid row number (" + arrayList.size() + ") outside allowable range (0.." + 1048576 + ")");
}
//1,创建表
createSheet();
//2,创建第一行模板名称
createTlType(title.length , bookName);
//3,创建第二行模版注释
createTlAnnotation(title.length , annotations);
//4,创建第三行模板标题
createTitle(title);
//5,创建第四行模板数据导入
createData(arrayList);
ServletOutputStream out = response.getOutputStream();
wb.write(out);
out.flush();
out.close();
wb.close();
}
}
package com.example.demo.exportExcel;
/**
* Copyright © 2018 Shanghai \
*
* @Description ExcelTemplateConstant excel工作簿 模板名称/标题/标题示例/注释 模板
* @Author zhaoweijiang
* @Date 2019/3/2710:53
*
*/
public final class ExcelTlCon{
//工资单导入模板
public static final String PAYROLL_TL= "工资单导入模板";
// first bill 标题
public static final String[] HFW_FIRST_BILL_TITLE = {"身份证号(必填)", "用户姓名(必填)", "发薪主体(必填)", "操作金额", "资金类型(发薪)", "发薪年份", "发薪月份", "描述"};
// first bill 示例数据
public static final String[] HFW_FIRST_BILL_DATA = {"342422199209272334","小黄鸭", "上海银行", "6666.00", "发薪", "2019", "07", "2019年07月工资"};
//注释1
public static final String ANNOTATION_ONE = "1.所有数据均为文本格式。";
//注释2
public static final String ANNOTATION_TWO = "2.请不要在未有标题的列存放数据。";
//注释3
public static final String ANNOTATION_THREE = "3.请你一定要爱我。";
}
package com.example.demo.exportExcel;
/**
* Copyright © 2018 Shanghai
*
* @Description excel模板类型 / 枚举类
* @Author zhaoweijiang
* @Date 2019/3/2713:44
*/
public enum ExcelTypeTl {
//2003版本后缀名
EXCEL_2003(2003,".xls"),
//2007版本后缀名
EXCEL_2007(2007,".xlsx");
private final int code;
private final String type;
ExcelTypeTl(int code, String type) {
this.code = code;
this.type = type;
}
public String getType() {
return type;
}
public int getCode() {
return code;
}
public static String fromInt(int code) {
if (code < 0){
throw new IllegalArgumentException("Illegal ExcelTypeTl code: " + code);
}
String var0 = null;
ExcelTypeTl[] values = values();
for (ExcelTypeTl excelTypeTl : values){
if (excelTypeTl.code == code){
return excelTypeTl.getType();
}
}
if (var0 == null){
throw new IllegalArgumentException("Illegal ExcelTypeTl code: " + code);
}
return var0;
}
}
这是我严格意义上第一次接触POI,当我第一次去做这个东西的时候,首先去http://POI.apache.org官网看了半天的demo,按照demo教程敲了一遍.第二天写了一个简单的工具类,应该说是第一个版本的,只有3个方法,创建工作簿和表,创建行,和创建行数据.极其的简漏.自己都觉得很不好看.随后对源码进行了多次的查看,写成现在的样子,可能你会觉得很low,没关系,做个借鉴.其中遇到几个小问题源码也没怎么看懂
1, row.setRowStyle(style); 把样式传进去并没有得到修改,问了一位大佬,建议我查看源码,最终没有去看.
2, 当我去设置所创建的列全局单元格为文本格式的时候.如果导出的是空工作簿,你在往里面填数据的时候就是文本格式,但是当你设置好之后,在没有导出工作簿前,往单元格里放数据他会修改单元格文本为常规.也就是说如果你要往单元格放数据的时候,最好放一个数据设置一个样式.提供的代码就是这样玩的.
3,背景颜色可能比较单一,可以参考https://blog.youkuaiyun.com/ruanhao1203/article/details/39553915
4,有疑问可以留言呗!