zhzhenqin 7 месяцев назад
Родитель
Сommit
0e416d54d4
1 измененных файлов с 206 добавлено и 0 удалено
  1. 206 0
      java-excel/ExcelExportService.java

+ 206 - 0
java-excel/ExcelExportService.java

@@ -0,0 +1,206 @@
+package cn.exlive.credit.manager.modules.credit.service;
+
+import cn.exlive.credit.manager.core.aspect.annotation.Dict;
+import cn.exlive.credit.manager.core.aspect.annotation.Fill;
+import cn.exlive.credit.manager.core.system.vo.DictModel;
+import cn.exlive.credit.manager.modules.credit.service.impl.EnterpriseService;
+import cn.exlive.credit.manager.modules.ledger.cache.MemCached;
+import cn.exlive.credit.manager.modules.system.service.ISysDictItemService;
+import cn.exlive.credit.manager.modules.system.service.ISysDictService;
+import cn.exlive.credit.manager.modules.vehicle.service.IVehicleRecordService;
+import cn.hutool.core.util.ReflectUtil;
+import com.alibaba.excel.EasyExcel;
+import com.alibaba.excel.ExcelWriter;
+import com.alibaba.excel.write.builder.ExcelWriterBuilder;
+import com.alibaba.excel.write.metadata.WriteSheet;
+import com.alibaba.excel.write.metadata.fill.FillWrapper;
+import com.alibaba.fastjson.JSON;
+import com.alibaba.fastjson.JSONObject;
+import com.fasterxml.jackson.annotation.JsonFormat;
+import org.apache.commons.lang3.StringUtils;
+import org.apache.commons.lang3.time.FastDateFormat;
+import org.springframework.core.io.ClassPathResource;
+import org.springframework.stereotype.Service;
+
+import javax.annotation.Resource;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.lang.reflect.Field;
+import java.util.ArrayList;
+import java.util.Date;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * Excel 导出服务
+ * <pre>
+ *
+ * Created by zhenqin.
+ * User: zhenqin
+ * Date: 2025/1/25
+ * Time: 17:51
+ * Vendor: yiidata.com
+ *
+ * </pre>
+ *
+ * @author zhenqin
+ */
+@Service
+public class ExcelExportService {
+
+    @Resource
+    ISysDictService sysDictService;
+
+    @Resource
+    ISysDictItemService sysDictItemService;
+
+    @Resource
+    EnterpriseService enterpriseService;
+
+    @Resource
+    IVehicleRecordService vehicleRecordService;
+
+    /**
+     * 开始导出,导出为 excel 字节码
+     * @param sheetName
+     * @param templateName 采用的模板,传入空则不采用
+     * @param dataset 数据集
+     * @param extInfo 附加信息
+     * @return
+     * @throws IOException
+     */
+    public byte[] export(String sheetName,
+                         String templateName,
+                         List dataset,
+                         Map<String, Object> extInfo) throws IOException {
+        if(dataset == null || dataset.isEmpty()) {
+            throw new IllegalArgumentException("没有有效的数据行。");
+        }
+        // 所有时间字段
+        final Map<String, JsonFormat> dateFields = new HashMap<>();
+        // 所有字典字段
+        final Map<String, Dict> dictFields = new HashMap<>();
+        // 所有需要转换的字段
+        final Map<String, Fill> convertFields = new HashMap<>();
+        // 所有字段字段,包含的字典
+        final Map<String, Object> dictMap = new HashMap<>();
+        final Class<? extends Object> aClass = dataset.get(0).getClass();
+        // 不是 map 以及子类,则是 bean 类型,bean 上可能有注解字典
+        if(!Map.class.isAssignableFrom(aClass)) {
+            // 获取字段上的注解,并把注解 code 上的字典,put 到缓存中
+            final Field[] fields = ReflectUtil.getFields(aClass);
+            for (Field field : fields) {
+                final Dict annos = field.getAnnotation(Dict.class);
+                final JsonFormat df = field.getAnnotation(JsonFormat.class);
+                final Fill fill = field.getAnnotation(Fill.class);
+                if(field.getType() == Date.class && df != null) {
+                    // 需要时间格式化的字段
+                    dateFields.put(field.getName(), df);
+                } else if(fill != null) {
+                    // 需要转换填充的字段
+                    convertFields.put(field.getName(), fill);
+                } else if (annos != null) {
+                    // 需要转换的字典码
+                    final List<DictModel> dictModels = sysDictService.queryDictItemsByCode(annos.dicCode());
+                    if (dictModels == null || dictModels.isEmpty()) {
+                        throw new IllegalStateException("非法的字典编码:" + annos.dicCode());
+                    }
+                    dictFields.put(field.getName(), annos);
+                    for (DictModel dictModel : dictModels) {
+                        // 放入缓存
+                        dictMap.put("DICT:" + annos.dicCode() + ":" + dictModel.getValue(), dictModel.getText());
+                    }
+                }
+            }
+        }
+
+        //转换后的列表数据
+        List<Map<String, Object>> list = new ArrayList<>(dataset.size());
+        for (Object o : dataset) {
+            if(o == null) {
+                continue;
+            } else if(o instanceof Map) {
+                list.add((Map)o);
+            } else {
+                final JSONObject jsonObject = (JSONObject) JSON.toJSON(o);
+                // 字典字段
+                for (Map.Entry<String, Dict> entry : dictFields.entrySet()) {
+                    final String dictVal = jsonObject.getString(entry.getKey());
+                    if(StringUtils.isBlank(dictVal)) {
+                        // 字典字段是空的,则不需替换
+                        continue;
+                    }
+                    // 替换字典字段
+                    final Dict annos = entry.getValue();
+                    final Object o1 = dictMap.get("DICT:" + annos.dicCode() + ":" + dictVal);
+                    jsonObject.put(entry.getKey(), o1);
+                }
+
+                // 日期字段
+                for (Map.Entry<String, JsonFormat> entry : dateFields.entrySet()) {
+                    final Date dateVal = jsonObject.getDate(entry.getKey());
+                    if(dateVal == null) {
+                        // 字典字段是空的,则不需替换
+                        continue;
+                    }
+
+                    // 替换字典字段
+                    final JsonFormat df = entry.getValue();
+                    // 格式化时间
+                    jsonObject.put(entry.getKey(), FastDateFormat.getInstance(df.pattern()).format(dateVal));
+                }
+
+                // 需要填充转换的字段
+                for (Map.Entry<String, Fill> entry : convertFields.entrySet()) {
+                    final String convertVal = jsonObject.getString(entry.getKey());
+                    if(StringUtils.isBlank(convertVal)) {
+                        // 字典字段是空的,则不需替换
+                        continue;
+                    }
+                    String newVal = convertVal;
+                    if("enterprise".equals(entry.getValue().type())) {
+                        // 企业
+                        newVal = MemCached.CLIENT_NAME.get(Integer.parseInt(convertVal));
+                    } else if("vehicle".equals(entry.getValue().type())) {
+                        // 车辆
+                        newVal = MemCached.VEHICLE_CODE.get(convertVal);
+                    }
+                    jsonObject.put(entry.getKey(), newVal);
+                }
+                list.add(jsonObject);
+            }
+        }
+
+        // dictMap 中已经有了 code 的缓存,下面如果遇到字典码,则直接获取
+        ByteArrayOutputStream out = new ByteArrayOutputStream();
+        // 有模板则使用模板上的,没有模板,则使用类上的标记
+        final ExcelWriterBuilder builder = StringUtils.isNotBlank(templateName) ? EasyExcel.write(out) : EasyExcel.write(out, aClass);
+        if(StringUtils.isNotBlank(templateName)) {
+            // 有模板,采用模板写入
+            final String realTemplate = "/excel/" + templateName;
+            ClassPathResource templateStream = new ClassPathResource(realTemplate);
+            try(final InputStream inputStream = templateStream.getInputStream();){
+                try(final ExcelWriter excelWriter = builder.withTemplate(inputStream).build();) {
+                    WriteSheet writeSheet = StringUtils.isNotBlank(sheetName) ?
+                            EasyExcel.writerSheet(sheetName).build() : EasyExcel.writerSheet().build();
+                    // ext info
+                    if(extInfo != null && !extInfo.isEmpty()) {
+                        excelWriter.fill(extInfo, writeSheet);
+                    }
+                    excelWriter.fill(new FillWrapper("dataset", list), writeSheet);
+                }
+            }
+        } else {
+            // 没有模板,则直接写入
+            if(StringUtils.isNotBlank(sheetName)) {
+                builder.sheet(sheetName).doWrite(dataset);
+            } else {
+                builder.sheet().doWrite(dataset);
+            }
+        }
+        out.flush();
+        return out.toByteArray();
+    }
+}