Преглед на файлове

add
输注列表新增输注标识

lifang преди 2 месеца
родител
ревизия
3fdd09820e

+ 12 - 0
nb-service/web-service/src/main/java/com/nb/web/service/bus/YiXinQian/AccessTokenData.java

@@ -0,0 +1,12 @@
+package com.nb.web.service.bus.YiXinQian;
+
+import lombok.Data;
+
+/**
+ * 获取AccessToken接口的返回数据
+ */
+@Data
+public class AccessTokenData {
+    /** 访问令牌(调用业务接口的凭证) */
+    private String accessToken;
+}

+ 25 - 0
nb-service/web-service/src/main/java/com/nb/web/service/bus/YiXinQian/RespResult.java

@@ -0,0 +1,25 @@
+package com.nb.web.service.bus.YiXinQian;
+
+import lombok.Data;
+
+/**
+ * 医信签接口通用返回结果
+ * @param <T> 数据类型
+ */
+@Data
+public class RespResult<T> {
+    /** 状态码:0=成功,其他=错误(参考文档5.状态表) */
+    private String status;
+    /** 提示信息:success=成功,其他=错误描述 */
+    private String message;
+    /** 业务数据(具体接口返回的内容) */
+    private T data;
+
+    /**
+     * 判断是否请求成功
+     * @return true=成功,false=失败
+     */
+    public boolean isSuccess() {
+        return "0".equals(this.status);
+    }
+}

+ 48 - 0
nb-service/web-service/src/main/java/com/nb/web/service/bus/YiXinQian/UserInfoData.java

@@ -0,0 +1,48 @@
+package com.nb.web.service.bus.YiXinQian;
+
+import lombok.Data;
+
+/**
+ * 查询用户信息接口的返回数据(4.2.3)
+ */
+@Data
+public class UserInfoData {
+    /** 用户类型:1=机构,2=个人 */
+    private String userType;
+    /** 所属机构编号 */
+    private String orgId;
+    /** 用户编号(工号) */
+    private String userId;
+    /** 用户姓名 */
+    private String userName;
+    /** 身份证号 */
+    private String userIdcard;
+    /** 电话号码 */
+    private String userPhone;
+    /** 电子邮件 */
+    private String userEmail;
+    /** 实名认证状态:0=已认证,-1=未认证 */
+    private String realNameStatus;
+    /** 微信/企业微信OPENID */
+    private String wechatOpenId;
+    /** 证书序列号 */
+    private String certSN;
+    /** 证书主题 */
+    private String certDN;
+    /** 证书生效日期 */
+    private String certStartTime;
+    /** 证书终止日期 */
+    private String certEndTime;
+    /** 证书颁发机构 */
+    private String certIssuer;
+    /** 手写签字图片(PNG格式,Base64编码) */
+    private String signatureImg;
+    /** 科室名称 */
+    private String depName;
+    /** 是否存在有效临时授权密钥:0=不存在,1=存在 */
+    private String isAuthValid;
+    /** 用户数字证书公钥实体对象(X.509/Base64,isBackSignCert=1时返回) */
+    private String signCert;
+    /** 手写签字图片更新时间 */
+    private String imageUpdateTime;
+}

+ 36 - 0
nb-service/web-service/src/main/java/com/nb/web/service/bus/YiXinQian/UserInfoQueryParam.java

@@ -0,0 +1,36 @@
+package com.nb.web.service.bus.YiXinQian;
+
+import jodd.util.StringUtil;
+import lombok.Data;
+import javax.validation.constraints.Pattern;
+
+/**
+ * 查询用户信息接口请求参数(4.2.3)
+ */
+@Data
+public class UserInfoQueryParam {
+    /** 用户编号(三选一) */
+    private String userId;
+
+    /** 用户身份证号码(三选一) */
+    @Pattern(regexp = "^(\\d{18}|\\d{17}(\\d|X|x))$", message = "身份证号格式错误")
+    private String userIdcard;
+
+    /** 用户电话号码(三选一) */
+    @Pattern(regexp = "^1[3-9]\\d{9}$", message = "手机号格式错误")
+    private String userPhone;
+
+    /** 是否返回签名证书:0=不返回(默认),1=返回 */
+    private String isBackSignCert = "0";
+
+    /**
+     * 校验参数:userId、userIdcard、userPhone必须三选一
+     */
+    public void validate() {
+        if ((userId == null || StringUtil.isBlank(userId)) &&
+            (userIdcard == null || StringUtil.isBlank(userIdcard)) &&
+            (userPhone == null || StringUtil.isBlank(userPhone))) {
+            throw new IllegalArgumentException("userId、userIdcard、userPhone必须三选一");
+        }
+    }
+}

+ 22 - 0
nb-service/web-service/src/main/java/com/nb/web/service/bus/YiXinQian/YixinqianConfig.java

@@ -0,0 +1,22 @@
+package com.nb.web.service.bus.YiXinQian;
+
+import lombok.Data;
+import org.springframework.boot.context.properties.ConfigurationProperties;
+import org.springframework.stereotype.Component;
+
+/**
+ * 医信签配置类(读取application.yml中的yixinqian配置)
+ */
+@Data
+@Component
+@ConfigurationProperties(prefix = "yixinqian") // 前缀与yml中一致
+public class YixinqianConfig {
+    /** 医信签基础URL(测试地址) */
+    private String baseUrl;
+    /** 应用编号 */
+    private String appId;
+    /** 应用密钥 */
+    private String appKey;
+    /** AccessToken有效期(毫秒) */
+    private Long tokenExpire;
+}

