From bce489fe5544cf763b5a53b913682eb0b40af37f Mon Sep 17 00:00:00 2001 From: Jack <46790855@qq.com> Date: Fri, 13 Jun 2025 10:36:38 +0800 Subject: [PATCH] =?UTF-8?q?=E5=95=86=E5=93=81=E5=BA=93=E5=AD=98=E7=B4=AF?= =?UTF-8?q?=E5=8A=A0=E5=87=8F=E5=85=AC=E5=85=B1=E6=96=B9=E6=B3=95=E4=BF=AE?= =?UTF-8?q?=E6=AD=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../mall/common/service/CommonService.java | 34 ++ .../service/impl/CommonServiceImpl.java | 86 ++++ .../src/main/resources/application-local.yml | 10 + .../sync/service/SyncThirdDataService.java | 41 +- .../impl/SyncThirdDataServiceImpl.java | 441 ++++++++++-------- 5 files changed, 407 insertions(+), 205 deletions(-) create mode 100644 mall-common/src/main/java/com/suisung/mall/common/service/CommonService.java create mode 100644 mall-common/src/main/java/com/suisung/mall/common/service/impl/CommonServiceImpl.java diff --git a/mall-common/src/main/java/com/suisung/mall/common/service/CommonService.java b/mall-common/src/main/java/com/suisung/mall/common/service/CommonService.java new file mode 100644 index 00000000..1176bd03 --- /dev/null +++ b/mall-common/src/main/java/com/suisung/mall/common/service/CommonService.java @@ -0,0 +1,34 @@ +/* + * 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.common.service; + +/** + * 通用服务接口 + */ +public interface CommonService { + + + /** + * 尝试获取分布式锁 + * + * @param lockKey 锁的key + * @param expireSeconds 锁过期时间(秒) + * @return 锁标识(解锁时需用),加锁失败返回null + */ + String tryDistributedLock(String lockKey, long expireSeconds); + + /** + * 释放分布式锁 + * + * @param lockKey 锁的key + * @param lockValue 加锁时返回的value,确保只有持有锁的线程能解锁 + * @return 是否释放成功 + */ + boolean releaseLock(String lockKey, String lockValue); +} diff --git a/mall-common/src/main/java/com/suisung/mall/common/service/impl/CommonServiceImpl.java b/mall-common/src/main/java/com/suisung/mall/common/service/impl/CommonServiceImpl.java new file mode 100644 index 00000000..c6397880 --- /dev/null +++ b/mall-common/src/main/java/com/suisung/mall/common/service/impl/CommonServiceImpl.java @@ -0,0 +1,86 @@ +/* + * 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.common.service.impl; + +import lombok.extern.slf4j.Slf4j; +import org.springframework.context.annotation.Lazy; +import org.springframework.data.redis.core.RedisTemplate; +import org.springframework.data.redis.core.script.DefaultRedisScript; +import org.springframework.stereotype.Service; + +import javax.annotation.Resource; +import java.util.Collections; +import java.util.UUID; +import java.util.concurrent.TimeUnit; + +@Slf4j +@Service +public class CommonServiceImpl { + + @Lazy + @Resource + private RedisTemplate redisTemplate; + + /** + * 尝试获取分布式锁 + *

+ * 使用实例: + * String lockKey = "order:123"; + * long expireSeconds = 10; + * String lockValue = commonServiceImpl.tryDistributedLock(lockKey, expireSeconds); + * if (lockValue != null) { + * try { + * // 执行业务逻辑 + * } finally { + * commonServiceImpl.releaseLock(lockKey, lockValue); + * } + * } else { + * // 获取锁失败,做相应处理 + * } + * + * @param lockKey 锁的key + * @param expireSeconds 锁过期时间(秒) + * @return 锁标识(解锁时需用),加锁失败返回null + */ + public String tryDistributedLock(String lockKey, long expireSeconds) { + String lockValue = UUID.randomUUID().toString(); + try { + Boolean success = redisTemplate.opsForValue().setIfAbsent(lockKey, lockValue, expireSeconds, TimeUnit.SECONDS); + return Boolean.TRUE.equals(success) ? lockValue : null; + } catch (Exception e) { + // 记录异常日志,实际项目可用Logger + e.printStackTrace(); + return null; + } + } + + /** + * 释放分布式锁 + * + * @param lockKey 锁的key + * @param lockValue 加锁时返回的value,确保只有持有锁的线程能解锁 + * @return 是否释放成功 + */ + public boolean releaseLock(String lockKey, String lockValue) { + String luaScript = + "if redis.call('get', KEYS[1]) == ARGV[1] then " + + " return redis.call('del', KEYS[1]) " + + "else " + + " return 0 " + + "end"; + try { + DefaultRedisScript script = new DefaultRedisScript<>(luaScript, Long.class); + Long result = (Long) redisTemplate.execute(script, Collections.singletonList(lockKey), lockValue); + return result != null && result > 0; + } catch (Exception e) { + log.error("释放分布式锁异常,key={}, error={}", lockKey, e.getMessage(), e); + return false; + } + } +} diff --git a/mall-common/src/main/resources/application-local.yml b/mall-common/src/main/resources/application-local.yml index e58d5ab0..213d045f 100644 --- a/mall-common/src/main/resources/application-local.yml +++ b/mall-common/src/main/resources/application-local.yml @@ -28,6 +28,16 @@ redis: separator: ":" expire: 3600 +redisson: + address: redis://@redis.host@:@redis.port@ + database: @redis.database@ # Redis 库索引 + password: @redis.password@ # Redis 密码 + connectionPoolSize: 64 # 连接池大小 + connectionMinimumIdleSize: 10 # 最小空闲连接数 + idleConnectionTimeout: 10000 # 空闲连接超时时间(毫秒) + connectTimeout: 10000 # 连接超时时间(毫秒) + timeout: 3000 # 命令等待超时时间(毫秒) + baidu: map: app_id: 116444176 diff --git a/mall-shop/src/main/java/com/suisung/mall/shop/sync/service/SyncThirdDataService.java b/mall-shop/src/main/java/com/suisung/mall/shop/sync/service/SyncThirdDataService.java index a8b9baf7..e7db8458 100644 --- a/mall-shop/src/main/java/com/suisung/mall/shop/sync/service/SyncThirdDataService.java +++ b/mall-shop/src/main/java/com/suisung/mall/shop/sync/service/SyncThirdDataService.java @@ -10,14 +10,12 @@ 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; import java.util.Map; @@ -41,6 +39,7 @@ public interface SyncThirdDataService { /** * 批量保存商品记录 + * * @param goodsListJSON * @return */ @@ -48,6 +47,7 @@ public interface SyncThirdDataService { /** * 批量保存会员记录 + * * @param memberList * @return */ @@ -55,6 +55,7 @@ public interface SyncThirdDataService { /** * 手动触发同步 + * * @param storeId * @param syncType * @return @@ -62,42 +63,43 @@ public interface SyncThirdDataService { 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); + 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 folders); + void SyncReadSxFileData(String appKey, String sign, String syncType, List folders); /** * 下载客户端更新包 + * * @param primaryKey * @return */ - ResponseEntity downloadToClient(String primaryKey,String clienVersionName); + ResponseEntity downloadToClient(String primaryKey, String clienVersionName); /** * 获取客户端数据库配置 + * * @param appKey * @param sign * @return */ - ThirdApiRes getStoreDbConfig(String appKey,String sign); + ThirdApiRes getStoreDbConfig(String appKey, String sign); /** * 同步商品数据库存到客户端 + * * @param appKey * @param sign * @return @@ -105,18 +107,33 @@ public interface SyncThirdDataService { ThirdApiRes getStoreDataRelease(String appKey, String sign); /** - * 存储扣减商品到redis + * 保存一个或多个商品刚刚变化的库存到 redis hash 缓存 + * * @param storeData */ - void saveStoreRealeas(Map storeData); +// void saveStoreRelease(Map storeData); + + /** + * 从 Redis 中获取商品(有变动的)库存数据 + * + * @return + */ + Map getProductStockFromRedis(); + + /** + * 下单或支付后,批量累加减商品库存,使用 Redis Hash 的原子自增操作,保证并发安全 + * + * @param stockDeltaMap key 为商品唯一key,value 为库存增降量 例如 {"1234567890123": 100, "1234567890124": 50} 库存数为正负整数,单位可能是个数或重量(克) + * 数量为正数时,库存数增加;数量为负数时,库存数减少 + */ + void incrProductStockToRedis(Map stockDeltaMap); /** - * * @param appKey * @param sign * @param folders * @return */ - ThirdApiRes fileUploadToOss(String appKey, String sign,String syncType, List folders); + ThirdApiRes fileUploadToOss(String appKey, String sign, String syncType, List folders); } diff --git a/mall-shop/src/main/java/com/suisung/mall/shop/sync/service/impl/SyncThirdDataServiceImpl.java b/mall-shop/src/main/java/com/suisung/mall/shop/sync/service/impl/SyncThirdDataServiceImpl.java index 628be020..4c72b8fe 100644 --- a/mall-shop/src/main/java/com/suisung/mall/shop/sync/service/impl/SyncThirdDataServiceImpl.java +++ b/mall-shop/src/main/java/com/suisung/mall/shop/sync/service/impl/SyncThirdDataServiceImpl.java @@ -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 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 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 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 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 sxSyncGoodsList= sxSyncGoodsService.findGoodsListPage(dataBaseInfo,i,pages); + int count = 0; + List sxSyncGoodsList = sxSyncGoodsService.findGoodsListPage(dataBaseInfo, i, pages); //todo 数据转换 - List sxGoosModelList= CvtToGoosModel(sxSyncGoodsList); - if(CollectionUtil.isEmpty(sxSyncGoodsList)){ + List 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 memberList=new ArrayList<>(); - SyncThirdMemberReq syncThirdMemberReq=null; - int syncCount =0; + List 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 sxSyncVipList= sxSyncVipService.findVipMemberPage(dataBaseInfo,i,SxDataDao.PAGESIZE); + syncThirdMemberReq = new SyncThirdMemberReq(); + List 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 list = sxSyncCategoryService.getCategoryByDataBasePage(dataBaseInfo,i,SxDataDao.PAGESIZE); + List list = sxSyncCategoryService.getCategoryByDataBasePage(dataBaseInfo, i, SxDataDao.PAGESIZE); if (CollUtil.isEmpty(list)) { continue; } - JSONArray categoryListJSON=JSONUtil.parseArray(list); + JSONArray categoryListJSON = JSONUtil.parseArray(list); List 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() - .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 folders) { SyncApp syncApp = syncAppService.getOne(new LambdaQueryWrapper() - .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 newFolders=new ArrayList<>(); - folders.forEach(page->{ - String newfolder=new FileUtils().getSyncTypeFlag(syncType,clientPath)+storeId+FileUtils.pathSeparator+page+FileUtils.pathSeparator; + List 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> futures = new ArrayList<>(); // 提交任务 - AtomicInteger success= new AtomicInteger(); - AtomicInteger fails= new AtomicInteger(); - List failFolders=new ArrayList<>(); - List failMessage=new ArrayList<>(); + AtomicInteger success = new AtomicInteger(); + AtomicInteger fails = new AtomicInteger(); + List failFolders = new ArrayList<>(); + List 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 syncFileLogs=new ArrayList<>(); + List 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 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 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 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() - .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 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() - .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 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 sme = resultMap.entrySet(); +// storeDataResultMap = sme.stream().filter(m -> !(m.getValue().equals((double) 0))).collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue)); +// } + + Map 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 getProductStockFromRedis() { + try { + // 从 Redis 获取 hash 结构的所有键值对 + Map redisHash = redisTemplate.opsForHash().entries(RedisKey.STOREDATARELEASE); + if (redisHash == null || redisHash.isEmpty()) { + return Collections.emptyMap(); + } + // 转换为 Map + 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 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 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 folders) { SyncApp syncApp = syncAppService.getOne(new LambdaQueryWrapper() - .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("上传成功"); }