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 7aa2ee0..f99ca44 100644 --- a/src/main/java/cn/van/business/controller/jd/JDInnerController.java +++ b/src/main/java/cn/van/business/controller/jd/JDInnerController.java @@ -2,50 +2,118 @@ package cn.van.business.controller.jd; import cn.van.business.util.JDProductService; import com.alibaba.fastjson2.JSONArray; +import com.alibaba.fastjson2.JSONObject; 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.RequestBody; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RestController; +import org.springframework.web.bind.annotation.*; import java.util.Map; -/** - * @author Leo - * @version 1.0 - * @create 2025/8/15 10:12 - * @description:没有权限校验,只暴露本地调用 - */ -@Controller -@RequestMapping("/jd") @RestController +@RequestMapping("/jd") @Slf4j public class JDInnerController { private static final Logger logger = LoggerFactory.getLogger(JDInnerController.class); + private static final String SKEY = "2192057370ef8140c201079969c956a3"; - private final static String skey = "2192057370ef8140c201079969c956a3"; - private boolean checkSkey(String skey) { - return skey.equals(this.skey); + private boolean checkSkey(String provided) { + return !SKEY.equals(provided); } - private JDProductService jdProductService; + + private final JDProductService jdProductService; @Autowired public JDInnerController(JDProductService jdProductService) { this.jdProductService = jdProductService; } - @RequestMapping("/generatePromotionContent") - public JSONArray generatePromotionContent(@RequestBody Map requestBody) { - String promotionContent = requestBody.get("promotionContent"); - logger.info("generatePromotionContent message:{}", promotionContent); - if (!checkSkey(skey)) { - return null; + @PostMapping("/generatePromotionContent") + public Object generatePromotionContent(@RequestBody Map requestBody) { + String skey = requestBody.get("skey") != null ? String.valueOf(requestBody.get("skey")) : null; + String promotionContent = requestBody.get("promotionContent") != null ? String.valueOf(requestBody.get("promotionContent")) : null; + logger.info("generatePromotionContent message: {}", promotionContent); + if (checkSkey(skey)) { + return error("invalid skey"); } - return jdProductService.generatePromotionContentAsJsonArray(promotionContent); + if (promotionContent == null || promotionContent.trim().isEmpty()) { + return error("promotionContent is required"); + } + JSONArray arr = jdProductService.generatePromotionContentAsJsonArray(promotionContent); + return arr; } + @PostMapping("/createGiftCoupon") + public Object createGiftCoupon(@RequestBody Map body) { + String skey = body.get("skey") != null ? String.valueOf(body.get("skey")) : null; + if (checkSkey(skey)) { + return error("invalid skey"); + } + String skuId = body.get("skuId") != null ? String.valueOf(body.get("skuId")) : null; + String materialUrl = body.get("materialUrl") != null ? String.valueOf(body.get("materialUrl")) : null; + String owner = body.get("owner") != null ? String.valueOf(body.get("owner")) : "g"; + String skuName = body.get("skuName") != null ? String.valueOf(body.get("skuName")) : ""; + double amount = parseDouble(body.get("amount"), -1); + int quantity = parseInt(body.get("quantity"), -1); + + String idOrUrl = skuId != null && !skuId.trim().isEmpty() ? skuId : materialUrl; + if (idOrUrl == null || idOrUrl.trim().isEmpty()) { + return error("skuId or materialUrl is required"); + } + if (amount <= 0 || quantity <= 0) { + return error("amount and quantity must be positive"); + } + + try { + String giftKey = jdProductService.createGiftCoupon(idOrUrl, amount, quantity, owner, skuName); + JSONObject resp = new JSONObject(); + resp.put("giftCouponKey", giftKey); + // 可选:入库/缓存 + if (giftKey != null) { + jdProductService.saveGiftCouponToRedis(idOrUrl, giftKey, skuName, owner); + } + return resp; + } catch (Exception e) { + logger.error("createGiftCoupon error", e); + return error("createGiftCoupon failed: " + e.getMessage()); + } + } + + @PostMapping("/transfer") + public Object transfer(@RequestBody Map body) { + String skey = body.get("skey") != null ? String.valueOf(body.get("skey")) : null; + if (checkSkey(skey)) { + return error("invalid skey"); + } + String materialUrl = body.get("materialUrl") != null ? String.valueOf(body.get("materialUrl")) : null; + String giftCouponKey = body.get("giftCouponKey") != null ? String.valueOf(body.get("giftCouponKey")) : null; + if (materialUrl == null || materialUrl.trim().isEmpty()) { + return error("materialUrl is required"); + } + try { + String shortUrl = jdProductService.transfer(materialUrl, giftCouponKey); + JSONObject resp = new JSONObject(); + resp.put("shortURL", shortUrl); + return resp; + } catch (Exception e) { + logger.error("transfer error", e); + return error("transfer failed: " + e.getMessage()); + } + } + + private static JSONObject error(String msg) { + JSONObject o = new JSONObject(); + o.put("error", msg); + return o; + } + + private static int parseInt(Object o, int def) { + try { return o == null ? def : Integer.parseInt(String.valueOf(o)); } catch (Exception e) { return def; } + } + + private static double parseDouble(Object o, double def) { + try { return o == null ? def : Double.parseDouble(String.valueOf(o)); } catch (Exception e) { return def; } + } } diff --git a/src/main/java/cn/van/business/util/JDProductService.java b/src/main/java/cn/van/business/util/JDProductService.java index d142d3d..df43911 100644 --- a/src/main/java/cn/van/business/util/JDProductService.java +++ b/src/main/java/cn/van/business/util/JDProductService.java @@ -7,8 +7,6 @@ import cn.van.business.repository.XbMessageRepository; import com.alibaba.fastjson2.JSON; import com.alibaba.fastjson2.JSONArray; import com.alibaba.fastjson2.JSONObject; -import java.util.regex.Matcher; -import java.util.regex.Pattern; 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; @@ -38,14 +36,10 @@ 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"; @@ -55,24 +49,18 @@ public class JDProductService { private final StringRedisTemplate redisTemplate; private final XbMessageRepository xbMessageRepository; private final XbMessageItemRepository xbMessageItemRepository; + @Autowired - public JDProductService(StringRedisTemplate redisTemplate, XbMessageRepository xbMessageRepository, XbMessageItemRepository xbMessageItemRepository) { + public JDProductService(StringRedisTemplate redisTemplate, + XbMessageRepository xbMessageRepository, + XbMessageItemRepository xbMessageItemRepository) { this.redisTemplate = redisTemplate; this.xbMessageRepository = xbMessageRepository; this.xbMessageItemRepository = xbMessageItemRepository; } - - /** - * 生成转链和方案的方法(JSON数组格式) - * - * @param message 方案内容,包含商品链接 - * @return 处理后的方案,以标准JSON数组格式返回,每个商品及其文案为一个独立对象 - */ public synchronized JSONArray generatePromotionContentAsJsonArray(String message) { JSONArray resultArray = new JSONArray(); - - // 提取方案中的所有 u.jd.com 链接 List urls = extractUJDUrls(message); if (urls.isEmpty()) { JSONObject errorObj = new JSONObject(); @@ -81,17 +69,13 @@ public class JDProductService { return resultArray; } - String format = null; DateFormat dateFormat = new SimpleDateFormat("yyyy年MM月dd日HH时mm分ss秒"); for (String url : urls) { try { - // 新建格式好日期 - format = dateFormat.format(new Date()); - - // 查询商品信息 + String format = dateFormat.format(new Date()); GoodsQueryResult productInfo = queryProductInfoByUJDUrl(url); - if (productInfo == null || productInfo.getCode() != 200) { + if (productInfo == null || productInfo.getCode() != 200 || productInfo.getData() == null || productInfo.getData().length == 0) { JSONObject errorObj = new JSONObject(); errorObj.put("url", url); errorObj.put("error", "链接查询失败"); @@ -99,20 +83,8 @@ public class JDProductService { continue; } - long totalCount = productInfo.getTotalCount(); - if (totalCount == 0) { - JSONObject errorObj = new JSONObject(); - errorObj.put("url", url); - errorObj.put("error", "未找到商品信息"); - resultArray.add(errorObj); - continue; - } - - // 创建商品对象 JSONObject productObj = new JSONObject(); productObj.put("url", url); - - // 商品基本信息 productObj.put("materialUrl", productInfo.getData()[0].getMaterialUrl()); productObj.put("oriItemId", productInfo.getData()[0].getOriItemId()); productObj.put("owner", productInfo.getData()[0].getOwner()); @@ -124,28 +96,27 @@ public class JDProductService { productObj.put("spuid", String.valueOf(productInfo.getData()[0].getSpuid())); productObj.put("commission", String.valueOf(productInfo.getData()[0].getCommissionInfo().getCommission())); productObj.put("commissionShare", String.valueOf(productInfo.getData()[0].getCommissionInfo().getCommissionShare())); - productObj.put("price", String.valueOf(productInfo.getData()[0].getPriceInfo().getPrice())); + if (productInfo.getData()[0].getPriceInfo() != null && productInfo.getData()[0].getPriceInfo().getPrice() != null) { + productObj.put("price", String.valueOf(productInfo.getData()[0].getPriceInfo().getPrice())); + } - // 图片信息 JSONArray imageArray = new JSONArray(); - if (productInfo.getData()[0].getImageInfo() != null) { + if (productInfo.getData()[0].getImageInfo() != null && + productInfo.getData()[0].getImageInfo().getImageList() != null) { for (UrlInfo image : productInfo.getData()[0].getImageInfo().getImageList()) { imageArray.add(image.getUrl()); } } productObj.put("images", imageArray); - // 文案信息 JSONArray wenanArray = new JSONArray(); - 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")) { + if (lines.length > 1 && lines[1].length() > 3 && !lines[1].contains("u.jd")) { title = title + lines[1]; } title = title.replaceAll("@|所有人", ""); @@ -155,7 +126,6 @@ public class JDProductService { log.error("文案首行异常", e); } - // 生成各种文案 JSONObject wenan1 = new JSONObject(); wenan1.put("type", "标价到手-方案1"); wenan1.put("content", "(标价到手) " + title + cleanSkuName + "\n" + WENAN_FANAN_LQD.replaceAll("更新", format + "更新")); @@ -176,14 +146,12 @@ public class JDProductService { wenan4.put("content", "【教你下单】 " + title + cleanSkuName + "\n" + WENAN_FANAN_BX.replaceAll("信息更新日期:", "信息更新日期:" + format)); wenanArray.add(wenan4); - productObj.put("wenan", wenanArray); - - // 添加通用文案 JSONObject commonWenan = new JSONObject(); commonWenan.put("type", "通用文案"); commonWenan.put("content", format + FANAN_COMMON + message); wenanArray.add(commonWenan); + productObj.put("wenan", wenanArray); resultArray.add(productObj); } catch (Exception e) { @@ -194,39 +162,19 @@ public class JDProductService { resultArray.add(errorObj); } } - return resultArray; } - /** - * 查询商品信息 - * - * @param uJDUrl 京东商品链接 - * @return 商品查询结果 - * @throws Exception 查询异常 - */ public GoodsQueryResult queryProductInfoByUJDUrl(String uJDUrl) throws Exception { UnionOpenGoodsQueryResponse response = getUnionOpenGoodsQueryRequest(uJDUrl); - if (response == null || response.getQueryResult() == null) { - return null; - } + if (response == null || response.getQueryResult() == null) return null; GoodsQueryResult queryResult = response.getQueryResult(); - if (queryResult.getCode() != 200) { - return null; - } + 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); @@ -234,56 +182,31 @@ public class JDProductService { 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; + request.setTimestamp(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date())); + return client.execute(request); } - /** - * 创建礼金 - * - * @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) { + if (skuId == null || skuId.trim().isEmpty() || amount <= 0 || quantity <= 0) { log.error("礼金创建失败:参数错误,SKU={}, 金额={}元,数量={}", skuId, amount, quantity); return null; } - - // 设置默认值 - owner = (owner != null) ? owner : "g"; + owner = (owner != null && !owner.isEmpty()) ? 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.setSkuMaterialId(skuId); couponReq.setDiscount(amount); couponReq.setAmount(quantity); - // 自营的只能设置一天,pop的只能设置7天,默认为自营 - String startTime; + String startTime = LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH")); String endTime; - if ("pop".equals(owner)) { - startTime = LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH")); + if ("pop".equalsIgnoreCase(owner)) { 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); } @@ -294,88 +217,53 @@ public class JDProductService { 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()); - + if (skuName == null) skuName = ""; + if (skuName.length() > 25) skuName = skuName.substring(0, 25); + skuName = skuName + " " + new SimpleDateFormat("yyyyMMddHHmmss").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) { + if ("0".equals(response.getCode()) && response.getGetResult() != null && response.getGetResult().getCode() == 200) { String giftKey = response.getGetResult().getData().getGiftCouponKey(); - log.debug("礼金创建成功:批次ID={}, 返回数据:{}", giftKey, response.getGetResult().getData()); + log.debug("礼金创建成功:giftKey={}", giftKey); return giftKey; - } else { - log.error("礼金创建失败:错误码={}, 错误信息={}", response.getCode(), response.getMsg()); } + log.error("礼金创建失败:code={}, msg={}", response != null ? response.getCode() : "null", response != null ? response.getMsg() : "null"); 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) { + if (giftCouponKey != null && !giftCouponKey.isEmpty()) { promotionCodeReq.setGiftCouponKey(giftCouponKey); } - request.setPromotionCodeReq(promotionCodeReq); request.setVersion("1.0"); - UnionOpenPromotionBysubunionidGetResponse response; try { - response = client.execute(request); + UnionOpenPromotionBysubunionidGetResponse response = client.execute(request); + if (response != null && "0".equals(response.getCode()) && + response.getGetResult() != null && response.getGetResult().getCode() == 200) { + return response.getGetResult().getData().getShortURL(); + } } 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; + return null; } - /** - * 将礼金信息写入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(owner.equals("g") ? 0 : 7, java.time.temporal.ChronoUnit.DAYS); + LocalDateTime expireTime = LocalDateTime.now().plus("g".equals(owner) ? 0 : 7, java.time.temporal.ChronoUnit.DAYS); Map data = new HashMap<>(); data.put("giftKey", giftKey); @@ -383,40 +271,26 @@ public class JDProductService { data.put("owner", owner); data.put("expireTime", expireTime.format(DateTimeFormatter.ISO_DATE_TIME)); - // 存入 Redis Hash redisTemplate.opsForHash().put(key, hashKey, JSON.toJSONString(data)); } - /** - * 提取商品价格信息 - * - * @param productInfo 商品查询结果 - * @return 包含价格信息的Map - */ public Map extractPriceInfo(GoodsQueryResult productInfo) { Map priceMap = new HashMap<>(); - if (productInfo == null || productInfo.getData() == null || productInfo.getData().length == 0) { priceMap.put("error", "商品信息为空"); return priceMap; } - try { - // 获取第一个商品的价格信息 var priceInfo = productInfo.getData()[0].getPriceInfo(); if (priceInfo != null) { - priceMap.put("price", priceInfo.getPrice()); // 原价 - priceMap.put("lowestPrice", priceInfo.getLowestPrice()); // 最低价 - priceMap.put("lowestCouponPrice", priceInfo.getLowestCouponPrice()); // 最低券后价 - priceMap.put("lowestPriceType", priceInfo.getLowestPriceType()); // 最低价类型 - - // 计算优惠金额 + priceMap.put("price", priceInfo.getPrice()); + priceMap.put("lowestPrice", priceInfo.getLowestPrice()); + priceMap.put("lowestCouponPrice", priceInfo.getLowestCouponPrice()); + priceMap.put("lowestPriceType", priceInfo.getLowestPriceType()); if (priceInfo.getPrice() != null && priceInfo.getLowestCouponPrice() != null) { double discount = priceInfo.getPrice() - priceInfo.getLowestCouponPrice(); - priceMap.put("discount", discount); // 优惠金额 + priceMap.put("discount", discount); } - - // 格式化价格显示 priceMap.put("priceFormatted", "¥" + (priceInfo.getPrice() != null ? priceInfo.getPrice() / 100.0 : 0)); priceMap.put("lowestPriceFormatted", "¥" + (priceInfo.getLowestPrice() != null ? priceInfo.getLowestPrice() / 100.0 : 0)); priceMap.put("lowestCouponPriceFormatted", "¥" + (priceInfo.getLowestCouponPrice() != null ? priceInfo.getLowestCouponPrice() / 100.0 : 0)); @@ -427,16 +301,9 @@ public class JDProductService { log.error("提取价格信息时发生异常", e); priceMap.put("error", "提取价格信息时发生异常: " + e.getMessage()); } - return priceMap; } - /** - * 通过商品链接提取价格信息 - * - * @param uJDUrl 京东商品链接 - * @return 包含价格信息的Map - */ public Map extractPriceInfoByUrl(String uJDUrl) { try { GoodsQueryResult productInfo = queryProductInfoByUJDUrl(uJDUrl);