+ 123 - 0
nb-service/web-service/src/main/java/com/nb/web/service/bus/YiXinQian/YixinqianService.java

@@ -0,0 +1,123 @@
+package com.nb.web.service.bus.YiXinQian;
+
+import cn.hutool.cache.Cache;
+import cn.hutool.cache.CacheUtil;
+import cn.hutool.core.util.StrUtil;
+import cn.hutool.http.HttpRequest;
+import cn.hutool.http.HttpResponse;
+import cn.hutool.http.HttpUtil;
+import cn.hutool.json.JSONUtil;
+import lombok.RequiredArgsConstructor;
+import org.springframework.stereotype.Service;
+
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * 医信签核心服务(实现4.1.1获取Token、4.2.3查询用户信息)
+ */
+@Service
+@RequiredArgsConstructor // 构造器注入配置类
+public class YixinqianService {
+    // 注入医信签配置
+    private final YixinqianConfig yixinqianConfig;
+
+    // 本地缓存:存储AccessToken(key=固定值,value=accessToken),有效期=配置的tokenExpire
+    private final Cache<String, String> accessTokenCache = CacheUtil.newTimedCache(yixinqianConfig.getTokenExpire());
+    private static final String CACHE_KEY_ACCESS_TOKEN = "YIXINQIAN_ACCESS_TOKEN";
+
+    /**
+     * 1. 获取AccessToken(4.1.1接口)
+     * 逻辑:优先从缓存取,缓存不存在/过期则调用接口获取,并更新缓存
+     * @return AccessToken
+     */
+    public String getAccessToken() {
+        // 1. 从缓存获取AccessToken
+        String accessToken = accessTokenCache.get(CACHE_KEY_ACCESS_TOKEN);
+        if (accessToken != null && !StrUtil.isBlank(accessToken)) {
+            return accessToken;
+        }
+
+        // 2. 缓存无有效Token,调用接口获取
+        String tokenUrl = yixinqianConfig.getBaseUrl() + "/api/v1.0/getAccessToken";
+        // 构造请求参数(appid、appkey)
+        Map<String, Object> tokenParam = new HashMap<>(2);
+        tokenParam.put("appid", yixinqianConfig.getAppId());
+        tokenParam.put("appkey", yixinqianConfig.getAppKey());
+
+        // 发送POST请求(JSON格式)
+        String tokenRespStr = HttpUtil.post(tokenUrl, JSONUtil.toJsonStr(tokenParam));
+        // 解析返回结果
+        RespResult<AccessTokenData> tokenResp = JSONUtil.toBean(
+                tokenRespStr,
+                new cn.hutool.core.lang.TypeReference<RespResult<AccessTokenData>>() {},
+                false
+        );
+
+        // 校验请求结果
+        if (!tokenResp.isSuccess()) {
+            throw new RuntimeException("获取AccessToken失败:" + tokenResp.getMessage() + "(状态码:" + tokenResp.getStatus() + ")");
+        }
+
+        // 3. 提取AccessToken并存入缓存
+        AccessTokenData tokenData = tokenResp.getData();
+        if (tokenData == null || tokenData.getAccessToken() == null || StrUtil.isBlank(tokenData.getAccessToken())) {
+            throw new RuntimeException("获取AccessToken失败:返回Token为空");
+        }
+        accessToken = tokenData.getAccessToken();
+        accessTokenCache.put(CACHE_KEY_ACCESS_TOKEN, accessToken); // 存入缓存(自动过期)
+
+        return accessToken;
+    }
+
+    /**
+     * 2. 查询用户信息(4.2.3接口)
+     * 逻辑:先获取AccessToken,再调用查询接口,返回用户信息
+     * @param queryParam 查询参数(三选一)
+     * @return 用户信息
+     */
+    public UserInfoData queryUserInfo(UserInfoQueryParam queryParam) {
+        // 1. 参数校验(三选一)
+        queryParam.validate();
+
+        // 2. 获取有效的AccessToken
+        String accessToken = getAccessToken();
+
+        // 3. 构造查询用户信息的URL(带accessToken参数)
+        String userInfoUrl = yixinqianConfig.getBaseUrl() + "/doctor/api/v1.0/user/info?accessToken=" + accessToken;
+
+        // 4. 发送POST请求(JSON格式,设置请求头)
+        HttpResponse userInfoResp = HttpRequest.post(userInfoUrl)
+                .header("Content-Type", "application/json") // 传参格式:JSON
+                .header("Accept", "application/json")       // 返回格式:JSON
+                .body(JSONUtil.toJsonStr(queryParam))        // 请求体(JSON字符串)
+                .execute();
+
+        // 5. 解析返回结果
+        String userInfoRespStr = userInfoResp.body();
+        RespResult<UserInfoData> userInfoResult = JSONUtil.toBean(
+                userInfoRespStr, 
+                new cn.hutool.core.lang.TypeReference<RespResult<UserInfoData>>() {},
+                false
+        );
+
+        // 6. 校验请求结果
+        if (!userInfoResult.isSuccess()) {
+            throw new RuntimeException("查询用户信息失败:" + userInfoResult.getMessage() + "(状态码:" + userInfoResult.getStatus() + ")");
+        }
+
+        // 7. 返回用户信息(data字段)
+        UserInfoData userInfoData = userInfoResult.getData();
+        if (userInfoData == null) {
+            throw new RuntimeException("查询用户信息失败:返回用户数据为空");
+        }
+        return userInfoData;
+    }
+
+    /**
+     * 手动刷新AccessToken(可选,用于测试)
+     */
+    public void refreshAccessToken() {
+        accessTokenCache.remove(CACHE_KEY_ACCESS_TOKEN);
+    }
+}