Ver código fonte

Merge branch 'master' of http://gogs.ywtinfo.com/guochengfeng/alipay-mp-service

wuyongyi 2 anos atrás
pai
commit
10bcb81b80

+ 5 - 6
onemini-hospital-empty/src/main/java/com/ywt/alipaympapi/EmptyApplication.java

@@ -2,6 +2,7 @@ package com.ywt.alipaympapi;
 
 import com.alipay.easysdk.factory.Factory;
 import com.alipay.easysdk.kernel.Config;
+import com.ywt.alipaympapi.models.Constants;
 import com.ywt.rpc.core.RestServerStarter;
 import org.springframework.boot.SpringApplication;
 import org.springframework.boot.autoconfigure.SpringBootApplication;
@@ -21,7 +22,7 @@ public class EmptyApplication {
 
     /**
      * 初始化 alipay-easy-sdk
-     * 后续开通多医院需要做动态读取配置处理
+     * FIXME: 后续扩展多医院需要将 pk & apk 配置化
      */
     private static void initAlipayEasySdk() {
         Config config = new Config();
@@ -29,13 +30,11 @@ public class EmptyApplication {
         config.gatewayHost = "openapi.alipay.com";
         config.signType = "RSA2";
 
-        config.appId = "2021003141662056";
+        config.appId = Constants.ALIPAYMP_APPID_NFYYBYFY;
         // 为避免私钥随源码泄露,推荐从文件中读取私钥字符串而不是写入源码中
-        config.merchantPrivateKey = "MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQDTrydAgG5HUwvoYE6L4WFlgIhX2fKPEFvlpDyCremBPk5Zp3OMpoj3cfcd36Im/0MndQII90hErcRqfUEPJhw+F2CSBpxkLTb/7J1iRyUiKjv5G+24qG4FQIo/yc0o7xQsNLJR7McbS3ROuuPg1jN5qL8XKCPxCHEL5QzzJCVp+Jz+GKeGYPPmPdALC1nxgOKjYjpJrwOGtaU+7WuaB9SVz98xU3FocLFDTqE0MCQySOxxB0CZgBEPahp2l2B6FcMBoRok2p1ODIlN1ihfEEIrAU9rmso7swxEo65oaCuZu/bkH1FvmcayjMJ0xBir8pBh96tKt8loU++LY9y1rq6tAgMBAAECggEAAqvUJ/k26wl+PflxJEy8yOYdUlZ6vBltv3EaHmAJcUsS/Aij6aN0WQMEJklbJ3jTJR1R4EEWlV9H+jwIZSOK+bGb01vn/0+ewQ4AUmwpaMv1o8gZcNoXQVO2KuXmA904ePJVSbleLdb+6btsArtRPPjHKIimI3WCz66dQjgzjKnDloaaDIrx6bi3J0GOxzRGfMTMTuqhr6cm1OWCgSIFK+jTj61o7eIx1ZYY3OorApS9Q5CF3OHAXn6ignBxdvuyzDfA9VNMihrnuDcWy674mMOciu6TYx4Y0nwpFedKU29uR5Scgr0DGQFeLBSZmyd5kblDTu/CF5sFK5kr7H2pYQKBgQD3guHqAeObnItkmLdJfOkdfcoSmS5UZeyyyaJitjCbUGydJPUA8RipYKCM4rhRQYZvyIWwo52BahhzwGrp+3gdQWOQ6SRVXZXQVwsvWfkWaVkgRxeM0GASsFAnSjoHEEfRNifWRPcCSzSrvr0W+X7Wjc9XSiafOaKPuJeyTrVHiQKBgQDa8ba3l1/L2q6+al6UFsgn4WeIDHVaiDnIp1W+tT7UYPBEraedke1SjjGACfOrFfvNW35Vo6nV1olekB0D1AB2alLXN0x0swjit2TRKHOj8eH5uzplcktBNygDicnG09JW5RnQL21D7xf01L5b2lv52DvR7anrikkf3TdrNAbBBQKBgESm9wazU3CcMUXL3jrx/K8DbwNNnb4nL0pAB1yd8EmEOzwzPgnu1cpVVPL/B+Tx6dojooFmQI/e371rh7wy1hQ3SOiu4jcTaDSLkDyoFiETQ3digLO8MIm+gd0EB6hh6amr/cy/AEyQk6F3nHc86OOWHga2OJQ9pkt7BgidMEcRAoGBAKE9MVqzWBFA0z/YBh75SB5WmXBP/HzXpfZnhXYU9Fhjq45odPBN74DExx+MNK7iWbY6kyduiDy66h+B8lxHXK/YTXnBd8TZtMmCVfTS3Zb3I3xOrgrXySQWApnYd4i9pkHoJsJyqv1Er1fW9PmgLewpmqRXarPT+1ZEC/QfNHohAoGBAOpKX5QeQfk3x9ae6Wtvuw5hdF0aPaWpimPAFion5jqINoJc13gMo1YhU2eUMwvw8kkB/edvAp12EFRb7Esza4ZXc7uDWnYMPh8Wx8iHBEKxpUneNADmxpo2LXO+AXE4ZgIojeUSYPAGSHb16uG15lxamLqlLIJ44FR+1F86jk4L";
+        config.merchantPrivateKey = Constants.MERCHANT_PRIVATE_KEY;
         // 注:如果采用非证书模式,则无需赋值上面的三个证书路径,改为赋值如下的支付宝公钥字符串即可
-        config.alipayPublicKey = "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAtUtjYn+V60um6GVF0ezsI4NCI8QAiM8BT7SQda3RDzIssPbU5U3GJo/5bbu+k+pOpCOUlGVve2VoO+AXMWizCA8U/RleN7fNE09yw7RdLfLssNp6J4zGfBHQBWMiTrJvGZ4LzZHiwJgf28CGwcovjAK6M8bjF30k5ChQ8YIi+YYuer8yae7XfORLiSTByakglURlVUZF7QgbLph9i/OBk83HribZh+B/n97vavrAUyTjbDE3TMsINsAfMSY1omweXuvqjndYI+XmiBM4nBPHlPsXEeaF9TE8LuIqWm5mnRKWa/0I31RkE+W19tFUx5mF3oHw6SvyVuUQVx0HWGIPKQIDAQAB";
-        // 可设置异步通知接收服务地址(可选)
-        config.notifyUrl = "https://pay-qa.ywtinfo.com";
+        config.alipayPublicKey = Constants.ALIPAY_PUBLIC_KEY;
         Factory.setOptions(config);
     }
 }

+ 12 - 0
onemini-hospital-empty/src/main/java/com/ywt/alipaympapi/core/utils/BizUtil.java

@@ -146,6 +146,18 @@ public final class BizUtil {
         }
     }
 
