Merge remote-tracking branch 'origin/main'

This commit is contained in:
Jack 2025-05-20 21:13:35 +08:00
commit 20726bf256
108 changed files with 8293 additions and 410 deletions

126
client/pom.xml Normal file
View File

@ -0,0 +1,126 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.small</groupId>
<artifactId>client</artifactId>
<version>v1</version>
<packaging>jar</packaging>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.3.0.RELEASE</version>
<relativePath/>
<!-- lookup parent from repository -->
</parent>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<maven.compiler.source>8</maven.compiler.source>
<maven.compiler.target>8</maven.compiler.target>
<hutool.version>5.8.20</hutool.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-text</artifactId>
<version>1.10.0</version>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger2</artifactId>
<version>2.9.2</version>
</dependency>
<!--jdbc数据库-->
<dependency>
<groupId>com.microsoft.sqlserver</groupId>
<artifactId>mssql-jdbc</artifactId>
<version>9.4.1.jre8</version> <!-- -->
</dependency>
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
</dependency>
<dependency>
<groupId>cn.hutool</groupId>
<artifactId>hutool-all</artifactId>
<version>${hutool.version}</version>
</dependency>
</dependencies>
<!-- 指定仓库为阿里云与阿帕奇 -->
<repositories>
<repository>
<id>ali-maven</id>
<url>https://maven.aliyun.com/repository/central</url>
<releases>
<enabled>true</enabled>
</releases>
<snapshots>
<enabled>true</enabled>
<updatePolicy>always</updatePolicy>
<checksumPolicy>fail</checksumPolicy>
</snapshots>
</repository>
<repository>
<id>repo.maven.apache.org</id>
<url>https://repo.maven.apache.org/maven2</url>
<releases>
<enabled>true</enabled>
</releases>
<snapshots>
<enabled>true</enabled>
<updatePolicy>always</updatePolicy>
<checksumPolicy>fail</checksumPolicy>
</snapshots>
</repository>
</repositories>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<excludes>
<exclude>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</exclude>
</excludes>
</configuration>
<executions>
<execution>
<goals>
<goal>repackage</goal> <!-- 生成可执行JAR -->
</goals>
</execution>
</executions>
</plugin>
<!-- 指定JDK版本 -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<source>1.8</source> <!-- Spring Boot 3.x需要JDK17+ -->
<target>1.8</target>
</configuration>
</plugin>
</plugins>
</build>
</project>

21
client/readme.txt Normal file
View File

@ -0,0 +1,21 @@
本系统主要安装在客户端
主要有以下几个功能
第一阶段
1、通过http获取远程数据小发服务配置基础数据包括主要包括数据库地址ip数据库名称数据库密码以及同步定时时间
2.采集本地数据库,通过多线程调用同步接口,同步商品,种类,会员
第二阶段
由于系统的数据同步存在性能瓶颈,需要使用文件传输的方式同步数据,
文件采用分页形式同步数据,每一页使用一个文件,服务器解析文件采用多线程解析方式解析
打包功能更需要写一个shell脚本自动打包放到服务器供给下载和java的jkd安装包这些下载放到后端的网页端暴露下载地址
todo
1、通过http获取dataInfo没有写
2、文件传输没有写
3.商品同步没有写
4.商品分类同步没有写

View File

@ -0,0 +1,48 @@
package com.small.client.Cache;
import cn.hutool.cache.Cache;
import cn.hutool.cache.impl.FIFOCache;
import cn.hutool.core.date.DateUnit;
import com.small.client.dto.BrandModel;
import com.small.client.dto.SpecPriceDto;
import org.springframework.stereotype.Component;
import java.util.List;
/**
* 用于本地缓存
*/
@Component
public class CommonCache {
public final static String CACHE_CATEGROY = "CACHE_CATEGROY";//分类缓存
private Cache<String, String> cache =new FIFOCache<>(20000);
private Cache<String, List<SpecPriceDto>> spriceCache =new FIFOCache<>(20);
private Cache<String, List<BrandModel>> brandCahce =new FIFOCache<>(20);
public void put(String key, String value) {
cache.put(key, value, DateUnit.MINUTE.getMillis()*20);
}
public String get(String key) {
return cache.get(key);
}
public void putSpecPrice(String key, List<SpecPriceDto> value) {
spriceCache.put(key, value, DateUnit.MINUTE.getMillis()*20);
}
public List<SpecPriceDto> getSpecPrice(String key) {
return spriceCache.get(key);
}
public List<BrandModel> getBrandCahce(String key) {
return brandCahce.get(key);
}
public void setBrandCahce(String key, List<BrandModel> value) {
brandCahce.put(key, value, DateUnit.MINUTE.getMillis()*20);
}
}

View File

@ -0,0 +1,27 @@
package com.small.client;
import com.small.client.Utils.JarPathUtil;
import com.small.client.service.SxDataService;
import com.small.client.service.WebClientService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.CommandLineRunner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.ComponentScan;
import javax.annotation.Resource;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.StandardCopyOption;
@SpringBootApplication
@Slf4j
public class ClientApplication{
public static void main(String[] args) {
SpringApplication.run(ClientApplication.class, args);
}
}

View File

@ -0,0 +1,103 @@
package com.small.client.Schedule;
import com.small.client.dto.CommentModel;
import com.small.client.dto.DataBaseInfo;
import com.small.client.service.SxDataService;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.TaskScheduler;
import org.springframework.scheduling.support.CronTrigger;
import org.springframework.stereotype.Service;
import javax.annotation.PostConstruct;
import java.time.Duration;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ScheduledFuture;
@Service
@Slf4j
public class DynamicTaskScheduler {
private final TaskScheduler taskScheduler;
private final SxDataService sxDataService;
private final Map<String, ScheduledFuture<?>> scheduledTasks = new ConcurrentHashMap<>();
private boolean isRuning =false;
@Autowired
public DynamicTaskScheduler(TaskScheduler taskScheduler, SxDataService sxDataService) {
this.taskScheduler = taskScheduler;
this.sxDataService = sxDataService;
}
@PostConstruct
public void initTasks() {
refreshTasks();
// 每5分钟检查一次数据库更新
taskScheduler.scheduleAtFixedRate(this::refreshTasks, Duration.ofHours(1));
}
public void refreshTasks() {
if(!isRuning){
sxDataService.checkForUpdates();//检查app更新
}
CommentModel commentModel =sxDataService.getCommentModel();
DataBaseInfo enabledTask = sxDataService.getDataBaseInfo(commentModel);
List<DataBaseInfo> enabledTasks=new ArrayList<>();
enabledTasks.add(enabledTask);
// 移除已禁用或删除的任务
scheduledTasks.keySet().removeIf(taskKey ->
enabledTasks.stream().noneMatch(task -> task.getDataBaseName().equals(taskKey)));
// 新增或更新任务
enabledTasks.forEach(task -> {
if (!scheduledTasks.containsKey(task.getDataBaseName()) ||
isCronModified(task)) {
cancelExistingTask(task.getDataBaseName());
scheduleTask(task,commentModel);
}
});
}
private void scheduleTask(DataBaseInfo task, CommentModel commentModel) {
ScheduledFuture<?> future = taskScheduler.schedule(
() -> executeTask(task.getDataBaseName(),commentModel),
new CronTrigger(task.getCronExpression())
);
scheduledTasks.put(task.getDataBaseName(), future);
}
/**
* 业务逻辑执行
* @param taskKey
*/
private void executeTask(String taskKey, CommentModel commentModel) {
isRuning=true;
log.info("execute task key:{}, commentModel:{}", taskKey, commentModel);
if(commentModel==null){
commentModel =sxDataService.getCommentModel();
}
if(StringUtils.isEmpty(commentModel.getSyncTime())){
commentModel =sxDataService.getCommentModel();
}
DataBaseInfo dataBaseInfo=sxDataService.getDataBaseInfo(commentModel);
sxDataService.SyncBranchList(dataBaseInfo,commentModel);
sxDataService.SyncCategory(dataBaseInfo,commentModel);
sxDataService.SyncGoods(dataBaseInfo,commentModel);//todo 暂时同步全部的商品如果后期修改需要增加服务器的字段test
sxDataService.SyncVipList(dataBaseInfo,commentModel);
isRuning=false;
}
private void cancelExistingTask(String taskKey) {
Optional.ofNullable(scheduledTasks.remove(taskKey))
.ifPresent(future -> future.cancel(false));
}
private boolean isCronModified(DataBaseInfo newTask) {
DataBaseInfo dataBaseInfo= sxDataService.getDataBaseInfo(sxDataService.getCommentModel());
return scheduledTasks.containsKey(newTask.getDataBaseName()) &&
!dataBaseInfo.getCronExpression().equals(newTask.getCronExpression());
}
}

View File

@ -0,0 +1,98 @@
/*
* 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.small.client.Utils;
import cn.hutool.core.util.StrUtil;
import cn.hutool.http.HttpUtil;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
public class CommonUtil {
private final static String apiUrl = "http://4ei8850868ux.vicp.fun";
public static JSONObject sendPostRequestToSiXun(String urlPath, JSONObject params) {
String resp = HttpUtil.post(apiUrl + urlPath, params.toString());
if (StrUtil.isBlank(resp)) {
return null;
}
JSONObject respObj = JSONUtil.parseObj(resp);
return respObj;
}
/**
* 根据总条数和分页大小求页数
*
* @param total
* @param pageSize
* @return
*/
public static Integer getPagesCount(Integer total, Integer pageSize) {
if (total == null || pageSize == null || pageSize <= 0 || total <= 0) {
return 0;
}
int pagesCount = 0;
pagesCount = total / pageSize;
if (total % pageSize > 0) {
// 有余数
pagesCount++;
} else {
if (pagesCount == 0) {
pagesCount = 1;
}
}
return pagesCount;
}
/**
* 接口是否成功执行返回
*
* @param jsonObject
* @return
*/
public static Boolean isSuccess(JSONObject jsonObject) {
if (jsonObject == null) {
return false;
}
return jsonObject.get("code") != null && jsonObject.getStr("code").equals("0");
}
/**
* 接口是否成功执行返回
*
* @param jsonObject
* @return
*/
public static Boolean hasSuccessData(JSONObject jsonObject) {
if (jsonObject == null) {
return false;
}
return jsonObject.get("code") != null && jsonObject.getStr("code").equals("0") && jsonObject.get("data") != null;
}
/**
* 通过json节点表达式获取节点json字符串驼峰命名改成下划线命名
*
* @param jsonObject
* @param expression json 节点表达式比如 data.list, msg, code
* @return
*/
public static String toUnderlineJson(JSONObject jsonObject, String expression) {
return StrUtil.toUnderlineCase(jsonObject.getByPath(expression, String.class));
}
}

View File

@ -0,0 +1,110 @@
package com.small.client.Utils;
import javax.crypto.Cipher;
import javax.crypto.spec.SecretKeySpec;
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 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);
}
}

View File

