通过easyexcel导入数据,添加表格参数的校验,同表格内校验以及和已有数据的校验

引入依赖

<dependency>
      <groupId>com.alibaba</groupId>
      <artifactId>easyexcel</artifactId>
      <version>2.2.11</version>
      <scope>compile</scope>
    </dependency>

需要导入到某个目录下

如果产品名称相同,就追加里面的型号,如果型号也相同就返回提示,

如果产品名称相同,表格内的数据要和浏览器录入的 型号对应参数保持一致,顺序、名称、数量等都要完全一致

如果产品名称相同,表格内部的 型号对应的参数必须保持一致,顺序、名称、数量等都要完全一致;

例如:

导入的表格要个浏览器对应上

controller

	/**
	 * 导入设备
	 */
	@PostMapping("importProduct")
	@ApiOperationSupport(order = 11)
	@ApiOperation(value = "导入设备", notes = "传入excel/产品")
	public R importProduct(MultipartFile file, Long categoryId) throws IOException {
		//此处判断文件大小不能为0
		if (file.getSize() == 0) {
			return R.fail("文件大小不能为空");
		}
		if (categoryId == null || categoryId <= 0) {
			return R.fail("请选择所属产品分类");
		}
		return productService.importProduct(file, categoryId);
	}

services

	//导入产品
	@Override
	@Transactional(rollbackFor = Exception.class)
	public R importProduct(MultipartFile file, Long categoryId) throws IOException {
		CategoryEntity category = categoryService.getById(categoryId);
		if (category == null) {
			throw new ServiceException("产品分类不存在");
		}
		DataExcelListener<ProductImportExcel> listener = new DataExcelListener<ProductImportExcel>();
		// headRowNumber(2):表示第一、二行为表头,从第三行取值
		ExcelReader excelReader = EasyExcelFactory.read(file.getInputStream(), ProductImportExcel.class, listener).headRowNumber(2).build();
		excelReader.readAll();
		List<ProductImportExcel> data = listener.getDatas();
		excelReader.finish();
		Map<String, List<CodeProTypeJson>> map = new LinkedHashMap<>();
		//获取表格数据,根据表格每一行的列数量不同,获取数据后组装型号json
		getExcelData(data, map);
		// 转换数据并添加产品
		List<ProductEntity> productList = new ArrayList<>();
		//判断导入的产品名称和已有的产品名称是否相同,如果相同就追加型号
		List<String> productNameList = new ArrayList<>();
		for (Map.Entry<String, List<CodeProTypeJson>> listEntry : map.entrySet()) {
			String productName = listEntry.getKey();
			List<CodeProTypeJson> value = listEntry.getValue();
			ProductEntity product = new ProductEntity();
			product.setCategoryId(categoryId);
			product.setCodeProName(productName);
			product.setCodeProType(JSON.toJSONString(value));
			product.setCodeProTypeNum(value.size());
			product.setEnterpriseId(IotAuthUtil.getEnterpriseId());
			productNameList.add(productName);
			productList.add(product);
		}
		// 批量查询 已经存在的产品 存在就覆盖 不存在就新增
		if (productNameList != null && productNameList.size() > 0) {
			LambdaQueryWrapper<ProductEntity> queryWrapper = new LambdaQueryWrapper<>();
			queryWrapper.in(ProductEntity::getCodeProName, productNameList);
			List<ProductEntity> selectList = baseMapper.selectList(queryWrapper);
			List<ProductEntity> updateList = new ArrayList<>();
			List<ProductEntity> addList = new ArrayList<>();
			for (ProductEntity entity : productList) {
				// 判断产品是否已经添加,如已添加就走修改逻辑,未添加就走添加逻辑
				ProductEntity product = containsProductEntity(entity, selectList);
				if (product != null) {
					entity.setId(product.getId());
					updateList.add(entity);
				} else {
					addList.add(entity);
				}
				/*Long productId = containsProductEntity(entity, selectList);
				if (productId != null) {
					entity.setId(productId);
					updateList.add(entity);
				} else {
					addList.add(entity);
				}*/

			}
			// 批量更新
			if (updateList != null && updateList.size() > 0) {
				this.updateBatchById(updateList);
			}
			// 批量添加
			if (addList != null && addList.size() > 0) {
				this.saveBatch(addList);
			}
		}
		return R.success("导入成功!");
	}

Excel导入数据 解析监听器 用于获取excel表格的数据

package com.bluebird.code.util;

