ExcelExportService.java 8.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206
  1. package cn.exlive.credit.manager.modules.credit.service;
  2. import cn.exlive.credit.manager.core.aspect.annotation.Dict;
  3. import cn.exlive.credit.manager.core.aspect.annotation.Fill;
  4. import cn.exlive.credit.manager.core.system.vo.DictModel;
  5. import cn.exlive.credit.manager.modules.credit.service.impl.EnterpriseService;
  6. import cn.exlive.credit.manager.modules.ledger.cache.MemCached;
  7. import cn.exlive.credit.manager.modules.system.service.ISysDictItemService;
  8. import cn.exlive.credit.manager.modules.system.service.ISysDictService;
  9. import cn.exlive.credit.manager.modules.vehicle.service.IVehicleRecordService;
  10. import cn.hutool.core.util.ReflectUtil;
  11. import com.alibaba.excel.EasyExcel;
  12. import com.alibaba.excel.ExcelWriter;
  13. import com.alibaba.excel.write.builder.ExcelWriterBuilder;
  14. import com.alibaba.excel.write.metadata.WriteSheet;
  15. import com.alibaba.excel.write.metadata.fill.FillWrapper;
  16. import com.alibaba.fastjson.JSON;
  17. import com.alibaba.fastjson.JSONObject;
  18. import com.fasterxml.jackson.annotation.JsonFormat;
  19. import org.apache.commons.lang3.StringUtils;
  20. import org.apache.commons.lang3.time.FastDateFormat;
  21. import org.springframework.core.io.ClassPathResource;
  22. import org.springframework.stereotype.Service;
  23. import javax.annotation.Resource;
  24. import java.io.ByteArrayOutputStream;
  25. import java.io.IOException;
  26. import java.io.InputStream;
  27. import java.lang.reflect.Field;
  28. import java.util.ArrayList;
  29. import java.util.Date;
  30. import java.util.HashMap;
  31. import java.util.List;
  32. import java.util.Map;
  33. /**
  34. * Excel 导出服务
  35. * <pre>
  36. *
  37. * Created by zhenqin.
  38. * User: zhenqin
  39. * Date: 2025/1/25
  40. * Time: 17:51
  41. * Vendor: yiidata.com
  42. *
  43. * </pre>
  44. *
  45. * @author zhenqin
  46. */
  47. @Service
  48. public class ExcelExportService {
  49. @Resource
  50. ISysDictService sysDictService;
  51. @Resource
  52. ISysDictItemService sysDictItemService;
  53. @Resource
  54. EnterpriseService enterpriseService;
  55. @Resource
  56. IVehicleRecordService vehicleRecordService;
  57. /**
  58. * 开始导出,导出为 excel 字节码
  59. * @param sheetName
  60. * @param templateName 采用的模板,传入空则不采用
  61. * @param dataset 数据集
  62. * @param extInfo 附加信息
  63. * @return
  64. * @throws IOException
  65. */
  66. public byte[] export(String sheetName,
  67. String templateName,
  68. List dataset,
  69. Map<String, Object> extInfo) throws IOException {
  70. if(dataset == null || dataset.isEmpty()) {
  71. throw new IllegalArgumentException("没有有效的数据行。");
  72. }
  73. // 所有时间字段
  74. final Map<String, JsonFormat> dateFields = new HashMap<>();
  75. // 所有字典字段
  76. final Map<String, Dict> dictFields = new HashMap<>();
  77. // 所有需要转换的字段
  78. final Map<String, Fill> convertFields = new HashMap<>();
  79. // 所有字段字段,包含的字典
  80. final Map<String, Object> dictMap = new HashMap<>();
  81. final Class<? extends Object> aClass = dataset.get(0).getClass();
  82. // 不是 map 以及子类,则是 bean 类型,bean 上可能有注解字典
  83. if(!Map.class.isAssignableFrom(aClass)) {
  84. // 获取字段上的注解,并把注解 code 上的字典,put 到缓存中
  85. final Field[] fields = ReflectUtil.getFields(aClass);
  86. for (Field field : fields) {
  87. final Dict annos = field.getAnnotation(Dict.class);
  88. final JsonFormat df = field.getAnnotation(JsonFormat.class);
  89. final Fill fill = field.getAnnotation(Fill.class);
  90. if(field.getType() == Date.class && df != null) {
  91. // 需要时间格式化的字段
  92. dateFields.put(field.getName(), df);
  93. } else if(fill != null) {
  94. // 需要转换填充的字段
  95. convertFields.put(field.getName(), fill);
  96. } else if (annos != null) {
  97. // 需要转换的字典码
  98. final List<DictModel> dictModels = sysDictService.queryDictItemsByCode(annos.dicCode());
  99. if (dictModels == null || dictModels.isEmpty()) {
  100. throw new IllegalStateException("非法的字典编码:" + annos.dicCode());
  101. }
  102. dictFields.put(field.getName(), annos);
  103. for (DictModel dictModel : dictModels) {
  104. // 放入缓存
  105. dictMap.put("DICT:" + annos.dicCode() + ":" + dictModel.getValue(), dictModel.getText());
  106. }
  107. }
  108. }
  109. }
  110. //转换后的列表数据
  111. List<Map<String, Object>> list = new ArrayList<>(dataset.size());
  112. for (Object o : dataset) {
  113. if(o == null) {
  114. continue;
  115. } else if(o instanceof Map) {
  116. list.add((Map)o);
  117. } else {
  118. final JSONObject jsonObject = (JSONObject) JSON.toJSON(o);
  119. // 字典字段
  120. for (Map.Entry<String, Dict> entry : dictFields.entrySet()) {
  121. final String dictVal = jsonObject.getString(entry.getKey());
  122. if(StringUtils.isBlank(dictVal)) {
  123. // 字典字段是空的,则不需替换
  124. continue;
  125. }
  126. // 替换字典字段
  127. final Dict annos = entry.getValue();
  128. final Object o1 = dictMap.get("DICT:" + annos.dicCode() + ":" + dictVal);
  129. jsonObject.put(entry.getKey(), o1);
  130. }
  131. // 日期字段
  132. for (Map.Entry<String, JsonFormat> entry : dateFields.entrySet()) {
  133. final Date dateVal = jsonObject.getDate(entry.getKey());
  134. if(dateVal == null) {
  135. // 字典字段是空的,则不需替换
  136. continue;
  137. }
  138. // 替换字典字段
  139. final JsonFormat df = entry.getValue();
  140. // 格式化时间
  141. jsonObject.put(entry.getKey(), FastDateFormat.getInstance(df.pattern()).format(dateVal));
  142. }
  143. // 需要填充转换的字段
  144. for (Map.Entry<String, Fill> entry : convertFields.entrySet()) {
  145. final String convertVal = jsonObject.getString(entry.getKey());
  146. if(StringUtils.isBlank(convertVal)) {
  147. // 字典字段是空的,则不需替换
  148. continue;
  149. }
  150. String newVal = convertVal;
  151. if("enterprise".equals(entry.getValue().type())) {
  152. // 企业
  153. newVal = MemCached.CLIENT_NAME.get(Integer.parseInt(convertVal));
  154. } else if("vehicle".equals(entry.getValue().type())) {
  155. // 车辆
  156. newVal = MemCached.VEHICLE_CODE.get(convertVal);
  157. }
  158. jsonObject.put(entry.getKey(), newVal);
  159. }
  160. list.add(jsonObject);
  161. }
  162. }
  163. // dictMap 中已经有了 code 的缓存,下面如果遇到字典码,则直接获取
  164. ByteArrayOutputStream out = new ByteArrayOutputStream();
  165. // 有模板则使用模板上的,没有模板,则使用类上的标记
  166. final ExcelWriterBuilder builder = StringUtils.isNotBlank(templateName) ? EasyExcel.write(out) : EasyExcel.write(out, aClass);
  167. if(StringUtils.isNotBlank(templateName)) {
  168. // 有模板,采用模板写入
  169. final String realTemplate = "/excel/" + templateName;
  170. ClassPathResource templateStream = new ClassPathResource(realTemplate);
  171. try(final InputStream inputStream = templateStream.getInputStream();){
  172. try(final ExcelWriter excelWriter = builder.withTemplate(inputStream).build();) {
  173. WriteSheet writeSheet = StringUtils.isNotBlank(sheetName) ?
  174. EasyExcel.writerSheet(sheetName).build() : EasyExcel.writerSheet().build();
  175. // ext info
  176. if(extInfo != null && !extInfo.isEmpty()) {
  177. excelWriter.fill(extInfo, writeSheet);
  178. }
  179. excelWriter.fill(new FillWrapper("dataset", list), writeSheet);
  180. }
  181. }
  182. } else {
  183. // 没有模板,则直接写入
  184. if(StringUtils.isNotBlank(sheetName)) {
  185. builder.sheet(sheetName).doWrite(dataset);
  186. } else {
  187. builder.sheet().doWrite(dataset);
  188. }
  189. }
  190. out.flush();
  191. return out.toByteArray();
  192. }
  193. }