@ -0,0 +1,176 @@
package com.small.client.Utils;
import lombok.extern.slf4j.Slf4j;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.StandardCopyOption;
import java.util.Calendar;
import java.util.Date;
@Slf4j
public class FileUtils {
public static final String pathSeparator = System.getProperty("file.separator");
public static final String FOLDER = System.getProperty("user.home") + pathSeparator+"uploaded"+pathSeparator;
public static final String GOODS = pathSeparator+"goods"+pathSeparator;//商品
public static final String CATEGORY= pathSeparator+ "category"+pathSeparator;//分类
public static final String BRAND = pathSeparator+"brand/"+pathSeparator;//品牌
public static final String MEMBER= pathSeparator+"member"+pathSeparator;//会员
public static final String CLIENTSTALLPATH = System.getProperty("user.home") + pathSeparator+"cientStorePath"+pathSeparator;
public static final String REFLESHDATE="refleshdate.txt";
public static final String PRIMARYKEY="primaryKey.txt";
public static final String GOODS_TYPE = "goods";//商品
public static final String CATEGORY_TYPE= "category";//分类
public static final String BRAND_TYPE = "brand";//品牌
public static final String MEMBER_TYPE= "member";//会员
public static final String okEnd = "ok";//后缀
public static final String txtEnd = "txt";//后缀
public static String fileFormat = "%s_%s.%s";//good_1
public static String getSyncTypeFlag(String syncType){
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 =FOLDER;
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 syncType
* @param page
* @return
*/
public File createFile(String syncType,Integer page){
String path= getSyncTypeFlag(syncType+pathSeparator+page+pathSeparator);
File file=new File(path);
if(!file.exists()){
file.mkdirs();
}
return file;
}
/**
* 创建文件
* @param path
* @return
*/
public File createFile(String path){
File file=new File(path);
if(!file.exists()){
file.mkdirs();
}
return file;
}
/**
* 文件写入
* @param filePath
*/
public void writeFile(String filePath,String fileName,String content){
try {
FileWriter writer = new FileWriter(filePath+pathSeparator+fileName);
writer.write(content);
writer.close();
log.info("文件写入成功!");
} catch (IOException e) {
log.info("文件写入失败:{}", e.getMessage());
}
}
/**
* 根据类型获取文件名称
* @param syncType
* @param page
* @return
*/
public String getFileName(String syncType ,Integer page,String endFix){
String result="";
switch (syncType){
case "1":
result=GOODS_TYPE;
break;
case "2":
result=CATEGORY_TYPE;
break;
case "3":
result=BRAND_TYPE;
break;
case "4":
result=MEMBER_TYPE;
break;
default:
break;
}
return String.format(fileFormat, result,page,endFix);
}
/**
* 创建文件
* @param folderPath
* @param filePath
*/
public static void createFolderAndFileUsingFile(String folderPath, String filePath) {
File folder = new File(folderPath);
if (!folder.exists()) {
folder.mkdir();
}
File file = new File(filePath);
try {
if (!file.exists()) {
file.createNewFile();
}
} catch (IOException e) {
e.printStackTrace();
}
}
public static void copyFile(String srcFile, String destFile) {
String path= JarPathUtil.getRuntimePath();
Path sourceFile = Paths.get(srcFile);
Path targetDir =Paths.get(destFile);
try {
Files.copy(sourceFile, targetDir.resolve(sourceFile.getFileName()),
StandardCopyOption.REPLACE_EXISTING);
} catch (IOException e) {
throw new RuntimeException(e);
}
}
public static void main(String[] args) {
FileUtils fileUtils= new FileUtils();
File file=fileUtils.createFile("1",1);
System.out.printf("--"+file.getAbsoluteFile());
fileUtils.writeFile(file.getAbsolutePath(),fileUtils.getFileName("1",2,txtEnd),"456");
}
}

View File

@ -0,0 +1,107 @@
package com.small.client.Utils;
import cn.hutool.json.JSON;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import com.small.client.dto.StoreDbConfig;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.util.MultiValueMap;
import org.springframework.web.client.RestTemplate;
import java.util.Map;
@Slf4j
public class HttpUtils {
public static final String SUCCESSCODE="0";//上传文件
public static final String URL_UPLOUP="/shop/sync/third/uploudSxData";//上传文件
public static final String URL_SYNC_CATEGORY="/shop/sync/third/goods/category";//商品分类数据同步
public static final String URL_SYNC_BRAND="/shop/sync/third/goods/brand";//商品品牌数据同步
public static final String URL_SYNC_GOODS="/shop/sync/third/goods";//商品数据同步
public static final String URL_SYNC_MEMBER="/shop/sync/third/member";
public static final String URL_SYNC_GOODS_READ="/shop/sync/third/readSxData";//商品数据同步
public static final String URL_SYNC_GET_APPSIGN="/shop/sync/third/getAppSign";//获取密文
public static final String URL_SYNC_GET_DOWNCLIENTJAR="/shop/sync/app/downClientJar";//文件下载
public static final String URL_SYNC_GET_STOREdBCONFIG="/shop/sync/third/getStoreDbConfig";//文件下载
public static String postData(RestTemplate restTemplate, String url,Object modelObject){
// 创建表单参数
// MultiValueMap<String, String> map = new LinkedMultiValueMap<>();
// map.add("key1", "value1");
// map.add("key2", "value2");
// 设置Content-Type为application/x-www-form-urlencoded
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_JSON);
log.info(modelObject.toString());
HttpEntity<Object> request = new HttpEntity<>(modelObject, headers);
// 发送POST请求
JSONObject jsonObject = restTemplate.postForObject(url, request, JSONObject.class);
assert jsonObject != null;
log.info(jsonObject.toString());
return jsonObject.getStr("error_code");
}
public static String postData(RestTemplate restTemplate, String url,Object modelObject,String contentName){
// 创建表单参数
// MultiValueMap<String, String> map = new LinkedMultiValueMap<>();
// map.add("key1", "value1");
// map.add("key2", "value2");
// 设置Content-Type为application/x-www-form-urlencoded
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_JSON);
log.info(modelObject.toString());
HttpEntity<Object> request = new HttpEntity<>(modelObject, headers);
// 发送POST请求
JSONObject jsonObject = restTemplate.postForObject(url, request, JSONObject.class);
assert jsonObject != null;
log.info(jsonObject.toString());
if("OK".equals(jsonObject.get("resultCode"))){
return jsonObject.getStr(contentName);
}
return null;
}
public static StoreDbConfig postDataGetConfig(RestTemplate restTemplate, String url, Object modelObject){
// 创建表单参数
// MultiValueMap<String, String> map = new LinkedMultiValueMap<>();
// map.add("key1", "value1");
// map.add("key2", "value2");
// 设置Content-Type为application/x-www-form-urlencoded
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_JSON);
log.info(modelObject.toString());
HttpEntity<Object> request = new HttpEntity<>(modelObject, headers);
// 发送POST请求
JSONObject jsonObject = restTemplate.postForObject(url, request, JSONObject.class);
assert jsonObject != null;
log.info(jsonObject.toString());
if(0==jsonObject.getInt("error_code")){
JSONObject object= jsonObject.getJSONObject("result");
if(null!=object){
return JSONUtil.toBean(object,StoreDbConfig.class);
}
}
return null;
}
}

View File

@ -0,0 +1,70 @@
package com.small.client.Utils;
import lombok.extern.slf4j.Slf4j;
import java.io.File;
import java.net.URISyntaxException;
import java.net.URL;
import java.nio.file.Path;
import java.nio.file.Paths;
@Slf4j
public class JarPathUtil {
/**
* 更健壮的获取JAR路径方法
*/
public static String getJarPath() {
try {
// 获取当前类的URI
String jarPath = JarPathUtil.class
.getProtectionDomain()
.getCodeSource()
.getLocation()
.toURI()
.getPath();
// 处理Windows路径问题
if (jarPath.startsWith("/") && System.getProperty("os.name").contains("Windows")) {
jarPath = jarPath.substring(1);
}
return new File(jarPath).getAbsolutePath();
} catch (URISyntaxException e) {
throw new RuntimeException("无法解析JAR文件URI", e);
}
}
/**
* 使用NIO获取JAR所在目录
*/
public static String getJarParentPath() {
try {
Path path = Paths.get(JarPathUtil.class.getProtectionDomain()
.getCodeSource()
.getLocation()
.toURI());
return path.getParent().toString();
} catch (URISyntaxException e) {
throw new RuntimeException("无法解析JAR文件URI", e);
}
}
public static String getRuntimePath() {
URL location = JarPathUtil.class.getProtectionDomain()
.getCodeSource()
.getLocation();
String path = location.getPath();
// 判断是否在IDE中运行class文件
if (path.endsWith(".jar")) {
// JAR运行模式
return new File(path).getParent();
} else {
// IDE运行模式返回项目目录
return new File("").getAbsolutePath();
}
}
public static void main(String[] args) {
log.info(getRuntimePath());
}
}

View File

@ -0,0 +1,30 @@
package com.small.client.comment;
import lombok.Getter;
public enum DicEnum {
//1-品牌2-分类3-商品4-会员
SYNCTYPE_1("1","品牌","syncType","同步类型"),
SYNCTYPE_2("2","分类","syncType","同步类型"),
SYNCTYPE_3("3","商品","syncType","同步类型"),
SYNCTYPE_4("4","会员","syncType","同步类型"),
;
@Getter
private String code;
@Getter
private String name;
@Getter
private String dicType;
@Getter
private String description;
DicEnum(String code, String name, String dicType, String description) {
this.code = code;
this.name = name;
this.dicType = dicType;
this.description = description;
}
}

View File

@ -0,0 +1,11 @@
package com.small.client.comment;
public class UrlComment {
public static String url="";//获取shop的数据库基本信息 todo
public static String UrlSynShop="";//商品同步接口
public static String UrlSynCategory="";//商品种类同步接口
public static String UrlSynProduct="";
}

View File

@ -0,0 +1,14 @@
package com.small.client.config;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.client.RestTemplate;
@Configuration
public class ClientConfig {
@Bean
public RestTemplate restTemplate() {
return new RestTemplate();
}
}

View File

@ -0,0 +1,18 @@
package com.small.client.config;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.TaskScheduler;
import org.springframework.scheduling.annotation.EnableScheduling;
import org.springframework.scheduling.concurrent.ConcurrentTaskScheduler;
import java.util.concurrent.Executors;
@Configuration
@EnableScheduling
public class TaskConfig {
@Bean
public TaskScheduler taskScheduler() {
return new ConcurrentTaskScheduler(Executors.newScheduledThreadPool(10)); // 使用默认线程池
}
}

View File

@ -0,0 +1,79 @@
package com.small.client.controller;
import com.small.client.Utils.HttpUtils;
import com.small.client.dto.DataBaseInfo;
import com.small.client.dto.SyncGoodsSearchModel;
import com.small.client.service.SxDataService;
import com.small.client.service.WebClientService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
@RequestMapping("/client")
@Slf4j
public class WebController {
@Autowired
private WebClientService webClientService;
@Autowired
private SxDataService sxDataService;
@RequestMapping("/upload")
public void upload(){
System.out.println("upload");
//webClientService.uploudSxData();
}
@RequestMapping("/synBrand")
public void synBrand(){
log.info("synBrand");
sxDataService.getAppSign();
sxDataService.SyncBranchList(new DataBaseInfo(),sxDataService.getCommentModel());
}
@RequestMapping("/syncCategory")
public void syncCategory(){
log.info("syncCategory");
sxDataService.getAppSign();
sxDataService.SyncCategory(new DataBaseInfo(),sxDataService.getCommentModel());
}
@RequestMapping("/syncGoods")
public void syncGoods(){
log.info("syncGoods");
sxDataService.getAppSign();
sxDataService.SyncGoods(new DataBaseInfo(),sxDataService.getCommentModel());
}
@RequestMapping("/synvip")
public void synvip(){
log.info("synvip");
sxDataService.getAppSign();
sxDataService.SyncVipList(new DataBaseInfo(),sxDataService.getCommentModel());
}
@RequestMapping("/getAppSign")
public void getAppSign(){
log.info("getAppSign");
sxDataService.getAppSign();
}
@RequestMapping("/downLoadClient")
public void downLoadClient(){
log.info("downLoadClient");
sxDataService.downLoadClient();
}
@RequestMapping("/udpateAndStart")
public void updateAndStart(){
sxDataService.checkForUpdates();
}
@RequestMapping("/getDataBaseInfo")
public void getDataBaseInfo(){
sxDataService.getDataBaseInfo(sxDataService.getCommentModel());
}
}

View File

@ -0,0 +1,246 @@
package com.small.client.dao;
import com.microsoft.sqlserver.jdbc.SQLServerDataSource;
import com.microsoft.sqlserver.jdbc.SQLServerException;
import com.small.client.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 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,Integer port, 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(port==null?PortNumber:port);
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,Integer portNumber, String dataBaseName, String table,String where){
Connection connection=getConnection(ip,username,password,portNumber,dataBaseName);
String sql="select * from %s %s";
sql=String.format(sql, table,where);
ResultDto resultDto=new ResultDto();
ResultSet rs=null;
log.info(sql);
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,Integer portNumber, String dataBaseName, String table,String orderColumn, int pageNo, int pageSize,String where){
Connection connection=getConnection(ip,username,password,portNumber,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 %s" +
" ) as r where rowId between %s and %s";
sql=String.format(sql, orderColumn,table,where,start,end);
log.info(sql);
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,Integer portNumber, String dataBaseName, String table,String where){
int total=0;
Connection connection=getConnection(ip,username,password,portNumber,dataBaseName);
try {
String sql="select count(*) from %s %s";
sql=String.format(sql, table,where);
log.info(sql);
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;
}
public Integer getBaseJoinTotal(String ip, String username, String password,Integer portNumber, String dataBaseName, String table,String joinTable,String onLeft,String onRight,String orderColumn,String rightSelect,String where){
int total=0;
Connection connection=getConnection(ip,username,password,portNumber,dataBaseName);
try {
String sql=" select COUNT(*) from( " +
" select ROW_NUMBER() OVER(ORDER BY b.%s) as rowId,b.*,%s from %s b left join %s t on b.%s=t.%s %s" +
" ) r";
sql=String.format(sql, orderColumn,rightSelect,table,joinTable,onLeft,onRight,where);
log.info(sql);
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;
}
/**
* 带分页数据关联分页查询
* @param ip
* @param username
* @param password
* @param dataBaseName
* @param table
* @return
*/
public ResultDto baseFindListJoinPage(String ip, String username, String password,Integer portNumber, String dataBaseName, String table,String joinTable,String onLeft,String onRight,String orderColumn,String rightSelect, int pageNo, int pageSize,String where){
Connection connection=getConnection(ip,username,password,portNumber,dataBaseName);
int start=(pageNo-1)*pageSize+1;
int end=pageNo*pageSize;
String sql=" select * from( " +
" select ROW_NUMBER() OVER(ORDER BY b.%s) as rowId,b.*,%s from %s b left join %s t on b.%s=t.%s %s" +
" ) as r where rowId between %s and %s";
sql=String.format(sql, orderColumn,rightSelect,table,joinTable,onLeft,onRight,where,start,end);
log.info(sql);
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.baseFindListJoinPage",e.getMessage());
throw new RuntimeException(e);
}
resultDto.setResultSet(rs);
resultDto.setConnection(connection);
return resultDto;
}
/**
*
* @param ip
* @param username
* @param password
* @param dataBaseName
* @param table
* @param joinTable
* @param onLeft
* @param onRight
* @param rightSelect
* @param where
* @return
*/
public ResultDto baseFindListJoin(String ip, String username, String password,Integer portNumber, String dataBaseName, String table,String joinTable,String onLeft,String onRight,String rightSelect, String where){
Connection connection=getConnection(ip,username,password,portNumber,dataBaseName);
String sql= "select b.*,%s from %s b left join %s t on b.%s=t.%s %s " ;
sql=String.format(sql,rightSelect,table,joinTable,onLeft,onRight,where);
log.info(sql);
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.baseFindListJoin",e.getMessage());
throw new RuntimeException(e);
}
resultDto.setResultSet(rs);
resultDto.setConnection(connection);
return resultDto;
}
}

