java操作excel文件通用工具類
阿新 • • 發佈:2018-11-06
1.自定義註解類
package cn.com.test.annotation; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; /** * 自定義註解 * @author: Rodge * @time: 2017年12月26日 下午8:32:10 * @version: V1.0.0 */ @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.FIELD) public @interface CellField { /** * 檔案列名 */ public String name() default ""; }
2.excel工具類
package cn.com.javatest.utils; import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.io.PushbackInputStream; import java.lang.reflect.Field; import java.lang.reflect.Method; import java.math.BigDecimal; import java.net.URLEncoder; import java.text.SimpleDateFormat; import java.util.ArrayList; import java.util.Date; import java.util.HashMap; import java.util.Iterator; import java.util.List; import java.util.Map; import javax.servlet.http.HttpServletResponse; import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.time.DateFormatUtils; import org.apache.commons.lang3.time.DateUtils; import org.apache.poi.hssf.usermodel.HSSFWorkbook; import org.apache.poi.openxml4j.opc.OPCPackage; import org.apache.poi.poifs.filesystem.FileMagic; import org.apache.poi.ss.usermodel.Cell; import org.apache.poi.ss.usermodel.Row; import org.apache.poi.ss.usermodel.Sheet; import org.apache.poi.ss.usermodel.Workbook; import org.apache.poi.xssf.usermodel.XSSFWorkbook; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.util.ReflectionUtils; import cn.com.javatest.annotation.CellField; /** * Excel工具類 * * @author: Rodge * @time: 2017年12月26日 下午8:54:10 * @version: V1.0.0 */ public final class ExcelUtils { /** 日誌物件 **/ private static final Logger LOGGER = LoggerFactory.getLogger(ExcelUtils.class); /** 私有無參構造方法 **/ private ExcelUtils() { } /** * 生成excel2007文件 * * @param filePath 檔案儲存路徑 ,例如:D:/excel/test.xlsx * @param beans 實體物件 */ public static <T> void createExcel(String filePath, List<T> beans) { String fileName = filePath.substring(filePath.lastIndexOf('/') + 1); Workbook wb = createWorkbook(beans, fileName); File file = createFile(filePath); try (OutputStream os = new FileOutputStream(file)) { wb.write(os); } catch (IOException e) { LOGGER.error("生成excel2007檔案失敗", e); } } /** * 匯出excel2007檔案 * * @param response 響應物件 * @param beans 實體物件集合 */ public static <T> void exportExcel(HttpServletResponse response, List<T> beans) { // 以當前時間作為檔名 String fileName = new SimpleDateFormat("yyyyMMddHHmmss").format(new Date()); // 建立Workbook物件 Workbook wb = createWorkbook(beans, fileName); // 匯出excel try (OutputStream os = response.getOutputStream()) { response.setContentType("application/octet-stream;charset=UTF-8"); response.setHeader("Access-Control-Allow-Origin", "*"); response.setHeader("Access-Control-Expose-Headers", "*"); response.setHeader("content-Type", "application/vnd.ms-excel"); response.setHeader("Content-Disposition", "attachment;filename=" + URLEncoder.encode(fileName, "UTF-8") + ".xlsx"); wb.write(os); } catch (IOException e) { LOGGER.error("匯出excel2007檔案失敗", e); } } /** * 匯出excel2007檔案 * * @param response 響應物件 * @param beans 實體物件集合 * @param fileName 檔名稱 ,如:測試名稱 */ public static <T> void exportExcel(HttpServletResponse response, List<T> beans, String fileName) { // 建立Workbook物件 Workbook wb = createWorkbook(beans, fileName); // 匯出excel try (OutputStream os = response.getOutputStream()) { response.setContentType("application/octet-stream;charset=UTF-8"); response.setHeader("Access-Control-Allow-Origin", "*"); response.setHeader("Access-Control-Expose-Headers", "*"); response.setHeader("content-Type", "application/vnd.ms-excel"); response.setHeader("Content-Disposition", "attachment;filename=" + URLEncoder.encode(fileName, "UTF-8") + ".xlsx"); wb.write(os); } catch (IOException e) { LOGGER.error("匯出excel2007檔案失敗", e); } } /** * 匯出excel2007模板 * * @param response 響應物件 * @param Class<T> 類型別 */ public static <T> void exportExcelTemplate(HttpServletResponse response, Class<T> clazz) { // 以當前時間作為檔名 String fileName = new SimpleDateFormat("yyyyMMddHHmmss").format(new Date()); exportExcelTemplate(response, clazz, fileName); } /** * 匯出excel2007模板 * * @param response 響應物件 * @param Class<T> 類型別 * @param fileName 檔名稱 */ public static <T> void exportExcelTemplate(HttpServletResponse response, Class<T> clazz, String fileName) { // 1.建立2007版工作簿 Workbook wb = new XSSFWorkbook(); // 2.建立工作表 Sheet sheet = wb.createSheet(fileName); // 3.獲取實體類標有@CellField註解的Field物件 List<Field> fields = new ArrayList<Field>(); Field[] declaredFields = clazz.getDeclaredFields(); for (Field field : declaredFields) { CellField anno = field.getAnnotation(CellField.class); if (anno != null) { fields.add(field); } } // 4.設定列寬 for (int i = 0; i < fields.size(); i++) { sheet.setColumnWidth((short) i, (short) (20.7 * 150)); } // 5.寫入標題 Row row = sheet.createRow(0); writeTitles(fields, row); // 6.匯出excel模板 try (OutputStream os = response.getOutputStream()) { response.setContentType("application/octet-stream;charset=UTF-8"); response.setHeader("Access-Control-Allow-Origin", "*"); response.setHeader("Access-Control-Expose-Headers", "*"); response.setHeader("content-Type", "application/vnd.ms-excel"); response.setHeader("Content-Disposition", "attachment;filename=" + URLEncoder.encode(fileName, "UTF-8") + ".xlsx"); wb.write(os); } catch (IOException e) { LOGGER.error("匯出excel2007模板失敗", e); } finally { if (wb != null) { try { wb.close(); } catch (IOException e) { e.printStackTrace(); } } } } /** * 解析Excel文件,轉成物件集合返回 * * @param filePath 檔案存放路徑,例如:D:/excel/test.xlsx * @param clazz 泛型類型別 * @return List<T> 物件集合 */ public static <T> List<T> parseExcel(String filePath, Class<T> clazz) { List<T> list = new ArrayList<>(); InputStream input = null; try { input = new FileInputStream(new File(filePath)); if (input != null && !input.markSupported()) { input = new PushbackInputStream(input, 8); } Workbook wb = getWorkbook(input); if (wb != null) { list = getBeanList(wb, clazz); } } catch (Exception e) { LOGGER.error("解析檔案失敗", e); } finally { if (input != null) { try { input.close(); } catch (IOException e) { LOGGER.error("關閉流失敗", e); } } } return list; } /** * 刪除該目錄下所有檔案 * @param filePath 檔案目錄路徑,如:d:/test/ * @return boolean */ public static boolean deleteFiles(String filePath) { File file = new File(filePath); if (file.exists()) { File[] files = file.listFiles(); if (files != null && files.length > 0) { for (File f : files) { if (f.isFile() && f.delete()) { LOGGER.info("刪除" + f.getName() + "檔案成功"); } } return true; } } return false; } /** * 刪除指定檔案 * @param filePath 檔案目錄路徑,如:d:/test/ * @param fileName 檔名稱,如:test.xlsx * @return boolean */ public static boolean deleteFile(String filePath, String fileName) { File file = new File(filePath); if (file.exists()) { File[] files = file.listFiles(); if (files != null && files.length > 0) { for (File f : files) { if (f.isFile() && f.getName().equals(fileName)) { return f.delete(); } } } } return false; } /** * 獲取Workbook物件 * * @param input 輸入流 * @return Workbook */ private static Workbook getWorkbook(InputStream input) { try { if (POIFSFileSystem.hasPOIFSHeader(input)) { return new HSSFWorkbook(input); // 得到2003工作簿 } else { try (OPCPackage op = OPCPackage.open(input)) { return new XSSFWorkbook(op); // 得到2007工作簿 } catch (Exception e) { LOGGER.error("獲取Workbook物件失敗", e); } } } catch (IOException e) { LOGGER.error("獲取Workbook物件失敗", e); } return null; } /** * 通過泛型轉換為物件集合 * * @param wb 工作簿物件 * @param clazz 實體物件類型別 * @param <T> 泛型型別 * @return <T> 泛型實體物件 */ private static <T> List<T> getBeanList(Workbook wb, Class<T> clazz) { List<T> list = new ArrayList<T>(); // 註解名稱與欄位屬性的對應關係 Map<String, Field> annoMap = getFields(clazz); // 列所引與標題名稱對應關係 Map<Integer, String> titleMap = new HashMap<Integer, String>(); Sheet sheet = wb.getSheetAt(0); // 獲取第一張工作表 Iterator<Row> rows = sheet.iterator(); // 利用迭代器,取出每一個行 int index = 0; while (rows.hasNext()) { Row row = rows.next(); // 每一行 Iterator<Cell> cells = row.iterator(); // 利用迭代器,取出每一個格 if (index == 0) { // 獲取第一行標題 while (cells.hasNext()) { Cell cell = cells.next(); // 每一格 titleMap.put(cell.getColumnIndex(), cell.getStringCellValue().trim()); } } else { // 建立實體物件,把值設定進去 if (!annoMap.isEmpty() && !titleMap.isEmpty()) { list.add(buildBean(annoMap, titleMap, clazz, cells)); } } index++; } return list; } /** * 註解名稱與欄位屬性的對應關係 * * @param clazz 實體物件類型別 * @return Map<String,Field> */ private static <T> Map<String, Field> getFields(Class<T> clazz) { Map<String, Field> annoMap = new HashMap<String, Field>(); Field[] fileds = clazz.getDeclaredFields(); for (Field filed : fileds) { CellField cellField = filed.getAnnotation(CellField.class); if (cellField != null && StringUtils.isNotBlank(cellField.name())) { annoMap.put(cellField.name(), filed); } } return annoMap; } /** * 建立實體,設定值 * * @param annoMap 註解名稱與欄位屬性的對應的Map * @param titleMap excel列所引與標題名稱對應的Map * @param clazz 實體物件類型別 * @param cells 每一行的所有格子 * @return List<T> */ private static <T> T buildBean(Map<String, Field> annoMap, Map<Integer, String> titleMap, Class<T> clazz, Iterator<Cell> cells) { T t = null; try { t = clazz.newInstance(); while (cells.hasNext()) { Cell cell = cells.next(); // 每一格 String title = titleMap.get(cell.getColumnIndex()); if (annoMap.containsKey(title)) { Field field = annoMap.get(title); Class<?> valType = field.getType(); Object value = getType(cell.getStringCellValue(), valType); String fieldName = field.getName(); String methodName = "set" + fieldName.substring(0, 1).toUpperCase() + fieldName.substring(1); Method method = ReflectionUtils.findMethod(clazz, methodName, valType); if (method != null) { ReflectionUtils.invokeMethod(method, t, value); } } } } catch (Exception e) { LOGGER.error("建立泛型實體物件失敗", e); } return t; } /** * 轉換成實體屬性對應的型別 * * @param value 每一格的數值 * @param valType 實體屬性型別 * @return Object 轉換為對應型別以obj返回 */ private static <T> Object getType(String value, Class<T> valType) { try { if (valType == String.class) { return String.valueOf(value); } else if (valType == Date.class) { SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); // 預設格式 return sdf.parse(value); } else if (valType == Double.class) { return Double.parseDouble(value); }else if (valType == BigDecimal.class) { return new BigDecimal(value); } else if (valType == Integer.class) { return Integer.parseInt(value); } else if (valType == Long.class) { return Long.parseLong(value); } else if (valType == Boolean.class) { return Boolean.parseBoolean(value); } } catch (Exception e) { LOGGER.error("型別轉換異常", e); } return value; } /** * 建立Workbook物件 * * @param beans 實體集合物件 * @param fileName 檔名 * @return Workbook */ private static <T> Workbook createWorkbook(List<T> beans, String fileName) { // 1.建立2007版工作簿 Workbook wb = new XSSFWorkbook(); // 2.建立工作表 Sheet sheet = wb.createSheet(fileName); // 3.獲取實體類標有@CellField註解的Field物件 List<Field> fields = getFields(beans); // 4.設定列寬 for (int i = 0; i < fields.size(); i++) { sheet.setColumnWidth((short) i, (short) (20.7 * 150)); } // 5.寫入標題 Row row = sheet.createRow(0); writeTitles(fields, row); // 6.寫入內容 writeContents(beans, fields, sheet); return wb; } /** * 建立檔案物件 * * @param filePath 儲存路徑 * @return File */ private static File createFile(String filePath) { File file = null; try { // 建立檔案目錄 file = new File(filePath.substring(0, filePath.lastIndexOf('/'))); if (!file.exists()) { file.mkdirs(); } // 建立檔案路徑 file = new File(filePath); if (!file.exists() && file.createNewFile()) { LOGGER.info("建立檔案物件成功"); } } catch (IOException e) { LOGGER.error("建立檔案物件失敗", e); } return file; } /** * 寫入標題 * * @param fields Field物件集合 * @param row 行物件 */ private static void writeTitles(List<Field> fields, Row row) { if (fields != null && !fields.isEmpty()) { for (int i = 0; i < fields.size(); i++) { CellField cellField = fields.get(i).getAnnotation(CellField.class); if (cellField == null) { continue; } Cell cell = row.createCell(i); // 獲取帶有name屬性的值並寫入 if (StringUtils.isNotBlank(cellField.name())) { cell.setCellValue(cellField.name()); } } } } /** * 寫入內容 * * @param beans 實體物件集合 * @param fields Field物件集合 * @param sheet 工作表物件 * @param <T> 泛型類 */ private static <T> void writeContents(List<T> beans, List<Field> fields, Sheet sheet) { for (int i = 0; i < beans.size(); i++) { T t = beans.get(i); Row row = sheet.createRow(i + 1); for (int j = 0; j < fields.size(); j++) { CellField cellField = fields.get(j).getAnnotation(CellField.class); if (cellField != null) { Class<?> valType = fields.get(j).getType(); // 獲取屬性型別 String fieldName = fields.get(j).getName(); // 獲取屬性名 String methodName = "get" + fieldName.substring(0, 1).toUpperCase() + fieldName.substring(1); Method method = ReflectionUtils.findMethod(t.getClass(), methodName); setValues(method, t, j, valType, cellField, row); // 設定值 } } } } /** * 設定值 * * @param method 方法物件 * @param t 泛型物件 * @param j 下標 * @param valType 型別物件 * @param cellField 註解物件 * @param row 行物件 * @param <T> 泛型 */ private static <T> void setValues(Method method, T t, int j, Class<?> valType, CellField cellField, Row row) { if (method != null) { Object value = ReflectionUtils.invokeMethod(method, t); if (value != null && valType == Date.class) { // 預設日期型別格式:yyyy-MM-dd HH:mm:ss SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); row.createCell(j).setCellValue(sdf.format(((Date) value).getTime())); } else { // 字串 row.createCell(j).setCellValue(value == null ? "" : String.valueOf(value)); } } } /** * 獲取標有@CellField註解的Field物件 * * @param beans 物件集合 * @return List<Field> */ private static <T> List<Field> getFields(List<T> beans) { Class<? extends Object> cls = beans.get(0).getClass(); Field[] declaredFields = cls.getDeclaredFields(); List<Field> annoFields = new ArrayList<Field>(); // 篩選出標有註解的欄位 for (Field field : declaredFields) { CellField anno = field.getAnnotation(CellField.class); if (anno != null) { annoFields.add(field); } } return annoFields; } }
3.測試實體類
package cn.com.test.entity; import org.apache.commons.lang3.builder.ReflectionToStringBuilder; import org.apache.commons.lang3.builder.ToStringStyle; import cn.com.test.annotation.CellField; /** * 檔案資訊實體類 * @author: Rodge * @time: 2017年12月26日 下午8:22:14 * @version: V1.0.0 */ public class IPOFileInfo { /**檔案所屬型別*/ @CellField(name = "檔案型別") private String fileType; /**檔案所屬編碼 */ @CellField(name = "檔案編碼") private String fileCode; /**檔名稱 */ @CellField(name = "檔名稱") private String fileName; /**檔案URL */ @CellField(name = "檔案URL") private String fileUrl; /**檔案日期 */ @CellField(name = "檔案日期") private String fileDate; /**MongoDB返回的檔案id */ @CellField(name = "檔案id") private String fileId; public String getFileType() { return fileType; } public void setFileType(String fileType) { this.fileType = fileType; } public String getFileCode() { return fileCode; } public void setFileCode(String fileCode) { this.fileCode = fileCode; } public String getFileName() { return fileName; } public void setFileName(String fileName) { this.fileName = fileName; } public String getFileUrl() { return fileUrl; } public void setFileUrl(String fileUrl) { this.fileUrl = fileUrl; } public String getFileDate() { return fileDate; } public void setFileDate(String fileDate) { this.fileDate = fileDate; } public String getFileId() { return fileId; } public void setFileId(String fileId) { this.fileId = fileId; } @Override public String toString() { return ReflectionToStringBuilder.toString(this, ToStringStyle.SHORT_PREFIX_STYLE); } }
4.測試類
package cn.com.test.ehcache;
import java.util.ArrayList;
import java.util.List;
import cn.com.test.entity.IPOFileInfo;
import cn.com.test.util.ExcelUtils;
/**
* excel工具類測試
* @author: Rodge
* @time: 2017年12月26日 下午10:22:04
* @version: V1.0.0
*/
public class TestExcelUtils {
public static void main(String[] args) {
List<IPOFileInfo> list = new ArrayList<>();
IPOFileInfo info = new IPOFileInfo();
info.setFileType("1");
info.setFileCode("001");
info.setFileDate("2017-12-26");
info.setFileId("111");
info.setFileName("測試文件1");
info.setFileUrl("www.baidu.com");
list.add(info);
IPOFileInfo info2 = new IPOFileInfo();
info2.setFileType("2");
info2.setFileCode("002");
info2.setFileDate("2017-12-26");
info2.setFileId("222");
info2.setFileName("測試文件2");
info2.setFileUrl("www.baidu.com");
list.add(info2);
IPOFileInfo info3 = new IPOFileInfo();
info3.setFileType("3");
info3.setFileCode("003");
info3.setFileDate("2017-12-26");
info3.setFileId("333");
info3.setFileName("測試文件3");
info3.setFileUrl("www.baidu.com");
list.add(info3);
// 生成excel2007文件
ExcelUtils.createExcel("D:/excel/2017-12-26.xlsx", list);
// 解析excel文件
List<IPOFileInfo> results = ExcelUtils.parseExcel("D:/excel/2017-12-26.xlsx", IPOFileInfo.class);
for (IPOFileInfo ipoFileInfo : results) {
System.out.println(ipoFileInfo);
}
}
}