excel转实体类 java

先贴代码,然后解释几个容易出错的地方(工具类来自网上,我只负责解说)

import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;

import org.apache.poi.hssf.usermodel.HSSFWorkbook;
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 com.myproject.common.normalUtils.excel.constant.ExcelType;
import com.myproject.common.normalUtils.excel.util.BeanUtils;

/**
 * excel解析
 *
 */
public class ExcelExtractor {

  private static Logger logger = LoggerFactory.getLogger(ExcelExtractor.class);

  /**
   * 解析excel,默认第一行为表头
   *
   * @param type         excel类型
   * @param excel        excel输入流
   * @param tClass       要生成的实体类
   * @param headerMapper 实体类和表格第一行的映射,key是表格,val是实体类name
   * @param sheetIndex   需要解析的工作表,第一张是 0
   * @return 解析后集合
   * @throws IllegalArgumentException 解析错误
   */
  public static <T> List<T> extractFrom(ExcelType type, InputStream excel, Class<T> tClass,
      Map<String, String> headerMapper, Integer sheetIndex) throws IllegalArgumentException, IOException {
    Workbook workbook;
    try {
      workbook = type.equals(ExcelType.XLS) ? new HSSFWorkbook(excel) : new XSSFWorkbook(excel);
    } catch (IOException e) {
      throw new IllegalArgumentException("未知的表格类型");
    }
    //解析表头.默认第一行为表头
    Sheet sheet = workbook.getSheetAt(sheetIndex);
    logger.debug("总行数:{}",sheet.getLastRowNum());
    Iterator<Row> rowIterator = sheet.rowIterator();
    //第一行
    Row firstRow = rowIterator.next();
    Iterator<Cell> firstCell = firstRow.cellIterator();

    Set<String> existHeaderSet = new HashSet<>();
    List<String> existHeader = new ArrayList<>(headerMapper.size());
    firstCell.forEachRemaining(cell -> {
      if (cell.getCellType() != Cell.CELL_TYPE_STRING) {
        throw new IllegalArgumentException("第一行必须全部为字符串,第" + cell.getColumnIndex() + 1 + "有问题");
      }
      existHeaderSet.add(cell.getStringCellValue());
      existHeader.add(cell.getStringCellValue());
    });
    //查询出不存在的表头
    for (String s : headerMapper.keySet()) {
      if (!existHeaderSet.contains(s)) {
        throw new IllegalArgumentException("不存在的表头:" + s);
      }
    }
    //开始解析表单
    Integer lineNumber = 0;
    List<T> result = new ArrayList<T>();
    try {
      while (rowIterator.hasNext()){
        Row x = rowIterator.next();
        lineNumber++;
        Map<String, Object> tempMap = new HashMap<>();
        Iterator<Cell> cellIterator = x.cellIterator();
        cellIterator.forEachRemaining(y -> {
          Object value = null;
          switch (y.getCellType()) {
            case Cell.CELL_TYPE_STRING:
              value = y.getStringCellValue();
              break;
            case Cell.CELL_TYPE_BOOLEAN:
              value = y.getBooleanCellValue();
              break;
            case Cell.CELL_TYPE_NUMERIC:
              value = y.getNumericCellValue();
              break;
            case Cell.CELL_TYPE_ERROR:
              value = "";
              break;
            case Cell.CELL_TYPE_BLANK:
              value = "";
              break;
            default:
              value = "";
          }
          String key = headerMapper.get(existHeader.get(y.getColumnIndex()));
          tempMap.put(key, value);
        });
        result.add(BeanUtils.map2Bean(tempMap, tClass));
      }
    } catch (Exception e) {
    	logger.error("解析错误",e);
      logger.error("第{}行解析错误",lineNumber);
    }
    return result;
  }
}
/**
   * map转bean
   * @param source   map属性
   * @param instance 要转换成的实体类
   * @return 
   */
  public static <T> T map2Bean(Map<String, Object> source, Class<T> instance) {
    try {
      T object = instance.newInstance();
      Field[] fields = object.getClass().getDeclaredFields();
      for (Field field : fields) {
        field.setAccessible(true);
        FieldName fieldName = field.getAnnotation(FieldName.class);
        if (fieldName != null){
          field.set(object,source.get(fieldName.value()));
        }else {
          field.set(object,source.get(field.getName()));
        }
      }
      return object;
    } catch (InstantiationException | IllegalAccessException e) {
      e.printStackTrace();
    }
    return null;
  }


/**
 * 定义excel格式
 */
public enum ExcelEnums {
  XLS, XLSX;
}

备注:
1. 数值类型处理。通过POI取出的数值默认都是double,即使excel单元格中存的是1,取出来的值也是1.0,这就造成了一些问题,如果数据库字段是int,那么就会wrong data type,所以需要对数值类型处理。
 Double doubleVal=y.getNumericCellValue();
 if (!isEmpty(y) && y.getCellType() == Cell.CELL_TYPE_NUMERIC) {
    long longVal = Math.round(y.getNumericCellValue());
    if (Double.parseDouble(longVal + ".0") == doubleVal)
       value =  Integer.parseInt(String.valueOf(longVal));
    else
       value = doubleVal;
 }
这么处理后,单元格中的小数没有变化,如果是整数,也会取到整数。


2.日期类型处理。POI对单元格日期处理很弱,没有针对的类型,日期类型取出来的也是一个double值,所以同样作为数值类型。


3.map2Bean()。

FieldName fieldName = field.getAnnotation(FieldName.class);
if (fieldName != null){
field.set(object,source.get(fieldName.value()));
}else {
field.set(object,source.get(field.getName()));
}
如果实体类字段是double等类型,会报 无法赋值的错误。

猜你喜欢

转载自blog.csdn.net/the_knife/article/details/79157716
今日推荐