1. 程式人生 > >JAVA 使用POI 上傳 excel檔案

JAVA 使用POI 上傳 excel檔案

作為一名底層的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"); } }