+    /**
+     * 根据医院 id 获取对应支付宝小程序终端号
+     */
+    public static int getAlipayMpTerminalIdByHospitalId(int hospitalId) {
+        switch (hospitalId) {
+            case Constants.HOSPITAL_ID_NFYYBYFY:
+                return TerminalEnum.NFYYBYFY_ALIPAY_MP.getValue();
+            default:
+                return TerminalEnum.UNKNOWN.getValue();
+        }
+    }
+
     public static int getCurrentTerminalWrapped() {
 //        return TerminalEnum.NFYYBYFY_WXAPP.getValue();
 //        return TerminalEnum.TaiheWxOfficial.getValue();

+ 10 - 2
onemini-hospital-empty/src/main/java/com/ywt/alipaympapi/face/impl/AlipayService.java

@@ -5,6 +5,7 @@ import com.alipay.api.AlipayRequest;
 import com.alipay.api.AlipayResponse;
 import com.alipay.api.DefaultAlipayClient;
 import com.ywt.alipaympapi.face.IAlipayService;
+import com.ywt.alipaympapi.models.Constants;
 import lombok.extern.slf4j.Slf4j;
 import org.springframework.stereotype.Component;
 
@@ -47,8 +48,15 @@ public class AlipayService implements IAlipayService {
         }
     }
 
-    private AlipayClient getAlipayClient(String appId) {
+    /**
+     * 构造 AlipayClient,调用 AlipaySDK。有些业务场景(如“智能”消息)下用 EasySDK 调不通,只能使用普通 SDK
+     * @param appId 小程序 appId
+     * FIXME: 后续扩展多医院需要将 pk & apk 配置化
+     */
+    public AlipayClient getAlipayClient(String appId) {
+        String pk = Constants.MERCHANT_PRIVATE_KEY;
+        String apk = Constants.ALIPAY_PUBLIC_KEY;
         //实例化客户端
-        return new DefaultAlipayClient("https://openapi.alipay.com/gateway.do", "", "", "json", "UTF-8", "", "RSA2");
+        return new DefaultAlipayClient("https://openapi.alipay.com/gateway.do", appId, pk, "json", "UTF-8", apk, "RSA2");
     }
 }