View File

@ -0,0 +1,448 @@
package com.small.client.dao;
import com.small.client.dto.*;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.nio.charset.Charset;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;
/**
* 考虑到每个思迅软件都是自己的数据所以采用动态获取的方式获取数据
* 数据库为MS SQL
* todo 如果考虑到数据量需要分页多线程
*/
@Service
@Slf4j
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 T_RM_VIP_INFO="t_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";//会员表排序字段
private final static String T_BD_BASE_CODE="t_bd_base_code";//品牌表
private final static String T_BD_BASECODE_TYPE="t_bd_basecode_type";//品牌表
private final static String TYPE_NO="type_no";//品牌排序字段
private final static String T_IM_BRANCH_STOCK="t_im_branch_stock";//库存表
private final static String T_RM_SPEC_PRICE="t_rm_spec_price";//活动表
public final static Integer PAGESIZE=500;
public final static String DEFALTWHERE="where 1=1";
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 dataBaseInfo
*/
public List<SxSyncCategory> findTBdItemClsList(DataBaseInfo dataBaseInfo){
ResultDto resultDto=baseFindList(dataBaseInfo.getIp(),dataBaseInfo.getUserName(),dataBaseInfo.getPassword(),dataBaseInfo.getDbPort(),dataBaseInfo.getDataBaseName(),T_BD_ITEM_CLS,DEFALTWHERE);
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").trim());//分类名称
if(null!=rs.getString("cls_parent")){
sxSyncCategory.setCls_parent(rs.getString("cls_parent").trim());//父级编码
}
sxSyncCategory.setItem_clsno(rs.getString("item_clsno").trim());//分类编码
// 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;
}
/**
* 分页查找商品分类数据
* @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.getDbPort(),dataBaseInfo.getDataBaseName(),T_BD_ITEM_CLS,ITEM_CLSNO,pageNo,pageSize,DEFALTWHERE);
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"));//分类编码
// log.info(rs.getString("item_clsname")+"\t");//分类名称
//log.info(rs.getString("cls_parent")+"\t");//父级编码
//log.info(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.getDbPort(),dataBaseInfo.getDataBaseName(),T_BD_ITEM_CLS,DEFALTWHERE);
}
/**
* 获取商品表t_bd_item_info表的数量
* @param dataBaseInfo
* @return
*/
public int getTBditemInfoTotal(DataBaseInfo dataBaseInfo){
// String where =DEFALTWHERE;
// if(syncGoodsSearchModel!=null){
// if(dataBaseInfo.getWhere()!=null){
// where+= dataBaseInfo.getWhere();
// }
// }
return getBaseTotal(dataBaseInfo.getIp(),dataBaseInfo.getUserName(),dataBaseInfo.getPassword(),dataBaseInfo.getDbPort(),dataBaseInfo.getDataBaseName(),T_BD_ITEM_INFO,dataBaseInfo.getWhere());
}
/**
* 获取商品表t_bd_item_info表的数量
* @param dataBaseInfo
* @return
*/
public int getTBditemInfoJoninTotal(DataBaseInfo dataBaseInfo){
return getBaseJoinTotal(dataBaseInfo.getIp(),dataBaseInfo.getUserName(),dataBaseInfo.getPassword(),dataBaseInfo.getDbPort(),dataBaseInfo.getDataBaseName()
, T_BD_ITEM_INFO
,T_IM_BRANCH_STOCK
,"item_no"
,"item_no"
,ITEM_CLSNO
,"t.stock_qty,t.oper_date"
,dataBaseInfo.getWhere()==null?DEFALTWHERE:dataBaseInfo.getWhere());
}
/**
* 获取会员表t_rm_vip_info表的数量
* @param dataBaseInfo
* @return
*/
public int getTrmVipInfoTotal(DataBaseInfo dataBaseInfo){
return getBaseTotal(dataBaseInfo.getIp(),dataBaseInfo.getUserName(),dataBaseInfo.getPassword(),dataBaseInfo.getDbPort(),dataBaseInfo.getDataBaseName(),T_RM_VIP_INFO,dataBaseInfo.getWhere());
}
/**
* 分页查找商品数据
* 表T_BD_ITEM_INFO
* @param dataBaseInfo
* @param pageNo
* @param pageSize
*/
public List<SxSyncGoods> findBditemInfoListPage(DataBaseInfo dataBaseInfo,int pageNo,int pageSize){
ResultDto resultDto=baseFindListJoinPage(dataBaseInfo.getIp(),dataBaseInfo.getUserName(),dataBaseInfo.getPassword(),dataBaseInfo.getDbPort(),dataBaseInfo.getDataBaseName()
, T_BD_ITEM_INFO
,T_IM_BRANCH_STOCK
,"item_no"
,"item_no"
,ITEM_CLSNO
,"t.stock_qty,t.oper_date"
,pageNo,pageSize,dataBaseInfo.getWhere()==null?DEFALTWHERE:dataBaseInfo.getWhere());
ResultSet rs= resultDto.getResultSet();
List<SxSyncGoods> sxSyncGoodses=new ArrayList<>();
SxSyncGoods sxSyncGoods=null;
try {
while (rs.next()) {
sxSyncGoods=new SxSyncGoods();
BigDecimal price=new BigDecimal(rs.getString("price"));
BigDecimal salePrice=new BigDecimal(rs.getString("sale_price"));
if(salePrice.compareTo(new BigDecimal("0"))>0){
try{
BigDecimal gross= salePrice.subtract(price).divide(salePrice,4, RoundingMode.HALF_UP);
sxSyncGoods.setGross_margin(gross);//毛利率
}catch (RuntimeException e){
log.info("运行错误:{}",e.getMessage());
log.info(String.valueOf(rs.getString("sale_price")));
}
}else {
sxSyncGoods.setGross_margin(new BigDecimal("0"));//毛利率
}
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(rs.getString("item_clsno").trim());//商品小类 todo 如何关联
sxSyncGoods.setItem_size(rs.getString("item_size"));//规格
sxSyncGoods.setUnit_no(rs.getString("unit_no"));//单位 todo
sxSyncGoods.setStock(rs.getBigDecimal("stock_qty"));//库存数量 todo item_stock
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"));//生产日期 todo
sxSyncGoods.setValid_days(getStopDate(rs));//保质期 todo stop_date-build_date
sxSyncGoods.setItem_brand_name(rs.getString("item_brandname"));
sxSyncGoods.setItemBrand(rs.getString("item_brand"));
sxSyncGoods.setItem_clsno(rs.getString("item_clsno").trim());
sxSyncGoods.setItem_size(rs.getString("item_size"));
sxSyncGoodses.add(sxSyncGoods);
}
} catch (SQLException e) {
throw new RuntimeException(e);
} finally {
try {
resultDto.getConnection().close();
} catch (SQLException e) {
throw new RuntimeException(e);
}
}
return sxSyncGoodses;
}
private static String getStopDate(ResultSet rs) throws SQLException {
return rs.getString("stop_date");
}
/**
* 分页查找会员数据
* 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.getDbPort(),dataBaseInfo.getDataBaseName(),T_RM_VIP_INFO,CARD_ID,pageNo,pageSize,dataBaseInfo.getWhere());
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"));//建档日期
log.info(rs.getString("vip_name"));//会员名称
log.info(rs.getString("mobile"));//会员手机号
log.info(rs.getString("vip_sex"));//会员性别
log.info(rs.getString("birthday"));//会员生日
log.info(rs.getString("card_no"));//会员卡号
log.info(rs.getString("card_type"));//会员等级
log.info("{}",rs.getBigDecimal("residual_amt"));//储值余额
log.info("{}",rs.getBigDecimal("now_acc_num"));//会员积分
log.info(rs.getString("vip_start_date"));//建档日期
log.info("{}",rs.getInt("card_status"));//会员状态
}
sxSyncVips.add(sxSyncVip);
}
}catch (SQLException e){
throw new RuntimeException(e);
}
return sxSyncVips;
}
/**
* 获取品牌数据
* @param dataBaseInfo
*/
public List<BrandModel> getBdBrandList(DataBaseInfo dataBaseInfo) {
String where="where t.type_name='品牌'";
ResultDto resultDto=baseFindListJoin(dataBaseInfo.getIp()
,dataBaseInfo.getUserName()
,dataBaseInfo.getPassword()
,dataBaseInfo.getDbPort()
,dataBaseInfo.getDataBaseName()
,T_BD_BASE_CODE
,"t_bd_basecode_type"
,"type_no"
,"type_no"
,"t.type_name"
,where);
ResultSet rs= resultDto.getResultSet();
List<BrandModel> brandModels=new ArrayList<>();
try {
while (rs.next()) {
BrandModel brandModel=new BrandModel();
brandModel.setBrand_name(rs.getString("code_name"));
brandModel.setBrand_desc(rs.getString("code_name"));
brandModel.setCodeId(rs.getString("code_id"));
brandModel.setBrand_image("");
brandModel.setCategory("0");
brandModel.setBrand_recommend("0");//是否推荐
brandModels.add(brandModel);
// log.info(rs.getString("type_no")+"--"+rs.getString("code_name"));//分类编码-分类名称
}
} catch (SQLException e) {
throw new RuntimeException(e);
} finally {
try {
resultDto.getConnection().close();
} catch (SQLException e) {
throw new RuntimeException(e);
}
}
return brandModels;
}
/**
* 获取库存数据
* @return
*/
public List<ImBranchStock> getImBranchStockList(DataBaseInfo dataBaseInfo,String where){
ResultDto resultDto=baseFindList(dataBaseInfo.getIp()
,dataBaseInfo.getUserName()
,dataBaseInfo.getPassword()
,dataBaseInfo.getDbPort()
,dataBaseInfo.getDataBaseName()
,T_IM_BRANCH_STOCK
,where);
ResultSet rs= resultDto.getResultSet();
List<ImBranchStock> branchStocks=new ArrayList<>();
try {
while (rs.next()) {
ImBranchStock brandModel=new ImBranchStock();
brandModel.setBranchNo(rs.getString("branch_no"));
brandModel.setStockQty(rs.getBigDecimal("stock_qty"));
brandModel.setItemNo(rs.getString("item_no"));
brandModel.setPerDate(rs.getString("oper_date"));
branchStocks.add(brandModel);
}
} catch (SQLException e) {
throw new RuntimeException(e);
} finally {
try {
resultDto.getConnection().close();
} catch (SQLException e) {
throw new RuntimeException(e);
}
}
return branchStocks;
}
/**
*获取促销活动价格 时段特价单
* @param dataBaseInfo
* @return
*/
public List<SpecPriceDto> getSpecPriceList(DataBaseInfo dataBaseInfo){
ResultDto resultDto=baseFindList(dataBaseInfo.getIp()
,dataBaseInfo.getUserName()
,dataBaseInfo.getPassword()
,dataBaseInfo.getDbPort()
,dataBaseInfo.getDataBaseName()
,"T_RM_SPEC_PRICE"
,"where special_type ='0'");
ResultSet rs= resultDto.getResultSet();
List<SpecPriceDto> specPriceDtos=new ArrayList<>();
try {
while (rs.next()) {
SpecPriceDto specPriceDto=new SpecPriceDto();
specPriceDto.setItemNo(rs.getString("item_no"));//
specPriceDto.setOldPrice(rs.getBigDecimal("old_price"));//原价
specPriceDto.setSpecPrice(rs.getBigDecimal("spe_price"));//特价
specPriceDto.setSpecPrice(rs.getBigDecimal("sale_qty"));//限购
specPriceDto.setDiscountType("0");
specPriceDtos.add(specPriceDto);
}
} catch (SQLException e) {
throw new RuntimeException(e);
} finally {
try {
resultDto.getConnection().close();
} catch (SQLException e) {
throw new RuntimeException(e);
}
}
return specPriceDtos;
}
/**
* 折扣商品
* @param dataBaseInfo
* @return
*/
public List<SpecPriceDto> getDiscountPriceList(DataBaseInfo dataBaseInfo){
ResultDto resultDto=baseFindList(dataBaseInfo.getIp()
,dataBaseInfo.getUserName()
,dataBaseInfo.getPassword()
,dataBaseInfo.getDbPort()
,dataBaseInfo.getDataBaseName()
,T_RM_SPEC_PRICE
,"where special_type in('6','G')");
ResultSet rs= resultDto.getResultSet();
List<SpecPriceDto> specPriceDtos=new ArrayList<>();
try {
while (rs.next()) {
SpecPriceDto specPriceDto=new SpecPriceDto();
specPriceDto.setItemNo(rs.getString("item_no"));//
specPriceDto.setDiscount(rs.getBigDecimal("discount"));//原价
specPriceDto.setDiscountType("1");
specPriceDtos.add(specPriceDto);
}
} catch (SQLException e) {
throw new RuntimeException(e);
} finally {
try {
resultDto.getConnection().close();
} catch (SQLException e) {
throw new RuntimeException(e);
}
}
return specPriceDtos;
}
}

