e8adb240273df9685b77ec59d7fa52e98b0ee31d.svn-base 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521
  1. package cn.com.goldenwater.dcproj.utils.impexcel;
  2. import cn.com.goldenwater.dcproj.socket.WebSocketServer;
  3. import org.apache.commons.collections.MapUtils;
  4. import org.apache.commons.lang.StringUtils;
  5. import org.apache.poi.hssf.usermodel.HSSFWorkbook;
  6. import org.apache.poi.ss.usermodel.Cell;
  7. import org.apache.poi.ss.usermodel.Row;
  8. import org.apache.poi.ss.usermodel.Sheet;
  9. import org.apache.poi.ss.usermodel.Workbook;
  10. import org.apache.poi.xssf.usermodel.XSSFWorkbook;
  11. import java.io.File;
  12. import java.io.FileInputStream;
  13. import java.io.IOException;
  14. import java.lang.reflect.Field;
  15. import java.lang.reflect.InvocationTargetException;
  16. import java.lang.reflect.Method;
  17. import java.text.SimpleDateFormat;
  18. import java.util.*;
  19. import java.util.regex.Matcher;
  20. import java.util.regex.Pattern;
  21. import static cn.com.goldenwater.dcproj.utils.export.FieldFormatDispatch.getFormatValue;
  22. import static cn.com.goldenwater.dcproj.utils.impexcel.ImpUtil.XLS;
  23. import static cn.com.goldenwater.dcproj.utils.impexcel.ImpUtil.checkIsDate;
  24. /**
  25. * <p>
  26. * 导入工具类
  27. *
  28. * </p>
  29. *
  30. * @author liyz
  31. * @date 2019/4/10 19:43
  32. */
  33. public class ImportExcel {
  34. private static final SimpleDateFormat SIMPLE_DATE_FORMAT = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss:SSS");
  35. private static final String EMPTY = "";
  36. // public static void main(String[] args) {
  37. // String filePath = "C:\\Users\\a\\Desktop\\小水库督查情况表1554796096158.xls";
  38. // int startRow = 4;
  39. // int endRow = 0;
  40. //
  41. // try {
  42. // List<HashMap> bookList = (List<HashMap>) ImportExcel.importExcel(filePath, startRow, endRow, HashMap.class, "", "sk");
  43. // } catch (IOException e) {
  44. // e.printStackTrace();
  45. // }
  46. // }
  47. /**
  48. * 正则表达式 用于匹配属性的第一个字母
  49. */
  50. private static final String REGEX = "[a-zA-Z]";
  51. /**
  52. * 功能: Excel数据导入到数据库
  53. * 参数: originUrl[Excel表的所在路径]
  54. * 参数: startRow[从第几行开始]
  55. * 参数: endRow[到第几行结束
  56. * (0表示所有行;
  57. * 正数表示到第几行结束;
  58. * 负数表示到倒数第几行结束)]
  59. * 参数: clazz[要返回的对象集合的类型]
  60. */
  61. public static List<?> importExcel(String originUrl, int startRow, int endRow, Class<?> clazz, String sid, String type) throws IOException {
  62. //是否打印提示信息
  63. boolean showInfo = true;
  64. return doImportExcel(originUrl, startRow, endRow, showInfo, clazz, sid, type);
  65. }
  66. /**
  67. * 功能:判断文件是否存在
  68. */
  69. public static File isExist(String originUrl) throws IOException {
  70. // 判断文件是否存在
  71. File file = new File(originUrl);
  72. if (!file.exists()) {
  73. throw new IOException("文件名为" + file.getName() + "Excel文件不存在!");
  74. }
  75. return file;
  76. }
  77. /**
  78. * 功能:真正实现导入
  79. */
  80. private static List<Object> doImportExcel(String originUrl, int startRow, int endRow, boolean showInfo, Class<?> clazz, String sid, String type) throws IOException {
  81. // 判断文件是否存在
  82. File file = isExist(originUrl);
  83. HSSFWorkbook wb = null;
  84. FileInputStream fis = null;
  85. List<Row> rowList = new ArrayList<Row>();
  86. try {
  87. fis = new FileInputStream(file);
  88. // 去读Excel
  89. wb = new HSSFWorkbook(fis);
  90. Sheet sheet = wb.getSheetAt(0);
  91. // 获取最后行号
  92. int lastRowNum = sheet.getLastRowNum();
  93. // 如果>0,表示有数据
  94. if (lastRowNum > 0) {
  95. out("\n开始读取并校验名为【" + sheet.getSheetName() + "】的内容:", showInfo, sid);
  96. WebSocketServer.sendInfo(SIMPLE_DATE_FORMAT.format(new Date()) + "-②开始读取并校验名为【" + sheet.getSheetName() + "】的内容", sid);
  97. }
  98. Row row = null;
  99. // 循环读取
  100. for (int i = startRow; i <= lastRowNum + endRow; i++) {
  101. row = sheet.getRow(i);
  102. if (row != null) {
  103. rowList.add(row);
  104. out("第" + (i + 1) + "行:", showInfo, false, sid);
  105. // 获取每一单元格的值
  106. for (int j = 0; j < row.getLastCellNum(); j++) {
  107. String value = getCellValue(row.getCell(j));
  108. // if (!value.equals("")) {
  109. out(value + " | ", showInfo, false, sid);
  110. // }
  111. }
  112. out("", showInfo, sid);
  113. }
  114. }
  115. } catch (IOException e) {
  116. e.printStackTrace();
  117. } finally {
  118. wb.close();
  119. }
  120. return returnObjectList(rowList, type, sid);
  121. }
  122. /**
  123. * 功能:获取单元格的值
  124. */
  125. private static String getCellValue(Cell cell) {
  126. Object result = "";
  127. if (cell != null) {
  128. switch (cell.getCellType()) {
  129. case STRING:
  130. result = cell.getStringCellValue();
  131. break;
  132. case NUMERIC:
  133. result = cell.getNumericCellValue();
  134. break;
  135. case BOOLEAN:
  136. result = cell.getBooleanCellValue();
  137. break;
  138. case FORMULA:
  139. result = cell.getCellFormula();
  140. break;
  141. case ERROR:
  142. result = cell.getErrorCellValue();
  143. break;
  144. case BLANK:
  145. break;
  146. default:
  147. break;
  148. }
  149. }
  150. return result.toString();
  151. }
  152. /**
  153. * 功能:返回指定的对象集合
  154. */
  155. private static List<Object> returnObjectList(List<Row> rowList, String type, String sid) {
  156. List<Object> objectList = null;
  157. List<String> keys = new ArrayList<>();
  158. Row keyRow = rowList.get(0);
  159. for (int i = 0; i < keyRow.getPhysicalNumberOfCells(); i++) {
  160. keys.add(keyRow.getCell(i).toString());
  161. }
  162. try {
  163. objectList = new ArrayList<>();
  164. for (int i = 1; i < rowList.size(); i++) {
  165. Row row = rowList.get(i);
  166. HashMap<String, String> map = new LinkedHashMap<>();
  167. int check = 0;
  168. for (int j = 0; j < keys.size(); j++) {
  169. // 此单元格的值
  170. String cellValue = getCellValue(row.getCell(j));
  171. // 格式化后的值
  172. String formatValue = getFormatValue(type, keys.get(j), cellValue, true).toString();
  173. map.put(keys.get(j), formatValue);
  174. // 先不格式化
  175. // map.put(keys.get(j), getCellValue(row.getCell(j)));
  176. // 错误的话输出一下
  177. if (formatValue.contains("$E$")) {
  178. check++;
  179. WebSocketServer.sendInfo(SIMPLE_DATE_FORMAT.format(new Date()) + "-第" + (i + 5) + "行[" + cellValue + "]填写有误,请查看弹出信息,并重新上传模板!", sid);
  180. }
  181. }
  182. if (check == 0 && row.getCell(2) != null && !"".equals(row.getCell(2).toString())) {
  183. WebSocketServer.sendInfo(SIMPLE_DATE_FORMAT.format(new Date()) + "-第" + (i + 5) + "行验证完毕,数据无误。", sid);
  184. }
  185. objectList.add(map);
  186. }
  187. } catch (Exception e) {
  188. e.printStackTrace();
  189. }
  190. return objectList;
  191. }
  192. /**
  193. * 功能:返回指定的对象集合,(有单表实体类时可用)
  194. */
  195. private static List<Object> returnObjectList(List<Row> rowList, Class<?> clazz) {
  196. List<Object> objectList = null;
  197. Object obj = null;
  198. String attribute = null;
  199. String value = null;
  200. int j = 0;
  201. try {
  202. objectList = new ArrayList<Object>();
  203. Field[] declaredFields = clazz.getDeclaredFields();
  204. for (Row row : rowList) {
  205. j = 0;
  206. obj = clazz.newInstance();
  207. for (Field field : declaredFields) {
  208. attribute = field.getName().toString();
  209. value = getCellValue(row.getCell(j));
  210. setAttrributeValue(obj, attribute, value);
  211. j++;
  212. }
  213. objectList.add(obj);
  214. }
  215. } catch (Exception e) {
  216. e.printStackTrace();
  217. }
  218. return objectList;
  219. }
  220. /**
  221. * 功能:给指定对象的指定属性赋值
  222. */
  223. public static void setAttrributeValue(Object obj, String attribute, String value) {
  224. //得到该属性的set方法名
  225. String methodName = convertToMethodName(attribute, obj.getClass(), true);
  226. Method[] methods = obj.getClass().getMethods();
  227. for (Method method : methods) {
  228. /*
  229. 因为这里只是调用bean中属性的set方法,属性名称不能重复
  230. 所以set方法也不会重复,所以就直接用方法名称去锁定一个方法
  231. (注:在java中,锁定一个方法的条件是方法名及参数)
  232. */
  233. if (method.getName().equals(methodName)) {
  234. Class<?>[] parameterC = method.getParameterTypes();
  235. try {
  236. /*
  237. 如果是(整型,浮点型,布尔型,字节型,时间类型,Long类型),
  238. 按照各自的规则把value值转换成各自的类型
  239. 否则一律按类型强制转换(比如:String类型)
  240. */
  241. if (parameterC[0] == int.class || parameterC[0] == Integer.class) {
  242. value = value.substring(0, value.lastIndexOf("."));
  243. method.invoke(obj, Integer.valueOf(value));
  244. break;
  245. } else if (parameterC[0] == float.class || parameterC[0] == Float.class) {
  246. method.invoke(obj, Float.valueOf(value));
  247. break;
  248. } else if (parameterC[0] == double.class || parameterC[0] == Double.class) {
  249. if (value != null && !"".equals(value)) {
  250. method.invoke(obj, Double.valueOf(value));
  251. }
  252. break;
  253. } else if (parameterC[0] == long.class || parameterC[0] == Long.class) {
  254. if (value != null && !"".equals(value)) {
  255. method.invoke(obj, Long.valueOf(value));
  256. }
  257. break;
  258. } else if (parameterC[0] == byte.class || parameterC[0] == Byte.class) {
  259. method.invoke(obj, Byte.valueOf(value));
  260. break;
  261. } else if (parameterC[0] == boolean.class || parameterC[0] == Boolean.class) {
  262. method.invoke(obj, Boolean.valueOf(value));
  263. break;
  264. } else if (parameterC[0] == Date.class) {
  265. SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
  266. Date date = null;
  267. try {
  268. if (StringUtils.isNotBlank(value)) {
  269. // 可能是年月日格式的,处理一下
  270. value = value.replace("年","-").replace("月","-").replace("日","");
  271. if(checkIsDate(value)){
  272. date = sdf.parse(value.replace("/","-"));
  273. }
  274. }
  275. } catch (Exception e) {
  276. e.printStackTrace();
  277. }
  278. method.invoke(obj, date);
  279. break;
  280. } else {
  281. method.invoke(obj, parameterC[0].cast(value));
  282. break;
  283. }
  284. } catch (IllegalArgumentException e) {
  285. e.printStackTrace();
  286. } catch (IllegalAccessException e) {
  287. e.printStackTrace();
  288. } catch (InvocationTargetException e) {
  289. e.printStackTrace();
  290. } catch (SecurityException e) {
  291. e.printStackTrace();
  292. }
  293. }
  294. }
  295. }
  296. /**
  297. * 功能:根据属性生成对应的set/get方法
  298. */
  299. private static String convertToMethodName(String attribute, Class<?> objClass, boolean isSet) {
  300. // 通过正则表达式来匹配第一个字符
  301. Pattern p = Pattern.compile(REGEX);
  302. Matcher m = p.matcher(attribute);
  303. StringBuilder sb = new StringBuilder();
  304. // 如果是set方法名称
  305. if (isSet) {
  306. sb.append("set");
  307. } else {
  308. // get方法名称
  309. try {
  310. Field attributeField = objClass.getDeclaredField(attribute);
  311. // 如果类型为boolean
  312. if (attributeField.getType() == boolean.class || attributeField.getType() == Boolean.class) {
  313. sb.append("is");
  314. } else {
  315. sb.append("get");
  316. }
  317. } catch (SecurityException e) {
  318. e.printStackTrace();
  319. } catch (NoSuchFieldException e) {
  320. e.printStackTrace();
  321. }
  322. }
  323. // 针对以下划线开头的属性
  324. if (attribute.charAt(0) != '_' && m.find()) {
  325. sb.append(m.replaceFirst(m.group().toUpperCase()));
  326. } else {
  327. sb.append(attribute);
  328. }
  329. return sb.toString();
  330. }
  331. /**
  332. * 功能:输出提示信息(普通信息打印)
  333. */
  334. private static void out(String info, boolean showInfo, String sid) {
  335. if (showInfo) {
  336. // System.out.print(info + (showInfo ? "\n" : ""));
  337. }
  338. }
  339. /**
  340. * 功能:输出提示信息(同一行的不同单元格信息打印)
  341. */
  342. private static void out(String info, boolean showInfo, boolean nextLine, String sid) {
  343. if (showInfo) {
  344. if (nextLine) {
  345. // System.out.print(info + (showInfo ? "\n" : ""));
  346. WebSocketServer.sendInfo(info + (showInfo ? "\n" : ""), sid);
  347. } else {
  348. // System.out.print(info);
  349. }
  350. }
  351. }
  352. // 新方法
  353. /**
  354. * 功能:获取Excel数据行集合(可单独使用)
  355. *
  356. * @param originUrl Excel文件路径
  357. * @param startRow 起始读取行
  358. * @param endRow 结束读取行
  359. */
  360. public static List<Row> getRowList(String originUrl, int startRow, int endRow) throws IOException {
  361. // 判断文件是否存在
  362. File file = isExist(originUrl);
  363. // 开始读取Excel的内容
  364. Workbook wb = null;
  365. FileInputStream fis = null;
  366. List<Row> rowList = new ArrayList<Row>();
  367. try {
  368. fis = new FileInputStream(file);
  369. if (originUrl.substring(originUrl.lastIndexOf(".") + 1).equals(XLS)) {
  370. wb = new HSSFWorkbook(fis);
  371. } else {
  372. wb = new XSSFWorkbook(fis);
  373. }
  374. Sheet sheet = wb.getSheetAt(0);
  375. // int lastRowNum = sheet.getLastRowNum();
  376. int lastRowNum = sheet.getPhysicalNumberOfRows();
  377. Row row;
  378. for (int i = startRow; i <= lastRowNum + endRow; i++) {
  379. row = sheet.getRow(i);
  380. if (row != null) {
  381. rowList.add(row);
  382. }
  383. }
  384. } catch (IOException e) {
  385. e.printStackTrace();
  386. } finally {
  387. if (wb != null) {
  388. wb.close();
  389. }
  390. if (fis != null) {
  391. fis.close();
  392. }
  393. }
  394. return rowList;
  395. }
  396. /**
  397. * 功能:把List<Row>转为List<Map>并格式化字段(可单独使用)
  398. */
  399. public static List<LinkedHashMap<String, Object>> getDataList(List<Row> rowList, Class<?> clazz) {
  400. List<LinkedHashMap<String, Object>> objectList = null;
  401. List<String> nameKeys = new ArrayList<>();
  402. Row keyRow = rowList.get(0);
  403. for (int i = 0; i < keyRow.getPhysicalNumberOfCells(); i++) {
  404. nameKeys.add(keyRow.getCell(i).toString().trim());
  405. }
  406. try {
  407. objectList = new ArrayList<>();
  408. for (int i = 1; i < rowList.size(); i++) {
  409. Row row = rowList.get(i);
  410. LinkedHashMap<String, Object> map = new LinkedHashMap<>();
  411. int check = 0;
  412. for (int j = 0; j < nameKeys.size(); j++) {
  413. // 此单元格的值
  414. String cellValue = getCellValue(row.getCell(j));
  415. // 格式化后的值
  416. String name = nameKeys.get(j);
  417. map.put(name, formatValue(name, cellValue, clazz));
  418. }
  419. objectList.add(map);
  420. }
  421. } catch (Exception e) {
  422. e.printStackTrace();
  423. }
  424. return objectList;
  425. }
  426. /**
  427. * 功能:格式化字段(可单独使用,具体格式化方式由claszz决定,通常也检查字段是否合法,并注上错误标识)
  428. */
  429. public static Object formatValue(String name, Object value, Class<?> formatClazz) {
  430. Method[] methods = formatClazz.getMethods();
  431. for (Method method : methods) {
  432. if (("format" + name).toLowerCase().equals(method.getName().toLowerCase())) {
  433. try {
  434. Class<?>[] parameterC = method.getParameterTypes();
  435. if (parameterC[0] == Date.class) {
  436. if (value instanceof Date) {
  437. return method.invoke(formatClazz, (Date) value);
  438. } else {
  439. return value;
  440. }
  441. } else {
  442. // 找到对应的方法,并把原始值传进去,返回格式化后的值
  443. return method.invoke(formatClazz, value);
  444. }
  445. } catch (Exception e) {
  446. e.printStackTrace();
  447. }
  448. }
  449. }
  450. return value;
  451. }
  452. /**
  453. * 功能:直接调用此方法获取解析后的数据
  454. */
  455. public static List<LinkedHashMap<String, Object>> getParseData(String originUrl, int startRow, int endRow
  456. , Class<?> clazz) throws IOException {
  457. return getDataList(getRowList(originUrl, startRow, endRow), clazz);
  458. }
  459. /**
  460. * 功能:把解析数据转为展示数据,例如:字典项 1 转为 是
  461. */
  462. public static List<LinkedHashMap<String, Object>> getShowData(List<LinkedHashMap<String, Object>> parseData, Class<?> clazz) {
  463. List<LinkedHashMap<String, Object>> listShow = new ArrayList<>();
  464. for (LinkedHashMap lhm : parseData) {
  465. LinkedHashMap<String, Object> map = new LinkedHashMap<>();
  466. for (Object o : lhm.keySet()) {
  467. String key = o.toString();
  468. String value = lhm.get(key).toString();
  469. Object formatValue = ImportExcel.formatValue(key, value, clazz);
  470. map.put(key, formatValue);
  471. }
  472. listShow.add(map);
  473. }
  474. return listShow;
  475. }
  476. /**
  477. * 功能:把Map转成Bean (主要用于把从Excel解析出来的Map对象还原成实体类对象,方便入库)
  478. */
  479. public static Object convertMapToBean(Class<?> clazz, Map lhp) throws IllegalAccessException, InstantiationException {
  480. Field[] fields = clazz.getDeclaredFields();
  481. Object obj = clazz.newInstance();
  482. for (Field field : fields) {
  483. setAttrributeValue(obj, field.getName(), MapUtils.getString(lhp, field.getName()));
  484. }
  485. return obj;
  486. }
  487. }