+ 5 - 0
onemini-hospital-empty/src/main/java/com/ywt/alipaympapi/models/Constants.java

@@ -13,9 +13,14 @@ public class Constants {
     public static final int TAIHE_HOSPITAL_ID = 12;
 
     public static final String ALIPAYMP_APPID_NFYYBYFY = "2021003141662056";
+    public static final String MERCHANT_PRIVATE_KEY = "MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQDTrydAgG5HUwvoYE6L4WFlgIhX2fKPEFvlpDyCremBPk5Zp3OMpoj3cfcd36Im/0MndQII90hErcRqfUEPJhw+F2CSBpxkLTb/7J1iRyUiKjv5G+24qG4FQIo/yc0o7xQsNLJR7McbS3ROuuPg1jN5qL8XKCPxCHEL5QzzJCVp+Jz+GKeGYPPmPdALC1nxgOKjYjpJrwOGtaU+7WuaB9SVz98xU3FocLFDTqE0MCQySOxxB0CZgBEPahp2l2B6FcMBoRok2p1ODIlN1ihfEEIrAU9rmso7swxEo65oaCuZu/bkH1FvmcayjMJ0xBir8pBh96tKt8loU++LY9y1rq6tAgMBAAECggEAAqvUJ/k26wl+PflxJEy8yOYdUlZ6vBltv3EaHmAJcUsS/Aij6aN0WQMEJklbJ3jTJR1R4EEWlV9H+jwIZSOK+bGb01vn/0+ewQ4AUmwpaMv1o8gZcNoXQVO2KuXmA904ePJVSbleLdb+6btsArtRPPjHKIimI3WCz66dQjgzjKnDloaaDIrx6bi3J0GOxzRGfMTMTuqhr6cm1OWCgSIFK+jTj61o7eIx1ZYY3OorApS9Q5CF3OHAXn6ignBxdvuyzDfA9VNMihrnuDcWy674mMOciu6TYx4Y0nwpFedKU29uR5Scgr0DGQFeLBSZmyd5kblDTu/CF5sFK5kr7H2pYQKBgQD3guHqAeObnItkmLdJfOkdfcoSmS5UZeyyyaJitjCbUGydJPUA8RipYKCM4rhRQYZvyIWwo52BahhzwGrp+3gdQWOQ6SRVXZXQVwsvWfkWaVkgRxeM0GASsFAnSjoHEEfRNifWRPcCSzSrvr0W+X7Wjc9XSiafOaKPuJeyTrVHiQKBgQDa8ba3l1/L2q6+al6UFsgn4WeIDHVaiDnIp1W+tT7UYPBEraedke1SjjGACfOrFfvNW35Vo6nV1olekB0D1AB2alLXN0x0swjit2TRKHOj8eH5uzplcktBNygDicnG09JW5RnQL21D7xf01L5b2lv52DvR7anrikkf3TdrNAbBBQKBgESm9wazU3CcMUXL3jrx/K8DbwNNnb4nL0pAB1yd8EmEOzwzPgnu1cpVVPL/B+Tx6dojooFmQI/e371rh7wy1hQ3SOiu4jcTaDSLkDyoFiETQ3digLO8MIm+gd0EB6hh6amr/cy/AEyQk6F3nHc86OOWHga2OJQ9pkt7BgidMEcRAoGBAKE9MVqzWBFA0z/YBh75SB5WmXBP/HzXpfZnhXYU9Fhjq45odPBN74DExx+MNK7iWbY6kyduiDy66h+B8lxHXK/YTXnBd8TZtMmCVfTS3Zb3I3xOrgrXySQWApnYd4i9pkHoJsJyqv1Er1fW9PmgLewpmqRXarPT+1ZEC/QfNHohAoGBAOpKX5QeQfk3x9ae6Wtvuw5hdF0aPaWpimPAFion5jqINoJc13gMo1YhU2eUMwvw8kkB/edvAp12EFRb7Esza4ZXc7uDWnYMPh8Wx8iHBEKxpUneNADmxpo2LXO+AXE4ZgIojeUSYPAGSHb16uG15lxamLqlLIJ44FR+1F86jk4L";
+    public static final String ALIPAY_PUBLIC_KEY = "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAtUtjYn+V60um6GVF0ezsI4NCI8QAiM8BT7SQda3RDzIssPbU5U3GJo/5bbu+k+pOpCOUlGVve2VoO+AXMWizCA8U/RleN7fNE09yw7RdLfLssNp6J4zGfBHQBWMiTrJvGZ4LzZHiwJgf28CGwcovjAK6M8bjF30k5ChQ8YIi+YYuer8yae7XfORLiSTByakglURlVUZF7QgbLph9i/OBk83HribZh+B/n97vavrAUyTjbDE3TMsINsAfMSY1omweXuvqjndYI+XmiBM4nBPHlPsXEeaF9TE8LuIqWm5mnRKWa/0I31RkE+W19tFUx5mF3oHw6SvyVuUQVx0HWGIPKQIDAQAB";
     public static final String ALIPAYMP_SAAS_SEC_KEY_NFYYBYFY = "LdYnclVYOKdN5NRDbTDVyXbQiBQiysOQ";
 
     public static final String DOCTOR_AVATAR_URL = "http://ywt-image.oss-cn-shenzhen.aliyuncs.com/doctor/avatar/default.png?x-oss-process=image/resize,h_180,w_180";
 
     public static final String HIS_PAY_MODE_ALIPAY = "ALIPAY"; // 支付宝缴费传给 HIS 的支付标识
+
+    // 支付宝 accessToken Redis key,第一个参数是 appId,第二个参数 alipayUid
+    public static final String RK_ACCESS_TOKEN = "ALI_TOKEN_%s_%s";
 }