View File

@ -0,0 +1,27 @@
package com.small.client.dto;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import java.io.Serializable;
@Data
public class BrandModel implements Serializable {
@ApiModelProperty("品牌名称")
private String brand_name;
@ApiModelProperty("品牌编号")
private String codeId;
@ApiModelProperty("品牌描述")
private String brand_desc;
@ApiModelProperty("品牌分类")
private String category;
@ApiModelProperty("图片")
private String brand_image;
@ApiModelProperty("是否推荐")
private String brand_recommend;
}

View File

@ -0,0 +1,17 @@
package com.small.client.dto;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
@Data
public class CommentModel {
@ApiModelProperty("店铺的key")
private String appKey;
@ApiModelProperty("店铺的密钥")
private String sign;
@ApiModelProperty("店铺的id")
private String storeId;
@ApiModelProperty(value = "同步时间-用于增量同步,大于这个时间证明是增量")
private String syncTime;//同步时间
}

View File

@ -0,0 +1,33 @@
package com.small.client.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;
@ApiModelProperty("条件")
private String where;
@ApiModelProperty(value = "数据库端口")
private Integer dbPort;
@ApiModelProperty(value = "定时同步的cron表达式")
private String cronExpression;
@ApiModelProperty(value = "同步模式(1:定时同步,2:间隔同步)")
private String syncMode;
@ApiModelProperty(value = "商品分类")
private String categoryName;
@ApiModelProperty(value = "01全量02增量")
private String syncType;
@ApiModelProperty(value = "操作时间")
private String operDate;
}

View File

@ -0,0 +1,18 @@
package com.small.client.dto;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import java.math.BigDecimal;
@Data
public class ImBranchStock {
@ApiModelProperty("商品编号")
private String itemNo;
@ApiModelProperty("商标编号")
private String branchNo;
@ApiModelProperty("库存")
private BigDecimal stockQty;
@ApiModelProperty("操作时间")
private String perDate;
}

View File

@ -0,0 +1,17 @@
package com.small.client.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;
}

View File

@ -0,0 +1,17 @@
package com.small.client.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;
}

View File

@ -0,0 +1,15 @@
package com.small.client.dto;
import lombok.Data;
import java.sql.Connection;
import java.sql.ResultSet;
@Data
public class ResultDto {
private Connection connection;
private ResultSet resultSet;
}

View File

@ -0,0 +1,19 @@
package com.small.client.dto;
import lombok.Data;
import java.math.BigDecimal;
@Data
public class SpecPriceDto {
private String itemNo;
private BigDecimal oldPrice;//原价
private BigDecimal specPrice;//折后价
private BigDecimal discount;//折扣('6','G')
private Integer saleQty;//限购
private String discountType;//折扣类型 0-特价1打折
}

View File

@ -0,0 +1,64 @@
package com.small.client.dto;
import com.fasterxml.jackson.annotation.JsonFormat;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import java.io.Serializable;
import java.util.Date;
@Data
public class StoreDbConfig implements Serializable {
private static final long serialVersionUID = 1L;
@ApiModelProperty(value = "主键ID")
private Long id;
@ApiModelProperty(value = "店铺ID")
private String storeId;
@ApiModelProperty(value = "数据库类型(mysql/oracle/sqlserver等)")
private String dbType = "sqlserver";
@ApiModelProperty(value = "数据库名称")
private String dbName;
@ApiModelProperty(value = "数据库IP地址")
private String dbIp;
@ApiModelProperty(value = "数据库端口")
private Integer dbPort;
@ApiModelProperty(value = "数据库用户名")
private String dbUsername;
@ApiModelProperty(value = "数据库密码(建议加密存储)")
private String dbPassword;
@ApiModelProperty(value = "是否有外网访问(0:无,1:有)")
private String hasInternet;
@ApiModelProperty(value = "同步模式(1:定时同步,2:间隔同步)")
private String syncMode;
@ApiModelProperty(value = "是否启用(0:否,1:是)")
private String hasStart;
@ApiModelProperty(value = "定时同步的cron表达式")
private String cronExpression;
@ApiModelProperty(value = "商品分类")
private String categoryName;
@ApiModelProperty(value = "创建时间")
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
private Date createTime;
@ApiModelProperty(value = "更新时间")
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
private Date updateTime;
@ApiModelProperty(value = "备注信息")
private String remark;
}

View File

@ -0,0 +1,32 @@
package com.small.client.dto;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import java.math.BigDecimal;
/**
* 模型对应
*/
@Data
public class SxCategoryModel {
//模型对应ShopBaseProductCategory start
private String parent_name;//暂时不用
@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;
}

View File

@ -0,0 +1,103 @@
package com.small.client.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;
}

View File

@ -0,0 +1,68 @@
/*
* Copyright (c) 2024. 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.small.client.dto;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.NoArgsConstructor;
import java.io.Serializable;
import java.util.Date;
import java.util.List;
/**
* 思迅同步的商品分类表
*/
@Data
@NoArgsConstructor
@AllArgsConstructor
@EqualsAndHashCode
@ApiModel(value = "商品分类表", description = "商品分类表")
public class SxSyncCategory implements Serializable {
private static final long serialVersionUID = 1L;
@ApiModelProperty(value = "自增ID")
private Long id;
@ApiModelProperty(value = "店铺Id")
private String store_id;
@ApiModelProperty(value = "分类编码")
private String item_clsno;
@ApiModelProperty(value = "分类名称")
private String item_clsname;
@ApiModelProperty(value = "父类编号")
private String cls_parent;
@ApiModelProperty(value = "分类排序")
private Integer item_order;
@ApiModelProperty(value = "是否显示1-前台显示 0-前台不显示")
private Integer display_flag;
@ApiModelProperty(value = "状态")
private Integer status;
@ApiModelProperty(value = "同步时间戳")
private Long sync_time;
@ApiModelProperty(value = "新增时间")
private Date created_at;
@ApiModelProperty(value = "更新时间")
private Date updated_at;
@ApiModelProperty(value = "子节点")
List<SxSyncCategory> children;
}

View File

@ -0,0 +1,118 @@
/*
* Copyright (c) 2024. 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.small.client.dto;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.NoArgsConstructor;
import java.io.Serializable;
import java.math.BigDecimal;
import java.util.Date;
/**
* 思迅同步的商品表
*/
@Data
@NoArgsConstructor
@AllArgsConstructor
@EqualsAndHashCode
@ApiModel(value = "商品信息表", description = "商品信息表")
public class SxSyncGoods implements Serializable {
private static final long serialVersionUID = 1L;
@ApiModelProperty(value = "自增ID")
private Long id;
@ApiModelProperty(value = "店铺Id")
private String store_id;
@ApiModelProperty(value = "商品编号")
private String item_no;
@ApiModelProperty(value = "商品名称")
private String item_subname;
@ApiModelProperty(value = "商品条码")
private String item_subno;
@ApiModelProperty(value = "小分类编号")
private String item_clsno;
@ApiModelProperty(value = "大分类名称")
private String big_cls_name;
@ApiModelProperty(value = "小分类名称")
private String small_cls_name;
@ApiModelProperty(value = "规格")
private String item_size;
@ApiModelProperty(value = "单位")
private String unit_no;
@ApiModelProperty(value = "库存")
private BigDecimal stock;
@ApiModelProperty(value = "毛利率")
private BigDecimal gross_margin;
@ApiModelProperty(value = "进货价")
private BigDecimal price;
@ApiModelProperty(value = "零售价")
private BigDecimal sale_price;
@ApiModelProperty(value = "会员价")
private BigDecimal vip_price;
@ApiModelProperty(value = "允许积分")
private BigDecimal vip_acc_flag;
@ApiModelProperty(value = "积分值")
private BigDecimal vip_acc_num;
@ApiModelProperty(value = "商品状态")
private Integer sale_flag;
@ApiModelProperty(value = "品牌名称")
private String item_brand_name;
@ApiModelProperty(value = "商品助记号")
private String item_rem;
@ApiModelProperty(value = "生产日期")
private String build_date;
@ApiModelProperty(value = "质保期")
private String valid_days;
@ApiModelProperty(value = "状态")
private Integer status;
@ApiModelProperty(value = "同步时间戳")
private Long sync_time;
@ApiModelProperty(value = "同步备注")
private String remark;
@ApiModelProperty(value = "新增时间")
private Date created_at;
@ApiModelProperty(value = "更新时间")
private Date updated_at;
@ApiModelProperty(value = "品牌")
private String itemBrand;
}

View File

@ -0,0 +1,80 @@
/*
* Copyright (c) 2024. 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.small.client.dto;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.NoArgsConstructor;
import java.io.Serializable;
import java.math.BigDecimal;
import java.util.Date;
/**
* 思迅同步的商品表
*/
@Data
@NoArgsConstructor
@AllArgsConstructor
@EqualsAndHashCode
@ApiModel(value = "会员表", description = "会员表")
public class SxSyncVip implements Serializable {
private static final long serialVersionUID = 1L;
@ApiModelProperty(value = "自增ID")
private Long id;
@ApiModelProperty(value = "店铺Id")
private String store_id;
@ApiModelProperty(value = "会员名称")
private String vip_name;
@ApiModelProperty(value = "手机号")
private String mobile;
@ApiModelProperty(value = "会员性别")
private String vip_sex;
@ApiModelProperty(value = "会员生日")
private String birthday;
@ApiModelProperty(value = "会员卡号(唯一键)")
private String card_no;
@ApiModelProperty(value = "会员等级")
private String card_type;
@ApiModelProperty(value = "储值余额")
private BigDecimal residual_amt;
@ApiModelProperty(value = "会员积分")
private BigDecimal now_acc_num;
@ApiModelProperty(value = "加入时间")
private String vip_date;
@ApiModelProperty(value = "会员状态")
private Integer card_status;
@ApiModelProperty(value = "同步时间")
private Long sync_time;
@ApiModelProperty(value = "状态")
private Integer status;
@ApiModelProperty(value = "新增时间")
private Date created_at;
@ApiModelProperty(value = "更新时间")
private Date updated_at;
}

View File

@ -0,0 +1,22 @@
package com.small.client.dto;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import java.io.Serializable;
@Data
public class SyncGoodsSearchModel implements Serializable {
@ApiModelProperty(value = "分类名称")
private String categoryName;//分类名称
@ApiModelProperty(value = "同步分类编号")
private String itemClsno;
@ApiModelProperty(value = "操作时间")
private String operDate;
@ApiModelProperty(value = "01全量02增量")
private String syncType;
}

View File

