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");
   }
}

猜你喜欢

转载自blog.csdn.net/afmin/article/details/82872739