import com.alibaba.excel.context.AnalysisContext;
import com.alibaba.excel.event.AnalysisEventListener;
import com.alibaba.excel.metadata.Cell;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;

/**
 * Excel导入数据 解析监听器 用于获取excel表格的数据
 */
public class DataExcelListener<T> extends AnalysisEventListener<T> {
    /**
     * 自定义用于暂时存储data
     * 可以通过实例获取该值
     */
    private List<T> datas = new ArrayList<>();

    /**
     * 每解析一行都会回调invoke()方法
     *
     * @param object  读取后的数据对象
     * @param context 内容
     */
    @Override
    @SuppressWarnings("unchecked")
    public void invoke(Object object, AnalysisContext context) {
        T data = (T) object;
        //数据存储到list,供批量处理,判断每一行是否为空行。
		if (data != null && !isEmptyRow(context.readRowHolder().getCellMap())) {
			datas.add(data);
		}

    }

    @Override
    public void doAfterAllAnalysed(AnalysisContext context) {
        //解析结束销毁不用的资源
        //注意不要调用datas.clear(),否则getDatas为null
    }

    /**
     * 返回数据
     *
     * @return 返回读取的数据集合
     **/
    public List<T> getDatas() {
        return datas;
    }

    /**
     * 设置读取的数据集合
     *
     * @param datas 设置读取的数据集合
     **/
    public void setDatas(List<T> datas) {
        this.datas = datas;
    }


	/**
	 * 判断一行是否为空行
	 * @param cellMap 当前行的单元格映射
	 * @return 如果所有单元格都为空,则返回 true,否则返回 false
	 */
	private boolean isEmptyRow(Map<Integer, Cell> cellMap) {
		for (Object cellValue : cellMap.values()) {
			if (cellValue != null && !cellValue.toString().trim().isEmpty()) {
				return false;
			}
		}
		return true;
	}

}

获取数据后组装型号json串 (同时处理表格内部相同产品名称不同型号参数名的问题,要确保相同参数名称的参数名保持一致)

