@ -9,27 +9,22 @@
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.CharsetUtil ;
import cn.hutool.core.util.ObjectUtil ;
import cn.hutool.core.util.StrUtil ;
import cn.hutool.core.util.ZipUtil ;
import cn.hutool.json.JSONArray ;
import cn.hutool.json.JSONUtil ;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper ;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper ;
import com.qcloud.cos.model.COSObjectSummary ;
import com.suisung.mall.common.api.CommonResult ;
import com.suisung.mall.common.enums.DicEnum ;
import com.suisung.mall.common.modules.base.ShopBaseProductBrand ;
import com.suisung.mall.common.modules.base.ShopBaseProductCategory ;
import com.suisung.mall.common.modules.sixun.SxSyncGoods ;
import com.suisung.mall.common.modules.sixun.SxSyncVip ;
import com.suisung.mall.common.modules.sync.StoreDbConfig ;
@ -38,9 +33,7 @@ import com.suisung.mall.common.modules.sync.SyncConfig;
import com.suisung.mall.common.modules.sync.SyncFileLog ;
import com.suisung.mall.common.pojo.req.SyncThirdMemberReq ;
import com.suisung.mall.common.pojo.res.ThirdApiRes ;
import com.suisung.mall.common.utils.I18nUtil ;
import com.suisung.mall.common.utils.StringUtils ;
import com.suisung.mall.core.web.service.RedisService ;
import com.suisung.mall.shop.base.service.ShopBaseProductCategoryService ;
@ -60,15 +53,15 @@ import com.suisung.mall.shop.sixun.utils.FileUtils;
import com.suisung.mall.shop.sync.Utils.ThreadFileUtils ;
import com.suisung.mall.shop.sync.keymanage.RedisKey ;
import com.suisung.mall.shop.sync.service.* ;
import org.slf4j.Logger ;
import org.slf4j.LoggerFactory ;
import org.springframework.beans.factory.annotation.Autowired ;
import org.springframework.beans.factory.annotation.Value ;
import org.springframework.context.annotation.Lazy ;
import org.springframework.core.io.ByteArrayResource ;
import org.springframework.core.io.FileSystemResource ;
import org.springframework.core.io.Resource ;
import org.springframework.data.redis.core.RedisTemplate ;
import org.springframework.http.HttpHeaders ;
import org.springframework.http.HttpStatus ;
import org.springframework.http.MediaType ;
@ -76,6 +69,7 @@ import org.springframework.http.ResponseEntity;
import org.springframework.scheduling.annotation.Async ;
import org.springframework.stereotype.Service ;
import org.springframework.web.multipart.MultipartFile ;
import java.io.File ;
import java.io.IOException ;
import java.nio.charset.StandardCharsets ;
@ -85,17 +79,19 @@ import java.nio.file.Paths;
import java.time.Duration ;
import java.time.Instant ;
import java.util.* ;
import java.util.concurrent.* ;
import java.util.concurrent.ExecutorService ;
import java.util.concurrent.Executors ;
import java.util.concurrent.Future ;
import java.util.concurrent.atomic.AtomicInteger ;
import java.util.concurrent.atomic.AtomicLong ;
import java.util.stream.Collectors ;
@Service
public class SyncThirdDataServiceImpl extends SyncBaseThirdSxAbstract implements SyncThirdDataService {
private static Logger logger = LoggerFactory . getLogger ( SyncThirdDataServiceImpl . class ) ;
public class SyncThirdDataServiceImpl extends SyncBaseThirdSxAbstract implements SyncThirdDataService {
private static final Logger logger = LoggerFactory . getLogger ( SyncThirdDataServiceImpl . class ) ;
private final int limitCnt = 300 ;
private final AtomicLong threadNum = new AtomicLong ( 0 ) ;
@Value ( " ${client.path} " )
public String clientPath ;
@Autowired
@ -104,15 +100,12 @@ public class SyncThirdDataServiceImpl extends SyncBaseThirdSxAbstract implements
private SyncConfigService syncConfigService ;
@Autowired
private SxSyncCategoryService sxSyncCategoryService ;
@Autowired
private SxSyncGoodsService sxSyncGoodsService ;
@Autowired
private SxSyncVipService sxSyncVipService ;
@Autowired
private ShopNumberSeqService shopNumberSeqService ;
private final AtomicLong threadNum = new AtomicLong ( 0 ) ;
@Autowired
private SyncFileLogService syncFileLogService ;
@Autowired
@ -121,6 +114,11 @@ public class SyncThirdDataServiceImpl extends SyncBaseThirdSxAbstract implements
@Autowired
private RedisService redisService ;
@Lazy
@Autowired
private RedisTemplate redisTemplate ;
@Autowired
private StoreDbConfigService storeDbConfigService ;
@ -135,6 +133,7 @@ public class SyncThirdDataServiceImpl extends SyncBaseThirdSxAbstract implements
@Value ( " #{accountBaseConfigService.getConfig('tengxun_default_dir')} " )
private String TENGXUN_DEFA ;
/ * *
* 批量保存商品的分类
*
@ -163,7 +162,7 @@ public class SyncThirdDataServiceImpl extends SyncBaseThirdSxAbstract implements
return new ThirdApiRes ( ) . fail ( 1004 , I18nUtil . _ ( " 单次同步记录最多 " + limitCnt + " 条! " ) ) ;
}
int count = baseSaveOrUpdateShopBaseProductCategoryBatch ( list , categoryListJSON , storeId ) ;
int count = baseSaveOrUpdateShopBaseProductCategoryBatch ( list , categoryListJSON , storeId ) ;
Map < String , Integer > resp = new HashMap < > ( ) ;
resp . put ( " count " , count ) ;
@ -198,7 +197,7 @@ public class SyncThirdDataServiceImpl extends SyncBaseThirdSxAbstract implements
return new ThirdApiRes ( ) . fail ( 1004 , I18nUtil . _ ( " 单次同步记录最多 " + limitCnt + " 条! " ) ) ;
}
int count = baseSaveOrUpdateShopBaseProductBrandBatch ( goodBrandList , storeId , brandListJSON ) ;
int count = baseSaveOrUpdateShopBaseProductBrandBatch ( goodBrandList , storeId , brandListJSON ) ;
Map < String , Integer > resp = new HashMap < > ( ) ;
resp . put ( " count " , count ) ;
@ -227,7 +226,7 @@ public class SyncThirdDataServiceImpl extends SyncBaseThirdSxAbstract implements
return new ThirdApiRes ( ) . fail ( 1004 , I18nUtil . _ ( " 单次同步记录最多 " + limitCnt + " 条! " ) ) ;
}
int count = baseSaveOrUpdateGoods ( goodsListJSON , storeId ) ;
int count = baseSaveOrUpdateGoods ( goodsListJSON , storeId ) ;
Map < String , Integer > resp = new HashMap < > ( ) ;
resp . put ( " count " , count ) ;
@ -257,7 +256,7 @@ public class SyncThirdDataServiceImpl extends SyncBaseThirdSxAbstract implements
return new ThirdApiRes ( ) . fail ( 1004 , I18nUtil . _ ( " 单次同步记录最多 " + limitCnt + " 条! " ) ) ;
}
int count = baseSaveOrUpdateMemberBatch ( memberList , storeId ) ;
int count = baseSaveOrUpdateMemberBatch ( memberList , storeId ) ;
Map < String , Integer > resp = new HashMap < > ( ) ;
resp . put ( " count " , count ) ;
@ -299,13 +298,13 @@ public class SyncThirdDataServiceImpl extends SyncBaseThirdSxAbstract implements
/ / 1 - 品牌 , 2 - 分类 , 3 - 商品 , 4 - 会员
switch ( syncType ) {
case 1 :
return syncProductBrand ( new DataBaseInfo ( ) , storeId ) ; / / todo
return syncProductBrand ( new DataBaseInfo ( ) , storeId ) ; / / todo
case 2 :
return syncProductClazz ( new DataBaseInfo ( ) , storeId ) ; / / todo 测试
return syncProductClazz ( new DataBaseInfo ( ) , storeId ) ; / / todo 测试
case 3 :
return syncProduct ( new DataBaseInfo ( ) , storeId ) ; / / todo 没做完
return syncProduct ( new DataBaseInfo ( ) , storeId ) ; / / todo 没做完
case 4 :
return syncVip ( new DataBaseInfo ( ) , storeId ) ; / / todo 测试
return syncVip ( new DataBaseInfo ( ) , storeId ) ; / / todo 测试
}
return CommonResult . success ( ) ;
}
@ -316,26 +315,26 @@ public class SyncThirdDataServiceImpl extends SyncBaseThirdSxAbstract implements
*
* @return
* /
public CommonResult syncProduct ( DataBaseInfo dataBaseInfo , String storeId ) {
int total = sxSyncGoodsService . getGoodsTotal ( dataBaseInfo ) ;
public CommonResult syncProduct ( DataBaseInfo dataBaseInfo , String storeId ) {
int total = sxSyncGoodsService . getGoodsTotal ( dataBaseInfo ) ;
/ / 总页数
int pages = CommonUtil . getPagesCount ( total , SxDataDao . PAGESIZE ) ;
int syncCount = 0 ;
int syncCount = 0 ;
for ( int i = 1 ; i < pages ; i + + ) {
int count = 0 ;
List < SxSyncGoods > sxSyncGoodsList = sxSyncGoodsService . findGoodsListPage ( dataBaseInfo , i , pages ) ;
int count = 0 ;
List < SxSyncGoods > sxSyncGoodsList = sxSyncGoodsService . findGoodsListPage ( dataBaseInfo , i , pages ) ;
/ / todo 数据转换
List < SxGoosModel > sxGoosModelList = CvtToGoosModel ( sxSyncGoodsList ) ;
if ( CollectionUtil . isEmpty ( sxSyncGoodsList ) ) {
List < SxGoosModel > sxGoosModelList = CvtToGoosModel ( sxSyncGoodsList ) ;
if ( CollectionUtil . isEmpty ( sxSyncGoodsList ) ) {
continue ;
}
count = baseSaveOrUpdateGoods ( JSONUtil . parseArray ( sxGoosModelList ) , storeId ) ;
if ( count < = 0 ) {
count = baseSaveOrUpdateGoods ( JSONUtil . parseArray ( sxGoosModelList ) , storeId ) ;
if ( count < = 0 ) {
continue ;
}
syncCount + = count ;
syncCount + = count ;
}
logger . info ( " 同步商品的总数为{},成功数量为{} " , total , syncCount ) ;
logger . info ( " 同步商品的总数为{},成功数量为{} " , total , syncCount ) ;
return CommonResult . success ( ) ;
}
@ -345,29 +344,29 @@ public class SyncThirdDataServiceImpl extends SyncBaseThirdSxAbstract implements
*
* @return
* /
public CommonResult syncVip ( DataBaseInfo dataBaseInfo , String storeId ) {
public CommonResult syncVip ( DataBaseInfo dataBaseInfo , String storeId ) {
/ / 记录总数
Integer total = sxSyncVipService . getVipMembersTotal ( dataBaseInfo ) ;
/ / 总页数
int pages = CommonUtil . getPagesCount ( total , SxDataDao . PAGESIZE ) ;
List < SyncThirdMemberReq > memberList = new ArrayList < > ( ) ;
SyncThirdMemberReq syncThirdMemberReq = null ;
int syncCount = 0 ;
List < SyncThirdMemberReq > memberList = new ArrayList < > ( ) ;
SyncThirdMemberReq syncThirdMemberReq = null ;
int syncCount = 0 ;
for ( int i = 1 ; i < pages ; i + + ) {
memberList . clear ( ) ;
int count = 0 ;
syncThirdMemberReq = new SyncThirdMemberReq ( ) ;
List < SxSyncVip > sxSyncVipList = sxSyncVipService . findVipMemberPage ( dataBaseInfo , i , SxDataDao . PAGESIZE ) ;
syncThirdMemberReq = new SyncThirdMemberReq ( ) ;
List < SxSyncVip > sxSyncVipList = sxSyncVipService . findVipMemberPage ( dataBaseInfo , i , SxDataDao . PAGESIZE ) ;
/ / 处理数据转换SxSyncVip > SyncThirdMemberReq
memberList = ConverList ( sxSyncVipList ) ;
memberList = ConverList ( sxSyncVipList ) ;
memberList . add ( syncThirdMemberReq ) ;
count = baseSaveOrUpdateMemberBatch ( memberList , storeId ) ;
count = baseSaveOrUpdateMemberBatch ( memberList , storeId ) ;
if ( count < = 0 ) {
continue ;
}
syncCount + = count ;
syncCount + = count ;
}
logger . info ( " vip会员总共有{}条数据,同步完成{}条 " , total , syncCount ) ;
logger . info ( " vip会员总共有{}条数据,同步完成{}条 " , total , syncCount ) ;
return CommonResult . success ( ) ;
}
@ -376,61 +375,63 @@ public class SyncThirdDataServiceImpl extends SyncBaseThirdSxAbstract implements
*
* @return
* /
public CommonResult syncProductBrand ( DataBaseInfo dataBaseInfo , String storeId ) {
public CommonResult syncProductBrand ( DataBaseInfo dataBaseInfo , String storeId ) {
return null ;
}
/ * *
* 同步商品分类
*
* @return
* /
public CommonResult syncProductClazz ( DataBaseInfo dataBaseInfo , String storeId ) {
public CommonResult syncProductClazz ( DataBaseInfo dataBaseInfo , String storeId ) {
/ / 记录总数
Integer total = sxSyncCategoryService . getCategoryTotal ( dataBaseInfo ) ;
/ / 总页数
int pages = CommonUtil . getPagesCount ( total , SxDataDao . PAGESIZE ) ;
int syncCount = 0 ;
int syncCount = 0 ;
for ( int i = 1 ; i < = pages ; i + + ) {
int count = 0 ;
List < SxCategoryModel > list = sxSyncCategoryService . getCategoryByDataBasePage ( dataBaseInfo , i , SxDataDao . PAGESIZE ) ;
List < SxCategoryModel > list = sxSyncCategoryService . getCategoryByDataBasePage ( dataBaseInfo , i , SxDataDao . PAGESIZE ) ;
if ( CollUtil . isEmpty ( list ) ) {
continue ;
}
JSONArray categoryListJSON = JSONUtil . parseArray ( list ) ;
JSONArray categoryListJSON = JSONUtil . parseArray ( list ) ;
List < ShopBaseProductCategory > shopBaseProductCategories = JSONUtil . toList ( categoryListJSON , ShopBaseProductCategory . class ) ;
if ( shopBaseProductCategories = = null ) {
logger . info ( " 转换类型为空,类方法为{} " , " com.suisung.mall.shop.sync.service.impl.SyncThirdDataServiceImpl.syncProductClazz " ) ;
logger . info ( " 转换类型为空,类方法为{} " , " com.suisung.mall.shop.sync.service.impl.SyncThirdDataServiceImpl.syncProductClazz " ) ;
continue ;
}
count = baseSaveOrUpdateShopBaseProductCategoryBatch ( shopBaseProductCategories , categoryListJSON , storeId ) ;
count = baseSaveOrUpdateShopBaseProductCategoryBatch ( shopBaseProductCategories , categoryListJSON , storeId ) ;
if ( count < = 0 ) {
continue ;
}
syncCount + = count ;
syncCount + = count ;
}
logger . info ( " 商品分类总共有{}条数据,同步完成{}条 " , total , syncCount ) ;
logger . info ( " 商品分类总共有{}条数据,同步完成{}条 " , total , syncCount ) ;
return CommonResult . success ( ) ;
}
/ * *
* 文件上传
*
* @param appKey
* @param sign
* @param page 分页
* @param page 分页
* @param syncType
* @param multipartFile
* @return
* /
@Override
public ThirdApiRes fileUpload ( String appKey , String sign , String page , String syncType , MultipartFile multipartFile ) {
if ( StrUtil . isBlank ( appKey ) | | StrUtil . isBlank ( sign ) ) {
public ThirdApiRes fileUpload ( String appKey , String sign , String page , String syncType , MultipartFile multipartFile ) {
if ( StrUtil . isBlank ( appKey ) | | StrUtil . isBlank ( sign ) ) {
return new ThirdApiRes ( ) . fail ( 1003 , I18nUtil . _ ( " 缺少必要参数! " ) ) ;
}
/ / 验签 、 appid , 必要参数判断
SyncApp syncAppO = syncAppService . getOne ( new LambdaQueryWrapper < SyncApp > ( )
. select ( SyncApp : : getApp_key , SyncApp : : getApp_secret , SyncApp : : getStore_id )
. select ( SyncApp : : getApp_key , SyncApp : : getApp_secret , SyncApp : : getStore_id )
. eq ( SyncApp : : getApp_key , appKey )
. eq ( SyncApp : : getApp_secret , sign ) ) ;
. eq ( SyncApp : : getApp_secret , sign ) ) ;
if ( syncAppO = = null ) {
return new ThirdApiRes ( ) . fail ( 1001 , I18nUtil . _ ( " 签名有误! " ) ) ;
}
@ -441,13 +442,13 @@ public class SyncThirdDataServiceImpl extends SyncBaseThirdSxAbstract implements
return new ThirdApiRes ( ) . fail ( 1001 , I18nUtil . _ ( " 文件不能为空! " ) ) ;
}
byte [ ] bytes = multipartFile . getBytes ( ) ;
String folder = new FileUtils ( ) . getSyncTypeFlag ( syncType , clientPath ) + storeId + FileUtils . pathSeparator + page + FileUtils . pathSeparator ;
String filName = multipartFile . getOriginalFilename ( ) ;
String filePath = FileUtils . createFolderAndFileUsingFile ( folder , filName ) ;
String folder = new FileUtils ( ) . getSyncTypeFlag ( syncType , clientPath ) + storeId + FileUtils . pathSeparator + page + FileUtils . pathSeparator ;
String filName = multipartFile . getOriginalFilename ( ) ;
String filePath = FileUtils . createFolderAndFileUsingFile ( folder , filName ) ;
Path path = Paths . get ( filePath ) ;
Files . write ( path , bytes ) ;
logger . info ( " path-{},parent-{},filename-{},root-{} " , path . toString ( ) , path . getParent ( ) , path . getFileName ( ) . toString ( ) , path . getRoot ( ) ) ;
/ / String filaPath = path . toString ( ) ;
logger . info ( " path-{},parent-{},filename-{},root-{} " , path , path . getParent ( ) , path . getFileName ( ) . toString ( ) , path . getRoot ( ) ) ;
/ / String filaPath = path . toString ( ) ;
/ / if ( filePath . contains ( " : " ) ) {
/ / filePath = filePath . substring ( filePath . indexOf ( " : " ) + 1 ) ;
/ / }
@ -460,12 +461,13 @@ public class SyncThirdDataServiceImpl extends SyncBaseThirdSxAbstract implements
/ / . toUriString ( ) ;
return new ThirdApiRes ( ) . success ( " 文件上传成功 " ) ;
} catch ( IOException e ) {
return new ThirdApiRes ( ) . fail ( 500 , " 文件上传失败 " ) ;
return new ThirdApiRes ( ) . fail ( 500 , " 文件上传失败 " ) ;
}
}
/ * *
* 多线程处理文件
*
* @param appKey
* @param sign
* @param syncType
@ -475,24 +477,24 @@ public class SyncThirdDataServiceImpl extends SyncBaseThirdSxAbstract implements
@Async
public void SyncReadSxFileData ( String appKey , String sign , String syncType , List < String > folders ) {
SyncApp syncApp = syncAppService . getOne ( new LambdaQueryWrapper < SyncApp > ( )
. select ( SyncApp : : getApp_key , SyncApp : : getApp_secret , SyncApp : : getStore_id )
. select ( SyncApp : : getApp_key , SyncApp : : getApp_secret , SyncApp : : getStore_id )
. eq ( SyncApp : : getApp_key , appKey )
. eq ( SyncApp : : getApp_secret , sign ) ) ;
. eq ( SyncApp : : getApp_secret , sign ) ) ;
String storeId = syncApp . getStore_id ( ) ;
Date tenMinutesAgo = Date . from ( Instant . now ( ) . minus ( Duration . ofMinutes ( 5 ) ) ) ; / / 校准误差
Date date = DateUtil . date ( tenMinutesAgo ) ;
if ( null = = syncApp . getStore_id ( ) | | syncApp . getStore_id ( ) . isEmpty ( ) ) {
Date date = DateUtil . date ( tenMinutesAgo ) ;
if ( null = = syncApp . getStore_id ( ) | | syncApp . getStore_id ( ) . isEmpty ( ) ) {
logger . info ( " 商品id为空 " ) ;
return ;
}
if ( folders = = null | | folders . isEmpty ( ) ) {
if ( folders = = null | | folders . isEmpty ( ) ) {
logger . info ( " 没有商品数据 " ) ;
return ;
}
List < String > newFolders = new ArrayList < > ( ) ;
folders . forEach ( page - > {
String newfolder = new FileUtils ( ) . getSyncTypeFlag ( syncType , clientPath ) + storeId + FileUtils . pathSeparator + page + FileUtils . pathSeparator ;
List < String > newFolders = new ArrayList < > ( ) ;
folders . forEach ( page - > {
String newfolder = new FileUtils ( ) . getSyncTypeFlag ( syncType , clientPath ) + storeId + FileUtils . pathSeparator + page + FileUtils . pathSeparator ;
newFolders . add ( newfolder ) ;
} ) ;
@ -505,35 +507,35 @@ public class SyncThirdDataServiceImpl extends SyncBaseThirdSxAbstract implements
ExecutorService executor = Executors . newFixedThreadPool ( 6 ) ;
List < Future < ? > > futures = new ArrayList < > ( ) ;
/ / 提交任务
AtomicInteger success = new AtomicInteger ( ) ;
AtomicInteger fails = new AtomicInteger ( ) ;
List < String > failFolders = new ArrayList < > ( ) ;
List < String > failMessage = new ArrayList < > ( ) ;
AtomicInteger success = new AtomicInteger ( ) ;
AtomicInteger fails = new AtomicInteger ( ) ;
List < String > failFolders = new ArrayList < > ( ) ;
List < String > failMessage = new ArrayList < > ( ) ;
shopBaseProductCategoryService . getCategoryListByStoreId ( storeId ) ;
for ( int i = 0 ; i < newFolders . size ( ) ; i + + ) {
final int taskId = i ;
threadNum . incrementAndGet ( ) ;
futures . add ( executor . submit ( ( ) - > {
futures . add ( executor . submit ( ( ) - > {
int count = 0 ; / / 失败重试机制 , 当失败重试一次 , 再次失败则记录到数据库中
while ( true ) {
while ( true ) {
count + + ;
String taskName = newFolders . get ( taskId ) ;
String fileName = " good_ " + ( taskId + 1 ) + " .txt " ;
JSONArray jsonArray = new ThreadFileUtils ( ) . processFolder ( taskName , newFolders . get ( taskId ) ) ;
String taskName = newFolders . get ( taskId ) ;
String fileName = " good_ " + ( taskId + 1 ) + " .txt " ;
JSONArray jsonArray = new ThreadFileUtils ( ) . processFolder ( taskName , newFolders . get ( taskId ) ) ;
try {
baseSaveOrUpdateGoodsBatch ( jsonArray , storeId ) ;
baseSaveOrUpdateGoodsBatch ( jsonArray , storeId ) ;
success . getAndIncrement ( ) ;
threadNum . decrementAndGet ( ) ;
return " 成功 " + taskId ;
} catch ( Exception e ) {
if ( count < 2 ) {
} catch ( Exception e ) {
if ( count < 2 ) {
/ / Thread . sleep ( 100 ) ;
continue ;
}
fails . getAndIncrement ( ) ;
failFolders . add ( newFolders . get ( taskId ) + fileName ) ;
failMessage . add ( taskId + " _ " + e . getMessage ( ) ) ;
return " 失败 " + newFolders . get ( taskId ) ;
failFolders . add ( newFolders . get ( taskId ) + fileName ) ;
failMessage . add ( taskId + " _ " + e . getMessage ( ) ) ;
return " 失败 " + newFolders . get ( taskId ) ;
}
}
} ) ) ;
@ -553,13 +555,13 @@ public class SyncThirdDataServiceImpl extends SyncBaseThirdSxAbstract implements
shopBaseProductCategoryService . clearCategoryCache ( storeId ) ;
shopProductSpecItemService . clearExistItem ( Integer . valueOf ( storeId ) ) ;
baseProductSpecService . clearShopBaseProductSpecMap ( Integer . valueOf ( storeId ) ) ;
List < SyncFileLog > syncFileLogs = new ArrayList < > ( ) ;
List < SyncFileLog > syncFileLogs = new ArrayList < > ( ) ;
for ( int i = 0 ; i < failFolders . size ( ) ; i + + ) {
String path = failFolders . get ( i ) ;
String taskId = failMessage . get ( i ) . split ( " _ " ) [ 0 ] ;
SyncFileLog syncFileLog = new SyncFileLog ( ) ;
String path = failFolders . get ( i ) ;
String taskId = failMessage . get ( i ) . split ( " _ " ) [ 0 ] ;
SyncFileLog syncFileLog = new SyncFileLog ( ) ;
syncFileLog . setSyncType ( syncType ) ;
syncFileLog . setFileName ( path . substring ( path . lastIndexOf ( FileUtils . pathSeparator ) + 1 ) ) ;
syncFileLog . setFileName ( path . substring ( path . lastIndexOf ( FileUtils . pathSeparator ) + 1 ) ) ;
syncFileLog . setSyncStatus ( DicEnum . FAILED . getCode ( ) ) ;
syncFileLog . setSyncTaskId ( taskId ) ;
syncFileLog . setSyncStoreId ( storeId ) ;
@ -569,56 +571,56 @@ public class SyncThirdDataServiceImpl extends SyncBaseThirdSxAbstract implements
syncFileLog . setTargetSystem ( DicEnum . SOURCE_SYSTEM_TYPE_SELF . getCode ( ) ) ;
syncFileLogs . add ( syncFileLog ) ;
}
if ( CollUtil . isNotEmpty ( syncFileLogs ) ) {
syncFileLogService . saveBatch ( syncFileLogs , syncFileLogs . size ( ) ) ;
if ( CollUtil . isNotEmpty ( syncFileLogs ) ) {
syncFileLogService . saveBatch ( syncFileLogs , syncFileLogs . size ( ) ) ;
}
/ / todo 定时清理文件 , 建议用服务器脚本
logger . info ( " 执行成功{}个文件,失败{}个文件 " , success , fails ) ;
logger . info ( " 执行成功{}个文件,失败{}个文件 " , success , fails ) ;
logger . info ( " 同步商品数据执行结束 " ) ;
/ / 更新当前的获取时间 , 用户客户端获取
/ / 更新当前的获取时间 , 用户客户端获取
try {
QueryWrapper < StoreDbConfig > storeDbConfigQueryWrapper = new QueryWrapper < > ( ) ;
storeDbConfigQueryWrapper . eq ( " store_id " , storeId ) ;
StoreDbConfig storeDbConfig = storeDbConfigService . getOne ( storeDbConfigQueryWrapper ) ;
if ( ObjectUtil . isNotEmpty ( storeDbConfig ) ) {
StoreDbConfig storeDbConfig = storeDbConfigService . getOne ( storeDbConfigQueryWrapper ) ;
if ( ObjectUtil . isNotEmpty ( storeDbConfig ) ) {
storeDbConfig . setRefreshTime ( date ) ;
storeDbConfigService . saveOrUpdate ( storeDbConfig ) ;
}
} catch ( RuntimeException e ) {
logger . error ( " 同步时间失败 " + e . getMessage ( ) ) ;
} catch ( RuntimeException e ) {
logger . error ( " 同步时间失败 " + e . getMessage ( ) ) ;
}
}
@Override
public ResponseEntity < Resource > downloadToClient ( String primaryKey , String clienVersionName ) {
logger . info ( " primaryKey:{} " , primaryKey ) ;
boolean checked = syncAppService . checkPrimaryKey ( primaryKey ) ;
if ( checked ) {
String tempFilePath = System . getProperty ( " user.home " ) ;
String clientJarPath = " " ;
COSObjectSummary cosObjectSummary = ossService . findNewestFile ( FileUtils . OSSCLIENTFOLDER ) ;
String jarFileName = cosObjectSummary . getKey ( ) . substring ( cosObjectSummary . getKey ( ) . lastIndexOf ( " / " ) + 1 ) ;
if ( jarFileName . equals ( clienVersionName + " .jar " ) ) {
logger . error ( " 没有版本更新 " ) ;
return ResponseEntity . ok ( )
. contentType ( MediaType . APPLICATION_OCTET_STREAM )
. header ( HttpHeaders . CONTENT_DISPOSITION ,
" attachment; filename=error.txt " )
. header ( " error " , " noVersion " )
. body ( new ByteArrayResource ( clienVersionName . getBytes ( StandardCharsets . UTF_8 ) ) ) ;
} else {
String filePath = cosObjectSummary . getKey ( ) ;
clientJarPath = ossService . download ( filePath , tempFilePath + FileUtils . pathSeparator + filePath ) ;
}
if ( StringUtils . isNotEmpty ( clientJarPath ) ) {
public ResponseEntity < Resource > downloadToClient ( String primaryKey , String clienVersionName ) {
logger . info ( " primaryKey:{} " , primaryKey ) ;
boolean checked = syncAppService . checkPrimaryKey ( primaryKey ) ;
if ( checked ) {
String tempFilePath = System . getProperty ( " user.home " ) ;
String clientJarPath = " " ;
COSObjectSummary cosObjectSummary = ossService . findNewestFile ( FileUtils . OSSCLIENTFOLDER ) ;
String jarFileName = cosObjectSummary . getKey ( ) . substring ( cosObjectSummary . getKey ( ) . lastIndexOf ( " / " ) + 1 ) ;
if ( jarFileName . equals ( clienVersionName + " .jar " ) ) {
logger . error ( " 没有版本更新 " ) ;
return ResponseEntity . ok ( )
. contentType ( MediaType . APPLICATION_OCTET_STREAM )
. header ( HttpHeaders . CONTENT_DISPOSITION ,
" attachment; filename=error.txt " )
. header ( " error " , " noVersion " )
. body ( new ByteArrayResource ( clienVersionName . getBytes ( StandardCharsets . UTF_8 ) ) ) ;
} else {
String filePath = cosObjectSummary . getKey ( ) ;
clientJarPath = ossService . download ( filePath , tempFilePath + FileUtils . pathSeparator + filePath ) ;
}
if ( StringUtils . isNotEmpty ( clientJarPath ) ) {
/ / 构建文件路径
Path filePath = Paths . get ( clientJarPath ) ;
File file = filePath . toFile ( ) ;
/ / 检查文件是否存在
if ( ! file . exists ( ) ) {
return ResponseEntity . status ( HttpStatus . NOT_FOUND )
. header ( " error " , " noFile " )
. header ( " error " , " noFile " )
. body ( new ByteArrayResource ( jarFileName . getBytes ( ) ) ) ;
}
/ / 创建Resource对象
@ -629,13 +631,13 @@ public class SyncThirdDataServiceImpl extends SyncBaseThirdSxAbstract implements
contentType = Files . probeContentType ( filePath ) ;
} catch ( IOException e ) {
return ResponseEntity . status ( HttpStatus . NOT_FOUND )
. header ( " error " , " 500 " )
. header ( " error " , " 500 " )
. body ( new ByteArrayResource ( jarFileName . getBytes ( ) ) ) ;
}
if ( contentType = = null ) {
contentType = " application/octet-stream " ;
}
/ / redisService . set ( RedisKey . SXCLIENTKEYVERSION , jarFileName ) ;
/ / redisService . set ( RedisKey . SXCLIENTKEYVERSION , jarFileName ) ;
/ / 构建响应
return ResponseEntity . ok ( )
. contentType ( MediaType . parseMediaType ( contentType ) )
@ -646,69 +648,120 @@ public class SyncThirdDataServiceImpl extends SyncBaseThirdSxAbstract implements
}
logger . info ( " !校验失败 " ) ;
return ResponseEntity . status ( HttpStatus . NOT_FOUND )
. header ( " error " , " noValid " )
. header ( " error " , " noValid " )
. body ( new ByteArrayResource ( " version " . getBytes ( ) ) ) ;
}
@Override
public ThirdApiRes getStoreDbConfig ( String appKey , String sign ) {
if ( StrUtil . isBlank ( appKey ) | | StrUtil . isBlank ( sign ) ) {
public ThirdApiRes getStoreDbConfig ( String appKey , String sign ) {
if ( StrUtil . isBlank ( appKey ) | | StrUtil . isBlank ( sign ) ) {
return new ThirdApiRes ( ) . fail ( 1003 , I18nUtil . _ ( " 缺少必要参数! " ) ) ;
}
/ / 验签 、 appid , 必要参数判断
SyncApp syncAppO = syncAppService . getOne ( new LambdaQueryWrapper < SyncApp > ( )
. select ( SyncApp : : getApp_key , SyncApp : : getApp_secret , SyncApp : : getStore_id )
. select ( SyncApp : : getApp_key , SyncApp : : getApp_secret , SyncApp : : getStore_id )
. eq ( SyncApp : : getApp_key , appKey )
. eq ( SyncApp : : getApp_secret , sign ) ) ;
. eq ( SyncApp : : getApp_secret , sign ) ) ;
if ( syncAppO = = null ) {
return new ThirdApiRes ( ) . fail ( 1001 , I18nUtil . _ ( " 签名有误! " ) ) ;
}
String storeId = syncAppO . getStore_id ( ) ;
QueryWrapper < StoreDbConfig > queryWrapper = new QueryWrapper < > ( ) ;
queryWrapper . eq ( " store_id " , storeId ) ;
queryWrapper . eq ( " has_start " , DicEnum . YESORNO_1 . getCode ( ) ) ;
StoreDbConfig storeDbConfig = storeDbConfigService . getOne ( queryWrapper ) ;
queryWrapper . eq ( " has_start " , DicEnum . YESORNO_1 . getCode ( ) ) ;
StoreDbConfig storeDbConfig = storeDbConfigService . getOne ( queryWrapper ) ;
if ( storeDbConfig = = null ) {
return new ThirdApiRes ( ) . fail ( 1003 , I18nUtil . _ ( " 服务器配置缺少配置信息! " ) ) ;
}
return new ThirdApiRes ( ) . success ( " 成功 " , storeDbConfig ) ;
return new ThirdApiRes ( ) . success ( " 成功 " , storeDbConfig ) ;
}
@Override
public ThirdApiRes getStoreDataRelease ( String appKey , String sign ) {
if ( StrUtil . isBlank ( appKey ) | | StrUtil . isBlank ( sign ) ) {
if ( StrUtil . isBlank ( appKey ) | | StrUtil . isBlank ( sign ) ) {
return new ThirdApiRes ( ) . fail ( 1003 , I18nUtil . _ ( " 缺少必要参数! " ) ) ;
}
/ / 验签 、 appid , 必要参数判断
SyncApp syncAppO = syncAppService . getOne ( new LambdaQueryWrapper < SyncApp > ( )
. select ( SyncApp : : getApp_key , SyncApp : : getApp_secret , SyncApp : : getStore_id )
. select ( SyncApp : : getApp_key , SyncApp : : getApp_secret , SyncApp : : getStore_id )
. eq ( SyncApp : : getApp_key , appKey )
. eq ( SyncApp : : getApp_secret , sign ) ) ;
. eq ( SyncApp : : getApp_secret , sign ) ) ;
if ( syncAppO = = null ) {
return new ThirdApiRes ( ) . fail ( 1001 , I18nUtil . _ ( " 签名有误! " ) ) ;
}
Object obRst = redisService . get ( RedisKey . STOREDATARELEASE ) ; / / 商品库存扣减
Map storeDataResultMap = new HashMap ( ) ;
if ( obRst ! = null ) {
Map resultMap = ( Map ) obRst ;
Set < Map . Entry > sme = resultMap . entrySet ( ) ;
storeDataResultMap = sme . stream ( ) . filter ( m - > ! ( m . getValue ( ) . equals ( ( double ) 0 ) ) ) . collect ( Collectors . toMap ( Map . Entry : : getKey , Map . Entry : : getValue ) ) ;
/ / Object obRst = redisService . get ( RedisKey . STOREDATARELEASE ) ; / / 商品库存扣减
/ / Map storeDataResultMap = new HashMap ( ) ;
/ / if ( obRst ! = null ) {
/ / Map resultMap = ( Map ) obRst ;
/ / Set < Map . Entry > sme = resultMap . entrySet ( ) ;
/ / storeDataResultMap = sme . stream ( ) . filter ( m - > ! ( m . getValue ( ) . equals ( ( double ) 0 ) ) ) . collect ( Collectors . toMap ( Map . Entry : : getKey , Map . Entry : : getValue ) ) ;
/ / }
Map < String , Integer > storeDataResultMap = getProductStockFromRedis ( ) ;
return new ThirdApiRes ( ) . success ( " success " , storeDataResultMap ) ;
}
/ / @Override
/ / public void saveStoreRelease ( Map storeData ) {
/ / / / RMK : 这样写 , 存在严重的线程安全问题 , 可能会导致数据丢失或覆盖 ,
/ / / / 改成 redis 原子级别的 hash 类别存储
/ / if ( CollectionUtil . isEmpty ( storeData ) ) {
/ / return ;
/ / }
/ / Object obRst = redisService . get ( RedisKey . STOREDATARELEASE ) ;
/ / if ( obRst ! = null ) {
/ / Map map = ( Map ) obRst ;
/ / map . putAll ( storeData ) ;
/ / redisService . set ( RedisKey . STOREDATARELEASE , map ) ;
/ / } else {
/ / redisService . set ( RedisKey . STOREDATARELEASE , storeData ) ;
/ / }
/ / }
@Override
public Map < String , Integer > getProductStockFromRedis ( ) {
try {
/ / 从 Redis 获取 hash 结构的所有键值对
Map < Object , Object > redisHash = redisTemplate . opsForHash ( ) . entries ( RedisKey . STOREDATARELEASE ) ;
if ( redisHash = = null | | redisHash . isEmpty ( ) ) {
return Collections . emptyMap ( ) ;
}
/ / 转换为 Map < String , Integer >
return redisHash . entrySet ( ) . stream ( )
. collect ( Collectors . toMap (
entry - > String . valueOf ( entry . getKey ( ) ) ,
entry - > Convert . toInt ( entry . getValue ( ) , 0 ) / / 转换失败时默认为 0
) ) ;
} catch ( Exception e ) {
logger . error ( " 从 Redis 获取商品库存失败: {} " , e . getMessage ( ) , e ) ;
return Collections . emptyMap ( ) ;
}
return new ThirdApiRes ( ) . success ( " success " , storeDataResultMap ) ;
}
@Override
public void saveStoreRealeas ( Map storeData ) {
if ( CollectionUtil . isEmpty ( storeData ) ) {
public void incrProductStockToRedis ( Map < String , Integer > stockDeltaMap ) {
/ / 校验参数 , 避免空指针
if ( CollectionUtil . isEmpty ( stockDeltaMap ) ) {
return ;
}
Object obRst = redisService . get ( RedisKey . STOREDATARELEASE ) ;
if ( obRst ! = null ) {
Map map = ( Map ) obRst ;
map . putAll ( storeData ) ;
redisService . set ( RedisKey . STOREDATARELEASE , map ) ;
} else {
redisService . set ( RedisKey . STOREDATARELEASE , storeData ) ;
for ( Map . Entry < String , Integer > entry : stockDeltaMap . entrySet ( ) ) {
String productKey = entry . getKey ( ) ;
Integer delta = entry . getValue ( ) ;
if ( StrUtil . isBlank ( productKey ) | | delta = = null ) {
continue ;
}
try {
/ / 使用 Redis 的 HINCRBY 保证原子性和高性能
redisTemplate . opsForHash ( ) . increment ( RedisKey . STOREDATARELEASE , productKey , delta ) ;
} catch ( Exception e ) {
logger . error ( " 库存累加失败, productKey={}, delta={}, error={} " , productKey , delta , e . getMessage ( ) , e ) ;
}
}
}
@ -717,79 +770,81 @@ public class SyncThirdDataServiceImpl extends SyncBaseThirdSxAbstract implements
* 压缩商家数据 , 并上传cos
* 保存商店数据 如
* " E: \\ data \\ uploaded \\ goods \\ 2025 \\ 6 \\ 6 \\ 1 \\ 2 "
*
* @param path
* /
public void upLoadZipToOss ( String path ) {
File file = new File ( path ) ;
File parentFile = null ;
if ( ! file . exists ( ) ) { / / 存在则取本地 , 不存在下载cos的数据
public void upLoadZipToOss ( String path ) {
File file = new File ( path ) ;
File parentFile = null ;
if ( ! file . exists ( ) ) { / / 存在则取本地 , 不存在下载cos的数据
logger . info ( " 没有同步数据上传 " ) ;
return ;
}
parentFile = file . getParentFile ( ) ;
String filePath = parentFile . getPath ( ) ;
filePath = filePath . replaceAll ( " \\ \\ " , " / " ) ;
String folderName = parentFile . getName ( ) ;
String parentFolderName = parentFile . getParentFile ( ) . getPath ( ) . replaceAll ( " \\ \\ " , " / " ) ;
String localPath = parentFolderName + " / " + folderName + " .zip " ;
ZipUtil . zip ( filePath , localPath , true ) ;
if ( parentFolderName . contains ( " : " ) ) {
parentFolderName = parentFolderName . substring ( filePath . indexOf ( " : " ) + 1 ) ;
parentFile = file . getParentFile ( ) ;
String filePath = parentFile . getPath ( ) ;
filePath = filePath . replaceAll ( " \\ \\ " , " / " ) ;
String folderName = parentFile . getName ( ) ;
String parentFolderName = parentFile . getParentFile ( ) . getPath ( ) . replaceAll ( " \\ \\ " , " / " ) ;
String localPath = parentFolderName + " / " + folderName + " .zip " ;
ZipUtil . zip ( filePath , localPath , true ) ;
if ( parentFolderName . contains ( " : " ) ) {
parentFolderName = parentFolderName . substring ( filePath . indexOf ( " : " ) + 1 ) ;
}
String cosFileName = TENGXUN_DEFA . concat ( " / " ) . concat ( " sync " ) . concat ( parentFolderName ) . concat ( " / " ) . concat ( folderName + " .zip " ) ;
ossService . uploadObject4OSS ( new File ( localPath ) , cosFileName ) ;
String cosFileName = TENGXUN_DEFA . concat ( " / " ) . concat ( " sync " ) . concat ( parentFolderName ) . concat ( " / " ) . concat ( folderName + " .zip " ) ;
ossService . uploadObject4OSS ( new File ( localPath ) , cosFileName ) ;
}
/ * *
* 压缩商家数据 , 并上传cos
* 保存商店数据 如
* " E: \\ data \\ uploaded \\ goods \\ 2025 \\ 6 \\ 6 \\ 1 \\ 2 "
*
* @param path
* /
public void dowloadAndUnZip ( String path ) {
File file = new File ( path ) ;
File parentFile = null ;
if ( file . exists ( ) ) { / / 存在则取本地 , 不存在下载cos的数据
public void dowloadAndUnZip ( String path ) {
File file = new File ( path ) ;
File parentFile = null ;
if ( file . exists ( ) ) { / / 存在则取本地 , 不存在下载cos的数据
logger . info ( " 没有同步数据下载 " ) ;
} else {
parentFile = file . getParentFile ( ) ;
String ossFilePath = parentFile . getParentFile ( ) . getPath ( ) ;
} else {
parentFile = file . getParentFile ( ) ;
String ossFilePath = parentFile . getParentFile ( ) . getPath ( ) ;
String fileName = parentFile . getName ( ) + " .zip " ;
String fileName = parentFile . getName ( ) + " .zip " ;
String parentFolderName = parentFile . getParent ( ) . replaceAll ( " \\ \\ " , " / " ) ;
String localPath = parentFolderName + " / " + fileName ;
ossFilePath = ossFilePath . replaceAll ( " \\ \\ " , " / " ) + " / " + fileName ;
String parentFolderName = parentFile . getParent ( ) . replaceAll ( " \\ \\ " , " / " ) ;
String localPath = parentFolderName + " / " + fileName ;
ossFilePath = ossFilePath . replaceAll ( " \\ \\ " , " / " ) + " / " + fileName ;
if ( ossFilePath . contains ( " : " ) ) {
ossFilePath = ossFilePath . substring ( ossFilePath . indexOf ( " : " ) + 1 ) ;
if ( ossFilePath . contains ( " : " ) ) {
ossFilePath = ossFilePath . substring ( ossFilePath . indexOf ( " : " ) + 1 ) ;
}
ossFilePath = TENGXUN_DEFA . concat ( " / " ) . concat ( " sync " ) . concat ( ossFilePath ) ;
String dowlowFilePath = ossService . download ( ossFilePath , localPath ) ;
File localFile = new File ( dowlowFilePath ) ;
ZipUtil . unzip ( dowlowFilePath , localFile . getParent ( ) , CharsetUtil . CHARSET_GBK ) ;
ossFilePath = TENGXUN_DEFA . concat ( " / " ) . concat ( " sync " ) . concat ( ossFilePath ) ;
String dowlowFilePath = ossService . download ( ossFilePath , localPath ) ;
File localFile = new File ( dowlowFilePath ) ;
ZipUtil . unzip ( dowlowFilePath , localFile . getParent ( ) , CharsetUtil . CHARSET_GBK ) ;
}
}
@Override
public ThirdApiRes fileUploadToOss ( String appKey , String sign , String syncType , List < String > folders ) {
SyncApp syncApp = syncAppService . getOne ( new LambdaQueryWrapper < SyncApp > ( )
. select ( SyncApp : : getApp_key , SyncApp : : getApp_secret , SyncApp : : getStore_id )
. select ( SyncApp : : getApp_key , SyncApp : : getApp_secret , SyncApp : : getStore_id )
. eq ( SyncApp : : getApp_key , appKey )
. eq ( SyncApp : : getApp_secret , sign ) ) ;
. eq ( SyncApp : : getApp_secret , sign ) ) ;
String storeId = syncApp . getStore_id ( ) ;
Date tenMinutesAgo = Date . from ( Instant . now ( ) . minus ( Duration . ofMinutes ( 5 ) ) ) ; / / 校准误差
Date date = DateUtil . date ( tenMinutesAgo ) ;
if ( null = = syncApp . getStore_id ( ) | | syncApp . getStore_id ( ) . isEmpty ( ) ) {
Date date = DateUtil . date ( tenMinutesAgo ) ;
if ( null = = syncApp . getStore_id ( ) | | syncApp . getStore_id ( ) . isEmpty ( ) ) {
logger . info ( " 商品id为空 " ) ;
return new ThirdApiRes ( ) . fail ( 250 , " 商品id为空 " ) ;
return new ThirdApiRes ( ) . fail ( 250 , " 商品id为空 " ) ;
}
if ( folders = = null | | folders . isEmpty ( ) ) {
if ( folders = = null | | folders . isEmpty ( ) ) {
logger . info ( " 没有商品数据 " ) ;
return new ThirdApiRes ( ) . fail ( 250 , " 没有商品数据 " ) ;
return new ThirdApiRes ( ) . fail ( 250 , " 没有商品数据 " ) ;
}
String newfolder = new FileUtils ( ) . getSyncTypeFlag ( syncType , clientPath ) + storeId + FileUtils . pathSeparator + folders . get ( 0 ) + FileUtils . pathSeparator ;
String newfolder = new FileUtils ( ) . getSyncTypeFlag ( syncType , clientPath ) + storeId + FileUtils . pathSeparator + folders . get ( 0 ) + FileUtils . pathSeparator ;
upLoadZipToOss ( newfolder ) ; / / 上传文件到cos
return new ThirdApiRes ( ) . success ( " 上传成功 " ) ;
}