+ 14 - 0
onemini-hospital-empty/src/main/java/com/ywt/alipaympapi/models/auth/SubmitAuthCodeReq.java

@@ -0,0 +1,14 @@
+package com.ywt.alipaympapi.models.auth;
+
+import lombok.Data;
+
+/**
+ * @author Walker
+ * Created on 2022/9/28
+ */
+@Data
+public class SubmitAuthCodeReq {
+    private String authCode;
+    private String alipayUid;
+    private String appId;
+}

+ 27 - 0
onemini-hospital-empty/src/main/java/com/ywt/alipaympapi/models/msg/SendRegMsgReq.java

@@ -0,0 +1,27 @@
+package com.ywt.alipaympapi.models.msg;
+
+import lombok.Data;
+
+/**
+ * @author Walker
+ * Created on 2022/9/28
+ */
+@Data
+public class SendRegMsgReq {
+    private Integer orderId;
+    private String orderNo;
+    private String orderCreateTime;
+    private String orderAmountStr;
+    private String tradeNo;
+    private String hospitalName;
+    private String deptName;
+    private String doctorName;
+    private String doctorId;
+    private String patientName;
+    private String regDate;
+    private String deptLoc;
+
+    private String alipayUid;
+
+    private Integer hospitalId;
+}

+ 143 - 0
onemini-hospital-empty/src/main/java/com/ywt/alipaympapi/service/MessageService.java