// 获取数据后组装型号json串 (同时处理表格内部相同产品名称不同型号参数名的问题,要确保相同参数名称的参数名保持一致)
	public void getExcelData(List<ProductImportExcel> data, Map<String, List<CodeProTypeJson>> map) {
		int count = 2;
		// 判断产品名称和型号是否相等,如过相等就返回提示,产品名和型号组成合并后需要唯一
		Map<String, String> proNameTypeMap = new HashMap<>();
		// 定义一个map集合,key:产品名称,value:型号集合的名称拼接
		Map<String, String> mapProductType = new LinkedHashMap<>();
		for (ProductImportExcel entity : data) {
			count++;
			String productName = entity.getCodeProName();
			String codeProType = entity.getCodeProType();
			String proNameType = productName + codeProType;

			if (StringUtils.isBlank(productName) || StringUtils.isEmpty(productName)) {
				throw new ServiceException("第 " + count + " 行产品名称不能为空!");
			}
			if (StringUtils.isBlank(codeProType) || StringUtils.isEmpty(codeProType)) {
				throw new ServiceException("第 " + count + " 行规格型号不能为空!");
			}
			//
			String proNameTypeStr = proNameTypeMap.get(proNameType);
			if (StringUtils.isNotBlank(proNameTypeStr)) {
				throw new ServiceException("第 " + count + " 行和第 " + (count - 1) + "产品名称下的规格型号不能重复!");
			}
			proNameTypeMap.put(proNameType, proNameType);

			List<CodeProTypeJson> list = map.get(productName);
			CodeProTypeJson json = new CodeProTypeJson();

			List<CodeProTypeJson.SkuParamsList> listDate = new ArrayList<>();
			json.setSkuName(entity.getCodeProType());
			json.setSkuId(IdWorker.getIdStr());

			// 将参数名进行拼接
			StringBuilder paramSb = new StringBuilder();
			// 根据型号参数名字处理表格数据,如果此单元格为空就不处理(因为每个产品的型号数量不确定)
			if (StringUtils.isNotEmpty(entity.getParamName1())) {
				CodeProTypeJson.SkuParamsList skuParamsList = new CodeProTypeJson.SkuParamsList();
				skuParamsList.setParamId(IdWorker.getIdStr());
				skuParamsList.setParamName(entity.getParamName1());
				skuParamsList.setParamValue(entity.getParamValue1());
				listDate.add(skuParamsList);
				paramSb.append(entity.getParamName1());
			}
			// 根据型号参数名字处理表格数据,如果此单元格为空就不处理(因为每个产品的型号数量不确定)
			if (StringUtils.isNotEmpty(entity.getParamName2())) {
				CodeProTypeJson.SkuParamsList skuParamsList = new CodeProTypeJson.SkuParamsList();
				skuParamsList.setParamId(IdWorker.getIdStr());
				skuParamsList.setParamName(entity.getParamName2());
				skuParamsList.setParamValue(entity.getParamValue2());
				listDate.add(skuParamsList);
				paramSb.append("->");
				paramSb.append(entity.getParamName2());
			}
			// 根据型号参数名字处理表格数据,如果此单元格为空就不处理(因为每个产品的型号数量不确定)
			if (StringUtils.isNotEmpty(entity.getParamName3())) {
				CodeProTypeJson.SkuParamsList skuParamsList = new CodeProTypeJson.SkuParamsList();
				skuParamsList.setParamId(IdWorker.getIdStr());
				skuParamsList.setParamName(entity.getParamName3());
				skuParamsList.setParamValue(entity.getParamValue3());
				listDate.add(skuParamsList);
				paramSb.append("->");
				paramSb.append(entity.getParamName3());
			}
			// 根据型号参数名字处理表格数据,如果此单元格为空就不处理(因为每个产品的型号数量不确定)
			if (StringUtils.isNotEmpty(entity.getParamName4())) {
				CodeProTypeJson.SkuParamsList skuParamsList = new CodeProTypeJson.SkuParamsList();
				skuParamsList.setParamId(IdWorker.getIdStr());
				skuParamsList.setParamName(entity.getParamName4());
				skuParamsList.setParamValue(entity.getParamValue4());
				listDate.add(skuParamsList);
				paramSb.append("->");
				paramSb.append(entity.getParamName4());
			}

			// 根据型号参数名字处理表格数据,如果此单元格为空就不处理(因为每个产品的型号数量不确定)
			if (StringUtils.isNotEmpty(entity.getParamName5())) {
				CodeProTypeJson.SkuParamsList skuParamsList = new CodeProTypeJson.SkuParamsList();
				skuParamsList.setParamId(IdWorker.getIdStr());
				skuParamsList.setParamName(entity.getParamName5());
				skuParamsList.setParamValue(entity.getParamValue5());
				listDate.add(skuParamsList);
				paramSb.append("->");
				paramSb.append(entity.getParamName5());
			}
			// 根据型号参数名字处理表格数据,如果此单元格为空就不处理(因为每个产品的型号数量不确定)
			if (StringUtils.isNotEmpty(entity.getParamName6())) {
				CodeProTypeJson.SkuParamsList skuParamsList = new CodeProTypeJson.SkuParamsList();
				skuParamsList.setParamId(IdWorker.getIdStr());
				skuParamsList.setParamName(entity.getParamName6());
				skuParamsList.setParamValue(entity.getParamValue6());
				listDate.add(skuParamsList);
				paramSb.append("->");
				paramSb.append(entity.getParamName6());
			}
			// 根据型号参数名字处理表格数据,如果此单元格为空就不处理(因为每个产品的型号数量不确定)
			if (StringUtils.isNotEmpty(entity.getParamName7())) {
				CodeProTypeJson.SkuParamsList skuParamsList = new CodeProTypeJson.SkuParamsList();
				skuParamsList.setParamId(IdWorker.getIdStr());
				skuParamsList.setParamName(entity.getParamName7());
				skuParamsList.setParamValue(entity.getParamValue7());
				listDate.add(skuParamsList);
				paramSb.append("->");
				paramSb.append(entity.getParamName7());
			}
			// 根据型号参数名字处理表格数据,如果此单元格为空就不处理(因为每个产品的型号数量不确定)
			if (StringUtils.isNotEmpty(entity.getParamName8())) {
				CodeProTypeJson.SkuParamsList skuParamsList = new CodeProTypeJson.SkuParamsList();
				skuParamsList.setParamId(IdWorker.getIdStr());
				skuParamsList.setParamName(entity.getParamName8());
				skuParamsList.setParamValue(entity.getParamValue8());
				listDate.add(skuParamsList);
				paramSb.append("->");
				paramSb.append(entity.getParamName8());
			}
			// 将参数名拼接后转换字符串
			String paramSbStr = paramSb.toString();
			// 根据当前行的产品名称去map集合获取已经存入的参数名的拼接串
			String paramNameMap = mapProductType.get(productName);
			if (Func.isNotBlank( paramNameMap ) && !paramNameMap.equals( paramSbStr )) {
				String msg = "[ " + paramNameMap + " ] 和 [ " + paramSbStr + " ] 型号参数名称、数量、顺序需保持一致";
				throw new ServiceException(" 产品名称为:[ " + productName + " ] 的型号参数与表格其他行的参数名称或顺序不一致,请修改!</br>" + msg);
			}
			// 如果校验通过后添加参数拼接串到map集合中
			mapProductType.put(productName, paramSbStr);

			json.setSkuParamsList(listDate);
			if (list == null) {
				list = new ArrayList<>();
			}

			List<CodeProTypeJson> typeJsons = map.get(productName);
			if (typeJsons != null && typeJsons.size() > 0) {
				typeJsons.add(json);
				map.put(productName, typeJsons);
			} else {
				list.add(json);
				map.put(productName, list);
			}
		}
	}

