欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

java EasyExcel實現(xiàn)動態(tài)列解析和存表

 更新時間:2023年06月15日 17:28:32   作者:我是一顆小虎牙_  
這篇文章主要為大家介紹了java EasyExcel實現(xiàn)動態(tài)列解析和存表示例解析,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪

背景

一個表中的數(shù)據(jù)來源于多個其他系統(tǒng)的導(dǎo)出表,其中的特點就是大多數(shù)的字段都是一樣的(可能導(dǎo)出的表頭不一樣),只有部分少數(shù)字段是每個系統(tǒng)自己獨有的。圍繞這個做一次功能性分析

分析:大多數(shù)字段是一樣的,那么就是實際的表字段,唯一的區(qū)別就是各系統(tǒng)內(nèi)的名字可能不一樣,少數(shù)每個系統(tǒng)獨有的字段,可以歸為動態(tài)字段。

總結(jié):

  • 公共字段(翻譯表頭:@ExcelProperty 可以指定多個表頭( @ExcelProperty(value = {"發(fā)貨數(shù)量", "采購數(shù)量(臺)"}) ))
  • 動態(tài)字段(需要有每個系統(tǒng)內(nèi)動態(tài)字段的字段名稱和表頭的對應(yīng)關(guān)系,考慮使用字典,供業(yè)務(wù)員配置,后續(xù)如果新添加其他動態(tài)字段直接在字典中配置,無需另行開發(fā))

注意:由于無法控制和預(yù)料固定字段在新接入的系統(tǒng)中的實際表頭,所以如果新接入系統(tǒng)的公共表頭與表字段不一致,需要在 @ExcelProperty(value = {}) 中添加新的表頭

效果

字典配置:

數(shù)據(jù)表結(jié)果:

公共字段使用常規(guī)的數(shù)據(jù)庫表字段存儲,動態(tài)字段使用額外列存 JSON 串。

代碼

引入pom坐標(biāo)

<dependency>
    <groupId>com.alibaba</groupId>
    <artifactId>easyexcel</artifactId>
    <version>3.1.0</version>
</dependency>

創(chuàng)建實體類

public class AgentDeliverOrderImportVo {
    @ExcelProperty(value = {"訂單編號"}, order = 1)
    private String deliverNo;
    @ExcelProperty(value = {"發(fā)貨數(shù)量", "采購數(shù)量(臺)"}, order = 14)
    @ColumnName(name = {"發(fā)貨數(shù)量", "采購數(shù)量(臺)"})
    private Integer deliverCount;
    /**
     * 動態(tài)字段(業(yè)務(wù)線編號區(qū)分)
     */
    private String dynamicFields;
    private Date createTime;
    private String createBy;
}
  • 因為存在不確定的列,所以只能使用 EasyExcel 的不創(chuàng)建對象的寫,那么
public String test(MultipartFile file) throws IOException {
    //假設(shè)從字典中獲取字典值
    Map<String, String> dictMap = new HashMap<>();
    dictMap.put("項目", "xm");
    dictMap.put("嗨一付訂單編號", "hyfddbh");
    try (InputStream inputStream = file.getInputStream()) {
        EasyExcel.read(inputStream, new ReadListener<Map<String, String>>(){
            private Map<Integer, String> fieldHead;
            //獲取表頭
            @Override
            public void invokeHead(Map<Integer, ReadCellData<?>> headMap, AnalysisContext context) {
                Map<Integer, String> integerStringMap = ConverterUtils.convertToStringMap(headMap, context);
                log.info("解析到一條頭數(shù)據(jù):{}", JSON.toJSONString(integerStringMap));
                fieldHead = ExcelParsing.setFieldHead(integerStringMap, AgentDeliverOrderImportVo.class);
                log.info("轉(zhuǎn)化后頭數(shù)據(jù):{}", JSONObject.toJSONString(fieldHead));
            }
            //獲取數(shù)據(jù)
            @Override
            public void invoke(Map<String, String> map, AnalysisContext analysisContext) {
                log.info("解析到一條數(shù)據(jù):{}", JSON.toJSONString(map));
                Map<String, String> valueMap = ExcelParsing.setFieldValue(fieldHead, dictMap, map);
                log.info("轉(zhuǎn)化一條數(shù)據(jù):{}", JSONObject.toJSONString(valueMap));
                log.info("轉(zhuǎn)化一條動態(tài)數(shù)據(jù):{}", JSONObject.toJSONString(ExcelParsing.getValueMap(valueMap, AgentDeliverOrderImportVo.class)));
            }
            @Override
            public void doAfterAllAnalysed(AnalysisContext analysisContext) {
            }
        }).sheet().doRead();
    }
    return "完成";
}
/**
 * @author Surpass
 * @Description: excel處理類
 * @date 27/07/2022 15:04
 */
