JAVA 使用POI 上傳 excel檔案
阿新 • • 發佈:2018-12-12
作為一名底層的JAVA碼農,今天領導有個我分了個爛大街的需求,使用POI做個excel檔案的匯出。太簡單了吧,立馬把平時百度的手速拿了出來,翻了一頁又一頁,demo很多,但是幾乎都有bug,最終,我在github拔了好幾段靠譜的程式碼。廢話不多說,貼程式碼:
package com.github.xjs.util; import com.github.xjs.util.PoiUtil.FieldInfo; import org.apache.poi.POIXMLException; import org.apache.poi.hssf.usermodel.HSSFDateUtil; import org.apache.poi.hssf.usermodel.HSSFWorkbook; import org.apache.poi.poifs.filesystem.OfficeXmlFileException; 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 java.io.ByteArrayInputStream; import java.io.IOException; import java.lang.reflect.Field; import java.text.SimpleDateFormat; import java.util.ArrayList; import java.util.Date; import java.util.List; public class PoiImport { private static Logger log = LoggerFactory.getLogger(PoiImport.class); // bytes:筒子們,直接使用這個靜態方法,將待上傳的excel檔案讀入成流陣列。 // skipNum:自己看著辦,從哪一行開始讀起 public static <T> List<T> readExcel(String filename, byte[] bytes, Class<T> clazz, int sheetIndex, int skipNum) throws IOException { List<String[]> arrList = readExcel(filename, bytes, sheetIndex, skipNum); if (arrList == null || arrList.size() <= 0) { return null; } List<T> list = new ArrayList<T>(arrList.size()); for (String[] arr : arrList) { T t = stringArrToBean(arr, clazz); if (t != null) { list.add(t); } } return list; } // 不好意思,太長了,又是抄的,如果想研究,自己慢慢debug public static List<String[]> readExcel(String filename, byte[] bytes, int sheetIndex, int skipNum) throws IOException { //獲得Workbook工作薄物件 Workbook workbook = null; try { workbook = getWorkBook(bytes, filename); } catch (Exception exception) {//如果人為修改了字尾名 String realFileName = filename; if (exception instanceof OfficeXmlFileException) {//2007改為了2003 realFileName = filename + "x"; } else if (exception instanceof POIXMLException) {//2003改為了2007 realFileName = filename.substring(0, filename.length() - 1); } else { throw new RuntimeException("檔案解析異常", exception); } if (!filename.equals(realFileName)) { workbook = getWorkBook(bytes, realFileName); } } //建立返回物件,把每行中的值作為一個數組,所有行作為一個集合返回 List<String[]> list = new ArrayList<String[]>(); //獲得sheet工作表 Sheet sheet = workbook.getSheetAt(sheetIndex); if (sheet == null) { return null; } //獲得當前sheet的開始行 int firstRowNum = sheet.getFirstRowNum(); //獲得當前sheet的結束行 int lastRowNum = sheet.getLastRowNum(); //迴圈所有行 while (skipNum-- > 0) { firstRowNum++; } for (int rowNum = firstRowNum; rowNum <= lastRowNum; rowNum++) { //獲得當前行 Row row = sheet.getRow(rowNum); if (row == null) { continue; } //獲得當前行的開始列 int firstCellNum = row.getFirstCellNum(); //獲得當前行的列數 int cellNums = row.getPhysicalNumberOfCells(); if (firstCellNum < 0 || cellNums <= 0) { continue; } String[] cells = new String[firstCellNum + cellNums]; //迴圈當前行 for (int cellNum = firstCellNum; cellNum < firstCellNum + cellNums; cellNum++) { Cell cell = row.getCell(cellNum); cells[cellNum] = getCellValue(cell); } list.add(cells); } return list; } private static <T> T stringArrToBean(String[] arr, Class<T> clazz) { try { T t = clazz.newInstance(); // 附在後面,自己慢慢看吧,長的很。 List<FieldInfo> fields = PoiUtil.getFiledInfos(clazz); if (fields == null || fields.size() <= 0) { return null; } for (FieldInfo filed : fields) { int idx = filed.getOrder(); if (arr.length <= idx) { continue; } fillBeanFieldValue(t, filed, arr[idx]); } return t; } catch (Exception e) { throw new RuntimeException(e); } } private static <T> void fillBeanFieldValue(T bean, FieldInfo filedInfo, String fieldValue) { if (fieldValue == null || fieldValue.length() <= 0) { return; } try { Field filed = filedInfo.getFiled(); Class<?> fieldType = filed.getType(); // 這個設定男女性別的方法有點笨,但是哥不想優化 if ("男".equals(fieldValue) || "女".equals(fieldValue)) { if ("男".equals(fieldValue)) { filed.set(bean, 1); } else { filed.set(bean, 0); } } else if (fieldType == String.class) { filed.set(bean, fieldValue); } else if (fieldType == int.class) { filed.set(bean, Integer.valueOf(fieldValue).intValue()); } else if (fieldType == byte.class) { filed.set(bean, Byte.valueOf(fieldValue).byteValue()); } else if (fieldType == long.class) { filed.set(bean, Long.valueOf(fieldValue).longValue()); } else if (fieldType == double.class) { filed.set(bean, Double.valueOf(fieldValue).doubleValue()); } else if (fieldType == boolean.class) { if ("是".equals(fieldValue) || "Y".equalsIgnoreCase(fieldValue) || "YES".equalsIgnoreCase(fieldValue) || "T".equalsIgnoreCase(fieldValue) || "TRUE".equalsIgnoreCase(fieldValue)) { filed.set(bean, true); } else if ("否".equals(fieldValue) || "N".equalsIgnoreCase(fieldValue) || "NO".equalsIgnoreCase(fieldValue) || "F".equalsIgnoreCase(fieldValue) || "FALSE".equalsIgnoreCase(fieldValue)) { filed.set(bean, false); } } else if (fieldType == Integer.class) { filed.set(bean, Integer.valueOf(fieldValue)); } else if (fieldType == Byte.class) { filed.set(bean, Byte.valueOf(fieldValue)); } else if (fieldType == Long.class) { filed.set(bean, Long.valueOf(fieldValue)); } else if (fieldType == Double.class) { filed.set(bean, Double.valueOf(fieldValue)); } else if (fieldType == Boolean.class) { if ("是".equals(fieldValue) || "Y".equalsIgnoreCase(fieldValue) || "YES".equalsIgnoreCase(fieldValue) || "T".equalsIgnoreCase(fieldValue) || "TRUE".equalsIgnoreCase(fieldValue)) { filed.set(bean, Boolean.TRUE); } else if ("否".equals(fieldValue) || "N".equalsIgnoreCase(fieldValue) || "NO".equalsIgnoreCase(fieldValue) || "F".equalsIgnoreCase(fieldValue) || "FALSE".equalsIgnoreCase(fieldValue)) { filed.set(bean, Boolean.FALSE); } } else if (fieldType == Date.class) { filed.set(bean, DateUtil.parse(fieldValue, DateUtil.FORMAT_YMD)); } else { throw new RuntimeException("不支援的資料型別:" + filed.getName() + ":" + fieldType); } } catch (Exception e) { throw new RuntimeException("設定欄位值異常:" + bean + "," + filedInfo.getFiled().getName() + ":" + fieldValue, e); } } private static Workbook getWorkBook(byte[] bytes, String fileName) { try { fileName = fileName.toLowerCase(); //根據檔案字尾名不同(xls和xlsx)獲得不同的Workbook實現類物件 if (fileName.endsWith(".xls")) { //2003 return new HSSFWorkbook(new ByteArrayInputStream(bytes)); } else if (fileName.endsWith(".xlsx")) { //2007 return new XSSFWorkbook(new ByteArrayInputStream(bytes)); } else { throw new RuntimeException("檔案字尾名不合法"); } } catch (IOException e) { log.error(e.getMessage(), e); throw new RuntimeException(e); } } private static String getCellValue(Cell cell) { String cellValue = ""; if (cell == null) { return cellValue; } switch (cell.getCellType()) { case Cell.CELL_TYPE_NUMERIC: //數字 // 特麼的超級坑,Java將日期讀成數字,老子花了會功夫才解決這個問題。 // 避免將日期讀成數字 if (HSSFDateUtil.isCellDateFormatted(cell)) { Date date = cell.getDateCellValue(); String value = new SimpleDateFormat("yyyy-MM-dd").format(date); return value; } //把數字當成String來讀,避免出現1讀成1.0的情況 cell.setCellType(Cell.CELL_TYPE_STRING); // cellValue = String.valueOf(cell.getNumericCellValue()); cellValue = String.valueOf(cell.getStringCellValue()); break; case Cell.CELL_TYPE_STRING: //字串 cellValue = String.valueOf(cell.getStringCellValue()); break; case Cell.CELL_TYPE_BOOLEAN: //Boolean cellValue = String.valueOf(cell.getBooleanCellValue()); break; case Cell.CELL_TYPE_FORMULA: //公式 cellValue = String.valueOf(cell.getCellFormula()); break; case Cell.CELL_TYPE_BLANK: //空值 cellValue = ""; break; case Cell.CELL_TYPE_ERROR: //故障 cellValue = "非法字元"; break; default: cellValue = "未知型別"; break; } return cellValue; } // public static void main(String[] args) throws Exception { // // InputStream in = new FileInputStream("E:" + File.separator + "xxxx.xlsx"); // byte[] bytes = IOUtil.readInputStream(in); // List<PatientInfo> infos = readExcel("xxxx.xlsx", bytes, PatientInfo.class, 0, 3); // if (in != null) { // in.close(); // } // // } }
不好意思,以下完全是大牛的程式碼,作為程式設計師,重複造輪子是大忌,所以直接貼給大家了,順便跟大家說說,github真的有很多優秀的大牛程式碼。
package com.github.xjs.util; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; import java.lang.reflect.Field; import java.lang.reflect.Modifier; import java.net.URLEncoder; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.Comparator; import java.util.Date; import java.util.List; import java.util.concurrent.ConcurrentHashMap; import javax.servlet.http.HttpServletResponse; /** * @author[email protected] * * @date 2017年8月16日 下午2:1:12 */ public class PoiUtil { @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.FIELD) public static @interface FiledOrder{ public int value();//從0開始 } public interface FieldSerializer<T,V>{ public String serialize(T bean, V fieldValue); } public static abstract class FieldNameSerializer<T, V> implements FieldSerializer<T,V> { private String fieldName; public FieldNameSerializer(String fieldName) { this.fieldName = fieldName; } public String getFieldName() { return this.fieldName; } } public static abstract class FieldTypeSerializer<T, V> implements FieldSerializer<T,V> { private Class<V> fieldType; public FieldTypeSerializer(Class<V> clazz) { this.fieldType = clazz; } public Class<V> getFieldType(){ return this.fieldType; } } public static <T> List<T> readExcel(String filename, byte[] bytes,Class<T> clazz) throws IOException{ return PoiImport.readExcel(filename, bytes, clazz, 0, true); } public static <T> List<T> readExcel(String filename, byte[] bytes,Class<T> clazz, int sheetIndex) throws IOException{ return PoiImport.readExcel(filename, bytes, clazz, sheetIndex, true); } public static <T> List<T> readExcel(String filename, byte[] bytes,Class<T> clazz, int sheetIndex, boolean skipFirst) throws IOException{ return PoiImport.readExcel(filename, bytes, clazz, sheetIndex, skipFirst); } public static <T,V> byte[] writeExcel(List<T> datas) throws Exception{ return writeExcel((List<String>)null, datas, (List<FieldSerializer<T,V>>)null); } public static <T,V> byte[] writeExcel(String[] heads, List<T> datas) throws Exception{ return writeExcel(heads==null?(List<String>)null:Arrays.asList(heads), datas, (List<FieldSerializer<T,V>>)null); } public static <T,V> byte[] writeExcel(List<String> heads, List<T> datas) throws Exception{ return writeExcel(heads, datas, (List<FieldSerializer<T,V>>)null); } @SafeVarargs public static <T, V> byte[] writeExcel(String[] heads, List<T> datas, FieldSerializer<T,V>... serializers) throws Exception{ return writeExcel(heads==null?(List<String>)null:Arrays.asList(heads), datas, serializers==null?(List<FieldSerializer<T,V>>)null:Arrays.asList(serializers)); } @SafeVarargs public static <T, V> byte[] writeExcel(List<String> heads, List<T> datas, FieldSerializer<T,V>... serializers) throws Exception{ return writeExcel(heads, datas, serializers==null?(List<FieldSerializer<T,V>>)null:Arrays.asList(serializers)); } public static <T, V> byte[] writeExcel(String[] heads, List<T> datas, List<FieldSerializer<T,V>> serializers) throws Exception{ return writeExcel(heads==null?(List<String>)null:Arrays.asList(heads), datas, serializers); } public static <T,V> byte[] writeExcel(List<String> heads, List<T> datas, List<FieldSerializer<T,V>> serializers) throws Exception{ PoiExport pe = new PoiExport(); pe.registerFormatters(serializers); return pe.writeExcel(heads, datas); } public static <T,V> void downloadExcel(HttpServletResponse response, String filename, List<T> dataset) throws Exception { downloadExcel(response, filename, (List<String>)null, dataset, (List<FieldSerializer<T,V>>)null); } public static <T,V> void downloadExcel(HttpServletResponse response, String filename, String[] headers, List<T> dataset) throws Exception { downloadExcel(response, filename, headers==null?null:Arrays.asList(headers), dataset, (List<FieldSerializer<T,V>>)null); } public static <T,V> void downloadExcel(HttpServletResponse response, String filename, List<String> headers, List<T> dataset) throws Exception { downloadExcel(response, filename, headers, dataset, (List<FieldSerializer<T,V>>)null); } @SafeVarargs public static <T,V> void downloadExcel(HttpServletResponse response, String filename, String[] headers, List<T> dataset,FieldSerializer<T,V>... serializers) throws Exception { downloadExcel(response, filename, headers==null?null:Arrays.asList(headers), dataset, serializers==null?(List<FieldSerializer<T,V>>)null:Arrays.asList(serializers)); } @SafeVarargs public static <T,V> void downloadExcel(HttpServletResponse response, String filename, List<String> headers, List<T> dataset,FieldSerializer<T,V>... serializers) throws Exception { downloadExcel(response, filename, headers, dataset, serializers==null?null:Arrays.asList(serializers)); } public static <T,V> void downloadExcel(HttpServletResponse response, String filename, String[] headers, List<T> dataset,List<FieldSerializer<T,V>> serializers) throws Exception { downloadExcel(response, filename, headers==null?null:Arrays.asList(headers), dataset, serializers); } public static <T,V> void downloadExcel(HttpServletResponse response, String filename,List<String> headers, List<T> dataset, List<FieldSerializer<T,V>> serializers) throws Exception { //設定檔案ContentType型別,這樣設定,會自動判斷下載檔案型別 response.setContentType("multipart/form-data;charset=UTF-8"); //設定檔案頭:最後一個引數是設定下載檔名 response.setHeader("Content-Disposition", "attachment;fileName="+ URLEncoder.encode(filename, "UTF-8")); byte[] bytes = writeExcel(headers, dataset, serializers); OutputStream out = response.getOutputStream(); out.write(bytes); out.flush(); } private static ConcurrentHashMap<Class<?>, List<FieldInfo>> fieldInfoCache = new ConcurrentHashMap<Class<?>, List<FieldInfo>>(); public static class FieldInfo{ private Field filed; private int order; public FieldInfo(Field filed, int order) { super(); this.filed = filed; this.order = order; } public Field getFiled() { return filed; } public void setFiled(Field filed) { this.filed = filed; } public int getOrder() { return order; } public void setOrder(int order) { this.order = order; } } public static List<FieldInfo> getFiledInfos(Class<?> clazz){ List<FieldInfo> list = fieldInfoCache.get(clazz); if(list != null && list.size() > 0) { return list; } List<FieldInfo> fieldInfos = new ArrayList<FieldInfo>(); Class<?> targetClass = clazz; do { Field[] fields = targetClass.getDeclaredFields(); for (Field field : fields) { if((Modifier.isStatic(field.getModifiers()) || Modifier.isFinal(field.getModifiers()))){ continue; } field.setAccessible(true); FiledOrder orderAnno = field.getAnnotation(FiledOrder.class); if(orderAnno == null) { continue; } fieldInfos.add(new FieldInfo(field, orderAnno.value())); } targetClass = targetClass.getSuperclass(); } while (targetClass != null && targetClass != Object.class); Collections.sort(fieldInfos, new Comparator<FieldInfo>() { @Override public int compare(FieldInfo o1, FieldInfo o2) { return o1.getOrder()-o2.getOrder(); } }); fieldInfoCache.putIfAbsent(clazz, fieldInfos); return fieldInfos; } // 以下是TEST public static class User{//不用遵守javabean規範 @FiledOrder(0) private int id; @FiledOrder(1) private String name; @FiledOrder(2) private Date birthDay; @FiledOrder(3) private boolean isMale; public User() {} public User(int id, String name, Date birthDay, boolean isMale) { this.id = id; this.name = name; this.birthDay = birthDay; this.isMale = isMale; } @Override public String toString() { return "User [id=" + id + ", name=" + name + ", birthDay=" + birthDay + ", isMale=" + isMale + "]"; } } public static void main(String args[])throws Exception { String file = "C:\\Users\\xujs\\Desktop\\aa.xls"; User user1 = new User(1, "aaa", new Date(), true); User user2 = new User(2, "bbb", new Date(), false); User user3 = new User(3, "ccc", new Date(), true); User user4 = new User(4, "ddd", new Date(), false); List<User> users = new ArrayList<User>(4); users.add(user1);users.add(user2);users.add(user3);users.add(user4); FieldSerializer<User, Boolean> serializer = new FieldNameSerializer<User, Boolean>("isMale") { @Override public String serialize(User bean, Boolean fieldValue) { if(fieldValue) { return "是"; }else { return "否"; } } }; byte[] bytes = writeExcel(new String[] {"id","姓名","生日","是否男性"}, users, serializer); OutputStream out = new FileOutputStream(file); out.write(bytes); out.close(); System.out.println("write over"); InputStream in = new FileInputStream(file); bytes = IOUtil.readInputStream(in); in.close(); List<User> list = readExcel(file,bytes, User.class); System.out.println(list.size()); for(User u : list) { System.out.println(u); } System.out.println("read over"); } }