@ -0,0 +1,54 @@
/*
* 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.small.client.dto;
import com.fasterxml.jackson.annotation.JsonInclude;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.io.Serializable;
import java.math.BigDecimal;
import java.util.Date;
@Data
@AllArgsConstructor
@NoArgsConstructor
@JsonInclude(JsonInclude.Include.NON_NULL)
@ApiModel(description = "第三方会员同步请求参数")
public class SyncThirdMemberReq{
private static final long serialVersionUID = 1L;
@ApiModelProperty("会员手机号")
private String user_mobile;
@ApiModelProperty("会员昵称")
private String user_nickname;
@ApiModelProperty("会员真实姓名")
private String user_realname;
@ApiModelProperty("会员性别1-男2-女;")
private Integer user_gender;
@ApiModelProperty("会员生日 yyyy-MM-dd")
private String user_birthday;
@ApiModelProperty("会员等级v1...v9")
private String user_level;
@ApiModelProperty("会员卡号")
private String user_level_card;
@ApiModelProperty("会员积分值")
private BigDecimal user_points;
@ApiModelProperty("会员余额")
private BigDecimal user_money;
@ApiModelProperty("加入时间")
private Date join_time;
@ApiModelProperty("秒级别时间戳")
private Long time_stamp;
@ApiModelProperty("随机字符串")
private String nonce_str;
}

View File

@ -0,0 +1,15 @@
package com.small.client.dto;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import lombok.EqualsAndHashCode;
@EqualsAndHashCode(callSuper = true)
@Data
public class UploadModel extends CommentModel{
@ApiModelProperty("页数作为路径")
private String page;
@ApiModelProperty("同步类型1商品,2分类,3品牌,4会员")
private String syncType;
}

View File

@ -0,0 +1,72 @@
package com.small.client.enums;
public enum DicEnum {
SYNCTYPE_01("01","全量","syncType","同步类型","全量同步"),
SYNCTYPE_02("02","增量","syncType","同步类型","增量同步"),
MUAL_1("1","商品","mual","商品","全量同步"),
MUAL_2("2","分类","mual","分类","分类"),
MUAL_3("3","品牌","mual","品牌","品牌"),
MUAL_4("4","会员","mual","会员","会员"),
;
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;
}
}

View File

@ -0,0 +1,180 @@
package com.small.client.service.SxDataAbst;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.collection.CollectionUtil;
import com.small.client.Cache.CommonCache;
import com.small.client.dao.SxDataDao;
import com.small.client.dto.*;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.time.DateUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.math.BigDecimal;
import java.text.ParseException;
import java.util.*;
import java.util.stream.Collectors;
@Service
@Slf4j
public abstract class SxDataAbstService {
@Autowired
private CommonCache commonCache;
/**
* 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 ("".equals(sxSyncVip.getVip_name())) {//todo 需要确认数据是不是这样判断
syncThirdMemberReq.setUser_gender(1);
}
if ("".equals(sxSyncVip.getVip_name())) {
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) {
log.info("时间转换异常{0}",e);
throw new RuntimeException(e);
}
}
syncThirdMemberReqList.add(syncThirdMemberReq);
}
}
return syncThirdMemberReqList;
}
/**
*
* @param sxSyncCategories
* @param allSxSyncCategories 所有分类
* @return
*/
public List<SxCategoryModel> ConVToSxCategoryModel(List<SxSyncCategory> sxSyncCategories,List<SxSyncCategory> allSxSyncCategories) {
if(CollectionUtil.isEmpty(sxSyncCategories)){
return new ArrayList<>();
}
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(allSxSyncCategories,sxSyncCategory.getCls_parent());
sxCategoryModel.setParent_name(firstNode.getItem_clsname());//todo 暂时无用
//如何存在上级的上级则上级为第二层上上及为第一层
if(null!=firstNode.getCls_parent()) {//还存在上级
SxSyncCategory secondNode=getParentNode(allSxSyncCategories,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();
}
/**
* 将List<sxSyncGoods>转换为List<SxGoosModel>
* @param sxSyncGoods
* @return
*/
public List<SxGoosModel> CvtToGoosModel(List<SxSyncGoods> sxSyncGoods,List<SpecPriceDto> specPriceDtoList){
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(sxSyncGood.getItem_no().trim());// todo
sxGoosModel.setProduct_barcode(sxSyncGood.getItem_subno());// todo
sxGoosModel.setFirst_category_name(commonCache.get(sxSyncGood.getSmall_cls_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.setPrice(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.setRetail_price(sxSyncGood.getSale_price());
// sxGoosModel.setBuy_limit(10);//最大购买商品量 todo
sxGoosModel.setBrand_name(commonCache.get(sxSyncGood.getItemBrand()));//品牌 todo
sxGoosModel.setTags("");//标签 todo
sxGoosModel.setProduct_assist(Arrays.asList(sxSyncGood.getItem_subname()));//帮助 todo
sxGoosModel.setProduct_spec(Collections.singletonList(sxSyncGood.getItem_size()==null?"":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
SxGoosModel finalSxGoosModel = sxGoosModel;
specPriceDtoList.forEach(m->{
if(sxSyncGood.getItem_no().equals(m.getItemNo())){
String type=m.getDiscountType();
if(type.equals("1")){
finalSxGoosModel.setPrice(m.getSpecPrice());
finalSxGoosModel.setBuy_limit(m.getSaleQty());//最大购买商品量 todo
}
if(type.equals("2")){
finalSxGoosModel.setPrice(finalSxGoosModel.getPrice().multiply(m.getDiscount()));
}
}
});
sxGoosModelList.add(sxGoosModel);
}
return sxGoosModelList;
}
}

View File

@ -0,0 +1,53 @@
package com.small.client.service;
import com.small.client.dto.*;
public interface SxDataService {
/**
* 同步商品分类数据
* @param dataBaseInfo
* @param commentModel
*/
void SyncCategory(DataBaseInfo dataBaseInfo, CommentModel commentModel);
/**
* 同步商品数据
* @param dataBaseInfo
* @param commentModel
*/
void SyncGoods(DataBaseInfo dataBaseInfo, CommentModel commentModel);
/**
* 品牌同步
* @param dataBaseInfo
* @return
*/
void SyncBranchList(DataBaseInfo dataBaseInfo, CommentModel commentModel);
/**
* 同步会员数据
* @param dataBaseInfo
*/
void SyncVipList(DataBaseInfo dataBaseInfo, CommentModel commentModel);
CommentModel getCommentModel();
void getAppSign();
String downLoadClient();
void checkForUpdates();
/**
* 获取服务器配置
* @param commentModel
* @return
*/
DataBaseInfo getDataBaseInfo(CommentModel commentModel);
}

View File

@ -0,0 +1,88 @@
package com.small.client.service;
import cn.hutool.json.JSONObject;
import com.small.client.Utils.FileUtils;
import com.small.client.Utils.HttpUtils;
import com.small.client.dto.CommentModel;
import com.small.client.dto.UploadModel;
import lombok.extern.slf4j.Slf4j;
import netscape.javascript.JSObject;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.core.io.FileSystemResource;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpMethod;
import org.springframework.http.MediaType;
import org.springframework.stereotype.Component;
import org.springframework.stereotype.Service;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;
import org.springframework.web.client.RestTemplate;
@Service
@Slf4j
@Component
public class WebClientService {
@Value("${remoteIp}")
private String remoteIp;
private final RestTemplate restTemplate;
public WebClientService(RestTemplate restTemplate) {
this.restTemplate = restTemplate;
}
public String get(String url) {
return restTemplate.getForObject(url, String.class);
}
/**
* 文件上传
*/
public String uploudSxData(String filePath, CommentModel commentModel,String page,String syncType){
UploadModel uploadModel=new UploadModel();
uploadModel.setAppKey(commentModel.getAppKey());
uploadModel.setSign(commentModel.getSign());
uploadModel.setPage(page);
uploadModel.setSyncType(syncType);
//"C:\\Users\\Administrator\\uploaded\\2025\\3\\25\\goods_1.txt"
return this.uploadFile(filePath, remoteIp+HttpUtils.URL_UPLOUP,uploadModel);
}
public String uploadFile(String filePath, String url, UploadModel uploadModel) {
// 创建MultiValueMap来封装文件数据和请求参数如果有的话
MultiValueMap<String, Object> body = new LinkedMultiValueMap<>();
FileSystemResource file = new FileSystemResource(filePath); // 文件路径
body.add("file", file); // "file"是与服务器期望的表单字段名称相对应的键例如在Spring Controller中用@RequestParam("file") String file接收文件数据
body.add("appKey",uploadModel.getAppKey());
body.add("sign",uploadModel.getSign());
body.add("page",uploadModel.getPage());//页数
body.add("syncType",uploadModel.getSyncType());//商品类型
// 设置请求头指定为multipart/form-data类型并设置boundary可选
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.MULTIPART_FORM_DATA);
// 创建HttpEntity对象它将用于POST请求体中包含文件数据和请求头信息
HttpEntity<MultiValueMap<String, Object>> requestEntity = new HttpEntity<>(body, headers);
// 执行POST请求进行文件上传
JSONObject jsonObject= restTemplate.exchange(url, HttpMethod.POST, requestEntity, JSONObject.class).getBody();
log.info(jsonObject.toString());
log.info(jsonObject.getStr("error_msg"));
log.info(jsonObject.getStr("error_code"));
return jsonObject.getStr("error_code");
}
public static void main(String[] args) {
// String responseStr= new WebClientService(new RestTemplate()).get("http://localhost:8088/mobile/account/login/testcase");
// String responseStr= new WebClientService(new RestTemplate()).get("http://localhost:8088/mobile/account/login/testcase");
// System.out.printf(responseStr);
// new WebClientService(new RestTemplate()).uploudSxData();
log.info("测试");
}
}

View File

@ -0,0 +1,645 @@
package com.small.client.service.imp;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.date.DateUtil;
import cn.hutool.json.JSONArray;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.small.client.Cache.CommonCache;
import com.small.client.Utils.*;
import com.small.client.dao.SxDataDao;
import com.small.client.dto.*;
import com.small.client.enums.DicEnum;
import com.small.client.service.SxDataAbst.SxDataAbstService;
import com.small.client.service.SxDataService;
import com.small.client.service.WebClientService;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.core.io.Resource;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpMethod;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Service;
import org.springframework.util.StreamUtils;
import org.springframework.web.client.RestTemplate;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.util.*;
import java.util.stream.Collectors;
import static com.small.client.Utils.FileUtils.copyFile;
@Service
@Slf4j
public class SxDataServiceImp extends SxDataAbstService implements SxDataService {
@Autowired
private SxDataDao sxDataDao;
@Autowired
private RestTemplate restTemplate;
@Value("${remoteIp}")
private String remoteIp;
@Autowired
private CommonCache commonCache;
@Autowired
private WebClientService webClientService;
/**
* 同步商品分类数据
* @param dataBaseInfo
* @param commentModel
*/
@Override
public void SyncCategory(DataBaseInfo dataBaseInfo, CommentModel commentModel) {
dataBaseInfo= getDataBaseInfo(commentModel);
// 记录总数
Integer total = sxDataDao.getTBdItemClsTotal(dataBaseInfo);
if(total==0){
log.info("暂无商品分类同步");
return;
}
// 总页数
int pages = CommonUtil.getPagesCount(total, SxDataDao.PAGESIZE);
List<SxSyncCategory> allSxSyncCategories= sxDataDao.findTBdItemClsList(dataBaseInfo);
int syncCount =0;
for (int i = 1; i <=pages; i++) {
List<SxSyncCategory> sxSyncCategories= sxDataDao.findTBdItemClsListPage(dataBaseInfo,i,SxDataDao.PAGESIZE);
List<SxCategoryModel> sxCategoryModelList= ConVToSxCategoryModel(sxSyncCategories,allSxSyncCategories);
JSONArray jsonArray =null;
String jsonString="";
ObjectMapper objectMapper = new ObjectMapper();
try {
jsonString = objectMapper.writeValueAsString(sxCategoryModelList);
jsonArray = JSONUtil.parseArray(jsonString);
} catch (JsonProcessingException e) {
throw new RuntimeException(e);
}
String code= HttpUtils.postData(restTemplate,remoteIp+HttpUtils.URL_SYNC_CATEGORY
+"?appKey="+commentModel.getAppKey()
+"&sign="+commentModel.getSign(),jsonArray);//todo 后期改为文件传输
if (!HttpUtils.SUCCESSCODE.equals(code)) {
continue;
}
syncCount+=sxCategoryModelList.size();
}
log.info("商品分类总共有{}条数据,同步完成{}条",total,syncCount);
}
/**
* 同步商品数据
* @param dataBaseInfo
* @param commentModel
*/
@Override
public void SyncGoods(DataBaseInfo dataBaseInfo, CommentModel commentModel) {
//dataBaseInfo= getDataBaseInfo(commentModel);
String syncType ="01";
if(StringUtils.isNotEmpty(commentModel.getSyncTime())){//如果有同步时间则为增量
syncType="02";
dataBaseInfo.setSyncType("02");
}
if(StringUtils.isEmpty(syncType)){
syncType="01";
dataBaseInfo.setSyncType("01");
}
switch (syncType) {
case "01"://全量
syncAllGoods(dataBaseInfo, commentModel);
break;
case "02"://增量 todo test
syncIncrementAddGoods(dataBaseInfo, commentModel);
syncIncrementModifyGoods(dataBaseInfo, commentModel);
syncIncrementStock(dataBaseInfo, commentModel);
break;
}
}
/**
* 同步品牌数据
* @param dataBaseInfo
* @param commentModel
*/
@Override
public void SyncBranchList(DataBaseInfo dataBaseInfo, CommentModel commentModel) {
dataBaseInfo= getDataBaseInfo(commentModel);
List<BrandModel> brandModels= sxDataDao.getBdBrandList(dataBaseInfo);
if(brandModels!=null&&brandModels.size()>0){
String jsonString ="";
JSONArray jsonArray =new JSONArray();
ObjectMapper objectMapper = new ObjectMapper();
try {
jsonString = objectMapper.writeValueAsString(brandModels);
jsonArray = JSONUtil.parseArray(jsonString);
} catch (JsonProcessingException e) {
throw new RuntimeException(e);
}
String code= HttpUtils.postData(restTemplate,remoteIp+HttpUtils.URL_SYNC_BRAND
+"?appKey="+commentModel.getAppKey()
+"&sign="+commentModel.getSign(),jsonArray);//todo 后期改为文件传输
if(code!=null){
log.info("品牌总共有{}条数据,同步完成{}条",brandModels.size(),brandModels.size());
}
}else {
log.info("品牌数据为空");
}
}
/**
* 同步会员数据
* @param dataBaseInfo
* @param commentModel
*/
@Override
public void SyncVipList(DataBaseInfo dataBaseInfo, CommentModel commentModel) {
dataBaseInfo= getDataBaseInfo(commentModel);
String where="where 1=1 ";
if(StringUtils.isNotEmpty(commentModel.getSyncTime())){
where+="and oper_date > '"+commentModel.getSyncTime()+"'";
}
dataBaseInfo.setWhere(where);
// 记录总数
Integer total = sxDataDao.getTrmVipInfoTotal(dataBaseInfo);
if(total==0){
log.info("暂无会员数据同步");
return;
}
// 总页数
int pages = CommonUtil.getPagesCount(total, SxDataDao.PAGESIZE);
List<SyncThirdMemberReq> memberList=new ArrayList<>();
int syncCount =0;
for (int i = 1; i <=pages; i++) {
memberList.clear();
List<SxSyncVip> sxSyncVipList= sxDataDao.findRmVipInfoListPage(dataBaseInfo,i,SxDataDao.PAGESIZE);
//处理数据转换SxSyncVip>SyncThirdMemberReq
memberList=ConverList(sxSyncVipList);
String jsonString ="";
ObjectMapper objectMapper = new ObjectMapper();
try {
jsonString = objectMapper.writeValueAsString(memberList);
} catch (JsonProcessingException e) {
throw new RuntimeException(e);
}
String code= HttpUtils.postData(restTemplate,remoteIp+HttpUtils.URL_SYNC_MEMBER
+"?appKey="+commentModel.getAppKey()
+"&sign="+commentModel.getSign(),memberList);//todo 后期改为文件传输
if (!HttpUtils.SUCCESSCODE.equals(code)) {
continue;
}
syncCount+=memberList.size();
}
log.info("vip会员总共有{}条数据,同步完成{}条",total,syncCount);
}
/**
* 获取并缓存父节点的根节点用户查找数据
* @param dataBaseInfo
* @param parentName
*/
public String getAndCacheTree(DataBaseInfo dataBaseInfo,String parentName){
List<SxSyncCategory> sxSyncCategories=new SxDataDao().findTBdItemClsList(dataBaseInfo);
String parentId= sxSyncCategories.stream().filter(m->m.getItem_clsname().equals(parentName)).
map(SxSyncCategory::getItem_clsno).collect(Collectors.joining());
getBdBrandCacheList(dataBaseInfo);
String childrens=commonCache.get(CommonCache.CACHE_CATEGROY+parentId);
if(childrens==null){
log.info(JSONUtil.toJsonStr(buildTree(sxSyncCategories,parentId)));
}
return parentId;
}
/**
* 构建树节点
* @param sxSyncCategories
* @return
*/
public List<SxSyncCategory> buildTree(List<SxSyncCategory> sxSyncCategories,String parentId){
List<SxSyncCategory> treeNodes=new ArrayList<>();
List<SxSyncCategory> rootSxSyncCategory=getRootNode(sxSyncCategories);
for (SxSyncCategory node : rootSxSyncCategory) {
node=buildChildTree(node,sxSyncCategories,parentId);
treeNodes.add(node);
}
return treeNodes;
}
/**
* 获取所有的根节点
* @param sxSyncCategories
* @return
*/
public List<SxSyncCategory> getRootNode(List<SxSyncCategory> sxSyncCategories){
List<SxSyncCategory> rootNodeList=new ArrayList<>();
for (SxSyncCategory node : sxSyncCategories) {
if (null==node.getCls_parent()) {
rootNodeList.add(node);
}
}
return rootNodeList;
}
/**
* 构建子节点
* @param root
* @param sxSyncCategories
* @return
*/
public SxSyncCategory buildChildTree(SxSyncCategory root,List<SxSyncCategory> sxSyncCategories,String findByParentId) {
List<SxSyncCategory> children = new ArrayList<>();
for (SxSyncCategory node : sxSyncCategories) {
commonCache.put(node.getItem_clsno(),node.getItem_clsname());//把数据加入缓存
if (root.getItem_clsno().equals(node.getCls_parent())) {
children.add(buildChildTree(node,sxSyncCategories,findByParentId));
}
}
if(root.getItem_clsno().equals(findByParentId)){
commonCache.put(CommonCache.CACHE_CATEGROY+findByParentId,children.stream().map(SxSyncCategory::getItem_clsno).collect(Collectors.joining(",")));
}
root.setChildren(children);
return root;
}
/**
*同步所有商品
* @param dataBaseInfo
* @param commentModel
*/
private void syncAllGoods(DataBaseInfo dataBaseInfo, CommentModel commentModel){
String where="where 1=1";
Integer total =0;
if(DicEnum.SYNCTYPE_02.getCode().equals(dataBaseInfo.getSyncType())){
if (StringUtils.isNotEmpty(dataBaseInfo.getCategoryName())) {
String parentId=getAndCacheTree(dataBaseInfo,dataBaseInfo.getCategoryName());
String childrens= commonCache.get(CommonCache.CACHE_CATEGROY+parentId);
//syncGoodsSearchModel.setItemClsno(childrens);
where += " and b.item_clsno in ('" + childrens + "')";
}
if(StringUtils.isNotEmpty(commentModel.getSyncTime())){
where+=" and b.modify_date>'"+commentModel.getSyncTime()+"' ";
where+=" or b.build_date>'"+commentModel.getSyncTime()+"' ";
}
if(StringUtils.isNotEmpty(dataBaseInfo.getOperDate())){
where+=" and t.oper_date>'"+dataBaseInfo.getOperDate()+"' ";
}
dataBaseInfo.setWhere(where);
// 记录总数
total = sxDataDao.getTBditemInfoJoninTotal(dataBaseInfo);
}else {
dataBaseInfo.setWhere(where);
total = sxDataDao.getTBditemInfoTotal(dataBaseInfo);
}
if(total==0){
log.info("暂无商品同步");
return;
}
// 总页数
int pages = CommonUtil.getPagesCount(total, SxDataDao.PAGESIZE);
int syncCount =0;
List<SpecPriceDto> discountList= getDiscountFromCache(dataBaseInfo);
List<SpecPriceDto> specPriceDtoList= getSpecPriceFromCache(dataBaseInfo);
specPriceDtoList.addAll(discountList);
List<String> folders=new ArrayList<>();
for (int i = 1; i <=pages; i++) {
List<SxSyncGoods> sxSyncGoods= sxDataDao.findBditemInfoListPage(dataBaseInfo,i,SxDataDao.PAGESIZE);
List<SxGoosModel> sxGoosModelList= CvtToGoosModel(sxSyncGoods,specPriceDtoList);
String jsonString="";
ObjectMapper objectMapper = new ObjectMapper();
try {
jsonString = objectMapper.writeValueAsString(sxGoosModelList);
} catch (JsonProcessingException e) {
throw new RuntimeException(e);
}
String code= writeToFileAndUploud(i,jsonString,commentModel,DicEnum.MUAL_1.getCode());
if (!HttpUtils.SUCCESSCODE.equals(code)) {
continue;
}
folders.add(String.valueOf(i));
syncCount+=sxSyncGoods.size();
}
// folders.add(String.valueOf(2));
//folders.add(String.valueOf(4));
//folders.add(String.valueOf(5));
log.info("商品分类总共有{}条数据,同步完成{}条",total,syncCount);
String code= HttpUtils.postData(restTemplate,remoteIp+HttpUtils.URL_SYNC_GOODS_READ
+"?appKey="+commentModel.getAppKey()
+"&sign="+commentModel.getSign()
+"&syncType="+DicEnum.MUAL_1.getCode(),
JSONUtil.parseArray(folders));
if (HttpUtils.SUCCESSCODE.equals(code)) {
log.info("思迅商品同步完成,通知服务器处理数据相应成功");
//记录同步时间
createDateFile();
}
}
/**
* 文件上传到服务器
* @param page
* @param content
* @param commentModel
* @return
*/
private String writeToFileAndUploud(Integer page,String content,CommentModel commentModel,String syncType){
FileUtils fileUtils= new FileUtils();
File file=fileUtils.createFile(syncType,page);
String fileName=fileUtils.getFileName(syncType,page,FileUtils.txtEnd);
String filePath=file.getAbsolutePath();
fileUtils.writeFile(filePath,fileName,content);
return webClientService.uploudSxData(filePath+FileUtils.pathSeparator+fileName,commentModel,page.toString(),syncType);
}
/**
* 记录同步时间
*/
private void createDateFile(){
String path=JarPathUtil.getRuntimePath();
FileUtils fileUtils= new FileUtils();
File file=fileUtils.createFile(path);
String filePath=file.getAbsolutePath();
String date= DateUtil.format(new Date(),"yyyy-MM-dd");
fileUtils.writeFile(filePath,FileUtils.REFLESHDATE,date);
}
/**
* 增量新增数据新增商品数据
* @param dataBaseInfo
* @param commentModel
*/
private void syncIncrementAddGoods(DataBaseInfo dataBaseInfo, CommentModel commentModel){
syncAllGoods(dataBaseInfo,commentModel);
}
/**
* 增量同步 商品内容变化
* @param dataBaseInfo
* @param commentModel
*/
private void syncIncrementModifyGoods(DataBaseInfo dataBaseInfo, CommentModel commentModel){
syncAllGoods(dataBaseInfo,commentModel);
}
/**
* 增量同步 库存变化
*/
private void syncIncrementStock(DataBaseInfo dataBaseInfo, CommentModel commentModel){
dataBaseInfo.setOperDate(commentModel.getSyncTime());
commentModel.setSyncTime("");
syncAllGoods(dataBaseInfo,commentModel);
}
/**
*获取特价商品
* @param dataBaseInfo
* @return
*/
public List<SpecPriceDto> getDiscountFromCache(DataBaseInfo dataBaseInfo){
List<SpecPriceDto> specPriceDtos= commonCache.getSpecPrice("specDiscountCache");
if (null!=specPriceDtos){
return specPriceDtos;
}else {
specPriceDtos= sxDataDao.getSpecPriceList(dataBaseInfo);
commonCache.putSpecPrice("specDiscountCache",specPriceDtos);
}
return specPriceDtos;
}
/**
*获取促销产品数据
* @param dataBaseInfo
* @return
*/
public List<SpecPriceDto> getSpecPriceFromCache(DataBaseInfo dataBaseInfo){
List<SpecPriceDto> specPriceDtos= commonCache.getSpecPrice("specPriceCache");
if(null!=specPriceDtos){
return specPriceDtos;
}else {
specPriceDtos= sxDataDao.getDiscountPriceList(dataBaseInfo);
commonCache.putSpecPrice("specDiscountCache",specPriceDtos);
}
return specPriceDtos;
}
/**
* 获取品牌数据并加入到缓存
* @param dataBaseInfo
* @return
*/
public void getBdBrandCacheList(DataBaseInfo dataBaseInfo){
List<BrandModel> specPriceDtos= commonCache.getBrandCahce("brandCache");
if(null==specPriceDtos){
specPriceDtos= sxDataDao.getBdBrandList(dataBaseInfo);
if(CollectionUtil.isNotEmpty(specPriceDtos)){
for (BrandModel brandModel : specPriceDtos) {
commonCache.put(brandModel.getCodeId(),brandModel.getBrand_name());
}
commonCache.setBrandCahce("brandCache",specPriceDtos);
}
}
}
@Override
public CommentModel getCommentModel() {
String path=JarPathUtil.getRuntimePath();
log.info(JarPathUtil.getRuntimePath());
File folder = new File(path);
//读取文件
try {
String encryptedData = getPrimaryKey();
Map<String, String> result= CryptoUtils.decryptAndUnpack(encryptedData);
CommentModel commentModel=new CommentModel();
commentModel.setSign(result.get("sign"));
commentModel.setAppKey(result.get("appKey"));
commentModel.setStoreId(result.get("storeId"));
//获取上次同步的最大时间
File[] lastDateJsonFile = folder.listFiles((dir, name) -> name.endsWith(FileUtils.REFLESHDATE));
if(lastDateJsonFile!=null&&lastDateJsonFile.length>0){
String lastDate = new String(Files.readAllBytes(lastDateJsonFile[0].toPath()), StandardCharsets.UTF_8).trim();
commentModel.setSyncTime(lastDate);
}
return commentModel;
} catch (RuntimeException | IOException e) {
throw new RuntimeException("密钥获取失败");
} catch (Exception e) {
throw new RuntimeException(e);
}
}
@Override
public void getAppSign() {
String encryptedData= getPrimaryKey();
JSONObject jsonObject=new JSONObject();
jsonObject.putOnce("primaryKey",encryptedData);
String primaryKey= HttpUtils.postData(restTemplate,remoteIp+HttpUtils.URL_SYNC_GET_APPSIGN
+"?primaryKey="+encryptedData, jsonObject,"primaryKey");
if(null!=primaryKey){
String path=JarPathUtil.getRuntimePath();
FileUtils fileUtils= new FileUtils();
File file=fileUtils.createFile(path);
String filePath=file.getAbsolutePath();
fileUtils.writeFile(filePath,FileUtils.PRIMARYKEY,primaryKey);
}else {
log.info("获取服务器密钥失败");
}
}
/**
* 获取文本密钥
* @return
*/
private String getPrimaryKey(){
String path=JarPathUtil.getRuntimePath();
log.info("RuntimePath:{}",JarPathUtil.getRuntimePath());
File folder = new File(path);
File[] jsonFiles = folder.listFiles((dir, name) -> name.endsWith(FileUtils.PRIMARYKEY));
if(null!=jsonFiles&&jsonFiles.length>0){
try {
return new String(Files.readAllBytes(jsonFiles[0].toPath()), StandardCharsets.UTF_8);
}catch (RuntimeException | IOException e){
throw new RuntimeException("读取[fileName]文件错误");
}
}
return null;
}
@Override
public String downLoadClient() {
String downloadDirectory=FileUtils.CLIENTSTALLPATH;
String originalFileName = "";
try {
File file= new File(downloadDirectory);
if(!file.exists()){
file.mkdirs(); // 确保目录存在
}
log.info("文件下载目录: {}", downloadDirectory);
HttpHeaders headers = new HttpHeaders();
HttpEntity<String> requestEntity = new HttpEntity<>(headers);
String encryptedData = getPrimaryKey();
ResponseEntity<Resource> response = restTemplate.exchange(
remoteIp+HttpUtils.URL_SYNC_GET_DOWNCLIENTJAR+"?primaryKey="+encryptedData,
HttpMethod.GET,
requestEntity,
Resource.class);
if(response.getStatusCode().is2xxSuccessful() && null!= response.getHeaders().getFirst("error")){
String error=response.getHeaders().getFirst("error");
switch (Objects.requireNonNull(error)){
case "noVersion":
log.info("没有版本更新");
break;
case "noFile":
log.info("系统错误:文件不存在");
break;
case "500":;
log.info("系统错误:系统内部错误");
break;
case "noValid":
log.info("密钥校验失败:密钥过期");
break;
}
return null;
}
if (response.getStatusCode().is2xxSuccessful() && response.getBody() != null) {
// 从Content-Disposition头获取文件名
String contentDisposition = response.getHeaders().getFirst(HttpHeaders.CONTENT_DISPOSITION);
if (contentDisposition != null && contentDisposition.contains("filename=")) {
originalFileName = contentDisposition
.split("filename=")[1]
.replace("\"", ""); // 去除引号
}
// 如果无法从header获取使用默认名
if (originalFileName == null || originalFileName.isEmpty()) {
originalFileName = "new_client" + System.currentTimeMillis()+".jar";
}
File outputFile = new File(downloadDirectory + originalFileName);
try (FileOutputStream outputStream = new FileOutputStream(outputFile)) {
StreamUtils.copy(response.getBody().getInputStream(), outputStream);
log.info("文件下载成功: {}" , outputFile.getAbsolutePath());
}catch (Exception e){
log.error("下载失败,下载流异常:{}",e.getMessage());
return null;
}
} else {
log.error("文件下载失败: {}", response.getStatusCode());
return null;
}
}catch (Exception e){
log.error("文件下载失败:{}",e.getMessage());
return null;
}
return downloadDirectory+originalFileName;
}
@Override
public void checkForUpdates() {
log.info("curentPath:{}",JarPathUtil.getRuntimePath());
File classDirFile = new File(JarPathUtil.getRuntimePath());
File parentDir = classDirFile.getParentFile();
String filePath= this.downLoadClient();
if (filePath != null) {
copyFile(filePath,parentDir.getAbsolutePath()+"/lib");
applyUpdate();
}
}
private void applyUpdate() {
try {
File classDirFile = new File(JarPathUtil.getRuntimePath());
File parentDir = classDirFile.getParentFile();
// 执行脚本并退出当前应用
log.info(parentDir.getAbsolutePath()+"/bin/run.bat");
Runtime.getRuntime().exec(parentDir.getAbsolutePath()+"/bin/run.bat");
log.info(parentDir.getAbsolutePath()+"/bin/run.bat");
System.exit(0);
} catch (IOException e) {
log.error("异常{}", e.getMessage());
}
}
@Override
public DataBaseInfo getDataBaseInfo(CommentModel commentModel) {
JSONObject jsonObject=new JSONObject();
jsonObject.putOnce("appKey",commentModel.getAppKey());
jsonObject.putOnce("sign",commentModel.getSign());
StoreDbConfig storeDbConfig= HttpUtils.postDataGetConfig(restTemplate,remoteIp+HttpUtils.URL_SYNC_GET_STOREdBCONFIG
+"?appKey="+commentModel.getAppKey()
+"&sign="+commentModel.getSign(), jsonObject);
DataBaseInfo dataBaseInfo=new DataBaseInfo();
if(null!=storeDbConfig){
dataBaseInfo.setIp(storeDbConfig.getDbIp());
dataBaseInfo.setPassword(storeDbConfig.getDbPassword());
dataBaseInfo.setDataBaseName(storeDbConfig.getDbName());
dataBaseInfo.setDbPort(storeDbConfig.getDbPort());
dataBaseInfo.setSyncMode(storeDbConfig.getSyncMode());
dataBaseInfo.setCronExpression(storeDbConfig.getCronExpression());
dataBaseInfo.setCategoryName(storeDbConfig.getCategoryName());
return dataBaseInfo;
}
return new DataBaseInfo();
}
}

View File

@ -0,0 +1,15 @@
server:
port: 9099
servlet:
encoding:
charset: UTF-8
enabled: true
force: true
#配置远程模板信息
#服务器地址
logging:
charset:
console: UTF-8
remoteIp: https://mall.gpxscs.cn

View File

@ -0,0 +1,19 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE configuration>
<configuration>
<!--引用默认日志配置-->
<include resource="org/springframework/boot/logging/logback/defaults.xml"/>
<!--使用默认的控制台日志输出实现-->
<include resource="org/springframework/boot/logging/logback/console-appender.xml"/>
<!--接口访问记录日志输出到LogStash-->
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
<encoder>
<charset>UTF-8</charset>
<pattern>%d{yyyy-MM-dd HH:mm:ss} - %msg%n</pattern>
</encoder>
</appender>
<root level="info">
<appender-ref ref="STDOUT" />
</root>
</configuration>

View File

@ -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;
}
}

View File

@ -91,7 +91,7 @@ public class SxSyncGoods implements Serializable {
private BigDecimal item_brand_name;
@ApiModelProperty(value = "商品助记号")
private Integer item_rem;
private String item_rem;
@ApiModelProperty(value = "生产日期")
private String build_date;
@ -113,5 +113,6 @@ public class SxSyncGoods implements Serializable {
@ApiModelProperty(value = "更新时间")
private Date updated_at;
}

View File

@ -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;
}

View File

@ -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;
}

View File

@ -8,6 +8,7 @@ import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import javax.annotation.PostConstruct;
import java.util.Objects;
@Component
@Slf4j
@ -39,8 +40,12 @@ public class ContextUtil {
public static UserDto getCurrentUser() {
try {
UserDto loginUser = staticUserInfoService.getUser();
// log.info("##### 当前登录用户:{}###", JsonUtil.object2json(loginUser));
return loginUser;
log.info("##### 当前登录用户:{}###", JsonUtil.object2json(loginUser));
return loginUser;//todo 测试去除
// UserDto user= new UserDto();
// user.setStore_id("1");
// user.setRole_id(9);
// return user;
} catch (Exception e) {
System.out.println(e.getMessage());
}
@ -73,6 +78,21 @@ public class ContextUtil {
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
public void init() {
ContextUtil.staticUserInfoService = userInfoService;

View File

@ -205,7 +205,9 @@ public class MallsuiteImSocketHandler implements WebSocketHandler {
if (!mine.getId().equals(to.getId())) {
sendVO.setMine(false);
if ("voice".equals(receiveDTO.getMine().getType()) || "video".equals(receiveDTO.getMine().getType())) {
sendVO.setMessage_length(receiveDTO.getMine().getContent());
}
//保存聊天记录
if ("friend".equals(type) || "user".equals(type)) {
//如果是私聊

View File

@ -76,6 +76,9 @@ public class SendVO implements Serializable {
@ApiModelProperty(value = "和状态一致")
private Map msg;
@ApiModelProperty(value = "消息长度")
private String message_length;
@Override
public String toString() {

View File

@ -294,6 +294,12 @@
<version>2.8.0</version>
<scope>compile</scope>
</dependency>
<!--jdbc数据库-->
<dependency>
<groupId>com.microsoft.sqlserver</groupId>
<artifactId>mssql-jdbc</artifactId>
<version>9.2.1.jre8</version>
</dependency>
</dependencies>

View File

@ -143,4 +143,10 @@ public interface ShopBaseProductCategoryService extends IBaseService<ShopBasePro
Boolean syncSxCategoryToShopBaseProductCategory(String storeId, Integer pageNum, Integer pageSize);
/**
* 查询并缓存到热点数据中提高查询效率
* @param storeId
*/
Map getCategoryListByStoreId(String storeId);
}

View File

@ -326,6 +326,7 @@ public class AccountBaseConfigServiceImpl extends BaseServiceImpl<AccountBaseCon
configList = Convert.toList(AccountBaseConfig.class, listByIds(configKeys));
Map<String, AccountBaseConfig> configMap = configList.stream()
.collect(Collectors.toMap(AccountBaseConfig::getConfig_key, config -> config));
redisService.hSetAll(RedisConstant.Config_Cache_Key, configMap);
redisService.incr(RedisConstant.Config_Cache_Version, 1);
}

View File

@ -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.sixun.SxSyncCategory;
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.pojo.dto.ProductSearchDTO;
import com.suisung.mall.common.utils.CheckUtil;
@ -1235,4 +1236,26 @@ public class ShopBaseProductCategoryServiceImpl extends BaseServiceImpl<ShopBase
public boolean saveOrUpdate(ShopBaseProductCategory 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;
}
}

View File

@ -86,6 +86,7 @@ public class ShopBaseProductTypeServiceImpl extends BaseServiceImpl<ShopBaseProd
data.put("brands", brandService.getBrandsByIds(shopBaseProductType.getType_brand_ids()));
Integer store_id = Convert.toInt(userInfoService.getUser().getStore_id());
//Integer store_id =1;
data.put("specs", specService.getSpecsByIds(shopBaseProductType.getType_spec_ids(), store_id));

View File

@ -43,7 +43,6 @@ public class ShopChainUserRightsBaseServiceImpl extends BaseServiceImpl<ShopChai
tree.add(chainUserRightBase);
}
}
return tree;
}
}

View File

@ -1,6 +1,7 @@
package com.suisung.mall.shop.config;
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.WebMvcConfigurer;

View File

@ -4,6 +4,8 @@ import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.suisung.mall.common.modules.number.ShopNumberSeq;
import org.springframework.stereotype.Repository;
import java.util.List;
/**
* <p>
* Id管理表 Mapper 接口
@ -16,4 +18,7 @@ import org.springframework.stereotype.Repository;
@Repository
public interface ShopNumberSeqMapper extends BaseMapper<ShopNumberSeq> {
List<ShopNumberSeq> findNumberFromShopBaseAndItem(ShopNumberSeq shopNumberSeq);
List<ShopNumberSeq> findProductAndImtemId(ShopNumberSeq shopNumberSeq);
void myUpdateSeq(ShopNumberSeq shopNumberSeq);
}

View File

@ -3,6 +3,8 @@ package com.suisung.mall.shop.number.service;
import com.suisung.mall.common.modules.number.ShopNumberSeq;
import com.suisung.mall.core.web.service.IBaseService;
import java.util.List;
/**
* <p>
* Id管理表 服务类
@ -17,4 +19,9 @@ public interface ShopNumberSeqService extends IBaseService<ShopNumberSeq> {
Long createNextNo(String prefix);
List<Long> batchCreateNextNo(String seqName, int batchSize);
void clearRelateGoodsId();
void clearKey();
}

View File

@ -1,15 +1,25 @@
package com.suisung.mall.shop.number.service.impl;
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.core.web.service.RedisService;
import com.suisung.mall.core.web.service.impl.BaseServiceImpl;
import com.suisung.mall.shop.number.mapper.ShopNumberSeqMapper;
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.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
import java.util.Collections;
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
*/
@Service
@lombok.extern.slf4j.Slf4j
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
* 方法走到这里会产生串行化集群部署这里不能使用单机锁
@ -65,6 +82,10 @@ public class ShopNumberSeqServiceImpl extends BaseServiceImpl<ShopNumberSeqMappe
*/
@Override
public Long createNextNo(String prefix) {
//相当于加锁等待同步数据执行完成
// if(prefix.equals("product_id")||prefix.equals("item_id")){
// checkPrimaryKey();
// }
String id = prefix;
ShopNumberSeq shopNumberSeq = getById(id);
if (shopNumberSeq == null) {
@ -79,6 +100,7 @@ public class ShopNumberSeqServiceImpl extends BaseServiceImpl<ShopNumberSeqMappe
}
Long number = shopNumberSeq.getNumber();
shopNumberSeq.setPrefix(id);
//不走缓存
@ -90,4 +112,112 @@ public class ShopNumberSeqServiceImpl extends BaseServiceImpl<ShopNumberSeqMappe
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);
}
}

View File

@ -1,12 +1,14 @@
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.OssPolicyResultDTO;
import javax.servlet.http.HttpServletRequest;
import java.io.File;
import java.io.InputStream;
import java.util.List;
/**
* oss上传管理Service
@ -42,4 +44,26 @@ public interface OssService {
*/
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);
}

