商品,品牌,商品分类excle导入新功能,未测试
This commit is contained in:
parent
c31b094cce
commit
8b65072fea
@ -0,0 +1,92 @@
|
|||||||
|
package com.suisung.mall.shop.sync.controller;
|
||||||
|
|
||||||
|
import com.suisung.mall.common.api.CommonResult;
|
||||||
|
import com.suisung.mall.common.service.impl.BaseControllerImpl;
|
||||||
|
import com.suisung.mall.shop.sync.service.ShopSyncImportService;
|
||||||
|
import io.swagger.annotations.ApiOperation;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.web.bind.annotation.*;
|
||||||
|
import org.springframework.web.multipart.MultipartFile;
|
||||||
|
|
||||||
|
import javax.servlet.http.HttpServletResponse;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 商品数据导入,
|
||||||
|
* 包括,分类,和商品的 导入,导入之后自动生成分类的其他属性,由于系统的局限性,品牌不做导入,默认生成其他匹配
|
||||||
|
*/
|
||||||
|
@RestController
|
||||||
|
@RequestMapping("/admin/shop/shop-sync-import")
|
||||||
|
@lombok.extern.slf4j.Slf4j
|
||||||
|
public class ShopSyncImportController extends BaseControllerImpl {
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private ShopSyncImportService shopSyncImportService;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 品牌导入模板下载
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
@ApiOperation(value = "品牌导入模板下载", notes = "模板下载")
|
||||||
|
@RequestMapping(value = "/brandTemplate", method = RequestMethod.GET)
|
||||||
|
public void brandTemplate(HttpServletResponse response) {
|
||||||
|
shopSyncImportService.downloadBrandTemplate(response);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 商品分类导入模板下载
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
@ApiOperation(value = "商品分类导入模板下载", notes = "模板下载")
|
||||||
|
@RequestMapping(value = "/categoryTemplate", method = RequestMethod.GET)
|
||||||
|
public void categoryTemplate(HttpServletResponse response) {
|
||||||
|
shopSyncImportService.downloadCategoryTemplate(response);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 商品导入模板下载
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
@ApiOperation(value = "商品导入模板下载", notes = "模板下载")
|
||||||
|
@RequestMapping(value = "/shopTemplate", method = RequestMethod.GET)
|
||||||
|
public void shopTemplate(HttpServletResponse response) {
|
||||||
|
shopSyncImportService.downloadShopsTemplate(response);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 品牌数据导入
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
@ApiOperation(value = "品牌数据导入", notes = "品牌数据导入")
|
||||||
|
@RequestMapping(value = "/brandImportData", method = RequestMethod.POST)
|
||||||
|
public CommonResult brandImportData(@RequestParam("file") MultipartFile file,@RequestParam("storeId")String storeId) {
|
||||||
|
// ImportResult result = productMappingService.importData(file);
|
||||||
|
// return !result.getErrorMessages().isEmpty() ?CommonResult.failed((IErrorCode) result.getErrorMessages()):CommonResult.success(result);
|
||||||
|
return shopSyncImportService.importBrandData(file,storeId);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 商品分类导入数据
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
@ApiOperation(value = "商品分类数据导入", notes = "分类数据导入")
|
||||||
|
@RequestMapping(value = "/categoryImportData", method = RequestMethod.POST)
|
||||||
|
public CommonResult categoryImportData(@RequestParam("file") MultipartFile file,@RequestParam("storeId")String storeId) {
|
||||||
|
// ImportResult result = productMappingService.importData(file);
|
||||||
|
// return !result.getErrorMessages().isEmpty() ?CommonResult.failed((IErrorCode) result.getErrorMessages()):CommonResult.success(result);
|
||||||
|
return shopSyncImportService.importCategoryData(file,storeId);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 商品导入数据
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
@ApiOperation(value = "商品数据导入", notes = "分类数据导入")
|
||||||
|
@RequestMapping(value = "/shopImportData", method = RequestMethod.POST)
|
||||||
|
public CommonResult shopImportData(@RequestParam("file") MultipartFile file,@RequestParam("storeId")String storeId) {
|
||||||
|
// ImportResult result = productMappingService.importData(file);
|
||||||
|
// return !result.getErrorMessages().isEmpty() ?CommonResult.failed((IErrorCode) result.getErrorMessages()):CommonResult.success(result);
|
||||||
|
shopSyncImportService.importShopsData(file,storeId);
|
||||||
|
return CommonResult.success("服务器正则处理文件,稍后查看商品列表");
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@ -28,5 +28,6 @@ public class SxCategoryModel {
|
|||||||
private String first_category_name;
|
private String first_category_name;
|
||||||
@ApiModelProperty(value = "第二级父类")
|
@ApiModelProperty(value = "第二级父类")
|
||||||
private String second_category_name;
|
private String second_category_name;
|
||||||
|
@ApiModelProperty(value = "品牌名称")
|
||||||
|
private String brandName;
|
||||||
}
|
}
|
||||||
@ -0,0 +1,23 @@
|
|||||||
|
package com.suisung.mall.shop.sync.exelModel;
|
||||||
|
|
||||||
|
|
||||||
|
import com.alibaba.excel.annotation.ExcelIgnore;
|
||||||
|
import com.alibaba.excel.annotation.ExcelProperty;
|
||||||
|
import io.swagger.annotations.ApiModelProperty;
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
@Data
|
||||||
|
public class BrandModelExcel{
|
||||||
|
public static final String TEMPLATE_NAME = "品牌导入模板.xlsx";
|
||||||
|
@ApiModelProperty("品牌名称")
|
||||||
|
@ExcelProperty(value = "商品名称", index = 0)
|
||||||
|
private String brand_name;
|
||||||
|
|
||||||
|
@ApiModelProperty("品牌描述")
|
||||||
|
@ExcelProperty(value = "品牌描述", index = 1)
|
||||||
|
private String brand_desc;
|
||||||
|
|
||||||
|
@ApiModelProperty("是否推荐")
|
||||||
|
@ExcelIgnore
|
||||||
|
private String brand_recommend="0";
|
||||||
|
}
|
||||||
@ -0,0 +1,44 @@
|
|||||||
|
package com.suisung.mall.shop.sync.exelModel;
|
||||||
|
|
||||||
|
import com.alibaba.excel.annotation.ExcelIgnore;
|
||||||
|
import com.alibaba.excel.annotation.ExcelProperty;
|
||||||
|
import io.swagger.annotations.ApiModelProperty;
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 模型对应
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
public class SxCategoryModelExcel {
|
||||||
|
public static final String TEMPLATE_NAME = "商品分类导入模板.xlsx";
|
||||||
|
@ApiModelProperty(value = "商品分类名称")
|
||||||
|
@ExcelProperty(value = "商品分类名称", index = 0)
|
||||||
|
private String category_name;
|
||||||
|
@ApiModelProperty(value = "分类图片")
|
||||||
|
@ExcelIgnore
|
||||||
|
private String category_image="https://digitalassets.tesla.com/tesla-contents/image/upload/f_auto,q_auto/Homepage-Model-Y-2-Promo-Hero-Tablet-CN.png";
|
||||||
|
@ApiModelProperty(value = "是否允许虚拟商品(ENUM):1-是; 0-否")
|
||||||
|
@ExcelIgnore
|
||||||
|
private Integer category_virtual_enable=0;
|
||||||
|
/**
|
||||||
|
* 产品类型=商品分类名称
|
||||||
|
*/
|
||||||
|
@ApiModelProperty(value = "产品类型")
|
||||||
|
@ExcelIgnore
|
||||||
|
private String product_type=category_name;
|
||||||
|
/**
|
||||||
|
* 第一级分类 当前分类的最顶层,如 生鲜->蔬菜->菜苗 如果当前分类(category_name)为菜苗,则第一级分类是”生鲜“,第二级分类是”蔬菜“,如果当前分类是蔬菜,则第一级分类是生鲜,第二级分类为空
|
||||||
|
* 第二级分类 当前分类最顶层数的第二层
|
||||||
|
*/
|
||||||
|
@ApiModelProperty(value = "第一级分类")
|
||||||
|
@ExcelProperty(value = "第一级分类", index = 1)
|
||||||
|
private String first_category_name;
|
||||||
|
@ApiModelProperty(value = "第二级分类")
|
||||||
|
@ExcelProperty(value = "第二级分类", index =2)
|
||||||
|
private String second_category_name;
|
||||||
|
|
||||||
|
@ApiModelProperty(value = "品牌名称")
|
||||||
|
@ExcelIgnore
|
||||||
|
private String brandName="其他品牌";
|
||||||
|
}
|
||||||
@ -0,0 +1,52 @@
|
|||||||
|
package com.suisung.mall.shop.sync.exelModel;
|
||||||
|
|
||||||
|
import com.alibaba.excel.annotation.ExcelIgnore;
|
||||||
|
import com.alibaba.excel.annotation.ExcelProperty;
|
||||||
|
import io.swagger.annotations.ApiModelProperty;
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
import java.math.BigDecimal;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 思迅同步商品数据入口数据
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
public class SxGoosModelExcel {
|
||||||
|
public static final String TEMPLATE_NAME = "商品导入模板.xlsx";
|
||||||
|
@ApiModelProperty("商品名称")
|
||||||
|
@ExcelProperty(value = "商品名称", index = 0)
|
||||||
|
private String product_name;
|
||||||
|
|
||||||
|
@ApiModelProperty("商品货号")
|
||||||
|
@ExcelProperty(value = "商品货号", index = 1)
|
||||||
|
private String product_number;
|
||||||
|
|
||||||
|
@ApiModelProperty("商品条形码")
|
||||||
|
@ExcelProperty(value = "商品条形码", index = 2)
|
||||||
|
private String product_barcode;
|
||||||
|
|
||||||
|
@ApiModelProperty("所属分类")
|
||||||
|
@ExcelProperty(value = "所属分类", index = 3)
|
||||||
|
private String first_category_name;
|
||||||
|
|
||||||
|
@ApiModelProperty("零售价")
|
||||||
|
@ExcelProperty(value = "零售价", index = 4)
|
||||||
|
private BigDecimal retail_price;
|
||||||
|
|
||||||
|
@ApiModelProperty("原价")
|
||||||
|
@ExcelIgnore
|
||||||
|
private BigDecimal original_price=retail_price;
|
||||||
|
|
||||||
|
@ApiModelProperty("库存")
|
||||||
|
@ExcelProperty(value = "库存", index = 5)
|
||||||
|
private BigDecimal stock;
|
||||||
|
|
||||||
|
@ApiModelProperty("规格单位")
|
||||||
|
@ExcelProperty(value = "规格单位", index = 6)
|
||||||
|
private String unit;
|
||||||
|
|
||||||
|
@ApiModelProperty("最大购买商品量")
|
||||||
|
@ExcelProperty(value = "最大购买商品量", index = 7)
|
||||||
|
private Integer buy_limit;
|
||||||
|
|
||||||
|
}
|
||||||
@ -0,0 +1,118 @@
|
|||||||
|
package com.suisung.mall.shop.sync.listen;
|
||||||
|
|
||||||
|
import cn.hutool.json.JSONArray;
|
||||||
|
import com.alibaba.excel.context.AnalysisContext;
|
||||||
|
import com.alibaba.excel.event.AnalysisEventListener;
|
||||||
|
import com.google.gson.Gson;
|
||||||
|
import com.suisung.mall.shop.sync.exelModel.SxGoosModelExcel;
|
||||||
|
import com.suisung.mall.shop.sync.service.SyncThirdDataService;
|
||||||
|
import lombok.Getter;
|
||||||
|
import lombok.Setter;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.concurrent.*;
|
||||||
|
import java.util.concurrent.atomic.AtomicInteger;
|
||||||
|
|
||||||
|
@Component
|
||||||
|
@Slf4j
|
||||||
|
public class ShopBatchSubmitListener extends AnalysisEventListener<SxGoosModelExcel> {
|
||||||
|
// 批处理阈值
|
||||||
|
private static final int BATCH_SIZE = 10;
|
||||||
|
// 数据缓存
|
||||||
|
private List<SxGoosModelExcel> cachedDataList = new ArrayList<>(BATCH_SIZE);
|
||||||
|
|
||||||
|
private SyncThirdDataService syncThirdDataService;
|
||||||
|
|
||||||
|
// 线程池配置
|
||||||
|
private final ExecutorService executorService;
|
||||||
|
|
||||||
|
private List<Future<?>> futures ;
|
||||||
|
private AtomicInteger success;
|
||||||
|
private AtomicInteger fails;
|
||||||
|
private AtomicInteger batchSize;
|
||||||
|
@Setter
|
||||||
|
@Getter
|
||||||
|
private String storeId;
|
||||||
|
|
||||||
|
@Setter
|
||||||
|
@Getter
|
||||||
|
private String isNegativeAllowed;
|
||||||
|
|
||||||
|
@Setter
|
||||||
|
@Getter
|
||||||
|
private Map<String,Integer> brandMaps;
|
||||||
|
|
||||||
|
|
||||||
|
public ShopBatchSubmitListener(SyncThirdDataService syncThirdDataService) {
|
||||||
|
this.syncThirdDataService = syncThirdDataService;
|
||||||
|
// 创建线程池(根据CPU核心数优化)
|
||||||
|
int corePoolSize = Runtime.getRuntime().availableProcessors();
|
||||||
|
this.executorService = Executors.newFixedThreadPool(corePoolSize);
|
||||||
|
this.futures = new ArrayList<>();
|
||||||
|
this.success = new AtomicInteger();
|
||||||
|
this.fails = new AtomicInteger();
|
||||||
|
this.batchSize= new AtomicInteger();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void invoke(SxGoosModelExcel sxGoosModelExcel, AnalysisContext analysisContext) {
|
||||||
|
synchronized (cachedDataList) {
|
||||||
|
cachedDataList.add(sxGoosModelExcel);
|
||||||
|
// 达到批处理阈值时提交
|
||||||
|
if (cachedDataList.size() >= BATCH_SIZE) {
|
||||||
|
batchSize.incrementAndGet();
|
||||||
|
submitBatch();
|
||||||
|
// 提交后清空缓存
|
||||||
|
cachedDataList.clear();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void doAfterAllAnalysed(AnalysisContext context) {
|
||||||
|
synchronized (cachedDataList) {
|
||||||
|
// 处理最后一批不足BATCH_SIZE的数据
|
||||||
|
if (!cachedDataList.isEmpty()) {
|
||||||
|
batchSize.incrementAndGet();
|
||||||
|
submitBatch();
|
||||||
|
cachedDataList.clear();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// 等待所有任务完成
|
||||||
|
for (Future<?> future : futures) {
|
||||||
|
try {
|
||||||
|
log.info("任务结果:{}" ,future.get());
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.info("任务执行异常: {}", e.getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
log.info("Excel解析完成,总处理条数: {}" , context.readSheetHolder().getTotal());
|
||||||
|
log.info("成功数量:{};失败数量:{}",success.get(),fails.get());
|
||||||
|
// 关闭线程池
|
||||||
|
executorService.shutdown();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void submitBatch() {
|
||||||
|
// 复制当前批次数据(避免异步修改)
|
||||||
|
List<SxGoosModelExcel> batchCopy = new ArrayList<>(cachedDataList);
|
||||||
|
futures.add(executorService.submit(()->{
|
||||||
|
try {
|
||||||
|
Gson gson=new Gson();
|
||||||
|
String jsonShops=gson.toJson(batchCopy);
|
||||||
|
JSONArray jsonArray=new JSONArray(jsonShops);
|
||||||
|
syncThirdDataService.baseSaveOrUpdateGoodsBatch(jsonArray,storeId,isNegativeAllowed,brandMaps);
|
||||||
|
log.info("已提交批次: {} 条", cachedDataList.size());
|
||||||
|
success.getAndIncrement();
|
||||||
|
return "完成"+batchSize.get();
|
||||||
|
} catch (Exception e) {
|
||||||
|
fails.getAndIncrement();
|
||||||
|
return "失败:"+batchSize.get()+";失败原因:"+e.getMessage();
|
||||||
|
}
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@ -0,0 +1,30 @@
|
|||||||
|
package com.suisung.mall.shop.sync.service;
|
||||||
|
|
||||||
|
import com.suisung.mall.common.api.CommonResult;
|
||||||
|
import org.springframework.web.multipart.MultipartFile;
|
||||||
|
|
||||||
|
import javax.servlet.http.HttpServletResponse;
|
||||||
|
|
||||||
|
|
||||||
|
public interface ShopSyncImportService{
|
||||||
|
|
||||||
|
|
||||||
|
// 下载品牌导入模板
|
||||||
|
void downloadBrandTemplate(HttpServletResponse response);
|
||||||
|
|
||||||
|
// 下载商品分类导入模板
|
||||||
|
void downloadCategoryTemplate(HttpServletResponse response);
|
||||||
|
|
||||||
|
// 下载商品导入模板
|
||||||
|
void downloadShopsTemplate(HttpServletResponse response);
|
||||||
|
|
||||||
|
// 导入品牌Excel数据
|
||||||
|
CommonResult importBrandData(MultipartFile file,String storeId);
|
||||||
|
|
||||||
|
|
||||||
|
// 导入商品分类Excel数据
|
||||||
|
CommonResult importCategoryData(MultipartFile file,String storeId);
|
||||||
|
|
||||||
|
// 导入商品Excel数据
|
||||||
|
void importShopsData(MultipartFile file,String storeId);
|
||||||
|
}
|
||||||
@ -10,6 +10,8 @@ package com.suisung.mall.shop.sync.service;
|
|||||||
|
|
||||||
import cn.hutool.json.JSONArray;
|
import cn.hutool.json.JSONArray;
|
||||||
import com.suisung.mall.common.api.CommonResult;
|
import com.suisung.mall.common.api.CommonResult;
|
||||||
|
import com.suisung.mall.common.modules.base.ShopBaseProductBrand;
|
||||||
|
import com.suisung.mall.common.modules.base.ShopBaseProductCategory;
|
||||||
import com.suisung.mall.common.pojo.req.SyncThirdMemberReq;
|
import com.suisung.mall.common.pojo.req.SyncThirdMemberReq;
|
||||||
import com.suisung.mall.common.pojo.res.ThirdApiRes;
|
import com.suisung.mall.common.pojo.res.ThirdApiRes;
|
||||||
import org.springframework.core.io.Resource;
|
import org.springframework.core.io.Resource;
|
||||||
@ -169,4 +171,30 @@ public interface SyncThirdDataService {
|
|||||||
ThirdApiRes syncRefreshTime(@RequestParam String appKey, @RequestParam String sign);
|
ThirdApiRes syncRefreshTime(@RequestParam String appKey, @RequestParam String sign);
|
||||||
|
|
||||||
CommonResult importLibProductImg(String updateTime);
|
CommonResult importLibProductImg(String updateTime);
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 保存品牌接口
|
||||||
|
* 内部使用
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
int baseSaveOrUpdateShopBaseProductBrandBatch(List<ShopBaseProductBrand> goodBrandList,String storeId,JSONArray brandListJSON);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 保存商品分类接口
|
||||||
|
* 内部使用
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
int baseSaveOrUpdateShopBaseProductCategoryBatch(List<ShopBaseProductCategory> list , JSONArray categoryListJSON,
|
||||||
|
String storeId);
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 保存商品接口
|
||||||
|
* 内部使用
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
int baseSaveOrUpdateGoodsBatch(JSONArray goodsListJSON,String storeId,String isNegativeAllowed,
|
||||||
|
Map<String,Integer> brandMaps);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -0,0 +1,215 @@
|
|||||||
|
package com.suisung.mall.shop.sync.service.impl;
|
||||||
|
|
||||||
|
import cn.hutool.json.JSONArray;
|
||||||
|
import cn.hutool.json.JSONUtil;
|
||||||
|
import com.alibaba.excel.EasyExcel;
|
||||||
|
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
|
||||||
|
import com.google.gson.Gson;
|
||||||
|
import com.suisung.mall.common.api.CommonResult;
|
||||||
|
import com.suisung.mall.common.exception.ApiException;
|
||||||
|
import com.suisung.mall.common.modules.base.ShopBaseProductBrand;
|
||||||
|
import com.suisung.mall.common.modules.base.ShopBaseProductCategory;
|
||||||
|
import com.suisung.mall.common.modules.sync.StoreDbConfig;
|
||||||
|
import com.suisung.mall.shop.base.service.ShopBaseProductBrandService;
|
||||||
|
import com.suisung.mall.shop.sync.excleHandle.TemplateStyleHandler;
|
||||||
|
import com.suisung.mall.shop.sync.exelModel.*;
|
||||||
|
import com.suisung.mall.shop.sync.listen.ShopBatchSubmitListener;
|
||||||
|
import com.suisung.mall.shop.sync.service.ShopSyncImportService;
|
||||||
|
import com.suisung.mall.shop.sync.service.StoreDbConfigService;
|
||||||
|
import com.suisung.mall.shop.sync.service.SyncThirdDataService;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.beans.factory.annotation.Value;
|
||||||
|
import org.springframework.scheduling.annotation.Async;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
import org.springframework.web.multipart.MultipartFile;
|
||||||
|
|
||||||
|
import javax.servlet.http.HttpServletResponse;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.UnsupportedEncodingException;
|
||||||
|
import java.net.URLEncoder;
|
||||||
|
import java.nio.file.Files;
|
||||||
|
import java.nio.file.Path;
|
||||||
|
import java.nio.file.Paths;
|
||||||
|
import java.nio.file.StandardCopyOption;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
@Service
|
||||||
|
@Slf4j
|
||||||
|
public class ShopSyncImportServiceImpl implements ShopSyncImportService {
|
||||||
|
@Value("${file.upload-dir}")
|
||||||
|
private String uploadDir;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private SyncThirdDataService syncThirdDataService;
|
||||||
|
@Autowired
|
||||||
|
private ShopBaseProductBrandService productBrandService;
|
||||||
|
@Autowired
|
||||||
|
private StoreDbConfigService storeDbConfigService;
|
||||||
|
private final int limitCnt = 100;
|
||||||
|
@Override
|
||||||
|
public void downloadBrandTemplate(HttpServletResponse response) {
|
||||||
|
try {
|
||||||
|
// 设置响应头
|
||||||
|
setExcelResponseHeader(response, BrandModelExcel.TEMPLATE_NAME);
|
||||||
|
// 创建空模板
|
||||||
|
EasyExcel.write(response.getOutputStream(), BrandModelExcel.class)
|
||||||
|
.sheet("商品品牌")
|
||||||
|
.registerWriteHandler(new TemplateStyleHandler())
|
||||||
|
.doWrite(new ArrayList<>());
|
||||||
|
} catch (IOException e) {
|
||||||
|
log.error("商品品牌下载模板失败", e);
|
||||||
|
throw new RuntimeException("商品品牌下载模板失败");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void downloadCategoryTemplate(HttpServletResponse response) {
|
||||||
|
try {
|
||||||
|
// 设置响应头
|
||||||
|
setExcelResponseHeader(response, SxCategoryModelExcel.TEMPLATE_NAME);
|
||||||
|
// 创建空模板
|
||||||
|
EasyExcel.write(response.getOutputStream(), SxCategoryModelExcel.class)
|
||||||
|
.sheet("商品分类")
|
||||||
|
.registerWriteHandler(new TemplateStyleHandler())
|
||||||
|
.doWrite(new ArrayList<>());
|
||||||
|
} catch (IOException e) {
|
||||||
|
log.error("商品分类下载模板失败", e);
|
||||||
|
throw new RuntimeException("商品分类下载模板失败");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void downloadShopsTemplate(HttpServletResponse response) {
|
||||||
|
try {
|
||||||
|
// 设置响应头
|
||||||
|
setExcelResponseHeader(response, SxGoosModelExcel.TEMPLATE_NAME);
|
||||||
|
// 创建空模板
|
||||||
|
EasyExcel.write(response.getOutputStream(), SxGoosModelExcel.class)
|
||||||
|
.sheet("商品")
|
||||||
|
.registerWriteHandler(new TemplateStyleHandler())
|
||||||
|
.doWrite(new ArrayList<>());
|
||||||
|
} catch (IOException e) {
|
||||||
|
log.error("商品下载模板失败", e);
|
||||||
|
throw new RuntimeException("商品下载模板失败");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public CommonResult importBrandData(MultipartFile file,String storeId) {
|
||||||
|
String fileName = storeUploadedFile(file);
|
||||||
|
try {
|
||||||
|
List<BrandModelExcel> excelList = readBrandExcelData(fileName);
|
||||||
|
if(excelList.isEmpty()) {
|
||||||
|
return CommonResult.failed("品牌数据为空");
|
||||||
|
}
|
||||||
|
if(excelList.size()>limitCnt){
|
||||||
|
return CommonResult.failed("导入品牌数据超过"+limitCnt+"条");
|
||||||
|
}
|
||||||
|
Gson gson=new Gson();
|
||||||
|
String brandJsonStr=gson.toJson(excelList);
|
||||||
|
JSONArray jsonArray=new JSONArray(brandJsonStr);
|
||||||
|
List<ShopBaseProductBrand> goodBrandList = JSONUtil.toList(jsonArray, ShopBaseProductBrand.class);
|
||||||
|
syncThirdDataService.baseSaveOrUpdateShopBaseProductBrandBatch(goodBrandList,storeId,jsonArray);
|
||||||
|
return CommonResult.success();
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.error("导入品牌数据失败", e);
|
||||||
|
throw new RuntimeException("导入品牌数据失败: " + e.getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public CommonResult importCategoryData(MultipartFile file,String storeId) {
|
||||||
|
String fileName = storeUploadedFile(file);
|
||||||
|
try {
|
||||||
|
List<SxCategoryModelExcel> excelList = readCategoryExcelData(fileName);
|
||||||
|
if(excelList.isEmpty()) {
|
||||||
|
return CommonResult.failed("商品分类数据为空");
|
||||||
|
}
|
||||||
|
if(excelList.size()>limitCnt){
|
||||||
|
return CommonResult.failed("导入商品分类数据超过"+limitCnt+"条");
|
||||||
|
}
|
||||||
|
Gson gson=new Gson();
|
||||||
|
String brandJsonStr=gson.toJson(excelList);
|
||||||
|
JSONArray jsonArray=new JSONArray(brandJsonStr);
|
||||||
|
List<ShopBaseProductCategory> goodBrandList = JSONUtil.toList(jsonArray, ShopBaseProductCategory.class);
|
||||||
|
syncThirdDataService.baseSaveOrUpdateShopBaseProductCategoryBatch(goodBrandList,jsonArray,storeId);
|
||||||
|
return CommonResult.success();
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.error("导入数据失败", e);
|
||||||
|
throw new ApiException("导入数据失败: " + e.getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@Async
|
||||||
|
public void importShopsData(MultipartFile file,String storeId) {
|
||||||
|
String fileName = storeUploadedFile(file);
|
||||||
|
readAndImportShopsExcelData(fileName,storeId);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 存储上传文件
|
||||||
|
private String storeUploadedFile(MultipartFile file) {
|
||||||
|
if (file.isEmpty()) {
|
||||||
|
throw new RuntimeException("上传文件为空");
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
String fileName = System.currentTimeMillis() + "_" + file.getOriginalFilename();
|
||||||
|
String prexfix = fileName.substring(fileName.lastIndexOf(".")).toLowerCase();//后缀名称
|
||||||
|
if(!prexfix.contains("xlsx")||!prexfix.contains("xls")) {
|
||||||
|
throw new ApiException("必须为excel文件");
|
||||||
|
}
|
||||||
|
Path filePath = Paths.get(uploadDir, fileName);
|
||||||
|
Files.createDirectories(filePath.getParent());
|
||||||
|
Files.copy(file.getInputStream(), filePath, StandardCopyOption.REPLACE_EXISTING);
|
||||||
|
return filePath.toString();
|
||||||
|
} catch (IOException e) {
|
||||||
|
log.error("存储上传文件失败", e);
|
||||||
|
throw new RuntimeException("存储上传文件失败");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// 设置Excel响应头
|
||||||
|
private void setExcelResponseHeader(HttpServletResponse response, String fileName) {
|
||||||
|
try {
|
||||||
|
response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
|
||||||
|
response.setCharacterEncoding("utf-8");
|
||||||
|
String encodedFileName = URLEncoder.encode(fileName, "UTF-8").replaceAll("\\+", "%20");
|
||||||
|
response.setHeader("Content-disposition", "attachment;filename*=utf-8''" + encodedFileName);
|
||||||
|
} catch (UnsupportedEncodingException e) {
|
||||||
|
throw new RuntimeException("文件名编码失败");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 读取品牌Excel数据
|
||||||
|
private List<BrandModelExcel> readBrandExcelData(String filePath) {
|
||||||
|
return EasyExcel.read(filePath)
|
||||||
|
.head(BrandModelExcel.class)
|
||||||
|
.sheet()
|
||||||
|
.doReadSync();
|
||||||
|
}
|
||||||
|
// 读取商品分类Excel数据
|
||||||
|
private List<SxCategoryModelExcel> readCategoryExcelData(String filePath) {
|
||||||
|
return EasyExcel.read(filePath)
|
||||||
|
.head(SxCategoryModelExcel.class)
|
||||||
|
.sheet()
|
||||||
|
.doReadSync();
|
||||||
|
}
|
||||||
|
|
||||||
|
// 读取商品Excel数据
|
||||||
|
private void readAndImportShopsExcelData(String filePath,String storeId) {
|
||||||
|
Map<String, Integer> brandMaps = productBrandService.getBrandMapByStoreId(storeId);
|
||||||
|
QueryWrapper<StoreDbConfig> storeDbConfigQueryWrapper = new QueryWrapper<>();
|
||||||
|
storeDbConfigQueryWrapper.eq("store_id", storeId);
|
||||||
|
StoreDbConfig storeDbConfig = storeDbConfigService.getOne(storeDbConfigQueryWrapper);
|
||||||
|
String isNegativeAllowed = storeDbConfig.getIsNegativeAllowed();
|
||||||
|
ShopBatchSubmitListener shopBatchSubmitListener=new ShopBatchSubmitListener(syncThirdDataService);
|
||||||
|
shopBatchSubmitListener.setStoreId(storeId);
|
||||||
|
shopBatchSubmitListener.setBrandMaps(brandMaps);
|
||||||
|
shopBatchSubmitListener.setIsNegativeAllowed(isNegativeAllowed);
|
||||||
|
EasyExcel.read(filePath,SxGoosModelExcel.class,shopBatchSubmitListener).sheet().doRead();
|
||||||
|
}
|
||||||
|
}
|
||||||
Loading…
Reference in New Issue
Block a user