diff --git a/pjcloud-register/src/main/resources/application-qlinprod.yml b/pjcloud-register/src/main/resources/application-qlinprod.yml new file mode 100644 index 000000000..3cc63aef7 --- /dev/null +++ b/pjcloud-register/src/main/resources/application-qlinprod.yml @@ -0,0 +1,59 @@ +server: + port: 18848 + tomcat: + basedir: logs + error: + include-message: always +db: + num: 1 + user: ${MYSQL_USER:pjcloudx_config} + password: ${MYSQL_PWD:Bsd#1799} + url: + 0: jdbc:mysql://${MYSQL_HOST:pjcloud-mysql}:${MYSQL_PORT:3306}/${MYSQL_DB:pjcloudx_config}?characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=false&useJDBCCompliantTimezoneShift=true&useLegacyDatetimeCode=false&serverTimezone=GMT%2B8&nullCatalogMeansCurrent=true&allowPublicKeyRetrieval=true + pool: + config: + connectionTimeout: 30000 + validationTimeout: 10000 + +nacos: + core: + auth: + server: + identity: + key: serverIdentity + value: security + system.type: nacos + plugin.nacos.token.secret.key: SecretKey012345678901234567890123456789012345678901234567890123456789 + security: + ignore: + urls: /actuator/**,/,/error,/**/*.css,/**/*.js,/**/*.html,/**/*.map,/**/*.svg,/**/*.png,/**/*.ico,/console-fe/public/**,/v1/auth/**,/v1/console/health/**,/actuator/**,/v1/console/server/** + +spring: + datasource: + platform: mysql #这个过期属性不能修改,nacos 代码对此有硬编码 + security: + enabled: true + boot: # 接入 spring boot admin + admin: + client: + url: http://pjcloud-monitor:5001 + username: pig + password: pig + instance: + service-host-type: ip + application: + name: @project.artifactId@ + +useAddressServer: true + +management: + endpoints: + web: + exposure: + include: '*' + metrics: + export: + influx: + enabled: false + elastic: + enabled: false diff --git a/pjcloud-thirdparty/pjcloud-thirdparty-biz/src/main/java/com/bsd/pjcloud/thirdparty/shpj/ShpjApiWrapper.java b/pjcloud-thirdparty/pjcloud-thirdparty-biz/src/main/java/com/bsd/pjcloud/thirdparty/shpj/ShpjApiWrapper.java new file mode 100644 index 000000000..da80431d2 --- /dev/null +++ b/pjcloud-thirdparty/pjcloud-thirdparty-biz/src/main/java/com/bsd/pjcloud/thirdparty/shpj/ShpjApiWrapper.java @@ -0,0 +1,17 @@ +package com.bsd.pjcloud.thirdparty.shpj; + +import lombok.Data; + +@Data +public class ShpjApiWrapper { + + private int code; + + private T data; + + private String message; + + public boolean isSuccessful() { + return code == 0; + } +} diff --git a/pjcloud-thirdparty/pjcloud-thirdparty-biz/src/main/java/com/bsd/pjcloud/thirdparty/shpj/ShpjOpenapiUser.java b/pjcloud-thirdparty/pjcloud-thirdparty-biz/src/main/java/com/bsd/pjcloud/thirdparty/shpj/ShpjOpenapiUser.java new file mode 100644 index 000000000..6263ebb3c --- /dev/null +++ b/pjcloud-thirdparty/pjcloud-thirdparty-biz/src/main/java/com/bsd/pjcloud/thirdparty/shpj/ShpjOpenapiUser.java @@ -0,0 +1,42 @@ +package com.bsd.pjcloud.thirdparty.shpj; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import lombok.Data; + +/** + * 诗画浦江开放接口用户信息(对齐对方 OpenapiUser) + */ +@Data +@JsonIgnoreProperties(ignoreUnknown = true) +public class ShpjOpenapiUser { + + private int is_faceVerify; + + private String city; + + private String nickName; + + private boolean forbidden; + + private String mobile; + + private String deviceId; + + private boolean freezed; + + private String accountId; + + private int isLogin; + + private String createdAt; + + private String headImgUrl; + + private String clientCode; + + private String recentActiveTime; + + private int grade; + + private String refCode; +} diff --git a/pjcloud-thirdparty/pjcloud-thirdparty-biz/src/main/java/com/bsd/pjcloud/thirdparty/shpj/ShpjProperties.java b/pjcloud-thirdparty/pjcloud-thirdparty-biz/src/main/java/com/bsd/pjcloud/thirdparty/shpj/ShpjProperties.java new file mode 100644 index 000000000..036c9f2a8 --- /dev/null +++ b/pjcloud-thirdparty/pjcloud-thirdparty-biz/src/main/java/com/bsd/pjcloud/thirdparty/shpj/ShpjProperties.java @@ -0,0 +1,24 @@ +package com.bsd.pjcloud.thirdparty.shpj; + +import lombok.Data; +import org.springframework.boot.context.properties.ConfigurationProperties; +import org.springframework.stereotype.Component; + +/** + * 诗画浦江开放接口配置(直连 vcms,不经对方中转服务) + */ +@Data +@Component +@ConfigurationProperties(prefix = "pjcloud.shpj") +public class ShpjProperties { + + private String appKey; + + private String appSecret; + + private String connectNo; + + private String baseUrl = "https://vcms.tmuyun.com"; + + private int httpTimeoutSeconds = 5; +} diff --git a/pjcloud-thirdparty/pjcloud-thirdparty-biz/src/main/java/com/bsd/pjcloud/thirdparty/shpj/ShpjSignHelper.java b/pjcloud-thirdparty/pjcloud-thirdparty-biz/src/main/java/com/bsd/pjcloud/thirdparty/shpj/ShpjSignHelper.java new file mode 100644 index 000000000..4121e2ea1 --- /dev/null +++ b/pjcloud-thirdparty/pjcloud-thirdparty-biz/src/main/java/com/bsd/pjcloud/thirdparty/shpj/ShpjSignHelper.java @@ -0,0 +1,38 @@ +package com.bsd.pjcloud.thirdparty.shpj; + +import org.springframework.util.DigestUtils; +import org.springframework.util.StringUtils; + +import java.nio.charset.StandardCharsets; +import java.util.Arrays; +import java.util.Map; +import java.util.SortedMap; +import java.util.TreeMap; + +/** + * 诗画浦江签名:timestamp&&appkey&&appsecret&&noncestr&¶mValues + */ +public final class ShpjSignHelper { + + private ShpjSignHelper() { + } + + public static String sign(Map businessParams, String timestamp, String appKey, String appSecret, String nonce) { + String raw = String.format("%s&&%s&&%s&&%s", timestamp, appKey, appSecret, nonce) + extraSign(businessParams); + return DigestUtils.md5DigestAsHex(raw.getBytes(StandardCharsets.UTF_8)); + } + + private static String extraSign(Map paramsMap) { + SortedMap resMap = new TreeMap<>(paramsMap); + String[] keys = resMap.keySet().toArray(new String[0]); + Arrays.sort(keys); + StringBuilder paramBuffer = new StringBuilder(); + for (String key : keys) { + String value = resMap.get(key); + if (StringUtils.hasLength(value) && !"0".equals(value)) { + paramBuffer.append("&&").append(value); + } + } + return paramBuffer.toString(); + } +} diff --git a/pjcloud-thirdparty/pjcloud-thirdparty-biz/src/main/java/com/bsd/pjcloud/thirdparty/shpj/ShpjUserClient.java b/pjcloud-thirdparty/pjcloud-thirdparty-biz/src/main/java/com/bsd/pjcloud/thirdparty/shpj/ShpjUserClient.java new file mode 100644 index 000000000..fcf7aa955 --- /dev/null +++ b/pjcloud-thirdparty/pjcloud-thirdparty-biz/src/main/java/com/bsd/pjcloud/thirdparty/shpj/ShpjUserClient.java @@ -0,0 +1,85 @@ +package com.bsd.pjcloud.thirdparty.shpj; + +import cn.hutool.http.HttpRequest; +import cn.hutool.http.HttpResponse; +import com.bsd.pjcloud.thirdparty.exception.ThirdPartyException; +import com.fasterxml.jackson.databind.ObjectMapper; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Component; +import org.springframework.util.StringUtils; + +import java.util.HashMap; +import java.util.Map; + +/** + * 诗画浦江用户开放接口客户端(直连) + */ +@Slf4j +@Component +@RequiredArgsConstructor +public class ShpjUserClient { + + private final ShpjProperties properties; + + private final ObjectMapper objectMapper; + + /** + * 按 accountId + sessionId 查询诗画用户详情 + */ + public ShpjOpenapiUser getUserInfo(String accountId, String sessionId) { + if (!StringUtils.hasText(accountId) || "-1".equals(accountId)) { + throw new ThirdPartyException("请先登录诗画客户端", "SHPJ_NOT_LOGIN"); + } + if (!StringUtils.hasText(sessionId)) { + throw new ThirdPartyException("sessionId不能为空", "SHPJ_SESSION_EMPTY"); + } + if (!StringUtils.hasText(properties.getAppKey()) || !StringUtils.hasText(properties.getAppSecret()) + || !StringUtils.hasText(properties.getConnectNo())) { + throw new ThirdPartyException("诗画浦江开放接口未配置", "SHPJ_CFG"); + } + + String timestamp = String.valueOf(System.currentTimeMillis()); + String nonce = timestamp + "shpj"; + + Map businessParams = new HashMap<>(2); + businessParams.put("sessionId", sessionId); + businessParams.put("connectNo", properties.getConnectNo()); + + Map form = new HashMap<>(); + form.put("appkey", properties.getAppKey()); + form.put("noncestr", nonce); + form.put("timestamp", timestamp); + form.put("signature", ShpjSignHelper.sign(businessParams, timestamp, properties.getAppKey(), properties.getAppSecret(), nonce)); + form.putAll(businessParams); + + String apiUrl = "/openapi/v2/" + accountId + "/detail"; + String fullUrl = properties.getBaseUrl() + apiUrl; + log.info("调用诗画浦江接口[{}]开始, accountId={}, sessionId={}", apiUrl, accountId, sessionId); + + try (HttpResponse httpResponse = HttpRequest.get(fullUrl) + .timeout(properties.getHttpTimeoutSeconds() * 1000) + .form(form) + .execute()) { + String body = httpResponse.body(); + if (!httpResponse.isOk()) { + log.error("诗画浦江接口[{}]HTTP错误:{} - {}", apiUrl, httpResponse.getStatus(), body); + throw new ThirdPartyException("诗画浦江接口调用失败", "SHPJ_HTTP"); + } + log.info("诗画浦江接口[{}]完成, 返回:{}", apiUrl, body); + + ShpjApiWrapper resp = objectMapper.readValue(body, + objectMapper.getTypeFactory().constructParametricType(ShpjApiWrapper.class, ShpjOpenapiUser.class)); + if (!resp.isSuccessful()) { + log.error("诗画浦江接口[{}]业务失败: [{}-{}]", apiUrl, resp.getCode(), resp.getMessage()); + throw new ThirdPartyException("诗画浦江接口调用失败:" + resp.getMessage(), "SHPJ_BIZ_" + resp.getCode()); + } + return resp.getData(); + } catch (ThirdPartyException e) { + throw e; + } catch (Exception e) { + log.error("诗画浦江接口[{}]异常", apiUrl, e); + throw new ThirdPartyException("诗画浦江服务暂时不可用", "SHPJ_ERROR"); + } + } +}