View File

@ -14,9 +14,7 @@ import com.qcloud.cos.COSClient;
import com.qcloud.cos.ClientConfig;
import com.qcloud.cos.auth.BasicCOSCredentials;
import com.qcloud.cos.auth.COSCredentials;
import com.qcloud.cos.model.CannedAccessControlList;
import com.qcloud.cos.model.PutObjectRequest;
import com.qcloud.cos.model.PutObjectResult;
import com.qcloud.cos.model.*;
import com.qcloud.cos.region.Region;
import com.suisung.mall.common.api.CommonResult;
import com.suisung.mall.common.constant.ConfigConstant;
@ -49,7 +47,9 @@ import java.nio.charset.StandardCharsets;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
/**
* oss上传管理Service实现类
@ -569,4 +569,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;
}
}

View File

@ -3,6 +3,8 @@ package com.suisung.mall.shop.product.service;
import com.suisung.mall.common.modules.product.ShopProductAssistIndex;
import com.suisung.mall.core.web.service.IBaseService;
import java.util.List;
/**
* <p>
* 商品与属性对应表 服务类
@ -12,5 +14,7 @@ import com.suisung.mall.core.web.service.IBaseService;
* @since 2021-05-19
*/
public interface ShopProductAssistIndexService extends IBaseService<ShopProductAssistIndex> {
List<ShopProductAssistIndex> getShopProductAssistIndexStoreId(Integer storeId);
void clearCacheShopProductAssistIndexByStoreId(Integer storeId);
}

