商瑞9.7同步数据服务端开发
This commit is contained in:
parent
7da8978760
commit
46a5af7d47
@ -0,0 +1,88 @@
|
|||||||
|
package com.suisung.mall.common.enums;
|
||||||
|
|
||||||
|
public enum DicEnum {
|
||||||
|
|
||||||
|
ERR_1003("1003","缺少必要参数","errCode","错误码","缺少必要参数"),
|
||||||
|
ERR_1001("1001","签名有误","errCode","错误码","签名有误"),
|
||||||
|
ERR_1004("1004","缺少必要参数","errCode","错误码","缺少必要参数"),
|
||||||
|
|
||||||
|
DATA_SOURCE_1("1","自添加","dtaSource","数据来源","数据来源"),
|
||||||
|
DATA_SOURCE_2("2","缺少必要参数","dtaSource","数据来源","数据来源"),
|
||||||
|
|
||||||
|
PRODUCT("1", "商品","product","同步类型","同步类型"),
|
||||||
|
PRODUCT_CATEGORY("2", "商品分类","productCategory","同步类型","数据来源"),
|
||||||
|
BRAND("3", "品牌","brand","同步类型","同步类型"),
|
||||||
|
MEMBER("4", "会员","member","同步类型","同步类型"),
|
||||||
|
|
||||||
|
PENDING("0", "等待中","brand","同步类型","同步类型"),
|
||||||
|
PROCESSING("1", "进行中","brand","同步类型","同步类型"),
|
||||||
|
SUCCESS("2", "成功","brand","同步类型","同步类型"),
|
||||||
|
FAILED("3", "失败","brand","同步类型","同步类型"),
|
||||||
|
|
||||||
|
SOURCE_SYSTEM_TYPE_1005("1005", "思迅","sourceSystemType","数据来源","数据来源"),
|
||||||
|
SOURCE_SYSTEM_TYPE_SELF("self", "蓝驰","sourceSystemType","数据来源","数据来源"),
|
||||||
|
TIMED("1", "定时同步","syncMode","同步类型","同步类型"),
|
||||||
|
INTERVAL("2", "间隔同步","syncMode","同步类型","同步类型"),
|
||||||
|
|
||||||
|
YESORNO_0("0", "否","yesOrno","是否","是否"),
|
||||||
|
YESORNO_1("1", "是","yesOrno","是否","是否"),
|
||||||
|
;
|
||||||
|
;
|
||||||
|
private String code;
|
||||||
|
|
||||||
|
private String value;
|
||||||
|
|
||||||
|
private String dicType;
|
||||||
|
|
||||||
|
private String dicName;
|
||||||
|
|
||||||
|
private String desc;
|
||||||
|
|
||||||
|
DicEnum(String code, String value, String dicType, String dicName, String desc) {
|
||||||
|
this.code = code;
|
||||||
|
this.value = value;
|
||||||
|
this.dicType = dicType;
|
||||||
|
this.dicName = dicName;
|
||||||
|
this.desc = desc;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getCode() {
|
||||||
|
return code;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setCode(String code) {
|
||||||
|
this.code = code;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getValue() {
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setValue(String value) {
|
||||||
|
this.value = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getDicType() {
|
||||||
|
return dicType;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setDicType(String dicType) {
|
||||||
|
this.dicType = dicType;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getDicName() {
|
||||||
|
return dicName;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setDicName(String dicName) {
|
||||||
|
this.dicName = dicName;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getDesc() {
|
||||||
|
return desc;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setDesc(String desc) {
|
||||||
|
this.desc = desc;
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -91,7 +91,7 @@ public class SxSyncGoods implements Serializable {
|
|||||||
private BigDecimal item_brand_name;
|
private BigDecimal item_brand_name;
|
||||||
|
|
||||||
@ApiModelProperty(value = "商品助记号")
|
@ApiModelProperty(value = "商品助记号")
|
||||||
private Integer item_rem;
|
private String item_rem;
|
||||||
|
|
||||||
@ApiModelProperty(value = "生产日期")
|
@ApiModelProperty(value = "生产日期")
|
||||||
private String build_date;
|
private String build_date;
|
||||||
@ -113,5 +113,6 @@ public class SxSyncGoods implements Serializable {
|
|||||||
|
|
||||||
@ApiModelProperty(value = "更新时间")
|
@ApiModelProperty(value = "更新时间")
|
||||||
private Date updated_at;
|
private Date updated_at;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -0,0 +1,87 @@
|
|||||||
|
package com.suisung.mall.common.modules.sync;
|
||||||
|
|
||||||
|
import com.baomidou.mybatisplus.annotation.IdType;
|
||||||
|
import com.baomidou.mybatisplus.annotation.TableField;
|
||||||
|
import com.baomidou.mybatisplus.annotation.TableId;
|
||||||
|
import com.baomidou.mybatisplus.annotation.TableName;
|
||||||
|
import com.fasterxml.jackson.annotation.JsonFormat;
|
||||||
|
import io.swagger.annotations.ApiModel;
|
||||||
|
import io.swagger.annotations.ApiModelProperty;
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
import java.io.Serializable;
|
||||||
|
import java.util.Date;
|
||||||
|
|
||||||
|
@Data
|
||||||
|
@TableName("store_db_config")
|
||||||
|
@ApiModel(value = "StoreDbConfig对象", description = "店铺数据库连接配置表")
|
||||||
|
public class StoreDbConfig implements Serializable {
|
||||||
|
|
||||||
|
private static final long serialVersionUID = 1L;
|
||||||
|
|
||||||
|
@TableId(value = "id", type = IdType.AUTO)
|
||||||
|
@ApiModelProperty(value = "主键ID")
|
||||||
|
private Long id;
|
||||||
|
|
||||||
|
@TableField("store_id")
|
||||||
|
@ApiModelProperty(value = "店铺ID")
|
||||||
|
private String storeId;
|
||||||
|
|
||||||
|
@TableField("db_type")
|
||||||
|
@ApiModelProperty(value = "数据库类型(mysql/oracle/sqlserver等)")
|
||||||
|
private String dbType = "sqlserver";
|
||||||
|
|
||||||
|
@TableField("db_name")
|
||||||
|
@ApiModelProperty(value = "数据库名称")
|
||||||
|
private String dbName;
|
||||||
|
|
||||||
|
@TableField("db_ip")
|
||||||
|
@ApiModelProperty(value = "数据库IP地址")
|
||||||
|
private String dbIp;
|
||||||
|
|
||||||
|
@TableField("db_port")
|
||||||
|
@ApiModelProperty(value = "数据库端口")
|
||||||
|
private Integer dbPort = 3306;
|
||||||
|
|
||||||
|
@TableField("db_username")
|
||||||
|
@ApiModelProperty(value = "数据库用户名")
|
||||||
|
private String dbUsername;
|
||||||
|
|
||||||
|
@TableField("db_password")
|
||||||
|
@ApiModelProperty(value = "数据库密码(建议加密存储)")
|
||||||
|
private String dbPassword;
|
||||||
|
|
||||||
|
@TableField("has_internet")
|
||||||
|
@ApiModelProperty(value = "是否有外网访问(0:无,1:有)")
|
||||||
|
private String hasInternet;
|
||||||
|
|
||||||
|
@TableField("sync_mode")
|
||||||
|
@ApiModelProperty(value = "同步模式(1:定时同步,2:间隔同步)")
|
||||||
|
private String syncMode;
|
||||||
|
|
||||||
|
@TableField("has_start")
|
||||||
|
@ApiModelProperty(value = "是否启用(0:否,1:是)")
|
||||||
|
private String hasStart;
|
||||||
|
|
||||||
|
@TableField("cron_expression")
|
||||||
|
@ApiModelProperty(value = "定时同步的cron表达式")
|
||||||
|
private String cronExpression;
|
||||||
|
|
||||||
|
@TableField("category_name")
|
||||||
|
@ApiModelProperty(value = "商品分类")
|
||||||
|
private String categoryName;
|
||||||
|
|
||||||
|
@TableField("create_time")
|
||||||
|
@ApiModelProperty(value = "创建时间")
|
||||||
|
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
|
||||||
|
private Date createTime;
|
||||||
|
|
||||||
|
@TableField("update_time")
|
||||||
|
@ApiModelProperty(value = "更新时间")
|
||||||
|
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
|
||||||
|
private Date updateTime;
|
||||||
|
|
||||||
|
@TableField("remark")
|
||||||
|
@ApiModelProperty(value = "备注信息")
|
||||||
|
private String remark;
|
||||||
|
}
|
||||||
@ -0,0 +1,103 @@
|
|||||||
|
package com.suisung.mall.common.modules.sync;
|
||||||
|
|
||||||
|
import com.baomidou.mybatisplus.annotation.*;
|
||||||
|
import com.fasterxml.jackson.annotation.JsonFormat;
|
||||||
|
import io.swagger.annotations.ApiModel;
|
||||||
|
import io.swagger.annotations.ApiModelProperty;
|
||||||
|
import lombok.*;
|
||||||
|
|
||||||
|
import javax.validation.constraints.NotEmpty;
|
||||||
|
import java.util.Date;
|
||||||
|
import java.util.Map;
|
||||||
|
@NoArgsConstructor
|
||||||
|
@AllArgsConstructor
|
||||||
|
@EqualsAndHashCode
|
||||||
|
@ApiModel(value = "文件同步日志表实体类", description = "文件同步日志表实体类")
|
||||||
|
@TableName("sync_file_log")
|
||||||
|
@Data
|
||||||
|
public class SyncFileLog {
|
||||||
|
private static final long serialVersionUID = 1L;
|
||||||
|
|
||||||
|
@TableId(value = "id", type = IdType.AUTO)
|
||||||
|
@ApiModelProperty(value = "自增ID")
|
||||||
|
private Long id;
|
||||||
|
|
||||||
|
@TableField(value = "sync_task_id")
|
||||||
|
@ApiModelProperty(value = "同步任务ID")
|
||||||
|
private String syncTaskId;
|
||||||
|
|
||||||
|
@TableField(value = "sync_store_id")
|
||||||
|
@ApiModelProperty(value = "店铺id")
|
||||||
|
private String syncStoreId;
|
||||||
|
|
||||||
|
@TableField(value = "file_path")
|
||||||
|
@ApiModelProperty(value = "文件路径")
|
||||||
|
private String filePath;
|
||||||
|
|
||||||
|
@TableField(value = "file_name")
|
||||||
|
@ApiModelProperty(value = "文件名")
|
||||||
|
private String fileName;
|
||||||
|
|
||||||
|
@TableField(value = "file_size")
|
||||||
|
@ApiModelProperty(value = "文件大小(字节)")
|
||||||
|
private Long fileSize;
|
||||||
|
|
||||||
|
@TableField(value = "file_md5")
|
||||||
|
@ApiModelProperty(value = "文件MD5值")
|
||||||
|
private String fileMd5;
|
||||||
|
|
||||||
|
@TableField(value = "source_system")
|
||||||
|
@ApiModelProperty(value = "源系统标识")
|
||||||
|
@NotEmpty
|
||||||
|
private String sourceSystem;
|
||||||
|
|
||||||
|
@TableField(value = "target_system")
|
||||||
|
@ApiModelProperty(value = "目标系统标识")
|
||||||
|
@NotEmpty
|
||||||
|
private String targetSystem;
|
||||||
|
|
||||||
|
@TableField(value = "sync_type")
|
||||||
|
@ApiModelProperty(value = "同步类型(1:商品,2:商品分类,3:会员,4:品牌)")
|
||||||
|
private String syncType;
|
||||||
|
|
||||||
|
@TableField(value = "sync_status")
|
||||||
|
@ApiModelProperty(value = "同步状态(0:等待中,1:进行中,2:成功,3:失败)")
|
||||||
|
private String syncStatus;
|
||||||
|
|
||||||
|
@TableField(value = "retry_count")
|
||||||
|
@ApiModelProperty(value = "重试次数")
|
||||||
|
private Integer retryCount;
|
||||||
|
|
||||||
|
@TableField(value = "error_message")
|
||||||
|
@ApiModelProperty(value = "错误信息")
|
||||||
|
private String errorMessage;
|
||||||
|
|
||||||
|
@TableField(value = "start_time")
|
||||||
|
@ApiModelProperty(value = "开始时间")
|
||||||
|
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
|
||||||
|
private Date startTime;
|
||||||
|
|
||||||
|
@TableField(value = "end_time")
|
||||||
|
@ApiModelProperty(value = "结束时间")
|
||||||
|
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
|
||||||
|
private Date endTime;
|
||||||
|
|
||||||
|
@TableField(value = "duration")
|
||||||
|
@ApiModelProperty(value = "耗时(毫秒)")
|
||||||
|
private Integer duration;
|
||||||
|
|
||||||
|
@TableField(value = "create_time", fill = FieldFill.DEFAULT)
|
||||||
|
@ApiModelProperty(value = "创建时间")
|
||||||
|
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
|
||||||
|
private Date createTime;
|
||||||
|
|
||||||
|
@TableField(value = "update_time", fill = FieldFill.DEFAULT)
|
||||||
|
@ApiModelProperty(value = "更新时间")
|
||||||
|
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
|
||||||
|
private Date updateTime;
|
||||||
|
|
||||||
|
@TableField(value = "extra_info", typeHandler = com.baomidou.mybatisplus.extension.handlers.JacksonTypeHandler.class)
|
||||||
|
@ApiModelProperty(value = "额外信息(JSON格式)")
|
||||||
|
private Map<String, Object> extraInfo;
|
||||||
|
|
||||||
|
}
|
||||||
@ -8,6 +8,7 @@ import org.springframework.beans.factory.annotation.Autowired;
|
|||||||
import org.springframework.stereotype.Component;
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
import javax.annotation.PostConstruct;
|
import javax.annotation.PostConstruct;
|
||||||
|
import java.util.Objects;
|
||||||
|
|
||||||
@Component
|
@Component
|
||||||
@Slf4j
|
@Slf4j
|
||||||
@ -40,7 +41,11 @@ public class ContextUtil {
|
|||||||
try {
|
try {
|
||||||
UserDto loginUser = staticUserInfoService.getUser();
|
UserDto loginUser = staticUserInfoService.getUser();
|
||||||
log.info("##### 当前登录用户:{}###", JsonUtil.object2json(loginUser));
|
log.info("##### 当前登录用户:{}###", JsonUtil.object2json(loginUser));
|
||||||
return loginUser;
|
return loginUser;//todo 测试去除
|
||||||
|
// UserDto user= new UserDto();
|
||||||
|
// user.setStore_id("1");
|
||||||
|
// user.setRole_id(9);
|
||||||
|
// return user;
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
System.out.println(e.getMessage());
|
System.out.println(e.getMessage());
|
||||||
}
|
}
|
||||||
@ -73,6 +78,21 @@ public class ContextUtil {
|
|||||||
return loginUser.getId();
|
return loginUser.getId();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 传入的
|
||||||
|
* @param storeId
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public static String getStoreId(String storeId){
|
||||||
|
if(getCurrentUser()==null){
|
||||||
|
throw new RuntimeException("未登录");
|
||||||
|
}
|
||||||
|
if(Objects.requireNonNull(getCurrentUser()).getRole_id()==9){//平台
|
||||||
|
return storeId;
|
||||||
|
}
|
||||||
|
return Objects.requireNonNull(getCurrentUser()).getStore_id();
|
||||||
|
}
|
||||||
|
|
||||||
@PostConstruct
|
@PostConstruct
|
||||||
public void init() {
|
public void init() {
|
||||||
ContextUtil.staticUserInfoService = userInfoService;
|
ContextUtil.staticUserInfoService = userInfoService;
|
||||||
|
|||||||
@ -278,6 +278,12 @@
|
|||||||
<version>9.4.1.jre8</version> <!-- 或者使用合适的版本 -->
|
<version>9.4.1.jre8</version> <!-- 或者使用合适的版本 -->
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.microsoft.sqlserver</groupId>
|
||||||
|
<artifactId>mssql-jdbc</artifactId>
|
||||||
|
<version>9.2.1.jre8</version>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
</dependencies>
|
</dependencies>
|
||||||
|
|
||||||
<profiles>
|
<profiles>
|
||||||
|
|||||||
@ -143,4 +143,10 @@ public interface ShopBaseProductCategoryService extends IBaseService<ShopBasePro
|
|||||||
Boolean syncSxCategoryToShopBaseProductCategory(String storeId, Integer pageNum, Integer pageSize);
|
Boolean syncSxCategoryToShopBaseProductCategory(String storeId, Integer pageNum, Integer pageSize);
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 查询并缓存到热点数据中,提高查询效率
|
||||||
|
* @param storeId
|
||||||
|
*/
|
||||||
|
Map getCategoryListByStoreId(String storeId);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -326,6 +326,7 @@ public class AccountBaseConfigServiceImpl extends BaseServiceImpl<AccountBaseCon
|
|||||||
configList = Convert.toList(AccountBaseConfig.class, listByIds(configKeys));
|
configList = Convert.toList(AccountBaseConfig.class, listByIds(configKeys));
|
||||||
Map<String, AccountBaseConfig> configMap = configList.stream()
|
Map<String, AccountBaseConfig> configMap = configList.stream()
|
||||||
.collect(Collectors.toMap(AccountBaseConfig::getConfig_key, config -> config));
|
.collect(Collectors.toMap(AccountBaseConfig::getConfig_key, config -> config));
|
||||||
|
|
||||||
redisService.hSetAll(RedisConstant.Config_Cache_Key, configMap);
|
redisService.hSetAll(RedisConstant.Config_Cache_Key, configMap);
|
||||||
redisService.incr(RedisConstant.Config_Cache_Version, 1);
|
redisService.incr(RedisConstant.Config_Cache_Version, 1);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -26,6 +26,7 @@ import com.suisung.mall.common.modules.product.ShopProductIndex;
|
|||||||
import com.suisung.mall.common.modules.product.ShopProductItem;
|
import com.suisung.mall.common.modules.product.ShopProductItem;
|
||||||
import com.suisung.mall.common.modules.sixun.SxSyncCategory;
|
import com.suisung.mall.common.modules.sixun.SxSyncCategory;
|
||||||
import com.suisung.mall.common.modules.store.ShopStoreActivityItem;
|
import com.suisung.mall.common.modules.store.ShopStoreActivityItem;
|
||||||
|
import com.suisung.mall.common.modules.store.ShopStoreProductCategory;
|
||||||
import com.suisung.mall.common.modules.user.ShopUserCart;
|
import com.suisung.mall.common.modules.user.ShopUserCart;
|
||||||
import com.suisung.mall.common.pojo.dto.ProductSearchDTO;
|
import com.suisung.mall.common.pojo.dto.ProductSearchDTO;
|
||||||
import com.suisung.mall.common.utils.CheckUtil;
|
import com.suisung.mall.common.utils.CheckUtil;
|
||||||
@ -1235,4 +1236,26 @@ public class ShopBaseProductCategoryServiceImpl extends BaseServiceImpl<ShopBase
|
|||||||
public boolean saveOrUpdate(ShopBaseProductCategory a) {
|
public boolean saveOrUpdate(ShopBaseProductCategory a) {
|
||||||
return super.saveOrUpdate(a);
|
return super.saveOrUpdate(a);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Map getCategoryListByStoreId(String storeId) {
|
||||||
|
String cache_key = String.format("storeCategory:%s", storeId);
|
||||||
|
// 设置cache
|
||||||
|
Map map = (Map) redisService.get(cache_key);
|
||||||
|
if (CollUtil.isEmpty(map)) {
|
||||||
|
QueryWrapper<ShopBaseProductCategory> queryWrapper = new QueryWrapper<>();
|
||||||
|
queryWrapper.eq("store_id", storeId);
|
||||||
|
List<ShopBaseProductCategory> categoryList = find(queryWrapper);
|
||||||
|
// 类似数据可以放到前端整理
|
||||||
|
List<Map> category_tmp_rows = Convert.toList(Map.class, categoryList);
|
||||||
|
map=new HashMap();
|
||||||
|
for (Map category_row : category_tmp_rows) {
|
||||||
|
map.put(category_row.get("category_name"),category_row.get("category_id"));
|
||||||
|
}
|
||||||
|
if (CollUtil.isNotEmpty(map)) redisService.set(cache_key, map, 60 * 60);
|
||||||
|
|
||||||
|
}
|
||||||
|
return map;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -85,7 +85,8 @@ public class ShopBaseProductTypeServiceImpl extends BaseServiceImpl<ShopBaseProd
|
|||||||
data.put("assists", assistService.getAssistsByIds(shopBaseProductType.getType_assist_ids()));
|
data.put("assists", assistService.getAssistsByIds(shopBaseProductType.getType_assist_ids()));
|
||||||
data.put("brands", brandService.getBrandsByIds(shopBaseProductType.getType_brand_ids()));
|
data.put("brands", brandService.getBrandsByIds(shopBaseProductType.getType_brand_ids()));
|
||||||
|
|
||||||
Integer store_id = Convert.toInt(userInfoService.getUser().getStore_id());
|
//Integer store_id = Convert.toInt(userInfoService.getUser().getStore_id());
|
||||||
|
Integer store_id =1;
|
||||||
data.put("specs", specService.getSpecsByIds(shopBaseProductType.getType_spec_ids(), store_id));
|
data.put("specs", specService.getSpecsByIds(shopBaseProductType.getType_spec_ids(), store_id));
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@ -43,7 +43,6 @@ public class ShopChainUserRightsBaseServiceImpl extends BaseServiceImpl<ShopChai
|
|||||||
tree.add(chainUserRightBase);
|
tree.add(chainUserRightBase);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return tree;
|
return tree;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -0,0 +1,30 @@
|
|||||||
|
package com.suisung.mall.shop.config;
|
||||||
|
|
||||||
|
import org.springframework.context.annotation.Bean;
|
||||||
|
import org.springframework.context.annotation.Configuration;
|
||||||
|
import org.springframework.web.cors.CorsConfiguration;
|
||||||
|
import org.springframework.web.cors.reactive.CorsWebFilter;
|
||||||
|
import org.springframework.web.cors.reactive.UrlBasedCorsConfigurationSource;
|
||||||
|
import org.springframework.web.util.pattern.PathPatternParser;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 全局跨域配置
|
||||||
|
* 注意:前端从网关进行调用时需要配置 //本地测试
|
||||||
|
*/
|
||||||
|
@Configuration
|
||||||
|
public class GlobalCorsConfig {
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
public CorsWebFilter corsFilter() {
|
||||||
|
CorsConfiguration config = new CorsConfiguration();
|
||||||
|
config.addAllowedMethod("*");
|
||||||
|
config.addAllowedOrigin("*");
|
||||||
|
config.addAllowedHeader("*");
|
||||||
|
config.setAllowCredentials(true);
|
||||||
|
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource(new PathPatternParser());
|
||||||
|
source.registerCorsConfiguration("/**", config);
|
||||||
|
|
||||||
|
return new CorsWebFilter(source);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@ -1,6 +1,7 @@
|
|||||||
package com.suisung.mall.shop.config;
|
package com.suisung.mall.shop.config;
|
||||||
|
|
||||||
import org.springframework.context.annotation.Configuration;
|
import org.springframework.context.annotation.Configuration;
|
||||||
|
import org.springframework.web.servlet.config.annotation.CorsRegistry;
|
||||||
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
|
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
|
||||||
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
|
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
|
||||||
|
|
||||||
@ -15,4 +16,15 @@ public class WebConfig implements WebMvcConfigurer {
|
|||||||
public void addResourceHandlers(ResourceHandlerRegistry registry) {
|
public void addResourceHandlers(ResourceHandlerRegistry registry) {
|
||||||
registry.addResourceHandler("/static/**").addResourceLocations("classpath:/static/");
|
registry.addResourceHandler("/static/**").addResourceLocations("classpath:/static/");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void addCorsMappings(CorsRegistry registry) {
|
||||||
|
registry.addMapping("/**") // 对所有路径应用CORS配置
|
||||||
|
.allowedOrigins("*") // 允许的源
|
||||||
|
.allowedMethods("GET", "POST", "PUT", "DELETE") // 允许的方法
|
||||||
|
.allowedHeaders("*") // 允许的头部
|
||||||
|
.allowCredentials(true) // 是否发送cookies等信息
|
||||||
|
.maxAge(3600); // 预检请求的有效期(秒)
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -4,6 +4,8 @@ import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
|||||||
import com.suisung.mall.common.modules.number.ShopNumberSeq;
|
import com.suisung.mall.common.modules.number.ShopNumberSeq;
|
||||||
import org.springframework.stereotype.Repository;
|
import org.springframework.stereotype.Repository;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* <p>
|
* <p>
|
||||||
* Id管理表 Mapper 接口
|
* Id管理表 Mapper 接口
|
||||||
@ -16,4 +18,7 @@ import org.springframework.stereotype.Repository;
|
|||||||
@Repository
|
@Repository
|
||||||
public interface ShopNumberSeqMapper extends BaseMapper<ShopNumberSeq> {
|
public interface ShopNumberSeqMapper extends BaseMapper<ShopNumberSeq> {
|
||||||
|
|
||||||
|
List<ShopNumberSeq> findNumberFromShopBaseAndItem(ShopNumberSeq shopNumberSeq);
|
||||||
|
List<ShopNumberSeq> findProductAndImtemId(ShopNumberSeq shopNumberSeq);
|
||||||
|
void myUpdateSeq(ShopNumberSeq shopNumberSeq);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -3,6 +3,8 @@ package com.suisung.mall.shop.number.service;
|
|||||||
import com.suisung.mall.common.modules.number.ShopNumberSeq;
|
import com.suisung.mall.common.modules.number.ShopNumberSeq;
|
||||||
import com.suisung.mall.core.web.service.IBaseService;
|
import com.suisung.mall.core.web.service.IBaseService;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* <p>
|
* <p>
|
||||||
* Id管理表 服务类
|
* Id管理表 服务类
|
||||||
@ -17,4 +19,9 @@ public interface ShopNumberSeqService extends IBaseService<ShopNumberSeq> {
|
|||||||
|
|
||||||
Long createNextNo(String prefix);
|
Long createNextNo(String prefix);
|
||||||
|
|
||||||
|
List<Long> batchCreateNextNo(String seqName, int batchSize);
|
||||||
|
|
||||||
|
void clearRelateGoodsId();
|
||||||
|
void clearKey();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,15 +1,25 @@
|
|||||||
package com.suisung.mall.shop.number.service.impl;
|
package com.suisung.mall.shop.number.service.impl;
|
||||||
|
|
||||||
import cn.hutool.core.date.DateUtil;
|
import cn.hutool.core.date.DateUtil;
|
||||||
|
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
|
||||||
import com.suisung.mall.common.modules.number.ShopNumberSeq;
|
import com.suisung.mall.common.modules.number.ShopNumberSeq;
|
||||||
|
import com.suisung.mall.core.web.service.RedisService;
|
||||||
import com.suisung.mall.core.web.service.impl.BaseServiceImpl;
|
import com.suisung.mall.core.web.service.impl.BaseServiceImpl;
|
||||||
import com.suisung.mall.shop.number.mapper.ShopNumberSeqMapper;
|
import com.suisung.mall.shop.number.mapper.ShopNumberSeqMapper;
|
||||||
import com.suisung.mall.shop.number.service.ShopNumberSeqService;
|
import com.suisung.mall.shop.number.service.ShopNumberSeqService;
|
||||||
|
import org.apache.ibatis.session.ExecutorType;
|
||||||
|
import org.apache.ibatis.session.SqlSession;
|
||||||
|
import org.apache.ibatis.session.SqlSessionFactory;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
import org.springframework.transaction.annotation.Propagation;
|
import org.springframework.transaction.annotation.Propagation;
|
||||||
import org.springframework.transaction.annotation.Transactional;
|
import org.springframework.transaction.annotation.Transactional;
|
||||||
|
|
||||||
|
import java.util.Collections;
|
||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
import java.util.stream.LongStream;
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -21,8 +31,15 @@ import java.util.Date;
|
|||||||
* @since 2021-09-18
|
* @since 2021-09-18
|
||||||
*/
|
*/
|
||||||
@Service
|
@Service
|
||||||
|
@lombok.extern.slf4j.Slf4j
|
||||||
public class ShopNumberSeqServiceImpl extends BaseServiceImpl<ShopNumberSeqMapper, ShopNumberSeq> implements ShopNumberSeqService {
|
public class ShopNumberSeqServiceImpl extends BaseServiceImpl<ShopNumberSeqMapper, ShopNumberSeq> implements ShopNumberSeqService {
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private ShopNumberSeqMapper shopNumberSeqMapper;
|
||||||
|
@Autowired
|
||||||
|
private RedisService redisService;
|
||||||
|
private String CACHE_PREFIX = "shop_number_seq:%S";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 得到下一个Id
|
* 得到下一个Id
|
||||||
* 方法走到这里会产生串行化,集群部署这里不能使用单机锁
|
* 方法走到这里会产生串行化,集群部署这里不能使用单机锁
|
||||||
@ -65,6 +82,10 @@ public class ShopNumberSeqServiceImpl extends BaseServiceImpl<ShopNumberSeqMappe
|
|||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public Long createNextNo(String prefix) {
|
public Long createNextNo(String prefix) {
|
||||||
|
//相当于加锁,等待同步数据执行完成
|
||||||
|
// if(prefix.equals("product_id")||prefix.equals("item_id")){
|
||||||
|
// checkPrimaryKey();
|
||||||
|
// }
|
||||||
String id = prefix;
|
String id = prefix;
|
||||||
ShopNumberSeq shopNumberSeq = getById(id);
|
ShopNumberSeq shopNumberSeq = getById(id);
|
||||||
if (shopNumberSeq == null) {
|
if (shopNumberSeq == null) {
|
||||||
@ -79,6 +100,7 @@ public class ShopNumberSeqServiceImpl extends BaseServiceImpl<ShopNumberSeqMappe
|
|||||||
}
|
}
|
||||||
|
|
||||||
Long number = shopNumberSeq.getNumber();
|
Long number = shopNumberSeq.getNumber();
|
||||||
|
|
||||||
shopNumberSeq.setPrefix(id);
|
shopNumberSeq.setPrefix(id);
|
||||||
|
|
||||||
//不走缓存
|
//不走缓存
|
||||||
@ -90,4 +112,112 @@ public class ShopNumberSeqServiceImpl extends BaseServiceImpl<ShopNumberSeqMappe
|
|||||||
|
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 校验同步数据是否同步完成,就是两个库的主键是否一致
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
private void checkPrimaryKey(){
|
||||||
|
boolean flag = shopNumberSeqMapper.findNumberFromShopBaseAndItem(new ShopNumberSeq()).size()>1;
|
||||||
|
while (!flag){
|
||||||
|
try {
|
||||||
|
Thread.sleep(3600);
|
||||||
|
} catch (InterruptedException e) {
|
||||||
|
log.error("checkPrimaryKey枷锁失败--"+e.getMessage());
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
flag=shopNumberSeqMapper.findNumberFromShopBaseAndItem(new ShopNumberSeq()).size()>1;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 批量获取id
|
||||||
|
* @param seqName
|
||||||
|
* @param batchSize
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
@Transactional(propagation = Propagation.NOT_SUPPORTED)
|
||||||
|
public synchronized List<Long> batchCreateNextNo(String seqName, int batchSize) {
|
||||||
|
if (batchSize <= 0) {
|
||||||
|
return Collections.emptyList();
|
||||||
|
}
|
||||||
|
long number= 0;
|
||||||
|
if (null==redisService.get(String.format(CACHE_PREFIX, seqName))) {
|
||||||
|
// 1. 获取当前序列值
|
||||||
|
QueryWrapper<ShopNumberSeq> wrapper = new QueryWrapper<>();
|
||||||
|
wrapper.eq("prefix", seqName);
|
||||||
|
ShopNumberSeq seq = getById(seqName);
|
||||||
|
|
||||||
|
if (seq == null) {
|
||||||
|
seq = new ShopNumberSeq();
|
||||||
|
seq.setPrefix(seqName);
|
||||||
|
seq.setNumber((long) batchSize);
|
||||||
|
save(seq);
|
||||||
|
return LongStream.range(1, batchSize + 1).boxed().collect(Collectors.toList());
|
||||||
|
}
|
||||||
|
number = seq.getNumber();
|
||||||
|
}else {
|
||||||
|
int numberCache=(Integer) redisService.get(String.format(CACHE_PREFIX, seqName))+1;
|
||||||
|
number= numberCache;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// 2. 计算新值范围
|
||||||
|
long start = number;
|
||||||
|
long end = start + batchSize - 1;
|
||||||
|
|
||||||
|
// 3. 更新序列值到缓存,在并发时使用
|
||||||
|
redisService.set(String.format(CACHE_PREFIX, seqName), end);
|
||||||
|
// 4. 返回生成的ID范围
|
||||||
|
return LongStream.rangeClosed(start, end).boxed().collect(Collectors.toList());
|
||||||
|
}
|
||||||
|
|
||||||
|
public void batchUpdateSeq(List<ShopNumberSeq> shopNumberSeqList){
|
||||||
|
int count=0;
|
||||||
|
for (int i = 0; i < shopNumberSeqList.size(); i++) {
|
||||||
|
shopNumberSeqMapper.myUpdateSeq(shopNumberSeqList.get(i));
|
||||||
|
count++;
|
||||||
|
}
|
||||||
|
log.info("更新成功{}条数据",count);
|
||||||
|
}
|
||||||
|
public void clearKey(){
|
||||||
|
redisService.del(String.format(CACHE_PREFIX,"item_id"));
|
||||||
|
redisService.del(String.format(CACHE_PREFIX,"product_id"));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 清除缓存,专门给并发使用,防止redis的缓存没有加载
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public void clearRelateGoodsId(){
|
||||||
|
boolean flag = shopNumberSeqMapper.findNumberFromShopBaseAndItem(new ShopNumberSeq()).size()>1;
|
||||||
|
if(flag){
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
List<ShopNumberSeq> shopNumberSeqList=shopNumberSeqMapper.findProductAndImtemId(new ShopNumberSeq());
|
||||||
|
for (ShopNumberSeq shopNumberSeq:shopNumberSeqList) {
|
||||||
|
if(shopNumberSeq.getPrefix().equals("product_id")){
|
||||||
|
clearCache("product_id",shopNumberSeq.getNumber());
|
||||||
|
}
|
||||||
|
if(shopNumberSeq.getPrefix().equals("item_id")){
|
||||||
|
clearCache("item_id",shopNumberSeq.getNumber());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* 刷新缓存
|
||||||
|
*/
|
||||||
|
private void clearCache(String seqName,long number){
|
||||||
|
QueryWrapper<ShopNumberSeq> wrapper = new QueryWrapper<>();
|
||||||
|
wrapper.eq("prefix", seqName);
|
||||||
|
ShopNumberSeq seq = getById(seqName);
|
||||||
|
if (seq != null) {
|
||||||
|
seq = new ShopNumberSeq();
|
||||||
|
seq.setNumber(number-1);
|
||||||
|
seq.setPrefix(seqName);
|
||||||
|
}
|
||||||
|
edit(seq);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,12 +1,14 @@
|
|||||||
package com.suisung.mall.shop.page.service;
|
package com.suisung.mall.shop.page.service;
|
||||||
|
|
||||||
|
|
||||||
|
import com.qcloud.cos.model.COSObjectSummary;
|
||||||
import com.suisung.mall.common.pojo.dto.OssCallbackResultDTO;
|
import com.suisung.mall.common.pojo.dto.OssCallbackResultDTO;
|
||||||
import com.suisung.mall.common.pojo.dto.OssPolicyResultDTO;
|
import com.suisung.mall.common.pojo.dto.OssPolicyResultDTO;
|
||||||
|
|
||||||
import javax.servlet.http.HttpServletRequest;
|
import javax.servlet.http.HttpServletRequest;
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* oss上传管理Service
|
* oss上传管理Service
|
||||||
@ -42,4 +44,26 @@ public interface OssService {
|
|||||||
*/
|
*/
|
||||||
String uploadObject4OSS(String fileUrl, String concat);
|
String uploadObject4OSS(String fileUrl, String concat);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 根据目录查询目录下的目录列表
|
||||||
|
* @param folder
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
List<String> listFolders(String folder);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 根据目录查询目录下的文件
|
||||||
|
* @param folder
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
List<COSObjectSummary> listDocuments(String folder);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 下载文件返回路径
|
||||||
|
* @param ossFolder
|
||||||
|
* @param localFolder
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
String download(String ossFolder, String localFolder);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -14,9 +14,7 @@ import com.qcloud.cos.COSClient;
|
|||||||
import com.qcloud.cos.ClientConfig;
|
import com.qcloud.cos.ClientConfig;
|
||||||
import com.qcloud.cos.auth.BasicCOSCredentials;
|
import com.qcloud.cos.auth.BasicCOSCredentials;
|
||||||
import com.qcloud.cos.auth.COSCredentials;
|
import com.qcloud.cos.auth.COSCredentials;
|
||||||
import com.qcloud.cos.model.CannedAccessControlList;
|
import com.qcloud.cos.model.*;
|
||||||
import com.qcloud.cos.model.PutObjectRequest;
|
|
||||||
import com.qcloud.cos.model.PutObjectResult;
|
|
||||||
import com.qcloud.cos.region.Region;
|
import com.qcloud.cos.region.Region;
|
||||||
import com.suisung.mall.common.api.CommonResult;
|
import com.suisung.mall.common.api.CommonResult;
|
||||||
import com.suisung.mall.common.constant.ConfigConstant;
|
import com.suisung.mall.common.constant.ConfigConstant;
|
||||||
@ -49,7 +47,9 @@ import java.nio.charset.StandardCharsets;
|
|||||||
import java.text.SimpleDateFormat;
|
import java.text.SimpleDateFormat;
|
||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* oss上传管理Service实现类
|
* oss上传管理Service实现类
|
||||||
@ -568,4 +568,49 @@ public class OssServiceImpl implements OssService {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<String> listFolders(String folder) {
|
||||||
|
COSClient ossCli = initCOSClient();
|
||||||
|
ListObjectsRequest listObjectsRequest = new ListObjectsRequest();
|
||||||
|
listObjectsRequest.setBucketName(TENGXUN_BUCKET_NAME);
|
||||||
|
listObjectsRequest.setPrefix(folder);
|
||||||
|
listObjectsRequest.setDelimiter("/");
|
||||||
|
ObjectListing objectListing = ossCli.listObjects(listObjectsRequest);
|
||||||
|
List<String> commonPrefixes = objectListing.getCommonPrefixes();
|
||||||
|
logger.info(JSONUtil.toJsonStr(commonPrefixes));
|
||||||
|
return commonPrefixes;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<COSObjectSummary> listDocuments(String folder) {
|
||||||
|
COSClient ossCli = initCOSClient();
|
||||||
|
ListObjectsRequest listObjectsRequest = new ListObjectsRequest();
|
||||||
|
listObjectsRequest.setBucketName(TENGXUN_BUCKET_NAME);
|
||||||
|
listObjectsRequest.setPrefix(folder);
|
||||||
|
listObjectsRequest.setDelimiter("");
|
||||||
|
ObjectListing objectListing = ossCli.listObjects(listObjectsRequest);
|
||||||
|
List<COSObjectSummary> files = objectListing.getObjectSummaries()
|
||||||
|
.stream()
|
||||||
|
// 过滤掉目录(目录通常以 '/' 结尾或大小为0)
|
||||||
|
.filter(obj -> !obj.getKey().endsWith("/") || obj.getSize() > 0)
|
||||||
|
.collect(Collectors.toList());
|
||||||
|
// 获取目录下的文件
|
||||||
|
return files;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @param ossFolder 如folder/example.txt
|
||||||
|
* @param localFolder 如/path/to/local/example.txt
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public String download(String ossFolder, String localFolder) {
|
||||||
|
COSClient ossCli = initCOSClient();
|
||||||
|
ossCli.getObject(new GetObjectRequest(TENGXUN_BUCKET_NAME, ossFolder),
|
||||||
|
new File(localFolder));
|
||||||
|
return localFolder;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@ -3,6 +3,8 @@ package com.suisung.mall.shop.product.service;
|
|||||||
import com.suisung.mall.common.modules.product.ShopProductAssistIndex;
|
import com.suisung.mall.common.modules.product.ShopProductAssistIndex;
|
||||||
import com.suisung.mall.core.web.service.IBaseService;
|
import com.suisung.mall.core.web.service.IBaseService;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* <p>
|
* <p>
|
||||||
* 商品与属性对应表 服务类
|
* 商品与属性对应表 服务类
|
||||||
@ -12,5 +14,7 @@ import com.suisung.mall.core.web.service.IBaseService;
|
|||||||
* @since 2021-05-19
|
* @since 2021-05-19
|
||||||
*/
|
*/
|
||||||
public interface ShopProductAssistIndexService extends IBaseService<ShopProductAssistIndex> {
|
public interface ShopProductAssistIndexService extends IBaseService<ShopProductAssistIndex> {
|
||||||
|
List<ShopProductAssistIndex> getShopProductAssistIndexStoreId(Integer storeId);
|
||||||
|
|
||||||
|
void clearCacheShopProductAssistIndexByStoreId(Integer storeId);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -283,4 +283,10 @@ public interface ShopProductBaseService extends IBaseService<ShopProductBase> {
|
|||||||
|
|
||||||
Pair<Boolean, String> saveProduct(ShopProductBase shopProductBase, ShopProductIndex shopProductIndex, ShopProductData shopProductData, ShopProductDetail shopProductDetail, ShopProductInfo shopProductInfo, List<ShopProductItem> shopProductItemList, List<ShopProductImage> shopProductImageList, ShopProductValidPeriod shopProductValidPeriod, List<ShopProductAssistIndex> shopProductAssistIndexList);
|
Pair<Boolean, String> saveProduct(ShopProductBase shopProductBase, ShopProductIndex shopProductIndex, ShopProductData shopProductData, ShopProductDetail shopProductDetail, ShopProductInfo shopProductInfo, List<ShopProductItem> shopProductItemList, List<ShopProductImage> shopProductImageList, ShopProductValidPeriod shopProductValidPeriod, List<ShopProductAssistIndex> shopProductAssistIndexList);
|
||||||
|
|
||||||
|
Pair<Boolean, String> saveProductBatch(List<ShopProductBase> shopProductBaseList, List<ShopProductIndex> shopProductIndexList,
|
||||||
|
List<ShopProductData> shopProductDataList, List<ShopProductDetail> shopProductDetailList,
|
||||||
|
List<ShopProductInfo> shopProductInfoList, List<List<ShopProductItem>> shopProductItemList,
|
||||||
|
List<List<ShopProductImage>> shopProductImageList,
|
||||||
|
List<ShopProductValidPeriod> shopProductValidPeriodList,
|
||||||
|
List<ShopProductAssistIndex> shopProductAssistIndexList);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -3,6 +3,8 @@ package com.suisung.mall.shop.product.service;
|
|||||||
import com.suisung.mall.common.modules.product.ShopProductImage;
|
import com.suisung.mall.common.modules.product.ShopProductImage;
|
||||||
import com.suisung.mall.core.web.service.IBaseService;
|
import com.suisung.mall.core.web.service.IBaseService;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* <p>
|
* <p>
|
||||||
* 产品图片表,按照颜色规格 服务类
|
* 产品图片表,按照颜色规格 服务类
|
||||||
@ -13,4 +15,7 @@ import com.suisung.mall.core.web.service.IBaseService;
|
|||||||
*/
|
*/
|
||||||
public interface ShopProductImageService extends IBaseService<ShopProductImage> {
|
public interface ShopProductImageService extends IBaseService<ShopProductImage> {
|
||||||
|
|
||||||
|
List<ShopProductImage> getShopProductImageByStoreId(Integer storeId);
|
||||||
|
|
||||||
|
void clearCacheShopProductImageByStoreId(Integer storeId);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,11 +1,17 @@
|
|||||||
package com.suisung.mall.shop.product.service.impl;
|
package com.suisung.mall.shop.product.service.impl;
|
||||||
|
|
||||||
|
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
|
||||||
import com.suisung.mall.common.modules.product.ShopProductAssistIndex;
|
import com.suisung.mall.common.modules.product.ShopProductAssistIndex;
|
||||||
|
import com.suisung.mall.core.web.service.RedisService;
|
||||||
import com.suisung.mall.core.web.service.impl.BaseServiceImpl;
|
import com.suisung.mall.core.web.service.impl.BaseServiceImpl;
|
||||||
import com.suisung.mall.shop.product.mapper.ShopProductAssistIndexMapper;
|
import com.suisung.mall.shop.product.mapper.ShopProductAssistIndexMapper;
|
||||||
import com.suisung.mall.shop.product.service.ShopProductAssistIndexService;
|
import com.suisung.mall.shop.product.service.ShopProductAssistIndexService;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* <p>
|
* <p>
|
||||||
@ -17,4 +23,24 @@ import org.springframework.stereotype.Service;
|
|||||||
*/
|
*/
|
||||||
@Service
|
@Service
|
||||||
public class ShopProductAssistIndexServiceImpl extends BaseServiceImpl<ShopProductAssistIndexMapper, ShopProductAssistIndex> implements ShopProductAssistIndexService {
|
public class ShopProductAssistIndexServiceImpl extends BaseServiceImpl<ShopProductAssistIndexMapper, ShopProductAssistIndex> implements ShopProductAssistIndexService {
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private RedisService redisService;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<ShopProductAssistIndex> getShopProductAssistIndexStoreId(Integer storeId) {
|
||||||
|
List<ShopProductAssistIndex> shopProductAssistIndexList= (List<ShopProductAssistIndex>) redisService.get("ShopProductAssistIndexStoreId:"+storeId);
|
||||||
|
if(shopProductAssistIndexList==null){
|
||||||
|
QueryWrapper<ShopProductAssistIndex> queryWrapper= new QueryWrapper<ShopProductAssistIndex>();
|
||||||
|
queryWrapper.eq("store_id",storeId);
|
||||||
|
shopProductAssistIndexList=this.list(queryWrapper);
|
||||||
|
redisService.set("ShopProductAssistIndexStoreId:"+storeId,shopProductAssistIndexList);
|
||||||
|
}
|
||||||
|
return shopProductAssistIndexList;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void clearCacheShopProductAssistIndexByStoreId(Integer storeId) {
|
||||||
|
redisService.del("ShopProductAssistIndexStoreId:"+storeId);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -6,6 +6,7 @@ import cn.hutool.core.collection.CollectionUtil;
|
|||||||
import cn.hutool.core.convert.Convert;
|
import cn.hutool.core.convert.Convert;
|
||||||
import cn.hutool.core.date.DateTime;
|
import cn.hutool.core.date.DateTime;
|
||||||
import cn.hutool.core.date.DateUtil;
|
import cn.hutool.core.date.DateUtil;
|
||||||
|
import cn.hutool.core.date.StopWatch;
|
||||||
import cn.hutool.core.util.NumberUtil;
|
import cn.hutool.core.util.NumberUtil;
|
||||||
import cn.hutool.core.util.ObjectUtil;
|
import cn.hutool.core.util.ObjectUtil;
|
||||||
import cn.hutool.core.util.StrUtil;
|
import cn.hutool.core.util.StrUtil;
|
||||||
@ -15,6 +16,8 @@ import com.alibaba.fastjson.JSON;
|
|||||||
import com.alibaba.fastjson.JSONArray;
|
import com.alibaba.fastjson.JSONArray;
|
||||||
import com.alibaba.fastjson.JSONObject;
|
import com.alibaba.fastjson.JSONObject;
|
||||||
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
|
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
|
||||||
|
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||||
|
import com.baomidou.mybatisplus.core.mapper.Mapper;
|
||||||
import com.baomidou.mybatisplus.core.metadata.IPage;
|
import com.baomidou.mybatisplus.core.metadata.IPage;
|
||||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||||
import com.suisung.mall.common.api.CommonResult;
|
import com.suisung.mall.common.api.CommonResult;
|
||||||
@ -62,14 +65,22 @@ import com.suisung.mall.shop.product.pojo.vo.ProductVo;
|
|||||||
import com.suisung.mall.shop.product.service.*;
|
import com.suisung.mall.shop.product.service.*;
|
||||||
import com.suisung.mall.shop.sixun.service.SxSyncGoodsService;
|
import com.suisung.mall.shop.sixun.service.SxSyncGoodsService;
|
||||||
import com.suisung.mall.shop.store.service.*;
|
import com.suisung.mall.shop.store.service.*;
|
||||||
|
import com.suisung.mall.shop.sync.Utils.BatchInsertUtils;
|
||||||
import com.suisung.mall.shop.user.service.*;
|
import com.suisung.mall.shop.user.service.*;
|
||||||
import org.apache.commons.lang3.StringUtils;
|
import org.apache.commons.lang3.StringUtils;
|
||||||
|
import org.apache.ibatis.session.SqlSession;
|
||||||
|
import org.apache.ibatis.session.SqlSessionFactory;
|
||||||
|
import org.bouncycastle.jcajce.provider.symmetric.util.BaseMac;
|
||||||
|
import org.mybatis.spring.SqlSessionFactoryBean;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
import org.springframework.data.util.Pair;
|
import org.springframework.data.util.Pair;
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
|
import org.springframework.transaction.PlatformTransactionManager;
|
||||||
|
import org.springframework.transaction.TransactionDefinition;
|
||||||
import org.springframework.transaction.annotation.Transactional;
|
import org.springframework.transaction.annotation.Transactional;
|
||||||
|
import org.springframework.transaction.support.TransactionTemplate;
|
||||||
import org.springframework.web.context.request.RequestContextHolder;
|
import org.springframework.web.context.request.RequestContextHolder;
|
||||||
import org.springframework.web.context.request.ServletRequestAttributes;
|
import org.springframework.web.context.request.ServletRequestAttributes;
|
||||||
|
|
||||||
@ -81,7 +92,9 @@ import java.math.BigDecimal;
|
|||||||
import java.math.RoundingMode;
|
import java.math.RoundingMode;
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
import java.util.concurrent.CompletableFuture;
|
import java.util.concurrent.CompletableFuture;
|
||||||
|
import java.util.concurrent.CountDownLatch;
|
||||||
import java.util.concurrent.ThreadPoolExecutor;
|
import java.util.concurrent.ThreadPoolExecutor;
|
||||||
|
import java.util.function.Function;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
import static com.suisung.mall.common.utils.ContextUtil.getCurrentUser;
|
import static com.suisung.mall.common.utils.ContextUtil.getCurrentUser;
|
||||||
@ -195,6 +208,11 @@ public class ShopProductBaseServiceImpl extends BaseServiceImpl<ShopProductBaseM
|
|||||||
@Autowired
|
@Autowired
|
||||||
private SxSyncGoodsService sxSyncGoodsService;
|
private SxSyncGoodsService sxSyncGoodsService;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private PlatformTransactionManager transactionManager;
|
||||||
|
@Autowired
|
||||||
|
private SqlSessionFactory sqlSessionFactory;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean trySaveProduct(String productObj, String productItems) {
|
public boolean trySaveProduct(String productObj, String productItems) {
|
||||||
|
|
||||||
@ -681,7 +699,7 @@ public class ShopProductBaseServiceImpl extends BaseServiceImpl<ShopProductBaseM
|
|||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public Pair<Boolean, String> saveProduct(ShopProductBase shopProductBase, ShopProductIndex shopProductIndex, ShopProductData shopProductData, ShopProductDetail shopProductDetail, ShopProductInfo shopProductInfo, List<ShopProductItem> shopProductItemList, List<ShopProductImage> shopProductImageList, ShopProductValidPeriod shopProductValidPeriod, List<ShopProductAssistIndex> shopProductAssistIndexList) {
|
public synchronized Pair<Boolean, String> saveProduct(ShopProductBase shopProductBase, ShopProductIndex shopProductIndex, ShopProductData shopProductData, ShopProductDetail shopProductDetail, ShopProductInfo shopProductInfo, List<ShopProductItem> shopProductItemList, List<ShopProductImage> shopProductImageList, ShopProductValidPeriod shopProductValidPeriod, List<ShopProductAssistIndex> shopProductAssistIndexList) {
|
||||||
Integer store_id = shopProductBase.getStore_id();
|
Integer store_id = shopProductBase.getStore_id();
|
||||||
if (store_id == null) {
|
if (store_id == null) {
|
||||||
return Pair.of(false, I18nUtil._("缺少店铺ID!"));
|
return Pair.of(false, I18nUtil._("缺少店铺ID!"));
|
||||||
@ -718,7 +736,7 @@ public class ShopProductBaseServiceImpl extends BaseServiceImpl<ShopProductBaseM
|
|||||||
// 生成商品ID:product_id
|
// 生成商品ID:product_id
|
||||||
productId = shopNumberSeqService.createNextNo("product_id");
|
productId = shopNumberSeqService.createNextNo("product_id");
|
||||||
if (null == productId) {
|
if (null == productId) {
|
||||||
return Pair.of(false, I18nUtil._("生成商品编号异常!"));
|
return Pair.of(false, I18nUtil._("生成商品编号异常!"));
|
||||||
} else {
|
} else {
|
||||||
shopProductBase.setProduct_id(productId);
|
shopProductBase.setProduct_id(productId);
|
||||||
}
|
}
|
||||||
@ -2713,7 +2731,7 @@ public class ShopProductBaseServiceImpl extends BaseServiceImpl<ShopProductBaseM
|
|||||||
public Map getList(QueryWrapper<ShopProductBase> wrapper, Integer pageNum, Integer pageSize) {
|
public Map getList(QueryWrapper<ShopProductBase> wrapper, Integer pageNum, Integer pageSize) {
|
||||||
|
|
||||||
Map map = new HashMap();
|
Map map = new HashMap();
|
||||||
Integer store_id = Convert.toInt(getCurrentUser().getStore_id());
|
Integer store_id = Convert.toInt(getCurrentUser().getStore_id(),1);
|
||||||
Integer nodeid = Convert.toInt(getParameter("nodeid"), 0);
|
Integer nodeid = Convert.toInt(getParameter("nodeid"), 0);
|
||||||
|
|
||||||
if (CheckUtil.isNotEmpty(nodeid)) {
|
if (CheckUtil.isNotEmpty(nodeid)) {
|
||||||
@ -5243,4 +5261,835 @@ public class ShopProductBaseServiceImpl extends BaseServiceImpl<ShopProductBaseM
|
|||||||
|
|
||||||
return productNameIndex;
|
return productNameIndex;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Pair<Boolean, String> saveProductBatch(List<ShopProductBase> shopProductBaseList, List<ShopProductIndex> shopProductIndexList,
|
||||||
|
List<ShopProductData> shopProductDataList, List<ShopProductDetail> shopProductDetailList,
|
||||||
|
List<ShopProductInfo> shopProductInfoList, List<List<ShopProductItem>> shopProductItemList,
|
||||||
|
List<List<ShopProductImage>> shopProductImageList, List<ShopProductValidPeriod> shopProductValidPeriodList,
|
||||||
|
List<ShopProductAssistIndex> shopProductAssistIndexList) {
|
||||||
|
|
||||||
|
// 1. 参数校验
|
||||||
|
if (shopProductBaseList == null || shopProductBaseList.isEmpty()) {
|
||||||
|
return Pair.of(false, "商品列表不能为空");
|
||||||
|
}
|
||||||
|
|
||||||
|
// 2. 检查并设置已存在商品的ID
|
||||||
|
Map<String, Long> existingProducts = checkExistingProducts(shopProductBaseList);
|
||||||
|
|
||||||
|
// 3. 分离新增和更新的商品
|
||||||
|
List<ShopProductBase> newProducts = new ArrayList<>();
|
||||||
|
List<ShopProductBase> updateProducts = new ArrayList<>();
|
||||||
|
|
||||||
|
List<ShopProductIndex> newShopProductIndexList = new ArrayList<>();
|
||||||
|
List<ShopProductIndex> updateShopProductIndexList = new ArrayList<>();
|
||||||
|
|
||||||
|
List<ShopProductData> newProductDataList=new ArrayList<>();
|
||||||
|
List<ShopProductData> updateProductDataList=new ArrayList<>();
|
||||||
|
|
||||||
|
List<ShopProductDetail> newShopProductDetailList=new ArrayList<>();
|
||||||
|
List<ShopProductDetail> updateShopProductDetailList=new ArrayList<>();
|
||||||
|
|
||||||
|
List<ShopProductInfo> newShopProductInfoList=new ArrayList<>();
|
||||||
|
List<ShopProductInfo> updateShopProductInfoList=new ArrayList<>();
|
||||||
|
|
||||||
|
List<List<ShopProductItem>> newShopProductItemList=new ArrayList<>();
|
||||||
|
List<List<ShopProductItem>> updateShopProductItemList=new ArrayList<>();
|
||||||
|
|
||||||
|
List<List<ShopProductImage>> newShopProductImageList=new ArrayList<>();
|
||||||
|
List<List<ShopProductImage>> updateShopProductImageList=new ArrayList<>();
|
||||||
|
|
||||||
|
List<ShopProductValidPeriod> newShopProductValidPeriodList=new ArrayList<>();
|
||||||
|
List<ShopProductValidPeriod> updateShopProductValidPeriodList=new ArrayList<>();
|
||||||
|
|
||||||
|
List<ShopProductAssistIndex> newShopProductAssistIndexList=new ArrayList<>();
|
||||||
|
List<ShopProductAssistIndex> updateShopProductAssistIndexList=new ArrayList<>();
|
||||||
|
try {
|
||||||
|
for (int i = 0; i < shopProductBaseList.size(); i++) {
|
||||||
|
ShopProductBase base = shopProductBaseList.get(i);
|
||||||
|
String key = base.getStore_id() + "_" + base.getProduct_number();
|
||||||
|
if (existingProducts.containsKey(key)) {
|
||||||
|
|
||||||
|
// 已存在商品,设置ID并加入更新列表
|
||||||
|
Long existId = existingProducts.get(key);
|
||||||
|
base.setProduct_id(existId);
|
||||||
|
|
||||||
|
shopProductBaseList.get(i).setProduct_id(existId);
|
||||||
|
//shopProductIndexList.get(i).setProduct_id(existId);
|
||||||
|
// shopProductIndexList.get(i).setProduct_unit_points(BigDecimal.ZERO);
|
||||||
|
shopProductIndexList.get(i).setProduct_unit_price_max(base.getProduct_market_price());
|
||||||
|
shopProductIndexList.get(i).setProduct_unit_sp(Convert.toBigDecimal(base.getProduct_unit_sp()));
|
||||||
|
shopProductIndexList.get(i).setProduct_sale_time(base.getProduct_sale_time().getTime());
|
||||||
|
shopProductIndexList.get(i).setProduct_verify_id(base.getProduct_verify_id());
|
||||||
|
shopProductIndexList.get(i).setProduct_state_id(base.getProduct_state_id());
|
||||||
|
// 判断店铺是否开启
|
||||||
|
// shopProductIndexList.get(i).setStore_is_open(1);
|
||||||
|
// shopProductIndexList.get(i).setStore_is_selfsupport(1);
|
||||||
|
// shopProductIndexList.get(i).setStore_type(1);
|
||||||
|
// shopProductIndexList.get(i).setSubsite_id(0);
|
||||||
|
// shopProductIndexList.get(i).setProduct_number(base.getProduct_number());
|
||||||
|
|
||||||
|
// shopProductDataList.get(i).setProduct_id(existId);
|
||||||
|
// shopProductDetailList.get(i).setProduct_id(existId);
|
||||||
|
// shopProductInfoList.get(i).setProduct_id(existId);
|
||||||
|
if(CollUtil.isNotEmpty(shopProductIndexList)){
|
||||||
|
updateShopProductIndexList.add(shopProductIndexList.get(i));
|
||||||
|
}
|
||||||
|
if(CollUtil.isNotEmpty(shopProductDataList)){
|
||||||
|
updateProductDataList.add(shopProductDataList.get(i));
|
||||||
|
}
|
||||||
|
if(CollUtil.isNotEmpty(shopProductDetailList)){
|
||||||
|
updateShopProductDetailList.add(shopProductDetailList.get(i));
|
||||||
|
}
|
||||||
|
if(CollUtil.isNotEmpty(shopProductInfoList)){
|
||||||
|
updateShopProductInfoList.add(shopProductInfoList.get(i));
|
||||||
|
}
|
||||||
|
if(CollUtil.isNotEmpty(shopProductItemList)){
|
||||||
|
updateShopProductItemList.add(shopProductItemList.get(i));
|
||||||
|
}
|
||||||
|
|
||||||
|
if(CollUtil.isNotEmpty(shopProductImageList)){
|
||||||
|
updateShopProductImageList.add(shopProductImageList.get(i));
|
||||||
|
}
|
||||||
|
if(CollUtil.isNotEmpty(shopProductValidPeriodList)){
|
||||||
|
updateShopProductValidPeriodList.add(shopProductValidPeriodList.get(i));
|
||||||
|
}
|
||||||
|
if(CollUtil.isNotEmpty(shopProductAssistIndexList)){
|
||||||
|
updateShopProductAssistIndexList.add(shopProductAssistIndexList.get(i));
|
||||||
|
}
|
||||||
|
|
||||||
|
updateProducts.add(base);
|
||||||
|
|
||||||
|
} else {
|
||||||
|
base.setProduct_verify_id(StateCode.PRODUCT_VERIFY_PASSED);//审核通过
|
||||||
|
base.setProduct_state_id(StateCode.PRODUCT_STATE_OFF_THE_SHELF);//下架状态
|
||||||
|
|
||||||
|
shopProductIndexList.get(i).setProduct_unit_points(BigDecimal.ZERO);
|
||||||
|
shopProductIndexList.get(i).setProduct_unit_price_max(base.getProduct_market_price());
|
||||||
|
shopProductIndexList.get(i).setProduct_unit_sp(Convert.toBigDecimal(base.getProduct_unit_sp()));
|
||||||
|
shopProductIndexList.get(i).setProduct_sale_time(base.getProduct_sale_time().getTime());
|
||||||
|
shopProductIndexList.get(i).setProduct_verify_id(base.getProduct_verify_id());
|
||||||
|
shopProductIndexList.get(i).setProduct_state_id(base.getProduct_state_id());
|
||||||
|
// 判断店铺是否开启
|
||||||
|
shopProductIndexList.get(i).setStore_is_open(1);
|
||||||
|
shopProductIndexList.get(i).setStore_is_selfsupport(1);
|
||||||
|
shopProductIndexList.get(i).setStore_type(1);
|
||||||
|
shopProductIndexList.get(i).setSubsite_id(0);
|
||||||
|
shopProductIndexList.get(i).setProduct_number(base.getProduct_number());
|
||||||
|
|
||||||
|
if(CollUtil.isNotEmpty(shopProductIndexList)){
|
||||||
|
newShopProductIndexList.add(shopProductIndexList.get(i));
|
||||||
|
}
|
||||||
|
if(CollUtil.isNotEmpty(shopProductDataList)){
|
||||||
|
newProductDataList.add(shopProductDataList.get(i));
|
||||||
|
}
|
||||||
|
if(CollUtil.isNotEmpty(shopProductDetailList)){
|
||||||
|
newShopProductDetailList.add(shopProductDetailList.get(i));
|
||||||
|
}
|
||||||
|
if(CollUtil.isNotEmpty(shopProductInfoList)){
|
||||||
|
newShopProductInfoList.add(shopProductInfoList.get(i));
|
||||||
|
}
|
||||||
|
if(CollUtil.isNotEmpty(shopProductItemList)){
|
||||||
|
newShopProductItemList.add(shopProductItemList.get(i));
|
||||||
|
}
|
||||||
|
if(CollUtil.isNotEmpty(shopProductImageList)){
|
||||||
|
newShopProductImageList.add(shopProductImageList.get(i));
|
||||||
|
}
|
||||||
|
if(CollUtil.isNotEmpty(shopProductValidPeriodList)){
|
||||||
|
newShopProductValidPeriodList.add(shopProductValidPeriodList.get(i));
|
||||||
|
}
|
||||||
|
if(CollUtil.isNotEmpty(shopProductAssistIndexList)){
|
||||||
|
newShopProductAssistIndexList.add(shopProductAssistIndexList.get(i));
|
||||||
|
}
|
||||||
|
// 新商品,加入新增列表
|
||||||
|
newProducts.add(base);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}catch (RuntimeException e){
|
||||||
|
logger.info("异常报错:{}",e.getMessage());
|
||||||
|
}
|
||||||
|
|
||||||
|
return executeBatchOperations(newProducts,updateProducts,newShopProductIndexList,updateShopProductIndexList,
|
||||||
|
newProductDataList,updateProductDataList,newShopProductDetailList,updateShopProductDetailList,
|
||||||
|
newShopProductInfoList,updateShopProductInfoList,newShopProductItemList,updateShopProductItemList,
|
||||||
|
newShopProductImageList,updateShopProductImageList,newShopProductValidPeriodList,updateShopProductValidPeriodList,
|
||||||
|
newShopProductAssistIndexList,updateShopProductAssistIndexList);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 执行批量操作(新增和更新分开处理)
|
||||||
|
*/
|
||||||
|
private Pair<Boolean, String> executeBatchOperations(List<ShopProductBase> newProducts, List<ShopProductBase> updateProducts,
|
||||||
|
List<ShopProductIndex> newShopProductIndexList,List<ShopProductIndex> updateShopProductIndexList,
|
||||||
|
List<ShopProductData> newShopProductDataList, List<ShopProductData> updateShopProductDataList,
|
||||||
|
List<ShopProductDetail> newShopProductDetailList, List<ShopProductDetail> updateShopProductDetailList,
|
||||||
|
List<ShopProductInfo> newShopProductInfoList, List<ShopProductInfo> updateShopProductInfoList,
|
||||||
|
List<List<ShopProductItem>> newShopProductItemList,List<List<ShopProductItem>> udpateShopProductItemList,
|
||||||
|
List<List<ShopProductImage>> newShopProductImageList, List<List<ShopProductImage>> udpteShopProductImageList,
|
||||||
|
List<ShopProductValidPeriod> newShopProductValidPeriodList, List<ShopProductValidPeriod> updateShopProductValidPeriodList,
|
||||||
|
List<ShopProductAssistIndex> newShopProductAssistIndexList, List<ShopProductAssistIndex> udpateShopProductAssistIndexList
|
||||||
|
) {
|
||||||
|
TransactionTemplate transactionTemplate = new TransactionTemplate(transactionManager);
|
||||||
|
transactionTemplate.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRED);
|
||||||
|
transactionTemplate.setIsolationLevel(TransactionDefinition.ISOLATION_READ_COMMITTED);
|
||||||
|
transactionTemplate.setTimeout(60); // 60秒超时
|
||||||
|
return transactionTemplate.execute(status -> {
|
||||||
|
try {
|
||||||
|
// Map<Long, List<Serializable>> productToItemsMap = new HashMap<>();
|
||||||
|
List<ShopProductAnalytics> addAnalyticsList = new ArrayList<>();
|
||||||
|
List<ShopProductAnalytics> udpateAnalyticsList = new ArrayList<>();
|
||||||
|
|
||||||
|
List<ShopProductItemSeq> addItemSeqs = new ArrayList<>();
|
||||||
|
List<ShopProductItemSeq> updateItemSeqs = new ArrayList<>();
|
||||||
|
|
||||||
|
List<Serializable> addItemIds = new ArrayList<>();
|
||||||
|
List<Serializable> udpateItemIds = new ArrayList<>();
|
||||||
|
List<ShopProductItem> addShopProductItems=new ArrayList<>();
|
||||||
|
List<ShopProductItem> updateShopProductItems=new ArrayList<>();
|
||||||
|
int taskCount = 2;
|
||||||
|
CountDownLatch latch = new CountDownLatch(taskCount);
|
||||||
|
// 1. 批量新增
|
||||||
|
if (CollUtil.isNotEmpty(newProducts)) {
|
||||||
|
// 4. 批量生成新商品的ID
|
||||||
|
List<Long> newIds = shopNumberSeqService.batchCreateNextNo("product_id", newProducts.size());
|
||||||
|
if (newIds == null || newIds.size() != newProducts.size()) {
|
||||||
|
return Pair.of(false, "生成商品编号异常");
|
||||||
|
}
|
||||||
|
for (int i = 0; i < newIds.size(); i++) {
|
||||||
|
Long productId = newIds.get(i);
|
||||||
|
ShopProductBase base = newProducts.get(i);
|
||||||
|
base.setProduct_id(productId);
|
||||||
|
// 设置关联ID
|
||||||
|
newProducts.get(i).setProduct_id(productId);
|
||||||
|
newShopProductIndexList.get(i).setProduct_id(productId);
|
||||||
|
newShopProductDataList.get(i).setProduct_id(productId);
|
||||||
|
newShopProductDetailList.get(i).setProduct_id(productId);
|
||||||
|
newShopProductInfoList.get(i).setProduct_id(productId);
|
||||||
|
|
||||||
|
// 处理商品项
|
||||||
|
List<ShopProductItem> items = newShopProductItemList.get(i);
|
||||||
|
processProductItems(items, productId, addItemSeqs);
|
||||||
|
addShopProductItems.addAll(items);
|
||||||
|
|
||||||
|
// 处理图片
|
||||||
|
if(CollUtil.isNotEmpty(newShopProductImageList)){
|
||||||
|
processProductImages(newShopProductImageList.get(i), productId,base.getStore_id());
|
||||||
|
}
|
||||||
|
|
||||||
|
// 处理辅助属性
|
||||||
|
if(CollUtil.isNotEmpty(newShopProductAssistIndexList)){
|
||||||
|
processAssistIndices(newShopProductAssistIndexList, base.getStore_id(),false);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 准备分析数据
|
||||||
|
ShopProductAnalytics shopProductAnalytics= new ShopProductAnalytics();
|
||||||
|
shopProductAnalytics.setProduct_id(productId);
|
||||||
|
shopProductAnalytics.setProduct_click(0);
|
||||||
|
addAnalyticsList.add(shopProductAnalytics);
|
||||||
|
}
|
||||||
|
List<Serializable> itemIds = processProductItemsId(addShopProductItems, addItemSeqs);
|
||||||
|
addItemIds.addAll(itemIds);
|
||||||
|
// 2. 批量更新
|
||||||
|
if (CollUtil.isNotEmpty(newProducts)) {
|
||||||
|
// new Thread(() -> {
|
||||||
|
logger.info("保存任务开始执行");
|
||||||
|
try {
|
||||||
|
long startTime=System.nanoTime();
|
||||||
|
saveBatch(newProducts,newProducts.size());
|
||||||
|
long endTime = System.nanoTime();
|
||||||
|
long duration = (endTime - startTime);
|
||||||
|
logger.info("新增newProducts--{}条数据耗时:{}",newProducts.size(),duration/1000000000);
|
||||||
|
latch.countDown();
|
||||||
|
} catch (Exception e) {
|
||||||
|
latch.countDown();
|
||||||
|
logger.error("系统异常"+e.getMessage());
|
||||||
|
}
|
||||||
|
// }).start();
|
||||||
|
}else{
|
||||||
|
// latch.countDown();
|
||||||
|
}
|
||||||
|
}else {
|
||||||
|
//latch.countDown();
|
||||||
|
}
|
||||||
|
if (CollUtil.isNotEmpty(updateProducts)) {
|
||||||
|
for(int i=0;i<updateProducts.size();i++){
|
||||||
|
Long productId = updateProducts.get(i).getProduct_id();
|
||||||
|
ShopProductBase base = updateProducts.get(i);
|
||||||
|
base.setProduct_id(productId);
|
||||||
|
|
||||||
|
// 设置关联ID
|
||||||
|
updateProducts.get(i).setProduct_id(productId);
|
||||||
|
updateShopProductIndexList.get(i).setProduct_id(productId);
|
||||||
|
updateShopProductDataList.get(i).setProduct_id(productId);
|
||||||
|
updateShopProductDetailList.get(i).setProduct_id(productId);
|
||||||
|
updateShopProductInfoList.get(i).setProduct_id(productId);
|
||||||
|
|
||||||
|
// 处理商品项
|
||||||
|
List<ShopProductItem> items = udpateShopProductItemList.get(i);
|
||||||
|
processProductItems(items, productId, updateItemSeqs);//
|
||||||
|
updateShopProductItems.addAll(items);
|
||||||
|
//allItemIds.addAll(itemIds);
|
||||||
|
// productToItemsMap.put(productId, itemIds);
|
||||||
|
|
||||||
|
// 处理图片
|
||||||
|
if(CollUtil.isNotEmpty(udpteShopProductImageList)){
|
||||||
|
processProductImages(udpteShopProductImageList.get(i), productId,base.getStore_id());
|
||||||
|
}
|
||||||
|
|
||||||
|
// 处理辅助属性
|
||||||
|
if(CollUtil.isNotEmpty(udpateShopProductAssistIndexList)){
|
||||||
|
processAssistIndices(udpateShopProductAssistIndexList, base.getStore_id(),true);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 准备分析数据
|
||||||
|
ShopProductAnalytics shopProductAnalytics= new ShopProductAnalytics();
|
||||||
|
shopProductAnalytics.setProduct_id(productId);
|
||||||
|
shopProductAnalytics.setProduct_click(0);
|
||||||
|
udpateAnalyticsList.add(shopProductAnalytics);
|
||||||
|
}
|
||||||
|
List<Serializable> itemIds = processProductItemsId(updateShopProductItems, updateItemSeqs);
|
||||||
|
udpateItemIds.addAll(itemIds);
|
||||||
|
// 2. 批量更新
|
||||||
|
if (CollUtil.isNotEmpty(updateProducts)) {
|
||||||
|
// new Thread(() -> {
|
||||||
|
logger.info("更新任务开始执行");
|
||||||
|
try {
|
||||||
|
long startTime=System.nanoTime();
|
||||||
|
updateBatchById(updateProducts);
|
||||||
|
long endTime = System.nanoTime();
|
||||||
|
long duration = (endTime - startTime);
|
||||||
|
logger.info("更新updateProducts-{}条数据耗时:{}",updateProducts.size(),duration/1000000000);
|
||||||
|
latch.countDown();
|
||||||
|
} catch (Exception e) {
|
||||||
|
latch.countDown();
|
||||||
|
logger.error("系统异常"+e.getMessage());
|
||||||
|
}
|
||||||
|
// }).start();
|
||||||
|
}else {
|
||||||
|
//latch.countDown();
|
||||||
|
}
|
||||||
|
}else {
|
||||||
|
// latch.countDown();
|
||||||
|
}
|
||||||
|
// latch.await();
|
||||||
|
// 3. 处理其他表的批量操作(同样需要区分新增和更新)
|
||||||
|
batchProcessOtherTables(newShopProductIndexList,updateShopProductIndexList,newShopProductDataList,updateShopProductDataList,
|
||||||
|
newShopProductDetailList,updateShopProductDetailList,newShopProductInfoList,updateShopProductInfoList,
|
||||||
|
newShopProductValidPeriodList,updateShopProductValidPeriodList,addShopProductItems,updateShopProductItems,
|
||||||
|
addAnalyticsList,udpateAnalyticsList,addItemSeqs,updateItemSeqs);
|
||||||
|
logger.info("处理成功,新增{}条,更新{}条", newProducts.size(), updateProducts.size());
|
||||||
|
return Pair.of(true, String.format("处理成功,新增%d条,更新%d条",
|
||||||
|
newProducts.size(), updateProducts.size()));
|
||||||
|
} catch (RuntimeException e) {
|
||||||
|
status.setRollbackOnly();
|
||||||
|
logger.error("批量操作异常", e);
|
||||||
|
return Pair.of(false, "批量操作异常: " + e.getMessage());
|
||||||
|
}
|
||||||
|
// catch (InterruptedException e) {
|
||||||
|
// status.setRollbackOnly();
|
||||||
|
// logger.error("批量操作异常", e);
|
||||||
|
// return Pair.of(false, "批量操作异常: " + e.getMessage());
|
||||||
|
// }
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// 批量保存操作
|
||||||
|
private void batchProcessOtherTables(List<ShopProductIndex> newShopProductIndex, List<ShopProductIndex> updateShopProductIndex,
|
||||||
|
List<ShopProductData> newShopProductDataList, List<ShopProductData> updateShopProductDataList,
|
||||||
|
List<ShopProductDetail> newshopProductDetailList, List<ShopProductDetail> updateShopProductDetailList,
|
||||||
|
List<ShopProductInfo> newShopProductInfoList,List<ShopProductInfo> updateShopProductInfoList,
|
||||||
|
List<ShopProductValidPeriod> newShopProductValidPeriodList,List<ShopProductValidPeriod> updateShopProductValidPeriodList,
|
||||||
|
List<ShopProductItem> newshopProductItemList,List<ShopProductItem> updateshopProductItemList,
|
||||||
|
List<ShopProductAnalytics> newShopProductAnalyticList,List<ShopProductAnalytics> updateShopProductAnalyticList,
|
||||||
|
List<ShopProductItemSeq> newShopProductItemSeqList,List<ShopProductItemSeq> updateShopProductItemSeqList) {
|
||||||
|
TransactionTemplate transactionTemplate = new TransactionTemplate(transactionManager);
|
||||||
|
transactionTemplate.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRED);
|
||||||
|
transactionTemplate.setIsolationLevel(TransactionDefinition.ISOLATION_READ_COMMITTED);
|
||||||
|
transactionTemplate.setTimeout(60); // 60秒超时
|
||||||
|
transactionTemplate.execute(status -> {
|
||||||
|
// 并行执行批量保存
|
||||||
|
//CompletableFuture<Void> future1 = CompletableFuture.runAsync(() -> {
|
||||||
|
try {
|
||||||
|
if (CollUtil.isNotEmpty(newShopProductIndex)) {
|
||||||
|
// synchronized (this){
|
||||||
|
long startTime=System.nanoTime();
|
||||||
|
shopProductIndexService.saveBatch(newShopProductIndex,newShopProductIndex.size());
|
||||||
|
long endTime = System.nanoTime();
|
||||||
|
long duration = (endTime - startTime);
|
||||||
|
logger.info("新增newShopProductIndex-{}条数据耗时:{}",newShopProductIndex.size(),duration/1000000000);
|
||||||
|
|
||||||
|
//}
|
||||||
|
|
||||||
|
}
|
||||||
|
if (CollUtil.isNotEmpty(updateShopProductIndex)) {
|
||||||
|
// synchronized (this) {
|
||||||
|
long startTime=System.nanoTime();
|
||||||
|
shopProductIndexService.updateBatchById(updateShopProductIndex);
|
||||||
|
long endTime = System.nanoTime();
|
||||||
|
long duration = (endTime - startTime);
|
||||||
|
logger.info("更新updateShopProductIndex-{}条数据耗时:{}",updateShopProductIndex.size(),duration/1000000000);
|
||||||
|
// }
|
||||||
|
}
|
||||||
|
|
||||||
|
if (CollUtil.isNotEmpty(newShopProductDataList)) {
|
||||||
|
//synchronized (this) {
|
||||||
|
long startTime=System.nanoTime();
|
||||||
|
shopProductDataService.saveBatch(newShopProductDataList, newShopProductDataList.size());
|
||||||
|
long endTime = System.nanoTime();
|
||||||
|
long duration = (endTime - startTime);
|
||||||
|
logger.info("新增newShopProductDataList-{}条数据耗时:{}",newShopProductDataList.size(),duration/1000000000);
|
||||||
|
//}
|
||||||
|
}
|
||||||
|
if (CollUtil.isNotEmpty(updateShopProductDataList)) {
|
||||||
|
// synchronized (this) {
|
||||||
|
long startTime=System.nanoTime();
|
||||||
|
shopProductDataService.updateBatchById(updateShopProductDataList);
|
||||||
|
long endTime = System.nanoTime();
|
||||||
|
long duration = (endTime - startTime);
|
||||||
|
logger.info("更新updateShopProductDataList-{}条数据耗时:{}",updateShopProductDataList.size(),duration/1000000000);
|
||||||
|
// }
|
||||||
|
}
|
||||||
|
}catch (RuntimeException e){
|
||||||
|
logger.info("批量报错附表失败{}",e.getMessage());
|
||||||
|
}
|
||||||
|
|
||||||
|
// });
|
||||||
|
|
||||||
|
// CompletableFuture<Void> future2 = CompletableFuture.runAsync(() -> {
|
||||||
|
try {
|
||||||
|
if (CollUtil.isNotEmpty(newshopProductDetailList)) {
|
||||||
|
// synchronized (this) {
|
||||||
|
long startTime=System.nanoTime();
|
||||||
|
shopProductDetailService.saveBatch(newshopProductDetailList, newshopProductDetailList.size());
|
||||||
|
long endTime = System.nanoTime();
|
||||||
|
long duration = (endTime - startTime);
|
||||||
|
logger.info("新增newshopProductDetailList-{}条数据耗时:{}",newshopProductDetailList.size(),duration/1000000000);
|
||||||
|
|
||||||
|
// }
|
||||||
|
}
|
||||||
|
if (CollUtil.isNotEmpty(updateShopProductDetailList)) {
|
||||||
|
// synchronized (this) {
|
||||||
|
long startTime=System.nanoTime();
|
||||||
|
shopProductDetailService.updateBatchById(updateShopProductDetailList);
|
||||||
|
long endTime = System.nanoTime();
|
||||||
|
long duration = (endTime - startTime);
|
||||||
|
logger.info("更新updateShopProductDetailList-{}条数据耗时:{}",updateShopProductDetailList.size(),duration/1000000000);
|
||||||
|
// }
|
||||||
|
}
|
||||||
|
if (CollUtil.isNotEmpty(newShopProductInfoList)) {
|
||||||
|
// synchronized (this) {
|
||||||
|
long startTime=System.nanoTime();
|
||||||
|
shopProductInfoService.saveBatch(newShopProductInfoList, newShopProductInfoList.size());
|
||||||
|
long endTime = System.nanoTime();
|
||||||
|
long duration = (endTime - startTime);
|
||||||
|
logger.info("新增updateShopProductDetailList-{}条数据耗时:{}",newShopProductInfoList.size(),duration/1000000000);
|
||||||
|
// }
|
||||||
|
}
|
||||||
|
if (CollUtil.isNotEmpty(updateShopProductInfoList)) {
|
||||||
|
// synchronized (this) {
|
||||||
|
long startTime=System.nanoTime();
|
||||||
|
shopProductInfoService.updateBatchById(updateShopProductInfoList);
|
||||||
|
long endTime = System.nanoTime();
|
||||||
|
long duration = (endTime - startTime);
|
||||||
|
logger.info("更新updateShopProductInfoList-{}条数据耗时:{}",updateShopProductInfoList.size(),duration/1000000000);
|
||||||
|
// }
|
||||||
|
}
|
||||||
|
}catch (RuntimeException e){
|
||||||
|
logger.info("批量报错附表失败{}",e.getMessage());
|
||||||
|
}
|
||||||
|
//});
|
||||||
|
|
||||||
|
//CompletableFuture<Void> future3 = CompletableFuture.runAsync(() -> {
|
||||||
|
try {
|
||||||
|
if (CollUtil.isNotEmpty(newShopProductValidPeriodList)) {
|
||||||
|
// synchronized (this) {
|
||||||
|
long startTime=System.nanoTime();
|
||||||
|
validPeriodService.saveBatch(newShopProductValidPeriodList, newShopProductValidPeriodList.size());
|
||||||
|
long endTime = System.nanoTime();
|
||||||
|
long duration = (endTime - startTime);
|
||||||
|
logger.info("新增newShopProductValidPeriodList-{}条数据耗时:{}",newShopProductValidPeriodList.size(),duration/1000000000);
|
||||||
|
// }
|
||||||
|
}
|
||||||
|
if (CollUtil.isNotEmpty(updateShopProductValidPeriodList)) {
|
||||||
|
//synchronized (this) {
|
||||||
|
long startTime=System.nanoTime();
|
||||||
|
validPeriodService.updateBatchById(updateShopProductValidPeriodList);
|
||||||
|
long endTime = System.nanoTime();
|
||||||
|
long duration = (endTime - startTime);
|
||||||
|
logger.info("更新updateShopProductValidPeriodList-{}条数据耗时:{}",updateShopProductValidPeriodList.size(),duration/1000000000);
|
||||||
|
// }
|
||||||
|
}
|
||||||
|
if (CollUtil.isNotEmpty(newShopProductAnalyticList)) {
|
||||||
|
// synchronized (this) {
|
||||||
|
long startTime=System.nanoTime();
|
||||||
|
shopProductAnalyticsService.saveBatch(newShopProductAnalyticList, newShopProductAnalyticList.size());
|
||||||
|
long endTime = System.nanoTime();
|
||||||
|
long duration = (endTime - startTime);
|
||||||
|
logger.info("新增newShopProductAnalyticList-{}条数据耗时:{}",newShopProductAnalyticList.size(),duration/1000000000);
|
||||||
|
// }
|
||||||
|
}
|
||||||
|
if (CollUtil.isNotEmpty(updateShopProductAnalyticList)) {
|
||||||
|
// synchronized (this) {
|
||||||
|
long startTime=System.nanoTime();
|
||||||
|
shopProductAnalyticsService.updateBatchById(updateShopProductAnalyticList);
|
||||||
|
long endTime = System.nanoTime();
|
||||||
|
long duration = (endTime - startTime);
|
||||||
|
logger.info("更新updateShopProductAnalyticList-{}条数据耗时:{}",updateShopProductAnalyticList.size(),duration/1000000000);
|
||||||
|
// }
|
||||||
|
}
|
||||||
|
}catch (RuntimeException e){
|
||||||
|
logger.info("批量报错附表失败{}",e.getMessage());
|
||||||
|
}
|
||||||
|
|
||||||
|
//});
|
||||||
|
|
||||||
|
//CompletableFuture<Void> future4 = CompletableFuture.runAsync(() -> {
|
||||||
|
try {
|
||||||
|
if (CollUtil.isNotEmpty(newshopProductItemList)) {
|
||||||
|
// synchronized (this) {
|
||||||
|
long startTime=System.nanoTime();
|
||||||
|
shopProductItemService.saveBatch(newshopProductItemList, newshopProductItemList.size());
|
||||||
|
long endTime = System.nanoTime();
|
||||||
|
long duration = (endTime - startTime);
|
||||||
|
logger.info("新增newshopProductItemList-{}条数据耗时:{}",newshopProductItemList.size(),duration/1000000000);
|
||||||
|
//}
|
||||||
|
}
|
||||||
|
if (CollUtil.isNotEmpty(updateshopProductItemList)) {
|
||||||
|
// synchronized (this) {
|
||||||
|
long startTime = System.nanoTime();
|
||||||
|
shopProductItemService.updateBatchById(updateshopProductItemList);
|
||||||
|
long endTime = System.nanoTime();
|
||||||
|
long duration = (endTime - startTime);
|
||||||
|
logger.info("更新updateshopProductItemList-{}条数据耗时:{}",updateshopProductItemList.size(),duration/1000000000);
|
||||||
|
//}
|
||||||
|
}
|
||||||
|
if (CollUtil.isNotEmpty(newShopProductItemSeqList)) {
|
||||||
|
// synchronized (this) {
|
||||||
|
long startTime = System.nanoTime();
|
||||||
|
shopProductItemSeqService.saveBatch(newShopProductItemSeqList, newShopProductItemSeqList.size());
|
||||||
|
long endTime = System.nanoTime();
|
||||||
|
long duration = (endTime - startTime);
|
||||||
|
logger.info("新曾newShopProductItemSeqList-{}条数据耗时:{}",newShopProductItemSeqList.size(),duration/1000000000);
|
||||||
|
// }
|
||||||
|
}
|
||||||
|
if (CollUtil.isNotEmpty(updateShopProductItemSeqList)) {
|
||||||
|
// synchronized (this) {
|
||||||
|
long startTime = System.nanoTime();
|
||||||
|
shopProductItemSeqService.updateBatchById(updateShopProductItemSeqList);
|
||||||
|
long endTime = System.nanoTime();
|
||||||
|
long duration = (endTime - startTime);
|
||||||
|
logger.info("更新updateShopProductItemSeqList-{}条数据耗时:{}",updateShopProductItemSeqList.size(),duration/1000000000);
|
||||||
|
// }
|
||||||
|
}
|
||||||
|
}catch (RuntimeException e){
|
||||||
|
logger.info("批量报错附表失败{}",e.getMessage());
|
||||||
|
}
|
||||||
|
//});
|
||||||
|
// 等待所有操作完成
|
||||||
|
// CompletableFuture.allOf(future1, future2, future3, future4).join();
|
||||||
|
return null;
|
||||||
|
});
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 批量生产itemid
|
||||||
|
* @param items
|
||||||
|
* @param itemSeqs
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
private List<Serializable> processProductItemsId(List<ShopProductItem> items,List<ShopProductItemSeq> itemSeqs){
|
||||||
|
List<Serializable> itemIds = new ArrayList<>();
|
||||||
|
if (CollUtil.isEmpty(items)) return itemIds;
|
||||||
|
List<Long> generatedIds = shopNumberSeqService.batchCreateNextNo("item_id", items.size());
|
||||||
|
for (int i = 0; i < items.size(); i++) {
|
||||||
|
Long itemId = generatedIds.get(i);
|
||||||
|
ShopProductItem item = items.get(i);
|
||||||
|
item.setItem_id(itemId);
|
||||||
|
itemIds.add(itemId);
|
||||||
|
ShopProductItemSeq field_row= itemSeqs.get(i);
|
||||||
|
field_row.setItem_id(itemId);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
return itemIds;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 处理商品项
|
||||||
|
private void processProductItems(List<ShopProductItem> items, Long productId,
|
||||||
|
List<ShopProductItemSeq> itemSeqs) {
|
||||||
|
|
||||||
|
for (int i = 0; i < items.size(); i++) {
|
||||||
|
ShopProductItem item = items.get(i);
|
||||||
|
item.setProduct_id(productId);
|
||||||
|
// itemIds.add(itemId);
|
||||||
|
|
||||||
|
// ITEM_ID/SKU唯一编号表。
|
||||||
|
// product_id + sort(spec_item_id) = 构造唯一ITEM ID
|
||||||
|
String item_spec = item.getItem_spec();
|
||||||
|
cn.hutool.json.JSONArray array_item_spec = cn.hutool.json.JSONUtil.parseArray(item_spec);
|
||||||
|
List<Integer> spec_item_ids = new ArrayList<>();
|
||||||
|
List<String> item_names = new ArrayList<>();
|
||||||
|
for (Object josn_item_spec : array_item_spec) {
|
||||||
|
cn.hutool.json.JSONObject itemJ = (cn.hutool.json.JSONObject) ((cn.hutool.json.JSONObject) josn_item_spec).get("item");
|
||||||
|
Integer id = Convert.toInt(itemJ.get("id"));
|
||||||
|
String name = Convert.toStr(itemJ.get("name"));
|
||||||
|
if (ObjectUtil.isNotNull(id)) spec_item_ids.add(id);
|
||||||
|
item_names.add(name);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (CollUtil.isNotEmpty(spec_item_ids)) Collections.sort(spec_item_ids);
|
||||||
|
|
||||||
|
//用来判断是否使用
|
||||||
|
item.setSpec_item_ids(CollUtil.join(spec_item_ids, ","));
|
||||||
|
|
||||||
|
// 创建itemSeq记录
|
||||||
|
String skuUniqid = generateSkuUniqid(item); // 生成SKU唯一标识
|
||||||
|
String seqVal = productId + ":" + skuUniqid;
|
||||||
|
ShopProductItemSeq field_row = new ShopProductItemSeq();
|
||||||
|
field_row.setProduct_id(productId);
|
||||||
|
field_row.setProduct_item_seq_val(seqVal);
|
||||||
|
field_row.setProduct_item_seq_id(SecureUtil.md5(seqVal));
|
||||||
|
//field_row.setItem_id(itemId);
|
||||||
|
|
||||||
|
// 修正默认价格, 防止出现不合理价格
|
||||||
|
BigDecimal item_platform_price = NumberUtil.max(item.getItem_cost_price(), item.getItem_platform_price());
|
||||||
|
BigDecimal _item_unit_price = NumberUtil.max(item.getItem_unit_price(), item.getItem_platform_price());
|
||||||
|
item.setItem_platform_price(item_platform_price);
|
||||||
|
item.setItem_unit_price(_item_unit_price);
|
||||||
|
item.setItem_name(CollUtil.join(item_names, ","));
|
||||||
|
item.setItem_title("");
|
||||||
|
item.setItem_freetime(0);
|
||||||
|
|
||||||
|
itemSeqs.add(field_row);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 生成SKU唯一标识符
|
||||||
|
* @param item 商品项
|
||||||
|
* @return SKU唯一标识字符串
|
||||||
|
*/
|
||||||
|
private String generateSkuUniqid(ShopProductItem item) {
|
||||||
|
// 1. 获取商品规格信息
|
||||||
|
String itemSpec = item.getItem_spec();
|
||||||
|
if (StrUtil.isBlank(itemSpec)) {
|
||||||
|
return "default"; // 无规格商品的默认标识
|
||||||
|
}
|
||||||
|
|
||||||
|
// 2. 解析规格JSON
|
||||||
|
cn.hutool.json.JSONArray specArray;
|
||||||
|
try {
|
||||||
|
specArray = JSONUtil.parseArray(itemSpec);
|
||||||
|
} catch (Exception e) {
|
||||||
|
logger.warn("商品规格解析失败,使用默认标识", e);
|
||||||
|
return "default";
|
||||||
|
}
|
||||||
|
|
||||||
|
// 3. 提取所有规格项ID并排序
|
||||||
|
List<Integer> specItemIds = new ArrayList<>();
|
||||||
|
for (Object specObj : specArray) {
|
||||||
|
JSONObject spec = (JSONObject) specObj;
|
||||||
|
JSONObject specItem = spec.getJSONObject("item");
|
||||||
|
if (specItem != null) {
|
||||||
|
Integer id = specItem.getInteger("id");
|
||||||
|
if (id != null) {
|
||||||
|
specItemIds.add(id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 4. 排序确保顺序一致性
|
||||||
|
Collections.sort(specItemIds);
|
||||||
|
|
||||||
|
// 5. 生成唯一标识字符串
|
||||||
|
return CollUtil.join(specItemIds, "-");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 检查哪些商品已存在
|
||||||
|
*/
|
||||||
|
private Map<String, Long> checkExistingProducts(List<ShopProductBase> productBases) {
|
||||||
|
// 1. 按店铺和货号分组
|
||||||
|
Map<String, List<ShopProductBase>> storeProductMap = productBases.stream()
|
||||||
|
.collect(Collectors.groupingBy(
|
||||||
|
p -> p.getStore_id() + "_" + p.getProduct_number()
|
||||||
|
));
|
||||||
|
|
||||||
|
// 2. 批量查询已存在的商品
|
||||||
|
List<Pair<Integer, String>> storeProductPairs = productBases.stream()
|
||||||
|
.map(p -> Pair.of(p.getStore_id(), p.getProduct_number()))
|
||||||
|
.distinct()
|
||||||
|
.collect(Collectors.toList());
|
||||||
|
|
||||||
|
// 3. 批量查询(优化为一次查询)
|
||||||
|
List<ShopProductBase> existing = batchGetByStoreAndProductNumber(storeProductPairs,productBases.get(0).getStore_id());
|
||||||
|
|
||||||
|
// 4. 构建存在商品的映射表
|
||||||
|
return existing.stream()
|
||||||
|
.collect(Collectors.toMap(
|
||||||
|
p -> p.getStore_id() + "_" + p.getProduct_number(),
|
||||||
|
ShopProductBase::getProduct_id
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 批量根据店铺和货号查询商品
|
||||||
|
*/
|
||||||
|
private List<ShopProductBase> batchGetByStoreAndProductNumber(List<Pair<Integer, String>> storeProductPairs,Integer storeId) {
|
||||||
|
if (CollUtil.isEmpty(storeProductPairs)) {
|
||||||
|
return Collections.emptyList();
|
||||||
|
}
|
||||||
|
|
||||||
|
// 使用IN查询优化(根据数据库特性可能需要分批)
|
||||||
|
QueryWrapper<ShopProductBase> query = new QueryWrapper<>();
|
||||||
|
query.select("product_id", "store_id", "product_number");
|
||||||
|
|
||||||
|
// 构建OR条件 (store_id=X AND product_number=Y) OR (store_id=A AND product_number=B)...
|
||||||
|
storeProductPairs.forEach(pair -> {
|
||||||
|
query.or(q -> q.eq("store_id", pair.getFirst())
|
||||||
|
.eq("product_number", pair.getSecond()));
|
||||||
|
});
|
||||||
|
|
||||||
|
return list(query);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 处理商品图片批量操作
|
||||||
|
* @param productImages 商品图片列表
|
||||||
|
* @param productId 商品ID
|
||||||
|
*/
|
||||||
|
private void processProductImages(List<ShopProductImage> productImages, Long productId, Integer storeId) {
|
||||||
|
if (CollUtil.isEmpty(productImages)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 1. 查询现有图片
|
||||||
|
List<ShopProductImage> existingImages = shopProductImageService.getShopProductImageByStoreId(storeId);
|
||||||
|
Map<Long, ShopProductImage> existingImageMap = existingImages.stream()
|
||||||
|
.collect(Collectors.toMap(ShopProductImage::getProduct_image_id, Function.identity()));
|
||||||
|
|
||||||
|
// 2. 分离需要新增、更新和删除的图片
|
||||||
|
List<ShopProductImage> toAdd = new ArrayList<>();
|
||||||
|
List<ShopProductImage> toUpdate = new ArrayList<>();
|
||||||
|
List<Long> toDelete = new ArrayList<>();
|
||||||
|
List<String> delBaiduImages = new ArrayList<>();
|
||||||
|
List<String> addBaiduImages = new ArrayList<>();
|
||||||
|
|
||||||
|
for (ShopProductImage newImage : productImages) {
|
||||||
|
newImage.setProduct_id(productId);
|
||||||
|
// 设置默认值
|
||||||
|
newImage.setItem_image_ext_1("");
|
||||||
|
newImage.setItem_image_ext_2("");
|
||||||
|
|
||||||
|
// 判断是新增还是更新
|
||||||
|
if (newImage.getProduct_image_id() == null) {
|
||||||
|
toAdd.add(newImage);
|
||||||
|
if (StrUtil.isNotBlank(newImage.getItem_image_default())) {
|
||||||
|
addBaiduImages.add(newImage.getItem_image_default());
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
ShopProductImage oldImage = existingImageMap.get(newImage.getProduct_image_id());
|
||||||
|
if (oldImage != null) {
|
||||||
|
// 检查图片是否有变化
|
||||||
|
if (!StrUtil.equals(oldImage.getItem_image_default(), newImage.getItem_image_default())) {
|
||||||
|
if (StrUtil.isNotBlank(oldImage.getItem_image_default())) {
|
||||||
|
delBaiduImages.add(oldImage.getItem_image_default());
|
||||||
|
}
|
||||||
|
if (StrUtil.isNotBlank(newImage.getItem_image_default())) {
|
||||||
|
addBaiduImages.add(newImage.getItem_image_default());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
toUpdate.add(newImage);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 找出需要删除的图片(存在但不在新列表中)
|
||||||
|
existingImages.forEach(oldImage -> {
|
||||||
|
boolean stillExists = productImages.stream()
|
||||||
|
.anyMatch(img -> Objects.equals(img.getProduct_image_id(), oldImage.getProduct_image_id()));
|
||||||
|
if (!stillExists) {
|
||||||
|
toDelete.add(oldImage.getProduct_image_id());
|
||||||
|
if (StrUtil.isNotBlank(oldImage.getItem_image_default())) {
|
||||||
|
delBaiduImages.add(oldImage.getItem_image_default());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// 3. 执行批量操作
|
||||||
|
if (CollUtil.isNotEmpty(toAdd)) {
|
||||||
|
shopProductImageService.saveBatch(toAdd,toAdd.size());
|
||||||
|
}
|
||||||
|
if (CollUtil.isNotEmpty(toUpdate)) {
|
||||||
|
shopProductImageService.updateBatchById(toUpdate);
|
||||||
|
}
|
||||||
|
if (CollUtil.isNotEmpty(toDelete)) {
|
||||||
|
shopProductImageService.removeByIds(toDelete);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* 处理商品辅助属性批量操作
|
||||||
|
* @param assistIndices 辅助属性列表
|
||||||
|
* @param storeId 商品ID
|
||||||
|
*/
|
||||||
|
private void processAssistIndices(List<ShopProductAssistIndex> assistIndices, Integer storeId,boolean isUpdate) {
|
||||||
|
if (CollUtil.isEmpty(assistIndices)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// 查询现有辅助属性
|
||||||
|
// QueryWrapper<ShopProductAssistIndex> query = new QueryWrapper<>();
|
||||||
|
//query.eq("product_id", productId);
|
||||||
|
List<ShopProductAssistIndex> existingAssists = assistIndexService.getShopProductAssistIndexStoreId(storeId);
|
||||||
|
|
||||||
|
// 分离需要新增、更新和删除的辅助属性
|
||||||
|
List<String> toDelete = new ArrayList<>();
|
||||||
|
// 找出需要删除的辅助属性(存在但不在新列表中)
|
||||||
|
existingAssists.forEach(oldAssist -> {
|
||||||
|
boolean stillExists = assistIndices.stream()
|
||||||
|
.anyMatch(a -> Objects.equals(
|
||||||
|
a.getProduct_assist_index_id(),
|
||||||
|
oldAssist.getProduct_assist_index_id()
|
||||||
|
));
|
||||||
|
if (!stillExists) {
|
||||||
|
toDelete.add(oldAssist.getProduct_assist_index_id());
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// 执行批量操作
|
||||||
|
if (CollUtil.isNotEmpty(assistIndices)) {
|
||||||
|
if(isUpdate){
|
||||||
|
assistIndexService.updateBatchById(assistIndices);
|
||||||
|
}else {
|
||||||
|
assistIndexService.saveBatch(assistIndices,assistIndices.size());
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
if (CollUtil.isNotEmpty(toDelete)) {
|
||||||
|
assistIndexService.removeByIds(toDelete);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//
|
||||||
|
// private void myShopProductBaseBatch(List<ShopProductBase> list){
|
||||||
|
// SqlSession sqlSession=sqlSessionFactory.openSession();
|
||||||
|
// StopWatch stopWatch=new StopWatch();
|
||||||
|
// stopWatch.start();
|
||||||
|
// shopProductBaseService.saveBatch(list);
|
||||||
|
// sqlSession.commit();
|
||||||
|
// stopWatch.stop();
|
||||||
|
// }
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,11 +1,18 @@
|
|||||||
package com.suisung.mall.shop.product.service.impl;
|
package com.suisung.mall.shop.product.service.impl;
|
||||||
|
|
||||||
|
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
|
||||||
import com.suisung.mall.common.modules.product.ShopProductImage;
|
import com.suisung.mall.common.modules.product.ShopProductImage;
|
||||||
|
import com.suisung.mall.core.web.service.RedisService;
|
||||||
import com.suisung.mall.core.web.service.impl.BaseServiceImpl;
|
import com.suisung.mall.core.web.service.impl.BaseServiceImpl;
|
||||||
import com.suisung.mall.shop.product.mapper.ShopProductImageMapper;
|
import com.suisung.mall.shop.product.mapper.ShopProductImageMapper;
|
||||||
import com.suisung.mall.shop.product.service.ShopProductImageService;
|
import com.suisung.mall.shop.product.service.ShopProductImageService;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* <p>
|
* <p>
|
||||||
@ -17,4 +24,26 @@ import org.springframework.stereotype.Service;
|
|||||||
*/
|
*/
|
||||||
@Service
|
@Service
|
||||||
public class ShopProductImageServiceImpl extends BaseServiceImpl<ShopProductImageMapper, ShopProductImage> implements ShopProductImageService {
|
public class ShopProductImageServiceImpl extends BaseServiceImpl<ShopProductImageMapper, ShopProductImage> implements ShopProductImageService {
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private RedisService redisService;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<ShopProductImage> getShopProductImageByStoreId(Integer storeId) {
|
||||||
|
|
||||||
|
List<ShopProductImage> existingImages = (List<ShopProductImage>) redisService.get("ShopProductImageStoreId:"+storeId);
|
||||||
|
if(existingImages==null){
|
||||||
|
QueryWrapper<ShopProductImage> query = new QueryWrapper<>();
|
||||||
|
query.eq("store_id", storeId);
|
||||||
|
existingImages = this.list(query);
|
||||||
|
redisService.set(""+storeId, existingImages);
|
||||||
|
}
|
||||||
|
|
||||||
|
return existingImages;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void clearCacheShopProductImageByStoreId(Integer storeId) {
|
||||||
|
redisService.del("ShopProductImageStoreId:"+storeId);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -0,0 +1,148 @@
|
|||||||
|
package com.suisung.mall.shop.sixun.dao;
|
||||||
|
|
||||||
|
import com.microsoft.sqlserver.jdbc.SQLServerDataSource;
|
||||||
|
import com.microsoft.sqlserver.jdbc.SQLServerException;
|
||||||
|
import com.suisung.mall.shop.sixun.dto.ResultDto;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
|
||||||
|
import java.sql.Connection;
|
||||||
|
import java.sql.PreparedStatement;
|
||||||
|
import java.sql.ResultSet;
|
||||||
|
import java.sql.SQLException;
|
||||||
|
|
||||||
|
@Slf4j
|
||||||
|
public class BaseDao {
|
||||||
|
|
||||||
|
private final static String DRIVER = "com.microsoft.sqlserver.jdbc.SQLServerDriver";
|
||||||
|
private final static String DEFAULT_IP="127.0.0.1";
|
||||||
|
private final static String DEFAULT_DATABASE="hbposev9";
|
||||||
|
private final static String DEFAULT_USERNAME="sa";
|
||||||
|
private final static String DEFAULT_PWD="123456";
|
||||||
|
private final static int PortNumber=1433;
|
||||||
|
private final static int LoginTimeout=10;
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* 动态获取数据库连接
|
||||||
|
* @param ip 数据库ip+
|
||||||
|
* @param username 用户名
|
||||||
|
* @param password 密码 todo 需要加密
|
||||||
|
* @param dataBaseName 数据库名称
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public Connection getConnection(String ip, String username, String password, String dataBaseName){
|
||||||
|
Connection conn=null;
|
||||||
|
SQLServerDataSource sqlServerDataSource=new SQLServerDataSource();
|
||||||
|
sqlServerDataSource.setDatabaseName(dataBaseName==null?DEFAULT_DATABASE:dataBaseName);
|
||||||
|
sqlServerDataSource.setServerName(ip==null?DEFAULT_IP:ip);
|
||||||
|
sqlServerDataSource.setPortNumber(PortNumber);
|
||||||
|
sqlServerDataSource.setLoginTimeout(LoginTimeout);
|
||||||
|
sqlServerDataSource.setPassword(password==null?DEFAULT_PWD:password);
|
||||||
|
sqlServerDataSource.setUser(username==null?DEFAULT_USERNAME:username);
|
||||||
|
try {
|
||||||
|
conn=sqlServerDataSource.getConnection();
|
||||||
|
} catch (SQLServerException e) {
|
||||||
|
log.info("数据库连接异常方法{}异常信息{}","com.suisung.mall.shop.sixun.dao.BaseDao.getConnection",e.getMessage());
|
||||||
|
throw new RuntimeException(e);
|
||||||
|
}
|
||||||
|
|
||||||
|
return conn;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 关闭数据库连接
|
||||||
|
* @param conn
|
||||||
|
*/
|
||||||
|
public void Close(Connection conn){
|
||||||
|
if(conn!=null){
|
||||||
|
try {
|
||||||
|
conn.close();
|
||||||
|
} catch (SQLException e) {
|
||||||
|
throw new RuntimeException(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 返回游标和连接 减少服务器的占用内存
|
||||||
|
* @param ip
|
||||||
|
* @param username
|
||||||
|
* @param password
|
||||||
|
* @param dataBaseName
|
||||||
|
* @return ResultDto
|
||||||
|
*/
|
||||||
|
public ResultDto baseFindList(String ip, String username, String password, String dataBaseName, String table){
|
||||||
|
Connection connection=getConnection(ip,username,password,dataBaseName);
|
||||||
|
String sql="select * from %s where 1=1";
|
||||||
|
sql=String.format(sql, table);
|
||||||
|
ResultDto resultDto=new ResultDto();
|
||||||
|
ResultSet rs=null;
|
||||||
|
try {
|
||||||
|
PreparedStatement ps= connection.prepareStatement(sql);
|
||||||
|
rs = ps.executeQuery();
|
||||||
|
} catch (SQLException e) {
|
||||||
|
log.info("数据库查询异常方法{},异常信息{}","com.suisung.mall.shop.sixun.dao.BaseDao.baseFindList",e.getMessage());
|
||||||
|
throw new RuntimeException(e);
|
||||||
|
}
|
||||||
|
resultDto.setResultSet(rs);
|
||||||
|
resultDto.setConnection(connection);
|
||||||
|
return resultDto;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 带分页数据
|
||||||
|
* @param ip
|
||||||
|
* @param username
|
||||||
|
* @param password
|
||||||
|
* @param dataBaseName
|
||||||
|
* @param table
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public ResultDto baseFindListPage(String ip, String username, String password, String dataBaseName, String table,String orderColumn, int pageNo, int pageSize){
|
||||||
|
Connection connection=getConnection(ip,username,password,dataBaseName);
|
||||||
|
int start=(pageNo-1)*pageSize+1;
|
||||||
|
int end=pageNo*pageSize;
|
||||||
|
String sql=" select * from( " +
|
||||||
|
" select ROW_NUMBER() OVER(ORDER BY %s) as rowId,* from %s " +
|
||||||
|
" ) as r where rowId between %s and %s";
|
||||||
|
sql=String.format(sql, orderColumn,table,start,end);
|
||||||
|
ResultDto resultDto=new ResultDto();
|
||||||
|
ResultSet rs=null;
|
||||||
|
try {
|
||||||
|
PreparedStatement ps= connection.prepareStatement(sql);
|
||||||
|
rs = ps.executeQuery();
|
||||||
|
} catch (SQLException e) {
|
||||||
|
log.info("数据库查询异常方法{},异常信息{}","com.suisung.mall.shop.sixun.dao.BaseDao.baseFindListPage",e.getMessage());
|
||||||
|
throw new RuntimeException(e);
|
||||||
|
}
|
||||||
|
resultDto.setResultSet(rs);
|
||||||
|
resultDto.setConnection(connection);
|
||||||
|
return resultDto;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Integer getBaseTotal(String ip, String username, String password, String dataBaseName, String table){
|
||||||
|
int total=0;
|
||||||
|
Connection connection=getConnection(ip,username,password,dataBaseName);
|
||||||
|
try {
|
||||||
|
String sql="select count(*) from %s where 1=1";
|
||||||
|
sql=String.format(sql, table);
|
||||||
|
PreparedStatement ps= connection.prepareStatement(sql);
|
||||||
|
ResultSet rs=ps.executeQuery();
|
||||||
|
while (rs.next()){
|
||||||
|
total=rs.getInt(1);
|
||||||
|
}
|
||||||
|
} catch (SQLException e) {
|
||||||
|
log.info("数据库查询异常方法{},异常信息{}","com.suisung.mall.shop.sixun.dao.BaseDao.getBaseTotal",e.getMessage());
|
||||||
|
throw new RuntimeException(e);
|
||||||
|
}
|
||||||
|
finally {
|
||||||
|
try {
|
||||||
|
connection.close();
|
||||||
|
} catch (SQLException e) {
|
||||||
|
throw new RuntimeException(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return total;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@ -0,0 +1,238 @@
|
|||||||
|
package com.suisung.mall.shop.sixun.dao;
|
||||||
|
|
||||||
|
import com.suisung.mall.common.modules.sixun.SxSyncCategory;
|
||||||
|
import com.suisung.mall.common.modules.sixun.SxSyncGoods;
|
||||||
|
import com.suisung.mall.common.modules.sixun.SxSyncVip;
|
||||||
|
import com.suisung.mall.shop.sixun.dto.DataBaseInfo;
|
||||||
|
import com.suisung.mall.shop.sixun.dto.ResultDto;
|
||||||
|
import com.suisung.mall.shop.sixun.dto.SxCategoryModel;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
|
import java.math.BigDecimal;
|
||||||
|
import java.math.RoundingMode;
|
||||||
|
import java.sql.*;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 考虑到每个思迅软件都是自己的数据,所以采用动态获取的方式获取数据
|
||||||
|
* 数据库为MS SQL
|
||||||
|
* todo 如果考虑到数据量需要分页多线程
|
||||||
|
*/
|
||||||
|
@Service
|
||||||
|
public class SxDataDao extends BaseDao{
|
||||||
|
|
||||||
|
private final static String T_BD_ITEM_CLS="t_bd_item_cls";//商品分类
|
||||||
|
private final static String T_BD_ITEM_INFO="t_bd_item_info";//商品表
|
||||||
|
private final static String RM_VIP_INFO="rm_vip_info";//会员表
|
||||||
|
|
||||||
|
private final static String ITEM_CLSNO="item_clsno";//商品分类排序字段
|
||||||
|
private final static String ITEM_NO="item_no";//商品排序字段
|
||||||
|
private final static String CARD_ID="card_id";//会员表排序字段
|
||||||
|
|
||||||
|
public final static Integer PAGESIZE=500;
|
||||||
|
|
||||||
|
public final static String DEFAULT_IMG="https://digitalassets.tesla.com/tesla-contents/image/upload/f_auto,q_auto/Homepage-Model-Y-2-Promo-Hero-Tablet-CN.png";
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 查找商品分类数据
|
||||||
|
* @param ip
|
||||||
|
* @param username
|
||||||
|
* @param password
|
||||||
|
* @param dataBaseName
|
||||||
|
*/
|
||||||
|
public void findTBdItemClsList(String ip,String username,String password,String dataBaseName){
|
||||||
|
ResultDto resultDto=baseFindList(ip,username,password,dataBaseName,T_BD_ITEM_CLS);
|
||||||
|
ResultSet rs= resultDto.getResultSet();
|
||||||
|
try {
|
||||||
|
while (rs.next()) {
|
||||||
|
System.out.printf(rs.getString("item_clsno"));//分类编码
|
||||||
|
System.out.printf(rs.getString("item_clsname")+"\t");//分类名称
|
||||||
|
System.out.print(rs.getString("cls_parent")+"\t");//父级编码
|
||||||
|
System.out.print(rs.getString("item_flag")+"\t" + "\n");//显示标识
|
||||||
|
}
|
||||||
|
} catch (SQLException e) {
|
||||||
|
throw new RuntimeException(e);
|
||||||
|
} finally {
|
||||||
|
try {
|
||||||
|
resultDto.getConnection().close();
|
||||||
|
} catch (SQLException e) {
|
||||||
|
throw new RuntimeException(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 分页查找商品分类数据
|
||||||
|
* @param dataBaseInfo
|
||||||
|
* @param pageNo
|
||||||
|
* @param pageSize
|
||||||
|
*/
|
||||||
|
public List<SxSyncCategory> findTBdItemClsListPage(DataBaseInfo dataBaseInfo, int pageNo, int pageSize){
|
||||||
|
ResultDto resultDto=baseFindListPage(dataBaseInfo.getIp(),dataBaseInfo.getUserName(),dataBaseInfo.getPassword(),dataBaseInfo.getDataBaseName(),T_BD_ITEM_CLS,ITEM_CLSNO,pageNo,pageSize);
|
||||||
|
ResultSet rs= resultDto.getResultSet();
|
||||||
|
List<SxSyncCategory> sxSyncCategories=new ArrayList<>();
|
||||||
|
SxSyncCategory sxSyncCategory=null;
|
||||||
|
try {
|
||||||
|
while (rs.next()) {
|
||||||
|
sxSyncCategory=new SxSyncCategory();
|
||||||
|
sxSyncCategory.setItem_clsname(rs.getString("item_clsname"));//分类名称
|
||||||
|
sxSyncCategory.setCls_parent(rs.getString("cls_parent"));//父级编码
|
||||||
|
sxSyncCategory.setItem_clsno(rs.getString("item_clsno"));//分类编码
|
||||||
|
// System.out.printf(rs.getString("item_clsno"));//分类编码
|
||||||
|
// System.out.printf(rs.getString("item_clsname")+"\t");//分类名称
|
||||||
|
// System.out.print(rs.getString("cls_parent")+"\t");//父级编码
|
||||||
|
// System.out.print(rs.getString("item_flag")+"\t" + "\n");//显示标识
|
||||||
|
sxSyncCategories.add(sxSyncCategory);
|
||||||
|
}
|
||||||
|
} catch (SQLException e) {
|
||||||
|
throw new RuntimeException(e);
|
||||||
|
} finally {
|
||||||
|
try {
|
||||||
|
resultDto.getConnection().close();
|
||||||
|
} catch (SQLException e) {
|
||||||
|
throw new RuntimeException(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return sxSyncCategories;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取商品分类TBdItemCls表的数量
|
||||||
|
* @param dataBaseInfo
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public Integer getTBdItemClsTotal(DataBaseInfo dataBaseInfo){
|
||||||
|
return getBaseTotal(dataBaseInfo.getIp(),dataBaseInfo.getUserName(),dataBaseInfo.getPassword(),dataBaseInfo.getDataBaseName(),T_BD_ITEM_CLS);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取商品表t_bd_item_info表的数量
|
||||||
|
* @param dataBaseInfo
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public int getTBditemInfoTotal(DataBaseInfo dataBaseInfo){
|
||||||
|
return getBaseTotal(dataBaseInfo.getIp(),dataBaseInfo.getUserName(),dataBaseInfo.getPassword(),dataBaseInfo.getDataBaseName(),ITEM_NO);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取会员表t_rm_vip_info表的数量
|
||||||
|
* @param dataBaseInfo
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public int getTrmVipInfoTotal(DataBaseInfo dataBaseInfo){
|
||||||
|
return getBaseTotal(dataBaseInfo.getIp(),dataBaseInfo.getUserName(),dataBaseInfo.getPassword(),dataBaseInfo.getDataBaseName(),CARD_ID);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 分页查找商品数据
|
||||||
|
* 表T_BD_ITEM_INFO
|
||||||
|
* @param dataBaseInfo
|
||||||
|
* @param pageNo
|
||||||
|
* @param pageSize
|
||||||
|
*/
|
||||||
|
public List<SxSyncGoods> findBditemInfoListPage(DataBaseInfo dataBaseInfo,int pageNo,int pageSize){
|
||||||
|
ResultDto resultDto=baseFindListPage(dataBaseInfo.getIp(),dataBaseInfo.getUserName(),dataBaseInfo.getPassword(),dataBaseInfo.getDataBaseName(),T_BD_ITEM_INFO,ITEM_CLSNO,pageNo,pageSize);
|
||||||
|
ResultSet rs= resultDto.getResultSet();
|
||||||
|
List<SxSyncGoods> sxSyncGoodses=new ArrayList<>();
|
||||||
|
SxSyncGoods sxSyncGoods=null;
|
||||||
|
try {
|
||||||
|
while (rs.next()) {
|
||||||
|
BigDecimal price=new BigDecimal(rs.getString("price"));
|
||||||
|
BigDecimal salePrice=new BigDecimal(rs.getString("sale_price"));
|
||||||
|
BigDecimal gross= salePrice.subtract(price).divide(salePrice,2, RoundingMode.HALF_UP);
|
||||||
|
sxSyncGoods=new SxSyncGoods();
|
||||||
|
sxSyncGoods.setItem_no(rs.getString("item_no"));//货号
|
||||||
|
sxSyncGoods.setItem_subname(rs.getString("item_subname"));//商品名称
|
||||||
|
sxSyncGoods.setItem_subno(rs.getString("item_subno"));//商品条码
|
||||||
|
sxSyncGoods.setBig_cls_name("9999");//商品大类 todo 如何关联
|
||||||
|
sxSyncGoods.setSmall_cls_name("9999");//商品小类 todo 如何关联
|
||||||
|
sxSyncGoods.setItem_size(rs.getString("item_size"));//规格
|
||||||
|
sxSyncGoods.setUnit_no(rs.getString("unit_no"));//单位 todo
|
||||||
|
sxSyncGoods.setStock(rs.getBigDecimal("item_flag"));//库存数量 todo item_stock?
|
||||||
|
|
||||||
|
|
||||||
|
sxSyncGoods.setGross_margin(gross);//毛利率 todo
|
||||||
|
sxSyncGoods.setPrice(rs.getBigDecimal("price"));//进货价
|
||||||
|
sxSyncGoods.setSale_price(rs.getBigDecimal("sale_price"));//零售价
|
||||||
|
|
||||||
|
sxSyncGoods.setVip_price(rs.getBigDecimal("vip_price"));//会员价
|
||||||
|
sxSyncGoods.setVip_acc_flag(rs.getBigDecimal("vip_acc_flag"));//允许积分
|
||||||
|
sxSyncGoods.setVip_acc_num(rs.getBigDecimal("vip_acc_num"));//积分值
|
||||||
|
sxSyncGoods.setSale_flag(rs.getInt("main_Sale_flag"));//商品状态 todo 是main_Sale_flag?
|
||||||
|
sxSyncGoods.setItem_rem(rs.getString("item_rem"));//助记码
|
||||||
|
sxSyncGoods.setBuild_date(rs.getString("build_date"));//生产日期
|
||||||
|
sxSyncGoods.setValid_days(rs.getString("item_flag"));//保质期 todo stop_date-build_date?
|
||||||
|
|
||||||
|
sxSyncGoodses.add(sxSyncGoods);
|
||||||
|
}
|
||||||
|
} catch (SQLException e) {
|
||||||
|
throw new RuntimeException(e);
|
||||||
|
} finally {
|
||||||
|
try {
|
||||||
|
resultDto.getConnection().close();
|
||||||
|
} catch (SQLException e) {
|
||||||
|
throw new RuntimeException(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return sxSyncGoodses;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 分页查找会员数据
|
||||||
|
* RM_VIP_INFO
|
||||||
|
* @param dataBaseInfo
|
||||||
|
* @param pageNo
|
||||||
|
* @param pageSize
|
||||||
|
*/
|
||||||
|
public List<SxSyncVip> findRmVipInfoListPage(DataBaseInfo dataBaseInfo, int pageNo, int pageSize){
|
||||||
|
ResultDto resultDto=baseFindListPage(dataBaseInfo.getIp(),dataBaseInfo.getUserName(),dataBaseInfo.getPassword(),dataBaseInfo.getDataBaseName(),RM_VIP_INFO,CARD_ID,pageNo,pageSize);
|
||||||
|
ResultSet rs= resultDto.getResultSet();
|
||||||
|
List<SxSyncVip> sxSyncVips=new ArrayList<>();
|
||||||
|
SxSyncVip sxSyncVip=null;
|
||||||
|
try {
|
||||||
|
while (rs.next()) {
|
||||||
|
sxSyncVip = new SxSyncVip();
|
||||||
|
int cardStatus=rs.getInt("card_status");
|
||||||
|
if(cardStatus!=1){
|
||||||
|
sxSyncVip.setVip_name(rs.getString("vip_name"));//会员名称
|
||||||
|
sxSyncVip.setVip_sex(rs.getString("vip_sex"));//会员名称
|
||||||
|
sxSyncVip.setMobile(rs.getString("mobile"));//会员名称
|
||||||
|
sxSyncVip.setBirthday(rs.getString("birthday"));//会员生日
|
||||||
|
sxSyncVip.setCard_type(rs.getString("card_type")==null?"v1":rs.getString("card_type"));//会员生日
|
||||||
|
sxSyncVip.setCard_no(rs.getString("card_no"));//会员卡号
|
||||||
|
sxSyncVip.setCard_no(rs.getString("now_acc_num"));//会员积分
|
||||||
|
sxSyncVip.setCard_no(rs.getString("residual_amt"));//储值余额
|
||||||
|
sxSyncVip.setCard_no(rs.getString("vip_start_date"));//建档日期
|
||||||
|
|
||||||
|
System.out.println(rs.getString("vip_name"));//会员名称
|
||||||
|
System.out.println(rs.getString("mobile"));//会员手机号
|
||||||
|
System.out.println(rs.getString("vip_sex"));//会员性别
|
||||||
|
System.out.println(rs.getString("birthday"));//会员生日
|
||||||
|
System.out.println(rs.getString("card_no"));//会员卡号
|
||||||
|
System.out.println(rs.getString("card_type"));//会员等级
|
||||||
|
System.out.println(rs.getBigDecimal("residual_amt"));//储值余额
|
||||||
|
System.out.println(rs.getBigDecimal("now_acc_num"));//会员积分
|
||||||
|
System.out.println(rs.getString("vip_start_date"));//建档日期
|
||||||
|
System.out.println(rs.getInt("card_status"));//会员状态
|
||||||
|
}
|
||||||
|
|
||||||
|
sxSyncVips.add(sxSyncVip);
|
||||||
|
}
|
||||||
|
}catch (SQLException e){
|
||||||
|
throw new RuntimeException(e);
|
||||||
|
}
|
||||||
|
return sxSyncVips;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public static void main(String[] args) {
|
||||||
|
//new SxDataUtils().findTBdItemClsList("127.0.0.1","sa","123456","hbposev9");
|
||||||
|
new SxDataDao().findTBdItemClsListPage(new DataBaseInfo(),4,10);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
@ -0,0 +1,16 @@
|
|||||||
|
package com.suisung.mall.shop.sixun.dto;
|
||||||
|
|
||||||
|
import io.swagger.annotations.ApiModelProperty;
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
@Data
|
||||||
|
public class DataBaseInfo {
|
||||||
|
@ApiModelProperty("数据库IP")
|
||||||
|
private String ip;
|
||||||
|
@ApiModelProperty("用户名")
|
||||||
|
private String userName;
|
||||||
|
@ApiModelProperty("密码")
|
||||||
|
private String password;
|
||||||
|
@ApiModelProperty("数据库名称")
|
||||||
|
private String dataBaseName;
|
||||||
|
}
|
||||||
@ -0,0 +1,17 @@
|
|||||||
|
package com.suisung.mall.shop.sixun.dto;
|
||||||
|
|
||||||
|
import io.swagger.annotations.ApiModelProperty;
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
@Data
|
||||||
|
public class ProductImage {
|
||||||
|
@ApiModelProperty("图片路径")
|
||||||
|
private String image_url;
|
||||||
|
@ApiModelProperty("推荐值")
|
||||||
|
private String seq;
|
||||||
|
@ApiModelProperty("介绍")
|
||||||
|
private String desc;
|
||||||
|
@ApiModelProperty("是否默认")
|
||||||
|
private String is_default;
|
||||||
|
|
||||||
|
}
|
||||||
@ -0,0 +1,17 @@
|
|||||||
|
package com.suisung.mall.shop.sixun.dto;
|
||||||
|
|
||||||
|
import io.swagger.annotations.ApiModelProperty;
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
@Data
|
||||||
|
public class PromotionDetail {
|
||||||
|
|
||||||
|
@ApiModelProperty("活动id")
|
||||||
|
private String activity_id;
|
||||||
|
@ApiModelProperty("活动名称")
|
||||||
|
private String activity_name;
|
||||||
|
@ApiModelProperty("价格")
|
||||||
|
private String price;
|
||||||
|
@ApiModelProperty("介绍")
|
||||||
|
private String intro;
|
||||||
|
}
|
||||||
@ -0,0 +1,15 @@
|
|||||||
|
package com.suisung.mall.shop.sixun.dto;
|
||||||
|
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
import java.sql.Connection;
|
||||||
|
import java.sql.ResultSet;
|
||||||
|
|
||||||
|
@Data
|
||||||
|
public class ResultDto {
|
||||||
|
|
||||||
|
private Connection connection;
|
||||||
|
|
||||||
|
private ResultSet resultSet;
|
||||||
|
|
||||||
|
}
|
||||||
@ -0,0 +1,34 @@
|
|||||||
|
package com.suisung.mall.shop.sixun.dto;
|
||||||
|
|
||||||
|
import io.swagger.annotations.ApiModelProperty;
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
import javax.validation.constraints.NotEmpty;
|
||||||
|
import java.math.BigDecimal;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 模型对应
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
public class SxCategoryModel {
|
||||||
|
//模型对应ShopBaseProductCategory start
|
||||||
|
private String parent_name;//暂时不用
|
||||||
|
@NotEmpty
|
||||||
|
@ApiModelProperty(value = "商品分类名称")
|
||||||
|
private String category_name;
|
||||||
|
@ApiModelProperty(value = "分类图片")
|
||||||
|
private String category_image;
|
||||||
|
@ApiModelProperty(value = "是否允许虚拟商品(ENUM):1-是; 0-否")
|
||||||
|
private Integer category_virtual_enable;
|
||||||
|
@ApiModelProperty(value = "分佣比例-百分比")
|
||||||
|
private BigDecimal category_commission_rate;
|
||||||
|
// private String type_name;//todo 看代码没有用,使用的是product_type
|
||||||
|
//模型对应ShopBaseProductCategory end
|
||||||
|
@ApiModelProperty(value = "产品类型")
|
||||||
|
private String product_type;
|
||||||
|
@ApiModelProperty(value = "第一级父类")
|
||||||
|
private String first_category_name;
|
||||||
|
@ApiModelProperty(value = "第二级父类")
|
||||||
|
private String second_category_name;
|
||||||
|
|
||||||
|
}
|
||||||
@ -0,0 +1,103 @@
|
|||||||
|
package com.suisung.mall.shop.sixun.dto;
|
||||||
|
|
||||||
|
import io.swagger.annotations.ApiModelProperty;
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
import java.math.BigDecimal;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 思迅同步商品数据入口数据
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
public class SxGoosModel {
|
||||||
|
|
||||||
|
@ApiModelProperty("商品名称")
|
||||||
|
private String product_name;
|
||||||
|
|
||||||
|
@ApiModelProperty("商品货号")
|
||||||
|
private String product_number;
|
||||||
|
|
||||||
|
@ApiModelProperty("商品条形码")
|
||||||
|
private String product_barcode;
|
||||||
|
|
||||||
|
@ApiModelProperty("一级分类")
|
||||||
|
private String first_category_name;
|
||||||
|
|
||||||
|
@ApiModelProperty("二级分类")
|
||||||
|
private String second_category_name;
|
||||||
|
|
||||||
|
@ApiModelProperty("三级分类")
|
||||||
|
private String three_category_name;
|
||||||
|
|
||||||
|
@ApiModelProperty("产品类型")
|
||||||
|
private String product_type;
|
||||||
|
|
||||||
|
@ApiModelProperty("商品种类")
|
||||||
|
private String product_kind;
|
||||||
|
|
||||||
|
@ApiModelProperty("成本价")
|
||||||
|
private BigDecimal cost_price;
|
||||||
|
|
||||||
|
@ApiModelProperty("价格")
|
||||||
|
private BigDecimal price;
|
||||||
|
|
||||||
|
@ApiModelProperty("原价")
|
||||||
|
private BigDecimal original_price;
|
||||||
|
|
||||||
|
@ApiModelProperty("商品价格")
|
||||||
|
private BigDecimal retail_price;
|
||||||
|
|
||||||
|
@ApiModelProperty("会员价")
|
||||||
|
private BigDecimal member_price;
|
||||||
|
|
||||||
|
@ApiModelProperty("库存")
|
||||||
|
private BigDecimal stock;
|
||||||
|
|
||||||
|
@ApiModelProperty("")
|
||||||
|
private BigDecimal gross_margin;
|
||||||
|
|
||||||
|
@ApiModelProperty("规格单位")
|
||||||
|
private String unit;
|
||||||
|
|
||||||
|
@ApiModelProperty("可用积分")
|
||||||
|
private BigDecimal can_piont;
|
||||||
|
|
||||||
|
@ApiModelProperty("总积分")
|
||||||
|
private BigDecimal points;
|
||||||
|
|
||||||
|
@ApiModelProperty("助记码")
|
||||||
|
private String mnemonic;
|
||||||
|
|
||||||
|
|
||||||
|
@ApiModelProperty("最大购买商品量")
|
||||||
|
private Integer buy_limit;
|
||||||
|
|
||||||
|
@ApiModelProperty("品牌名称")
|
||||||
|
private String brand_name;
|
||||||
|
|
||||||
|
@ApiModelProperty("标签")
|
||||||
|
private String tags;
|
||||||
|
|
||||||
|
@ApiModelProperty("辅助属性")
|
||||||
|
private List<String> product_assist;
|
||||||
|
|
||||||
|
@ApiModelProperty("规格(JSON)-规格、规格值、goods_id 规格不需要全选就可以添加对应数据[")
|
||||||
|
private List<String> product_spec;
|
||||||
|
|
||||||
|
@ApiModelProperty("商品卖点特征")
|
||||||
|
private String product_value;
|
||||||
|
|
||||||
|
@ApiModelProperty("商品视频")
|
||||||
|
private String product_video;
|
||||||
|
|
||||||
|
@ApiModelProperty("产品描述")
|
||||||
|
private String product_desc;
|
||||||
|
|
||||||
|
@ApiModelProperty("商品图片库")
|
||||||
|
private List<ProductImage> product_images;
|
||||||
|
|
||||||
|
|
||||||
|
@ApiModelProperty("商品详情")
|
||||||
|
private List<PromotionDetail> promotion_detail;
|
||||||
|
}
|
||||||
@ -11,6 +11,8 @@ package com.suisung.mall.shop.sixun.service;
|
|||||||
import com.baomidou.mybatisplus.core.metadata.IPage;
|
import com.baomidou.mybatisplus.core.metadata.IPage;
|
||||||
import com.suisung.mall.common.api.CommonResult;
|
import com.suisung.mall.common.api.CommonResult;
|
||||||
import com.suisung.mall.common.modules.sixun.SxSyncCategory;
|
import com.suisung.mall.common.modules.sixun.SxSyncCategory;
|
||||||
|
import com.suisung.mall.shop.sixun.dto.DataBaseInfo;
|
||||||
|
import com.suisung.mall.shop.sixun.dto.SxCategoryModel;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
@ -82,4 +84,22 @@ public interface SxSyncCategoryService {
|
|||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
Boolean updateStatusBatch(List<Long> list, Integer status);
|
Boolean updateStatusBatch(List<Long> list, Integer status);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 通过数据库获取店铺的商品分类
|
||||||
|
*
|
||||||
|
* @param dataBaseInfo
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
List<SxCategoryModel> getCategoryByDataBasePage( DataBaseInfo dataBaseInfo,int startPage,int pageSize);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 通过数据库获取店铺的商品分类总数
|
||||||
|
* @param dataBaseInfo
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
Integer getCategoryTotal( DataBaseInfo dataBaseInfo);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -11,6 +11,7 @@ package com.suisung.mall.shop.sixun.service;
|
|||||||
import com.baomidou.mybatisplus.core.metadata.IPage;
|
import com.baomidou.mybatisplus.core.metadata.IPage;
|
||||||
import com.suisung.mall.common.api.CommonResult;
|
import com.suisung.mall.common.api.CommonResult;
|
||||||
import com.suisung.mall.common.modules.sixun.SxSyncGoods;
|
import com.suisung.mall.common.modules.sixun.SxSyncGoods;
|
||||||
|
import com.suisung.mall.shop.sixun.dto.DataBaseInfo;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
@ -75,4 +76,20 @@ public interface SxSyncGoodsService {
|
|||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
IPage<SxSyncGoods> pageByStoreId(String storeId, Integer status, Integer pageNum, Integer pageSize);
|
IPage<SxSyncGoods> pageByStoreId(String storeId, Integer status, Integer pageNum, Integer pageSize);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 通过思迅数据库获取店铺的商品总数
|
||||||
|
* @param dataBaseInfo
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
Integer getGoodsTotal(DataBaseInfo dataBaseInfo);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 通过思迅数据库分页查找店铺的商品信息
|
||||||
|
* @param dataBaseInfo
|
||||||
|
* @param pageNum
|
||||||
|
* @param pageSize
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
List<SxSyncGoods> findGoodsListPage(DataBaseInfo dataBaseInfo,int pageNum,int pageSize);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -10,6 +10,7 @@ package com.suisung.mall.shop.sixun.service;
|
|||||||
|
|
||||||
import com.suisung.mall.common.api.CommonResult;
|
import com.suisung.mall.common.api.CommonResult;
|
||||||
import com.suisung.mall.common.modules.sixun.SxSyncVip;
|
import com.suisung.mall.common.modules.sixun.SxSyncVip;
|
||||||
|
import com.suisung.mall.shop.sixun.dto.DataBaseInfo;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
@ -57,4 +58,18 @@ public interface SxSyncVipService {
|
|||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
SxSyncVip getByVipNo(String storeId, String vipNo);
|
SxSyncVip getByVipNo(String storeId, String vipNo);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 通过数据库获取会员总数
|
||||||
|
* @param dataBaseInfo
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
Integer getVipMembersTotal( DataBaseInfo dataBaseInfo);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 分页通过数据库获取会员数据
|
||||||
|
* @param dataBaseInfo
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
List<SxSyncVip> findVipMemberPage( DataBaseInfo dataBaseInfo,int pageNum,int pageSize);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -9,7 +9,9 @@
|
|||||||
package com.suisung.mall.shop.sixun.service.impl;
|
package com.suisung.mall.shop.sixun.service.impl;
|
||||||
|
|
||||||
import cn.hutool.core.collection.CollUtil;
|
import cn.hutool.core.collection.CollUtil;
|
||||||
|
import cn.hutool.core.collection.CollectionUtil;
|
||||||
import cn.hutool.core.convert.Convert;
|
import cn.hutool.core.convert.Convert;
|
||||||
|
import cn.hutool.core.util.ObjectUtil;
|
||||||
import cn.hutool.json.JSONObject;
|
import cn.hutool.json.JSONObject;
|
||||||
import cn.hutool.json.JSONUtil;
|
import cn.hutool.json.JSONUtil;
|
||||||
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
|
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
|
||||||
@ -20,17 +22,23 @@ import com.suisung.mall.common.api.CommonResult;
|
|||||||
import com.suisung.mall.common.constant.CommonConstant;
|
import com.suisung.mall.common.constant.CommonConstant;
|
||||||
import com.suisung.mall.common.modules.sixun.SxSyncCategory;
|
import com.suisung.mall.common.modules.sixun.SxSyncCategory;
|
||||||
import com.suisung.mall.core.web.service.impl.BaseServiceImpl;
|
import com.suisung.mall.core.web.service.impl.BaseServiceImpl;
|
||||||
|
import com.suisung.mall.shop.sixun.dao.SxDataDao;
|
||||||
|
import com.suisung.mall.shop.sixun.dto.DataBaseInfo;
|
||||||
|
import com.suisung.mall.shop.sixun.dto.SxCategoryModel;
|
||||||
import com.suisung.mall.shop.sixun.mapper.SxSyncCategoryMapper;
|
import com.suisung.mall.shop.sixun.mapper.SxSyncCategoryMapper;
|
||||||
import com.suisung.mall.shop.sixun.service.SxSyncCategoryService;
|
import com.suisung.mall.shop.sixun.service.SxSyncCategoryService;
|
||||||
import com.suisung.mall.shop.sixun.utils.CommonUtil;
|
import com.suisung.mall.shop.sixun.utils.CommonUtil;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
import java.util.Date;
|
import javax.annotation.Resource;
|
||||||
import java.util.List;
|
import java.util.*;
|
||||||
import java.util.Objects;
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
@Service
|
@Service
|
||||||
public class SxSyncCategoryServiceImpl extends BaseServiceImpl<SxSyncCategoryMapper, SxSyncCategory> implements SxSyncCategoryService {
|
public class SxSyncCategoryServiceImpl extends BaseServiceImpl<SxSyncCategoryMapper, SxSyncCategory> implements SxSyncCategoryService {
|
||||||
|
@Resource
|
||||||
|
private SxDataDao sxDataDao;
|
||||||
/**
|
/**
|
||||||
* 同步店铺的商品分类
|
* 同步店铺的商品分类
|
||||||
*
|
*
|
||||||
@ -238,4 +246,74 @@ public class SxSyncCategoryServiceImpl extends BaseServiceImpl<SxSyncCategoryMap
|
|||||||
|
|
||||||
|
|
||||||
// ########### 从思迅商锐9.7系统获取数据区域 结束
|
// ########### 从思迅商锐9.7系统获取数据区域 结束
|
||||||
|
|
||||||
|
// ########### 从思迅数据库获取数据区域 start
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @param dataBaseInfo
|
||||||
|
* @param startPage
|
||||||
|
* @param pageSize
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public List<SxCategoryModel> getCategoryByDataBasePage(DataBaseInfo dataBaseInfo,int startPage,int pageSize) {
|
||||||
|
List<SxSyncCategory> sxSyncCategories=sxDataDao.findTBdItemClsListPage(dataBaseInfo,startPage, pageSize);
|
||||||
|
if(CollectionUtil.isEmpty(sxSyncCategories)){
|
||||||
|
return new ArrayList<>();
|
||||||
|
}
|
||||||
|
List<SxSyncCategory> sxSyncCategoriesCp = new ArrayList<>(sxSyncCategories);
|
||||||
|
Iterator<SxSyncCategory> iterator= sxSyncCategories.iterator();
|
||||||
|
List<SxCategoryModel> sxCategoryModels=new ArrayList<>();
|
||||||
|
SxCategoryModel sxCategoryModel=null;
|
||||||
|
while (iterator.hasNext()){
|
||||||
|
SxSyncCategory sxSyncCategory= iterator.next();
|
||||||
|
sxCategoryModel=new SxCategoryModel();
|
||||||
|
sxCategoryModel.setCategory_image(SxDataDao.DEFAULT_IMG);
|
||||||
|
sxCategoryModel.setCategory_name(sxSyncCategory.getItem_clsname());
|
||||||
|
//寻找父级
|
||||||
|
if(null!=sxSyncCategory.getCls_parent()){
|
||||||
|
SxSyncCategory firstNode=getParentNode(sxSyncCategoriesCp,sxSyncCategory.getCls_parent());
|
||||||
|
sxCategoryModel.setParent_name(firstNode.getItem_clsname());//todo 暂时无用
|
||||||
|
//如何存在上级的上级,则上级为第二层,上上及为第一层
|
||||||
|
if(null!=firstNode.getCls_parent()) {//还存在上级
|
||||||
|
SxSyncCategory secondNode=getParentNode(sxSyncCategoriesCp,sxSyncCategory.getCls_parent());
|
||||||
|
sxCategoryModel.setFirst_category_name(secondNode.getItem_clsname());
|
||||||
|
sxCategoryModel.setSecond_category_name(firstNode.getItem_clsname());
|
||||||
|
}else {
|
||||||
|
sxCategoryModel.setFirst_category_name(firstNode.getItem_clsname());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
sxCategoryModels.add(sxCategoryModel);
|
||||||
|
}
|
||||||
|
return sxCategoryModels;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 通过流查找父节点
|
||||||
|
* @param sxSyncCategories
|
||||||
|
* @param parentId
|
||||||
|
*/
|
||||||
|
private SxSyncCategory getParentNode(List<SxSyncCategory> sxSyncCategories,String parentId){
|
||||||
|
List<SxSyncCategory> list= sxSyncCategories.stream().filter(cc->
|
||||||
|
cc.getItem_clsno().trim().equals(parentId.trim()))
|
||||||
|
.collect(Collectors.toList());
|
||||||
|
return CollectionUtil.isNotEmpty(list)?list.get(0):new SxSyncCategory();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Integer getCategoryTotal(DataBaseInfo dataBaseInfo) {
|
||||||
|
// 记录总数
|
||||||
|
return sxDataDao.getTBdItemClsTotal(dataBaseInfo);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public static void main(String[] args) {
|
||||||
|
List<SxCategoryModel> list= new SxSyncCategoryServiceImpl().getCategoryByDataBasePage(new DataBaseInfo(),1,50);
|
||||||
|
list.forEach(e->{
|
||||||
|
System.out.println("node"+e.getCategory_name()+"--First_category_name--"+e.getFirst_category_name()+"--Second_category_name--"+e.getSecond_category_name());
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
//########### 从思迅数据库获取数据区域 end
|
||||||
}
|
}
|
||||||
|
|||||||
@ -20,18 +20,22 @@ import com.suisung.mall.common.api.CommonResult;
|
|||||||
import com.suisung.mall.common.constant.CommonConstant;
|
import com.suisung.mall.common.constant.CommonConstant;
|
||||||
import com.suisung.mall.common.modules.sixun.SxSyncGoods;
|
import com.suisung.mall.common.modules.sixun.SxSyncGoods;
|
||||||
import com.suisung.mall.core.web.service.impl.BaseServiceImpl;
|
import com.suisung.mall.core.web.service.impl.BaseServiceImpl;
|
||||||
|
import com.suisung.mall.shop.sixun.dao.SxDataDao;
|
||||||
|
import com.suisung.mall.shop.sixun.dto.DataBaseInfo;
|
||||||
import com.suisung.mall.shop.sixun.mapper.SxSyncGoodsMapper;
|
import com.suisung.mall.shop.sixun.mapper.SxSyncGoodsMapper;
|
||||||
import com.suisung.mall.shop.sixun.service.SxSyncGoodsService;
|
import com.suisung.mall.shop.sixun.service.SxSyncGoodsService;
|
||||||
import com.suisung.mall.shop.sixun.utils.CommonUtil;
|
import com.suisung.mall.shop.sixun.utils.CommonUtil;
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
|
import javax.annotation.Resource;
|
||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
|
|
||||||
@Service
|
@Service
|
||||||
public class SxSyncGoodsServiceImpl extends BaseServiceImpl<SxSyncGoodsMapper, SxSyncGoods> implements SxSyncGoodsService {
|
public class SxSyncGoodsServiceImpl extends BaseServiceImpl<SxSyncGoodsMapper, SxSyncGoods> implements SxSyncGoodsService {
|
||||||
|
@Resource
|
||||||
|
private SxDataDao sxDataDao;
|
||||||
/**
|
/**
|
||||||
* 同步记录
|
* 同步记录
|
||||||
*
|
*
|
||||||
@ -185,7 +189,6 @@ public class SxSyncGoodsServiceImpl extends BaseServiceImpl<SxSyncGoodsMapper, S
|
|||||||
return baseMapper.selectPage(new Page<>(pageNum, pageSize), queryWrapper);
|
return baseMapper.selectPage(new Page<>(pageNum, pageSize), queryWrapper);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// ########### 从思迅商锐9.7系统获取数据区域 开始
|
// ########### 从思迅商锐9.7系统获取数据区域 开始
|
||||||
|
|
||||||
public List<SxSyncGoods> pageGoodsListFromSiXun(Integer pageNo, Integer pageSize) {
|
public List<SxSyncGoods> pageGoodsListFromSiXun(Integer pageNo, Integer pageSize) {
|
||||||
@ -223,5 +226,12 @@ public class SxSyncGoodsServiceImpl extends BaseServiceImpl<SxSyncGoodsMapper, S
|
|||||||
}
|
}
|
||||||
|
|
||||||
// ########### 从思迅商锐9.7系统获取数据区域 结束
|
// ########### 从思迅商锐9.7系统获取数据区域 结束
|
||||||
|
@Override
|
||||||
|
public Integer getGoodsTotal(DataBaseInfo dataBaseInfo) {
|
||||||
|
return sxDataDao.getTBditemInfoTotal(dataBaseInfo);
|
||||||
|
}
|
||||||
|
@Override
|
||||||
|
public List<SxSyncGoods> findGoodsListPage(DataBaseInfo dataBaseInfo, int pageNum, int pageSize) {
|
||||||
|
return sxDataDao.findBditemInfoListPage(dataBaseInfo,pageNum,pageSize);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -18,18 +18,22 @@ import com.suisung.mall.common.api.CommonResult;
|
|||||||
import com.suisung.mall.common.constant.CommonConstant;
|
import com.suisung.mall.common.constant.CommonConstant;
|
||||||
import com.suisung.mall.common.modules.sixun.SxSyncVip;
|
import com.suisung.mall.common.modules.sixun.SxSyncVip;
|
||||||
import com.suisung.mall.core.web.service.impl.BaseServiceImpl;
|
import com.suisung.mall.core.web.service.impl.BaseServiceImpl;
|
||||||
|
import com.suisung.mall.shop.sixun.dao.SxDataDao;
|
||||||
|
import com.suisung.mall.shop.sixun.dto.DataBaseInfo;
|
||||||
import com.suisung.mall.shop.sixun.mapper.SxSyncVipMapper;
|
import com.suisung.mall.shop.sixun.mapper.SxSyncVipMapper;
|
||||||
import com.suisung.mall.shop.sixun.service.SxSyncVipService;
|
import com.suisung.mall.shop.sixun.service.SxSyncVipService;
|
||||||
import com.suisung.mall.shop.sixun.utils.CommonUtil;
|
import com.suisung.mall.shop.sixun.utils.CommonUtil;
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
|
import javax.annotation.Resource;
|
||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
|
|
||||||
@Service
|
@Service
|
||||||
public class SxSyncVipServiceImpl extends BaseServiceImpl<SxSyncVipMapper, SxSyncVip> implements SxSyncVipService {
|
public class SxSyncVipServiceImpl extends BaseServiceImpl<SxSyncVipMapper, SxSyncVip> implements SxSyncVipService {
|
||||||
|
@Resource
|
||||||
|
private SxDataDao sxDataDao;
|
||||||
/**
|
/**
|
||||||
* 同步店铺的
|
* 同步店铺的
|
||||||
*
|
*
|
||||||
@ -188,4 +192,14 @@ public class SxSyncVipServiceImpl extends BaseServiceImpl<SxSyncVipMapper, SxSyn
|
|||||||
|
|
||||||
// ########### 从思迅商锐9.7系统获取数据区域 结束
|
// ########### 从思迅商锐9.7系统获取数据区域 结束
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Integer getVipMembersTotal(DataBaseInfo dataBaseInfo) {
|
||||||
|
return sxDataDao.getTrmVipInfoTotal(dataBaseInfo);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<SxSyncVip> findVipMemberPage(DataBaseInfo dataBaseInfo,int pageNum,int pageSize) {
|
||||||
|
return sxDataDao.findRmVipInfoListPage(dataBaseInfo,pageNum,pageSize);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -0,0 +1,65 @@
|
|||||||
|
package com.suisung.mall.shop.sixun.utils;
|
||||||
|
|
||||||
|
import org.springframework.beans.factory.annotation.Value;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.util.Calendar;
|
||||||
|
|
||||||
|
@Component
|
||||||
|
public class FileUtils {
|
||||||
|
public static final String pathSeparator = System.getProperty("file.separator");
|
||||||
|
public static final String GOODS = "goods"+pathSeparator;//商品
|
||||||
|
public static final String CATEGORY= "category"+pathSeparator;//分类
|
||||||
|
public static final String BRAND = "brand"+pathSeparator;//品牌
|
||||||
|
public static final String MEMBER= "member"+pathSeparator;//会员
|
||||||
|
|
||||||
|
public String getSyncTypeFlag(String syncType,String path){
|
||||||
|
Calendar calendar=Calendar.getInstance();
|
||||||
|
int year=calendar.get(Calendar.YEAR);
|
||||||
|
int month=calendar.get(Calendar.MONTH)+1;
|
||||||
|
int date=calendar.get(Calendar.DAY_OF_MONTH);
|
||||||
|
String result = path+pathSeparator+"uploaded"+pathSeparator;
|
||||||
|
switch (syncType){
|
||||||
|
case "1":
|
||||||
|
result+=GOODS;
|
||||||
|
break;
|
||||||
|
case "2":
|
||||||
|
result+=CATEGORY;
|
||||||
|
break;
|
||||||
|
case "3":
|
||||||
|
result+=BRAND;
|
||||||
|
break;
|
||||||
|
case "4":
|
||||||
|
result+=MEMBER;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return result+year+pathSeparator+month+pathSeparator+date+pathSeparator;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 创建文件
|
||||||
|
* @param folderPath
|
||||||
|
* @param fileName
|
||||||
|
*/
|
||||||
|
public static String createFolderAndFileUsingFile(String folderPath, String fileName) {
|
||||||
|
String filePath = folderPath + fileName;
|
||||||
|
File folder = new File(folderPath);
|
||||||
|
if (!folder.exists()) {
|
||||||
|
folder.mkdirs();
|
||||||
|
}
|
||||||
|
|
||||||
|
File file = new File(filePath);
|
||||||
|
try {
|
||||||
|
if (!file.exists()) {
|
||||||
|
file.createNewFile();
|
||||||
|
}
|
||||||
|
} catch (IOException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
return filePath;
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,91 @@
|
|||||||
|
package com.suisung.mall.shop.sync.Utils;
|
||||||
|
|
||||||
|
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||||
|
import com.suisung.mall.common.modules.product.ShopProductBase;
|
||||||
|
import com.suisung.mall.shop.product.mapper.ShopProductBaseMapper;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.apache.ibatis.session.ExecutorType;
|
||||||
|
import org.apache.ibatis.session.SqlSession;
|
||||||
|
import org.apache.ibatis.session.SqlSessionFactory;
|
||||||
|
import org.mybatis.spring.SqlSessionUtils;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
import org.springframework.util.CollectionUtils;
|
||||||
|
|
||||||
|
import java.lang.reflect.Method;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
@Component
|
||||||
|
@Slf4j
|
||||||
|
public class BatchInsertUtils {
|
||||||
|
private static final int DEFAULT_BATCH_SIZE = 1000;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private SqlSessionFactory sqlSessionFactory;
|
||||||
|
/**
|
||||||
|
* 高性能批量插入
|
||||||
|
*/
|
||||||
|
public static <T> boolean batchInsert(Class<T> mapperClass, List<T> dataList, SqlSessionFactory sqlSessionFactory) {
|
||||||
|
return batchInsert(mapperClass, dataList, DEFAULT_BATCH_SIZE,sqlSessionFactory);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static <T> boolean batchInsert(Class<T> mapperClass, List<T> dataList, int batchSize, SqlSessionFactory sqlSessionFactory) {
|
||||||
|
if (CollectionUtils.isEmpty(dataList)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
try (SqlSession sqlSession = SqlSessionUtils.getSqlSession(
|
||||||
|
sqlSessionFactory,
|
||||||
|
ExecutorType.BATCH,
|
||||||
|
null)) {
|
||||||
|
|
||||||
|
BaseMapper<T> mapper = (BaseMapper<T>) sqlSession.getMapper(mapperClass);
|
||||||
|
int size = dataList.size();
|
||||||
|
|
||||||
|
for (int i = 0; i < size; i++) {
|
||||||
|
mapper.insert(dataList.get(i));
|
||||||
|
// 分批提交
|
||||||
|
if (i > 0 && i % batchSize == 0 || i == size - 1) {
|
||||||
|
sqlSession.flushStatements();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.error("批量插入失败", e);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 使用VALUES列表批量插入
|
||||||
|
*/
|
||||||
|
public static <T> boolean batchInsertWithValues(Class<? extends BaseMapper<T>> mapperClass,
|
||||||
|
String methodName,
|
||||||
|
List<T> dataList,SqlSessionFactory sqlSessionFactory) {
|
||||||
|
if (CollectionUtils.isEmpty(dataList)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
try (SqlSession sqlSession = sqlSessionFactory.openSession(ExecutorType.BATCH)) {
|
||||||
|
BaseMapper<T> mapper = sqlSession.getMapper(mapperClass);
|
||||||
|
Method method = mapper.getClass().getMethod(methodName, List.class);
|
||||||
|
|
||||||
|
int total = dataList.size();
|
||||||
|
int batchCount = (total + DEFAULT_BATCH_SIZE - 1) / DEFAULT_BATCH_SIZE;
|
||||||
|
|
||||||
|
for (int i = 0; i < batchCount; i++) {
|
||||||
|
int from = i * DEFAULT_BATCH_SIZE;
|
||||||
|
int to = Math.min(from + DEFAULT_BATCH_SIZE, total);
|
||||||
|
List<T> subList = dataList.subList(from, to);
|
||||||
|
|
||||||
|
method.invoke(mapper, subList);
|
||||||
|
sqlSession.flushStatements();
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.error("批量插入失败", e);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@ -0,0 +1,117 @@
|
|||||||
|
package com.suisung.mall.shop.sync.Utils;
|
||||||
|
|
||||||
|
import javax.crypto.Cipher;
|
||||||
|
import javax.crypto.spec.SecretKeySpec;
|
||||||
|
import java.io.UnsupportedEncodingException;
|
||||||
|
import java.nio.charset.StandardCharsets;
|
||||||
|
import java.security.MessageDigest;
|
||||||
|
import java.security.NoSuchAlgorithmException;
|
||||||
|
import java.util.Base64;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
public class CryptoUtils {
|
||||||
|
private static final String ALGORITHM = "AES";
|
||||||
|
private static final String TRANSFORMATION = "AES/ECB/PKCS5Padding";
|
||||||
|
private static final String SECRET_KEY = "9f823ea6ab22785caf040e4cc3930619"; // 必须16/24/32字符
|
||||||
|
|
||||||
|
private static final String HASH_ALGORITHM_KEY = "appKey=a&sign=b&storeId=c";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 打包并加密字段
|
||||||
|
*/
|
||||||
|
public static String packAndEncrypt(String appKey, String sign, String storeId) throws Exception {
|
||||||
|
String combined = String.format("appKey=%s&sign=%s&storeId=%s", appKey, sign, storeId);
|
||||||
|
return encrypt(combined);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 32位字符串生成
|
||||||
|
* @param input
|
||||||
|
* @return
|
||||||
|
* @throws NoSuchAlgorithmException
|
||||||
|
*/
|
||||||
|
public static String generate32CharMD5(String input) throws NoSuchAlgorithmException {
|
||||||
|
MessageDigest md = MessageDigest.getInstance("MD5");
|
||||||
|
byte[] hashBytes = md.digest(input.getBytes());
|
||||||
|
|
||||||
|
StringBuilder hexString = new StringBuilder();
|
||||||
|
for (byte b : hashBytes) {
|
||||||
|
String hex = Integer.toHexString(0xff & b);
|
||||||
|
if (hex.length() == 1) {
|
||||||
|
hexString.append('0');
|
||||||
|
}
|
||||||
|
hexString.append(hex);
|
||||||
|
}
|
||||||
|
|
||||||
|
return hexString.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 解密并解包字段
|
||||||
|
*/
|
||||||
|
public static Map<String, String> decryptAndUnpack(String encryptedData) throws Exception {
|
||||||
|
String decrypted = decrypt(encryptedData);
|
||||||
|
Map<String, String> result = new HashMap<>();
|
||||||
|
String[] pairs = decrypted.split("&");
|
||||||
|
for (String pair : pairs) {
|
||||||
|
String[] keyValue = pair.split("=");
|
||||||
|
if (keyValue.length == 2) {
|
||||||
|
result.put(keyValue[0], keyValue[1]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 加密
|
||||||
|
* @param value
|
||||||
|
* @return
|
||||||
|
* @throws Exception
|
||||||
|
*/
|
||||||
|
private static String encrypt(String value) throws Exception {
|
||||||
|
SecretKeySpec secretKey = new SecretKeySpec(SECRET_KEY.getBytes(StandardCharsets.UTF_8), ALGORITHM);
|
||||||
|
Cipher cipher = Cipher.getInstance(TRANSFORMATION);
|
||||||
|
cipher.init(Cipher.ENCRYPT_MODE, secretKey);
|
||||||
|
byte[] encryptedBytes = cipher.doFinal(value.getBytes(StandardCharsets.UTF_8));
|
||||||
|
return Base64.getEncoder().encodeToString(encryptedBytes);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 解密
|
||||||
|
* @param encryptedValue
|
||||||
|
* @return
|
||||||
|
* @throws Exception
|
||||||
|
*/
|
||||||
|
private static String decrypt(String encryptedValue) throws Exception {
|
||||||
|
SecretKeySpec secretKey = new SecretKeySpec(SECRET_KEY.getBytes(StandardCharsets.UTF_8), ALGORITHM);
|
||||||
|
Cipher cipher = Cipher.getInstance(TRANSFORMATION);
|
||||||
|
cipher.init(Cipher.DECRYPT_MODE, secretKey);
|
||||||
|
byte[] decodedBytes = Base64.getDecoder().decode(encryptedValue);
|
||||||
|
byte[] decryptedBytes = cipher.doFinal(decodedBytes);
|
||||||
|
return new String(decryptedBytes, StandardCharsets.UTF_8);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String dealBlankStr(String original) throws UnsupportedEncodingException {
|
||||||
|
return original.replaceAll(" ", "+");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// 示例用法
|
||||||
|
public static void main(String[] args) throws Exception {
|
||||||
|
|
||||||
|
String appKey = "d68397c4fb671bc024e24e1964b067cc35388818";
|
||||||
|
String sign = "d68397c4fb671bc024e24e1964b067cc35388818";
|
||||||
|
String storeId = "1";
|
||||||
|
|
||||||
|
// 打包加密
|
||||||
|
String encrypted = packAndEncrypt(appKey, sign, storeId);
|
||||||
|
System.out.println("加密结果: " + encrypted);
|
||||||
|
|
||||||
|
// 解密解包
|
||||||
|
Map<String, String> result = decryptAndUnpack(encrypted);
|
||||||
|
System.out.println("解密结果: " + result);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
@ -0,0 +1,37 @@
|
|||||||
|
package com.suisung.mall.shop.sync.Utils;
|
||||||
|
|
||||||
|
import cn.hutool.json.JSONArray;
|
||||||
|
import cn.hutool.json.JSONUtil;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.nio.charset.StandardCharsets;
|
||||||
|
import java.nio.file.Files;
|
||||||
|
import java.rmi.RemoteException;
|
||||||
|
|
||||||
|
@lombok.extern.slf4j.Slf4j
|
||||||
|
public class ThreadFileUtils {
|
||||||
|
|
||||||
|
public JSONArray processFolder(String taskName, String folderPath) throws RuntimeException {
|
||||||
|
File folder = new File(folderPath);
|
||||||
|
if (!folder.exists() || !folder.isDirectory()) {
|
||||||
|
throw new RuntimeException("文件夹不存在或不是目录: " + folderPath);
|
||||||
|
}
|
||||||
|
|
||||||
|
File[] jsonFiles = folder.listFiles((dir, name) -> name.endsWith(".txt"));
|
||||||
|
if (jsonFiles == null || jsonFiles.length == 0) {
|
||||||
|
log.info("[{}]文件夹中没有JSON文件: {}",taskName,folderPath);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
File jsonFile=jsonFiles[0];
|
||||||
|
JSONArray jsonArray =null;
|
||||||
|
try {
|
||||||
|
String content = new String(Files.readAllBytes(jsonFile.toPath()), StandardCharsets.UTF_8);
|
||||||
|
jsonArray = JSONUtil.parseArray(content);
|
||||||
|
log.info("[{}] 成功处理文件: {}",taskName,jsonFile.getAbsolutePath());
|
||||||
|
} catch (RuntimeException | IOException e) {
|
||||||
|
throw new RuntimeException("处理文件 " + jsonFile.getName() + " 失败: " + e.getMessage(), e);
|
||||||
|
}
|
||||||
|
return jsonArray;
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,29 @@
|
|||||||
|
package com.suisung.mall.shop.sync.controller;
|
||||||
|
|
||||||
|
import com.suisung.mall.shop.sync.service.SyncThirdDataService;
|
||||||
|
import io.swagger.annotations.Api;
|
||||||
|
import io.swagger.annotations.ApiOperation;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.core.io.Resource;
|
||||||
|
import org.springframework.http.MediaType;
|
||||||
|
import org.springframework.http.ResponseEntity;
|
||||||
|
import org.springframework.stereotype.Controller;
|
||||||
|
import org.springframework.web.bind.annotation.RequestMapping;
|
||||||
|
import org.springframework.web.bind.annotation.RequestMethod;
|
||||||
|
import org.springframework.web.bind.annotation.RequestParam;
|
||||||
|
import org.springframework.web.bind.annotation.RestController;
|
||||||
|
|
||||||
|
@Api(tags = "第三方数据同步")
|
||||||
|
@Controller
|
||||||
|
@RequestMapping("/shop/sync/app")
|
||||||
|
public class ClientController {
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private SyncThirdDataService syncThirdDataService;
|
||||||
|
|
||||||
|
@ApiOperation(value = "下载客户端应用", notes = "获取加密密钥")
|
||||||
|
@RequestMapping(value = "/downClientJar",produces = MediaType.APPLICATION_OCTET_STREAM_VALUE, method = RequestMethod.GET)
|
||||||
|
public ResponseEntity<Resource> downClientJar(@RequestParam String primaryKey) {
|
||||||
|
return syncThirdDataService.downloadToClient(primaryKey);
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,107 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2025. Lorem ipsum dolor sit amet, consectetur adipiscing elit.
|
||||||
|
* Morbi non lorem porttitor neque feugiat blandit. Ut vitae ipsum eget quam lacinia accumsan.
|
||||||
|
* Etiam sed turpis ac ipsum condimentum fringilla. Maecenas magna.
|
||||||
|
* Proin dapibus sapien vel ante. Aliquam erat volutpat. Pellentesque sagittis ligula eget metus.
|
||||||
|
* Vestibulum commodo. Ut rhoncus gravida arcu.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.suisung.mall.shop.sync.controller;
|
||||||
|
|
||||||
|
import com.suisung.mall.common.api.CommonResult;
|
||||||
|
import com.suisung.mall.common.modules.sync.StoreDbConfig;
|
||||||
|
import com.suisung.mall.common.modules.sync.SyncApp;
|
||||||
|
import com.suisung.mall.common.modules.sync.SyncFileLog;
|
||||||
|
import com.suisung.mall.shop.sync.service.StoreDbConfigService;
|
||||||
|
import com.suisung.mall.shop.sync.service.SyncFileLogService;
|
||||||
|
import io.swagger.annotations.Api;
|
||||||
|
import io.swagger.annotations.ApiOperation;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.web.bind.annotation.*;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <p>
|
||||||
|
* 页面导航表 前端控制器
|
||||||
|
* </p>
|
||||||
|
*
|
||||||
|
* @author lyj
|
||||||
|
* @since 2025-05-16
|
||||||
|
*/
|
||||||
|
@Api(tags = "页面导航表-店铺数据库连接配置")
|
||||||
|
@RestController
|
||||||
|
@RequestMapping("/admin/shop/shop-sync-storeDbConfig")
|
||||||
|
public class StoreDbConfigController {
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private StoreDbConfigService storeDbConfigService;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 分页列表查询
|
||||||
|
* @param storeDbConfig
|
||||||
|
* @param pageNum
|
||||||
|
* @param pageSize
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
@ApiOperation(value = "列表查询-分页列表查询店铺数据库连接配置", notes = "列表查询-分页列表查询店铺数据库连接配置")
|
||||||
|
@RequestMapping(value = "/list", method = RequestMethod.GET)
|
||||||
|
public CommonResult list(@RequestBody StoreDbConfig storeDbConfig ,
|
||||||
|
@RequestParam(name = "pageNum", defaultValue = "1") Integer pageNum,
|
||||||
|
@RequestParam(name = "pageSize", defaultValue = "10") Integer pageSize) {
|
||||||
|
return storeDbConfigService.findStoreDbConfigPageList(storeDbConfig, pageNum, pageSize);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 单笔获取
|
||||||
|
* @param storeDbConfig
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
@ApiOperation(value = "单笔获取-分页列表查询店铺数据库连接配置", notes = "单笔获取-分页列表查询店铺数据库连接配置")
|
||||||
|
@RequestMapping(value = "/getStoreDbConfig", method = RequestMethod.GET)
|
||||||
|
public CommonResult getStoreDbConfig(@RequestBody StoreDbConfig storeDbConfig) {
|
||||||
|
return CommonResult.success(storeDbConfigService.getStroeConfig(storeDbConfig));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 新增
|
||||||
|
* @param storeDbConfig
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
@ApiOperation(value = "新增-店铺数据库连接配置", notes = "新增-店铺数据库连接配置")
|
||||||
|
@RequestMapping(value = "/saveStoreDbConfig", method = RequestMethod.POST)
|
||||||
|
public CommonResult saveStoreDbConfig(@RequestBody StoreDbConfig storeDbConfig) {
|
||||||
|
return storeDbConfigService.addStoreDbConfig(storeDbConfig);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 更新
|
||||||
|
* @param storeDbConfig
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
@ApiOperation(value = "更新-店铺数据库连接配置", notes = "更新-店铺数据库连接配置")
|
||||||
|
@RequestMapping(value = "/udpateStoreDbConfig", method = RequestMethod.PUT)
|
||||||
|
public CommonResult udpateStoreDbConfig(@RequestBody StoreDbConfig storeDbConfig) {
|
||||||
|
return storeDbConfigService.updateStoreDbConfig(storeDbConfig);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 删除
|
||||||
|
* @param storeDbConfig
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
@ApiOperation(value = "删除-店铺数据库连接配置", notes = "删除-店铺数据库连接配置")
|
||||||
|
@RequestMapping(value = "/delStoreDbConfig", method = RequestMethod.PUT)
|
||||||
|
public CommonResult delStoreDbConfig(@RequestBody StoreDbConfig storeDbConfig) {
|
||||||
|
return storeDbConfigService.delStoreDbConfig(storeDbConfig);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 生产密钥,用来放到app/bin目录,替换原来的密钥
|
||||||
|
* @param syncApp
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
@ApiOperation(value = "客户端primaryKey.txt生产", notes = "密钥生成器")
|
||||||
|
@RequestMapping(value = "/getPrimaryKey", method = RequestMethod.PUT)
|
||||||
|
public String getPrimaryKey(@RequestBody SyncApp syncApp) {
|
||||||
|
return storeDbConfigService.getPrimaryKey(syncApp);
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -10,22 +10,30 @@ package com.suisung.mall.shop.sync.controller;
|
|||||||
|
|
||||||
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.sync.StoreDbConfig;
|
||||||
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 com.suisung.mall.shop.sync.service.SyncAppService;
|
||||||
import com.suisung.mall.shop.sync.service.SyncThirdDataService;
|
import com.suisung.mall.shop.sync.service.SyncThirdDataService;
|
||||||
import io.swagger.annotations.Api;
|
import io.swagger.annotations.Api;
|
||||||
import io.swagger.annotations.ApiOperation;
|
import io.swagger.annotations.ApiOperation;
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.http.MediaType;
|
||||||
|
import org.springframework.http.ResponseEntity;
|
||||||
import org.springframework.web.bind.annotation.*;
|
import org.springframework.web.bind.annotation.*;
|
||||||
|
import org.springframework.web.multipart.MultipartFile;
|
||||||
|
|
||||||
import javax.annotation.Resource;
|
import javax.annotation.Resource;
|
||||||
import javax.servlet.http.HttpServletRequest;
|
import javax.servlet.http.HttpServletRequest;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
@Api(tags = "第三方数据同步")
|
@Api(tags = "第三方数据同步")
|
||||||
@RestController
|
@RestController
|
||||||
@RequestMapping("/shop/sync/third")
|
@RequestMapping("/shop/sync/third")
|
||||||
public class SyncThirdDataController {
|
public class SyncThirdDataController {
|
||||||
|
@Resource
|
||||||
|
private SyncAppService syncAppService;
|
||||||
|
|
||||||
@Resource
|
@Resource
|
||||||
private SyncThirdDataService syncThirdDataService;
|
private SyncThirdDataService syncThirdDataService;
|
||||||
|
|
||||||
@ -82,4 +90,59 @@ public class SyncThirdDataController {
|
|||||||
return syncThirdDataService.syncManual(storeId, syncType);
|
return syncThirdDataService.syncManual(storeId, syncType);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ApiOperation(value = "思迅文件上传", notes = "死讯软件客户端文件上传")
|
||||||
|
@RequestMapping(value = "/uploudSxData", method = RequestMethod.POST)
|
||||||
|
public ThirdApiRes uploudSxData(@RequestParam("file") MultipartFile file,
|
||||||
|
@RequestParam String appKey,
|
||||||
|
@RequestParam String sign,
|
||||||
|
@RequestParam String page,
|
||||||
|
@RequestParam String syncType) {
|
||||||
|
return syncThirdDataService.fileUpload(appKey,sign,page,syncType,file);
|
||||||
|
}
|
||||||
|
|
||||||
|
@ApiOperation(value = "读取数据", notes = "当思迅发送完成数据后,调用该地址读取本地文件")
|
||||||
|
@RequestMapping(value = "/readSxData", method = RequestMethod.POST)
|
||||||
|
public ThirdApiRes readSxData(@RequestBody List<String> folders,
|
||||||
|
@RequestParam String appKey,
|
||||||
|
@RequestParam String sign,
|
||||||
|
@RequestParam String syncType) {
|
||||||
|
new Thread(new Runnable() {
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
syncThirdDataService.SyncReadSxFileData(appKey,sign,syncType,folders);
|
||||||
|
}
|
||||||
|
}).start();
|
||||||
|
return new ThirdApiRes().success("服务器已处理文件");
|
||||||
|
}
|
||||||
|
|
||||||
|
@ApiOperation(value = "读取数据", notes = "手动补偿商品同步失败的数据使用")
|
||||||
|
@RequestMapping(value = "/retryReadSxData", method = RequestMethod.POST)
|
||||||
|
public ThirdApiRes RetryReadSxData(@RequestParam List<String> folders,
|
||||||
|
@RequestParam String appKey,
|
||||||
|
@RequestParam String sign,
|
||||||
|
@RequestParam String syncType) {
|
||||||
|
return readSxData(folders,appKey,sign,syncType);
|
||||||
|
}
|
||||||
|
|
||||||
|
@ApiOperation(value = "获取加密密钥", notes = "获取加密密钥")
|
||||||
|
@RequestMapping(value = "/getAppSign", method = RequestMethod.POST)
|
||||||
|
public Map<String,Object> getAppSign(@RequestParam String primaryKey) {
|
||||||
|
return syncAppService.getAppSign(primaryKey);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 客户端查询配置
|
||||||
|
* @param appKey
|
||||||
|
* @param sign
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
@ApiOperation(value = "客户端查询配置", notes = "客户端查询配置")
|
||||||
|
@RequestMapping(value = "/getStoreDbConfig", method = RequestMethod.POST)
|
||||||
|
public ThirdApiRes getStoreDbConfig(@RequestParam String appKey,
|
||||||
|
@RequestParam String sign){
|
||||||
|
return syncThirdDataService.getStoreDbConfig(appKey,sign);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -0,0 +1,6 @@
|
|||||||
|
package com.suisung.mall.shop.sync.keymanage;
|
||||||
|
|
||||||
|
public class RedisKey {
|
||||||
|
|
||||||
|
public static final String SXCLIENTKEYVERSION="sxclientKey:version";
|
||||||
|
}
|
||||||
@ -0,0 +1,18 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2025. Lorem ipsum dolor sit amet, consectetur adipiscing elit.
|
||||||
|
* Morbi non lorem porttitor neque feugiat blandit. Ut vitae ipsum eget quam lacinia accumsan.
|
||||||
|
* Etiam sed turpis ac ipsum condimentum fringilla. Maecenas magna.
|
||||||
|
* Proin dapibus sapien vel ante. Aliquam erat volutpat. Pellentesque sagittis ligula eget metus.
|
||||||
|
* Vestibulum commodo. Ut rhoncus gravida arcu.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.suisung.mall.shop.sync.mapper;
|
||||||
|
|
||||||
|
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||||
|
import com.suisung.mall.common.modules.sync.StoreDbConfig;
|
||||||
|
import com.suisung.mall.common.modules.sync.SyncFileLog;
|
||||||
|
import org.springframework.stereotype.Repository;
|
||||||
|
|
||||||
|
@Repository
|
||||||
|
public interface StoreDbConfigMapper extends BaseMapper<StoreDbConfig> {
|
||||||
|
}
|
||||||
@ -0,0 +1,17 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2025. Lorem ipsum dolor sit amet, consectetur adipiscing elit.
|
||||||
|
* Morbi non lorem porttitor neque feugiat blandit. Ut vitae ipsum eget quam lacinia accumsan.
|
||||||
|
* Etiam sed turpis ac ipsum condimentum fringilla. Maecenas magna.
|
||||||
|
* Proin dapibus sapien vel ante. Aliquam erat volutpat. Pellentesque sagittis ligula eget metus.
|
||||||
|
* Vestibulum commodo. Ut rhoncus gravida arcu.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.suisung.mall.shop.sync.mapper;
|
||||||
|
|
||||||
|
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||||
|
import com.suisung.mall.common.modules.sync.SyncFileLog;
|
||||||
|
import org.springframework.stereotype.Repository;
|
||||||
|
|
||||||
|
@Repository
|
||||||
|
public interface SyncFileLogMapper extends BaseMapper<SyncFileLog> {
|
||||||
|
}
|
||||||
@ -0,0 +1,414 @@
|
|||||||
|
package com.suisung.mall.shop.sync.pool;
|
||||||
|
|
||||||
|
import cn.hutool.json.JSONArray;
|
||||||
|
import cn.hutool.json.JSONUtil;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.lang.management.ManagementFactory;
|
||||||
|
import java.lang.management.ThreadInfo;
|
||||||
|
import java.lang.management.ThreadMXBean;
|
||||||
|
import java.nio.charset.StandardCharsets;
|
||||||
|
import java.nio.file.Files;
|
||||||
|
import java.nio.file.Path;
|
||||||
|
import java.nio.file.Paths;
|
||||||
|
import java.nio.file.StandardOpenOption;
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Objects;
|
||||||
|
import java.util.concurrent.*;
|
||||||
|
import java.util.concurrent.atomic.AtomicInteger;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
import java.util.stream.Stream;
|
||||||
|
|
||||||
|
public class ThreadPoolManager {
|
||||||
|
private final ThreadPoolExecutor executor;
|
||||||
|
private final String successFile;
|
||||||
|
private final String failureFile;
|
||||||
|
private final AtomicInteger successCount = new AtomicInteger(0);
|
||||||
|
private final AtomicInteger failureCount = new AtomicInteger(0);
|
||||||
|
private final BlockingQueue<Runnable> pendingTasks = new LinkedBlockingQueue<>();
|
||||||
|
private volatile boolean isShutdown = false;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
public ThreadPoolManager(int corePoolSize, int maxPoolSize, String successFile, String failureFile) {
|
||||||
|
this.successFile = successFile;
|
||||||
|
this.failureFile = failureFile;
|
||||||
|
|
||||||
|
this.executor = new ThreadPoolExecutor(
|
||||||
|
corePoolSize,
|
||||||
|
maxPoolSize,
|
||||||
|
60L,
|
||||||
|
TimeUnit.SECONDS,
|
||||||
|
new LinkedBlockingQueue<>(100),
|
||||||
|
new CustomRejectedExecutionHandler());
|
||||||
|
|
||||||
|
this.executor.allowCoreThreadTimeOut(true);
|
||||||
|
startMonitorThread();
|
||||||
|
startPendingTaskConsumer();
|
||||||
|
}
|
||||||
|
|
||||||
|
public ThreadPoolManager(String successFile, String failureFile) {
|
||||||
|
this(Runtime.getRuntime().availableProcessors(),
|
||||||
|
Runtime.getRuntime().availableProcessors() * 2,
|
||||||
|
successFile, failureFile);
|
||||||
|
}
|
||||||
|
// 自定义线程工厂
|
||||||
|
private static class CustomThreadFactory implements ThreadFactory {
|
||||||
|
private final AtomicInteger counter = new AtomicInteger(0);
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Thread newThread(Runnable r) {
|
||||||
|
Thread thread = new Thread(r, "pool-thread-" + counter.incrementAndGet());
|
||||||
|
thread.setPriority(Thread.NORM_PRIORITY);
|
||||||
|
thread.setDaemon(false);
|
||||||
|
return thread;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// 自定义拒绝策略
|
||||||
|
private class CustomRejectedExecutionHandler implements RejectedExecutionHandler {
|
||||||
|
@Override
|
||||||
|
public void rejectedExecution(Runnable r, ThreadPoolExecutor executor) {
|
||||||
|
if (!isShutdown) {
|
||||||
|
// 1. 尝试直接执行(调用者线程)
|
||||||
|
try {
|
||||||
|
System.out.println("线程池饱和,由调用线程直接执行");
|
||||||
|
r.run();
|
||||||
|
} catch (Exception e) {
|
||||||
|
System.err.println("调用者执行任务失败: " + e.getMessage());
|
||||||
|
}
|
||||||
|
|
||||||
|
// 2. 记录指标
|
||||||
|
failureCount.incrementAndGet();
|
||||||
|
} else {
|
||||||
|
System.err.println("线程池已关闭,拒绝新任务");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// 消费待处理任务的线程
|
||||||
|
private void startPendingTaskConsumer() {
|
||||||
|
Thread consumerThread = new Thread(() -> {
|
||||||
|
while (!isShutdown || !pendingTasks.isEmpty()) {
|
||||||
|
try {
|
||||||
|
Runnable task = pendingTasks.take();
|
||||||
|
// 尝试重新提交任务
|
||||||
|
executor.submit(task);
|
||||||
|
} catch (InterruptedException e) {
|
||||||
|
Thread.currentThread().interrupt();
|
||||||
|
break;
|
||||||
|
} catch (Exception e) {
|
||||||
|
System.err.println("处理待处理任务时出错: " + e.getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
consumerThread.setDaemon(true);
|
||||||
|
consumerThread.start();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 提交文件夹处理任务(带重试机制)
|
||||||
|
*/
|
||||||
|
public void submitFolderTask(String taskName, String folderPath,
|
||||||
|
JsonProcessCallback callback, int maxRetries) {
|
||||||
|
Runnable task = () -> {
|
||||||
|
int retryCount = 0;
|
||||||
|
boolean success = false;
|
||||||
|
|
||||||
|
while (retryCount <= maxRetries && !success && !isShutdown) {
|
||||||
|
try {
|
||||||
|
processFolder(taskName, folderPath, callback);
|
||||||
|
successCount.incrementAndGet();
|
||||||
|
logSuccess(taskName, folderPath);
|
||||||
|
success = true;
|
||||||
|
} catch (Exception e) {
|
||||||
|
retryCount++;
|
||||||
|
if (retryCount > maxRetries) {
|
||||||
|
failureCount.incrementAndGet();
|
||||||
|
logFailure(taskName, folderPath,
|
||||||
|
"重试" + maxRetries + "次后失败: " + e.getMessage());
|
||||||
|
} else {
|
||||||
|
System.out.printf("[%s] 任务处理失败,第%d次重试...%n",
|
||||||
|
taskName, retryCount);
|
||||||
|
try {
|
||||||
|
Thread.sleep(1000 * retryCount); // 指数退避
|
||||||
|
} catch (InterruptedException ie) {
|
||||||
|
Thread.currentThread().interrupt();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
try {
|
||||||
|
executor.submit(task);
|
||||||
|
} catch (Exception e) {
|
||||||
|
System.err.println("提交任务失败: " + e.getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 批量提交文件夹处理任务
|
||||||
|
* @param taskName 任务名称(用于日志记录)
|
||||||
|
* @param folderPaths 要处理的文件夹路径列表
|
||||||
|
* @param callback 处理完成的回调接口
|
||||||
|
* @return CountDownLatch 用于等待所有任务完成
|
||||||
|
*/
|
||||||
|
// public void submitBatchFolderTasks(String taskName, List<String> folderPaths,
|
||||||
|
// JsonProcessCallback callback, int maxRetries) {
|
||||||
|
// Semaphore semaphore = new Semaphore(executor.getMaximumPoolSize() * 2);
|
||||||
|
//
|
||||||
|
// for (String folderPath : folderPaths) {
|
||||||
|
// try {
|
||||||
|
// semaphore.acquire();
|
||||||
|
// submitFolderTask(taskName, folderPath, callback, maxRetries);
|
||||||
|
// } catch (InterruptedException e) {
|
||||||
|
// Thread.currentThread().interrupt();
|
||||||
|
// break;
|
||||||
|
// } finally {
|
||||||
|
// semaphore.release();
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
public void submitBatchFolderTasks(String taskName, List<String> folderPaths,
|
||||||
|
JsonProcessCallback callback, int maxRetries) {
|
||||||
|
// 使用CountDownLatch跟踪批次完成
|
||||||
|
CountDownLatch batchLatch = new CountDownLatch(folderPaths.size());
|
||||||
|
|
||||||
|
// 控制并发度的信号量
|
||||||
|
Semaphore concurrencyLimiter = new Semaphore(executor.getMaximumPoolSize() * 2);
|
||||||
|
|
||||||
|
for (String folderPath : folderPaths) {
|
||||||
|
try {
|
||||||
|
concurrencyLimiter.acquire(); // 获取许可
|
||||||
|
|
||||||
|
executor.execute(() -> {
|
||||||
|
try {
|
||||||
|
submitFolderTask(taskName, folderPath, callback, maxRetries);
|
||||||
|
} finally {
|
||||||
|
concurrencyLimiter.release();
|
||||||
|
batchLatch.countDown();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
} catch (InterruptedException e) {
|
||||||
|
Thread.currentThread().interrupt();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
// 等待批次完成,带超时
|
||||||
|
batchLatch.await(30, TimeUnit.MINUTES);
|
||||||
|
} catch (InterruptedException e) {
|
||||||
|
Thread.currentThread().interrupt();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void processFolder(String taskName, String folderPath, JsonProcessCallback callback) throws IOException {
|
||||||
|
File folder = new File(folderPath);
|
||||||
|
// ... 参数校验 ...
|
||||||
|
|
||||||
|
// 使用try-with-resources确保资源释放
|
||||||
|
try (Stream<Path> paths = Files.list(folder.toPath())) {
|
||||||
|
paths.filter(path -> path.toString().endsWith(".txt"))
|
||||||
|
.parallel() // 并行处理文件
|
||||||
|
.forEach(path -> {
|
||||||
|
try {
|
||||||
|
String content = new String(Files.readAllBytes(path), StandardCharsets.UTF_8);
|
||||||
|
JSONArray jsonArray = JSONUtil.parseArray(content);
|
||||||
|
|
||||||
|
if (callback != null) {
|
||||||
|
callback.process(jsonArray, taskName, path.getFileName().toString());
|
||||||
|
}
|
||||||
|
|
||||||
|
System.out.println("[" + taskName + "] 成功处理文件: " + path);
|
||||||
|
} catch (Exception e) {
|
||||||
|
throw new RuntimeException("处理文件失败: " + path, e);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 记录成功处理
|
||||||
|
*/
|
||||||
|
private synchronized void logSuccess(String taskName, String folderPath) {
|
||||||
|
Path path = Paths.get(successFile);
|
||||||
|
String record = String.format("%s | %s | %d%n",
|
||||||
|
taskName, folderPath, System.currentTimeMillis());
|
||||||
|
try {
|
||||||
|
Files.write(path, record.getBytes(StandardCharsets.UTF_8),
|
||||||
|
StandardOpenOption.CREATE, StandardOpenOption.APPEND);
|
||||||
|
} catch (IOException e) {
|
||||||
|
throw new RuntimeException(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 记录处理失败
|
||||||
|
*/
|
||||||
|
private synchronized void logFailure(String taskName, String folderPath, String error) {
|
||||||
|
Path path = Paths.get(failureFile);
|
||||||
|
String record = String.format("%s | %s | %s | %d%n",
|
||||||
|
taskName, folderPath, error, System.currentTimeMillis());
|
||||||
|
try {
|
||||||
|
Files.write(path, record.getBytes(StandardCharsets.UTF_8),
|
||||||
|
StandardOpenOption.CREATE, StandardOpenOption.APPEND);
|
||||||
|
} catch (IOException e) {
|
||||||
|
throw new RuntimeException(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 启动监控线程
|
||||||
|
*/
|
||||||
|
private void startMonitorThread() {
|
||||||
|
Thread monitorThread = new Thread(() -> {
|
||||||
|
while (!executor.isShutdown()) {
|
||||||
|
try {
|
||||||
|
printPoolStatus();
|
||||||
|
checkForDeadlock();
|
||||||
|
adjustPoolSize();
|
||||||
|
TimeUnit.SECONDS.sleep(5);
|
||||||
|
} catch (InterruptedException e) {
|
||||||
|
Thread.currentThread().interrupt();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
monitorThread.setName("pool-monitor-thread");
|
||||||
|
monitorThread.setDaemon(true);
|
||||||
|
monitorThread.start();
|
||||||
|
}
|
||||||
|
private void printPoolStatus() {
|
||||||
|
System.out.println("\n=== 线程池状态 ===");
|
||||||
|
System.out.println("活跃线程: " + executor.getActiveCount());
|
||||||
|
System.out.println("核心线程: " + executor.getCorePoolSize());
|
||||||
|
System.out.println("最大线程: " + executor.getMaximumPoolSize());
|
||||||
|
System.out.println("队列大小: " + executor.getQueue().size());
|
||||||
|
System.out.println("待处理队列: " + pendingTasks.size());
|
||||||
|
System.out.println("完成任务: " + successCount.get());
|
||||||
|
System.out.println("失败任务: " + failureCount.get());
|
||||||
|
System.out.println("================\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 检测线程池死锁情况
|
||||||
|
*/
|
||||||
|
private void checkForDeadlock() {
|
||||||
|
// 1. 获取线程池工作线程
|
||||||
|
ThreadMXBean threadMXBean = ManagementFactory.getThreadMXBean();
|
||||||
|
long[] threadIds = threadMXBean.getAllThreadIds();
|
||||||
|
|
||||||
|
// 2. 查找死锁线程
|
||||||
|
long[] deadlockedThreadIds = threadMXBean.findDeadlockedThreads();
|
||||||
|
if (deadlockedThreadIds != null && deadlockedThreadIds.length > 0) {
|
||||||
|
System.err.println("⚠️ 检测到死锁线程:");
|
||||||
|
for (long threadId : deadlockedThreadIds) {
|
||||||
|
ThreadInfo threadInfo = threadMXBean.getThreadInfo(threadId);
|
||||||
|
System.err.println("死锁线程: " + threadInfo.getThreadName());
|
||||||
|
System.err.println("阻塞状态: " + threadInfo.getLockName() +
|
||||||
|
" 被 " + threadInfo.getLockOwnerName() + " 持有");
|
||||||
|
|
||||||
|
// 打印堆栈跟踪
|
||||||
|
System.err.println("堆栈跟踪:");
|
||||||
|
for (StackTraceElement ste : threadInfo.getStackTrace()) {
|
||||||
|
System.err.println("\t" + ste);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 3. 尝试恢复 - 中断死锁线程
|
||||||
|
if (executor instanceof ThreadPoolExecutor) {
|
||||||
|
ThreadPoolExecutor tpe = (ThreadPoolExecutor) executor;
|
||||||
|
BlockingQueue<Runnable> queue = tpe.getQueue();
|
||||||
|
|
||||||
|
System.err.println("尝试中断死锁线程并清空队列(" + queue.size() + "个任务)");
|
||||||
|
tpe.purge(); // 清除队列中所有任务
|
||||||
|
|
||||||
|
// 中断所有工作线程
|
||||||
|
for (long threadId : deadlockedThreadIds) {
|
||||||
|
ThreadInfo threadInfo = threadMXBean.getThreadInfo(threadId);
|
||||||
|
if (threadInfo != null) {
|
||||||
|
for (Thread thread : getAllThreads()) {
|
||||||
|
if (thread.getId() == threadId) {
|
||||||
|
thread.interrupt();
|
||||||
|
System.err.println("已中断线程: " + thread.getName());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取JVM中所有活动线程
|
||||||
|
*/
|
||||||
|
private List<Thread> getAllThreads() {
|
||||||
|
ThreadGroup rootGroup = Thread.currentThread().getThreadGroup();
|
||||||
|
while (rootGroup.getParent() != null) {
|
||||||
|
rootGroup = rootGroup.getParent();
|
||||||
|
}
|
||||||
|
|
||||||
|
Thread[] threads = new Thread[rootGroup.activeCount()];
|
||||||
|
while (rootGroup.enumerate(threads, true) == threads.length) {
|
||||||
|
threads = new Thread[threads.length * 2];
|
||||||
|
}
|
||||||
|
|
||||||
|
return Arrays.stream(threads)
|
||||||
|
.filter(Objects::nonNull)
|
||||||
|
.collect(Collectors.toList());
|
||||||
|
}
|
||||||
|
|
||||||
|
private void adjustPoolSize() {
|
||||||
|
// 动态调整线程池大小
|
||||||
|
if (executor.getQueue().size() > 50 &&
|
||||||
|
executor.getMaximumPoolSize() < 100) {
|
||||||
|
executor.setMaximumPoolSize(executor.getMaximumPoolSize() + 5);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* 关闭线程池(优雅关闭)
|
||||||
|
*/
|
||||||
|
public void shutdown() {
|
||||||
|
isShutdown = true;
|
||||||
|
executor.shutdown();
|
||||||
|
try {
|
||||||
|
if (!executor.awaitTermination(60, TimeUnit.SECONDS)) {
|
||||||
|
executor.shutdownNow();
|
||||||
|
}
|
||||||
|
} catch (InterruptedException e) {
|
||||||
|
executor.shutdownNow();
|
||||||
|
Thread.currentThread().interrupt();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 立即关闭线程池
|
||||||
|
*/
|
||||||
|
public void shutdownNow() {
|
||||||
|
executor.shutdownNow();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 等待所有任务完成
|
||||||
|
*/
|
||||||
|
public void awaitTermination(long timeout, TimeUnit unit) throws InterruptedException {
|
||||||
|
executor.awaitTermination(timeout, unit);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* JSON处理回调接口
|
||||||
|
*/
|
||||||
|
@FunctionalInterface
|
||||||
|
public interface JsonProcessCallback {
|
||||||
|
void process(JSONArray jsonArray, String taskName, String fileName);
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,33 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2025. Lorem ipsum dolor sit amet, consectetur adipiscing elit.
|
||||||
|
* Morbi non lorem porttitor neque feugiat blandit. Ut vitae ipsum eget quam lacinia accumsan.
|
||||||
|
* Etiam sed turpis ac ipsum condimentum fringilla. Maecenas magna.
|
||||||
|
* Proin dapibus sapien vel ante. Aliquam erat volutpat. Pellentesque sagittis ligula eget metus.
|
||||||
|
* Vestibulum commodo. Ut rhoncus gravida arcu.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.suisung.mall.shop.sync.service;
|
||||||
|
|
||||||
|
|
||||||
|
import com.baomidou.mybatisplus.extension.service.IService;
|
||||||
|
import com.suisung.mall.common.api.CommonResult;
|
||||||
|
import com.suisung.mall.common.modules.sync.StoreDbConfig;
|
||||||
|
import com.suisung.mall.common.modules.sync.SyncApp;
|
||||||
|
import com.suisung.mall.common.pojo.res.ThirdApiRes;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
public interface StoreDbConfigService extends IService<StoreDbConfig> {
|
||||||
|
|
||||||
|
CommonResult findStoreDbConfigPageList(StoreDbConfig storeDbConfig, Integer pageNum, Integer pageSize);
|
||||||
|
|
||||||
|
|
||||||
|
StoreDbConfig getStroeConfig(StoreDbConfig storeDbConfig);
|
||||||
|
|
||||||
|
CommonResult addStoreDbConfig(StoreDbConfig storeDbConfig);
|
||||||
|
|
||||||
|
CommonResult updateStoreDbConfig(StoreDbConfig storeDbConfig);
|
||||||
|
|
||||||
|
CommonResult delStoreDbConfig(StoreDbConfig storeDbConfig);
|
||||||
|
String getPrimaryKey(SyncApp syncApp);
|
||||||
|
}
|
||||||
@ -12,6 +12,8 @@ import com.baomidou.mybatisplus.core.metadata.IPage;
|
|||||||
import com.baomidou.mybatisplus.extension.service.IService;
|
import com.baomidou.mybatisplus.extension.service.IService;
|
||||||
import com.suisung.mall.common.modules.sync.SyncApp;
|
import com.suisung.mall.common.modules.sync.SyncApp;
|
||||||
|
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
public interface SyncAppService extends IService<SyncApp> {
|
public interface SyncAppService extends IService<SyncApp> {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -83,4 +85,13 @@ public interface SyncAppService extends IService<SyncApp> {
|
|||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
SyncApp checkAppSign(String appKey, String sign, String postData);
|
SyncApp checkAppSign(String appKey, String sign, String postData);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取加密的appKey,sign,streId
|
||||||
|
* @param primaryKey
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
Map<String,Object> getAppSign(String primaryKey);
|
||||||
|
|
||||||
|
boolean checkPrimaryKey(String primaryKey);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -0,0 +1,23 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2025. Lorem ipsum dolor sit amet, consectetur adipiscing elit.
|
||||||
|
* Morbi non lorem porttitor neque feugiat blandit. Ut vitae ipsum eget quam lacinia accumsan.
|
||||||
|
* Etiam sed turpis ac ipsum condimentum fringilla. Maecenas magna.
|
||||||
|
* Proin dapibus sapien vel ante. Aliquam erat volutpat. Pellentesque sagittis ligula eget metus.
|
||||||
|
* Vestibulum commodo. Ut rhoncus gravida arcu.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.suisung.mall.shop.sync.service;
|
||||||
|
|
||||||
|
|
||||||
|
import com.suisung.mall.common.api.CommonResult;
|
||||||
|
import com.suisung.mall.common.modules.sync.StoreDbConfig;
|
||||||
|
import com.suisung.mall.common.modules.sync.SyncFileLog;
|
||||||
|
import com.suisung.mall.common.pojo.res.ThirdApiRes;
|
||||||
|
import com.suisung.mall.core.web.service.IBaseService;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
public interface SyncFileLogService extends IBaseService<SyncFileLog> {
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
@ -10,9 +10,14 @@ 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.sync.StoreDbConfig;
|
||||||
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.http.ResponseEntity;
|
||||||
|
import org.springframework.web.multipart.MultipartFile;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
public interface SyncThirdDataService {
|
public interface SyncThirdDataService {
|
||||||
@ -54,4 +59,28 @@ public interface SyncThirdDataService {
|
|||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
CommonResult syncManual(String storeId, Integer syncType);
|
CommonResult syncManual(String storeId, Integer syncType);
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @param appKey
|
||||||
|
* @param sign
|
||||||
|
* @param multipartFile
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
ThirdApiRes fileUpload(String appKey, String sign,String path,String syncType, MultipartFile multipartFile);
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @param appKey
|
||||||
|
* @param sign
|
||||||
|
* @param folders
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
void SyncReadSxFileData(String appKey, String sign,String syncType, List<String> folders);
|
||||||
|
|
||||||
|
|
||||||
|
ResponseEntity<Resource> downloadToClient(String primaryKey);
|
||||||
|
|
||||||
|
ThirdApiRes getStoreDbConfig(String appKey,String sign);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -0,0 +1,187 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2025. Lorem ipsum dolor sit amet, consectetur adipiscing elit.
|
||||||
|
* Morbi non lorem porttitor neque feugiat blandit. Ut vitae ipsum eget quam lacinia accumsan.
|
||||||
|
* Etiam sed turpis ac ipsum condimentum fringilla. Maecenas magna.
|
||||||
|
* Proin dapibus sapien vel ante. Aliquam erat volutpat. Pellentesque sagittis ligula eget metus.
|
||||||
|
* Vestibulum commodo. Ut rhoncus gravida arcu.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.suisung.mall.shop.sync.service.impl;
|
||||||
|
|
||||||
|
import cn.hutool.core.convert.Convert;
|
||||||
|
import cn.hutool.core.util.ObjectUtil;
|
||||||
|
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
|
||||||
|
import com.suisung.mall.common.api.CommonResult;
|
||||||
|
import com.suisung.mall.common.enums.DicEnum;
|
||||||
|
import com.suisung.mall.common.modules.store.ShopStoreBase;
|
||||||
|
import com.suisung.mall.common.modules.sync.StoreDbConfig;
|
||||||
|
import com.suisung.mall.common.modules.sync.SyncApp;
|
||||||
|
import com.suisung.mall.common.pojo.res.ThirdApiRes;
|
||||||
|
import com.suisung.mall.common.utils.ContextUtil;
|
||||||
|
import com.suisung.mall.common.utils.StringUtils;
|
||||||
|
import com.suisung.mall.core.web.service.impl.BaseServiceImpl;
|
||||||
|
import com.suisung.mall.shop.store.service.ShopStoreBaseService;
|
||||||
|
import com.suisung.mall.shop.sync.Utils.CryptoUtils;
|
||||||
|
import com.suisung.mall.shop.sync.mapper.StoreDbConfigMapper;
|
||||||
|
import com.suisung.mall.shop.sync.service.StoreDbConfigService;
|
||||||
|
|
||||||
|
import com.suisung.mall.shop.sync.service.SyncAppService;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
|
import javax.swing.*;
|
||||||
|
import java.util.Objects;
|
||||||
|
|
||||||
|
import static com.suisung.mall.common.utils.ContextUtil.getStoreId;
|
||||||
|
|
||||||
|
|
||||||
|
@Service
|
||||||
|
public class StoreDbConfigServiceImpl extends BaseServiceImpl<StoreDbConfigMapper, StoreDbConfig> implements StoreDbConfigService {
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private ShopStoreBaseService shopStoreBaseService;
|
||||||
|
@Autowired
|
||||||
|
private SyncAppService syncAppService;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public CommonResult findStoreDbConfigPageList(StoreDbConfig storeDbConfig,Integer pageNum,Integer pageSize) {
|
||||||
|
checked();
|
||||||
|
String storeId= getStoreId(storeDbConfig.getStoreId());
|
||||||
|
QueryWrapper<StoreDbConfig> queryWrapper = new QueryWrapper<>();
|
||||||
|
queryWrapper.eq("store_id", storeId);
|
||||||
|
queryWrapper.eq("has_internet", storeDbConfig.getHasInternet());
|
||||||
|
queryWrapper.eq("has_start", storeDbConfig.getHasInternet());
|
||||||
|
return CommonResult.success(this.lists(queryWrapper,pageNum,pageSize));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public StoreDbConfig getStroeConfig(StoreDbConfig storeDbConfig) {
|
||||||
|
checked();
|
||||||
|
if(ObjectUtil.isEmpty(storeDbConfig)){
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
String storeId= getStoreId(storeDbConfig.getStoreId());
|
||||||
|
storeDbConfig.setStoreId(storeId);
|
||||||
|
|
||||||
|
QueryWrapper<StoreDbConfig> queryWrapper = new QueryWrapper<>();
|
||||||
|
queryWrapper.eq("store_id", storeId);
|
||||||
|
if(null!=storeDbConfig.getId()){
|
||||||
|
queryWrapper.eq("id", storeDbConfig.getId());
|
||||||
|
}
|
||||||
|
return this.getOne(queryWrapper);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public CommonResult addStoreDbConfig(StoreDbConfig storeDbConfig) {
|
||||||
|
checked();
|
||||||
|
if(ObjectUtil.isEmpty(storeDbConfig)){
|
||||||
|
return CommonResult.failed("店铺数据库连接配置缺少必要参数");
|
||||||
|
}
|
||||||
|
String storeId= getStoreId(storeDbConfig.getStoreId());//保证不能跨数据操作
|
||||||
|
if(StringUtils.isEmpty(storeId)){
|
||||||
|
return CommonResult.failed("店铺数据库连接配置新增失败");
|
||||||
|
}
|
||||||
|
|
||||||
|
QueryWrapper<StoreDbConfig> queryWrapper = new QueryWrapper<>();
|
||||||
|
queryWrapper.eq("store_id", storeId);
|
||||||
|
if(null!=storeDbConfig.getId()){
|
||||||
|
queryWrapper.eq("id", storeDbConfig.getId());
|
||||||
|
}
|
||||||
|
queryWrapper.eq("has_start",DicEnum.YESORNO_1.getCode());
|
||||||
|
if(null!=this.getOne(queryWrapper)){
|
||||||
|
return CommonResult.failed("店铺已存在有效配置,不能重复添加");
|
||||||
|
}
|
||||||
|
ShopStoreBase shopStoreBase=shopStoreBaseService.get(Convert.toInt(storeId));
|
||||||
|
if(shopStoreBase==null){
|
||||||
|
return CommonResult.failed("店铺数据库连接配置新增失败:失败原因是店铺不存在");
|
||||||
|
}
|
||||||
|
storeDbConfig.setStoreId(storeId);
|
||||||
|
if(!this.save(storeDbConfig)){
|
||||||
|
return CommonResult.failed("店铺数据库连接配置新增失败");
|
||||||
|
}
|
||||||
|
return CommonResult.success();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public CommonResult updateStoreDbConfig(StoreDbConfig storeDbConfig) {
|
||||||
|
checked();
|
||||||
|
if(ObjectUtil.isEmpty(storeDbConfig)){
|
||||||
|
return CommonResult.failed("店铺数据库连接配置缺少必要参数");
|
||||||
|
}
|
||||||
|
if(ObjectUtil.isEmpty(storeDbConfig.getId())){
|
||||||
|
return CommonResult.failed("店铺数据库连接配置缺少必要参数");
|
||||||
|
}
|
||||||
|
String storeId= getStoreId(storeDbConfig.getStoreId());//保证不能跨数据操作
|
||||||
|
ShopStoreBase shopStoreBase=shopStoreBaseService.get(Convert.toInt(storeId));
|
||||||
|
if(shopStoreBase==null){
|
||||||
|
return CommonResult.failed("店铺数据库连接配置新增失败:失败原因是店铺不存在");
|
||||||
|
}
|
||||||
|
storeDbConfig.setStoreId(storeId);
|
||||||
|
if(!this.updateById(storeDbConfig)){
|
||||||
|
return CommonResult.failed("店铺数据库连接配置更新失败");
|
||||||
|
}
|
||||||
|
return CommonResult.success();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public CommonResult delStoreDbConfig(StoreDbConfig storeDbConfig) {
|
||||||
|
checked();
|
||||||
|
if(ObjectUtil.isEmpty(storeDbConfig)){
|
||||||
|
return CommonResult.failed("店铺数据库连接配置缺少必要参数");
|
||||||
|
}
|
||||||
|
if(ObjectUtil.isEmpty(storeDbConfig.getId())){
|
||||||
|
return CommonResult.failed("店铺数据库连接配置缺少必要参数");
|
||||||
|
}
|
||||||
|
String storeId= getStoreId(storeDbConfig.getStoreId());//保证不能跨数据操作
|
||||||
|
ShopStoreBase shopStoreBase=shopStoreBaseService.get(Convert.toInt(storeId));
|
||||||
|
if(shopStoreBase==null){
|
||||||
|
return CommonResult.failed("店铺数据库连接配置删除失败:失败原因是店铺不存在");
|
||||||
|
}
|
||||||
|
QueryWrapper<StoreDbConfig> queryWrapper = new QueryWrapper<>();
|
||||||
|
queryWrapper.eq("store_id", storeId);
|
||||||
|
queryWrapper.eq("id", storeDbConfig.getId());
|
||||||
|
StoreDbConfig delDb= getOne(queryWrapper);
|
||||||
|
if(delDb==null){
|
||||||
|
return CommonResult.failed("店铺数据库连接配置删除失败");
|
||||||
|
}
|
||||||
|
if(!this.removeById(delDb.getId())){
|
||||||
|
return CommonResult.failed("店铺数据库连接配置删除失败");
|
||||||
|
}
|
||||||
|
return CommonResult.success();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getPrimaryKey(SyncApp syncApp) {
|
||||||
|
checked();
|
||||||
|
if(ObjectUtil.isEmpty(syncApp)){
|
||||||
|
throw new RuntimeException("对象不能为空");
|
||||||
|
}
|
||||||
|
if(ObjectUtil.isEmpty(syncApp.getStore_id())){
|
||||||
|
throw new RuntimeException("商店编号不能为空");
|
||||||
|
}
|
||||||
|
String storeId= getStoreId(syncApp.getStore_id());//保证不能跨数据操作
|
||||||
|
ShopStoreBase shopStoreBase=shopStoreBaseService.get(Convert.toInt(storeId));
|
||||||
|
if(shopStoreBase==null){
|
||||||
|
throw new RuntimeException("商品不存在");
|
||||||
|
}
|
||||||
|
QueryWrapper<SyncApp> queryWrapper = new QueryWrapper<>();
|
||||||
|
queryWrapper.eq("store_id", storeId);
|
||||||
|
SyncApp result= syncAppService.getOne(queryWrapper);
|
||||||
|
String primaryKey="";
|
||||||
|
try {
|
||||||
|
primaryKey= CryptoUtils.packAndEncrypt(result.getApp_key(),result.getApp_secret(),result.getStore_id());
|
||||||
|
} catch (Exception e) {
|
||||||
|
throw new RuntimeException(e);
|
||||||
|
}
|
||||||
|
return primaryKey;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void checked(){
|
||||||
|
int roleId= Objects.requireNonNull(ContextUtil.getCurrentUser()).getRole_id();
|
||||||
|
if(roleId!=9){
|
||||||
|
throw new RuntimeException("仅为平台操作");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@ -8,6 +8,7 @@
|
|||||||
|
|
||||||
package com.suisung.mall.shop.sync.service.impl;
|
package com.suisung.mall.shop.sync.service.impl;
|
||||||
|
|
||||||
|
import cn.hutool.core.convert.Convert;
|
||||||
import cn.hutool.core.util.StrUtil;
|
import cn.hutool.core.util.StrUtil;
|
||||||
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
|
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
|
||||||
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
|
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
|
||||||
@ -16,19 +17,25 @@ import com.suisung.mall.common.modules.sync.SyncApp;
|
|||||||
import com.suisung.mall.common.utils.CommonUtil;
|
import com.suisung.mall.common.utils.CommonUtil;
|
||||||
import com.suisung.mall.common.utils.StringUtils;
|
import com.suisung.mall.common.utils.StringUtils;
|
||||||
import com.suisung.mall.core.web.service.impl.BaseServiceImpl;
|
import com.suisung.mall.core.web.service.impl.BaseServiceImpl;
|
||||||
|
import com.suisung.mall.shop.sync.Utils.CryptoUtils;
|
||||||
import com.suisung.mall.shop.sync.mapper.SyncAppMapper;
|
import com.suisung.mall.shop.sync.mapper.SyncAppMapper;
|
||||||
import com.suisung.mall.shop.sync.service.SyncAppService;
|
import com.suisung.mall.shop.sync.service.SyncAppService;
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.http.HttpStatus;
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Map;
|
||||||
import java.util.function.Consumer;
|
import java.util.function.Consumer;
|
||||||
|
|
||||||
@Service
|
@Service
|
||||||
|
@lombok.extern.slf4j.Slf4j
|
||||||
public class SyncAppServiceImpl extends BaseServiceImpl<SyncAppMapper, SyncApp> implements SyncAppService {
|
public class SyncAppServiceImpl extends BaseServiceImpl<SyncAppMapper, SyncApp> implements SyncAppService {
|
||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
private SyncAppMapper syncAppMapper;
|
private SyncAppMapper syncAppMapper;
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 根据 appKey 获取一条记录
|
* 根据 appKey 获取一条记录
|
||||||
*
|
*
|
||||||
@ -181,4 +188,50 @@ public class SyncAppServiceImpl extends BaseServiceImpl<SyncAppMapper, SyncApp>
|
|||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Map<String,Object> getAppSign(String primaryKey) {
|
||||||
|
Map<String,Object> resultMap=new HashMap<>();
|
||||||
|
try {
|
||||||
|
primaryKey=CryptoUtils.dealBlankStr(primaryKey);
|
||||||
|
Map<String,String> map=CryptoUtils.decryptAndUnpack(primaryKey);
|
||||||
|
// String appKey=map.get("appKey");
|
||||||
|
// String sign=map.get("sign");
|
||||||
|
String storeId=map.get("storeId");
|
||||||
|
QueryWrapper<SyncApp> queryWrapper = new QueryWrapper<>();
|
||||||
|
SyncApp syncApp= getOne(queryWrapper.select("store_id","app_secret","app_key").eq("store_id", storeId));
|
||||||
|
if(syncApp==null){
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
resultMap.put("resultCode", HttpStatus.OK);
|
||||||
|
resultMap.put("primaryKey",CryptoUtils.packAndEncrypt(syncApp.getApp_key(),syncApp.getApp_secret(),syncApp.getStore_id()));
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.info("解析失败:"+e.getMessage());
|
||||||
|
resultMap.put("resultCode",500);
|
||||||
|
resultMap.put("msg:","解析失败:"+e.getMessage());
|
||||||
|
}
|
||||||
|
return resultMap;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean checkPrimaryKey(String primaryKey) {
|
||||||
|
try {
|
||||||
|
primaryKey=CryptoUtils.dealBlankStr(primaryKey);
|
||||||
|
Map<String,String> map=CryptoUtils.decryptAndUnpack(primaryKey);
|
||||||
|
String appKey=map.get("appKey");
|
||||||
|
String sign=map.get("sign");
|
||||||
|
String storeId=map.get("storeId");
|
||||||
|
log.info("店铺:{}校验",storeId);
|
||||||
|
QueryWrapper<SyncApp> queryWrapper = new QueryWrapper<>();
|
||||||
|
SyncApp syncApp= getOne(queryWrapper.select("store_id","app_secret","app_key").
|
||||||
|
eq("store_id", storeId).
|
||||||
|
eq("app_key", appKey).eq("app_secret", sign));
|
||||||
|
if(syncApp==null){
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -0,0 +1,695 @@
|
|||||||
|
package com.suisung.mall.shop.sync.service.impl;
|
||||||
|
|
||||||
|
import cn.hutool.core.collection.CollUtil;
|
||||||
|
import cn.hutool.core.collection.CollectionUtil;
|
||||||
|
import cn.hutool.core.convert.Convert;
|
||||||
|
import cn.hutool.core.date.DateUtil;
|
||||||
|
import cn.hutool.core.util.IdUtil;
|
||||||
|
import cn.hutool.core.util.ObjectUtil;
|
||||||
|
import cn.hutool.core.util.StrUtil;
|
||||||
|
import cn.hutool.crypto.SecureUtil;
|
||||||
|
import cn.hutool.json.JSONArray;
|
||||||
|
import cn.hutool.json.JSONObject;
|
||||||
|
import com.alibaba.excel.util.DateUtils;
|
||||||
|
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
|
||||||
|
import com.suisung.mall.common.api.StateCode;
|
||||||
|
import com.suisung.mall.common.constant.CommonConstant;
|
||||||
|
import com.suisung.mall.common.exception.ApiException;
|
||||||
|
import com.suisung.mall.common.feignService.AccountService;
|
||||||
|
import com.suisung.mall.common.feignService.PayService;
|
||||||
|
import com.suisung.mall.common.modules.account.AccountUserBase;
|
||||||
|
import com.suisung.mall.common.modules.account.AccountUserInfo;
|
||||||
|
import com.suisung.mall.common.modules.base.ShopBaseProductBrand;
|
||||||
|
import com.suisung.mall.common.modules.base.ShopBaseProductCategory;
|
||||||
|
import com.suisung.mall.common.modules.base.ShopBaseProductType;
|
||||||
|
import com.suisung.mall.common.modules.number.ShopNumberSeq;
|
||||||
|
import com.suisung.mall.common.modules.pay.PayUserResource;
|
||||||
|
import com.suisung.mall.common.modules.product.*;
|
||||||
|
import com.suisung.mall.common.modules.sixun.SxSyncGoods;
|
||||||
|
import com.suisung.mall.common.modules.sixun.SxSyncVip;
|
||||||
|
import com.suisung.mall.common.modules.store.ShopStoreBase;
|
||||||
|
import com.suisung.mall.common.pojo.req.SyncThirdMemberReq;
|
||||||
|
import com.suisung.mall.common.utils.DateTimeUtils;
|
||||||
|
import com.suisung.mall.common.utils.I18nUtil;
|
||||||
|
import com.suisung.mall.common.utils.StringUtils;
|
||||||
|
import com.suisung.mall.shop.base.service.ShopBaseProductBrandService;
|
||||||
|
import com.suisung.mall.shop.base.service.ShopBaseProductCategoryService;
|
||||||
|
import com.suisung.mall.shop.base.service.ShopBaseProductTypeService;
|
||||||
|
import com.suisung.mall.shop.number.service.impl.ShopNumberSeqServiceImpl;
|
||||||
|
import com.suisung.mall.shop.product.service.ShopProductBaseService;
|
||||||
|
import com.suisung.mall.shop.product.service.impl.ShopProductBaseServiceImpl;
|
||||||
|
import com.suisung.mall.shop.product.service.impl.ShopProductItemServiceImpl;
|
||||||
|
import com.suisung.mall.shop.sixun.dto.SxGoosModel;
|
||||||
|
import com.suisung.mall.shop.store.service.ShopStoreBaseService;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.data.util.Pair;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
|
import java.math.BigDecimal;
|
||||||
|
import java.text.ParseException;
|
||||||
|
import java.util.*;
|
||||||
|
import java.util.concurrent.atomic.AtomicInteger;
|
||||||
|
|
||||||
|
@Service
|
||||||
|
public abstract class SyncBaseThirdSxAbstract{
|
||||||
|
private final Logger logger = LoggerFactory.getLogger(SyncBaseThirdSxAbstract.class);
|
||||||
|
@Autowired
|
||||||
|
private ShopBaseProductBrandService productBrandService;
|
||||||
|
@Autowired
|
||||||
|
private ShopBaseProductCategoryService productCategoryService;
|
||||||
|
@Autowired
|
||||||
|
private ShopBaseProductTypeService productTypeService;
|
||||||
|
@Autowired
|
||||||
|
private ShopProductBaseService shopProductBaseService;
|
||||||
|
@Autowired
|
||||||
|
private ShopStoreBaseService shopStoreBaseService;
|
||||||
|
@Autowired
|
||||||
|
private AccountService accountService;
|
||||||
|
@Autowired
|
||||||
|
private PayService payService;
|
||||||
|
@Autowired
|
||||||
|
private ShopNumberSeqServiceImpl shopNumberSeqServiceImpl;
|
||||||
|
@Autowired
|
||||||
|
private ShopProductBaseServiceImpl shopProductBaseServiceImpl;
|
||||||
|
@Autowired
|
||||||
|
private ShopProductItemServiceImpl shopProductItemServiceImpl;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 对商品分类进行保存
|
||||||
|
* @param list
|
||||||
|
* @param categoryListJSON
|
||||||
|
* @param storeId
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public int baseSaveOrUpdateShopBaseProductCategoryBatch(List<ShopBaseProductCategory> list ,JSONArray categoryListJSON,
|
||||||
|
String storeId){
|
||||||
|
int count = 0;
|
||||||
|
for (int i = 0; i < list.size(); i++) {
|
||||||
|
list.get(i).setStore_id(storeId); // app 记录传进来
|
||||||
|
list.get(i).setData_source(2); // 思迅数据来源
|
||||||
|
list.get(i).setCategory_is_enable(1);
|
||||||
|
|
||||||
|
JSONObject o = (JSONObject) categoryListJSON.get(i);
|
||||||
|
if (o != null) {
|
||||||
|
// 重要:分类类型处理(强调共性)
|
||||||
|
Integer typeId = 1001;
|
||||||
|
if (StrUtil.isNotBlank(o.getStr("product_type"))) {
|
||||||
|
ShopBaseProductType productType = productTypeService.getProductTypeByName(o.getStr("product_type"));
|
||||||
|
if (productType != null) {
|
||||||
|
list.get(i).setType_id(productType.getType_id());
|
||||||
|
} else {
|
||||||
|
// 新增一个类型
|
||||||
|
ShopBaseProductType newProductType = new ShopBaseProductType();
|
||||||
|
newProductType.setType_name(o.getStr("product_type"));
|
||||||
|
newProductType.setType_buildin(0);
|
||||||
|
|
||||||
|
if (productTypeService.save(newProductType)) {
|
||||||
|
typeId = newProductType.getType_id();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
list.get(i).setType_id(typeId);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// 处理(第一级)父类字段 产品分类
|
||||||
|
Integer firstParentId = 0;
|
||||||
|
if (StrUtil.isNotBlank(o.getStr("first_category_name"))) {
|
||||||
|
// TODO storeId 不判断一下吗?
|
||||||
|
ShopBaseProductCategory cate = productCategoryService.getCategoryByName(o.getStr("first_category_name"));
|
||||||
|
if (cate != null) {
|
||||||
|
list.get(i).setParent_id(cate.getCategory_id());
|
||||||
|
} else {
|
||||||
|
// 新增一个(第一级)父类
|
||||||
|
ShopBaseProductCategory firstCate = new ShopBaseProductCategory();
|
||||||
|
firstCate.setCategory_name(o.getStr("first_category_name"));
|
||||||
|
firstCate.setParent_id(0);
|
||||||
|
firstCate.setStore_id(storeId);
|
||||||
|
firstCate.setType_id(typeId);
|
||||||
|
firstCate.setData_source(2);
|
||||||
|
if (productCategoryService.saveOrUpdate(firstCate)) {
|
||||||
|
// 当前子分类的父类id
|
||||||
|
firstParentId = firstCate.getId();
|
||||||
|
list.get(i).setParent_id(firstParentId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
list.get(i).setParent_id(firstParentId);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 处理(第二级)父类字段 产品分类
|
||||||
|
if (StrUtil.isNotBlank(o.getStr("second_category_name"))) {
|
||||||
|
// TODO storeId 不判断一下吗?
|
||||||
|
ShopBaseProductCategory cate = productCategoryService.getCategoryByName(o.getStr("second_category_name"));
|
||||||
|
if (cate != null) {
|
||||||
|
list.get(i).setParent_id(cate.getCategory_id());
|
||||||
|
} else {
|
||||||
|
// 新增一个(第二级)父类
|
||||||
|
ShopBaseProductCategory secondCate = new ShopBaseProductCategory();
|
||||||
|
secondCate.setCategory_name(o.getStr("second_category_name"));
|
||||||
|
secondCate.setParent_id(firstParentId);
|
||||||
|
secondCate.setStore_id(storeId);
|
||||||
|
secondCate.setType_id(typeId);
|
||||||
|
secondCate.setData_source(2);
|
||||||
|
if (productCategoryService.saveOrUpdate(secondCate)) {
|
||||||
|
// 当前子分类的第二级父类id
|
||||||
|
list.get(i).setParent_id(secondCate.getId());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
ShopBaseProductCategory productCategoryTemp = productCategoryService.getCategoryByName(list.get(i).getParent_id(), list.get(i).getCategory_name(), list.get(i).getStore_id());
|
||||||
|
if (productCategoryTemp != null) {
|
||||||
|
// 更改记录
|
||||||
|
if (!productCategoryTemp.getCategory_image().equals(list.get(i).getCategory_image())
|
||||||
|
|| !productCategoryTemp.getType_id().equals(list.get(i).getType_id())
|
||||||
|
|| !productCategoryTemp.getCategory_virtual_enable().equals(list.get(i).getCategory_virtual_enable())
|
||||||
|
|| !productCategoryTemp.getCategory_commission_rate().equals(list.get(i).getCategory_commission_rate())
|
||||||
|
|| !productCategoryTemp.getCategory_show_type().equals(list.get(i).getCategory_show_type())) {
|
||||||
|
list.get(i).setCategory_id(productCategoryTemp.getCategory_id());
|
||||||
|
} else {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (productCategoryService.saveOrUpdate(list.get(i))) {
|
||||||
|
count++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return count;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 保存品牌
|
||||||
|
* @param goodBrandList
|
||||||
|
* @param storeId
|
||||||
|
* @param brandListJSON
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public int baseSaveOrUpdateShopBaseProductBrandBatch(List<ShopBaseProductBrand> goodBrandList,String storeId,JSONArray brandListJSON){
|
||||||
|
int count = 0;
|
||||||
|
for (int i = 0; i < goodBrandList.size(); i++) {
|
||||||
|
goodBrandList.get(i).setStore_id(Integer.valueOf(storeId)); // app 记录传进来
|
||||||
|
JSONObject o = (JSONObject) brandListJSON.get(i);
|
||||||
|
if (o != null && StrUtil.isNotBlank(o.getStr("category"))) {
|
||||||
|
// category 一般是父分类名
|
||||||
|
ShopBaseProductCategory cate = productCategoryService.getCategoryByName(o.getStr("category"));
|
||||||
|
if (cate != null) {
|
||||||
|
goodBrandList.get(i).setCategory_id(cate.getCategory_id());
|
||||||
|
} else {
|
||||||
|
// TODO 如果没有分类,是否新建?
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
count += productBrandService.saveOrUpdateBrand2(goodBrandList.get(i));
|
||||||
|
}
|
||||||
|
|
||||||
|
return count;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 保存商品
|
||||||
|
* @param goodsListJSON
|
||||||
|
* @param storeId
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public int baseSaveOrUpdateGoods(JSONArray goodsListJSON,String storeId){
|
||||||
|
int count = 0;
|
||||||
|
Map categoryMap= productCategoryService.getCategoryListByStoreId(storeId);//热数据加载
|
||||||
|
for (JSONObject jsonObj : goodsListJSON.jsonIter()) {
|
||||||
|
Date currentDate = new Date();
|
||||||
|
String cateGoryId="";
|
||||||
|
if(null!=categoryMap.get(jsonObj.get("first_category_name"))){
|
||||||
|
cateGoryId=categoryMap.get(jsonObj.get("first_category_name")).toString();
|
||||||
|
}
|
||||||
|
Integer categoryId = Convert.toInt(cateGoryId, 0);
|
||||||
|
Integer storeIdInt = Convert.toInt(storeId);
|
||||||
|
ShopStoreBase store_row = shopStoreBaseService.get(storeId);
|
||||||
|
if (store_row == null) {
|
||||||
|
throw new ApiException(I18nUtil._("无法获取店铺信息!"));
|
||||||
|
}
|
||||||
|
|
||||||
|
ShopProductBase shopProductBase = new ShopProductBase();
|
||||||
|
shopProductBase.setProduct_sale_time(Convert.toDate(DateUtil.current() + 600)); //10分钟
|
||||||
|
shopProductBase.setStore_id(storeIdInt);
|
||||||
|
|
||||||
|
shopProductBase.setProduct_number((String) jsonObj.get("product_number"));
|
||||||
|
shopProductBase.setProduct_name((String) jsonObj.get("product_name"));
|
||||||
|
shopProductBase.setStore_name(store_row.getStore_name());
|
||||||
|
shopProductBase.setProduct_tips("");
|
||||||
|
shopProductBase.setProduct_video("");
|
||||||
|
shopProductBase.setTransport_type_id(StateCode.DELIVERY_TYPE_SAME_CITY);
|
||||||
|
shopProductBase.setProduct_state_id(StateCode.PRODUCT_STATE_NORMAL);
|
||||||
|
shopProductBase.setProduct_inventory_lock(1002); //库存锁定(ENUM):1001-下单锁定;1002-支付锁定;
|
||||||
|
shopProductBase.setProduct_fx_enable(0); // 供应商是否允许批发市场分销
|
||||||
|
shopProductBase.setProduct_dist_enable(0); // 是否允许三级分销
|
||||||
|
shopProductBase.setProduct_from(1005);// 商品来源(ENUM):1000-发布;1001-天猫;1002-淘宝;1003-阿里巴巴;1004-京东;1005-思迅;
|
||||||
|
shopProductBase.setProduct_add_time(currentDate.getTime());
|
||||||
|
|
||||||
|
// ShopProductIndex
|
||||||
|
ShopProductIndex shopProductIndex = new ShopProductIndex();
|
||||||
|
shopProductIndex.setProduct_add_time(currentDate.getTime());
|
||||||
|
shopProductIndex.setProduct_sale_time(DateUtil.current() + 600); //10分钟
|
||||||
|
shopProductIndex.setStore_category_ids(""); // 店铺分类编号(DOT)
|
||||||
|
shopProductIndex.setProduct_tags("");// 商品标签(DOT)
|
||||||
|
shopProductIndex.setBrand_id(0);
|
||||||
|
shopProductIndex.setProduct_name(shopProductBase.getProduct_name()); // 产品名称:店铺平台先在对用表中检索后通过id检索,检索使用
|
||||||
|
shopProductIndex.setProduct_name_index(shopProductIndex.getProduct_name()); // 名称索引关键字(DOT)
|
||||||
|
shopProductIndex.setCategory_id(categoryId); // 商品分类
|
||||||
|
shopProductIndex.setProduct_fx_enable(0); // 供应商是否允许批发市场分销
|
||||||
|
shopProductIndex.setProduct_dist_enable(0); // 是否允许三级分销
|
||||||
|
shopProductIndex.setStore_id(storeIdInt);
|
||||||
|
shopProductIndex.setStore_type(store_row.getStore_type());
|
||||||
|
shopProductIndex.setKind_id(StateCode.PRODUCT_KIND_ENTITY);// 实体商品
|
||||||
|
shopProductIndex.setStore_is_open(store_row.getStore_is_open());
|
||||||
|
shopProductIndex.setStore_is_selfsupport(store_row.getStore_is_selfsupport());
|
||||||
|
shopProductIndex.setStore_longitude(store_row.getStore_longitude());
|
||||||
|
shopProductIndex.setStore_latitude(store_row.getStore_latitude());
|
||||||
|
|
||||||
|
shopProductIndex.setCard_type_id(0);
|
||||||
|
shopProductIndex.setVoucher_activity_id("");
|
||||||
|
shopProductIndex.setCoupon_type_id(0);// product_assist_data // 辅助属性值列(DOT)
|
||||||
|
shopProductIndex.setProduct_transport_id(String.valueOf(StateCode.DELIVERY_TYPE_SAME_CITY));
|
||||||
|
|
||||||
|
ShopBaseProductCategory category_row = productCategoryService.get(categoryId);
|
||||||
|
if (ObjectUtil.isNotEmpty(category_row)) {
|
||||||
|
Integer type_id = category_row.getType_id();
|
||||||
|
shopProductIndex.setType_id(type_id);
|
||||||
|
}
|
||||||
|
|
||||||
|
// shop_product_data
|
||||||
|
ShopProductData shopProductData = new ShopProductData();
|
||||||
|
// product_id // 产品id
|
||||||
|
shopProductData.setProduct_edit_time(currentDate);
|
||||||
|
|
||||||
|
// shop_product_detail
|
||||||
|
ShopProductDetail shopProductDetail = new ShopProductDetail();
|
||||||
|
shopProductDetail.setProduct_detail("");
|
||||||
|
shopProductDetail.setProduct_param("");
|
||||||
|
shopProductDetail.setProduct_service("");
|
||||||
|
shopProductDetail.setProduct_tags("");
|
||||||
|
|
||||||
|
// shop_product_info
|
||||||
|
ShopProductInfo shopProductInfo = new ShopProductInfo();
|
||||||
|
shopProductInfo.setProduct_number((String) jsonObj.get("product_number"));// SPU商家编码:货号
|
||||||
|
shopProductInfo.setProduct_assist("");
|
||||||
|
shopProductInfo.setProduct_spec("");
|
||||||
|
|
||||||
|
shopProductInfo.setProduct_buy_limit(0); // 不限购
|
||||||
|
//商品规格
|
||||||
|
shopProductInfo.setSpec_ids("");
|
||||||
|
|
||||||
|
List<ShopProductItem> shopProductItemList = new ArrayList<>();
|
||||||
|
ShopProductItem shopProductItem = new ShopProductItem();
|
||||||
|
shopProductItem.setStore_id(storeIdInt);
|
||||||
|
shopProductItem.setCategory_id(categoryId);
|
||||||
|
//零售价
|
||||||
|
shopProductItem.setItem_unit_price(BigDecimal.valueOf(jsonObj.getDouble("retail_price")));
|
||||||
|
shopProductItem.setItem_advice_price(BigDecimal.valueOf(jsonObj.getDouble("retail_price")));
|
||||||
|
shopProductItem.setItem_market_price(BigDecimal.valueOf(jsonObj.getDouble("original_price")));
|
||||||
|
//积分价
|
||||||
|
shopProductItem.setItem_unit_points(new BigDecimal(jsonObj.getInt("points")));
|
||||||
|
shopProductItem.setItem_quantity(jsonObj.getInt("stock")); // 库存
|
||||||
|
shopProductItem.setItem_quantity_frozen(0);
|
||||||
|
shopProductItem.setItem_number(jsonObj.getStr("product_number"));// SKU商家编码
|
||||||
|
shopProductItem.setItem_barcode(jsonObj.getStr("product_number")); // 条形码正常情况下就是货号
|
||||||
|
shopProductItem.setItem_is_default(1);
|
||||||
|
shopProductItem.setItem_enable(1);
|
||||||
|
|
||||||
|
shopProductItemList.add(shopProductItem);
|
||||||
|
|
||||||
|
// 保存数据
|
||||||
|
Pair<Boolean, String> pair = shopProductBaseService.saveProduct(shopProductBase, shopProductIndex, shopProductData, shopProductDetail, shopProductInfo, shopProductItemList, new ArrayList<ShopProductImage>(), new ShopProductValidPeriod(), new ArrayList<ShopProductAssistIndex>());
|
||||||
|
if (!pair.getFirst()) {
|
||||||
|
logger.error(pair.getSecond());
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
count += 1;
|
||||||
|
}
|
||||||
|
return count;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 保存会员
|
||||||
|
* @param memberList
|
||||||
|
* @param storeId
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public int baseSaveOrUpdateMemberBatch(List<SyncThirdMemberReq> memberList,String storeId){
|
||||||
|
int count = 0;
|
||||||
|
for (SyncThirdMemberReq member : memberList) {
|
||||||
|
// account_user_base
|
||||||
|
AccountUserBase accountUserBase = new AccountUserBase();
|
||||||
|
accountUserBase.setUser_account(StringUtils.generateUniqueCode(8));
|
||||||
|
accountUserBase.setUser_nickname(member.getUser_nickname());
|
||||||
|
accountUserBase.setUser_state(2);// 状态(ENUM):0-锁定;1-未激活;2-已激活;
|
||||||
|
accountUserBase.setUser_is_admin(CommonConstant.USER_TYPE_NORMAL);
|
||||||
|
accountUserBase.setStore_ids(storeId);
|
||||||
|
accountUserBase.setRights_group_id("0");// 普通用户,不是商家
|
||||||
|
accountUserBase.setUser_type(CommonConstant.USER_TYPE_NORMAL);
|
||||||
|
|
||||||
|
// 默认给了随机密码和盐,token
|
||||||
|
String user_key = IdUtil.simpleUUID();
|
||||||
|
String user_salt = IdUtil.simpleUUID();
|
||||||
|
String user_token = IdUtil.simpleUUID();
|
||||||
|
accountUserBase.setUser_salt(user_salt);
|
||||||
|
accountUserBase.setUser_token(user_token);
|
||||||
|
accountUserBase.setUser_key(user_key);
|
||||||
|
accountUserBase.setUser_password(SecureUtil.md5(user_salt + SecureUtil.md5(IdUtil.simpleUUID())));
|
||||||
|
|
||||||
|
// 判断店铺是不是存在该昵称的会员了?
|
||||||
|
Boolean exists = accountService.existByNickname(member.getUser_nickname(), storeId);
|
||||||
|
if (exists) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
AccountUserBase accountUserBase2 = accountService.saveOrUpdateUserBase2(accountUserBase);
|
||||||
|
|
||||||
|
// 新增用户记录后,返回 userId ?
|
||||||
|
Integer userId = accountUserBase2.getUser_id();
|
||||||
|
if (userId == null || userId <= 0) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// account_user_info
|
||||||
|
AccountUserInfo accountUserInfo = new AccountUserInfo();
|
||||||
|
accountUserInfo.setUser_id(userId);
|
||||||
|
accountUserInfo.setUser_type_id(0);
|
||||||
|
accountUserInfo.setUser_mobile(member.getUser_mobile());
|
||||||
|
accountUserInfo.setUser_level_card(member.getUser_level_card());
|
||||||
|
//user_level_id
|
||||||
|
accountUserInfo.setUser_level_id(1); // todo select id
|
||||||
|
accountUserInfo.setUser_gender(member.getUser_gender());
|
||||||
|
accountUserInfo.setUser_mobile(member.getUser_mobile());
|
||||||
|
accountUserInfo.setUser_intl(CommonConstant.IDD_ZH_CN);
|
||||||
|
accountUserInfo.setUser_birthday(DateTimeUtils.parseDate(member.getUser_birthday(), "yyyy-MM-dd"));
|
||||||
|
boolean success = accountService.saveOrUpdateUserInfo(accountUserInfo);
|
||||||
|
if (member.getUser_money() != null || member.getUser_points() != null) {
|
||||||
|
// pay_user_resource 用户支付资源,积分,余额
|
||||||
|
PayUserResource payUserResource = new PayUserResource();
|
||||||
|
payUserResource.setUser_id(userId);
|
||||||
|
payUserResource.setUser_money(member.getUser_money());
|
||||||
|
payUserResource.setUser_money_frozen(BigDecimal.ZERO);
|
||||||
|
payUserResource.setUser_points(member.getUser_points());
|
||||||
|
payUserResource.setUser_points_frozen(BigDecimal.ZERO);
|
||||||
|
success = payService.saveOrUpdatePayUserResource(payUserResource);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (success) {
|
||||||
|
count += 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return count;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* List<SxSyncVip> 转换为 List<SyncThirdMemberReq>
|
||||||
|
* @param sxSyncVipList
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public List<SyncThirdMemberReq> ConverList(List<SxSyncVip> sxSyncVipList){
|
||||||
|
List<SyncThirdMemberReq> syncThirdMemberReqList=new ArrayList<>();
|
||||||
|
if(CollUtil.isNotEmpty(sxSyncVipList)){
|
||||||
|
SyncThirdMemberReq syncThirdMemberReq=null;
|
||||||
|
for (SxSyncVip sxSyncVip : sxSyncVipList) {
|
||||||
|
syncThirdMemberReq = new SyncThirdMemberReq();
|
||||||
|
syncThirdMemberReq.setUser_nickname(sxSyncVip.getVip_name());
|
||||||
|
syncThirdMemberReq.setUser_realname(sxSyncVip.getVip_name());
|
||||||
|
if (sxSyncVip.getVip_name().equals("男")) {//todo 需要确认数据是不是这样判断
|
||||||
|
syncThirdMemberReq.setUser_gender(1);
|
||||||
|
}
|
||||||
|
if (sxSyncVip.getVip_name().equals("女")) {
|
||||||
|
syncThirdMemberReq.setUser_gender(2);
|
||||||
|
}
|
||||||
|
syncThirdMemberReq.setUser_mobile(sxSyncVip.getMobile());
|
||||||
|
syncThirdMemberReq.setUser_birthday(sxSyncVip.getBirthday());
|
||||||
|
syncThirdMemberReq.setUser_level(sxSyncVip.getCard_type());//todo 涉及会员等级字典转换
|
||||||
|
syncThirdMemberReq.setUser_level_card(sxSyncVip.getCard_no());
|
||||||
|
syncThirdMemberReq.setUser_points(sxSyncVip.getNow_acc_num());
|
||||||
|
syncThirdMemberReq.setUser_money(sxSyncVip.getResidual_amt());
|
||||||
|
if(sxSyncVip.getVip_date()!=null){
|
||||||
|
try {
|
||||||
|
syncThirdMemberReq.setJoin_time(DateUtils.parseDate(sxSyncVip.getVip_date()));
|
||||||
|
} catch (ParseException e) {
|
||||||
|
logger.info("时间转换异常{0}",e);
|
||||||
|
throw new RuntimeException(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return syncThirdMemberReqList;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 将List<sxSyncGoods>转换为List<SxGoosModel>
|
||||||
|
* @param sxSyncGoods
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public List<SxGoosModel> CvtToGoosModel(List<SxSyncGoods> sxSyncGoods){
|
||||||
|
if(CollectionUtil.isEmpty(sxSyncGoods)){
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
List<SxGoosModel> sxGoosModelList=new ArrayList<>();
|
||||||
|
SxGoosModel sxGoosModel=null;
|
||||||
|
for (SxSyncGoods sxSyncGood:sxSyncGoods){
|
||||||
|
sxGoosModel=new SxGoosModel();
|
||||||
|
sxGoosModel.setProduct_name(sxSyncGood.getItem_subname());
|
||||||
|
sxGoosModel.setProduct_number("");// todo
|
||||||
|
sxGoosModel.setProduct_barcode("");// todo
|
||||||
|
sxGoosModel.setFirst_category_name("");// todo
|
||||||
|
sxGoosModel.setSecond_category_name("");// todo
|
||||||
|
sxGoosModel.setThree_category_name("");// todo
|
||||||
|
sxGoosModel.setProduct_type("");// todo
|
||||||
|
sxGoosModel.setProduct_kind("");// todo
|
||||||
|
sxGoosModel.setCost_price(sxSyncGood.getPrice());//成本价 todo
|
||||||
|
sxGoosModel.setOriginal_price(sxSyncGood.getSale_price());//原价 todo
|
||||||
|
sxGoosModel.setOriginal_price(sxSyncGood.getSale_price());//零售价=原价?
|
||||||
|
sxGoosModel.setMember_price(sxSyncGood.getVip_price());//会员价
|
||||||
|
sxGoosModel.setStock(sxSyncGood.getStock());//库存 todo
|
||||||
|
sxGoosModel.setGross_margin(sxSyncGood.getGross_margin()); //毛利率 todo
|
||||||
|
sxGoosModel.setUnit(sxSyncGood.getUnit_no());//单位
|
||||||
|
sxGoosModel.setCan_piont(new BigDecimal(0));//可用积分 todo
|
||||||
|
sxGoosModel.setPoints(sxSyncGood.getVip_acc_num());//总积分 todo
|
||||||
|
sxGoosModel.setMnemonic(sxSyncGood.getItem_rem());//助记码 todo
|
||||||
|
sxGoosModel.setBuy_limit(0);//最大购买商品量 todo
|
||||||
|
sxGoosModel.setBrand_name("");//品牌 todo
|
||||||
|
sxGoosModel.setTags("");//标签 todo
|
||||||
|
|
||||||
|
sxGoosModel.setProduct_assist(Arrays.asList("时令果蔬","生鲜"));//帮助 todo
|
||||||
|
|
||||||
|
sxGoosModel.setProduct_spec(Collections.singletonList(sxSyncGood.getItem_size()));//规格
|
||||||
|
|
||||||
|
sxGoosModel.setProduct_value("");//商品卖点特征 todo
|
||||||
|
|
||||||
|
sxGoosModel.setProduct_video("");//商品视频 todo
|
||||||
|
|
||||||
|
sxGoosModel.setProduct_desc("");//商品描述 todo
|
||||||
|
|
||||||
|
sxGoosModel.setProduct_images(new ArrayList<>());//介绍图片 todo
|
||||||
|
|
||||||
|
sxGoosModel.setPromotion_detail(new ArrayList<>());//活动列表 todo
|
||||||
|
|
||||||
|
sxGoosModelList.add(sxGoosModel);
|
||||||
|
}
|
||||||
|
return sxGoosModelList;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 批量保存商品
|
||||||
|
* @param goodsListJSON
|
||||||
|
* @param storeId
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public int baseSaveOrUpdateGoodsBatch(JSONArray goodsListJSON,String storeId){
|
||||||
|
AtomicInteger resultCount = new AtomicInteger();
|
||||||
|
Map categoryMap= productCategoryService.getCategoryListByStoreId(storeId);//热数据加载
|
||||||
|
List<ShopProductBase> shopProductBaseList=new ArrayList<>();
|
||||||
|
List<ShopProductIndex> shopProductIndexList=new ArrayList<>(); ;
|
||||||
|
List<ShopProductData> shopProductDataList=new ArrayList<>(); ;
|
||||||
|
List<ShopProductDetail> shopProductDetailList=new ArrayList<>(); ;
|
||||||
|
List<ShopProductInfo> shopProductInfoList=new ArrayList<>(); ;
|
||||||
|
List<List<ShopProductItem>> shopProductItemLists=new ArrayList<>();
|
||||||
|
ShopStoreBase store_row = shopStoreBaseService.get(storeId);
|
||||||
|
if (store_row == null) {
|
||||||
|
throw new ApiException(I18nUtil._("无法获取店铺信息!"));
|
||||||
|
}
|
||||||
|
goodsListJSON.stream().parallel().forEach(object -> {
|
||||||
|
final JSONObject jsonObj= (JSONObject) object;
|
||||||
|
Date currentDate = new Date();
|
||||||
|
String cateGoryId="";
|
||||||
|
if(null!=categoryMap.get(jsonObj.get("first_category_name"))){
|
||||||
|
cateGoryId=categoryMap.get(jsonObj.get("first_category_name")).toString();
|
||||||
|
}
|
||||||
|
Integer categoryId = Convert.toInt(cateGoryId, 0);
|
||||||
|
Integer storeIdInt = Convert.toInt(storeId);
|
||||||
|
|
||||||
|
|
||||||
|
ShopProductBase shopProductBase = new ShopProductBase();
|
||||||
|
shopProductBase.setProduct_sale_time(Convert.toDate(DateUtil.current() + 600)); //10分钟
|
||||||
|
shopProductBase.setStore_id(storeIdInt);
|
||||||
|
|
||||||
|
shopProductBase.setProduct_number((String) jsonObj.get("product_number"));
|
||||||
|
shopProductBase.setProduct_name((String) jsonObj.get("product_name"));
|
||||||
|
shopProductBase.setStore_name(store_row.getStore_name());
|
||||||
|
shopProductBase.setProduct_tips("");
|
||||||
|
shopProductBase.setProduct_video("");
|
||||||
|
shopProductBase.setTransport_type_id(StateCode.DELIVERY_TYPE_SAME_CITY);
|
||||||
|
shopProductBase.setProduct_state_id(StateCode.PRODUCT_STATE_NORMAL);
|
||||||
|
shopProductBase.setProduct_inventory_lock(1002); //库存锁定(ENUM):1001-下单锁定;1002-支付锁定;
|
||||||
|
shopProductBase.setProduct_fx_enable(0); // 供应商是否允许批发市场分销
|
||||||
|
shopProductBase.setProduct_dist_enable(0); // 是否允许三级分销
|
||||||
|
shopProductBase.setProduct_from(1005);// 商品来源(ENUM):1000-发布;1001-天猫;1002-淘宝;1003-阿里巴巴;1004-京东;1005-思迅;
|
||||||
|
shopProductBase.setProduct_add_time(currentDate.getTime());
|
||||||
|
|
||||||
|
// ShopProductIndex
|
||||||
|
ShopProductIndex shopProductIndex = new ShopProductIndex();
|
||||||
|
shopProductIndex.setProduct_add_time(currentDate.getTime());
|
||||||
|
shopProductIndex.setProduct_sale_time(DateUtil.current() + 600); //10分钟
|
||||||
|
shopProductIndex.setStore_category_ids(""); // 店铺分类编号(DOT)
|
||||||
|
shopProductIndex.setProduct_tags("");// 商品标签(DOT)
|
||||||
|
shopProductIndex.setBrand_id(0);
|
||||||
|
shopProductIndex.setProduct_name(shopProductBase.getProduct_name()); // 产品名称:店铺平台先在对用表中检索后通过id检索,检索使用
|
||||||
|
shopProductIndex.setProduct_name_index(shopProductIndex.getProduct_name()); // 名称索引关键字(DOT)
|
||||||
|
shopProductIndex.setCategory_id(categoryId); // 商品分类
|
||||||
|
shopProductIndex.setProduct_fx_enable(0); // 供应商是否允许批发市场分销
|
||||||
|
shopProductIndex.setProduct_dist_enable(0); // 是否允许三级分销
|
||||||
|
shopProductIndex.setStore_id(storeIdInt);
|
||||||
|
shopProductIndex.setStore_type(store_row.getStore_type());
|
||||||
|
shopProductIndex.setKind_id(StateCode.PRODUCT_KIND_ENTITY);// 实体商品
|
||||||
|
shopProductIndex.setStore_is_open(store_row.getStore_is_open());
|
||||||
|
shopProductIndex.setStore_is_selfsupport(store_row.getStore_is_selfsupport());
|
||||||
|
shopProductIndex.setStore_longitude(store_row.getStore_longitude());
|
||||||
|
shopProductIndex.setStore_latitude(store_row.getStore_latitude());
|
||||||
|
|
||||||
|
shopProductIndex.setCard_type_id(0);
|
||||||
|
shopProductIndex.setVoucher_activity_id("");
|
||||||
|
shopProductIndex.setCoupon_type_id(0);// product_assist_data // 辅助属性值列(DOT)
|
||||||
|
shopProductIndex.setProduct_transport_id(String.valueOf(StateCode.DELIVERY_TYPE_SAME_CITY));
|
||||||
|
|
||||||
|
ShopBaseProductCategory category_row = productCategoryService.get(categoryId);
|
||||||
|
if (ObjectUtil.isNotEmpty(category_row)) {
|
||||||
|
Integer type_id = category_row.getType_id();
|
||||||
|
shopProductIndex.setType_id(type_id);
|
||||||
|
}
|
||||||
|
|
||||||
|
// shop_product_data
|
||||||
|
ShopProductData shopProductData = new ShopProductData();
|
||||||
|
// product_id // 产品id
|
||||||
|
shopProductData.setProduct_edit_time(currentDate);
|
||||||
|
|
||||||
|
// shop_product_detail
|
||||||
|
ShopProductDetail shopProductDetail = new ShopProductDetail();
|
||||||
|
shopProductDetail.setProduct_detail("");
|
||||||
|
shopProductDetail.setProduct_param("");
|
||||||
|
shopProductDetail.setProduct_service("");
|
||||||
|
shopProductDetail.setProduct_tags("");
|
||||||
|
|
||||||
|
// shop_product_info
|
||||||
|
ShopProductInfo shopProductInfo = new ShopProductInfo();
|
||||||
|
shopProductInfo.setProduct_number((String) jsonObj.get("product_number"));// SPU商家编码:货号
|
||||||
|
shopProductInfo.setProduct_assist("");
|
||||||
|
shopProductInfo.setProduct_spec("");
|
||||||
|
|
||||||
|
shopProductInfo.setProduct_buy_limit(0); // 不限购
|
||||||
|
//商品规格
|
||||||
|
shopProductInfo.setSpec_ids("");
|
||||||
|
|
||||||
|
List<ShopProductItem> shopProductItemList = new ArrayList<>();
|
||||||
|
ShopProductItem shopProductItem = new ShopProductItem();
|
||||||
|
shopProductItem.setStore_id(storeIdInt);
|
||||||
|
shopProductItem.setCategory_id(categoryId);
|
||||||
|
//零售价
|
||||||
|
shopProductItem.setItem_unit_price(BigDecimal.valueOf(jsonObj.getDouble("retail_price")));
|
||||||
|
shopProductItem.setItem_advice_price(BigDecimal.valueOf(jsonObj.getDouble("retail_price")));
|
||||||
|
shopProductItem.setItem_market_price(BigDecimal.valueOf(jsonObj.getDouble("original_price")));
|
||||||
|
//积分价
|
||||||
|
shopProductItem.setItem_unit_points(new BigDecimal(jsonObj.getInt("points")));
|
||||||
|
shopProductItem.setItem_quantity(jsonObj.getInt("stock")); // 库存
|
||||||
|
shopProductItem.setItem_quantity_frozen(0);
|
||||||
|
shopProductItem.setItem_number(jsonObj.getStr("product_number"));// SKU商家编码
|
||||||
|
shopProductItem.setItem_barcode(jsonObj.getStr("product_number")); // 条形码正常情况下就是货号
|
||||||
|
shopProductItem.setItem_is_default(1);
|
||||||
|
shopProductItem.setItem_enable(1);
|
||||||
|
|
||||||
|
//添加数据到list
|
||||||
|
synchronized(shopProductBaseList){
|
||||||
|
shopProductItemList.add(shopProductItem);
|
||||||
|
shopProductBaseList.add(shopProductBase);
|
||||||
|
shopProductIndexList.add(shopProductIndex);
|
||||||
|
shopProductDataList.add(shopProductData);
|
||||||
|
shopProductDetailList.add(shopProductDetail);
|
||||||
|
shopProductInfoList.add(shopProductInfo);
|
||||||
|
shopProductItemLists.add(shopProductItemList);
|
||||||
|
}
|
||||||
|
// synchronized(shopProductIndexList){
|
||||||
|
// shopProductIndexList.add(shopProductIndex);
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// synchronized(shopProductDataList){
|
||||||
|
// shopProductDataList.add(shopProductData);
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// synchronized(shopProductDetailList){
|
||||||
|
// shopProductDetailList.add(shopProductDetail);
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// synchronized(shopProductInfoList){
|
||||||
|
// shopProductInfoList.add(shopProductInfo);
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// synchronized(shopProductItemLists){
|
||||||
|
// shopProductItemLists.add(shopProductItemList);
|
||||||
|
// }
|
||||||
|
|
||||||
|
// 保存数据
|
||||||
|
|
||||||
|
resultCount.addAndGet(1);
|
||||||
|
});
|
||||||
|
shopProductBaseService.saveProductBatch(shopProductBaseList,shopProductIndexList,shopProductDataList,shopProductDetailList,shopProductInfoList,shopProductItemLists,
|
||||||
|
new ArrayList<List<ShopProductImage>>(),
|
||||||
|
new ArrayList<ShopProductValidPeriod>(),
|
||||||
|
new ArrayList<ShopProductAssistIndex>());
|
||||||
|
|
||||||
|
return resultCount.get();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public void syncPrimaryKey(){
|
||||||
|
|
||||||
|
List<ShopNumberSeq> shopNumberSeqList=new ArrayList<>();
|
||||||
|
QueryWrapper<ShopProductBase> baseWrapper=new QueryWrapper<>();
|
||||||
|
baseWrapper.select("MAX(product_id) as product_id");
|
||||||
|
ShopProductBase shopProductBase= shopProductBaseServiceImpl.getOne(baseWrapper);
|
||||||
|
Long productId= shopProductBase.getProduct_id()+1;
|
||||||
|
//QueryWrapper<ShopNumberSeq> baseSeWrapper=new QueryWrapper();
|
||||||
|
//baseSeWrapper.eq("prefix", "product_id");
|
||||||
|
ShopNumberSeq shopNumberSeqBase= new ShopNumberSeq();
|
||||||
|
shopNumberSeqBase.setPrefix("product_id");
|
||||||
|
shopNumberSeqBase.setNumber(productId);
|
||||||
|
//shopNumberSeqServiceImpl.edit(shopNumberSeqBase,baseWrapper);
|
||||||
|
//查询产品item
|
||||||
|
QueryWrapper<ShopProductItem> itemQuery=new QueryWrapper<>();
|
||||||
|
itemQuery.select("MAX(item_id) as item_id");
|
||||||
|
ShopProductItem shopProductItem= shopProductItemServiceImpl.getOne(itemQuery);
|
||||||
|
Long itemtId= shopProductItem.getItem_id()+1;
|
||||||
|
// QueryWrapper<ShopNumberSeq> itemWrapper=new QueryWrapper();
|
||||||
|
//itemWrapper.eq("prefix", "item_id");
|
||||||
|
ShopNumberSeq shopNumberSeqItem= new ShopNumberSeq();
|
||||||
|
shopNumberSeqItem.setNumber(itemtId);
|
||||||
|
shopNumberSeqItem.setPrefix("item_id");
|
||||||
|
shopNumberSeqList.add(shopNumberSeqBase);
|
||||||
|
shopNumberSeqList.add(shopNumberSeqItem);
|
||||||
|
shopNumberSeqServiceImpl.batchUpdateSeq(shopNumberSeqList);
|
||||||
|
shopNumberSeqServiceImpl.clearRelateGoodsId();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
@ -8,4 +8,6 @@ import org.springframework.stereotype.Service;
|
|||||||
|
|
||||||
@Service
|
@Service
|
||||||
public class SyncConfigServiceImpl extends ServiceImpl<SyncConfigServiceMapper, SyncConfig> implements SyncConfigService {
|
public class SyncConfigServiceImpl extends ServiceImpl<SyncConfigServiceMapper, SyncConfig> implements SyncConfigService {
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -0,0 +1,23 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2025. Lorem ipsum dolor sit amet, consectetur adipiscing elit.
|
||||||
|
* Morbi non lorem porttitor neque feugiat blandit. Ut vitae ipsum eget quam lacinia accumsan.
|
||||||
|
* Etiam sed turpis ac ipsum condimentum fringilla. Maecenas magna.
|
||||||
|
* Proin dapibus sapien vel ante. Aliquam erat volutpat. Pellentesque sagittis ligula eget metus.
|
||||||
|
* Vestibulum commodo. Ut rhoncus gravida arcu.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.suisung.mall.shop.sync.service.impl;
|
||||||
|
import com.suisung.mall.common.modules.sync.SyncFileLog;
|
||||||
|
import com.suisung.mall.core.web.service.impl.BaseServiceImpl;
|
||||||
|
import com.suisung.mall.shop.sync.mapper.SyncFileLogMapper;
|
||||||
|
|
||||||
|
import com.suisung.mall.shop.sync.service.SyncFileLogService;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@Service
|
||||||
|
public class SyncFileLogServiceImpl extends BaseServiceImpl<SyncFileLogMapper, SyncFileLog> implements SyncFileLogService {
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
@ -9,79 +9,120 @@
|
|||||||
package com.suisung.mall.shop.sync.service.impl;
|
package com.suisung.mall.shop.sync.service.impl;
|
||||||
|
|
||||||
import cn.hutool.core.collection.CollUtil;
|
import cn.hutool.core.collection.CollUtil;
|
||||||
|
|
||||||
|
import cn.hutool.core.collection.CollectionUtil;
|
||||||
import cn.hutool.core.convert.Convert;
|
import cn.hutool.core.convert.Convert;
|
||||||
import cn.hutool.core.date.DateUtil;
|
|
||||||
import cn.hutool.core.util.IdUtil;
|
|
||||||
import cn.hutool.core.util.ObjectUtil;
|
import cn.hutool.core.util.ObjectUtil;
|
||||||
import cn.hutool.core.util.StrUtil;
|
import cn.hutool.core.util.StrUtil;
|
||||||
import cn.hutool.crypto.SecureUtil;
|
import cn.hutool.http.HttpException;
|
||||||
import cn.hutool.json.JSONArray;
|
import cn.hutool.json.JSONArray;
|
||||||
import cn.hutool.json.JSONObject;
|
|
||||||
import cn.hutool.json.JSONUtil;
|
import cn.hutool.json.JSONUtil;
|
||||||
|
|
||||||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||||
|
|
||||||
|
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
|
||||||
import com.suisung.mall.common.api.CommonResult;
|
import com.suisung.mall.common.api.CommonResult;
|
||||||
import com.suisung.mall.common.api.StateCode;
|
|
||||||
import com.suisung.mall.common.constant.CommonConstant;
|
import com.suisung.mall.common.domain.UserDto;
|
||||||
import com.suisung.mall.common.exception.ApiException;
|
import com.suisung.mall.common.enums.DicEnum;
|
||||||
import com.suisung.mall.common.feignService.AccountService;
|
|
||||||
import com.suisung.mall.common.feignService.PayService;
|
|
||||||
import com.suisung.mall.common.modules.account.AccountUserBase;
|
|
||||||
import com.suisung.mall.common.modules.account.AccountUserInfo;
|
|
||||||
import com.suisung.mall.common.modules.base.ShopBaseProductBrand;
|
import com.suisung.mall.common.modules.base.ShopBaseProductBrand;
|
||||||
import com.suisung.mall.common.modules.base.ShopBaseProductCategory;
|
import com.suisung.mall.common.modules.base.ShopBaseProductCategory;
|
||||||
import com.suisung.mall.common.modules.base.ShopBaseProductType;
|
|
||||||
import com.suisung.mall.common.modules.pay.PayUserResource;
|
import com.suisung.mall.common.modules.sixun.SxSyncGoods;
|
||||||
import com.suisung.mall.common.modules.product.*;
|
import com.suisung.mall.common.modules.sixun.SxSyncVip;
|
||||||
import com.suisung.mall.common.modules.store.ShopStoreBase;
|
import com.suisung.mall.common.modules.sync.StoreDbConfig;
|
||||||
import com.suisung.mall.common.modules.sync.SyncApp;
|
import com.suisung.mall.common.modules.sync.SyncApp;
|
||||||
import com.suisung.mall.common.modules.sync.SyncConfig;
|
import com.suisung.mall.common.modules.sync.SyncConfig;
|
||||||
|
import com.suisung.mall.common.modules.sync.SyncFileLog;
|
||||||
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 com.suisung.mall.common.utils.DateTimeUtils;
|
|
||||||
|
import com.suisung.mall.common.utils.ContextUtil;
|
||||||
import com.suisung.mall.common.utils.I18nUtil;
|
import com.suisung.mall.common.utils.I18nUtil;
|
||||||
|
|
||||||
import com.suisung.mall.common.utils.StringUtils;
|
import com.suisung.mall.common.utils.StringUtils;
|
||||||
import com.suisung.mall.shop.base.service.ShopBaseProductBrandService;
|
import com.suisung.mall.core.web.service.RedisService;
|
||||||
import com.suisung.mall.shop.base.service.ShopBaseProductCategoryService;
|
import com.suisung.mall.shop.number.service.ShopNumberSeqService;
|
||||||
import com.suisung.mall.shop.base.service.ShopBaseProductTypeService;
|
import com.suisung.mall.shop.page.service.OssService;
|
||||||
import com.suisung.mall.shop.product.service.ShopProductBaseService;
|
import com.suisung.mall.shop.sixun.dao.SxDataDao;
|
||||||
import com.suisung.mall.shop.product.service.impl.ShopProductBaseServiceImpl;
|
import com.suisung.mall.shop.sixun.dto.DataBaseInfo;
|
||||||
import com.suisung.mall.shop.store.service.ShopStoreBaseService;
|
import com.suisung.mall.shop.sixun.dto.SxCategoryModel;
|
||||||
import com.suisung.mall.shop.sync.service.SyncAppService;
|
import com.suisung.mall.shop.sixun.dto.SxGoosModel;
|
||||||
import com.suisung.mall.shop.sync.service.SyncConfigService;
|
import com.suisung.mall.shop.sixun.service.SxSyncCategoryService;
|
||||||
import com.suisung.mall.shop.sync.service.SyncThirdDataService;
|
import com.suisung.mall.shop.sixun.service.SxSyncGoodsService;
|
||||||
|
import com.suisung.mall.shop.sixun.service.SxSyncVipService;
|
||||||
|
import com.suisung.mall.shop.sixun.utils.CommonUtil;
|
||||||
|
import com.suisung.mall.shop.sixun.utils.FileUtils;
|
||||||
|
import com.suisung.mall.shop.sync.Utils.CryptoUtils;
|
||||||
|
import com.suisung.mall.shop.sync.Utils.ThreadFileUtils;
|
||||||
|
import com.suisung.mall.shop.sync.keymanage.RedisKey;
|
||||||
|
import com.suisung.mall.shop.sync.service.*;
|
||||||
|
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
import org.springframework.data.util.Pair;
|
|
||||||
import org.springframework.jdbc.core.JdbcTemplate;
|
|
||||||
import org.springframework.jdbc.datasource.DriverManagerDataSource;
|
|
||||||
import org.springframework.stereotype.Service;
|
|
||||||
|
|
||||||
import java.math.BigDecimal;
|
import org.springframework.beans.factory.annotation.Value;
|
||||||
|
import org.springframework.core.io.ByteArrayResource;
|
||||||
|
import org.springframework.core.io.FileSystemResource;
|
||||||
|
import org.springframework.core.io.InputStreamSource;
|
||||||
|
import org.springframework.core.io.Resource;
|
||||||
|
import org.springframework.http.HttpHeaders;
|
||||||
|
import org.springframework.http.HttpStatus;
|
||||||
|
import org.springframework.http.MediaType;
|
||||||
|
import org.springframework.http.ResponseEntity;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
import org.springframework.web.multipart.MultipartFile;
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.nio.charset.StandardCharsets;
|
||||||
|
import java.nio.file.Files;
|
||||||
|
import java.nio.file.Path;
|
||||||
|
import java.nio.file.Paths;
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
|
import java.util.concurrent.*;
|
||||||
|
import java.util.concurrent.atomic.AtomicInteger;
|
||||||
|
import java.util.concurrent.atomic.AtomicLong;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@Service
|
@Service
|
||||||
public class SyncThirdDataServiceImpl implements SyncThirdDataService {
|
public class SyncThirdDataServiceImpl extends SyncBaseThirdSxAbstract implements SyncThirdDataService {
|
||||||
private final Logger logger = LoggerFactory.getLogger(ShopProductBaseServiceImpl.class);
|
private static Logger logger = LoggerFactory.getLogger(SyncThirdDataServiceImpl.class);
|
||||||
private final int limitCnt = 300;
|
private final int limitCnt = 300;
|
||||||
@Autowired
|
@Value("${client.path}")
|
||||||
private ShopBaseProductBrandService productBrandService;
|
public String clientPath;
|
||||||
@Autowired
|
|
||||||
private ShopBaseProductCategoryService productCategoryService;
|
|
||||||
@Autowired
|
|
||||||
private ShopBaseProductTypeService productTypeService;
|
|
||||||
@Autowired
|
|
||||||
private AccountService accountService;
|
|
||||||
@Autowired
|
|
||||||
private PayService payService;
|
|
||||||
@Autowired
|
|
||||||
private ShopProductBaseService shopProductBaseService;
|
|
||||||
@Autowired
|
|
||||||
private ShopStoreBaseService shopStoreBaseService;
|
|
||||||
@Autowired
|
@Autowired
|
||||||
private SyncAppService syncAppService;
|
private SyncAppService syncAppService;
|
||||||
@Autowired
|
@Autowired
|
||||||
private SyncConfigService syncConfigService;
|
private SyncConfigService syncConfigService;
|
||||||
|
@Autowired
|
||||||
|
private SxSyncCategoryService sxSyncCategoryService;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private SxSyncGoodsService sxSyncGoodsService;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private SxSyncVipService sxSyncVipService;
|
||||||
|
@Autowired
|
||||||
|
private ShopNumberSeqService shopNumberSeqService;
|
||||||
|
private final AtomicLong threadNum=new AtomicLong(0);
|
||||||
|
@Autowired
|
||||||
|
private SyncFileLogService syncFileLogService;
|
||||||
|
@Autowired
|
||||||
|
private OssService ossService;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private RedisService redisService;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private StoreDbConfigService storeDbConfigService;
|
||||||
|
|
||||||
|
private final static String CLIENTFILEPATH="sxclient/";
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 批量保存商品的分类
|
* 批量保存商品的分类
|
||||||
@ -111,103 +152,7 @@ public class SyncThirdDataServiceImpl implements SyncThirdDataService {
|
|||||||
return new ThirdApiRes().fail(1004, I18nUtil._("单次同步记录最多" + limitCnt + "条!"));
|
return new ThirdApiRes().fail(1004, I18nUtil._("单次同步记录最多" + limitCnt + "条!"));
|
||||||
}
|
}
|
||||||
|
|
||||||
int count = 0;
|
int count=baseSaveOrUpdateShopBaseProductCategoryBatch(list,categoryListJSON,storeId);
|
||||||
for (int i = 0; i < list.size(); i++) {
|
|
||||||
list.get(i).setStore_id(storeId); // app 记录传进来
|
|
||||||
list.get(i).setData_source(2); // 思迅数据来源
|
|
||||||
list.get(i).setCategory_is_enable(1);
|
|
||||||
|
|
||||||
JSONObject o = (JSONObject) categoryListJSON.get(i);
|
|
||||||
if (o != null) {
|
|
||||||
|
|
||||||
// 重要:分类类型处理(强调共性)
|
|
||||||
Integer typeId = 1001;
|
|
||||||
if (StrUtil.isNotBlank(o.getStr("product_type"))) {
|
|
||||||
ShopBaseProductType productType = productTypeService.getProductTypeByName(o.getStr("product_type"));
|
|
||||||
if (productType != null) {
|
|
||||||
list.get(i).setType_id(productType.getType_id());
|
|
||||||
} else {
|
|
||||||
// 新增一个类型
|
|
||||||
ShopBaseProductType newProductType = new ShopBaseProductType();
|
|
||||||
newProductType.setType_name(o.getStr("product_type"));
|
|
||||||
newProductType.setType_buildin(0);
|
|
||||||
|
|
||||||
if (productTypeService.save(newProductType)) {
|
|
||||||
typeId = newProductType.getType_id();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
list.get(i).setType_id(typeId);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// 处理(第一级)父类字段 产品分类
|
|
||||||
Integer firstParentId = 0;
|
|
||||||
if (StrUtil.isNotBlank(o.getStr("first_category_name"))) {
|
|
||||||
// TODO storeId 不判断一下吗?
|
|
||||||
ShopBaseProductCategory cate = productCategoryService.getCategoryByName(o.getStr("first_category_name"));
|
|
||||||
if (cate != null) {
|
|
||||||
list.get(i).setParent_id(cate.getCategory_id());
|
|
||||||
} else {
|
|
||||||
// 新增一个(第一级)父类
|
|
||||||
ShopBaseProductCategory firstCate = new ShopBaseProductCategory();
|
|
||||||
firstCate.setCategory_name(o.getStr("first_category_name"));
|
|
||||||
firstCate.setParent_id(0);
|
|
||||||
firstCate.setStore_id(storeId);
|
|
||||||
firstCate.setType_id(typeId);
|
|
||||||
firstCate.setData_source(2);
|
|
||||||
if (productCategoryService.saveOrUpdate(firstCate)) {
|
|
||||||
// 当前子分类的父类id
|
|
||||||
firstParentId = firstCate.getId();
|
|
||||||
list.get(i).setParent_id(firstParentId);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
list.get(i).setParent_id(firstParentId);
|
|
||||||
}
|
|
||||||
|
|
||||||
// 处理(第二级)父类字段 产品分类
|
|
||||||
if (StrUtil.isNotBlank(o.getStr("second_category_name"))) {
|
|
||||||
// TODO storeId 不判断一下吗?
|
|
||||||
ShopBaseProductCategory cate = productCategoryService.getCategoryByName(o.getStr("second_category_name"));
|
|
||||||
if (cate != null) {
|
|
||||||
list.get(i).setParent_id(cate.getCategory_id());
|
|
||||||
} else {
|
|
||||||
// 新增一个(第二级)父类
|
|
||||||
ShopBaseProductCategory secondCate = new ShopBaseProductCategory();
|
|
||||||
secondCate.setCategory_name(o.getStr("second_category_name"));
|
|
||||||
secondCate.setParent_id(firstParentId);
|
|
||||||
secondCate.setStore_id(storeId);
|
|
||||||
secondCate.setType_id(typeId);
|
|
||||||
secondCate.setData_source(2);
|
|
||||||
if (productCategoryService.saveOrUpdate(secondCate)) {
|
|
||||||
// 当前子分类的第二级父类id
|
|
||||||
list.get(i).setParent_id(secondCate.getId());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
ShopBaseProductCategory productCategoryTemp = productCategoryService.getCategoryByName(list.get(i).getParent_id(), list.get(i).getCategory_name(), list.get(i).getStore_id());
|
|
||||||
if (productCategoryTemp != null) {
|
|
||||||
// 更改记录
|
|
||||||
if (!productCategoryTemp.getCategory_image().equals(list.get(i).getCategory_image())
|
|
||||||
|| !productCategoryTemp.getType_id().equals(list.get(i).getType_id())
|
|
||||||
|| !productCategoryTemp.getCategory_virtual_enable().equals(list.get(i).getCategory_virtual_enable())
|
|
||||||
|| !productCategoryTemp.getCategory_commission_rate().equals(list.get(i).getCategory_commission_rate())
|
|
||||||
|| !productCategoryTemp.getCategory_show_type().equals(list.get(i).getCategory_show_type())) {
|
|
||||||
list.get(i).setCategory_id(productCategoryTemp.getCategory_id());
|
|
||||||
} else {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (productCategoryService.saveOrUpdate(list.get(i))) {
|
|
||||||
count++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Map<String, Integer> resp = new HashMap<>();
|
Map<String, Integer> resp = new HashMap<>();
|
||||||
resp.put("count", count);
|
resp.put("count", count);
|
||||||
|
|
||||||
@ -242,23 +187,7 @@ public class SyncThirdDataServiceImpl implements SyncThirdDataService {
|
|||||||
return new ThirdApiRes().fail(1004, I18nUtil._("单次同步记录最多" + limitCnt + "条!"));
|
return new ThirdApiRes().fail(1004, I18nUtil._("单次同步记录最多" + limitCnt + "条!"));
|
||||||
}
|
}
|
||||||
|
|
||||||
int count = 0;
|
int count=baseSaveOrUpdateShopBaseProductBrandBatch(goodBrandList,storeId,brandListJSON);
|
||||||
for (int i = 0; i < goodBrandList.size(); i++) {
|
|
||||||
goodBrandList.get(i).setStore_id(Integer.valueOf(storeId)); // app 记录传进来
|
|
||||||
JSONObject o = (JSONObject) brandListJSON.get(i);
|
|
||||||
if (o != null && StrUtil.isNotBlank(o.getStr("category"))) {
|
|
||||||
// category 一般是父分类名
|
|
||||||
ShopBaseProductCategory cate = productCategoryService.getCategoryByName(o.getStr("category"));
|
|
||||||
if (cate != null) {
|
|
||||||
goodBrandList.get(i).setCategory_id(cate.getCategory_id());
|
|
||||||
} else {
|
|
||||||
// TODO 如果没有分类,是否新建?
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
count += productBrandService.saveOrUpdateBrand2(goodBrandList.get(i));
|
|
||||||
}
|
|
||||||
|
|
||||||
Map<String, Integer> resp = new HashMap<>();
|
Map<String, Integer> resp = new HashMap<>();
|
||||||
resp.put("count", count);
|
resp.put("count", count);
|
||||||
|
|
||||||
@ -276,7 +205,6 @@ public class SyncThirdDataServiceImpl implements SyncThirdDataService {
|
|||||||
if (StrUtil.isBlank(appKey) || StrUtil.isBlank(sign) || ObjectUtil.isEmpty(goodsListJSON)) {
|
if (StrUtil.isBlank(appKey) || StrUtil.isBlank(sign) || ObjectUtil.isEmpty(goodsListJSON)) {
|
||||||
return new ThirdApiRes().fail(1003, I18nUtil._("缺少必要参数!"));
|
return new ThirdApiRes().fail(1003, I18nUtil._("缺少必要参数!"));
|
||||||
}
|
}
|
||||||
|
|
||||||
// 验签、appid,必要参数判断
|
// 验签、appid,必要参数判断
|
||||||
SyncApp syncApp = syncAppService.checkAppSign(appKey, sign, goodsListJSON.toString());
|
SyncApp syncApp = syncAppService.checkAppSign(appKey, sign, goodsListJSON.toString());
|
||||||
if (syncApp == null) {
|
if (syncApp == null) {
|
||||||
@ -288,115 +216,7 @@ public class SyncThirdDataServiceImpl implements SyncThirdDataService {
|
|||||||
return new ThirdApiRes().fail(1004, I18nUtil._("单次同步记录最多" + limitCnt + "条!"));
|
return new ThirdApiRes().fail(1004, I18nUtil._("单次同步记录最多" + limitCnt + "条!"));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int count=baseSaveOrUpdateGoods(goodsListJSON,storeId);
|
||||||
int count = 0;
|
|
||||||
for (JSONObject jsonObj : goodsListJSON.jsonIter()) {
|
|
||||||
Date currentDate = new Date();
|
|
||||||
|
|
||||||
Integer categoryId = Convert.toInt(jsonObj.get("first_category_name"), 0);
|
|
||||||
Integer storeIdInt = Convert.toInt(storeId);
|
|
||||||
ShopStoreBase store_row = shopStoreBaseService.get(storeId);
|
|
||||||
if (store_row == null) {
|
|
||||||
throw new ApiException(I18nUtil._("无法获取店铺信息!"));
|
|
||||||
}
|
|
||||||
|
|
||||||
ShopProductBase shopProductBase = new ShopProductBase();
|
|
||||||
shopProductBase.setProduct_sale_time(Convert.toDate(DateUtil.current() + 600)); //10分钟
|
|
||||||
shopProductBase.setStore_id(storeIdInt);
|
|
||||||
shopProductBase.setProduct_number((String) jsonObj.get("product_number"));
|
|
||||||
shopProductBase.setProduct_name((String) jsonObj.get("product_name"));
|
|
||||||
shopProductBase.setStore_name(store_row.getStore_name());
|
|
||||||
shopProductBase.setProduct_tips("");
|
|
||||||
shopProductBase.setProduct_video("");
|
|
||||||
shopProductBase.setTransport_type_id(StateCode.DELIVERY_TYPE_SAME_CITY);
|
|
||||||
shopProductBase.setProduct_state_id(StateCode.PRODUCT_STATE_NORMAL);
|
|
||||||
shopProductBase.setProduct_inventory_lock(1002); //库存锁定(ENUM):1001-下单锁定;1002-支付锁定;
|
|
||||||
shopProductBase.setProduct_fx_enable(0); // 供应商是否允许批发市场分销
|
|
||||||
shopProductBase.setProduct_dist_enable(0); // 是否允许三级分销
|
|
||||||
shopProductBase.setProduct_from(1005);// 商品来源(ENUM):1000-发布;1001-天猫;1002-淘宝;1003-阿里巴巴;1004-京东;1005-思迅;
|
|
||||||
shopProductBase.setProduct_add_time(currentDate.getTime());
|
|
||||||
|
|
||||||
// ShopProductIndex
|
|
||||||
ShopProductIndex shopProductIndex = new ShopProductIndex();
|
|
||||||
shopProductIndex.setProduct_add_time(currentDate.getTime());
|
|
||||||
shopProductIndex.setProduct_sale_time(DateUtil.current() + 600); //10分钟
|
|
||||||
shopProductIndex.setStore_category_ids(""); // 店铺分类编号(DOT)
|
|
||||||
shopProductIndex.setProduct_tags("");// 商品标签(DOT)
|
|
||||||
shopProductIndex.setBrand_id(0);
|
|
||||||
shopProductIndex.setProduct_name(shopProductBase.getProduct_name()); // 产品名称:店铺平台先在对用表中检索后通过id检索,检索使用
|
|
||||||
shopProductIndex.setProduct_name_index(shopProductIndex.getProduct_name()); // 名称索引关键字(DOT)
|
|
||||||
shopProductIndex.setCategory_id(categoryId); // 商品分类
|
|
||||||
shopProductIndex.setProduct_fx_enable(0); // 供应商是否允许批发市场分销
|
|
||||||
shopProductIndex.setProduct_dist_enable(0); // 是否允许三级分销
|
|
||||||
shopProductIndex.setStore_id(storeIdInt);
|
|
||||||
shopProductIndex.setStore_type(store_row.getStore_type());
|
|
||||||
shopProductIndex.setKind_id(StateCode.PRODUCT_KIND_ENTITY);// 实体商品
|
|
||||||
shopProductIndex.setStore_is_open(store_row.getStore_is_open());
|
|
||||||
shopProductIndex.setStore_is_selfsupport(store_row.getStore_is_selfsupport());
|
|
||||||
shopProductIndex.setStore_longitude(store_row.getStore_longitude());
|
|
||||||
shopProductIndex.setStore_latitude(store_row.getStore_latitude());
|
|
||||||
|
|
||||||
shopProductIndex.setCard_type_id(0);
|
|
||||||
shopProductIndex.setVoucher_activity_id("");
|
|
||||||
shopProductIndex.setCoupon_type_id(0);// product_assist_data // 辅助属性值列(DOT)
|
|
||||||
shopProductIndex.setProduct_transport_id(String.valueOf(StateCode.DELIVERY_TYPE_SAME_CITY));
|
|
||||||
|
|
||||||
ShopBaseProductCategory category_row = productCategoryService.get(categoryId);
|
|
||||||
if (ObjectUtil.isNotEmpty(category_row)) {
|
|
||||||
Integer type_id = category_row.getType_id();
|
|
||||||
shopProductIndex.setType_id(type_id);
|
|
||||||
}
|
|
||||||
|
|
||||||
// shop_product_data
|
|
||||||
ShopProductData shopProductData = new ShopProductData();
|
|
||||||
// product_id // 产品id
|
|
||||||
shopProductData.setProduct_edit_time(currentDate);
|
|
||||||
|
|
||||||
// shop_product_detail
|
|
||||||
ShopProductDetail shopProductDetail = new ShopProductDetail();
|
|
||||||
shopProductDetail.setProduct_detail("");
|
|
||||||
shopProductDetail.setProduct_param("");
|
|
||||||
shopProductDetail.setProduct_service("");
|
|
||||||
shopProductDetail.setProduct_tags("");
|
|
||||||
|
|
||||||
// shop_product_info
|
|
||||||
ShopProductInfo shopProductInfo = new ShopProductInfo();
|
|
||||||
shopProductInfo.setProduct_number((String) jsonObj.get("product_number"));// SPU商家编码:货号
|
|
||||||
shopProductInfo.setProduct_assist("");
|
|
||||||
shopProductInfo.setProduct_spec("");
|
|
||||||
shopProductInfo.setProduct_buy_limit(0); // 不限购
|
|
||||||
//商品规格
|
|
||||||
shopProductInfo.setSpec_ids("");
|
|
||||||
|
|
||||||
List<ShopProductItem> shopProductItemList = new ArrayList<>();
|
|
||||||
ShopProductItem shopProductItem = new ShopProductItem();
|
|
||||||
shopProductItem.setStore_id(storeIdInt);
|
|
||||||
shopProductItem.setCategory_id(categoryId);
|
|
||||||
//零售价
|
|
||||||
shopProductItem.setItem_unit_price((BigDecimal) jsonObj.get("retail_price"));
|
|
||||||
shopProductItem.setItem_advice_price((BigDecimal) jsonObj.get("retail_price"));
|
|
||||||
shopProductItem.setItem_market_price((BigDecimal) jsonObj.get("retail_price"));
|
|
||||||
//积分价
|
|
||||||
shopProductItem.setItem_unit_points((BigDecimal) jsonObj.get("points"));
|
|
||||||
shopProductItem.setItem_quantity((Integer) jsonObj.get("stock")); // 库存
|
|
||||||
shopProductItem.setItem_quantity_frozen(0);
|
|
||||||
shopProductItem.setItem_number((String) jsonObj.get("product_number"));// SKU商家编码
|
|
||||||
shopProductItem.setItem_barcode((String) jsonObj.get("product_number")); // 条形码正常情况下就是货号
|
|
||||||
shopProductItem.setItem_is_default(1);
|
|
||||||
shopProductItem.setItem_enable(1);
|
|
||||||
|
|
||||||
shopProductItemList.add(shopProductItem);
|
|
||||||
|
|
||||||
// 保存数据
|
|
||||||
Pair<Boolean, String> pair = shopProductBaseService.saveProduct(shopProductBase, shopProductIndex, shopProductData, shopProductDetail, shopProductInfo, shopProductItemList, new ArrayList<ShopProductImage>(), new ShopProductValidPeriod(), new ArrayList<ShopProductAssistIndex>());
|
|
||||||
if (!pair.getFirst()) {
|
|
||||||
logger.error(pair.getSecond());
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
count += 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
Map<String, Integer> resp = new HashMap<>();
|
Map<String, Integer> resp = new HashMap<>();
|
||||||
resp.put("count", count);
|
resp.put("count", count);
|
||||||
|
|
||||||
@ -426,72 +246,7 @@ public class SyncThirdDataServiceImpl implements SyncThirdDataService {
|
|||||||
return new ThirdApiRes().fail(1004, I18nUtil._("单次同步记录最多" + limitCnt + "条!"));
|
return new ThirdApiRes().fail(1004, I18nUtil._("单次同步记录最多" + limitCnt + "条!"));
|
||||||
}
|
}
|
||||||
|
|
||||||
int count = 0;
|
int count =baseSaveOrUpdateMemberBatch(memberList,storeId);
|
||||||
for (SyncThirdMemberReq member : memberList) {
|
|
||||||
// account_user_base
|
|
||||||
AccountUserBase accountUserBase = new AccountUserBase();
|
|
||||||
accountUserBase.setUser_account(StringUtils.generateUniqueCode(8));
|
|
||||||
accountUserBase.setUser_nickname(member.getUser_nickname());
|
|
||||||
accountUserBase.setUser_state(2);// 状态(ENUM):0-锁定;1-未激活;2-已激活;
|
|
||||||
accountUserBase.setUser_is_admin(CommonConstant.USER_TYPE_NORMAL);
|
|
||||||
accountUserBase.setStore_ids(storeId);
|
|
||||||
accountUserBase.setRights_group_id("0");// 普通用户,不是商家
|
|
||||||
accountUserBase.setUser_type(CommonConstant.USER_TYPE_NORMAL);
|
|
||||||
|
|
||||||
// 默认给了随机密码和盐,token
|
|
||||||
String user_key = IdUtil.simpleUUID();
|
|
||||||
String user_salt = IdUtil.simpleUUID();
|
|
||||||
String user_token = IdUtil.simpleUUID();
|
|
||||||
accountUserBase.setUser_salt(user_salt);
|
|
||||||
accountUserBase.setUser_token(user_token);
|
|
||||||
accountUserBase.setUser_key(user_key);
|
|
||||||
accountUserBase.setUser_password(SecureUtil.md5(user_salt + SecureUtil.md5(IdUtil.simpleUUID())));
|
|
||||||
|
|
||||||
// 判断店铺是不是存在该昵称的会员了?
|
|
||||||
Boolean exists = accountService.existByNickname(member.getUser_nickname(), storeId);
|
|
||||||
if (exists) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
AccountUserBase accountUserBase2 = accountService.saveOrUpdateUserBase2(accountUserBase);
|
|
||||||
|
|
||||||
// 新增用户记录后,返回 userId ?
|
|
||||||
Integer userId = accountUserBase2.getUser_id();
|
|
||||||
if (userId == null || userId <= 0) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
// account_user_info
|
|
||||||
AccountUserInfo accountUserInfo = new AccountUserInfo();
|
|
||||||
accountUserInfo.setUser_id(userId);
|
|
||||||
accountUserInfo.setUser_type_id(0);
|
|
||||||
accountUserInfo.setUser_mobile(member.getUser_mobile());
|
|
||||||
accountUserInfo.setUser_level_card(member.getUser_level_card());
|
|
||||||
//user_level_id
|
|
||||||
accountUserInfo.setUser_level_id(1); // todo select id
|
|
||||||
accountUserInfo.setUser_gender(member.getUser_gender());
|
|
||||||
accountUserInfo.setUser_mobile(member.getUser_mobile());
|
|
||||||
accountUserInfo.setUser_intl(CommonConstant.IDD_ZH_CN);
|
|
||||||
accountUserInfo.setUser_birthday(DateTimeUtils.parseDate(member.getUser_birthday(), "yyyy-MM-dd"));
|
|
||||||
boolean success = accountService.saveOrUpdateUserInfo(accountUserInfo);
|
|
||||||
|
|
||||||
if (member.getUser_money() != null || member.getUser_points() != null) {
|
|
||||||
// pay_user_resource 用户支付资源,积分,余额
|
|
||||||
PayUserResource payUserResource = new PayUserResource();
|
|
||||||
payUserResource.setUser_id(userId);
|
|
||||||
payUserResource.setUser_money(member.getUser_money());
|
|
||||||
payUserResource.setUser_money_frozen(BigDecimal.ZERO);
|
|
||||||
payUserResource.setUser_points(member.getUser_points());
|
|
||||||
payUserResource.setUser_points_frozen(BigDecimal.ZERO);
|
|
||||||
|
|
||||||
success = payService.saveOrUpdatePayUserResource(payUserResource);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (success) {
|
|
||||||
count += 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Map<String, Integer> resp = new HashMap<>();
|
Map<String, Integer> resp = new HashMap<>();
|
||||||
resp.put("count", count);
|
resp.put("count", count);
|
||||||
|
|
||||||
@ -530,42 +285,18 @@ public class SyncThirdDataServiceImpl implements SyncThirdDataService {
|
|||||||
return CommonResult.failed();
|
return CommonResult.failed();
|
||||||
}
|
}
|
||||||
|
|
||||||
//jdbcTemplate
|
|
||||||
JdbcTemplate jdbcTemplate = getJDBCTemplate(syncConfig);
|
|
||||||
if (null == jdbcTemplate) {
|
|
||||||
return CommonResult.failed();
|
|
||||||
}
|
|
||||||
|
|
||||||
//1-品牌,2-分类,3-商品,4-会员
|
//1-品牌,2-分类,3-商品,4-会员
|
||||||
switch (syncType) {
|
switch (syncType) {
|
||||||
case 1:
|
case 1:
|
||||||
return syncProductBrand(jdbcTemplate);
|
return syncProductBrand(new DataBaseInfo(),storeId);//todo
|
||||||
case 2:
|
case 2:
|
||||||
return syncProductClazz(jdbcTemplate);
|
return syncProductClazz(new DataBaseInfo(),storeId);//todo 测试
|
||||||
case 3:
|
case 3:
|
||||||
return syncProduct(jdbcTemplate);
|
return syncProduct(new DataBaseInfo(),storeId);//todo 没做完
|
||||||
case 4:
|
case 4:
|
||||||
return syncVip(jdbcTemplate);
|
return syncVip(new DataBaseInfo(),storeId);//todo 测试
|
||||||
}
|
}
|
||||||
return null;
|
return CommonResult.success();
|
||||||
}
|
|
||||||
|
|
||||||
//创建Template
|
|
||||||
private JdbcTemplate getJDBCTemplate(SyncConfig syncConfig) {
|
|
||||||
|
|
||||||
switch (syncConfig.getSys_version()) {
|
|
||||||
case "hbposev9":
|
|
||||||
DriverManagerDataSource dataSource = new DriverManagerDataSource();
|
|
||||||
dataSource.setDriverClassName("com.microsoft.sqlserver.jdbc.SQLServerDriver");
|
|
||||||
String url = String.format("jdbc:sqlserver://%s:%s;databaseName=%s",
|
|
||||||
syncConfig.getSever_ip(), syncConfig.getSql_port(), syncConfig.getSql_db());
|
|
||||||
dataSource.setUrl(url);
|
|
||||||
dataSource.setUsername(syncConfig.getSql_acc());
|
|
||||||
dataSource.setPassword(syncConfig.getSql_pwd());
|
|
||||||
// 创建 JdbcTemplate
|
|
||||||
return new JdbcTemplate(dataSource);
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -574,13 +305,27 @@ public class SyncThirdDataServiceImpl implements SyncThirdDataService {
|
|||||||
*
|
*
|
||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
public CommonResult syncProduct(JdbcTemplate template) {
|
public CommonResult syncProduct(DataBaseInfo dataBaseInfo,String storeId) {
|
||||||
//商品编码 item_no、商品名称 item_name、零售价 sale_price、会员价 vip_price
|
int total= sxSyncGoodsService.getGoodsTotal(dataBaseInfo);
|
||||||
String sql = "SELECT item_no, item_name, sale_price, vip_price FROM t_bd_item_info";
|
// 总页数
|
||||||
|
int pages = CommonUtil.getPagesCount(total, SxDataDao.PAGESIZE);
|
||||||
List<String> oList = template.queryForList(sql, String.class);
|
int syncCount =0;
|
||||||
//todo 第三方 商品同步接口
|
for (int i = 1; i < pages; i++) {
|
||||||
return null;
|
int count=0;
|
||||||
|
List<SxSyncGoods> sxSyncGoodsList= sxSyncGoodsService.findGoodsListPage(dataBaseInfo,i,pages);
|
||||||
|
//todo 数据转换
|
||||||
|
List<SxGoosModel> sxGoosModelList= CvtToGoosModel(sxSyncGoodsList);
|
||||||
|
if(CollectionUtil.isEmpty(sxSyncGoodsList)){
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
count= baseSaveOrUpdateGoods(JSONUtil.parseArray(sxGoosModelList),storeId);
|
||||||
|
if(count<=0){
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
syncCount+=count;
|
||||||
|
}
|
||||||
|
logger.info("同步商品的总数为{},成功数量为{}",total,syncCount);
|
||||||
|
return CommonResult.success();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -589,12 +334,30 @@ public class SyncThirdDataServiceImpl implements SyncThirdDataService {
|
|||||||
*
|
*
|
||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
public CommonResult syncVip(JdbcTemplate template) {
|
public CommonResult syncVip(DataBaseInfo dataBaseInfo,String storeId) {
|
||||||
//会员卡号card_no、card_id、会员姓名vip_name、手机号vip_tel | mobile、性别 vip_sex、生日 birthday
|
// 记录总数
|
||||||
String sql = "SELECT card_no, card_id, vip_name, vip_tel, vip_sex, birthday FROM t_rm_vip_info";
|
Integer total = sxSyncVipService.getVipMembersTotal(dataBaseInfo);
|
||||||
List<String> oList = template.queryForList(sql, String.class);
|
// 总页数
|
||||||
//todo 第三方 会员同步接口
|
int pages = CommonUtil.getPagesCount(total, SxDataDao.PAGESIZE);
|
||||||
return null;
|
List<SyncThirdMemberReq> memberList=new ArrayList<>();
|
||||||
|
SyncThirdMemberReq syncThirdMemberReq=null;
|
||||||
|
int syncCount =0;
|
||||||
|
for (int i = 1; i < pages; i++) {
|
||||||
|
memberList.clear();
|
||||||
|
int count = 0;
|
||||||
|
syncThirdMemberReq=new SyncThirdMemberReq();
|
||||||
|
List<SxSyncVip> sxSyncVipList= sxSyncVipService.findVipMemberPage(dataBaseInfo,i,SxDataDao.PAGESIZE);
|
||||||
|
//处理数据转换SxSyncVip>SyncThirdMemberReq
|
||||||
|
memberList=ConverList(sxSyncVipList);
|
||||||
|
memberList.add(syncThirdMemberReq);
|
||||||
|
count=baseSaveOrUpdateMemberBatch(memberList,storeId);
|
||||||
|
if (count <= 0) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
syncCount+=count;
|
||||||
|
}
|
||||||
|
logger.info("vip会员总共有{}条数据,同步完成{}条",total,syncCount);
|
||||||
|
return CommonResult.success();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -602,17 +365,287 @@ public class SyncThirdDataServiceImpl implements SyncThirdDataService {
|
|||||||
*
|
*
|
||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
public CommonResult syncProductBrand(JdbcTemplate template) {
|
public CommonResult syncProductBrand(DataBaseInfo dataBaseInfo,String storeId) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 同步商品分类
|
* 同步商品分类
|
||||||
*
|
|
||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
public CommonResult syncProductClazz(JdbcTemplate template) {
|
public CommonResult syncProductClazz(DataBaseInfo dataBaseInfo,String storeId) {
|
||||||
return null;
|
// 记录总数
|
||||||
|
Integer total = sxSyncCategoryService.getCategoryTotal(dataBaseInfo);
|
||||||
|
// 总页数
|
||||||
|
int pages = CommonUtil.getPagesCount(total, SxDataDao.PAGESIZE);
|
||||||
|
int syncCount =0;
|
||||||
|
for (int i = 1; i <= pages; i++) {
|
||||||
|
int count = 0;
|
||||||
|
List<SxCategoryModel> list = sxSyncCategoryService.getCategoryByDataBasePage(dataBaseInfo,i,SxDataDao.PAGESIZE);
|
||||||
|
if (CollUtil.isEmpty(list)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
JSONArray categoryListJSON=JSONUtil.parseArray(list);
|
||||||
|
List<ShopBaseProductCategory> shopBaseProductCategories = JSONUtil.toList(categoryListJSON, ShopBaseProductCategory.class);
|
||||||
|
if (shopBaseProductCategories == null) {
|
||||||
|
logger.info("转换类型为空,类方法为{}","com.suisung.mall.shop.sync.service.impl.SyncThirdDataServiceImpl.syncProductClazz");
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
count = baseSaveOrUpdateShopBaseProductCategoryBatch(shopBaseProductCategories,categoryListJSON,storeId);
|
||||||
|
if (count <= 0) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
syncCount+=count;
|
||||||
|
}
|
||||||
|
logger.info("商品分类总共有{}条数据,同步完成{}条",total,syncCount);
|
||||||
|
return CommonResult.success();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 文件上传
|
||||||
|
* @param appKey
|
||||||
|
* @param sign
|
||||||
|
* @param page 分页
|
||||||
|
* @param syncType
|
||||||
|
* @param multipartFile
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public ThirdApiRes fileUpload(String appKey, String sign,String page,String syncType, MultipartFile multipartFile) {
|
||||||
|
if (StrUtil.isBlank(appKey) || StrUtil.isBlank(sign) ) {
|
||||||
|
return new ThirdApiRes().fail(1003, I18nUtil._("缺少必要参数!"));
|
||||||
|
}
|
||||||
|
// 验签、appid,必要参数判断
|
||||||
|
SyncApp syncAppO = syncAppService.getOne(new LambdaQueryWrapper<SyncApp>()
|
||||||
|
.select(SyncApp::getApp_key, SyncApp::getApp_secret,SyncApp::getStore_id)
|
||||||
|
.eq(SyncApp::getApp_key, appKey)
|
||||||
|
.eq(SyncApp::getApp_secret,sign));
|
||||||
|
if (syncAppO == null) {
|
||||||
|
return new ThirdApiRes().fail(1001, I18nUtil._("签名有误!"));
|
||||||
|
}
|
||||||
|
String storeId = syncAppO.getStore_id();
|
||||||
|
try {
|
||||||
|
if (multipartFile.isEmpty()) {
|
||||||
|
return new ThirdApiRes().fail(1001, I18nUtil._("文件不能为空!"));
|
||||||
|
}
|
||||||
|
byte[] bytes = multipartFile.getBytes();
|
||||||
|
String folder=new FileUtils().getSyncTypeFlag(syncType,clientPath)+storeId+FileUtils.pathSeparator+page+FileUtils.pathSeparator;
|
||||||
|
String filName=multipartFile.getOriginalFilename();
|
||||||
|
String filePath= FileUtils.createFolderAndFileUsingFile(folder,filName);
|
||||||
|
Path path = Paths.get(filePath);
|
||||||
|
Files.write(path, bytes);
|
||||||
|
// String fileDownloadUri = ServletUriComponentsBuilder.fromCurrentContextPath()
|
||||||
|
// .path("/download/")
|
||||||
|
// .path(Objects.requireNonNull(multipartFile.getOriginalFilename()))
|
||||||
|
// .toUriString();
|
||||||
|
return new ThirdApiRes().success("文件上传成功");
|
||||||
|
} catch (IOException e) {
|
||||||
|
return new ThirdApiRes().fail(500,"文件上传失败");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 多线程处理文件
|
||||||
|
* @param appKey
|
||||||
|
* @param sign
|
||||||
|
* @param syncType
|
||||||
|
* @param folders
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public void SyncReadSxFileData(String appKey, String sign, String syncType, List<String> folders) {
|
||||||
|
SyncApp syncApp = syncAppService.getOne(new LambdaQueryWrapper<SyncApp>()
|
||||||
|
.select(SyncApp::getApp_key, SyncApp::getApp_secret,SyncApp::getStore_id)
|
||||||
|
.eq(SyncApp::getApp_key, appKey)
|
||||||
|
.eq(SyncApp::getApp_secret,sign));
|
||||||
|
String storeId = syncApp.getStore_id();
|
||||||
|
if(null==syncApp.getStore_id()|| syncApp.getStore_id().isEmpty()){
|
||||||
|
logger.info("商品id为空");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if(folders==null||folders.isEmpty()){
|
||||||
|
logger.info("没有商品数据");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
List<String> newFolders=new ArrayList<>();
|
||||||
|
folders.forEach(page->{
|
||||||
|
String newfolder=new FileUtils().getSyncTypeFlag(syncType,clientPath)+storeId+FileUtils.pathSeparator+page+FileUtils.pathSeparator;
|
||||||
|
newFolders.add(newfolder);
|
||||||
|
});
|
||||||
|
syncPrimaryKey();
|
||||||
|
shopNumberSeqService.clearKey();
|
||||||
|
ExecutorService executor = Executors.newFixedThreadPool(6);
|
||||||
|
List<Future<?>> futures = new ArrayList<>();
|
||||||
|
// 提交任务
|
||||||
|
AtomicInteger success= new AtomicInteger();
|
||||||
|
AtomicInteger fails= new AtomicInteger();
|
||||||
|
List<String> failFolders=new ArrayList<>();
|
||||||
|
List<String> failMessage=new ArrayList<>();
|
||||||
|
for (int i = 0; i < newFolders.size(); i++) {
|
||||||
|
final int taskId = i;
|
||||||
|
threadNum.incrementAndGet();
|
||||||
|
futures.add(executor.submit(() -> {
|
||||||
|
int count = 0;//失败重试机制,当失败重试一次,再次失败则记录到数据库中
|
||||||
|
while (true){
|
||||||
|
count++;
|
||||||
|
String taskName=newFolders.get(taskId);
|
||||||
|
String fileName="good_"+taskId+".txt";
|
||||||
|
JSONArray jsonArray=new ThreadFileUtils().processFolder(taskName,newFolders.get(taskId));
|
||||||
|
try {
|
||||||
|
baseSaveOrUpdateGoodsBatch(jsonArray,storeId);
|
||||||
|
success.getAndIncrement();
|
||||||
|
threadNum.decrementAndGet();
|
||||||
|
return "成功" + taskId;
|
||||||
|
}catch (Exception e){
|
||||||
|
if(count<2){
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
fails.getAndIncrement();
|
||||||
|
failFolders.add(newFolders.get(taskId)+fileName);
|
||||||
|
failMessage.add(taskId+"_"+e.getMessage());
|
||||||
|
return "失败"+newFolders.get(taskId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
// 等待所有任务完成
|
||||||
|
for (Future<?> future : futures) {
|
||||||
|
try {
|
||||||
|
System.out.println("任务结果: " + future.get());
|
||||||
|
} catch (Exception e) {
|
||||||
|
System.err.println("任务执行异常: " + e.getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
executor.shutdown();
|
||||||
|
//记录到数据库
|
||||||
|
syncPrimaryKey();
|
||||||
|
shopNumberSeqService.clearKey();
|
||||||
|
List<SyncFileLog> syncFileLogs=new ArrayList<>();
|
||||||
|
for (int i = 0; i < failFolders.size(); i++) {
|
||||||
|
String path=failFolders.get(i);
|
||||||
|
String taskId=failMessage.get(i).split("_")[0];
|
||||||
|
SyncFileLog syncFileLog=new SyncFileLog();
|
||||||
|
syncFileLog.setSyncType(syncType);
|
||||||
|
syncFileLog.setFileName(path.substring(path.lastIndexOf(FileUtils.pathSeparator)+1));
|
||||||
|
syncFileLog.setSyncStatus(DicEnum.FAILED.getCode());
|
||||||
|
syncFileLog.setSyncTaskId(taskId);
|
||||||
|
syncFileLog.setSyncStoreId(storeId);
|
||||||
|
syncFileLog.setFilePath(path);
|
||||||
|
syncFileLog.setErrorMessage(failMessage.get(i));
|
||||||
|
syncFileLog.setSourceSystem(DicEnum.SOURCE_SYSTEM_TYPE_1005.getCode());
|
||||||
|
syncFileLog.setTargetSystem(DicEnum.SOURCE_SYSTEM_TYPE_SELF.getCode());
|
||||||
|
syncFileLogs.add(syncFileLog);
|
||||||
|
}
|
||||||
|
if(CollUtil.isNotEmpty(syncFileLogs)){
|
||||||
|
syncFileLogService.saveBatch(syncFileLogs,syncFileLogs.size());
|
||||||
|
}
|
||||||
|
//todo 定时清理文件,建议用服务器脚本
|
||||||
|
logger.info("执行成功{}个文件,失败{}个文件",success,fails);
|
||||||
|
logger.info("同步商品数据执行结束");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ResponseEntity<Resource> downloadToClient(String primaryKey) {
|
||||||
|
logger.info("primaryKey:{}",primaryKey);
|
||||||
|
boolean checked= syncAppService.checkPrimaryKey(primaryKey);
|
||||||
|
// UserDto userDto=ContextUtil.getCurrentUser();
|
||||||
|
//redisService.del(RedisKey.SXCLIENTKEYVERSION);//todo 删除
|
||||||
|
String version= (String) redisService.get(RedisKey.SXCLIENTKEYVERSION);
|
||||||
|
if(checked){
|
||||||
|
String tempFilePath=System.getProperty("user.home");
|
||||||
|
String clientJarPath="";
|
||||||
|
if(StringUtils.isEmpty(version)){
|
||||||
|
version="v1";
|
||||||
|
//String ossFolder="/sxclient/"+version;
|
||||||
|
redisService.set(RedisKey.SXCLIENTKEYVERSION,version);
|
||||||
|
logger.error("没有版本更新");
|
||||||
|
return ResponseEntity.ok()
|
||||||
|
.contentType(MediaType.APPLICATION_OCTET_STREAM)
|
||||||
|
.header(HttpHeaders.CONTENT_DISPOSITION,
|
||||||
|
"attachment; filename=error.txt")
|
||||||
|
.header("error","noVersion")
|
||||||
|
.body(new ByteArrayResource(version.getBytes(StandardCharsets.UTF_8)));
|
||||||
|
}else {
|
||||||
|
List<String> folderList= ossService.listFolders(CLIENTFILEPATH);
|
||||||
|
version= String.valueOf(Convert.toInt(version.split("v")[1])+1);
|
||||||
|
version="v"+version;
|
||||||
|
String finalVersion =CLIENTFILEPATH + version+"/";
|
||||||
|
String folder= folderList.stream().filter(finalVersion::equals).collect(Collectors.joining());
|
||||||
|
if(StringUtils.isNotEmpty(folder)){
|
||||||
|
//String ossFolder="/sxclient/"+folder;
|
||||||
|
String filePath= ossService.listDocuments(folder).get(0).getKey();
|
||||||
|
clientJarPath= ossService.download(filePath,tempFilePath+FileUtils.pathSeparator+filePath);
|
||||||
|
}else {
|
||||||
|
logger.error("查找没有版本更新");
|
||||||
|
return ResponseEntity.ok()
|
||||||
|
.contentType(MediaType.APPLICATION_OCTET_STREAM)
|
||||||
|
.header(HttpHeaders.CONTENT_DISPOSITION,
|
||||||
|
"attachment; filename=error.txt")
|
||||||
|
.header("error","noVersion")
|
||||||
|
.body(new ByteArrayResource(version.getBytes(StandardCharsets.UTF_8)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(StringUtils.isNotEmpty(clientJarPath)){
|
||||||
|
// 构建文件路径
|
||||||
|
Path filePath = Paths.get(clientJarPath);
|
||||||
|
File file = filePath.toFile();
|
||||||
|
// 检查文件是否存在
|
||||||
|
if (!file.exists()) {
|
||||||
|
return ResponseEntity.status(HttpStatus.NOT_FOUND)
|
||||||
|
.header("error" ,"noFile")
|
||||||
|
.body(new ByteArrayResource(version.getBytes()));
|
||||||
|
}
|
||||||
|
// 创建Resource对象
|
||||||
|
Resource resource = new FileSystemResource(file);
|
||||||
|
|
||||||
|
// 获取文件MIME类型
|
||||||
|
String contentType = null;
|
||||||
|
try {
|
||||||
|
contentType = Files.probeContentType(filePath);
|
||||||
|
} catch (IOException e) {
|
||||||
|
return ResponseEntity.status(HttpStatus.NOT_FOUND)
|
||||||
|
.header("error" ,"500")
|
||||||
|
.body(new ByteArrayResource(version.getBytes()));
|
||||||
|
}
|
||||||
|
if (contentType == null) {
|
||||||
|
contentType = "application/octet-stream";
|
||||||
|
}
|
||||||
|
redisService.set(RedisKey.SXCLIENTKEYVERSION,version);
|
||||||
|
// 构建响应
|
||||||
|
return ResponseEntity.ok()
|
||||||
|
.contentType(MediaType.parseMediaType(contentType))
|
||||||
|
.header(HttpHeaders.CONTENT_DISPOSITION,
|
||||||
|
"attachment; filename=\"" + file.getName() + "\"")
|
||||||
|
.body(resource);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
logger.info("!校验失败");
|
||||||
|
return ResponseEntity.status(HttpStatus.NOT_FOUND)
|
||||||
|
.header("error" ,"noValid")
|
||||||
|
.body(new ByteArrayResource("version".getBytes()));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ThirdApiRes getStoreDbConfig(String appKey,String sign) {
|
||||||
|
if (StrUtil.isBlank(appKey) || StrUtil.isBlank(sign) ) {
|
||||||
|
return new ThirdApiRes().fail(1003, I18nUtil._("缺少必要参数!"));
|
||||||
|
}
|
||||||
|
// 验签、appid,必要参数判断
|
||||||
|
SyncApp syncAppO = syncAppService.getOne(new LambdaQueryWrapper<SyncApp>()
|
||||||
|
.select(SyncApp::getApp_key, SyncApp::getApp_secret,SyncApp::getStore_id)
|
||||||
|
.eq(SyncApp::getApp_key, appKey)
|
||||||
|
.eq(SyncApp::getApp_secret,sign));
|
||||||
|
if (syncAppO == null) {
|
||||||
|
return new ThirdApiRes().fail(1001, I18nUtil._("签名有误!"));
|
||||||
|
}
|
||||||
|
String storeId = syncAppO.getStore_id();
|
||||||
|
QueryWrapper<StoreDbConfig> queryWrapper = new QueryWrapper<>();
|
||||||
|
queryWrapper.eq("store_id", storeId);
|
||||||
|
queryWrapper.eq("has_start",DicEnum.YESORNO_1.getCode());
|
||||||
|
StoreDbConfig storeDbConfig= storeDbConfigService.getOne(queryWrapper);
|
||||||
|
if (storeDbConfig == null) {
|
||||||
|
return new ThirdApiRes().fail(1003, I18nUtil._("服务器配置缺少配置信息!"));
|
||||||
|
}
|
||||||
|
return new ThirdApiRes().success("成功",storeDbConfig);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -8,7 +8,7 @@ spring:
|
|||||||
mvc:
|
mvc:
|
||||||
static-path-pattern: /shop/static/**
|
static-path-pattern: /shop/static/**
|
||||||
datasource:
|
datasource:
|
||||||
url: jdbc:mysql://@mysql.host@:@mysql.port@/@mysql.db@?useUnicode=true&characterEncoding=utf-8&serverTimezone=Asia/Shanghai&&zeroDateTimeBehavior=convertToNull
|
url: jdbc:mysql://@mysql.host@:@mysql.port@/@mysql.db@?rewriteBatchedStatements=true&useUnicode=true&characterEncoding=utf-8&serverTimezone=Asia/Shanghai&&zeroDateTimeBehavior=convertToNull
|
||||||
username: @mysql.user@
|
username: @mysql.user@
|
||||||
password: @mysql.pwd@
|
password: @mysql.pwd@
|
||||||
driver-class-name: @mysql.driver@
|
driver-class-name: @mysql.driver@
|
||||||
|
|||||||
@ -8,7 +8,7 @@ spring:
|
|||||||
mvc:
|
mvc:
|
||||||
static-path-pattern: /shop/static/**
|
static-path-pattern: /shop/static/**
|
||||||
datasource:
|
datasource:
|
||||||
url: jdbc:mysql://@mysql.host@:@mysql.port@/@mysql.db@?useUnicode=true&characterEncoding=utf-8&serverTimezone=Asia/Shanghai&&zeroDateTimeBehavior=convertToNull
|
url: jdbc:mysql://@mysql.host@:@mysql.port@/@mysql.db@?rewriteBatchedStatements=true&useUnicode=true&characterEncoding=utf-8&serverTimezone=Asia/Shanghai&&zeroDateTimeBehavior=convertToNull
|
||||||
username: @mysql.user@
|
username: @mysql.user@
|
||||||
password: @mysql.pwd@
|
password: @mysql.pwd@
|
||||||
driver-class-name: @mysql.driver@
|
driver-class-name: @mysql.driver@
|
||||||
@ -155,4 +155,7 @@ esign:
|
|||||||
app_id: 7439053575
|
app_id: 7439053575
|
||||||
app_secret: 8da2e1eeeaf88e09bcf432a2fdd3e4d7
|
app_secret: 8da2e1eeeaf88e09bcf432a2fdd3e4d7
|
||||||
app_rsa: MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAiC+fUc0+O9m45VEcGciJQ5QQNXs3NkHoHM2qDAdrXOnTwku0Be1IPeWUZ4s7w8xqubyirAAJDc3LpRkwCK84NicA2VwraD4on8MNtX8MLALZjLc1jZTmRAPKVfTKAcainR7ET78Y+QKJgezNvI7u45FO4Db+dWCC7pbedxBo+kHKA8im+/G0hpQaklxw1wjIMNv+x+YBnm8FOXRPWJZ+eItF5qJOT2C16QCY7hdeHknom+NMpZD8E/WAMtf03BcgigsoavTVnPI0xnN8BCrgykDWgO5bUXeIgNEF1LJS6r8s6BaMl+ZWbuODtbsrQ941GbFOe6x8tnhPIeehIa1AWQIDAQAB
|
app_rsa: MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAiC+fUc0+O9m45VEcGciJQ5QQNXs3NkHoHM2qDAdrXOnTwku0Be1IPeWUZ4s7w8xqubyirAAJDc3LpRkwCK84NicA2VwraD4on8MNtX8MLALZjLc1jZTmRAPKVfTKAcainR7ET78Y+QKJgezNvI7u45FO4Db+dWCC7pbedxBo+kHKA8im+/G0hpQaklxw1wjIMNv+x+YBnm8FOXRPWJZ+eItF5qJOT2C16QCY7hdeHknom+NMpZD8E/WAMtf03BcgigsoavTVnPI0xnN8BCrgykDWgO5bUXeIgNEF1LJS6r8s6BaMl+ZWbuODtbsrQ941GbFOe6x8tnhPIeehIa1AWQIDAQAB
|
||||||
debug: true
|
debug: true
|
||||||
|
#客户端上传文件地址
|
||||||
|
client:
|
||||||
|
path: @client.path@
|
||||||
|
|||||||
@ -6,7 +6,7 @@ spring:
|
|||||||
mvc:
|
mvc:
|
||||||
static-path-pattern: /shop/static/**
|
static-path-pattern: /shop/static/**
|
||||||
datasource:
|
datasource:
|
||||||
url: jdbc:mysql://@mysql.host@:@mysql.port@/@mysql.db@?useUnicode=true&characterEncoding=utf-8&serverTimezone=Asia/Shanghai&&zeroDateTimeBehavior=convertToNull&autoReconnect=true&failOverReadOnly=false&maxReconnects=5
|
url: jdbc:mysql://@mysql.host@:@mysql.port@/@mysql.db@?rewriteBatchedStatements=true&useUnicode=true&characterEncoding=utf-8&serverTimezone=Asia/Shanghai&&zeroDateTimeBehavior=convertToNull&autoReconnect=true&failOverReadOnly=false&maxReconnects=5
|
||||||
username: @mysql.user@
|
username: @mysql.user@
|
||||||
password: @mysql.pwd@
|
password: @mysql.pwd@
|
||||||
driver-class-name: @mysql.driver@
|
driver-class-name: @mysql.driver@
|
||||||
|
|||||||
@ -6,7 +6,7 @@ spring:
|
|||||||
mvc:
|
mvc:
|
||||||
static-path-pattern: /shop/static/**
|
static-path-pattern: /shop/static/**
|
||||||
datasource:
|
datasource:
|
||||||
url: jdbc:mysql://@mysql.host@:@mysql.port@/@mysql.db@?useUnicode=true&characterEncoding=utf-8&serverTimezone=Asia/Shanghai&&zeroDateTimeBehavior=convertToNull
|
url: jdbc:mysql://@mysql.host@:@mysql.port@/@mysql.db@?rewriteBatchedStatements=true&useUnicode=true&characterEncoding=utf-8&serverTimezone=Asia/Shanghai&&zeroDateTimeBehavior=convertToNull
|
||||||
username: @mysql.user@
|
username: @mysql.user@
|
||||||
password: @mysql.pwd@
|
password: @mysql.pwd@
|
||||||
driver-class-name: @mysql.driver@
|
driver-class-name: @mysql.driver@
|
||||||
|
|||||||
@ -6,7 +6,7 @@ spring:
|
|||||||
mvc:
|
mvc:
|
||||||
static-path-pattern: /shop/static/**
|
static-path-pattern: /shop/static/**
|
||||||
datasource:
|
datasource:
|
||||||
url: jdbc:mysql://@mysql.host@:@mysql.port@/@mysql.db@?useUnicode=true&characterEncoding=utf-8&serverTimezone=Asia/Shanghai&&zeroDateTimeBehavior=convertToNull
|
url: jdbc:mysql://@mysql.host@:@mysql.port@/@mysql.db@?rewriteBatchedStatements=true&useUnicode=true&characterEncoding=utf-8&serverTimezone=Asia/Shanghai&&zeroDateTimeBehavior=convertToNull
|
||||||
username: @mysql.user@
|
username: @mysql.user@
|
||||||
password: @mysql.pwd@
|
password: @mysql.pwd@
|
||||||
driver-class-name: @mysql.driver@
|
driver-class-name: @mysql.driver@
|
||||||
|
|||||||
@ -6,5 +6,32 @@
|
|||||||
<sql id="Base_Column_List">
|
<sql id="Base_Column_List">
|
||||||
prefix, number
|
prefix, number
|
||||||
</sql>
|
</sql>
|
||||||
|
<resultMap id="shopNumberSeqMap" type="com.suisung.mall.common.modules.number.ShopNumberSeq">
|
||||||
|
<result property="prefix" column="prefix"/>
|
||||||
|
<result property="number" column="number"/>
|
||||||
|
</resultMap>
|
||||||
|
|
||||||
|
<select id="findNumberFromShopBaseAndItem" resultMap="shopNumberSeqMap">
|
||||||
|
SELECT * from shop_number_seq where prefix="product_id"
|
||||||
|
and number =(select max(product_id) from shop_product_base)+1
|
||||||
|
union
|
||||||
|
SELECT * from shop_number_seq where prefix="item_id"
|
||||||
|
and number =(select max(item_id) from shop_product_item)+1
|
||||||
|
</select>
|
||||||
|
|
||||||
|
<select id="findProductAndImtemId">
|
||||||
|
SELECT * from shop_number_seq where prefix in("product_id","item_id")
|
||||||
|
</select>
|
||||||
|
|
||||||
|
<update id="myUpdateSeq" parameterType="com.suisung.mall.common.modules.number.ShopNumberSeq">
|
||||||
|
UPDATE shop_number_seq
|
||||||
|
SET
|
||||||
|
prefix = #{prefix},
|
||||||
|
number = #{number}
|
||||||
|
WHERE prefix = #{prefix}
|
||||||
|
</update>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
</mapper>
|
</mapper>
|
||||||
|
|||||||
51
sql/shop/dev/20250520_ddl.sql
Normal file
51
sql/shop/dev/20250520_ddl.sql
Normal file
@ -0,0 +1,51 @@
|
|||||||
|
CREATE TABLE `sync_file_log` ( `id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '主键ID',
|
||||||
|
`sync_task_id` varchar(64) NOT NULL COMMENT '同步任务ID',
|
||||||
|
`sync_store_id` varchar(64) NOT NULL COMMENT '店铺id',
|
||||||
|
`file_path` varchar(1024) NOT NULL COMMENT '文件路径',
|
||||||
|
`file_name` varchar(255) NOT NULL COMMENT '文件名',
|
||||||
|
`file_size` bigint(20) DEFAULT NULL COMMENT '文件大小(字节)',
|
||||||
|
`file_md5` varchar(32) DEFAULT NULL COMMENT '文件MD5值',
|
||||||
|
`source_system` varchar(64) NOT NULL COMMENT '源系统标识',
|
||||||
|
`target_system` varchar(64) NOT NULL COMMENT '目标系统标识',
|
||||||
|
`sync_type` char(1) NOT NULL COMMENT '同步类型(1:商品,2:商品分类,3:会员,4.品牌)',
|
||||||
|
`sync_status` char(1) NOT NULL COMMENT '同步状态(0:等待中,1:进行中,2:成功,3:失败)',
|
||||||
|
`retry_count` tinyint(4) DEFAULT '0' COMMENT '重试次数',
|
||||||
|
`error_message` text ,
|
||||||
|
`start_time` datetime DEFAULT NULL COMMENT '开始时间',
|
||||||
|
`end_time` datetime DEFAULT NULL COMMENT '结束时间',
|
||||||
|
`duration` int(11) DEFAULT NULL COMMENT '耗时(毫秒)',
|
||||||
|
`create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
|
||||||
|
`update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
|
||||||
|
`extra_info` json DEFAULT NULL COMMENT '额外信息(JSON格式)',
|
||||||
|
PRIMARY KEY (`id`),
|
||||||
|
KEY `idx_sync_task_id` (`sync_task_id`),
|
||||||
|
KEY `idx_file_path` (`file_path`(255)),
|
||||||
|
KEY `idx_file_name` (`file_name`),
|
||||||
|
KEY `idx_source_target` (`source_system`, `target_system`),
|
||||||
|
KEY `idx_sync_status` (`sync_status`),
|
||||||
|
KEY `idx_create_time` (`create_time`),
|
||||||
|
KEY `idx_update_time` (`update_time`)
|
||||||
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='文件同步日志表';
|
||||||
|
|
||||||
|
CREATE TABLE `store_db_config` (
|
||||||
|
`id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '主键ID',
|
||||||
|
`store_id` varchar(64) NOT NULL COMMENT '店铺ID',
|
||||||
|
`db_type` varchar(20) NOT NULL DEFAULT 'sqlserver' COMMENT '数据库类型(mysql/oracle/sqlserver等)',
|
||||||
|
`db_name` varchar(64) NOT NULL COMMENT '数据库名称',
|
||||||
|
`db_ip` varchar(64) NOT NULL COMMENT '数据库IP地址',
|
||||||
|
`db_port` int(11) NOT NULL DEFAULT 3306 COMMENT '数据库端口',
|
||||||
|
`db_username` varchar(64) NOT NULL COMMENT '数据库用户名',
|
||||||
|
`db_password` varchar(256) NOT NULL COMMENT '数据库密码(建议加密存储)',
|
||||||
|
`has_internet` char(1) NOT NULL DEFAULT 0 COMMENT '是否有外网访问(0:无,1:有)',
|
||||||
|
`sync_mode` char(1) NOT NULL DEFAULT 2 COMMENT '同步模式(1:定时同步,2:间隔同步)',
|
||||||
|
`has_start` char(1) NOT NULL DEFAULT 1 COMMENT '是否启用(0:否,1:是)',
|
||||||
|
`cron_expression` varchar(64) DEFAULT NULL COMMENT '定时同步的cron表达式',
|
||||||
|
`category_name` text NULL DEFAULT NULL COMMENT '商品分类',
|
||||||
|
`create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
|
||||||
|
`update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
|
||||||
|
`remark` varchar(512) DEFAULT NULL COMMENT '备注信息',
|
||||||
|
PRIMARY KEY (`id`),
|
||||||
|
KEY `idx_store_id` (`store_id`),
|
||||||
|
KEY `idx_has_internet` (`has_internet`),
|
||||||
|
KEY `idx_has_start` (`has_start`)
|
||||||
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='店铺数据库连接配置表';
|
||||||
Loading…
Reference in New Issue
Block a user