ExcelUtil通用工具类
呼延辰龙
2023-12-01
import java.io.File;
import java.io.BufferedInputStream;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.text.DecimalFormat;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Date;
import java.util.Iterator;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import javax.swing.JOptionPane;
import org.apache.poi.hssf.usermodel.HSSFCell;
import org.apache.poi.hssf.usermodel.HSSFCellStyle;
import org.apache.poi.hssf.usermodel.HSSFClientAnchor;
import org.apache.poi.hssf.usermodel.HSSFComment;
import org.apache.poi.hssf.usermodel.HSSFFont;
import org.apache.poi.hssf.usermodel.HSSFPatriarch;
import org.apache.poi.hssf.usermodel.HSSFRichTextString;
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.hssf.util.HSSFColor;
import java.io.InputStream;
import java.util.HashMap;
import java.util.Map;
import org.apache.poi.POIXMLDocumentPart;
import org.apache.poi.hssf.usermodel.HSSFPicture;
import org.apache.poi.hssf.usermodel.HSSFPictureData;
import org.apache.poi.hssf.usermodel.HSSFShape;
import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.PictureData;
import org.apache.poi.ss.usermodel.Sheet;
import org.apache.poi.ss.usermodel.Workbook;
import org.apache.poi.ss.usermodel.WorkbookFactory;
import org.apache.poi.xssf.usermodel.XSSFCell;
import org.apache.poi.xssf.usermodel.XSSFClientAnchor;
import org.apache.poi.xssf.usermodel.XSSFDrawing;
import org.apache.poi.xssf.usermodel.XSSFPicture;
import org.apache.poi.xssf.usermodel.XSSFRow;
import org.apache.poi.xssf.usermodel.XSSFShape;
import org.apache.poi.xssf.usermodel.XSSFSheet;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import org.openxmlformats.schemas.drawingml.x2006.spreadsheetDrawing.CTMarker;
public class ExcelUtil<T> {
private Workbook workbook = null;
private Sheet sheet = null;
private String[] columnArray = null;
private List<String[]> rowList = new ArrayList<String[]>();
private String fileName = "";
private String fileDeskDir = "";
/**
* 文件后缀名
*/
private String fileExt = "";
public ExcelUtil() {
}
/**
*
* @param fileDeskDir
* 保存图片相对路径
* @param file
* Excel文档文件l
*/
public ExcelUtil(String fileDeskDir, String filePath) {
this.fileDeskDir = fileDeskDir;
File file = new File(filePath);
fileName = file.getName();
fileExt = fileName.substring(fileName.lastIndexOf(".") + 1);
try {
InputStream inputStream = new FileInputStream(file);
// 根据后缀判断excel 2003 or 2007+
if (fileExt.equals("xls")) {
workbook = (HSSFWorkbook) WorkbookFactory.create(inputStream);
} else {
workbook = new XSSFWorkbook(inputStream);
}
inputStream.close();
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* 获取所有文字数据,如果有图片,自动保存图片并封装图片路径到rowList集合
*
* @return 文字数据(包括图片路径)的集合
*/
public List<String[]> getTextAndImg() {
List<String[]> rowList = getText();
// 如果有图片,自动保存图片并封装图片路径到rowList集合
List<String> imgPaths = getAndSaveExcelImg();
if (imgPaths != null && imgPaths.size() > 0) {
for (int i = 0; i < rowList.size(); i++) {
for (int j = 0; j < rowList.get(i).length; j++) {
for (String imgPath : imgPaths) {
// 获取图片的行索引
int imgRowIndex = Integer.parseInt(imgPath.split("_")[1]);
// 获取图片的列索引
int imgColIndex = Integer
.parseInt(imgPath.substring(imgPath.lastIndexOf("_") + 1, imgPath.lastIndexOf(".")));
// 如果文字的行、列索引==图片的行、列索引
if (i == imgRowIndex && j == imgColIndex) {
rowList.get(i)[imgColIndex] = imgPath;
}
}
}
}
}
return rowList;
}
/**
* 获取excel中 图片,得到图片位置,并保存到D:/ExcelImg,以文档名为文件夹,
* 以图片位置索引命名,例如:Img0_1_0.png表示该图片位于第一个sheet的第2行第1列 支持03 07 多sheet
*
* @param excelPath
* Excel文档的路径
* @return 图片的相对路径集合
*/
public List<String> getAndSaveExcelImg() {
if (workbook != null) {
int sheetNumbers = workbook.getNumberOfSheets();
List<Map<String, PictureData>> sheetList = new ArrayList<Map<String, PictureData>>();
for (int i = 0; i < sheetNumbers; i++) {
sheet = workbook.getSheetAt(i);
// map等待存储excel图片
Map<String, PictureData> sheetIndexPicMap;
// 判断用07还是03的方法获取图片
if (fileExt.equals("xls")) {
sheetIndexPicMap = getSheetPictrues03(i, (HSSFSheet) sheet, (HSSFWorkbook) workbook);
} else {
sheetIndexPicMap = getSheetPictrues07(i, (XSSFSheet) sheet, (XSSFWorkbook) workbook);
}
// 将当前sheet图片map存入list
if (sheetIndexPicMap != null && sheetIndexPicMap.size() > 0) {
sheetList.add(sheetIndexPicMap);
}
}
if (sheetList != null && sheetList.size() > 0) {
return saveImgs(fileName, sheetList);
}
}
return null;
}
/**
* 获取Excel2003图片
*
* @param sheetNum
* 当前sheet编号
* @param sheet
* 当前sheet对象
* @param workbook
* 工作簿对象
* @return Map key:图片单元格索引(0_1_1)String,value:图片流PictureData
* @throws IOException
*/
private Map<String, PictureData> getSheetPictrues03(int sheetNum, HSSFSheet sheet, HSSFWorkbook workbook) {
Map<String, PictureData> sheetIndexPicMap = new HashMap<String, PictureData>();
List<HSSFPictureData> pictures = workbook.getAllPictures();
if (pictures.size() != 0) {
for (HSSFShape shape : sheet.getDrawingPatriarch().getChildren()) {
HSSFClientAnchor anchor = (HSSFClientAnchor) shape.getAnchor();
if (shape instanceof HSSFPicture) {
HSSFPicture pic = (HSSFPicture) shape;
int pictureIndex = pic.getPictureIndex() - 1;
HSSFPictureData picData = pictures.get(pictureIndex);
String picIndex = String.valueOf(sheetNum) + "_" + String.valueOf(anchor.getRow1()) + "_"
+ String.valueOf(anchor.getCol1());
sheetIndexPicMap.put(picIndex, picData);
}
}
return sheetIndexPicMap;
} else {
return null;
}
}
/**
* 获取Excel2007图片
*
* @param sheetNum
* 当前sheet编号
* @param sheet
* 当前sheet对象
* @param workbook
* 工作簿对象
* @return Map key:图片单元格索引(0_1_1)String,value:图片流PictureData
*/
private Map<String, PictureData> getSheetPictrues07(int sheetNum, XSSFSheet sheet, XSSFWorkbook workbook) {
Map<String, PictureData> sheetIndexPicMap = new HashMap<String, PictureData>();
for (POIXMLDocumentPart dr : sheet.getRelations()) {
if (dr instanceof XSSFDrawing) {
XSSFDrawing drawing = (XSSFDrawing) dr;
List<XSSFShape> shapes = drawing.getShapes();
for (XSSFShape shape : shapes) {
XSSFPicture pic = (XSSFPicture) shape;
XSSFClientAnchor anchor = pic.getPreferredSize();
CTMarker ctMarker = anchor.getFrom();
String picIndex = String.valueOf(sheetNum) + "_" + ctMarker.getRow() + "_" + ctMarker.getCol();
sheetIndexPicMap.put(picIndex, pic.getPictureData());
}
}
}
return sheetIndexPicMap;
}
/**
* 保存图片到硬盘,并返回图片相对路径集合
*
* @param fileName
* @param sheetList
* @return
*/
private List<String> saveImgs(String fileName, List<Map<String, PictureData>> sheetList) {
List<String> relativePaths = new ArrayList<String>();
String dirName = fileName.substring(0, fileName.lastIndexOf("."));
String fileDir = fileDeskDir + "/" + dirName;
File file = new File(fileDir);
if (!file.exists() && !file.isDirectory()) {
file.mkdirs();
}
if (sheetList != null && sheetList.size() > 0) {
for (Map<String, PictureData> map : sheetList) {
Object key[] = map.keySet().toArray();
for (int i = 0; i < map.size(); i++) {
// 获取图片流
PictureData pic = map.get(key[i]);
// 获取图片索引
String picName = key[i].toString();
// 获取图片格式
String ext = pic.suggestFileExtension();
String picPath = fileDir + "/Img" + picName + "." + ext;
byte[] data = pic.getData();
try {
FileOutputStream out = new FileOutputStream(picPath);
System.out.println("已将图片保存到:" + picPath);
out.write(data);
out.close();
} catch (IOException e) {
e.printStackTrace();
}
relativePaths.add(dirName + "/Img" + picName + "." + ext);
}
}
}
return relativePaths;
}
/**
* 根据后缀名判断是03还是07版,调用相应方法获取文档文字
*
* @return List<String[]>即:行集合<该行每一个单元格的值组成的数组>
*/
public List<String[]> getText() {
if (workbook != null) {
if (fileExt.equals("xlsx")) {
return getSheetText07(0, (XSSFWorkbook) workbook);
} else if (fileExt.equals("xls")) {
return getSheetText03(0, (HSSFWorkbook) workbook);
} else {
System.out.println("该文件不是标准的Excel文件");
}
}
return null;
}
/**
* 获取o3版文字内容
*
* @param sheetIndex
* @param workbook
* @return
*/
public List<String[]> getSheetText03(int sheetIndex, HSSFWorkbook workbook) {
/* 读EXCEL文字内容 */
HSSFSheet hssfSheet = (HSSFSheet) workbook.getSheetAt(sheetIndex);
int colCount = hssfSheet.getRow(0).getPhysicalNumberOfCells();
for (int rowNum = 0; rowNum < hssfSheet.getPhysicalNumberOfRows(); rowNum++) {
HSSFRow hssfRow = hssfSheet.getRow(rowNum);
if (hssfRow != null) {
columnArray = new String[colCount];
for (int colNum = 0; colNum < colCount; colNum++) {
columnArray[colNum] = getValue(hssfRow.getCell(colNum));
}
}
rowList.add(columnArray);
}
return rowList;
}
/**
* 获取o7+版文字内容
*
* @param sheetIndex
* @param workbook
* @return
*/
private List<String[]> getSheetText07(int sheetIndex, XSSFWorkbook workbook) {
/* 读EXCEL文字内容 */
XSSFSheet xssfSheet = (XSSFSheet) workbook.getSheetAt(sheetIndex);
int colCount = xssfSheet.getRow(0).getPhysicalNumberOfCells();
for (int rowNum = 0; rowNum < xssfSheet.getPhysicalNumberOfRows(); rowNum++) {
XSSFRow xssfRow = xssfSheet.getRow(rowNum);
if (xssfRow != null) {
columnArray = new String[colCount];
for (int colNum = 0; colNum < colCount; colNum++) {
columnArray[colNum] = getValue(xssfRow.getCell(colNum));
}
}
rowList.add(columnArray);
}
return rowList;
}
/**
* 获取单元格的值以字符串返回;03,07通用
*
* @param xssfRow
* @return
*/
private String getValue(Cell cell) {
String value = null;
if (cell != null) {
switch (cell.getCellType()) {
case XSSFCell.CELL_TYPE_BLANK:
value = "";
break;
case XSSFCell.CELL_TYPE_BOOLEAN:
value = String.valueOf(cell.getBooleanCellValue());
break;
case XSSFCell.CELL_TYPE_NUMERIC:
value = new DecimalFormat("#").format(cell.getNumericCellValue());
break;
case XSSFCell.CELL_TYPE_FORMULA:
value = cell.getCellFormula();
break;
default:
value = String.valueOf(cell.getStringCellValue());
break;
}
}
return value;
}
/**
* 这是一个通用的方法,利用了JAVA的反射机制,可以将放置在JAVA集合中并且符号一定条件的数据以EXCEL 的形式输出到指定IO设备上
*
* @param title
* 表格标题名
* @param headers
* 表格属性列名数组
* @param dataset
* 需要显示的数据集合,集合中一定要放置符合javabean风格的类的对象。此方法支持的
* javabean属性的数据类型有基本数据类型及String,Date,byte[](图片数据)
* @param out
* 与输出设备关联的流对象,可以将EXCEL文档导出到本地文件或者网络中
* @param pattern
* 如果有时间数据,设定输出格式。默认为"yyy-MM-dd"
*/
@SuppressWarnings("unchecked")
public void exportExcel(String title, String[] headers, Collection<T> dataset, OutputStream out, String pattern) {
// 声明一个工作薄
HSSFWorkbook workbook = new HSSFWorkbook();
// 生成一个表格
HSSFSheet sheet = workbook.createSheet(title);
// 设置表格默认列宽度为15个字节
sheet.setDefaultColumnWidth((short) 20);
// 生成一个样式
HSSFCellStyle style = workbook.createCellStyle();
// 设置样式
style.setAlignment(HSSFCellStyle.ALIGN_CENTER);
// 生成一个字体
HSSFFont font = workbook.createFont();
font.setFontHeightInPoints((short) 12);
font.setBoldweight(HSSFFont.BOLDWEIGHT_BOLD);
// 把字体应用到当前的样式
style.setFont(font);
// 生成并设置另一个样式
HSSFCellStyle style2 = workbook.createCellStyle();
style2.setAlignment(HSSFCellStyle.ALIGN_CENTER);
style2.setVerticalAlignment(HSSFCellStyle.VERTICAL_CENTER);
// 生成另一个字体
HSSFFont font2 = workbook.createFont();
font2.setFontHeightInPoints((short) 11);
font2.setColor(HSSFColor.BLACK.index);
// 把字体应用到当前的样式
style2.setFont(font2);
// 声明一个画图的顶级管理器
HSSFPatriarch patriarch = sheet.createDrawingPatriarch();
// 产生表格标题行
HSSFRow row = sheet.createRow(0);
for (short i = 0; i < headers.length; i++) {
HSSFCell cell = row.createCell(i);
cell.setCellStyle(style);
HSSFRichTextString text = new HSSFRichTextString(headers[i]);
cell.setCellValue(text);
}
HSSFFont font3 = workbook.createFont();
// 遍历集合数据,产生数据行
Iterator<T> it = dataset.iterator();
int index = 0;
while (it.hasNext()) {
index++;
row = sheet.createRow(index);
T t = (T) it.next();
// 利用反射,根据javabean属性的先后顺序,动态调用getXxx()方法得到属性值
Field[] fields = t.getClass().getDeclaredFields();
for (short i = 0; i < fields.length; i++) {
HSSFCell cell = row.createCell(i);
cell.setCellStyle(style2);
Field field = fields[i];
String fieldName = field.getName();
String getMethodName = "get" + fieldName.substring(0, 1).toUpperCase() + fieldName.substring(1);
try {
Class tCls = t.getClass();
Method getMethod = tCls.getMethod(getMethodName, new Class[] {});
Object value = getMethod.invoke(t, new Object[] {});
// 判断值的类型后进行强制类型转换
String textValue = null;
if (value instanceof Boolean) {
boolean bValue = (Boolean) value;
textValue = "男";
if (!bValue) {
textValue = "女";
}
} else if (value instanceof Date) {
Date date = (Date) value;
SimpleDateFormat sdf = new SimpleDateFormat(pattern);
textValue = sdf.format(date);
} else if (value instanceof byte[]) {
// 有图片时,设置行高为60px;
row.setHeightInPoints(60);
// 设置图片所在列宽度为80px,注意这里单位的一个换算
sheet.setColumnWidth(i, (short) (35.7 * 80));
// sheet.autoSizeColumn(i);
byte[] bsValue = (byte[]) value;
HSSFClientAnchor anchor = new HSSFClientAnchor(0, 0, 1023, 255, (short) 6, index, (short) 6,
index);
anchor.setAnchorType(2);
patriarch.createPicture(anchor, workbook.addPicture(bsValue, HSSFWorkbook.PICTURE_TYPE_JPEG));
} else {
// 其它数据类型都当作字符串简单处理
textValue = value == null ? "" : value.toString();
}
// 如果不是图片数据,就利用正则表达式判断textValue是否全部由数字组成
if (textValue != null) {
Pattern p = Pattern.compile("^//d+(//.//d+)?$");
Matcher matcher = p.matcher(textValue);
if (matcher.matches()) {
// 是数字当作double处理
cell.setCellValue(Double.parseDouble(textValue));
} else {
HSSFRichTextString richString = new HSSFRichTextString(textValue);
richString.applyFont(font3);
cell.setCellValue(richString);
}
}
} catch (Exception e) {
e.printStackTrace();
} finally {
// 清理资源
}
}
}
try {
workbook.write(out);
} catch (IOException e) {
e.printStackTrace();
}
}
}