记得上下班打卡 | git大法好,push需谨慎

Commit 27f158ac authored by 张国柄's avatar 张国柄

+api:店铺商品管理:批量导入数据;

parent c699e5dc
package com.liquidnet.service.goblin.dto;
import com.alibaba.excel.annotation.ExcelProperty;
import lombok.Data;
import java.math.BigDecimal;
@Data
public class GoblinGoodsImportDto {
@ExcelProperty(value = "商品编码")
private String spuCode;
@ExcelProperty(value = "商品名称")
private String spuName;
@ExcelProperty(value = "商品图片")
private String spuImgs;
@ExcelProperty(value = "商品规格")
private String skuSpec;
@ExcelProperty(value = "规格编码")
private String skuCode;
@ExcelProperty(value = "价格")
private BigDecimal price;
@ExcelProperty(value = "库存")
private Integer stock;
@ExcelProperty(value = "规格图片")
private String skuImg;
@ExcelProperty(value = "规格条码")
private String skuBarCode;
// @ExcelProperty(value = "商品条码")
// private String spuBarCode;
}
package com.liquidnet.service.goblin.controller.manage;
import com.liquidnet.common.exception.LiquidnetServiceException;
import com.liquidnet.commons.lang.util.CurrentUtil;
import com.liquidnet.service.base.ErrorMapping;
import com.liquidnet.service.base.ResponseDto;
import com.liquidnet.service.goblin.service.impl.manage.GoblinStoreMgtGoodsImportService;
import com.liquidnet.service.goblin.util.GoblinRedisUtils;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiImplicitParam;
import io.swagger.annotations.ApiImplicitParams;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;
import javax.validation.constraints.NotBlank;
import java.io.IOException;
@Api(tags = "店铺商品管理")
@Slf4j
@RestController
@RequestMapping("store/mgt/goods")
public class GoblinStoreMgtGoodsImportController {
@Autowired
GoblinRedisUtils goblinRedisUtils;
@Autowired
private GoblinStoreMgtGoodsImportService goblinStoreMgtGoodsImportService;
@PostMapping("/upload")
@ApiOperation(value = "批量导入数据", notes = "")
@ApiImplicitParams({
@ApiImplicitParam(type = "form", dataType = "File", name = "file", value = "文件", required = true),
@ApiImplicitParam(type = "form", dataType = "Integer", name = "dataType", value = "导入数据类型[1-商品数据]", example = "1"),
@ApiImplicitParam(type = "form", dataType = "String", name = "storeId", value = "店铺ID"),
})
public ResponseDto<String> upload(@RequestParam MultipartFile file, @RequestParam int dataType,
@RequestParam @NotBlank(message = "店铺ID不能为空") String storeId) {
String currentUid = CurrentUtil.getCurrentUid();
if (!goblinRedisUtils.hasStoreId(currentUid, storeId)) {
return ResponseDto.failure(ErrorMapping.get("149002"));
}
try {
switch (dataType) {
case 1:
goblinStoreMgtGoodsImportService.goodsInformationDataAnalysisProcessing(file, currentUid, storeId);
break;
case 2:
default:
return ResponseDto.failure(ErrorMapping.get("39001"));
}
} catch (LiquidnetServiceException e) {
return ResponseDto.failure(e.getMessage());
} catch (IOException e) {
log.error("店铺商品管理:批量导入数据:异常[UID={},dataType={},fileName={}]", currentUid, dataType, file.getOriginalFilename(), e);
return ResponseDto.failure("数据错误,解析失败");
}
return ResponseDto.success();
}
}
package com.liquidnet.service.goblin.service.impl.manage;
import com.alibaba.excel.EasyExcel;
import com.alibaba.excel.context.AnalysisContext;
import com.alibaba.excel.read.listener.PageReadListener;
import com.liquidnet.common.exception.LiquidnetServiceException;
import com.liquidnet.commons.lang.util.CollectionUtil;
import com.liquidnet.commons.lang.util.IDGenerator;
import com.liquidnet.commons.lang.util.JsonUtils;
import com.liquidnet.service.base.SqlMapping;
import com.liquidnet.service.base.constant.MQConst;
import com.liquidnet.service.goblin.dto.GoblinGoodsImportDto;
import com.liquidnet.service.goblin.dto.GoblinGoodsSpecDto;
import com.liquidnet.service.goblin.dto.vo.GoblinGoodsInfoVo;
import com.liquidnet.service.goblin.dto.vo.GoblinGoodsSkuInfoVo;
import com.liquidnet.service.goblin.dto.vo.GoblinGoodsSpecValueVo;
import com.liquidnet.service.goblin.dto.vo.GoblinGoodsSpecVo;
import com.liquidnet.service.goblin.util.GoblinMongoUtils;
import com.liquidnet.service.goblin.util.GoblinRedisUtils;
import com.liquidnet.service.goblin.util.ObjectUtil;
import com.liquidnet.service.goblin.util.QueueUtils;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.ArrayUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;
import java.io.IOException;
import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.util.*;
import java.util.regex.Pattern;
@Slf4j
@Service
public class GoblinStoreMgtGoodsImportService {
@Autowired
QueueUtils queueUtils;
@Autowired
GoblinRedisUtils goblinRedisUtils;
@Autowired
GoblinMongoUtils goblinMongoUtils;
/**
* 大小字母 || 数字
* 长度:0,50
*/
public static final String ALPHABET_NUMBER_UNDER_50 = "^[a-zA-Z0-9]{0,50}$";
/**
* 大小字母 || 数字
* 长度:0,32
*/
public static final String ALPHABET_NUMBER_32 = "^[a-zA-Z0-9]{0,32}$";
public void goodsInformationDataAnalysisProcessing(MultipartFile file, String uid, String storeId) throws IOException {
ArrayList<GoblinGoodsInfoVo> goodsInfoVos = ObjectUtil.goblinGoodsInfoVoArrayList();
ArrayList<GoblinGoodsSkuInfoVo> goodsSkuInfoVos = ObjectUtil.getGoblinGoodsSkuInfoVoArrayList();
LinkedList<Object[]> initGoodsSkuObjs = CollectionUtil.linkedListObjectArr();
EasyExcel.read(file.getInputStream(), GoblinGoodsImportDto.class, new PageReadListener<GoblinGoodsImportDto>(dts -> {
GoblinGoodsInfoVo lastGoodsInfoVo = null;
LocalDateTime now = LocalDateTime.now();
for (GoblinGoodsImportDto dt : dts) {
log.debug("dt1:{}", dt.toString());
if (StringUtils.isEmpty(dt.getSpuName()) || dt.getSpuName().length() > 100
|| StringUtils.isEmpty(dt.getSkuSpec())
|| null == dt.getPrice() || dt.getPrice().compareTo(BigDecimal.valueOf(0.01)) < 0 || dt.getPrice().compareTo(BigDecimal.valueOf(9999999)) > 0
|| null == dt.getStock() || dt.getStock() < 0 || dt.getStock() > 9999999
) {// 数据不规范停止解析并提示用户
throw new LiquidnetServiceException("-1", "数据内容不规范【请核实必填项信息】");
}
boolean tobeNextSpuFlg = false;
if (null == lastGoodsInfoVo || !lastGoodsInfoVo.getName().equals(dt.getSpuName())) {
lastGoodsInfoVo = GoblinGoodsInfoVo.getNew();
tobeNextSpuFlg = true;
}
if (tobeNextSpuFlg) {
lastGoodsInfoVo.setName(dt.getSpuName());//*
if (StringUtils.isNotEmpty(dt.getSpuCode())) {
if (Pattern.matches(ALPHABET_NUMBER_UNDER_50, dt.getSpuCode())) throw new LiquidnetServiceException("-1", "数据内容不规范【商品编码格式错误】");
lastGoodsInfoVo.setSpuId(IDGenerator.nextMilliId2() + dt.getSpuCode());//*
} else {
lastGoodsInfoVo.setSpuId(IDGenerator.nextMilliId2());//*
}
// if (StringUtils.isNotEmpty(dt.getSpuBarCode())) {
// lastGoodsInfoVo.setSpuNo(dt.getSpuBarCode());//*
// } else {
lastGoodsInfoVo.setSpuNo(lastGoodsInfoVo.getSpuId());//*
// }
if (StringUtils.isNotEmpty(dt.getSpuImgs())) {
if (!dt.getSkuImg().startsWith("【图片链接】")) throw new LiquidnetServiceException("-1", "数据内容不规范【商品图片格式错误】");
String[] spuImgsArr = dt.getSpuImgs().replace("【图片链接】", "").replace(";", ";").split(";");
if (spuImgsArr.length > 15) throw new LiquidnetServiceException("-1", "数据内容不规范【商品图片最多支持15张】");
List<String> imageList = Arrays.asList(spuImgsArr);
lastGoodsInfoVo.setImageList(imageList);
lastGoodsInfoVo.setCoverPic(imageList.get(0));
}
lastGoodsInfoVo.setSpuType(0);//*
lastGoodsInfoVo.setSpecMode("1");//*
lastGoodsInfoVo.setShelvesHandle("1");
lastGoodsInfoVo.setVirtualFlg("0");
lastGoodsInfoVo.setStatus("3");
lastGoodsInfoVo.setShelvesStatus("0");
lastGoodsInfoVo.setSpuAppear("0");//*
lastGoodsInfoVo.setSpuCanbuy("1");
lastGoodsInfoVo.setDelFlg("0");
lastGoodsInfoVo.setCreatedAt(now);
lastGoodsInfoVo.setCreatedBy(uid);//*
lastGoodsInfoVo.setStoreId(storeId);//*
this.goodsInformationDataAnalysisProcessingForSku(dt, lastGoodsInfoVo, uid, storeId, now, true, goodsSkuInfoVos, initGoodsSkuObjs);
goodsInfoVos.add(lastGoodsInfoVo);
} else {
this.goodsInformationDataAnalysisProcessingForSku(dt, lastGoodsInfoVo, uid, storeId, now, false, goodsSkuInfoVos, initGoodsSkuObjs);
}
log.debug("dt2:{}", lastGoodsInfoVo);
}
log.debug("dt3-1:{}", JsonUtils.toJson(goodsInfoVos));
log.debug("dt3-2:{}", JsonUtils.toJson(goodsSkuInfoVos));
goblinMongoUtils.insertMgtGoodsInfoVos(goodsInfoVos);
goblinMongoUtils.insertMgtGoodsSkuInfoVos(goodsSkuInfoVos);
goodsSkuInfoVos.forEach(r -> goblinRedisUtils.setSkuStock(null, r.getSkuId(), r.getSkuStock()));
LinkedList<String> toMqSqls = CollectionUtil.linkedListString();
toMqSqls.add(SqlMapping.get("goblin_goods.insert"));
LinkedList<Object[]> initGoodsObjs = CollectionUtil.linkedListObjectArr();
goodsInfoVos.forEach(r -> initGoodsObjs.add(new Object[]{
r.getSpuId(), r.getSpuNo(), r.getName(), r.getSubtitle(), r.getSellPrice(),
r.getPriceGe(), r.getPriceLe(), r.getIntro(), r.getDetails(), r.getCoverPic(),
r.getVideo(), r.getSpecMode(), r.getStoreId(), r.getCateFid(), r.getCateSid(),
r.getCateTid(), r.getStoreCateFid(), r.getStoreCateSid(), r.getStoreCateTid(), r.getBrandId(),
r.getShelvesHandle(), r.getShelvesTime(), r.getSpuValidity(), r.getVirtualFlg(), r.getStatus(),
r.getShelvesStatus(), r.getSpuAppear(), r.getShelvesAt(), r.getCreatedBy(), r.getCreatedAt(),
r.getLogisticsTemplate()
}));
toMqSqls.add(SqlMapping.get("goblin_goods_sku.insert"));
queueUtils.sendMsgByRedis(MQConst.GoblinQueue.SQL_GOODS.getKey(), SqlMapping.gets(toMqSqls, initGoodsObjs, initGoodsSkuObjs));
}) {
@Override
public void invoke(GoblinGoodsImportDto data, AnalysisContext context) {
Integer approximateTotalRowNumber = context.readSheetHolder().getApproximateTotalRowNumber();
if (approximateTotalRowNumber > 501) {
log.error("店铺商品管理:批量导入数据:异常[UID={},storeId={},totalRowNumber={}]", uid, storeId, approximateTotalRowNumber);
throw new LiquidnetServiceException("-1", "超出总行数限制500");
}
super.invoke(data, context);
}
}).sheet().doReadSync();
}
private void goodsInformationDataAnalysisProcessingForSku(GoblinGoodsImportDto dt, GoblinGoodsInfoVo lastGoodsInfoVo,
String uid, String storeId, LocalDateTime now, boolean hasNextSpuFlg,
List<GoblinGoodsSkuInfoVo> goodsSkuInfoVos, LinkedList<Object[]> initGoodsSkuObjs) {
GoblinGoodsSkuInfoVo skuInfoVo = GoblinGoodsSkuInfoVo.getNew();
skuInfoVo.setName("");
String[] skuSpecArr = dt.getSkuSpec().replace(":", ":").replace(";", ";").split(";");
List<GoblinGoodsSpecVo> spuSpecVos = hasNextSpuFlg ? ObjectUtil.getGoblinGoodsSpecVoArrayList() : lastGoodsInfoVo.getSpecVoList();
List<GoblinGoodsSpecDto> skuSpecDtos = ObjectUtil.getGoblinGoodsSpecDtoArrayList();
for (int i = 0, size = skuSpecArr.length; i < size; i++) {
String skuSpec = skuSpecArr[i];
if (StringUtils.isEmpty(skuSpec)) {// 数据不规范停止解析并提示用户
throw new LiquidnetServiceException("-1", "数据内容不规范【请核实商品规格信息】");
}
String[] specArr = skuSpec.split(":");
if (ArrayUtils.isEmpty(specArr) || specArr.length != 2
|| specArr[0].length() > 5 || specArr[1].length() > 40
) {// 数据不规范停止解析并提示用户
throw new LiquidnetServiceException("-1", "数据内容不规范【请核实商品规格信息】");
}
GoblinGoodsSpecDto skuSpecDto = GoblinGoodsSpecDto.getNew();
skuSpecDto.setSpecName(specArr[0]);
skuSpecDto.setSpecVname(specArr[1]);
skuSpecDtos.add(skuSpecDto);
skuInfoVo.setName(skuInfoVo.getName().concat(skuSpecDto.getSpecVname()));
if (hasNextSpuFlg) {
List<GoblinGoodsSpecValueVo> spuSpecValueVos = ObjectUtil.getGoblinGoodsSpecValueVoArrayList();
spuSpecValueVos.add(GoblinGoodsSpecValueVo.getNew().setSpecVname(skuSpecDto.getSpecVname()).setSpecVsort(1));
GoblinGoodsSpecVo spuSpecVo = GoblinGoodsSpecVo.getNew().setSpecName(skuSpecDto.getSpecName()).setSpecSort(i + 1).setSpecValues(spuSpecValueVos);
spuSpecVos.add(spuSpecVo);
} else {
Optional<GoblinGoodsSpecVo> hasSpecOptional = spuSpecVos.stream().filter(r -> r.getSpecName().equals(skuSpecDto.getSpecName())).findAny();
if (hasSpecOptional.isPresent()) {
GoblinGoodsSpecVo spuSpecVo = hasSpecOptional.get();
List<GoblinGoodsSpecValueVo> spuSpecValueVos = spuSpecVo.getSpecValues();
Optional<GoblinGoodsSpecValueVo> any = spuSpecValueVos.stream().filter(r -> r.getSpecVname().equals(skuSpecDto.getSpecVname())).findAny();
if (!any.isPresent()) {
spuSpecValueVos.add(
GoblinGoodsSpecValueVo.getNew().setSpecVname(skuSpecDto.getSpecVname()).setSpecVsort(lastGoodsInfoVo.getSkuIdList().size() + 1)
);
spuSpecVo.setSpecValues(spuSpecValueVos);
}
} else {// 不匹配的规格直接跳过(默认只匹配商品第一行数据中的规格项)
return;
}
}
}
skuInfoVo.setStock(dt.getStock());//*
skuInfoVo.setSkuStock(dt.getStock());//*
skuInfoVo.setPrice(dt.getPrice());//*
skuInfoVo.setPriceMember(dt.getPrice());//*
if (StringUtils.isNotEmpty(dt.getSkuCode())) {
if (Pattern.matches(ALPHABET_NUMBER_UNDER_50, dt.getSkuCode())) throw new LiquidnetServiceException("-1", "数据内容不规范【规格编码格式错误】");
skuInfoVo.setSkuId(lastGoodsInfoVo.getSpuId().concat(dt.getSkuCode()).concat(StringUtils.right(String.valueOf(System.nanoTime()), 5)));//*
} else {
skuInfoVo.setSkuId(lastGoodsInfoVo.getSpuId().concat(StringUtils.right(String.valueOf(System.nanoTime()), 5)));//*
}
if (StringUtils.isNotEmpty(dt.getSkuImg())) {
if (!dt.getSkuImg().startsWith("【图片链接】")) throw new LiquidnetServiceException("-1", "数据内容不规范【规格图片格式错误】");
String[] skuImgArr = dt.getSkuImg().replace("【图片链接】", "").replace(";", ";").split(";");
if (skuImgArr.length > 1) throw new LiquidnetServiceException("-1", "数据内容不规范【规格图片仅支持1张】");
skuInfoVo.setSkuPic(skuImgArr[0]);
}
if (StringUtils.isNotEmpty(dt.getSkuBarCode())) {
if (Pattern.matches(ALPHABET_NUMBER_32, dt.getSkuCode())) throw new LiquidnetServiceException("-1", "数据内容不规范【规格条码格式错误】");
skuInfoVo.setSkuNo(dt.getSkuBarCode());//*
} else {
skuInfoVo.setSkuNo(lastGoodsInfoVo.getSpuNo());//*
}
skuInfoVo.setSpuId(lastGoodsInfoVo.getSpuId());//*
skuInfoVo.setSkuType(0);//*
skuInfoVo.setBuyFactor("0");
skuInfoVo.setBuyLimit(0);
skuInfoVo.setStatus("3");
skuInfoVo.setShelvesStatus(lastGoodsInfoVo.getShelvesStatus());
skuInfoVo.setSoldoutStatus("0");//*
skuInfoVo.setSkuAppear("0");//*
skuInfoVo.setSkuCanbuy("1");
skuInfoVo.setDelFlg("0");
skuInfoVo.setCreatedAt(now);//*
skuInfoVo.setCreatedBy(uid);//*
skuInfoVo.setStoreId(storeId);
skuInfoVo.setSkuSpecList(skuSpecDtos);
goodsSkuInfoVos.add(skuInfoVo);
initGoodsSkuObjs.add(new Object[]{
skuInfoVo.getSkuId(), skuInfoVo.getSpuId(), skuInfoVo.getSkuNo(), skuInfoVo.getName(), skuInfoVo.getSubtitle(),
skuInfoVo.getSellPrice(), skuInfoVo.getSkuPic(), skuInfoVo.getSkuIsbn(), skuInfoVo.getStock(), skuInfoVo.getSkuStock(),
skuInfoVo.getWarningStock(), skuInfoVo.getPrice(), skuInfoVo.getPriceMember(), skuInfoVo.getWeight(), skuInfoVo.getBuyFactor(),
skuInfoVo.getBuyRoster(), skuInfoVo.getBuyLimit(), skuInfoVo.getStoreId(), skuInfoVo.getSkuValidity(), skuInfoVo.getVirtualFlg(),
skuInfoVo.getStatus(), skuInfoVo.getShelvesStatus(), skuInfoVo.getSkuAppear(), skuInfoVo.getShelvesAt(), uid,
now, skuInfoVo.getLogisticsTemplate()
});
if (hasNextSpuFlg) {
List<String> skuIdList = CollectionUtil.arrayListString();
skuIdList.add(skuInfoVo.getSkuId());
lastGoodsInfoVo.setSkuIdList(skuIdList);
lastGoodsInfoVo.setSpecVoList(spuSpecVos);
lastGoodsInfoVo.setPriceGe(skuInfoVo.getPrice());
lastGoodsInfoVo.setPriceLe(skuInfoVo.getPrice());
} else {
BigDecimal priceGe = lastGoodsInfoVo.getPriceGe();
BigDecimal priceLe = lastGoodsInfoVo.getPriceLe();
List<String> skuIdList = lastGoodsInfoVo.getSkuIdList();
skuIdList.add(skuInfoVo.getSkuId());
lastGoodsInfoVo.setSkuIdList(skuIdList);
lastGoodsInfoVo.setSpecVoList(spuSpecVos);
lastGoodsInfoVo.setPriceGe(skuInfoVo.getPrice().compareTo(priceGe) < 0 ? skuInfoVo.getPrice() : priceGe);
lastGoodsInfoVo.setPriceLe(priceLe.compareTo(skuInfoVo.getPrice()) < 0 ? skuInfoVo.getPrice() : priceLe);
}
}
}
......@@ -506,6 +506,10 @@ public class GoblinMongoUtils {
return mongoTemplate.insert(vo, GoblinGoodsInfoVo.class.getSimpleName());
}
public List<GoblinGoodsInfoVo> insertMgtGoodsInfoVos(List<GoblinGoodsInfoVo> vos) {
return (List<GoblinGoodsInfoVo>) mongoTemplate.insert(vos, GoblinGoodsInfoVo.class.getSimpleName());
}
public void upsertGoodsInfoVo(GoblinGoodsInfoVo vo) {
Document document = (Document) mongoConverter.convertToMongoType(vo);
Update update = Update.fromDocument(document);
......@@ -739,6 +743,10 @@ public class GoblinMongoUtils {
return mongoTemplate.insert(vo, GoblinGoodsSkuInfoVo.class.getSimpleName());
}
public List<GoblinGoodsSkuInfoVo> insertMgtGoodsSkuInfoVos(List<GoblinGoodsSkuInfoVo> vos) {
return (List<GoblinGoodsSkuInfoVo>) mongoTemplate.insert(vos, GoblinGoodsSkuInfoVo.class.getSimpleName());
}
public UpdateResult upsertGoodsSkuInfoVo(GoblinGoodsSkuInfoVo vo) {
Document document = (Document) mongoConverter.convertToMongoType(vo);
Update update = Update.fromDocument(document);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment