From 37fc0697b34134d241e8545ae882f560cb426aaa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=9B=B7=E6=AC=A7=EF=BC=88=E6=9E=97=E5=B9=B3=E5=87=A1?= =?UTF-8?q?=EF=BC=89?= Date: Fri, 15 Aug 2025 14:53:32 +0800 Subject: [PATCH] 1 --- .../controller/jd/JDInnerController.java | 11 +- .../van/business/util/JDProductService.java | 408 ++++++++++++++++++ 2 files changed, 418 insertions(+), 1 deletion(-) create mode 100644 src/main/java/cn/van/business/util/JDProductService.java diff --git a/src/main/java/cn/van/business/controller/jd/JDInnerController.java b/src/main/java/cn/van/business/controller/jd/JDInnerController.java index f7155cc..0ea853a 100644 --- a/src/main/java/cn/van/business/controller/jd/JDInnerController.java +++ b/src/main/java/cn/van/business/controller/jd/JDInnerController.java @@ -1,7 +1,11 @@ package cn.van.business.controller.jd; +import cn.van.business.controller.wx.WXListener; import cn.van.business.util.JDProductService; import cn.van.business.util.JDUtil; +import lombok.extern.slf4j.Slf4j; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.RequestMapping; @@ -19,7 +23,11 @@ import java.util.List; @Controller @RequestMapping("/jd") @RestController +@Slf4j public class JDInnerController { + private static final Logger logger = LoggerFactory.getLogger(JDInnerController.class); + + private final static String skey = "2192057370ef8140c201079969c956a3"; private boolean checkSkey(String skey) { return skey.equals(this.skey); @@ -32,7 +40,8 @@ public class JDInnerController { } @RequestMapping("/generatePromotionContent") - public HashMap> generatePromotionContent(String message) { + public HashMap> generatePromotionContent(String message,String skey) { + loo if (!checkSkey(skey)) { return null; } diff --git a/src/main/java/cn/van/business/util/JDProductService.java b/src/main/java/cn/van/business/util/JDProductService.java new file mode 100644 index 0000000..215af6b --- /dev/null +++ b/src/main/java/cn/van/business/util/JDProductService.java @@ -0,0 +1,408 @@ +package cn.van.business.util; + +import cn.van.business.model.cj.XbMessage; +import cn.van.business.model.cj.XbMessageItem; +import cn.van.business.repository.XbMessageItemRepository; +import cn.van.business.repository.XbMessageRepository; +import com.alibaba.fastjson2.JSON; +import com.alibaba.fastjson2.JSONObject; +import com.jd.open.api.sdk.DefaultJdClient; +import com.jd.open.api.sdk.JdClient; +import com.jd.open.api.sdk.domain.kplunion.CouponService.request.get.CreateGiftCouponReq; +import com.jd.open.api.sdk.domain.kplunion.GoodsService.request.query.GoodsReq; +import com.jd.open.api.sdk.domain.kplunion.GoodsService.response.query.GoodsQueryResult; +import com.jd.open.api.sdk.domain.kplunion.GoodsService.response.query.UrlInfo; +import com.jd.open.api.sdk.domain.kplunion.promotionbysubunioni.PromotionService.request.get.PromotionCodeReq; +import com.jd.open.api.sdk.request.kplunion.UnionOpenCouponGiftGetRequest; +import com.jd.open.api.sdk.request.kplunion.UnionOpenGoodsQueryRequest; +import com.jd.open.api.sdk.request.kplunion.UnionOpenPromotionBysubunionidGetRequest; +import com.jd.open.api.sdk.response.kplunion.UnionOpenCouponGiftGetResponse; +import com.jd.open.api.sdk.response.kplunion.UnionOpenGoodsQueryResponse; +import com.jd.open.api.sdk.response.kplunion.UnionOpenPromotionBysubunionidGetResponse; +import lombok.extern.slf4j.Slf4j; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.data.redis.core.StringRedisTemplate; +import org.springframework.stereotype.Service; + +import java.text.DateFormat; +import java.text.SimpleDateFormat; +import java.time.LocalDateTime; +import java.time.format.DateTimeFormatter; +import java.util.*; +import java.util.concurrent.TimeUnit; + +import static cn.van.business.util.JDUtil.*; + +/** + * 京东商品服务类,抽取来源于JDUtil + */ +@Service +@Slf4j +public class JDProductService { + + // 京东开放平台配置 + private static final String LPF_APP_KEY_WZ = "98e21c89ae5610240ec3f5f575f86a59"; + private static final String LPF_SECRET_KEY_WZ = "3dcb6b23a1104639ac433fd07adb6dfb"; + private static final String SERVER_URL = "https://api.jd.com/routerjson"; + private static final String ACCESS_TOKEN = ""; + private static final Logger logger = LoggerFactory.getLogger(JDProductService.class); + + private final StringRedisTemplate redisTemplate; + private final XbMessageRepository xbMessageRepository; + private final XbMessageItemRepository xbMessageItemRepository; + @Autowired + public JDProductService(StringRedisTemplate redisTemplate, XbMessageRepository xbMessageRepository, XbMessageItemRepository xbMessageItemRepository) { + this.redisTemplate = redisTemplate; + this.xbMessageRepository = xbMessageRepository; + this.xbMessageItemRepository = xbMessageItemRepository; + } + /** + * 生成转链和方案的方法 + * + * @param message 方案内容,包含商品链接 + * @param fromWxid + * @return 处理后的方案,附带商品信息 + */ + public synchronized HashMap> generatePromotionContent(String message) { + HashMap> finallyMessage = new HashMap<>(); + List textList = new ArrayList<>(); + List imagesList = new ArrayList<>(); + List dataList = new ArrayList<>(); + // 最终的方案 + List finalWenAn = new ArrayList<>(); + // 提取方案中的所有 u.jd.com 链接 + List urlList = new ArrayList<>(); + List priceList = new ArrayList<>(); + + // 提取方案中的所有 u.jd.com 链接 + List urls = extractUJDUrls(message); + if (urls.isEmpty()) { + textList.add("方案中未找到有效的商品链接,请检查格式是否正确。"); + finallyMessage.put("text", textList); + return finallyMessage; + } + + + // 如果需要图片和SKU名称,则代表要把图片下载发过去,还有对应的skuName + StringBuilder couponInfo = null; + ArrayList> resultList = new ArrayList<>(); + + String format = null; + DateFormat dateFormat = new SimpleDateFormat("yyyy年MM月dd日HH时mm分ss秒"); + + for (String url : urls) { + try { + // 重置。不然会一直追加文本内容 + couponInfo = new StringBuilder(); + // 新建格式好日期 + format = dateFormat.format(new Date()); + // 查询商品信息 + GoodsQueryResult productInfo = queryProductInfoByUJDUrl(url); + if (productInfo == null || productInfo.getCode() != 200) { + couponInfo.append("链接查询失败:").append(url).append("\n"); + continue; + } + long totalCount = productInfo.getTotalCount(); + if (totalCount == 0) { + //couponInfo.append("链接类型:优惠券\n\n"); + } else { + couponInfo.append(url).append("\n"); + urlList.add(url); + couponInfo.append("链接类型:商品\n\n"); + JSONObject jsonObject = JSONObject.parseObject(JSONObject.toJSONString(productInfo.getData()[0])); + jsonObject.put("url", url); + dataList.add(jsonObject.toString()); + + HashMap itemMap = new HashMap<>(); + itemMap.put("url", url); + itemMap.put("materialUrl", productInfo.getData()[0].getMaterialUrl()); + itemMap.put("oriItemId", productInfo.getData()[0].getOriItemId()); + itemMap.put("owner", productInfo.getData()[0].getOwner()); + itemMap.put("shopId", String.valueOf(productInfo.getData()[0].getShopInfo().getShopId())); + itemMap.put("shopName", productInfo.getData()[0].getShopInfo().getShopName()); + itemMap.put("skuName", productInfo.getData()[0].getSkuName()); + String replaceAll = itemMap.get("skuName").replaceAll("以旧|政府|换新|领取|国家|补贴|15%|20%|国补|立减|【|】", ""); + itemMap.put("spuid", String.valueOf(productInfo.getData()[0].getSpuid())); + itemMap.put("commission", String.valueOf(productInfo.getData()[0].getCommissionInfo().getCommission())); + itemMap.put("commissionShare", String.valueOf(productInfo.getData()[0].getCommissionInfo().getCommissionShare())); + //for (HashMap.Entry entry : itemMap.entrySet()) { + //couponInfo.append(" ").append(entry.getKey()).append(": ").append(entry.getValue()).append("\n"); + //} + couponInfo.append("店铺: ").append(itemMap.get("shopName")).append("\n").append("标题: ").append(replaceAll).append("\n").append("自营 POP: ").append(itemMap.get("owner").equals("g") ? " 自营 " : " POP ").append("\n").append("佣金比例: ").append(itemMap.get("commissionShare")).append("\n").append("佣金: ").append(itemMap.get("commission")).append("\n"); + + + //StringBuilder images = new StringBuilder(); + if (productInfo.getData()[0].getImageInfo() != null) { + //images.append(" ").append("图片信息:\n"); + //int index = 1; + + for (UrlInfo image : productInfo.getData()[0].getImageInfo().getImageList()) { + //images.append("图片 ").append(index++).append("\n").append(image.getUrl()).append("\n"); + imagesList.add(image.getUrl()); + } + } + //textList.add(String.valueOf(images)); + resultList.add(itemMap); + String title = ""; + + + try { + if (!message.equals(url)) { + String[] lines = message.split("\\r?\\n"); + if (lines.length > 0) { + title = lines[0]; + // 有的换行了 + if (lines[1].length() > 3 && !lines[1].contains("u.jd")) { + title = title + lines[1]; + } + logger.info("文案首行 {}", title); + title = title.replaceAll("@|所有人", ""); + } + } + + } catch (Exception e) { + logger.error("文案首行异常", e); + } + + + + /*直接生成闲鱼的商品文案*/ + StringBuilder sb1 = new StringBuilder(); + + sb1.append("(标价到手) ").append(title).append(replaceAll).append("\n").append(WENAN_FANAN_LQD.replaceAll("更新", format + "更新")); + //textList.add("闲鱼方案的文案:\n"); + textList.add(String.valueOf(sb1)); + StringBuilder sb2 = new StringBuilder(); + sb2.append("(一键代下) ").append(title).append(replaceAll).append("\n").append(WENAN_ZCXS); + //textList.add("闲鱼正常销售:\n"); + textList.add(String.valueOf(sb2)); + StringBuilder sb3 = new StringBuilder(); + sb3.append("(标价到手) ").append(title).append(replaceAll).append("\n").append(WENAN_FANAN_HG.replaceAll("更新", format + "更新")); + textList.add(String.valueOf(sb3)); + + StringBuilder sb4 = new StringBuilder(); + sb4.append("【教你下单】 ").append(title).append(replaceAll).append("\n").append(WENAN_FANAN_BX.replaceAll("信息更新日期:", "信息更新日期:" + format)); + textList.add(String.valueOf(sb4)); + } + + + textList.add(String.valueOf(couponInfo)); + finallyMessage.put("data", dataList); + finallyMessage.put("urlList", urlList); + + } catch (Exception e) { + logger.error("处理商品链接时发生异常:{}", url, e); + couponInfo.append(" 处理商品链接时发生异常:").append(url).append("\n"); + textList.add(String.valueOf(couponInfo)); + finallyMessage.put("text", textList); + } + } + /** + * 因为在这里转链返回,没有什么意义,后面走转链不转链,会重新发方案 + * */ + StringBuilder wenan = new StringBuilder(); + + wenan = new StringBuilder().append(format).append(FANAN_COMMON).append(message); + + + finalWenAn.add(String.valueOf(wenan)); + + finallyMessage.put("text", textList); + finallyMessage.put("images", imagesList); + finallyMessage.put("finalWenAn", finalWenAn); + + return finallyMessage; + + } + + /** + * 查询商品信息 + * + * @param uJDUrl 京东商品链接 + * @return 商品查询结果 + * @throws Exception 查询异常 + */ + public GoodsQueryResult queryProductInfoByUJDUrl(String uJDUrl) throws Exception { + UnionOpenGoodsQueryResponse response = getUnionOpenGoodsQueryRequest(uJDUrl); + if (response == null || response.getQueryResult() == null) { + return null; + } + GoodsQueryResult queryResult = response.getQueryResult(); + if (queryResult.getCode() != 200) { + return null; + } + return queryResult; + } + + /** + * 调用京东开放平台接口查询商品信息 + * + * @param uJDUrl 京东商品链接 + * @return 京东商品查询响应 + * @throws Exception 查询异常 + */ + public UnionOpenGoodsQueryResponse getUnionOpenGoodsQueryRequest(String uJDUrl) throws Exception { + JdClient client = new DefaultJdClient(SERVER_URL, ACCESS_TOKEN, LPF_APP_KEY_WZ, LPF_SECRET_KEY_WZ); + + UnionOpenGoodsQueryRequest request = new UnionOpenGoodsQueryRequest(); + GoodsReq goodsReq = new GoodsReq(); + goodsReq.setKeyword(uJDUrl); + goodsReq.setSceneId(1); + request.setGoodsReqDTO(goodsReq); + request.setVersion("1.0"); + request.setSignmethod("md5"); + + // 时间戳,格式为yyyy-MM-dd HH:mm:ss,时区为GMT+8 + Date date = new Date(); + SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); + request.setTimestamp(simpleDateFormat.format(date)); + + UnionOpenGoodsQueryResponse execute = client.execute(request); + return execute; + } + + /** + * 创建礼金 + * + * @param skuId 商品SKU ID + * @param amount 礼金金额 + * @param quantity 礼金数量 + * @param owner 商品所有者(g:自营, pop:POP商家) + * @param skuName 商品名称 + * @return 礼金Key + * @throws Exception 创建异常 + */ + public String createGiftCoupon(String skuId, double amount, int quantity, String owner, String skuName) throws Exception { + log.debug("准备创建礼金:SKU={}, 金额={}元,数量={}, Owner={}", skuId, amount, quantity, owner); + + // 参数校验 + if (skuId == null || amount <= 0 || quantity <= 0) { + log.error("礼金创建失败:参数错误,SKU={}, 金额={}元,数量={}", skuId, amount, quantity); + return null; + } + + // 设置默认值 + owner = (owner != null) ? owner : "g"; + + JdClient client = new DefaultJdClient(SERVER_URL, ACCESS_TOKEN, LPF_APP_KEY_WZ, LPF_SECRET_KEY_WZ); + + UnionOpenCouponGiftGetRequest request = new UnionOpenCouponGiftGetRequest(); + CreateGiftCouponReq couponReq = new CreateGiftCouponReq(); + couponReq.setSkuMaterialId(skuId); // 使用SKU或链接 + couponReq.setDiscount(amount); + couponReq.setAmount(quantity); + + // 自营的只能设置一天,pop的只能设置7天,默认为自营 + String startTime; + String endTime; + if ("pop".equals(owner)) { + startTime = LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH")); + endTime = LocalDateTime.now().plusDays(6).format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH")); + couponReq.setEffectiveDays(7); + } else { + startTime = LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH")); + endTime = LocalDateTime.now().plusDays(1).format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH")); + couponReq.setEffectiveDays(1); + } + + couponReq.setReceiveStartTime(startTime); + couponReq.setReceiveEndTime(endTime); + couponReq.setIsSpu(1); + couponReq.setExpireType(1); + couponReq.setShare(-1); + + if (skuName.length() >= 25) { + skuName = skuName.substring(0, 25); + } + + // 新建格式日期 + DateFormat dateFormat = new SimpleDateFormat("yyyyMMddHHmmss"); + skuName = skuName + " " + dateFormat.format(new Date()); + + couponReq.setCouponTitle(skuName); + couponReq.setContentMatch(1); + + request.setCouponReq(couponReq); + request.setVersion("1.0"); + + log.debug("请求参数:{}", JSON.toJSONString(request)); + + UnionOpenCouponGiftGetResponse response = client.execute(request); + log.debug("API响应:{}", JSON.toJSONString(response)); + + if ("0".equals(response.getCode()) && response.getGetResult().getCode() == 200) { + String giftKey = response.getGetResult().getData().getGiftCouponKey(); + log.debug("礼金创建成功:批次ID={}, 返回数据:{}", giftKey, response.getGetResult().getData()); + return giftKey; + } else { + log.error("礼金创建失败:错误码={}, 错误信息={}", response.getCode(), response.getMsg()); + } + return null; + } + + /** + * 转链接口:通过商品链接、领券链接、活动链接获取普通推广链接或优惠券二合一推广链接 + * + * @param url 原始链接 + * @param giftCouponKey 礼金Key(可选) + * @return 转换后的短链接 + */ + public String transfer(String url, String giftCouponKey) { + JdClient client = new DefaultJdClient(SERVER_URL, ACCESS_TOKEN, LPF_APP_KEY_WZ, LPF_SECRET_KEY_WZ); + + UnionOpenPromotionBysubunionidGetRequest request = new UnionOpenPromotionBysubunionidGetRequest(); + PromotionCodeReq promotionCodeReq = new PromotionCodeReq(); + promotionCodeReq.setSceneId(1); + promotionCodeReq.setMaterialId(url); + + if (giftCouponKey != null) { + promotionCodeReq.setGiftCouponKey(giftCouponKey); + } + + request.setPromotionCodeReq(promotionCodeReq); + request.setVersion("1.0"); + + UnionOpenPromotionBysubunionidGetResponse response; + try { + response = client.execute(request); + } catch (Exception e) { + throw new RuntimeException(e); + } + + String result = ""; + if (response != null) { + if ("0".equals(response.getCode()) && response.getGetResult().getCode() == 200) { + result = response.getGetResult().getData().getShortURL(); + } + } else { + result = null; + } + + return result; + } + + /** + * 将礼金信息写入Redis + * + * @param skuId 商品SKU ID + * @param giftKey 礼金Key + * @param skuName 商品名称 + * @param owner 商品所有者 + */ + public void saveGiftCouponToRedis(String skuId, String giftKey, String skuName, String owner) { + String key = "gift_coupon:" + skuId; + String hashKey = giftKey; + LocalDateTime expireTime = LocalDateTime.now().plus("g".equals(owner) ? 1 : 7, TimeUnit.DAYS.toChronoUnit()); + + Map data = new HashMap<>(); + data.put("giftKey", giftKey); + data.put("skuName", skuName); + data.put("owner", owner); + data.put("expireTime", expireTime.format(DateTimeFormatter.ISO_DATE_TIME)); + + // 存入 Redis Hash + redisTemplate.opsForHash().put(key, hashKey, JSON.toJSONString(data)); + } +}