ExcelUtil.java 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485
  1. package com.ruoyi.common.utils.poi;
  2. import java.io.File;
  3. import java.io.FileOutputStream;
  4. import java.io.IOException;
  5. import java.io.InputStream;
  6. import java.io.OutputStream;
  7. import java.lang.reflect.Field;
  8. import java.math.BigDecimal;
  9. import java.text.SimpleDateFormat;
  10. import java.util.ArrayList;
  11. import java.util.HashMap;
  12. import java.util.List;
  13. import java.util.Map;
  14. import java.util.UUID;
  15. import org.apache.poi.hssf.usermodel.DVConstraint;
  16. import org.apache.poi.hssf.usermodel.HSSFCell;
  17. import org.apache.poi.hssf.usermodel.HSSFCellStyle;
  18. import org.apache.poi.hssf.usermodel.HSSFDataValidation;
  19. import org.apache.poi.hssf.usermodel.HSSFFont;
  20. import org.apache.poi.hssf.usermodel.HSSFRow;
  21. import org.apache.poi.hssf.usermodel.HSSFSheet;
  22. import org.apache.poi.hssf.usermodel.HSSFWorkbook;
  23. import org.apache.poi.hssf.util.HSSFColor.HSSFColorPredefined;
  24. import org.apache.poi.ss.usermodel.Cell;
  25. import org.apache.poi.ss.usermodel.CellType;
  26. import org.apache.poi.ss.usermodel.FillPatternType;
  27. import org.apache.poi.ss.usermodel.HorizontalAlignment;
  28. import org.apache.poi.ss.usermodel.Row;
  29. import org.apache.poi.ss.usermodel.Sheet;
  30. import org.apache.poi.ss.usermodel.VerticalAlignment;
  31. import org.apache.poi.ss.usermodel.Workbook;
  32. import org.apache.poi.ss.usermodel.WorkbookFactory;
  33. import org.apache.poi.ss.util.CellRangeAddressList;
  34. import org.slf4j.Logger;
  35. import org.slf4j.LoggerFactory;
  36. import com.ruoyi.common.utils.StringUtils;
  37. import com.ruoyi.framework.aspectj.lang.annotation.Excel;
  38. import com.ruoyi.framework.config.RuoYiConfig;
  39. import com.ruoyi.framework.shiro.web.session.OnlineWebSessionManager;
  40. import com.ruoyi.framework.web.domain.AjaxResult;
  41. /**
  42. * Excel相关处理
  43. *
  44. * @author ruoyi
  45. */
  46. public class ExcelUtil<T>
  47. {
  48. private static final Logger log = LoggerFactory.getLogger(OnlineWebSessionManager.class);
  49. public Class<T> clazz;
  50. public ExcelUtil(Class<T> clazz)
  51. {
  52. this.clazz = clazz;
  53. }
  54. /**
  55. * 对excel表单默认第一个索引名转换成list
  56. *
  57. * @param input 输入流
  58. * @return 转换后集合
  59. */
  60. public List<T> importExcel(InputStream input) throws Exception
  61. {
  62. return importExcel(StringUtils.EMPTY, input);
  63. }
  64. /**
  65. * 对excel表单指定表格索引名转换成list
  66. *
  67. * @param sheetName 表格索引名
  68. * @param input 输入流
  69. * @return 转换后集合
  70. */
  71. public List<T> importExcel(String sheetName, InputStream input) throws Exception
  72. {
  73. List<T> list = new ArrayList<T>();
  74. Workbook workbook = WorkbookFactory.create(input);
  75. Sheet sheet = null;
  76. if (StringUtils.isNotEmpty(sheetName))
  77. {
  78. // 如果指定sheet名,则取指定sheet中的内容.
  79. sheet = workbook.getSheet(sheetName);
  80. }
  81. else
  82. {
  83. // 如果传入的sheet名不存在则默认指向第1个sheet.
  84. sheet = workbook.getSheetAt(0);
  85. }
  86. if (sheet == null)
  87. {
  88. throw new IOException("文件sheet不存在");
  89. }
  90. int rows = sheet.getPhysicalNumberOfRows();
  91. if (rows > 0)
  92. {
  93. // 默认序号
  94. int serialNum = 0;
  95. // 有数据时才处理 得到类的所有field.
  96. Field[] allFields = clazz.getDeclaredFields();
  97. // 定义一个map用于存放列的序号和field.
  98. Map<Integer, Field> fieldsMap = new HashMap<Integer, Field>();
  99. for (int col = 0; col < allFields.length; col++)
  100. {
  101. Field field = allFields[col];
  102. // 将有注解的field存放到map中.
  103. if (field.isAnnotationPresent(Excel.class))
  104. {
  105. // 设置类的私有字段属性可访问.
  106. field.setAccessible(true);
  107. fieldsMap.put(++serialNum, field);
  108. }
  109. }
  110. for (int i = 1; i < rows; i++)
  111. {
  112. // 从第2行开始取数据,默认第一行是表头.
  113. Row row = sheet.getRow(i);
  114. int cellNum = serialNum;
  115. T entity = null;
  116. for (int j = 0; j < cellNum; j++)
  117. {
  118. Cell cell = row.getCell(j);
  119. if (cell == null)
  120. {
  121. continue;
  122. }
  123. else
  124. {
  125. // 先设置Cell的类型,然后就可以把纯数字作为String类型读进来了
  126. row.getCell(j).setCellType(CellType.STRING);
  127. cell = row.getCell(j);
  128. }
  129. String c = cell.getStringCellValue();
  130. if (StringUtils.isEmpty(c))
  131. {
  132. continue;
  133. }
  134. // 如果不存在实例则新建.
  135. entity = (entity == null ? clazz.newInstance() : entity);
  136. // 从map中得到对应列的field.
  137. Field field = fieldsMap.get(j + 1);
  138. // 取得类型,并根据对象类型设置值.
  139. Class<?> fieldType = field.getType();
  140. if (String.class == fieldType)
  141. {
  142. field.set(entity, String.valueOf(c));
  143. }
  144. else if ((Integer.TYPE == fieldType) || (Integer.class == fieldType))
  145. {
  146. field.set(entity, Integer.parseInt(c));
  147. }
  148. else if ((Long.TYPE == fieldType) || (Long.class == fieldType))
  149. {
  150. field.set(entity, Long.valueOf(c));
  151. }
  152. else if ((Float.TYPE == fieldType) || (Float.class == fieldType))
  153. {
  154. field.set(entity, Float.valueOf(c));
  155. }
  156. else if ((Short.TYPE == fieldType) || (Short.class == fieldType))
  157. {
  158. field.set(entity, Short.valueOf(c));
  159. }
  160. else if ((Double.TYPE == fieldType) || (Double.class == fieldType))
  161. {
  162. field.set(entity, Double.valueOf(c));
  163. }
  164. else if (Character.TYPE == fieldType)
  165. {
  166. if ((c != null) && (c.length() > 0))
  167. {
  168. field.set(entity, Character.valueOf(c.charAt(0)));
  169. }
  170. }
  171. else if (java.util.Date.class == fieldType)
  172. {
  173. if (cell.getCellTypeEnum() == CellType.NUMERIC)
  174. {
  175. SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
  176. cell.setCellValue(sdf.format(cell.getNumericCellValue()));
  177. c = sdf.format(cell.getNumericCellValue());
  178. }
  179. else
  180. {
  181. c = cell.getStringCellValue();
  182. }
  183. }
  184. else if (java.math.BigDecimal.class == fieldType)
  185. {
  186. c = cell.getStringCellValue();
  187. }
  188. }
  189. if (entity != null)
  190. {
  191. list.add(entity);
  192. }
  193. }
  194. }
  195. return list;
  196. }
  197. /**
  198. * 对list数据源将其里面的数据导入到excel表单
  199. *
  200. * @param list 导出数据集合
  201. * @param sheetName 工作表的名称
  202. * @return 结果
  203. */
  204. public AjaxResult exportExcel(List<T> list, String sheetName)
  205. {
  206. OutputStream out = null;
  207. HSSFWorkbook workbook = null;
  208. try
  209. {
  210. // 得到所有定义字段
  211. Field[] allFields = clazz.getDeclaredFields();
  212. List<Field> fields = new ArrayList<Field>();
  213. // 得到所有field并存放到一个list中.
  214. for (Field field : allFields)
  215. {
  216. if (field.isAnnotationPresent(Excel.class))
  217. {
  218. fields.add(field);
  219. }
  220. }
  221. // 产生工作薄对象
  222. workbook = new HSSFWorkbook();
  223. // excel2003中每个sheet中最多有65536行
  224. int sheetSize = 65536;
  225. // 取出一共有多少个sheet.
  226. double sheetNo = Math.ceil(list.size() / sheetSize);
  227. for (int index = 0; index <= sheetNo; index++)
  228. {
  229. // 产生工作表对象
  230. HSSFSheet sheet = workbook.createSheet();
  231. if (sheetNo == 0)
  232. {
  233. workbook.setSheetName(index, sheetName);
  234. }
  235. else
  236. {
  237. // 设置工作表的名称.
  238. workbook.setSheetName(index, sheetName + index);
  239. }
  240. HSSFRow row;
  241. HSSFCell cell; // 产生单元格
  242. // 产生一行
  243. row = sheet.createRow(0);
  244. // 写入各个字段的列头名称
  245. for (int i = 0; i < fields.size(); i++)
  246. {
  247. Field field = fields.get(i);
  248. Excel attr = field.getAnnotation(Excel.class);
  249. // 创建列
  250. cell = row.createCell(i);
  251. // 设置列中写入内容为String类型
  252. cell.setCellType(CellType.STRING);
  253. HSSFCellStyle cellStyle = workbook.createCellStyle();
  254. cellStyle.setAlignment(HorizontalAlignment.CENTER);
  255. cellStyle.setVerticalAlignment(VerticalAlignment.CENTER);
  256. if (attr.name().indexOf("注:") >= 0)
  257. {
  258. HSSFFont font = workbook.createFont();
  259. font.setColor(HSSFFont.COLOR_RED);
  260. cellStyle.setFont(font);
  261. cellStyle.setFillForegroundColor(HSSFColorPredefined.YELLOW.getIndex());
  262. sheet.setColumnWidth(i, 6000);
  263. }
  264. else
  265. {
  266. HSSFFont font = workbook.createFont();
  267. // 粗体显示
  268. font.setBold(true);
  269. // 选择需要用到的字体格式
  270. cellStyle.setFont(font);
  271. cellStyle.setFillForegroundColor(HSSFColorPredefined.LIGHT_YELLOW.getIndex());
  272. // 设置列宽
  273. sheet.setColumnWidth(i, 3766);
  274. }
  275. cellStyle.setFillPattern(FillPatternType.SOLID_FOREGROUND);
  276. cellStyle.setWrapText(true);
  277. cell.setCellStyle(cellStyle);
  278. // 写入列名
  279. cell.setCellValue(attr.name());
  280. // 如果设置了提示信息则鼠标放上去提示.
  281. if (StringUtils.isNotEmpty(attr.prompt()))
  282. {
  283. // 这里默认设了2-101列提示.
  284. setHSSFPrompt(sheet, "", attr.prompt(), 1, 100, i, i);
  285. }
  286. // 如果设置了combo属性则本列只能选择不能输入
  287. if (attr.combo().length > 0)
  288. {
  289. // 这里默认设了2-101列只能选择不能输入.
  290. setHSSFValidation(sheet, attr.combo(), 1, 100, i, i);
  291. }
  292. }
  293. int startNo = index * sheetSize;
  294. int endNo = Math.min(startNo + sheetSize, list.size());
  295. // 写入各条记录,每条记录对应excel表中的一行
  296. HSSFCellStyle cs = workbook.createCellStyle();
  297. cs.setAlignment(HorizontalAlignment.CENTER);
  298. cs.setVerticalAlignment(VerticalAlignment.CENTER);
  299. for (int i = startNo; i < endNo; i++)
  300. {
  301. row = sheet.createRow(i + 1 - startNo);
  302. // 得到导出对象.
  303. T vo = (T) list.get(i);
  304. for (int j = 0; j < fields.size(); j++)
  305. {
  306. // 获得field.
  307. Field field = fields.get(j);
  308. // 设置实体类私有属性可访问
  309. field.setAccessible(true);
  310. Excel attr = field.getAnnotation(Excel.class);
  311. try
  312. {
  313. // 根据Excel中设置情况决定是否导出,有些情况需要保持为空,希望用户填写这一列.
  314. if (attr.isExport())
  315. {
  316. // 创建cell
  317. cell = row.createCell(j);
  318. cell.setCellStyle(cs);
  319. try
  320. {
  321. if (String.valueOf(field.get(vo)).length() > 10)
  322. {
  323. throw new Exception("长度超过10位就不用转数字了");
  324. }
  325. // 如果可以转成数字则导出为数字类型
  326. BigDecimal bc = new BigDecimal(String.valueOf(field.get(vo)));
  327. cell.setCellType(CellType.NUMERIC);
  328. cell.setCellValue(bc.doubleValue());
  329. }
  330. catch (Exception e)
  331. {
  332. cell.setCellType(CellType.STRING);
  333. if (vo == null)
  334. {
  335. // 如果数据存在就填入,不存在填入空格.
  336. cell.setCellValue("");
  337. }
  338. else
  339. {
  340. // 如果数据存在就填入,不存在填入空格.
  341. cell.setCellValue(field.get(vo) == null ? "" : String.valueOf(field.get(vo)));
  342. }
  343. }
  344. }
  345. }
  346. catch (Exception e)
  347. {
  348. log.error("导出Excel失败{}", e.getMessage());
  349. }
  350. }
  351. }
  352. }
  353. String filename = encodingFilename(sheetName);
  354. out = new FileOutputStream(getAbsoluteFile(filename));
  355. workbook.write(out);
  356. return AjaxResult.success(filename);
  357. }
  358. catch (Exception e)
  359. {
  360. log.error("导出Excel异常{}", e.getMessage());
  361. return AjaxResult.error("导出Excel失败,请联系网站管理员!");
  362. }
  363. finally
  364. {
  365. if (workbook != null)
  366. {
  367. try
  368. {
  369. workbook.close();
  370. }
  371. catch (IOException e1)
  372. {
  373. e1.printStackTrace();
  374. }
  375. }
  376. if (out != null)
  377. {
  378. try
  379. {
  380. out.close();
  381. }
  382. catch (IOException e1)
  383. {
  384. e1.printStackTrace();
  385. }
  386. }
  387. }
  388. }
  389. /**
  390. * 设置单元格上提示
  391. *
  392. * @param sheet 要设置的sheet.
  393. * @param promptTitle 标题
  394. * @param promptContent 内容
  395. * @param firstRow 开始行
  396. * @param endRow 结束行
  397. * @param firstCol 开始列
  398. * @param endCol 结束列
  399. * @return 设置好的sheet.
  400. */
  401. public static HSSFSheet setHSSFPrompt(HSSFSheet sheet, String promptTitle, String promptContent, int firstRow,
  402. int endRow, int firstCol, int endCol)
  403. {
  404. // 构造constraint对象
  405. DVConstraint constraint = DVConstraint.createCustomFormulaConstraint("DD1");
  406. // 四个参数分别是:起始行、终止行、起始列、终止列
  407. CellRangeAddressList regions = new CellRangeAddressList(firstRow, endRow, firstCol, endCol);
  408. // 数据有效性对象
  409. HSSFDataValidation dataValidationView = new HSSFDataValidation(regions, constraint);
  410. dataValidationView.createPromptBox(promptTitle, promptContent);
  411. sheet.addValidationData(dataValidationView);
  412. return sheet;
  413. }
  414. /**
  415. * 设置某些列的值只能输入预制的数据,显示下拉框.
  416. *
  417. * @param sheet 要设置的sheet.
  418. * @param textlist 下拉框显示的内容
  419. * @param firstRow 开始行
  420. * @param endRow 结束行
  421. * @param firstCol 开始列
  422. * @param endCol 结束列
  423. * @return 设置好的sheet.
  424. */
  425. public static HSSFSheet setHSSFValidation(HSSFSheet sheet, String[] textlist, int firstRow, int endRow,
  426. int firstCol, int endCol)
  427. {
  428. // 加载下拉列表内容
  429. DVConstraint constraint = DVConstraint.createExplicitListConstraint(textlist);
  430. // 设置数据有效性加载在哪个单元格上,四个参数分别是:起始行、终止行、起始列、终止列
  431. CellRangeAddressList regions = new CellRangeAddressList(firstRow, endRow, firstCol, endCol);
  432. // 数据有效性对象
  433. HSSFDataValidation dataValidationList = new HSSFDataValidation(regions, constraint);
  434. sheet.addValidationData(dataValidationList);
  435. return sheet;
  436. }
  437. /**
  438. * 编码文件名
  439. */
  440. public String encodingFilename(String filename)
  441. {
  442. filename = UUID.randomUUID().toString() + "_" + filename + ".xls";
  443. return filename;
  444. }
  445. /**
  446. * 获取下载路径
  447. *
  448. * @param filename 文件名称
  449. */
  450. public String getAbsoluteFile(String filename)
  451. {
  452. String downloadPath = RuoYiConfig.getDownloadPath() + filename;
  453. File desc = new File(downloadPath);
  454. if (!desc.getParentFile().exists())
  455. {
  456. desc.getParentFile().mkdirs();
  457. }
  458. return downloadPath;
  459. }
  460. }