View File

@ -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> 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);
}

View File

@ -3,6 +3,8 @@ package com.suisung.mall.shop.product.service;
import com.suisung.mall.common.modules.product.ShopProductImage;
import com.suisung.mall.core.web.service.IBaseService;
import java.util.List;
/**
* <p>
* 产品图片表按照颜色规格 服务类
@ -13,4 +15,7 @@ import com.suisung.mall.core.web.service.IBaseService;
*/
public interface ShopProductImageService extends IBaseService<ShopProductImage> {
List<ShopProductImage> getShopProductImageByStoreId(Integer storeId);
void clearCacheShopProductImageByStoreId(Integer storeId);
}

View File

@ -1,11 +1,17 @@
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.core.web.service.RedisService;
import com.suisung.mall.core.web.service.impl.BaseServiceImpl;
import com.suisung.mall.shop.product.mapper.ShopProductAssistIndexMapper;
import com.suisung.mall.shop.product.service.ShopProductAssistIndexService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.Collections;
import java.util.List;
/**
* <p>
@ -17,4 +23,24 @@ import org.springframework.stereotype.Service;
*/
@Service
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);
}
}

View File

@ -6,6 +6,7 @@ import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.convert.Convert;
import cn.hutool.core.date.DateTime;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.date.StopWatch;
import cn.hutool.core.util.NumberUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
@ -15,6 +16,8 @@ import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
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.extension.plugins.pagination.Page;
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.sixun.service.SxSyncGoodsService;
import com.suisung.mall.shop.store.service.*;
import com.suisung.mall.shop.sync.Utils.BatchInsertUtils;
import com.suisung.mall.shop.user.service.*;
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.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.util.Pair;
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.support.TransactionTemplate;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
@ -81,7 +92,9 @@ import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.*;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.function.Function;
import java.util.stream.Collectors;
import static com.suisung.mall.common.utils.ContextUtil.getCurrentUser;
@ -195,6 +208,11 @@ public class ShopProductBaseServiceImpl extends BaseServiceImpl<ShopProductBaseM
@Autowired
private SxSyncGoodsService sxSyncGoodsService;
@Autowired
private PlatformTransactionManager transactionManager;
@Autowired
private SqlSessionFactory sqlSessionFactory;
@Override
public boolean trySaveProduct(String productObj, String productItems) {
@ -681,7 +699,7 @@ public class ShopProductBaseServiceImpl extends BaseServiceImpl<ShopProductBaseM
* @return
*/
@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();
if (store_id == null) {
return Pair.of(false, I18nUtil._("缺少店铺ID!"));
@ -718,7 +736,7 @@ public class ShopProductBaseServiceImpl extends BaseServiceImpl<ShopProductBaseM
// 生成商品ID:product_id
productId = shopNumberSeqService.createNextNo("product_id");
if (null == productId) {
return Pair.of(false, I18nUtil._("生成商品编号异常!"));
return Pair.of(false, I18nUtil._("生成商品编号异常!"));
} else {
shopProductBase.setProduct_id(productId);
}
@ -2713,7 +2731,7 @@ public class ShopProductBaseServiceImpl extends BaseServiceImpl<ShopProductBaseM
public Map getList(QueryWrapper<ShopProductBase> wrapper, Integer pageNum, Integer pageSize) {
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);
if (CheckUtil.isNotEmpty(nodeid)) {
@ -5243,4 +5261,835 @@ public class ShopProductBaseServiceImpl extends BaseServiceImpl<ShopProductBaseM
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();
// }
}

View File

@ -1,11 +1,18 @@
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.core.web.service.RedisService;
import com.suisung.mall.core.web.service.impl.BaseServiceImpl;
import com.suisung.mall.shop.product.mapper.ShopProductImageMapper;
import com.suisung.mall.shop.product.service.ShopProductImageService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.Collections;
import java.util.List;
import java.util.Map;
/**
* <p>
@ -17,4 +24,26 @@ import org.springframework.stereotype.Service;
*/
@Service
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);
}
}

