需要的jar包有poi-3.17.jar
poi-ooxml-3.10-FINAL.jar
poi-ooxml-schemas-3.8.jar
xmlbeans-2.3.0.jar
/** * 将poi进行简单的封装,通过注解和反射,将excel中的集合和实体的set方法对应,形成执行集,再将执行集进行遍历,对bean进行封装,转化为 * 主要支持任意实体, * 支持excel文件中字段的不规则排序
* 单条记录的容错处理
* 支持扩展类型转化 * @author YKD * * @param <T> */
package gz.kd.utils.ExcelUtils; import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.IOException; import java.io.InputStream; import java.io.PushbackInputStream; import java.lang.reflect.Field; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.lang.reflect.ParameterizedType; import java.lang.reflect.Type; import java.text.DecimalFormat; import java.util.ArrayList; import java.util.Date; import java.util.HashMap; import java.util.List; import java.util.Map; import org.apache.poi.POIXMLDocument; import org.apache.poi.hssf.usermodel.HSSFWorkbook; import org.apache.poi.openxml4j.exceptions.InvalidFormatException; import org.apache.poi.openxml4j.opc.OPCPackage; import org.apache.poi.poifs.filesystem.POIFSFileSystem; import org.apache.poi.ss.usermodel.Cell; import org.apache.poi.ss.usermodel.DateUtil; 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.ss.usermodel.WorkbookFactory; import org.apache.poi.xssf.usermodel.XSSFWorkbook; import org.hamcrest.core.IsInstanceOf; import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** * 将poi进行简单的封装,通过注解和反射,将excel中的集合和实体的set方法对应,形成执行集,再将执行集进行遍历,对bean进行封装,转化为 * 主要支持任意实体, * 支持excel文件中字段的不规则排序 * @author [email protected] * * @param <T> */ public class ReadExcelByEntityUtils<T> { private Logger logger = LoggerFactory.getLogger(ReadExcelByEntityUtils.class); private Workbook wb;//每一个Excel文件都将被解析成一个WorkBook对象 private Sheet sheet;//Excel的每一页都将被解析成一个Sheet对象; private Row row;//Excel中的每一行都是一个Row对象,每一个单元格都是一个Cell对象。 private Map<Integer,T> map; //最终结果集 private Class<T> entity; //泛型类 private Field[] fields; //泛型方法集 private List<Class> TypeList; //转化类型 private Map<String,String> mapByAno=new HashMap<String,String>();//初始化集:<注解,属性名> /** * 构造工具类 * @param filepath * @throws InstantiationException * @throws IllegalAccessException * @throws InvalidFormatException */ @SuppressWarnings("unchecked") public ReadExcelByEntityUtils(String filepath) throws InstantiationException, IllegalAccessException, InvalidFormatException{ if(filepath==null){ System.out.println("Excel文件名为空"); return; } String lastName = filepath.substring(filepath.lastIndexOf(".")); try { InputStream is = new FileInputStream(filepath); if(".xls".equals(lastName)){ wb = new HSSFWorkbook(is); }else if(".xlsx".equals(lastName)){ File file = new File(filepath); wb = WorkbookFactory.create(file); }else{ wb=null; } } catch (FileNotFoundException e) { logger.error("文件找不到FileNotFoundException", e); } catch (IOException e) { logger.error("IOException", e); } entity = (Class<T>)((ParameterizedType)this.getClass().getGenericSuperclass()) .getActualTypeArguments()[0]; @SuppressWarnings("unused") T t = entity.newInstance(); if(this.entity!=null){ fields = entity.getDeclaredFields();//获取到属性字段 TypeList = new ArrayList<Class>(); for(Field f:fields){ //设置强制访问 f.setAccessible(true); EntiName e = f.getAnnotation(EntiName.class); if(!e.id()){ //对true的字段进行拦截 mapByAno.put(e.RName(),f.getName()); TypeList.add(e.clazz()); } } } } public Map<Integer,T> getMap() throws Exception{ setEntityMap(); return map; } /** * * 将excel数据内容填充到map * @throws Exception */ private void setEntityMap() throws Exception{ this.map = new HashMap<Integer, T>(); T t=null; String methodName=null; List<String> InvokeList = setInvokeList(); sheet = wb.getSheetAt(0); //总行数 int rowNum = sheet.getLastRowNum(); row = sheet.getRow(0); //得到每一行单元格个数,包括其中的空单元格,这里要求表格内容的每一行都是固定的个数 int colNum = row.getLastCellNum(); //每行单元格总数 for (int i = 1; i <= rowNum; i++) { //从第二行开始,遍历每一行 row = sheet.getRow(i); t = exchangeEntity(InvokeList, colNum,i); map.put(i-1, t); //将封装好的实体放入map } } private T exchangeEntity(List<String> InvokeList, int colNum,int rowNum){ T t=null; try { DecimalFormat df = new DecimalFormat("#"); // 对长数字段进行string的转化 String methodName; int j = 0; t = entity.newInstance(); //每次新建一个T while (j < colNum) { Object obj = getCellFormatValue(row.getCell(j)); // Class cs = TypeList.get(j); methodName=InvokeList.get(j); Method method = t.getClass().getMethod(methodName, TypeList.get(j)); if(obj==null||obj.equals("")){ try { method.invoke(t, (Object)null); //Object转化,很关键 } catch (Exception e) { // TODO Auto-generated catch block return t; } }else{ Object cast; if(cs.getName().equals("java.lang.String")){ //在这里拦截“excel中读取为double,date,int,boolean”,实际的实体函数形参却是String类型的 if(obj.getClass().getName().equals("java.lang.Double")){ cast = df.format(obj); }else{ cast = String.valueOf(obj); } }else if(cs.getName().equals("java.lang.Integer")){//形参需要的类型 if(obj.getClass().getName().equals("java.lang.Double")){ String intNUm = df.format(obj); cast = Integer.valueOf(intNUm); }else{ cast = cs.cast(obj); //可对类型进行扩展 } }/*else if(obj.getClass().getName().equals("java.util.Date")){ }else if(obj.getClass().getName().equals("set方法中的类型")){ 类型转化处理 } */else{ cast = cs.cast(obj); } //System.out.println(cast); method.invoke(t, cast); } j++; } } catch (Exception e) { // TODO Auto-generated catch block e.printStackTrace(); System.out.println("ExcelDEBUG:第"+rowNum+"行导入出错"); return t;//有异常返回一个空t } return t; } /** * 将标题头和实体的属性set方法对应上,形成一个执行函数集list,之后调用这个函数时,每次遍历list,然后invoke即可 * @throws Exception * */ private List<String> setInvokeList() throws Exception{ if(wb==null){ throw new Exception("Workbook对象为空!"); } List<String> invokeList = new ArrayList<String>(); List<String> readExcelTitle = readExcelTitle(); StringBuffer sb = new StringBuffer("set"); //System.out.println("setInvokeList的判断"+readExcelTitle.size()+"?==?"+mapByAno.size()); if(readExcelTitle.size()!=mapByAno.size()){ System.out.println("KD:excel表头跟注解数量不对应"); return null; }else{ for (String obj : readExcelTitle) { if(mapByAno.get(obj)==null){ System.out.println("KD:excel表头跟注解名称不对应"); return null; } String fieldname = mapByAno.get(obj); mapByAno.remove(obj, fieldname); //每拿一个put掉一个 sb = new StringBuffer("set"); String method = sb.append(fieldname.substring(0, 1).toUpperCase()) .append(fieldname.substring(1)).toString(); invokeList.add(method); } if(!mapByAno.isEmpty()){ System.out.println("KD:excel表头跟注解名称不对应"); return null; } return invokeList; /* */ } } /** * 得到标题头,标题头一定要是string类型,否则报错 * @return * @throws Exception */ public List<String> readExcelTitle() throws Exception{ if(wb == null){ throw new Exception("KD:workbook对象为空"); } sheet = wb.getSheetAt(0); row = sheet.getRow(0); //标题总列数 int colNum = row.getPhysicalNumberOfCells(); //去掉对空列的计数 //System.out.println("colNum:"+colNum); List<String> list = new ArrayList<String>(); for(int i = 0;i<colNum;i++){ if(row.getCell(i)==null||row.getCell(i).equals("")){ list.add(null); continue; }else { list.add((String) getCellFormatValue(row.getCell(i))); } } return list; } @SuppressWarnings("deprecation") private Object getCellFormatValue(Cell cell) { DecimalFormat df = new DecimalFormat("#"); // 对长数字段进行string的转化 Object cellvalue = null; if (cell != null) { // 判断当前Cell的Type switch (cell.getCellType()) { case Cell.CELL_TYPE_NUMERIC:// 如果当前Cell的Type为NUMERIC case Cell.CELL_TYPE_FORMULA: { // 判断当前的cell是否为Date if (DateUtil.isCellDateFormatted(cell)) { Date date = cell.getDateCellValue(); cellvalue = date; } else {// 如果是纯数字 // 取得当前Cell的数值 cellvalue = cell.getNumericCellValue(); /*if(cellvalue.getClass().getName().equals("java.lang.Double")){ cellvalue = df.format(cellvalue); }如果在此处拦截double就会使得所有的double都变成string,而有的时候我并不需要转成string */ } break; } case Cell.CELL_TYPE_STRING:// 如果当前Cell的Type为STRING // 取得当前的Cell字符串 cellvalue = cell.getRichStringCellValue().getString(); break; default:// 默认的Cell值 cellvalue = ""; } } else { cellvalue = ""; } return cellvalue; } }
import static java.lang.annotation.ElementType.FIELD; import static java.lang.annotation.ElementType.TYPE; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; /** * 辅助ReadExcelByEntityUtils * @author 姚楷东 [email protected] 做人,要有激情 */ @Target({FIELD}) @Retention(RetentionPolicy.RUNTIME)//指定注解在运行时有效 public @interface EntiName { /** * 是否为序列号 * @return */ boolean id() default false; /** * 字段名称 * @return */ String RName()default ""; /** * 形参类型 * @return */ Class clazz()default String.class; }
应用
举例
import java.util.Date; import gz.kd.utils.ExcelUtils.EntiName; public class Items { @EntiName(RName="序号",clazz=Integer.class) private Integer id; @EntiName(RName="名称") private String name; @EntiName(RName="价格",clazz=Double.class) private Double price; @EntiName(RName="照片",clazz=String.class) private String pic; @EntiName(RName="创建时间",clazz=Date.class) private Date createtime; @EntiName(RName="细节") private String detail; public Integer getId() { return id; } public void setId(Integer id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name == null ? null : name.trim(); } public Double getPrice() { return price; } public void setPrice(Double price) { this.price = price; } public String getPic() { return pic; } public void setPic(String pic) { this.pic = pic; } public Date getCreatetime() { return createtime; } public void setCreatetime(Date createtime) { this.createtime = createtime; } public String getDetail() { return detail; } public void setDetail(String detail) { this.detail = detail == null ? null : detail.trim(); } @Override public String toString() { return "Items [id=" + id + ", name=" + name + ", price=" + price + ", pic=" + pic + ", createtime=" + createtime + ", detail=" + detail + "]"; } }
运行结果为封装好的Map实体
下面的表格,首行为字段,必需要与实体上的注解对应,顺序不需要对应;第二行开始为表格内容:
名称 价格 照片 创建时间 细节 台式机 1a6f270c-714b-4070-b960-e25015615a19.jpg 细节 电脑 6000 2017/11/10 15:26 细节 背包 3600 2017/11/10 15:30 背包 2017/11/10 15:30 细节1
如果不懂或者需要源码,留下评论,欢迎加qq 276368974 交流