diff --git a/pom.xml b/pom.xml index ec88727..ccb1e73 100644 --- a/pom.xml +++ b/pom.xml @@ -190,6 +190,12 @@ 2.11.1 + + + commons-codec + commons-codec + 1.15 + io.springfox @@ -261,6 +267,13 @@ + + com.meituan.sdk + sdk + 1.0 + system + ${project.basedir}/src/main/resources/lib/MtOpJavaSDK-1.0-SNAPSHOT.jar + com.google.code.gson gson diff --git a/src/main/java/com/sczx/order/controller/VerifyController.java b/src/main/java/com/sczx/order/controller/VerifyController.java index 1863f30..2d29f74 100644 --- a/src/main/java/com/sczx/order/controller/VerifyController.java +++ b/src/main/java/com/sczx/order/controller/VerifyController.java @@ -33,13 +33,10 @@ public class VerifyController { @ApiOperation(value = "接收需据接口") @GetMapping("/Prepare") - public Result prepare(@RequestParam("code") String code, @RequestParam("sign") String sign, @RequestParam("developerId") Long developerId, @RequestParam("businessId") int businessId, - @RequestParam("state") String state) throws Exception { + public Result prepare(@RequestParam("code") String code) throws Exception { - log.info("接收美团授权数据 - code: {}, sign: {}, developerId: {}, businessId: {}, state: {}", - code, sign, developerId, businessId, state); - douyinService.prepare( null); + douyinService.getAccessToken( code); return null; } diff --git a/src/main/java/com/sczx/order/service/DouyinService.java b/src/main/java/com/sczx/order/service/DouyinService.java index d35ef2b..a9f5083 100644 --- a/src/main/java/com/sczx/order/service/DouyinService.java +++ b/src/main/java/com/sczx/order/service/DouyinService.java @@ -8,4 +8,6 @@ public interface DouyinService { void prepare(List orderIds) throws Exception; + + void getAccessToken(String code); } diff --git a/src/main/java/com/sczx/order/service/impl/DouyinServiceImpl.java b/src/main/java/com/sczx/order/service/impl/DouyinServiceImpl.java index dd4f90e..edd6b73 100644 --- a/src/main/java/com/sczx/order/service/impl/DouyinServiceImpl.java +++ b/src/main/java/com/sczx/order/service/impl/DouyinServiceImpl.java @@ -1,23 +1,31 @@ package com.sczx.order.service.impl; - +import com.alibaba.fastjson.JSONObject; import com.aliyun.tea.TeaException; import com.douyin.openapi.client.Client; import com.douyin.openapi.client.models.*; import com.douyin.openapi.credential.models.Config; +import com.meituan.sdk.DefaultMeituanClient; +import com.meituan.sdk.MeituanClient; +import com.meituan.sdk.auth.MeituanTokenResponse; +import com.meituan.sdk.internal.utils.SignerUtil; +import com.sczx.order.common.Result; import com.sczx.order.config.DouyinTokenManager; import com.sczx.order.exception.InnerException; import com.sczx.order.service.DouyinService; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Value; +import org.springframework.http.ResponseEntity; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import java.net.HttpURLConnection; import java.net.URL; +import java.util.HashMap; import java.util.List; +import java.util.Map; @Slf4j @Service @@ -35,10 +43,16 @@ public class DouyinServiceImpl implements DouyinService { //@Value("${douyin.poiId}") private String POI_ID = "7442188302710065206"; + private String meituanApiUrl = "https://api-open-cater.meituan.com/oauth/token"; + + private Long DeveloperId = 116997L; + + private String Signkey = "n8xihtshk7t1luvi"; + @Transactional(rollbackFor = Exception.class) @Override public String resolveShortUrlToGetObjectId(String shortUrl) { - try{ + try { URL url = new URL(shortUrl); HttpURLConnection connection = (HttpURLConnection) url.openConnection(); connection.setInstanceFollowRedirects(false); // 禁止自动重定向 @@ -60,7 +74,7 @@ public class DouyinServiceImpl implements DouyinService { } return null; - }catch (Exception e){ + } catch (Exception e) { log.error("二维码不正确"); throw new InnerException("扫码核销失败,二维码不正确"); } @@ -109,7 +123,7 @@ public class DouyinServiceImpl implements DouyinService { response.getData().getCertificates().forEach(certificate -> { Long certificateId = certificate.getCertificateId(); - String skuId =certificate.getSku().getSkuId() ; + String skuId = certificate.getSku().getSkuId(); certificate.getReserveInfo().getOrderReserveUserInfoList().forEach(orderReserveUserInfo -> { }); @@ -118,4 +132,22 @@ public class DouyinServiceImpl implements DouyinService { } + @Override + public void getAccessToken(String code) { + try { + // 使用美团SDK构建客户端 + MeituanClient client = DefaultMeituanClient.builder(DeveloperId, Signkey).build(); + + + // 使用美团SDK的getOAuthToken方法获取token + MeituanTokenResponse response = client.getOAuthToken(58, code); + + + log.info("获取access_token响应结果: {}", JSONObject.toJSONString(response)); + + + } catch (Exception e) { + log.error("获取access_token异常", e); + } + } } diff --git a/src/main/java/com/sczx/order/utils/DouyinTokenManager.java b/src/main/java/com/sczx/order/utils/DouyinTokenManager.java new file mode 100644 index 0000000..b691366 --- /dev/null +++ b/src/main/java/com/sczx/order/utils/DouyinTokenManager.java @@ -0,0 +1,107 @@ +package com.sczx.order.utils; + +import com.aliyun.tea.TeaException; +import com.douyin.openapi.client.Client; +import com.douyin.openapi.client.models.OauthClientTokenRequest; +import com.douyin.openapi.client.models.OauthClientTokenResponse; +import com.douyin.openapi.credential.models.Config; + +import java.util.concurrent.ScheduledThreadPoolExecutor; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicReference; + +/** + * 抖音 client_token 管理器 + * 负责定时获取和缓存 client_token + */ +public class DouyinTokenManager { + + // 应用凭证信息 + private static final String CLIENT_KEY = "awomt6nnjlfc491m"; + private static final String CLIENT_SECRET = "c678c411c7a68c6f97969f2dbd8ef8fc"; + + // Token 缓存 + private static final AtomicReference tokenCache = + new AtomicReference<>(); + + // 定时任务执行器 + private static final ScheduledThreadPoolExecutor scheduler = + new ScheduledThreadPoolExecutor(1, r -> { + Thread t = new Thread(r, "DouyinTokenRefreshThread"); + t.setDaemon(false); + return t; + }); + + static { + // 初始化时立即获取一次 token + refreshClientToken(); + + // 每小时更新一次 token (3600秒) + scheduler.scheduleAtFixedRate( + DouyinTokenManager::refreshClientToken, + 3600, + 3600, + TimeUnit.SECONDS + ); + } + + /** + * 获取当前有效的 client_token + * + * @return 当前有效的 access_token + */ + public static String getCurrentToken() { + OauthClientTokenResponse response = tokenCache.get(); + if (response != null && response.getData() != null) { + return response.getData().getAccessToken(); + } + return null; + } + + /** + * 刷新 client_token + */ + private static void refreshClientToken() { + try { + Config config = new Config() + .setClientKey(CLIENT_KEY) + .setClientSecret(CLIENT_SECRET); + + Client client = new Client(config); + + OauthClientTokenRequest sdkRequest = new OauthClientTokenRequest(); + sdkRequest.setClientKey(CLIENT_KEY); + sdkRequest.setClientSecret(CLIENT_SECRET); + sdkRequest.setGrantType("client_credential"); + + OauthClientTokenResponse sdkResponse = client.OauthClientToken(sdkRequest); + + // 更新缓存 + tokenCache.set(sdkResponse); + + if (sdkResponse.getData() != null) { + System.out.println("抖音 client_token 更新成功,有效期至: " + + (System.currentTimeMillis() + sdkResponse.getData().getExpiresIn() * 1000)); + } + } catch (TeaException e) { + System.err.println("获取抖音 client_token 失败 (TeaException): " + e.getMessage()); + } catch (Exception e) { + System.err.println("获取抖音 client_token 失败 (Exception): " + e.getMessage()); + } + } + + /** + * 关闭定时任务 + */ + public static void shutdown() { + scheduler.shutdown(); + + // 获取当前有效的 client_token + String token = DouyinTokenManager.getCurrentToken(); + + // 使用 token 调用抖音 API + if (token != null) { + // 调用订单查询等接口 + } + } +} diff --git a/src/main/java/com/sczx/order/utils/MeiTuanSignUtils.java b/src/main/java/com/sczx/order/utils/MeiTuanSignUtils.java new file mode 100644 index 0000000..d07b85a --- /dev/null +++ b/src/main/java/com/sczx/order/utils/MeiTuanSignUtils.java @@ -0,0 +1,86 @@ +package com.sczx.order.utils; + +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang.StringUtils; + +import java.io.UnsupportedEncodingException; +import java.security.MessageDigest; +import java.util.Map; +import java.util.Set; +import java.util.TreeSet; + +@Slf4j +public class MeiTuanSignUtils { + private MeiTuanSignUtils() {} + + public static String getSign(String signKey, Map params) { + try { + String sortedStr = getSortedParamStr(params); + String paraStr = signKey + sortedStr; + + return createSign(paraStr); + } catch (UnsupportedEncodingException e) { + log.warn("getSign UnsupportedEncodingException ", e); + } + + return StringUtils.EMPTY; + } + + /** + * 构造自然排序请求参数 + * + * @param params 请求 + * @return 字符串 + */ + private static String getSortedParamStr(Map params) throws UnsupportedEncodingException { + Set sortedParams = new TreeSet<>(params.keySet()); + + StringBuilder strB = new StringBuilder(); + // 排除sign和空值参数 + for (String key : sortedParams) { + if ("sign".equalsIgnoreCase(key)) { + continue; + } + + String value = params.get(key); + + if (StringUtils.isNotEmpty(value)) { + strB.append(key).append(value); + } + } + return strB.toString(); + } + + /** + * 生成新sign + * + * @param str 字符串 + * @return String + */ + private static String createSign(String str) { + if (str == null || str.length() == 0) { + return null; + } + char[] hexDigits = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'}; + try { + MessageDigest mdTemp = MessageDigest.getInstance("SHA1"); + mdTemp.update(str.getBytes("UTF-8")); + + byte[] md = mdTemp.digest(); + int j = md.length; + char[] buf = new char[j * 2]; + int k = 0; + int i = 0; + while (i < j) { + byte byte0 = md[i]; + buf[k++] = hexDigits[byte0 >>> 4 & 0xf]; + buf[k++] = hexDigits[byte0 & 0xf]; + i++; + } + return new String(buf); + } catch (Exception e) { + log.warn("create sign was failed", e); + return null; + } + } +} diff --git a/src/main/resources/lib/MtOpJavaSDK-1.0-SNAPSHOT.jar b/src/main/resources/lib/MtOpJavaSDK-1.0-SNAPSHOT.jar new file mode 100644 index 0000000..613edac Binary files /dev/null and b/src/main/resources/lib/MtOpJavaSDK-1.0-SNAPSHOT.jar differ