ExcelUtil.java 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267
  1. package com.ruoyi.common.utils.poi;
  2. import cn.hutool.core.collection.CollUtil;
  3. import cn.hutool.core.io.resource.ClassPathResource;
  4. import cn.hutool.core.util.IdUtil;
  5. import com.alibaba.excel.EasyExcel;
  6. import com.alibaba.excel.ExcelWriter;
  7. import com.alibaba.excel.write.builder.ExcelWriterSheetBuilder;
  8. import com.alibaba.excel.write.metadata.WriteSheet;
  9. import com.alibaba.excel.write.metadata.fill.FillConfig;
  10. import com.alibaba.excel.write.metadata.fill.FillWrapper;
  11. import com.alibaba.excel.write.style.column.LongestMatchColumnWidthStyleStrategy;
  12. import com.ruoyi.common.convert.ExcelBigNumberConvert;
  13. import com.ruoyi.common.excel.CellMergeStrategy;
  14. import com.ruoyi.common.excel.DefaultExcelListener;
  15. import com.ruoyi.common.excel.ExcelListener;
  16. import com.ruoyi.common.excel.ExcelResult;
  17. import com.ruoyi.common.utils.StringUtils;
  18. import com.ruoyi.common.utils.file.FileUtils;
  19. import lombok.AccessLevel;
  20. import lombok.NoArgsConstructor;
  21. import javax.servlet.ServletOutputStream;
  22. import javax.servlet.http.HttpServletResponse;
  23. import java.io.IOException;
  24. import java.io.InputStream;
  25. import java.io.UnsupportedEncodingException;
  26. import java.util.Collection;
  27. import java.util.List;
  28. import java.util.Map;
  29. /**
  30. * Excel相关处理
  31. *
  32. * @author Lion Li
  33. */
  34. @NoArgsConstructor(access = AccessLevel.PRIVATE)
  35. public class ExcelUtil {
  36. /**
  37. * 同步导入(适用于小数据量)
  38. *
  39. * @param is 输入流
  40. * @return 转换后集合
  41. */
  42. public static <T> List<T> importExcel(InputStream is, Class<T> clazz) {
  43. return EasyExcel.read(is).head(clazz).autoCloseStream(false).sheet().doReadSync();
  44. }
  45. /**
  46. * 使用校验监听器 异步导入 同步返回
  47. *
  48. * @param is 输入流
  49. * @param clazz 对象类型
  50. * @param isValidate 是否 Validator 检验 默认为是
  51. * @return 转换后集合
  52. */
  53. public static <T> ExcelResult<T> importExcel(InputStream is, Class<T> clazz, boolean isValidate) {
  54. DefaultExcelListener<T> listener = new DefaultExcelListener<>(isValidate);
  55. EasyExcel.read(is, clazz, listener).sheet().doRead();
  56. return listener.getExcelResult();
  57. }
  58. /**
  59. * 使用自定义监听器 异步导入 自定义返回
  60. *
  61. * @param is 输入流
  62. * @param clazz 对象类型
  63. * @param listener 自定义监听器
  64. * @return 转换后集合
  65. */
  66. public static <T> ExcelResult<T> importExcel(InputStream is, Class<T> clazz, ExcelListener<T> listener) {
  67. EasyExcel.read(is, clazz, listener).sheet().doRead();
  68. return listener.getExcelResult();
  69. }
  70. /**
  71. * 导出excel
  72. *
  73. * @param list 导出数据集合
  74. * @param sheetName 工作表的名称
  75. * @param clazz 实体类
  76. * @param response 响应体
  77. */
  78. public static <T> void exportExcel(List<T> list, String sheetName, Class<T> clazz, HttpServletResponse response) {
  79. exportExcel(list, sheetName, clazz, false, response);
  80. }
  81. /**
  82. * 导出excel
  83. *
  84. * @param list 导出数据集合
  85. * @param sheetName 工作表的名称
  86. * @param clazz 实体类
  87. * @param merge 是否合并单元格
  88. * @param response 响应体
  89. */
  90. public static <T> void exportExcel(List<T> list, String sheetName, Class<T> clazz, boolean merge, HttpServletResponse response) {
  91. try {
  92. resetResponse(sheetName, response);
  93. ServletOutputStream os = response.getOutputStream();
  94. ExcelWriterSheetBuilder builder = EasyExcel.write(os, clazz)
  95. .autoCloseStream(false)
  96. // 自动适配
  97. .registerWriteHandler(new LongestMatchColumnWidthStyleStrategy())
  98. // 大数值自动转换 防止失真
  99. .registerConverter(new ExcelBigNumberConvert())
  100. .sheet(sheetName);
  101. if (merge) {
  102. // 合并处理器
  103. builder.registerWriteHandler(new CellMergeStrategy(list, true));
  104. }
  105. builder.doWrite(list);
  106. } catch (IOException e) {
  107. throw new RuntimeException("导出Excel异常");
  108. }
  109. }
  110. /**
  111. * 单表多数据模板导出 模板格式为 {.属性}
  112. *
  113. * @param filename 文件名
  114. * @param templatePath 模板路径 resource 目录下的路径包括模板文件名
  115. * 例如: excel/temp.xlsx
  116. * 重点: 模板文件必须放置到启动类对应的 resource 目录下
  117. * @param data 模板需要的数据
  118. */
  119. public static void exportTemplate(List<Object> data, String filename, String templatePath, HttpServletResponse response) {
  120. try {
  121. resetResponse(filename, response);
  122. ClassPathResource templateResource = new ClassPathResource(templatePath);
  123. ExcelWriter excelWriter = EasyExcel.write(response.getOutputStream())
  124. .withTemplate(templateResource.getStream())
  125. .autoCloseStream(false)
  126. // 大数值自动转换 防止失真
  127. .registerConverter(new ExcelBigNumberConvert())
  128. .build();
  129. WriteSheet writeSheet = EasyExcel.writerSheet().build();
  130. if (CollUtil.isEmpty(data)) {
  131. throw new IllegalArgumentException("数据为空");
  132. }
  133. // 单表多数据导出 模板格式为 {.属性}
  134. for (Object d : data) {
  135. excelWriter.fill(d, writeSheet);
  136. }
  137. excelWriter.finish();
  138. } catch (IOException e) {
  139. throw new RuntimeException("导出Excel异常");
  140. }
  141. }
  142. /**
  143. * 多表多数据模板导出 模板格式为 {key.属性}
  144. *
  145. * @param filename 文件名
  146. * @param templatePath 模板路径 resource 目录下的路径包括模板文件名
  147. * 例如: excel/temp.xlsx
  148. * 重点: 模板文件必须放置到启动类对应的 resource 目录下
  149. * @param data 模板需要的数据
  150. */
  151. public static void exportTemplateMultiList(Map<String, Object> data, String filename, String templatePath, HttpServletResponse response) {
  152. try {
  153. resetResponse(filename, response);
  154. ClassPathResource templateResource = new ClassPathResource(templatePath);
  155. ExcelWriter excelWriter = EasyExcel.write(response.getOutputStream())
  156. .withTemplate(templateResource.getStream())
  157. .autoCloseStream(false)
  158. // 大数值自动转换 防止失真
  159. .registerConverter(new ExcelBigNumberConvert())
  160. .build();
  161. WriteSheet writeSheet = EasyExcel.writerSheet().build();
  162. if (CollUtil.isEmpty(data)) {
  163. throw new IllegalArgumentException("数据为空");
  164. }
  165. for (Map.Entry<String, Object> map : data.entrySet()) {
  166. // 设置列表后续还有数据
  167. FillConfig fillConfig = FillConfig.builder().forceNewRow(Boolean.TRUE).build();
  168. if (map.getValue() instanceof Collection) {
  169. // 多表导出必须使用 FillWrapper
  170. excelWriter.fill(new FillWrapper(map.getKey(), (Collection<?>) map.getValue()), fillConfig, writeSheet);
  171. } else {
  172. excelWriter.fill(map.getValue(), writeSheet);
  173. }
  174. }
  175. excelWriter.finish();
  176. } catch (IOException e) {
  177. throw new RuntimeException("导出Excel异常");
  178. }
  179. }
  180. /**
  181. * 重置响应体
  182. */
  183. private static void resetResponse(String sheetName, HttpServletResponse response) throws UnsupportedEncodingException {
  184. String filename = encodingFilename(sheetName);
  185. response.reset();
  186. FileUtils.setAttachmentResponseHeader(response, filename);
  187. response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet;charset=UTF-8");
  188. }
  189. /**
  190. * 解析导出值 0=男,1=女,2=未知
  191. *
  192. * @param propertyValue 参数值
  193. * @param converterExp 翻译注解
  194. * @param separator 分隔符
  195. * @return 解析后值
  196. */
  197. public static String convertByExp(String propertyValue, String converterExp, String separator) {
  198. StringBuilder propertyString = new StringBuilder();
  199. String[] convertSource = converterExp.split(",");
  200. for (String item : convertSource) {
  201. String[] itemArray = item.split("=");
  202. if (StringUtils.containsAny(propertyValue, separator)) {
  203. for (String value : propertyValue.split(separator)) {
  204. if (itemArray[0].equals(value)) {
  205. propertyString.append(itemArray[1] + separator);
  206. break;
  207. }
  208. }
  209. } else {
  210. if (itemArray[0].equals(propertyValue)) {
  211. return itemArray[1];
  212. }
  213. }
  214. }
  215. return StringUtils.stripEnd(propertyString.toString(), separator);
  216. }
  217. /**
  218. * 反向解析值 男=0,女=1,未知=2
  219. *
  220. * @param propertyValue 参数值
  221. * @param converterExp 翻译注解
  222. * @param separator 分隔符
  223. * @return 解析后值
  224. */
  225. public static String reverseByExp(String propertyValue, String converterExp, String separator) {
  226. StringBuilder propertyString = new StringBuilder();
  227. String[] convertSource = converterExp.split(",");
  228. for (String item : convertSource) {
  229. String[] itemArray = item.split("=");
  230. if (StringUtils.containsAny(propertyValue, separator)) {
  231. for (String value : propertyValue.split(separator)) {
  232. if (itemArray[1].equals(value)) {
  233. propertyString.append(itemArray[0] + separator);
  234. break;
  235. }
  236. }
  237. } else {
  238. if (itemArray[1].equals(propertyValue)) {
  239. return itemArray[0];
  240. }
  241. }
  242. }
  243. return StringUtils.stripEnd(propertyString.toString(), separator);
  244. }
  245. /**
  246. * 编码文件名
  247. */
  248. public static String encodingFilename(String filename) {
  249. return IdUtil.fastSimpleUUID() + "_" + filename + ".xlsx";
  250. }
  251. }