@@ -0,0 +1,143 @@
+package com.ywt.alipaympapi.service;
+
+import com.alibaba.fastjson.JSON;
+import com.alibaba.fastjson.JSONArray;
+import com.alibaba.fastjson.JSONObject;
+import com.alipay.api.AlipayApiException;
+import com.alipay.api.domain.CommerceAppUploadRequestContent;
+import com.alipay.api.request.AlipayCommerceAppAuthUploadRequest;
+import com.alipay.api.response.AlipayCommerceAppAuthUploadResponse;
+import com.alipay.easysdk.base.oauth.models.AlipaySystemOauthTokenResponse;
+import com.alipay.easysdk.factory.Factory;
+import com.ywt.alipaympapi.core.utils.CheckUtil;
+import com.ywt.alipaympapi.face.impl.AlipayService;
+import com.ywt.alipaympapi.models.Constants;
+import com.ywt.core.exception.AppMessageException;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.tomcat.util.bcel.Const;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+import redis.clients.jedis.JedisCommands;
+
+/**
+ * 支付宝“智能”消息服务
+ * 参考文档 <a href="https://opendocs.alipay.com/pre-open/01odaz">医疗小程序智能消息推送接入方案</a>
+ *
+ * @author Walker
+ * Created on 2022/9/28
+ */
+@Slf4j
+@Service
+public class MessageService {
+    @Autowired
+    AlipayService alipayService;
+    @Autowired
+    JedisCommands jedisCommands;
+
+    /**
+     * 小程序用 authCode 换取 accessToken
+     */
+    public String getAccessToken(String authCode) {
+        String accessToken = "";
+        try {
+            AlipaySystemOauthTokenResponse response = Factory.Base.OAuth().getToken(authCode);
+            log.info("MessageService#getAccessToken(authCode={} ):\n {}", authCode, JSON.toJSONString(response));
+            accessToken = response.getAccessToken();
+        } catch (Exception e) {
+            log.error("MessageService#getAccessToken(authCode={} ):\n {}", authCode, e.getMessage(), e);
+        }
+        return accessToken;
+    }
+
+    /**
+     * 发送“智能”消息
+     *
+     * @param appId    小程序 appId
+     * @param alipayUid 支付宝用户 id
+     * @param jsonBody 业务参数,具体根据业务类型按照文档拼接
+     */
+    public void sendIntelliMsg(String appId, String alipayUid, JSONObject jsonBody) {
+        try {
+            String rk = String.format(Constants.RK_ACCESS_TOKEN, appId, alipayUid);
+            String accessToken = jedisCommands.get(rk);
+            CheckUtil.ensureNotEmpty(accessToken, rk + " 无法获取 accessToken");
+            AlipayCommerceAppAuthUploadRequest request = new AlipayCommerceAppAuthUploadRequest();
+            request.setServiceName("alipay.commerce.app.data");//应用服务名称 固定值 String(256) 不可空
+            request.setTargetId("2088441565011410"); //目标用户 String(64) 签约商家 PID 不可空
+
+            CommerceAppUploadRequestContent content = new CommerceAppUploadRequestContent(); //服务数据参数
+            content.setTenantAppId("20220815114100017389"); //租户应 用ID String(64) 支付宝分配 不可空
+            content.setActivityId("upload_hospital_order"); //业务流程ID String(64) 不可空 此处固定为“upload_hospital_order”
+
+            content.setBody(JSONObject.toJSONString(jsonBody));
+            request.setContent(content);
+            log.info("MessageService#sendIntelliMsg(appId={}, accessToken={} ): 入参:{}", appId, accessToken, JSON.toJSONString(request));
+
+            AlipayCommerceAppAuthUploadResponse response = alipayService.getAlipayClient(appId).execute(request, accessToken);
+            log.info("MessageService#sendIntelliMsg(appId={}, accessToken={} ): 响应:{}", appId, accessToken, JSON.toJSONString(response));
+        } catch (AppMessageException e) {
+            log.error("MessageService#sendIntelliMsg(): 业务异常:{}", e.getMessage());
+        } catch (Exception e) {
+            log.error("MessageService#sendIntelliMsg(appId={} , jsonBody={} , alipayUid={} ):\n {}", appId, jsonBody, alipayUid, e.getMessage(), e);
+        }
+    }
+
+    /**
+     * 发送预约挂号成功消息
+     */
+    public void sendRegMsg(int orderId, String orderNo, String alipayUid, String orderCreateTime, String orderAmountStr,
+                           String tradeNo, String hospitalName, String deptName, String doctorName, String doctorId,
+                           String patientName, String regDate, String deptLoc, String appId) throws AppMessageException {
+        CheckUtil.ensureNotEmpty(deptLoc, "科室位置不能为空");
+        // ISV的PID,支付宝id(2088 开头)。同一家ISV 请保持一致!
+        String isvPid = "2088441568067687";
+        // 医院登记号
+        String hospRegId = "352790440111410131";
+        // 小程序跳转路径
+        String mpPath = String.format("alipays://platformapi/startapp?appId=%s&page=antbuilder/industry/hospitalV2/pages/page-no-pull/index&query=header=show&orderId=%d&pageType=appointment-result&title=挂号详情", appId, orderId);
+        JSONObject jsonBody = new JSONObject(); //业务流程参数 String(6000) 业务流程请求参数说明
+        jsonBody.put("out_biz_no", orderNo);//医院预约单订单号 唯一不重复(同一 家 ISV 接入的所有 医院的挂号单、检 查号、医药单都不 可重复) String(128)
+        jsonBody.put("partner_id", isvPid); //ISV的PID,支付宝id(2088 开头)。同一家ISV 请保持一致!
+        jsonBody.put("buyer_id", alipayUid);//就诊人 id,授权 人id 就诊人在支付宝平 台的 2088 开头 16 位id
+        jsonBody.put("tiny_app_id", appId);//医院在支付宝的小 程序id
+        jsonBody.put("order_create_time", orderCreateTime);//订单创建时间
+        jsonBody.put("order_modified_time", orderCreateTime);//订单修改时间
+        jsonBody.put("amount", orderAmountStr);//订单金额
+        jsonBody.put("pay_amount", orderAmountStr);//支付金额
+        jsonBody.put("trade_no", tradeNo);//支付宝交易号
+        jsonBody.put("order_type", "HOSPITAL_ORDER"); // 固定为 HOSPITAL_ORDER
+        jsonBody.put("out_biz_type", "HOSPITAL_APPOINTMENT"); // 固定值 HOSPITAL_APPOINTMENT
+        jsonBody.put("merchant_order_status", "MERCHANT_PREORDER_SUCCESS"); //状态 String(64) 枚举详见文档
+        JSONArray itemOrderList = new JSONArray();
+        JSONObject itemOrder = new JSONObject();
+        itemOrder.put("item_name", "预约挂号");//商品名称
+        itemOrder.put("quantity", "1");//商品数量
+        itemOrder.put("sku_id", "1"); //商品 skuId
+        itemOrder.put("unit_price", orderAmountStr);//商品单价
+        itemOrderList.add(itemOrder);
+        jsonBody.put("item_order_list", itemOrderList);
+
+        JSONObject extInfo = new JSONObject();
+        extInfo.put("hospital", hospitalName);//医院名称
+        extInfo.put("hospital_register_id", hospRegId);//医院登记号
+        extInfo.put("department", deptName);//就诊科室
+        extInfo.put("dept_num", "");//诊室编号
+        extInfo.put("dept_loc", deptLoc);//科室位置
+        extInfo.put("navigation", "");//导航地址
+        extInfo.put("doctor", doctorName);//医生名称
+        extInfo.put("doctor_rank", "");//医生职级
+        extInfo.put("doctor_id", doctorId);//医生 id
+        extInfo.put("doctor_avatar", "");//医生头像 url
+        extInfo.put("patient", patientName);//就诊人  必须与 buy_id 对 应的姓名一致
+        extInfo.put("scheduled_time", regDate);//预约时间
+        extInfo.put("take_num_url", "");//取号入口
+        extInfo.put("take_num_password", "");//取号密码
+        extInfo.put("call_num_url", "");//叫号进度入口
+        extInfo.put("medical_order_id", "");//就诊单id
+        extInfo.put("medical_num", "");//就诊/检 查序号
+        extInfo.put("merchant_order_link_page", mpPath);//订单链接
+        jsonBody.put("ext_info", extInfo);
+
+        sendIntelliMsg(appId, alipayUid, jsonBody);
+    }
+}