class ExcelParsing {
    /**
     * 將公共字段中的中文轉(zhuǎn)換成數(shù)據(jù)庫表字段,動態(tài)字段(其他字段保留)
     * @param headMap               {1:"姓名", 2:"年齡"}
     * @param obj                   AgentDeliverOrderImportVo(導(dǎo)入實體類)
     * @return java.util.Map<java.lang.String, java.lang.String>       {1:"name", 2:"年齡"}
     * @author Surpass
     * @date 01/08/2022 17:10
     */
    public static Map<Integer, String> setFieldHead(Map<Integer, String> headMap, Class<?> obj) {
        Field[] fields = obj.getDeclaredFields();
        for (Field field : fields) {
            ExcelProperty annotation = field.getAnnotation(ExcelProperty.class);
            if (annotation == null) {
                continue;
            }
            //存在翻譯字段的情況,一個字段對應(yīng)好幾個表頭(盡量避免)
            List<String> valueList = Arrays.asList(annotation.value());
            for (Map.Entry<Integer, String> entry : headMap.entrySet()) {
                if (valueList.contains(entry.getValue())) {
                    headMap.put(entry.getKey(), field.getName());
                }
            }
        }
        return headMap;
    }
    /**
     * 獲取數(shù)據(jù)(平鋪),指動態(tài)字段kv和公共字段kv在同一級
     * @param headMap               {1:"name", 2:"年齡"}
     * @param dictMap               {"年齡":"age"}
     * @param valueMap              {1:"廣州****公司", 2:"23"}
     * @return java.util.Map<java.lang.String, java.lang.String>
     * @author Surpass
     * @date 01/08/2022 17:10
     */
    public static Map<String, String> setFieldValue(Map<Integer, String> headMap,
                                                    Map<String, String> dictMap,
                                                    Map<String, String> valueMap) {
        Map<Integer, String> valueIntegerMap = valueMap.entrySet().stream().collect(
                Collectors.toMap(item -> Integer.valueOf(String.valueOf(item.getKey())),
                        item -> StrUtil.nullToEmpty(item.getValue()))
        );
        Map<String, String> valueResultMap = new HashMap<>(valueMap.size());
        Iterator<Map.Entry<Integer, String>> iterator = valueIntegerMap.entrySet().iterator();
        while (iterator.hasNext()) {
            Map.Entry<Integer, String> entry = iterator.next();
            //動態(tài)字段
            if (dictMap != null && dictMap.containsKey(headMap.get(entry.getKey()))) {
                valueResultMap.put(dictMap.get(headMap.get(entry.getKey())), entry.getValue());
                continue;
            }
            //公共字段
            valueResultMap.put(headMap.get(entry.getKey()), entry.getValue());
            iterator.remove();
        }
        return valueResultMap;
    }
    /**
     * 獲取數(shù)據(jù)(表結(jié)構(gòu)),指動態(tài)字段kv已經(jīng)加入到數(shù)據(jù)庫表字段 dynamicFields 中
     * @param obj                   AgentDeliverOrderImportVo(導(dǎo)入實體類)
     * @param valueMap              {"name":"廣州****公司", "age":"23"}
     * @return java.util.Map<java.lang.String, java.lang.String>  
     * 返回結(jié)果: {"name":"廣州****公司","dynamicFields":{"age":"23"}}
     * @author Surpass
     * @date 01/08/2022 17:10
     */
    public static Map<String, Object> getValueMap(Map<String, String> valueMap,
                                                  Class<?> obj) {
        Map<String, Object> resultMap = new HashMap<>(valueMap);
        List<String> commonFieldList = new ArrayList<>();
        Field[] fields = obj.getDeclaredFields();
        for (Field field : fields) {
            ExcelProperty annotation = field.getAnnotation(ExcelProperty.class);
            if (annotation == null) {
                continue;
            }
            commonFieldList.add(field.getName());
        }
        //過濾掉實體中的公共字段
        Map<String, String> dynamicMap = valueMap.entrySet().stream()
                .filter(item -> !commonFieldList.contains(item.getKey()))
                .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue));
        resultMap.put("dynamicFields", dynamicMap);;
        return resultMap;
    }
}

經(jīng)過解析以后這個文檔的數(shù)據(jù)已經(jīng)和數(shù)據(jù)庫表一致了,那么我們后續(xù)的操作就是常規(guī)的校驗和插入邏輯了。

目前有一個缺點就是這樣存的動態(tài)字段不好做條件查詢,影響不是很大。

總結(jié)

本文介紹了使用 EasyExcel 組件來進行導(dǎo)入,實現(xiàn)公共列和動態(tài)列組合類型的導(dǎo)入,以及如何存儲的功能,主要利用反射和字典分別來維護公共列和動態(tài)列的表頭和字段的對應(yīng)關(guān)系,利用此關(guān)系對數(shù)據(jù)進行解析。

以上就是java EasyExcel實現(xiàn)動態(tài)列解析和存表的詳細內(nèi)容,更多關(guān)于java EasyExcel動態(tài)列存表的資料請關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

最新評論