判断产品是否已经添加,如已添加就走修改逻辑,未添加就走添加逻辑 excel:entity

	// 判断产品是否已经添加,如已添加就走修改逻辑,未添加就走添加逻辑  excel:entity
	private static ProductEntity containsProductEntity(ProductEntity entity, List<ProductEntity> selectList) {
		for (ProductEntity item : selectList) {
			if (item.getCodeProName().equals(entity.getCodeProName())) {
				// 如果导入的产品名称和已经添加的产品名称相同,就追加型号,如果型号相同,就返回提示
				List<CodeProTypeJson> itemTypeJsonList = JSONObject.parseArray(Func.toStr(item.getCodeProType()), CodeProTypeJson.class);
				List<CodeProTypeJson> excelTypeJsonList = JSONObject.parseArray(Func.toStr(entity.getCodeProType()), CodeProTypeJson.class);
				for (CodeProTypeJson itemJson : itemTypeJsonList) {
					for (CodeProTypeJson excelJson : excelTypeJsonList) {
						if (Objects.equals(itemJson.getSkuName(), excelJson.getSkuName())) {
							throw new ServiceException(" 产品名称为: " + item.getCodeProName() + " 的 " + itemJson.getSkuName() + " 型号已存在,请先修改该型号");
						}
					}
				}
				// 比较 如果导入的产品名称和数据库已有的数据产品名称相同,就比对型号的名称和顺序是否一致,如果不一致就返回提示
				if (itemTypeJsonList != null && itemTypeJsonList.size() > 0 && excelTypeJsonList != null && excelTypeJsonList.size() > 0) {
					// 获取查询到的第一个型号的参数列表
					CodeProTypeJson codeProTypeJson = itemTypeJsonList.get(0);
					List<CodeProTypeJson.SkuParamsList> itemSkuParamsList = codeProTypeJson.getSkuParamsList();
					// 将参数名进行拼接
					StringBuilder sbItem = new StringBuilder();
					for (int i = 0; i < itemSkuParamsList.size(); i++) {
						CodeProTypeJson.SkuParamsList param = itemSkuParamsList.get(i);
						sbItem.append(param.getParamName());
						if (i < itemSkuParamsList.size() - 1) {
							sbItem.append("->");
						}
					}
					String itemTypeJson = sbItem.toString();
					// 遍历excel表格里面的所有型号对应的参数列表
					for (CodeProTypeJson json : excelTypeJsonList) {
						List<CodeProTypeJson.SkuParamsList> skuParamsList = json.getSkuParamsList();
						// 遍历某个型号的所有参数名,将参数名进行拼接
						StringBuilder sbJson = new StringBuilder();
						for (int i = 0; i < skuParamsList.size(); i++) {
							CodeProTypeJson.SkuParamsList param = skuParamsList.get(i);
							sbJson.append(param.getParamName());
							if (i < skuParamsList.size() - 1) {
								sbJson.append("->");
							}
						}
						String excelTypeJson = sbJson.toString();
						System.out.println("itemTypeJson " + itemTypeJson);
						System.out.println("excelTypeJson " + excelTypeJson);
						System.out.println(itemTypeJson.equals(excelTypeJson));
						// 比对数据库查询的 拼接参数和excel表格里面的 拼接参数是否一致
						if (!itemTypeJson.equals(excelTypeJson)) {
							String msg = "原参数[ " + itemTypeJson + " ] 新参数 [ " + excelTypeJson + " ]";
							throw new ServiceException(" 产品名称为:[ " + item.getCodeProName() + " ]的型号参数与已有参数名称不一致或顺序不一致,请修改!</br>" + msg);
						}
					}
				}
				itemTypeJsonList.addAll(excelTypeJsonList);
				entity.setCodeProType(JSON.toJSONString(itemTypeJsonList));
				entity.setCodeProTypeNum(itemTypeJsonList.size());
				entity.setId(item.getId());
				return entity;
			}
		}
		return null;
	}

