使用Apache POI包导入Excel时是需要根据行和列取到对应的值,因此取值时需要知道该列所对应的值应存放到对象的那个字段中去,表格出现变动就会变的比较麻烦,因此此处使用自定义注解的方式,在对象中标明该属性所对应的表头,从程序中遍历表头找到与之对应的单元格,方便数据的导入。
所需的jar包:(用了一下工具类,因此多导入了两个包)
<dependency> <groupId>org.apache.poi</groupId> <artifactId>poi</artifactId> <version>3.17</version> </dependency> <dependency> <groupId>org.apache.poi</groupId> <artifactId>poi-ooxml</artifactId> <version>3.17</version> </dependency> <dependency> <groupId>commons-beanutils</groupId> <artifactId>commons-beanutils</artifactId> <version>1.9.2</version> </dependency> <dependency> <groupId>org.apache.commons</groupId> <artifactId>commons-lang3</artifactId> <version>3.2.1</version> </dependency>
自定义注解:
@Retention(RetentionPolicy.RUNTIME) @Target({ElementType.FIELD ,ElementType.TYPE}) public @interface ExcelIn { /** * 导入sheet名称 * @return */ String sheetName() default ""; /** * 字段对应的表头名称 * @return */ String title() default ""; }
接收导入数据的实体:
@ExcelIn(sheetName = "用户信息") public class UserInfo { private String id; @ExcelIn(title = "姓名") private String name; @ExcelIn(title = "年龄") private Integer age; @ExcelIn(title = "出生日期") private Date birthday; }
导入Excel数据:
public class ExcelReader<T> { private static BeanUtilsBean beanUtilsBean = new BeanUtilsBean(); static { beanUtilsBean.getConvertUtils().register(new org.apache.commons.beanutils.converters.DateConverter(null), java.util.Date.class); } /** * 表头名字和对应所在第几列的下标,用于根据title取到对应的值 */ private final Map<String,Integer> title_to_index = new HashMap<>(); /** * 所有带有ExcelIn注解的字段 */ private final List<Field> fields = new ArrayList<>(); /** * 统计表格的行和列数量用来遍历表格 */ private int firstCellNum = 0; private int lastCellNum = 0; private int firstRowNum = 0; private int lastRowNum = 0; private String sheetName ; private HSSFSheet sheet ; public List<T> read(InputStream in , Class clazz) throws Exception { gatherAnnotationFields(clazz); configSheet(in); configHeader(); List rList= null; try { rList = readContent(clazz); } catch (IllegalAccessException e) { throw new Exception(e); } catch (InstantiationException e) { throw new Exception(e); } catch (InvocationTargetException e) { throw new Exception(e); } return rList ; } private List readContent(Class clazz) throws IllegalAccessException, InstantiationException, InvocationTargetException { Object o = null ; HSSFRow row = null ; List<Object> rsList = new ArrayList<>(); Object value = null ; for(int i = (firstRowNum+1);i<=lastRowNum;i++){ o = clazz.newInstance(); row = sheet.getRow(i); HSSFCell cell = null ; for (Field field : fields) { //根据注解中的title,取到表格中该列所对应的的值 Integer column=title_to_index.get(field.getAnnotation(ExcelIn.class).title()); if(column==null){ continue; } cell = row.getCell(column); value = getCellValue(cell) ; if(null != value && StringUtils.isNotBlank(value.toString())) { beanUtilsBean.setProperty(o, field.getName(), value); } } rsList.add(o); } return rsList ; } private void configSheet(InputStream in) throws Exception { //HSSFWorkbook:只能创建97-03版本的Excel,即:以xls结尾的Excel // 想要导入xlsx结尾的Excel,用XSSFWorkbook try(HSSFWorkbook wb = new HSSFWorkbook(in)){ getSheetByName(wb); } catch (FileNotFoundException e) { throw new Exception(e); } catch (IOException e) { throw new Exception(e); } } /** * 根据sheet获取对应的行列值,和表头对应的列值映射 */ private void configHeader(){ this.firstRowNum = sheet.getFirstRowNum() ; this.lastRowNum = sheet.getLastRowNum() ; //第一行为表头,拿到表头对应的列值 HSSFRow row = sheet.getRow(firstRowNum); this.firstCellNum = row.getFirstCellNum(); this.lastCellNum = row.getLastCellNum(); for (int i = firstCellNum;i<lastCellNum;i++){ title_to_index.put(row.getCell(i).getStringCellValue(),i); } } /** * 根据sheet名称获取sheet * @param workbook * @return * @throws Exception */ private void getSheetByName(HSSFWorkbook workbook) throws Exception { int sheetNumber = workbook.getNumberOfSheets(); for (int i = 0; i < sheetNumber; i++) { String name = workbook.getSheetName(i); if(StringUtils.equals(this.sheetName,name)) { this.sheet = workbook.getSheetAt(i); return; } } throw new Exception("excel中未找到名称为"+this.sheetName+"的sheet"); } /** * 根据自定义注解,获取所要导入表格的sheet名称和需要导入的字段名称 * @param clazz * @throws Exception */ private void gatherAnnotationFields(Class clazz) throws Exception { if(!clazz.isAnnotationPresent(ExcelIn.class)){ throw new Exception(clazz.getName()+"类上没有ExcelIn注解"); } ExcelIn excelIn = (ExcelIn)clazz.getAnnotation(ExcelIn.class) ; this.sheetName = excelIn.sheetName(); // 得到所有定义字段 Field[] allFields = FieldUtils.getAllFields(clazz) ; // 得到所有field并存放到一个list中 for (Field field : allFields) { if (field.isAnnotationPresent(ExcelIn.class)) { fields.add(field); } } if( fields.isEmpty()){ throw new Exception(clazz.getName()+"中没有ExcelIn注解字段"); } } private Object getCellValue(Cell cell) { if (cell == null) { return ""; } Object obj = null; switch (cell.getCellTypeEnum()) { case BOOLEAN: obj = cell.getBooleanCellValue(); break; case ERROR: obj = cell.getErrorCellValue(); break; case FORMULA: try { obj = String.valueOf(cell.getStringCellValue()); } catch (IllegalStateException e) { obj = numericToBigDecimal(cell); } break; case NUMERIC: obj = getNumericValue(cell); break; case STRING: String value = String.valueOf(cell.getStringCellValue()); value = value.replace(" ", ""); value = value.replace("\n", ""); value = value.replace("\t", ""); obj = value; break; default: break; } return obj; } private Object getNumericValue(Cell cell){ // 处理日期格式、时间格式 if (HSSFDateUtil.isCellDateFormatted(cell)) { return cell.getDateCellValue(); }else if (cell.getCellStyle().getDataFormat() == 58) { // 处理自定义日期格式:m月d日(通过判断单元格的格式id解决,id的值是58) double value = cell.getNumericCellValue(); return org.apache.poi.ss.usermodel.DateUtil.getJavaDate(value); } else { return numericToBigDecimal(cell); } } private Object numericToBigDecimal(Cell cell) { String valueOf = String.valueOf(cell.getNumericCellValue()); BigDecimal bd = new BigDecimal(valueOf); return bd; } }
测试导入结果:
@RunWith(SpringRunner.class) @SpringBootTest public class Test { @org.junit.Test public void t(){ try{ File file = new File("d:/abc.xls"); ExcelReader<UserInfo> reader = new ExcelReader<>(); InputStream is = new FileInputStream(file); List<UserInfo> list = reader.read(is,UserInfo.class); if (CollectionUtils.isNotEmpty(list)) { for (UserInfo u : list) { System.out.println("姓名:" + u.getName() + " ,年龄:" + u.getAge() + " ,出身日期:" + u.getBirthday()); } } }catch (Exception e){ e.printStackTrace(); } } }
导入的Excel数据:(Excel的sheet名称为接收实体对象的sheetName)
结果展示:
原文地址:https://www.cnblogs.com/xiao-OvO-/p/11012989.html
时间: 2024-10-03 21:40:18