+ 48 - 26
onemini-hospital-empty/src/main/java/com/ywt/alipaympapi/web/controller/AuthController.java

@@ -1,32 +1,27 @@
 package com.ywt.alipaympapi.web.controller;
 
 
-import com.ywt.alipaympapi.core.utils.*;
-
 import com.alibaba.fastjson.JSON;
+import com.alipay.easysdk.base.oauth.models.AlipaySystemOauthTokenResponse;
 import com.alipay.easysdk.factory.Factory;
-import com.alipay.easysdk.payment.common.models.AlipayTradeCreateResponse;
+import com.ywt.alipaympapi.core.utils.*;
 
 import com.ywt.alipaympapi.models.BaseResponse;
 import com.ywt.alipaympapi.models.BaseResponse2;
 import com.ywt.alipaympapi.models.Constants;
 import com.ywt.alipaympapi.models.auth.*;
-import com.ywt.alipaympapi.models.enums.TerminalEnum;
 import com.ywt.alipaympapi.service.AuthService;
 import com.ywt.alipaympapi.web.interceptors.WebAppContext;
 import com.ywt.core.exception.AppMessageException;
-import com.ywt.gapi.gateway.AuthServiceGrpc;
-import com.ywt.gapi.gateway.IssueJWTRequest;
-import com.ywt.gapi.gateway.IssueJWTResponse;
 import com.ywt.gapi.user.BindAlipayUserInfoRequest;
 import com.ywt.gapi.user.BindAlipayUserInfoResponse;
 import com.ywt.gapi.user.UserServiceGrpc;
 import lombok.extern.slf4j.Slf4j;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.web.bind.annotation.*;
