本文在之前的Excel导入导出1.0版本和Excel导入导出2.0版本基础上进一步改进,更新内容:
1、提供了公共的获取标题数组的方法。
2、提供了公共的获取数据总行数的方法(含标题)。
3、代码优化
package com.soft.util;
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
import org.apache.poi.ss.usermodel.*;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.*;
/**
* Excel导入
*
* Maven依赖
*
* org.apache.poi
* poi
* 4.1.1
*
*
* org.apache.poi
* poi-ooxml
* 4.1.1
*
**/
public class ExcelUtil {
// Excel后缀
public static final String SUFFIX_XLS = ".xls";
public static final String SUFFIX_XLSX = ".xlsx";
// 下载用:默认文件名
private static String fileName_default = "excel_export";
// 下载用:默认sheet名
private static String sheetName_default = "sheet1";
// 标题数组
private static String[] title;
// 数据总行数
private static Integer rowCount;
/**
* 读取Excel文件的数据,可以把数据封装为List类型
*
* 要求:
* 1、excel第一行必须是标题
* 2、excel所有单元格的格式必须是字符
*
* @param suffix excel文件后缀名
* @param inputStream 文件输入流
* @param clazz 类对象
* @return List
* @throws IOException
*/
public static <T> List<T> importExcel(String suffix, InputStream inputStream, Class<T> clazz) throws IOException,
IllegalAccessException, InstantiationException, InvocationTargetException {
// 判断后缀
if(suffix == null || "".equalsIgnoreCase(suffix)){
throw new RuntimeException("不能识别文件类型,支持.xls和.xlsx类型!");
}
// 判断输入流
if(inputStream == null){
throw new RuntimeException("文件解析失败,文件可能是空的!");
}
// 判断映射实体类类型
if(clazz == null){
throw new RuntimeException("对象映射错误!");
}
// Excel对象
Workbook book = null;
// 封装数据集合
List<T> list = null;
// 类对象生成的实例
Object obj = null;
// 2017以前版本
if(SUFFIX_XLS.equalsIgnoreCase(suffix)){
book = new HSSFWorkbook(inputStream);
// 2017以后版本
} else if(SUFFIX_XLSX.equalsIgnoreCase(suffix)){
book = new XSSFWorkbook(inputStream);
} else {
throw new RuntimeException("不能识别文件类型,支持.xls和.xlsx类型!");
}
// 获取工作簿,默认获取第一个工作簿对象
Sheet sheet = book.getSheetAt(0);
// 获取工作簿共有多少行数据
rowCount = sheet.getLastRowNum();
// 遍历数据行,开始封装数据
for(int i = 0; i <= rowCount; i++){
/*
由于要求第一行是标题,所以除了第一行不创建实体类对象以后每一行都创建
这里利用了对象类型是值引用的特性,可以先把对象添加到List中
*/
if(i > 0){
obj = clazz.newInstance();
if(list == null){
list = new ArrayList<T>();
}
list.add((T) obj);
}
// 获取行对象
Row row = sheet.getRow(i);
// 获取总有多少列数据
short lastCellNum = row.getLastCellNum();
// 遍历列
for(int j = 0; j < lastCellNum; j++){
// 单元格对象
Cell cell = row.getCell(j);
// 获取单元格数据
String value = cell.getStringCellValue();
// 第一行:标题
if(i == 0){
// 存放标题
if(title == null){
title = new String[lastCellNum];
}
title[j] = value.toLowerCase();
} else {
// 映射实体类set方法的集合
Map<String, Method> map = loadClass(clazz);
String methodName = "set" + title[j];
Method method = map.get(methodName);
if(method != null){
method.invoke(obj, value);
}
}
}
}
close(book, inputStream, null);
return list;
}
/**
* Excel导出,导出xlsx版本,支持2017以上版本
* 使用默认文件名:excel_export.xlsx
*
* @param list 结果集合,封装实体类
* @param clazz 实体类对象
* @param resp response
* @throws IOException InvocationTargetException IllegalAccessException
*/
public static <T> void exportExcel(List<T> list, Class<T> clazz, HttpServletResponse resp) throws IOException, InvocationTargetException, IllegalAccessException {
exportExcel(null, list, clazz, resp);
}
/**
* Excel导出,导出xlsx版本,支持2017以上版本
* 自定义文件名
*
* @param fileName 文件名
* @param list 结果集合,封装实体类
* @param clazz 实体类对象
* @param resp response
* @throws IOException InvocationTargetException IllegalAccessException
*/
public static <T> void exportExcel(String fileName, List<T> list, Class<T> clazz, HttpServletResponse resp) throws IOException, InvocationTargetException, IllegalAccessException {
// 判断文件名
if(fileName == null || "".equals(fileName)){
fileName = fileName_default;
}
// 创建Excel对象
Workbook book = new XSSFWorkbook();
// 创建工作簿
Sheet sheet = book.createSheet(sheetName_default);
// 获取对象中所有的公共属性
Field[] fields = clazz.getDeclaredFields();
// 行数
int r = 0;
// 遍历数据结果集
for(int i = 0; i < list.size();){
// 创建行对象
Row row = sheet.createRow(r);
// 遍历对象中的属性
for (int j = 0; j < fields.length; j++) {
// 获取属性名
String fieldName = fields[j].getName().toLowerCase();
String value = "";
// 标题
if(r == 0) {
// 标题数组
if (title == null) {
title = new String[fields.length];
}
title[j] = fieldName;
// 标题
value = fieldName;
} else {
// list集合中的单个对象
T t = list.get(i);
// 获取类对象中所有公共的方法
Map<String, Method> map = loadClass(clazz);
Method method = map.get("get" + fieldName);
if(method != null){
value = (String)method.invoke(t);
}
}
// 单元格对象
Cell cell = row.createCell(j);
// 单元格赋值
cell.setCellValue(value);
// 单元格样式
CellStyle cellStyle = book.createCellStyle();
// 四面边框实线
cellStyle.setBorderTop(BorderStyle.THIN);
cellStyle.setBorderRight(BorderStyle.THIN);
cellStyle.setBorderBottom(BorderStyle.THIN);
cellStyle.setBorderLeft(BorderStyle.THIN);
// 设置单元格样式
cell.setCellStyle(cellStyle);
}
// 判断行数,如果行数大于1,读取的数据下标才开始累加
if(r > 0){
i++;
}
// 行累加
r++;
}
// 设置响应头信息
resp.setHeader("content-disposition","attachement;filename=" + fileName + SUFFIX_XLSX);
// 把Excel响应到页面
ServletOutputStream outputStream = resp.getOutputStream();
book.write(resp.getOutputStream());
// 释放资源
close(book, null, outputStream);
}
/**
* 释放资源
* @param book
* @param inputStream
*/
private static void close(Workbook book, InputStream inputStream, OutputStream outputStream) {
try {
if(book != null){
book.close();
}
if(inputStream != null){
inputStream.close();
}
if(outputStream != null){
outputStream.close();
}
} catch (IOException e) {
throw new RuntimeException("资源释放失败!");
}
}
/**
* 解析类对象,返回set方法的Map映射集合
* @param clazz
* @return
*/
private static <T> Map<String, Method> loadClass(Class<T> clazz){
// 判断类对象是否为空
if(clazz == null){
throw new RuntimeException("对象映射错误!");
}
// 存储方法的Map集合
Map<String, Method> map = new HashMap<String, Method>();
// 获取类中所有的方法对象
Method[] methods = clazz.getMethods();
// 遍历
for (Method method : methods) {
String name = method.getName().toLowerCase();
map.put(name, method);
}
return map;
}
/**
* 获取Excel标题数组
* @return
*/
public static String[] getTitle() {
return title;
}
/**
* 获取Excel总数据行数
* @return
*/
public static Integer getRowCount() {
return rowCount;
}
}
更多技术分享请到个人主页查看。