我删减了一部分代码
思路:
1.通过注解获取需要导入对象的方法名的数组
2.获取方法的返回值及返回类型
循环excel的行,每行对应一个对象,而每个对象有对应的注解的集合,
在注解集合的子循环中,获取所在行的每一列数据,将列数据通过注解
与注解对应的get方法对应起来,得到get方法的返回值类型
3.将返回值转成需要的返回值类型
将列数据的Object类型转换成返回值类型的数据。
4.将值set到对象中
获取get方法对应的set方法,调用method.invoke(obj, args)(调用包
装在当前Method对象中的方法)将值set到对象中。
@RequiresPermissions("testterm:testTerm:edit") @RequestMapping(value = "import", method = RequestMethod.POST) public String importFile(String file, RedirectAttributes redirectAttributes) { if (Global.isDemoMode()) { addMessage(redirectAttributes, "演示模式,不允许操作!"); return "redirect:" + adminPath + "/sys/user/list?repage"; } file = ParamUtils.getParamValue("upload_path", "") + file; try { int successNum = 0; int failureNum = 0; StringBuilder failureMsg = new StringBuilder(); ImportExcel ei = new ImportExcel(file, 1, 0); List<TestTerm> list = ei.getDataList(TestTerm.class); for (TestTerm testTerm : list) { try { BeanValidators.validateWithException(validator, testTerm); testTermService.save(testTerm); successNum++; } catch (ConstraintViolationException ex) { failureMsg.append("<br/>术语及定义 " + testTerm.getName() + "导入失败:"); List<String> messageList = BeanValidators.extractPropertyAndMessageAsList(ex, ": "); for (String message : messageList) { failureMsg.append(message + "; "); failureNum++; } } catch (Exception ex) { failureMsg.append("<br/>术语及定义 " + testTerm.getName() + " 导入失败:" + ex.getMessage()); } } if (failureNum > 0) { failureMsg.insert(0, ",失败 " + failureNum + " 条术语及定义信息,导入信息如下:"); } addMessage(redirectAttributes, "已成功导入 " + successNum + " 条术语及定义信息" + failureMsg); FileUtils.deleteFile(file); } catch (Exception e) { addMessage(redirectAttributes, "导入术语及定义!失败信息:" + e.getMessage()); FileUtils.deleteFile(file); } return "redirect:" + adminPath + "/testterm/testTerm/list?repage"; }
/** * 导入Excel文件(支持“XLS”和“XLSX”格式) * @author ThinkGem * @version 2013-03-10 */ public class ImportExcel { private static Logger log = LoggerFactory.getLogger(ImportExcel.class); /** * 工作薄对象 */ private Workbook wb; /** * 工作表对象 */ private Sheet sheet; /** * 标题行号 */ private int headerNum; /** * 构造函数 * @param path 导入文件 * @param headerNum 标题行号,数据行号=标题行号+1 * @param sheetIndex 工作表编号 * @throws InvalidFormatException * @throws IOException */ public ImportExcel(String fileName, int headerNum, int sheetIndex) throws InvalidFormatException, IOException { this(new File(fileName), headerNum, sheetIndex); }/** * 构造函数 * @param path 导入文件对象 * @param headerNum 标题行号,数据行号=标题行号+1 * @param sheetIndex 工作表编号 * @throws InvalidFormatException * @throws IOException */ public ImportExcel(String fileName, InputStream is, int headerNum, int sheetIndex) throws InvalidFormatException, IOException { if (StringUtils.isBlank(fileName)){ throw new RuntimeException("导入文档为空!"); }else if(fileName.toLowerCase().endsWith("xls")){ this.wb = new HSSFWorkbook(is); }else if(fileName.toLowerCase().endsWith("xlsx")){ this.wb = new XSSFWorkbook(is); }else{ FileUtils.deleteFile(fileName); is.close(); throw new RuntimeException("文档格式不正确!"); } if (this.wb.getNumberOfSheets()<sheetIndex){ FileUtils.deleteFile(fileName); is.close(); throw new RuntimeException("文档中没有工作表!"); } this.sheet = this.wb.getSheetAt(sheetIndex); this.headerNum = headerNum; log.debug("Initialize success."); } /** * 获取行对象 * @param rownum * @return */ public Row getRow(int rownum){ return this.sheet.getRow(rownum); } /** * 获取数据行号 * @return */ public int getDataRowNum(){ return headerNum+1; } /** * 获取最后一个数据行号 * @return */ public int getLastDataRowNum(){ return this.sheet.getLastRowNum()+headerNum; } /** * 获取最后一个列号 * @return */ public int getLastCellNum(){ return this.getRow(headerNum).getLastCellNum(); } /** * 获取单元格值 * @param row 获取的行 * @param column 获取单元格列号 * @return 单元格值 */ public Object getCellValue(Row row, int column){ Object val = ""; try{ Cell cell = row.getCell(column); if (cell != null){ if (cell.getCellType() == Cell.CELL_TYPE_NUMERIC){ val = cell.getNumericCellValue(); }else if (cell.getCellType() == Cell.CELL_TYPE_STRING){ val = cell.getStringCellValue(); }else if (cell.getCellType() == Cell.CELL_TYPE_FORMULA){ val = cell.getCellFormula(); }else if (cell.getCellType() == Cell.CELL_TYPE_BOOLEAN){ val = cell.getBooleanCellValue(); }else if (cell.getCellType() == Cell.CELL_TYPE_ERROR){ val = cell.getErrorCellValue(); } } }catch (Exception e) { return val; } return val; } /** * 获取导入数据列表 * @param cls 导入对象类型 * @param groups 导入分组 */ public <E> List<E> getDataList(Class<E> cls, int... groups) throws InstantiationException, IllegalAccessException{ List<Object[]> annotationList = Lists.newArrayList(); // Get annotation method Method[] ms = cls.getDeclaredMethods(); for (Method m : ms){ ExcelField ef = m.getAnnotation(ExcelField.class); if (ef != null && (ef.type()==0 || ef.type()==2)){ annotationList.add(new Object[]{ef, m}); } } //log.debug("Import column count:"+annotationList.size()); // Get excel data List<E> dataList = Lists.newArrayList(); for (int i = this.getDataRowNum(); i < this.getLastDataRowNum(); i++) { E e = (E)cls.newInstance(); int column = 0; Row row = this.getRow(i); StringBuilder sb = new StringBuilder(); for (Object[] os : annotationList){ Object val = this.getCellValue(row, column++); if (val != null){ // Get param type and type cast Class<?> valType = Class.class; if (os[1] instanceof Method){ Method method = ((Method)os[1]); if ("get".equals(method.getName().substring(0, 3))){ valType = method.getReturnType(); }else if("set".equals(method.getName().substring(0, 3))){ valType = ((Method)os[1]).getParameterTypes()[0]; } } //log.debug("Import value type: ["+i+","+column+"] " + valType); try { if (valType == String.class){ String s = String.valueOf(val.toString()); if(StringUtils.endsWith(s, ".0")){ val = StringUtils.substringBefore(s, ".0"); }else{ val = String.valueOf(val.toString()); } }else if (valType == Integer.class){ val = Double.valueOf(val.toString()).intValue(); }else if (valType == Long.class){ val = Double.valueOf(val.toString()).longValue(); }else if (valType == Double.class){ val = Double.valueOf(val.toString()); }else if (valType == Float.class){ val = Float.valueOf(val.toString()); }else if (valType == Date.class){ val = DateUtil.getJavaDate((Double)val); } } catch (Exception ex) { log.info("Get cell value ["+i+","+column+"] error: " + ex.toString()); val = null; } // set entity value if (os[1] instanceof Method){ String mthodName = ((Method)os[1]).getName(); if ("get".equals(mthodName.substring(0, 3))){ mthodName = "set"+StringUtils.substringAfter(mthodName, "get"); } Reflections.invokeMethod(e, mthodName, new Class[] {valType}, new Object[] {val}); } } sb.append(val+", "); } dataList.add(e); log.debug("Read success: ["+i+"] "+sb.toString()); } return dataList; } }
/** * 直接调用对象方法, 无视private/protected修饰符. * 用于一次性调用的情况,否则应使用getAccessibleMethod()函数获得Method后反复调用. * 同时匹配方法名+参数类型, */ public static Object invokeMethod(final Object obj, final String methodName, final Class<?>[] parameterTypes, final Object[] args) { Method method = getAccessibleMethod(obj, methodName, parameterTypes); if (method == null) { throw new IllegalArgumentException("Could not find method [" + methodName + "] on target [" + obj + "]"); } try { return method.invoke(obj, args);
} catch (Exception e) { throw convertReflectionExceptionToUnchecked(e); } }
/** * 循环向上转型, 获取对象的DeclaredMethod,并强制设置为可访问. * 如向上转型到Object仍无法找到, 返回null. * 匹配函数名+参数类型。 * * 用于方法需要被多次调用的情况. 先使用本函数先取得Method,然后调用Method.invoke(Object obj, Object... args) */ public static Method getAccessibleMethod(final Object obj, final String methodName, final Class<?>... parameterTypes) { Validate.notNull(obj, "object can't be null"); Validate.notBlank(methodName, "methodName can't be blank"); for (Class<?> searchType = obj.getClass(); searchType != Object.class; searchType = searchType.getSuperclass()) { try { Method method = searchType.getDeclaredMethod(methodName, parameterTypes); makeAccessible(method); return method; } catch (NoSuchMethodException e) { // Method不在当前类定义,继续向上转型 continue;// new add } } return null; }
/** * 改变private/protected的方法为public,尽量不调用实际改动的语句,避免JDK的SecurityManager抱怨。 */ public static void makeAccessible(Method method) { if ((!Modifier.isPublic(method.getModifiers()) || !Modifier.isPublic(method.getDeclaringClass().getModifiers())) && !method.isAccessible()) { method.setAccessible(true); } }
invoke方法
作用:调用包装在当前Method对象中的方法。
原型:Object invoke(Object obj,Object...args)
参数解释:obj:实例化后的对象
args:用于方法调用的参数
返回:根据obj和args调用的方法的返回值
抛出错误:IllegalAccessException
原因:Method对象强制Java语言执行控制 或 无权访问obj对象
IllegalArgumentException
原因:方法是实例化方法,而指定需要调用的对象并不是实例化后的类或接口
getDeclaredMethod() 获取的是类自身声明的所有方法,包含public、protected和private方法。
getMethod () 获取的是类的所有共有方法,这就包括自身的所有public方法,和从基类继承的、从接口实现的所有public方法。