View File

@ -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;
}
}

View File

@ -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);
}
}

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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;
}

View File

@ -11,6 +11,8 @@ package com.suisung.mall.shop.sixun.service;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.suisung.mall.common.api.CommonResult;
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;
@ -82,4 +84,22 @@ public interface SxSyncCategoryService {
* @return
*/
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);
}

View File

@ -11,6 +11,7 @@ package com.suisung.mall.shop.sixun.service;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.suisung.mall.common.api.CommonResult;
import com.suisung.mall.common.modules.sixun.SxSyncGoods;
import com.suisung.mall.shop.sixun.dto.DataBaseInfo;
import java.util.List;
@ -75,4 +76,20 @@ public interface SxSyncGoodsService {
* @return
*/
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);
}

View File

@ -10,6 +10,7 @@ package com.suisung.mall.shop.sixun.service;
import com.suisung.mall.common.api.CommonResult;
import com.suisung.mall.common.modules.sixun.SxSyncVip;
import com.suisung.mall.shop.sixun.dto.DataBaseInfo;
import java.util.List;
@ -57,4 +58,18 @@ public interface SxSyncVipService {
* @return
*/
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);
}

View File

@ -9,7 +9,9 @@
package com.suisung.mall.shop.sixun.service.impl;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.convert.Convert;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
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.modules.sixun.SxSyncCategory;
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.service.SxSyncCategoryService;
import com.suisung.mall.shop.sixun.utils.CommonUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.Date;
import java.util.List;
import java.util.Objects;
import javax.annotation.Resource;
import java.util.*;
import java.util.stream.Collectors;
@Service
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系统获取数据区域 结束
// ########### 从思迅数据库获取数据区域 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
}

View File

@ -20,18 +20,22 @@ import com.suisung.mall.common.api.CommonResult;
import com.suisung.mall.common.constant.CommonConstant;
import com.suisung.mall.common.modules.sixun.SxSyncGoods;
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.service.SxSyncGoodsService;
import com.suisung.mall.shop.sixun.utils.CommonUtil;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
import java.util.Date;
import java.util.List;
import java.util.Objects;
@Service
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);
}
// ########### 从思迅商锐9.7系统获取数据区域 开始
public List<SxSyncGoods> pageGoodsListFromSiXun(Integer pageNo, Integer pageSize) {
@ -223,5 +226,12 @@ public class SxSyncGoodsServiceImpl extends BaseServiceImpl<SxSyncGoodsMapper, S
}
// ########### 从思迅商锐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);
}
}

View File

@ -18,18 +18,22 @@ import com.suisung.mall.common.api.CommonResult;
import com.suisung.mall.common.constant.CommonConstant;
import com.suisung.mall.common.modules.sixun.SxSyncVip;
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.service.SxSyncVipService;
import com.suisung.mall.shop.sixun.utils.CommonUtil;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
import java.util.Date;
import java.util.List;
import java.util.Objects;
@Service
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系统获取数据区域 结束
@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);
}
}

View File

@ -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;
}
}

View File

@ -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;
}
}
}

View File

@ -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);
}
}

View File

@ -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;
}
}

View File

@ -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);
}
}

View File

@ -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);
}
}

View File

@ -10,22 +10,30 @@ package com.suisung.mall.shop.sync.controller;
import cn.hutool.json.JSONArray;
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.res.ThirdApiRes;
import com.suisung.mall.shop.sync.service.SyncAppService;
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.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.util.List;
import java.util.Map;
@Api(tags = "第三方数据同步")
@RestController
@RequestMapping("/shop/sync/third")
public class SyncThirdDataController {
@Resource
private SyncAppService syncAppService;
@Resource
private SyncThirdDataService syncThirdDataService;
@ -82,4 +90,59 @@ public class SyncThirdDataController {
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);
}
}

View File

@ -0,0 +1,6 @@
package com.suisung.mall.shop.sync.keymanage;
public class RedisKey {
public static final String SXCLIENTKEYVERSION="sxclientKey:version";
}

View File

@ -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> {
}

View File

@ -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> {
}

View File

@ -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);
}
}

View File

@ -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);
}

View File

@ -12,6 +12,8 @@ import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.service.IService;
import com.suisung.mall.common.modules.sync.SyncApp;
import java.util.Map;
public interface SyncAppService extends IService<SyncApp> {
/**
@ -83,4 +85,13 @@ public interface SyncAppService extends IService<SyncApp> {
* @return
*/
SyncApp checkAppSign(String appKey, String sign, String postData);
/**
* 获取加密的appKeysignstreId
* @param primaryKey
* @return
*/
Map<String,Object> getAppSign(String primaryKey);
boolean checkPrimaryKey(String primaryKey);
}

View File

@ -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> {
}

View File

@ -10,9 +10,14 @@ package com.suisung.mall.shop.sync.service;
import cn.hutool.json.JSONArray;
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.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;
public interface SyncThirdDataService {
@ -54,4 +59,28 @@ public interface SyncThirdDataService {
* @return
*/
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);
}

View File

@ -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("仅为平台操作");
}
}
}

View File

@ -8,6 +8,7 @@
package com.suisung.mall.shop.sync.service.impl;
import cn.hutool.core.convert.Convert;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
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.StringUtils;
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.service.SyncAppService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.stereotype.Service;
import java.util.HashMap;
import java.util.Map;
import java.util.function.Consumer;
@Service
@lombok.extern.slf4j.Slf4j
public class SyncAppServiceImpl extends BaseServiceImpl<SyncAppMapper, SyncApp> implements SyncAppService {
@Autowired
private SyncAppMapper syncAppMapper;
/**
* 根据 appKey 获取一条记录
*
@ -181,4 +188,50 @@ public class SyncAppServiceImpl extends BaseServiceImpl<SyncAppMapper, SyncApp>
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;
}
}

View File

@ -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();
}
}

View File

@ -8,4 +8,6 @@ import org.springframework.stereotype.Service;
@Service
public class SyncConfigServiceImpl extends ServiceImpl<SyncConfigServiceMapper, SyncConfig> implements SyncConfigService {
}

View File

@ -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 {
}

Some files were not shown because too many files have changed in this diff Show More