这两天实现了将对账单中的数据导入excel表中的功能,具体需求如下:
首先需要复制一份公共的对账单excel模板,然后往新复制的excel模板文件中从第四行开始(因为前面三行是表头信息,规定的格式,不能修改)写入具体的数据。
先导入需要的jar包:
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi-ooxml</artifactId>
<version>3.9</version>
</dependency>
这里,复制excel文件和往excel表中写入数据,我分别封装在了两个方法中,直接上代码:
/**
* @Title: ExcelUtils.java
* @date 2019年3月18日
* @version V1.0
*/
package demo;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.Date;
import java.util.List;
import org.apache.log4j.Logger;
import org.apache.poi.hssf.usermodel.HSSFRow;
import org.apache.poi.hssf.usermodel.HSSFSheet;
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
import org.apache.poi.poifs.filesystem.POIFSFileSystem;
/**
* @ClassName: ExcelUtils
* @Description: TODO(这里用一句话描述这个类的作用)
* @author hqq
* @date 2019年3月18日
*
*/
public class ExcelUtils {
private static final Logger logger = Logger.getLogger(TimerTaskServiceImpl.class);
/**
* 利用java反射,将java实体类中的数据写入到excel表格中
* @param excelUrl 要写入数据的excel表格的绝对路径
* @param dateList 要写入excel表格的数据集
* @param classType 封装数据的实体类类型
* @param startRow 从excel表格的第 startRow行开始写入数据。假如是从第三行开始写入数据,那么startRow=2
* @param total 写入实体类中的前 total 个字段的数据,因为一个实体类可能有很多字段,但是只有部分字段是需要使用的,并且,实体类中的字段顺序应保持与excel表中每个指定单元格的位置一致,否则会造成写入的数据混乱或失败
*/
public static void appendDateToExcel(String excelUrl, List<?> dateList, Class<?> classType,
int startRow, int total) throws Exception {
FileInputStream fs = null;
FileOutputStream out = null;
HSSFWorkbook wb = null;
try {
Field[] fields = classType.getDeclaredFields();// 得到对象中的字段
fs = new FileInputStream(excelUrl); // 获取head.xls
POIFSFileSystem ps = new POIFSFileSystem(fs); // 使用POI提供的方法得到excel的信息
wb = new HSSFWorkbook(ps);
HSSFSheet sheet = wb.getSheetAt(0); // 获取到工作表,因为一个excel可能有多个工作表
out = new FileOutputStream(excelUrl); // 向head.xls中写数据
// 利用反射获取对象中的所有字段
Field field = null;
String fieldName = null;
String getMethodName = null;
Method getMethod = null;
HSSFRow row = null;
String type = null;
Object obj = null;
Object o = null;
int num=0;
// 遍历所有的对象
for (int i = 0, k = startRow; i < dateList.size(); i++, k++) {
o = dateList.get(i);
// 从指定行开始写入,如果是第3行开始写,则k=2(excel中的行默认从0开始)
row = sheet.createRow((short) (k));
//因为我的excel表中每一行的第一个单元格都是序号,此处可按需要修改
row.createCell(0).setCellValue(++num);
// 一个实体类中可能有很多字段,但是只有部分字段才是我们需要的,将需要的字段放在实体类中的最前面,并设置读取位置
for (int j = 0; j < total; j++) {
field = fields[j];
fieldName = field.getName();
getMethodName = "get" + fieldName.substring(0, 1).toUpperCase() + fieldName.substring(1);
getMethod = classType.getMethod(getMethodName);
obj = getMethod.invoke(o);// 调用对象的getXXX方法
// 这个字段是空值,就取消写入
if (obj == null) {
continue;
}
// 获取属性类型
type = field.getGenericType().toString();
switch (type) {
case "class java.lang.String":
row.createCell(j+1).setCellValue((String) obj);
break;
case "class java.lang.Integer":
row.createCell(j+1).setCellValue((Integer) obj);
break;
case "class java.lang.Double":
row.createCell(j+1).setCellValue((Double) obj);
break;
case "class java.lang.Boolean":
row.createCell(j+1).setCellValue((Boolean) obj);
break;
case "class java.util.Date"://日期类型的数据直接转换成字符串格式写入,否则读到excel表后可能无法识别
row.createCell(j+1).setCellValue(DateUtil.format((Date) obj));
break;
default:
row.createCell(j+1).setCellValue((String) obj);
break;
}
}
}
} catch (Exception e) {
logger.info("往excel表中写入数据异常:" + e.getMessage());
throw e;
} finally {
try {
if (out != null) {
out.flush();
}
if (wb != null) {
wb.write(out);
}
if (out != null) {
out.close();
}
} catch (Exception e) {
logger.info("往excel表格写入数据异常:"+e.getMessage());
}
}
}
/**
* 复制excel表格,该excel表格的格式应该是.xls
* @param modelExcel 模板excel文件的路径
* @param newExcel 新复制的excel文件需要保存的路径
* @param newName 新复制的excel文件的文件名
*/
public static void copyExcel(String modelExcel, String newExcel,String newName) {
HSSFWorkbook wb = null;
FileInputStream fis = null;
FileOutputStream fos = null;
try {
File file=new File(newExcel);
if(!file.exists()){
file.mkdirs();
}
fis = new FileInputStream(modelExcel);
fos = new FileOutputStream(newExcel+"/"+newName);
wb = new HSSFWorkbook(fis);
wb.write(fos);
} catch (Exception e) {
logger.info("复制excel表格异常1:" + e.getMessage());
} finally {
try {
if (fis != null) {
fis.close();
}
if (fos != null) {
fos.close();
}
} catch (IOException e) {
logger.info("复制excel表格异常2:" + e.getMessage());
}
}
}
}
此处节选部分调用该工具类的代码:
@Override
public void genOrderStatementExcel(List<OrderStatementInfo> list) {
try {
//模板文件的绝对路径
String modelExcel = "D:/model.xls";
String fileName="newfile.xls";
//复制模板
ExcelUtils.copyExcel(modelExcel, "D:/bill/",fileName);
//新文件的路径
fileName="D:/bill/"+fileName;
//往文件中写数据
ExcelUtils.appendDateToExcel(fileName, list, OrderStatementInfo.class, 3, 38);
//此处隐藏核心业务
} catch (Exception e) {
}
}
粘上部分实体类的信息,注意实体类的字段顺序应该与excel表中的单元格列顺序保持一致,否则反射写入时会写错:
截取部分写入成功之后的excel表信息:
至此,功能实现!