|
@@ -1,25 +1,32 @@
|
|
package com.simuwang.daq.service;
|
|
package com.simuwang.daq.service;
|
|
|
|
|
|
import cn.hutool.core.collection.CollUtil;
|
|
import cn.hutool.core.collection.CollUtil;
|
|
|
|
+import cn.hutool.core.date.DateUtil;
|
|
import cn.hutool.core.lang.Pair;
|
|
import cn.hutool.core.lang.Pair;
|
|
import cn.hutool.core.map.MapUtil;
|
|
import cn.hutool.core.map.MapUtil;
|
|
import cn.hutool.core.util.StrUtil;
|
|
import cn.hutool.core.util.StrUtil;
|
|
|
|
+import com.simuwang.base.common.conts.DateConst;
|
|
|
|
+import com.simuwang.base.common.conts.EmailFieldConst;
|
|
import com.simuwang.base.common.conts.EmailTypeConst;
|
|
import com.simuwang.base.common.conts.EmailTypeConst;
|
|
import com.simuwang.base.common.util.ExcelUtil;
|
|
import com.simuwang.base.common.util.ExcelUtil;
|
|
import com.simuwang.base.common.util.StringUtil;
|
|
import com.simuwang.base.common.util.StringUtil;
|
|
import com.simuwang.base.pojo.dto.EmailContentInfoDTO;
|
|
import com.simuwang.base.pojo.dto.EmailContentInfoDTO;
|
|
import com.simuwang.base.pojo.dto.EmailFundNavDTO;
|
|
import com.simuwang.base.pojo.dto.EmailFundNavDTO;
|
|
|
|
+import org.apache.poi.ss.usermodel.Cell;
|
|
import org.apache.poi.ss.usermodel.Row;
|
|
import org.apache.poi.ss.usermodel.Row;
|
|
import org.apache.poi.ss.usermodel.Sheet;
|
|
import org.apache.poi.ss.usermodel.Sheet;
|
|
import org.jsoup.Jsoup;
|
|
import org.jsoup.Jsoup;
|
|
import org.jsoup.nodes.Document;
|
|
import org.jsoup.nodes.Document;
|
|
import org.jsoup.nodes.Element;
|
|
import org.jsoup.nodes.Element;
|
|
import org.jsoup.select.Elements;
|
|
import org.jsoup.select.Elements;
|
|
|
|
+import org.slf4j.Logger;
|
|
|
|
+import org.slf4j.LoggerFactory;
|
|
import org.springframework.stereotype.Component;
|
|
import org.springframework.stereotype.Component;
|
|
|
|
|
|
import java.io.File;
|
|
import java.io.File;
|
|
import java.util.List;
|
|
import java.util.List;
|
|
import java.util.Map;
|
|
import java.util.Map;
|
|
|
|
+import java.util.Optional;
|
|
|
|
|
|
/**
|
|
/**
|
|
* @author mozuwen
|
|
* @author mozuwen
|
|
@@ -29,6 +36,13 @@ import java.util.Map;
|
|
@Component
|
|
@Component
|
|
public class NavEmailParser extends AbstractEmailParser {
|
|
public class NavEmailParser extends AbstractEmailParser {
|
|
|
|
|
|
|
|
+ private static final Logger log = LoggerFactory.getLogger(AbstractEmailParser.class);
|
|
|
|
+
|
|
|
|
+ private static final Integer ROW_DIRECTION_TYPE = 1;
|
|
|
|
+ private static final Integer COLUMN_DIRECTION_TYPE = 2;
|
|
|
|
+
|
|
|
|
+ private static final int MAX_COLUMN = 20;
|
|
|
|
+
|
|
@Override
|
|
@Override
|
|
public boolean isSupport(Integer emailType) {
|
|
public boolean isSupport(Integer emailType) {
|
|
return EmailTypeConst.NAV_EMAIL_TYPE.equals(emailType);
|
|
return EmailTypeConst.NAV_EMAIL_TYPE.equals(emailType);
|
|
@@ -58,27 +72,234 @@ public class NavEmailParser extends AbstractEmailParser {
|
|
* @return 解析到的净值数据
|
|
* @return 解析到的净值数据
|
|
*/
|
|
*/
|
|
private List<EmailFundNavDTO> parseExcelFile(String filePath, Map<String, List<String>> emailFieldMap) {
|
|
private List<EmailFundNavDTO> parseExcelFile(String filePath, Map<String, List<String>> emailFieldMap) {
|
|
- List<EmailFundNavDTO> fundNavDTOList = CollUtil.newArrayList();
|
|
|
|
File file = new File(filePath);
|
|
File file = new File(filePath);
|
|
Sheet sheet = ExcelUtil.getSheet(file, 0);
|
|
Sheet sheet = ExcelUtil.getSheet(file, 0);
|
|
|
|
+ // 1.找到表头所在位置
|
|
Map<String, Pair<Integer, Integer>> fieldPositionMap = getFieldPosition(sheet, emailFieldMap);
|
|
Map<String, Pair<Integer, Integer>> fieldPositionMap = getFieldPosition(sheet, emailFieldMap);
|
|
if (MapUtil.isEmpty(fieldPositionMap)) {
|
|
if (MapUtil.isEmpty(fieldPositionMap)) {
|
|
|
|
+ log.warn("找不到文件表头字段 -> 文件:{}", filePath);
|
|
|
|
+ return CollUtil.newArrayList();
|
|
|
|
+ }
|
|
|
|
+ // 2.解析sheet中的净值数据
|
|
|
|
+ return parseSheetData(sheet, fieldPositionMap);
|
|
|
|
+ }
|
|
|
|
|
|
|
|
+ private List<EmailFundNavDTO> parseSheetData(Sheet sheet, Map<String, Pair<Integer, Integer>> fieldPositionMap) {
|
|
|
|
+ List<EmailFundNavDTO> fundNavDTOList = CollUtil.newArrayList();
|
|
|
|
+ // 通过表头所在位置判断是行数据还是列数据
|
|
|
|
+ Integer dataDirectionType = detectDataDirection(fieldPositionMap);
|
|
|
|
+ // 数据起始行,起始列
|
|
|
|
+ int initRow = dataDirectionType.equals(ROW_DIRECTION_TYPE) ? fieldPositionMap.values().stream().map(Pair::getKey).max(Integer::compareTo).orElse(0)
|
|
|
|
+ : fieldPositionMap.values().stream().map(Pair::getKey).min(Integer::compareTo).orElse(0);
|
|
|
|
+ int initColumn = fieldPositionMap.values().stream().map(Pair::getValue).min(Integer::compareTo).orElse(0);
|
|
|
|
+ if (dataDirectionType.equals(ROW_DIRECTION_TYPE)) {
|
|
|
|
+ // 表头字段-列号映射关系
|
|
|
|
+ Map<String, Integer> fieldColumnMap = getFieldRow(fieldPositionMap);
|
|
|
|
+ int lastRowNum = sheet.getLastRowNum();
|
|
|
|
+ // 遍历可能的数据行
|
|
|
|
+ for (int rowNum = initRow + 1; rowNum <= lastRowNum; rowNum++) {
|
|
|
|
+ Row sheetRow = sheet.getRow(rowNum);
|
|
|
|
+ Optional.ofNullable(readSheetRowData(sheetRow, fieldColumnMap)).ifPresent(fundNavDTOList::add);
|
|
|
|
+ }
|
|
}
|
|
}
|
|
|
|
+ if (dataDirectionType.equals(COLUMN_DIRECTION_TYPE)) {
|
|
|
|
+ // 表头字段-行号映射关系
|
|
|
|
+ Map<Integer, String> fieldRowMap = getRowField(fieldPositionMap);
|
|
|
|
+ int lastRow = fieldPositionMap.values().stream().map(Pair::getKey).max(Integer::compareTo).orElse(0);
|
|
|
|
+ // 遍历每一列
|
|
|
|
+ for (int columnNum = initColumn + 1; columnNum < MAX_COLUMN; columnNum++) {
|
|
|
|
+ Map<String, String> fieldValueMap = MapUtil.newHashMap();
|
|
|
|
+ for (int rowNum = initRow; rowNum <= lastRow; rowNum++) {
|
|
|
|
+ Row row = sheet.getRow(rowNum);
|
|
|
|
+ Cell cell = row.getCell(columnNum);
|
|
|
|
+ if (cell == null) {
|
|
|
|
+ continue;
|
|
|
|
+ }
|
|
|
|
+ fieldValueMap.put(fieldRowMap.get(rowNum), cell.getStringCellValue());
|
|
|
|
+ }
|
|
|
|
+ Optional.ofNullable(buildEmailFundNavDTO(fieldValueMap)).ifPresent(fundNavDTOList::add);
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ // 兼容净值日期为空的情况
|
|
|
|
+ addPriceDateIfMiss(fundNavDTOList, getPriceDateFromSheet(sheet, initRow));
|
|
return fundNavDTOList;
|
|
return fundNavDTOList;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+ private void addPriceDateIfMiss(List<EmailFundNavDTO> fundNavDTOList, String priceDate) {
|
|
|
|
+ if (fundNavDTOList.stream().map(EmailFundNavDTO::getPriceDate).allMatch(StrUtil::isBlank)) {
|
|
|
|
+ fundNavDTOList.forEach(e -> e.setPriceDate(priceDate));
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ private String getPriceDateFromSheet(Sheet sheet, Integer maxRowNum) {
|
|
|
|
+ Map<Integer, String> priceDateMap = MapUtil.newHashMap();
|
|
|
|
+ for (int rowNum = 0; rowNum < maxRowNum; rowNum++) {
|
|
|
|
+ Row row = sheet.getRow(rowNum);
|
|
|
|
+ if (row == null) {
|
|
|
|
+ continue;
|
|
|
|
+ }
|
|
|
|
+ int lastCellNum = row.getLastCellNum();
|
|
|
|
+ for (int columnNum = 0; columnNum < lastCellNum; columnNum++) {
|
|
|
|
+ Cell cell = row.getCell(columnNum);
|
|
|
|
+ if (cell == null) {
|
|
|
|
+ continue;
|
|
|
|
+ }
|
|
|
|
+ String cellValue = cell.getStringCellValue();
|
|
|
|
+ if (StrUtil.isNotBlank(cellValue) && cellValue.contains("截至")) {
|
|
|
|
+ int index = cellValue.indexOf("截至");
|
|
|
|
+ String date = cellValue.substring(index + 2, index + 2 + 10);
|
|
|
|
+ if (StrUtil.isNotBlank(date)) {
|
|
|
|
+ date = date.replaceAll("年", "-").replaceAll("月", "-");
|
|
|
|
+ }
|
|
|
|
+ priceDateMap.put(1, date);
|
|
|
|
+ continue;
|
|
|
|
+ }
|
|
|
|
+ boolean isValidDate = StringUtil.isValidDate(cellValue);
|
|
|
|
+ if (isValidDate) {
|
|
|
|
+ String date = cellValue.replaceAll("年", "-").replaceAll("月", "-");
|
|
|
|
+ priceDateMap.put(2, date);
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ if (MapUtil.isNotEmpty(priceDateMap)) {
|
|
|
|
+ Integer key = priceDateMap.keySet().stream().min(Integer::compareTo).orElse(null);
|
|
|
|
+ return priceDateMap.get(key);
|
|
|
|
+ }
|
|
|
|
+ return null;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ private EmailFundNavDTO buildEmailFundNavDTO(Map<String, String> fieldValueMap) {
|
|
|
|
+ if (MapUtil.isEmpty(fieldValueMap) || fieldValueMap.values().stream().allMatch(StrUtil::isBlank)) {
|
|
|
|
+ return null;
|
|
|
|
+ }
|
|
|
|
+ EmailFundNavDTO fundNavDTO = new EmailFundNavDTO();
|
|
|
|
+ fundNavDTO.setFundName(fieldValueMap.get(EmailFieldConst.FUND_NAME));
|
|
|
|
+ fundNavDTO.setRegisterNumber(fieldValueMap.get(EmailFieldConst.REGISTER_NUMBER));
|
|
|
|
+ fundNavDTO.setPriceDate(fieldValueMap.get(EmailFieldConst.PRICE_DATE));
|
|
|
|
+ fundNavDTO.setNav(fieldValueMap.get(EmailFieldConst.NAV));
|
|
|
|
+ fundNavDTO.setCumulativeNavWithdrawal(fieldValueMap.get(EmailFieldConst.CUMULATIVE_NAV_WITHDRAWAL));
|
|
|
|
+ String assetNet = fieldValueMap.get(EmailFieldConst.ASSET_NET);
|
|
|
|
+ if (StrUtil.isBlank(assetNet) || !StrUtil.isNumeric(assetNet)) {
|
|
|
|
+ assetNet = null;
|
|
|
|
+ }
|
|
|
|
+ fundNavDTO.setAssetNet(assetNet);
|
|
|
|
+ String assetShares = fieldValueMap.get(EmailFieldConst.ASSET_NET);
|
|
|
|
+ if (StrUtil.isBlank(assetShares) || !StrUtil.isNumeric(assetShares)) {
|
|
|
|
+ assetShares = null;
|
|
|
|
+ }
|
|
|
|
+ fundNavDTO.setAssetShare(assetShares);
|
|
|
|
+ return fundNavDTO;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
|
|
|
|
+ private EmailFundNavDTO readSheetRowData(Row sheetRow, Map<String, Integer> columnFieldMap) {
|
|
|
|
+ if (sheetRow == null) {
|
|
|
|
+ return null;
|
|
|
|
+ }
|
|
|
|
+ String nav = columnFieldMap.get(EmailFieldConst.NAV) != null && sheetRow.getCell(columnFieldMap.get(EmailFieldConst.NAV)) != null
|
|
|
|
+ ? sheetRow.getCell(columnFieldMap.get(EmailFieldConst.NAV)).getStringCellValue() : null;
|
|
|
|
+ String cumulativeNavWithdrawal = columnFieldMap.get(EmailFieldConst.CUMULATIVE_NAV_WITHDRAWAL) != null && sheetRow.getCell(columnFieldMap.get(EmailFieldConst.CUMULATIVE_NAV_WITHDRAWAL)) != null ?
|
|
|
|
+ sheetRow.getCell(columnFieldMap.get(EmailFieldConst.CUMULATIVE_NAV_WITHDRAWAL)).getStringCellValue() : null;
|
|
|
|
+ if (StrUtil.isBlank(nav) || StrUtil.isBlank(cumulativeNavWithdrawal)) {
|
|
|
|
+ return null;
|
|
|
|
+ }
|
|
|
|
+ EmailFundNavDTO emailFundNavDTO = new EmailFundNavDTO();
|
|
|
|
+ String priceDate = columnFieldMap.get(EmailFieldConst.PRICE_DATE) != null && sheetRow.getCell(columnFieldMap.get(EmailFieldConst.PRICE_DATE)) != null ?
|
|
|
|
+ sheetRow.getCell(columnFieldMap.get(EmailFieldConst.PRICE_DATE)).getStringCellValue() : null;
|
|
|
|
+ if (StrUtil.isNotBlank(priceDate) && !priceDate.contains("-")) {
|
|
|
|
+ // 处理日期yyyyMMdd格式 -> 转成yyyy-MM-dd
|
|
|
|
+ priceDate = DateUtil.format(DateUtil.parse(priceDate, DateConst.YYYYMMDD), DateConst.YYYY_MM_DD);
|
|
|
|
+ }
|
|
|
|
+ emailFundNavDTO.setPriceDate(priceDate);
|
|
|
|
+ String fundName = columnFieldMap.get(EmailFieldConst.FUND_NAME) != null && sheetRow.getCell(columnFieldMap.get(EmailFieldConst.FUND_NAME)).getStringCellValue() != null ?
|
|
|
|
+ sheetRow.getCell(columnFieldMap.get(EmailFieldConst.FUND_NAME)).getStringCellValue() : null;
|
|
|
|
+ emailFundNavDTO.setFundName(fundName);
|
|
|
|
+ String registerNumber = columnFieldMap.get(EmailFieldConst.REGISTER_NUMBER) != null && sheetRow.getCell(columnFieldMap.get(EmailFieldConst.REGISTER_NUMBER)) != null ?
|
|
|
|
+ sheetRow.getCell(columnFieldMap.get(EmailFieldConst.REGISTER_NUMBER)).getStringCellValue() : null;
|
|
|
|
+ emailFundNavDTO.setRegisterNumber(registerNumber);
|
|
|
|
+ emailFundNavDTO.setNav(nav);
|
|
|
|
+ emailFundNavDTO.setCumulativeNavWithdrawal(cumulativeNavWithdrawal);
|
|
|
|
+ String virtualNav = columnFieldMap.get(EmailFieldConst.VIRTUAL_NAV) != null && sheetRow.getCell(columnFieldMap.get(EmailFieldConst.VIRTUAL_NAV)) != null ?
|
|
|
|
+ sheetRow.getCell(columnFieldMap.get(EmailFieldConst.VIRTUAL_NAV)).getStringCellValue() : null;
|
|
|
|
+ emailFundNavDTO.setVirtualNav(virtualNav);
|
|
|
|
+ String assetNet = columnFieldMap.get(EmailFieldConst.ASSET_NET) != null && sheetRow.getCell(columnFieldMap.get(EmailFieldConst.ASSET_NET)) != null ?
|
|
|
|
+ sheetRow.getCell(columnFieldMap.get(EmailFieldConst.ASSET_NET)).getStringCellValue() : null;
|
|
|
|
+ if (StrUtil.isBlank(assetNet) || !StrUtil.isNumeric(assetNet)) {
|
|
|
|
+ assetNet = null;
|
|
|
|
+ }
|
|
|
|
+ emailFundNavDTO.setAssetNet(assetNet);
|
|
|
|
+ String assetShares = columnFieldMap.get(EmailFieldConst.ASSET_SHARE) != null && sheetRow.getCell(columnFieldMap.get(EmailFieldConst.ASSET_SHARE)) != null ?
|
|
|
|
+ sheetRow.getCell(columnFieldMap.get(EmailFieldConst.ASSET_SHARE)).getStringCellValue() : null;
|
|
|
|
+ if (StrUtil.isBlank(assetShares) || !StrUtil.isNumeric(assetShares)) {
|
|
|
|
+ assetShares = null;
|
|
|
|
+ }
|
|
|
|
+ emailFundNavDTO.setAssetShare(assetShares);
|
|
|
|
+ return emailFundNavDTO;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ private Map<String, Integer> getFieldRow(Map<String, Pair<Integer, Integer>> fieldPositionMap) {
|
|
|
|
+ // 考虑日期字段识别逻辑的问题
|
|
|
|
+ long rowNumCount = fieldPositionMap.values().stream().map(Pair::getKey).distinct().count();
|
|
|
|
+ if (rowNumCount > 1) {
|
|
|
|
+ // 存在合并单元格的方式 -> 日期字段所在位置可能会存在错误
|
|
|
|
+ fieldPositionMap.remove(EmailFieldConst.PRICE_DATE);
|
|
|
|
+ }
|
|
|
|
+ Map<String, Integer> fieldRowMap = MapUtil.newHashMap();
|
|
|
|
+ for (Map.Entry<String, Pair<Integer, Integer>> fieldPositionEntry : fieldPositionMap.entrySet()) {
|
|
|
|
+ String field = fieldPositionEntry.getKey();
|
|
|
|
+ Integer column = fieldPositionEntry.getValue().getValue();
|
|
|
|
+ fieldRowMap.put(field, column);
|
|
|
|
+ }
|
|
|
|
+ return fieldRowMap;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ private Map<Integer, String> getRowField(Map<String, Pair<Integer, Integer>> fieldPositionMap) {
|
|
|
|
+ Map<Integer, String> fieldRowMap = MapUtil.newHashMap();
|
|
|
|
+ for (Map.Entry<String, Pair<Integer, Integer>> fieldPositionEntry : fieldPositionMap.entrySet()) {
|
|
|
|
+ String field = fieldPositionEntry.getKey();
|
|
|
|
+ Integer column = fieldPositionEntry.getValue().getKey();
|
|
|
|
+ fieldRowMap.put(column, field);
|
|
|
|
+ }
|
|
|
|
+ return fieldRowMap;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ /**
|
|
|
|
+ * 通过表头所在位置判断是行数据还是列数据
|
|
|
|
+ *
|
|
|
|
+ * @param fieldPositionMap excel中表头所在的位置
|
|
|
|
+ * @return 行方向-1,,列方向-2
|
|
|
|
+ */
|
|
|
|
+ private Integer detectDataDirection(Map<String, Pair<Integer, Integer>> fieldPositionMap) {
|
|
|
|
+ long count = fieldPositionMap.values().stream().map(Pair::getValue).distinct().count();
|
|
|
|
+ return count == 1 ? COLUMN_DIRECTION_TYPE : ROW_DIRECTION_TYPE;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ /**
|
|
|
|
+ * 找出excel中表头所在的位置
|
|
|
|
+ *
|
|
|
|
+ * @param sheet 表格工作簿
|
|
|
|
+ * @param emailFieldMap 邮件字段识别规则映射表
|
|
|
|
+ * @return excel中表头所在的位置(行, 列)
|
|
|
|
+ */
|
|
private Map<String, Pair<Integer, Integer>> getFieldPosition(Sheet sheet, Map<String, List<String>> emailFieldMap) {
|
|
private Map<String, Pair<Integer, Integer>> getFieldPosition(Sheet sheet, Map<String, List<String>> emailFieldMap) {
|
|
Map<String, Pair<Integer, Integer>> fieldPositionMap = MapUtil.newHashMap(8);
|
|
Map<String, Pair<Integer, Integer>> fieldPositionMap = MapUtil.newHashMap(8);
|
|
int lastRowNum = sheet.getLastRowNum();
|
|
int lastRowNum = sheet.getLastRowNum();
|
|
for (int rowNum = 0; rowNum < lastRowNum; rowNum++) {
|
|
for (int rowNum = 0; rowNum < lastRowNum; rowNum++) {
|
|
Row sheetRow = sheet.getRow(rowNum);
|
|
Row sheetRow = sheet.getRow(rowNum);
|
|
|
|
+ if (sheetRow == null) {
|
|
|
|
+ continue;
|
|
|
|
+ }
|
|
int lastCellNum = sheetRow.getLastCellNum();
|
|
int lastCellNum = sheetRow.getLastCellNum();
|
|
for (int cellNum = 0; cellNum < lastCellNum; cellNum++) {
|
|
for (int cellNum = 0; cellNum < lastCellNum; cellNum++) {
|
|
- String cellValue = sheetRow.getCell(cellNum).getStringCellValue();
|
|
|
|
|
|
+ Cell cell = sheetRow.getCell(cellNum);
|
|
|
|
+ if (cell == null) {
|
|
|
|
+ continue;
|
|
|
|
+ }
|
|
|
|
+ String cellValue = cell.getStringCellValue();
|
|
String field = fieldMatch(cellValue, emailFieldMap);
|
|
String field = fieldMatch(cellValue, emailFieldMap);
|
|
- if (StrUtil.isNotBlank(field) && !fieldPositionMap.containsKey(field)) {
|
|
|
|
|
|
+ // todo 考虑份额基金净值文件格式
|
|
|
|
+ if (StrUtil.isNotBlank(field)) {
|
|
fieldPositionMap.put(field, new Pair<>(rowNum, cellNum));
|
|
fieldPositionMap.put(field, new Pair<>(rowNum, cellNum));
|
|
}
|
|
}
|
|
}
|
|
}
|
|
@@ -86,6 +307,13 @@ public class NavEmailParser extends AbstractEmailParser {
|
|
return fieldPositionMap;
|
|
return fieldPositionMap;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+ /**
|
|
|
|
+ * 判断单元格值是否为表头字段
|
|
|
|
+ *
|
|
|
|
+ * @param cellValue 单元格值
|
|
|
|
+ * @param emailFieldMap 邮件字段识别规则映射表
|
|
|
|
+ * @return 表头对应的标识
|
|
|
|
+ */
|
|
public String fieldMatch(String cellValue, Map<String, List<String>> emailFieldMap) {
|
|
public String fieldMatch(String cellValue, Map<String, List<String>> emailFieldMap) {
|
|
if (StrUtil.isBlank(cellValue)) {
|
|
if (StrUtil.isBlank(cellValue)) {
|
|
return null;
|
|
return null;
|