+import redis.clients.jedis.JedisCommands;
 
-import java.net.URLDecoder;
-import java.util.HashMap;
+import java.util.Map;
 
 /**
  * @author Walker
@@ -40,9 +35,9 @@ public class AuthController {
     @Autowired
     private UserServiceGrpc.UserServiceBlockingStub userServiceBlockingStub;
     @Autowired
-    private AuthServiceGrpc.AuthServiceBlockingStub authServiceBlockingStub;
-    @Autowired
     private AuthService authService;
+    @Autowired
+    private JedisCommands jedisCommands;
 
 
     @RequestMapping(value = {"/bind"}, method = RequestMethod.POST)
@@ -71,15 +66,15 @@ public class AuthController {
             int age = Checker.getIntegerValue(resp.getAge());
             String idCardNo = Checker.getStringValue(resp.getIdCardNo());
             BindAlipayUserInfoResponse response = userServiceBlockingStub.bindAlipayUserInfo(BindAlipayUserInfoRequest.newBuilder()
-                            .setAlipayUid(alipayUid)
-                            .setAvatar(avatar)
-                            .setRealName(realName)
-                            .setNickName(nickName)
-                            .setMobile(mobile)
-                            .setIdCardNo(idCardNo)
-                            .setAge(age)
-                            .setTerminal(terminal)
-                            .setIp(ip)
+                    .setAlipayUid(alipayUid)
+                    .setAvatar(avatar)
+                    .setRealName(realName)
+                    .setNickName(nickName)
+                    .setMobile(mobile)
+                    .setIdCardNo(idCardNo)
+                    .setAge(age)
+                    .setTerminal(terminal)
+                    .setIp(ip)
                     .build());
             if (response.getCode() == BaseResponse.SUCCEED) {
                 int userId = response.getUserId();
@@ -100,16 +95,43 @@ public class AuthController {
         }
     }
 
+    /**
+     * 小程序提交 authCode,服务端换取 accessToken 并存入 Redis
+     */
+    @RequestMapping(value = {"/submitAuthCode"}, method = RequestMethod.POST)
+    public @ResponseBody com.ywt.model.BaseResponse submitAuthCode(@RequestBody SubmitAuthCodeReq reqData) {
+        com.ywt.model.BaseResponse baseResponse = new com.ywt.model.BaseResponse();
+        try {
+            String authCode = reqData.getAuthCode();
+            String alipayUid = reqData.getAlipayUid();
+            String appId = reqData.getAppId();
+            CheckUtil.ensureNotEmpty(authCode, "authCode 不能为空");
+            CheckUtil.ensureNotEmpty(alipayUid, "alipayUid 不能为空");
+            CheckUtil.ensureNotEmpty(appId, "appId 不能为空");
+            // auth_code 和 access_token 的区别:https://opendocs.alipay.com/support/01rg6k
+            // auth_code 作为换取 access_token 的票据,每次用户授权完成,回调地址中的 auth_code 将不一样,auth_code 只能使用一次,一天未被使用自动过期。
+            String rk = String.format(Constants.RK_ACCESS_TOKEN, appId, alipayUid);
+            AlipaySystemOauthTokenResponse response = Factory.Base.OAuth().getToken(authCode);
+            log.info("AuthController#submitAuthCode(): {} 换取 token: {}", rk, JSON.toJSONString(response));
+            String accessToken = response.getAccessToken();
+            int expire = (int) (Checker.getLongValue(response.getExpiresIn()) / 1000);
+            CheckUtil.ensureNotEmpty(accessToken, "获取 token 失败");
+            jedisCommands.set(rk, accessToken);
+            jedisCommands.expire(rk, expire);
+            return baseResponse.succeed();
+        } catch (AppMessageException appMessageException) {
+            return baseResponse.error(appMessageException.getMessage());
+        } catch (Exception e) {
+            log.error("AuthController#submitAuthCode(): {}", e.getMessage(), e);
+            return baseResponse.error(e.getMessage());
+        }
+    }
+
     @RequestMapping(value = {"/test"}, method = RequestMethod.POST)