ProductEntity实体类

package com.bluebird.code.entity;

import com.baomidou.mybatisplus.annotation.TableName;
import com.bluebird.core.tenant.mp.TenantEntity;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import lombok.EqualsAndHashCode;

/**
 * 赋码 - 产品表 实体类 
 */
@Data
@TableName("t_code_product")
@ApiModel(value = "Product对象", description = "赋码 - 产品表")
@EqualsAndHashCode(callSuper = true)
public class ProductEntity extends TenantEntity {

	/**
	 * 企业id
	 */
	@ApiModelProperty(value = "企业id")
	private Long enterpriseId;
	/**
	 * 产品名称
	 */
	@ApiModelProperty(value = "产品名称")
	private String codeProName;
	/**
	 * 产品编号
	 */
	@ApiModelProperty(value = "产品编号")
	private String codeProNum;
	/**
	 * 产品分类
	 */
	@ApiModelProperty(value = "产品分类")
	private Long categoryId;
	/**
	 * 产品图片
	 */
	@ApiModelProperty(value = "产品图片")
	private String codeProImage;

	/**
	 * 产品主图图片
	 */
	@ApiModelProperty(value = "产品主图图片")
	private String codeMainImage;


	/**
	 * 产品视频
	 */
	@ApiModelProperty(value = "产品视频")
	private String codeProVideo;
	/**
	 * 产品型号(第一组元素必须为规格型号)
	 *
	 * @see com.bluebird.code.dto.CodeProTypeJson
	 */
	@ApiModelProperty(value = "产品型号(第一组元素必须为规格型号)")
//	private CodeProTypeJson codeProType;
	private String codeProType;
	/**
	 * 产品简介
	 */
	@ApiModelProperty(value = "产品简介")
	private String codeProDesc;
	/**
	 * 规格数量
	 */
	@ApiModelProperty(value = "规格数量")
	private Integer codeProTypeNum;
	/**
	 * 排序
	 */
	@ApiModelProperty(value = "排序")
	private Integer sort;
	/**
	 * 备注
	 */
	@ApiModelProperty(value = "备注")
	private String remark;

}

CodeProTypeJson 产品型号Json对象 (第一组元素必须为规格型号)

package com.bluebird.code.dto;

import lombok.Data;

import java.util.List;

/***
 * 产品型号Json对象 (第一组元素必须为规格型号)
 *
 *
 * @return:
 * @date: 2024/6/20
 */
@Data
public class CodeProTypeJson {

	//产品id
	private String skuId;

	//产品型号
	private String skuName;

	//规格英文名称
	private String skuEnName;

	//产品规格参数List
	private List<SkuParamsList> skuParamsList;

	@Data
	public static class SkuParamsList {
		//规格id
		private String paramId;
		//规格名称
		private String paramName;
		//规格英文名称
		private String paramEnName;
		//规格参数值
		private String paramValue;
	}
}
相关推荐
lzb_kkk1 分钟前
【JavaEE】JUC的常见类
java·开发语言·java-ee
速盾cdn2 分钟前
速盾:vue的cdn是干嘛的?
服务器·前端·网络
安於宿命7 分钟前
【Linux】简易版shell
linux·运维·服务器
丶Darling.10 分钟前
MIT 6.S081 Lab1: Xv6 and Unix utilities翻译
服务器·unix·lab·mit 6.s081·英文翻译中文
黄小耶@18 分钟前
linux常见命令
linux·运维·服务器
爬山算法25 分钟前
Maven(28)如何使用Maven进行依赖解析?
java·maven
2401_857439691 小时前
SpringBoot框架在资产管理中的应用
java·spring boot·后端
怀旧6661 小时前
spring boot 项目配置https服务
java·spring boot·后端·学习·个人开发·1024程序员节
李老头探索1 小时前
Java面试之Java中实现多线程有几种方法
java·开发语言·面试
粤海科技君1 小时前
如何使用腾讯云GPU云服务器自建一个简单的类似ChatGPT、Kimi的会话机器人
服务器·chatgpt·机器人·腾讯云