-    public @ResponseBody BaseResponse2<String> test() {
+    public @ResponseBody BaseResponse2<String> test(@RequestBody Map<String, String> data) {
         BaseResponse2<String> baseResponse = new BaseResponse2<>();
         try {
-            AlipayTradeCreateResponse response = Factory.Payment.Common().create("测试创建订单", "YWT2022090512345678", "0.01", "2088902410459523");
-//            AlipayOpenAppQrcodeCreateResponse response = Factory.Base.Qrcode().create("antbuilder/industry/hospitalV2/pages/page-no-pull/index", "{}", "test");
-            log.info(JSON.toJSONString(response));
             return new BaseResponse2<>();
-        } catch (AppMessageException appMessageException) {
-            return baseResponse.error(appMessageException.getMessage());
         } catch (Exception e) {
             log.error("AuthController#test(): {}", e.getMessage(), e);
             return baseResponse.error(e.getMessage());

+ 61 - 0
onemini-hospital-empty/src/main/java/com/ywt/alipaympapi/web/controller/MsgController.java

@@ -0,0 +1,61 @@
+package com.ywt.alipaympapi.web.controller;
+
+import com.ywt.alipaympapi.core.utils.BizUtil;
+import com.ywt.alipaympapi.core.utils.Checker;
+import com.ywt.alipaympapi.models.BaseResponse2;
+import com.ywt.alipaympapi.models.auth.AlipayMpCfg;
+import com.ywt.alipaympapi.models.msg.SendRegMsgReq;
+import com.ywt.alipaympapi.service.AuthService;
+import com.ywt.alipaympapi.service.MessageService;
+import com.ywt.core.exception.AppMessageException;
+import com.ywt.model.BaseResponse;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.*;
+
+/**
+ * @author Walker
+ * Created on 2022/9/28
+ */
+@Slf4j
+@RestController("/msg")
+@RequestMapping({"/msg"})
+public class MsgController {
+    @Autowired
+    AuthService authService;
+
+    @Autowired
+    MessageService messageService;
+
+    @RequestMapping(value = {"/sendRegMsg"}, method = RequestMethod.POST)
+    public @ResponseBody BaseResponse sendRegMsg(@RequestBody SendRegMsgReq reqData) {
+        BaseResponse baseResponse = new BaseResponse();
+        try {
+            int orderId = Checker.getIntegerValue(reqData.getOrderId());
+            String orderNo = Checker.getStringValue(reqData.getOrderNo());
+            String orderCreateTime = Checker.getStringValue(reqData.getOrderCreateTime());
+            String orderAmountStr = Checker.getStringValue(reqData.getOrderAmountStr());
+            String tradeNo = Checker.getStringValue(reqData.getTradeNo());
+            String hospitalName = Checker.getStringValue(reqData.getHospitalName());
+            String deptName = Checker.getStringValue(reqData.getDeptName());
+            String doctorName = Checker.getStringValue(reqData.getDoctorName());
+            String doctorId = Checker.getStringValue(reqData.getDoctorId());
+            String patientName = Checker.getStringValue(reqData.getPatientName());
+            String regDate = Checker.getStringValue(reqData.getRegDate());
+            String deptLoc = Checker.getStringValue(reqData.getDeptLoc());
+            String alipayUid = Checker.getStringValue(reqData.getAlipayUid());
+            int hospitalId = Checker.getIntegerValue(reqData.getHospitalId());
+            int alipayMpTerminal = BizUtil.getAlipayMpTerminalIdByHospitalId(hospitalId);
+            AlipayMpCfg cfg = authService.getCfg(alipayMpTerminal);
+            String appId = cfg.getAppId();
+            messageService.sendRegMsg(orderId, orderNo, alipayUid, orderCreateTime, orderAmountStr, tradeNo, hospitalName, deptName,
+                    doctorName, doctorId, patientName, regDate, deptLoc, appId);
+            return baseResponse.succeed();
+        } catch (AppMessageException appMessageException) {
+            return baseResponse.error(appMessageException.getMessage());
+        } catch (Exception e) {
+            log.error("MsgController#sendRegMsg(reqData={} ):\n {}", reqData, e.getMessage(), e);
+            return baseResponse.error(e.getMessage());
+        }
+    }
+}