diff --git a/postdischarge-admin/src/main/resources/application.yml b/postdischarge-admin/src/main/resources/application.yml
index 0b21fe40..89a7ce9f 100644
--- a/postdischarge-admin/src/main/resources/application.yml
+++ b/postdischarge-admin/src/main/resources/application.yml
@@ -217,4 +217,6 @@ wechat-official-account-config:
# 微信公众号事件回调令牌
official-account-token: xinyilu
# 微信公众号事件回调消息加密密钥
- official-account-encoding-aes-key: Awcn7nvDU4bcfBwAZmiRbB3lFgXAm2RIg45utdb5Zt3
\ No newline at end of file
+ official-account-encoding-aes-key: Awcn7nvDU4bcfBwAZmiRbB3lFgXAm2RIg45utdb5Zt3
+ # 测试模板id
+ test-template-id: WUCYtSbH-QFRV_fMcfmn86QLsz1zo881QW7fQNTWOjc
\ No newline at end of file
diff --git a/postdischarge-common/pom.xml b/postdischarge-common/pom.xml
index f64df95d..73f446fc 100644
--- a/postdischarge-common/pom.xml
+++ b/postdischarge-common/pom.xml
@@ -111,6 +111,12 @@
org.projectlombok
lombok
+
+
+ org.apache.httpcomponents
+ httpclient
+ 4.5.13
+
\ No newline at end of file
diff --git a/postdischarge-common/src/main/java/com/xinelu/common/constant/Constants.java b/postdischarge-common/src/main/java/com/xinelu/common/constant/Constants.java
index 0023f012..fef06939 100644
--- a/postdischarge-common/src/main/java/com/xinelu/common/constant/Constants.java
+++ b/postdischarge-common/src/main/java/com/xinelu/common/constant/Constants.java
@@ -223,4 +223,44 @@ public class Constants {
* 获取微信小程序和微信公众号accessToken的url地址
*/
public static final String WE_CHAT_ACCESS_TOKEN_URL = "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential";
+
+ /**
+ * 微信公众号模板消息推送发送接口地址
+ */
+ public static final String OFFICIAL_ACCOUNT_TEMPLATE_SEND_URL = "https://api.weixin.qq.com/cgi-bin/message/template/send?access_token=";
+
+ /**
+ * 获取 access_token 时 AppSecret 错误,或者 access_token 无效。请开发者认真比对 AppSecret 的正确性,或查看是否正在为恰当的公众号调用接口
+ */
+ public static final int INVALID_CREDENTIAL_ACCESS_TOKEN_ISINVALID_OR_NOT_LATEST = 40001;
+
+ /**
+ * 不合法的 OpenID ,请开发者确认 OpenID (该用户)是否已关注公众号,或是否是其他公众号的 OpenID
+ */
+ public static final int INVALID_OPENID = 40003;
+
+ /**
+ * 不合法的 access_token ,请开发者认真比对 access_token 的有效性(如是否过期),或查看是否正在为恰当的公众号调用接口
+ */
+ public static final int INVALID_ACCESS_TOKEN = 40014;
+
+ /**
+ * 不合法的 template_id
+ */
+ public static final int INVALID_TEMPLATE_ID = 40037;
+
+ /**
+ * 用户拒接订阅
+ */
+ public static final int DENY_SUBSCRIPTION = 43101;
+
+ /**
+ * 参数无效
+ */
+ public static final int ARGUMENT_INVALID = 47003;
+
+ /**
+ * 成功
+ */
+ public static final int SUCCESS_ERROR_CODE = 0;
}
diff --git a/postdischarge-common/src/main/java/com/xinelu/common/enums/TemplateEventSendStatusEnum.java b/postdischarge-common/src/main/java/com/xinelu/common/enums/TemplateEventSendStatusEnum.java
new file mode 100644
index 00000000..8d45922a
--- /dev/null
+++ b/postdischarge-common/src/main/java/com/xinelu/common/enums/TemplateEventSendStatusEnum.java
@@ -0,0 +1,34 @@
+package com.xinelu.common.enums;
+
+import lombok.Getter;
+
+/**
+ * @Description 微信公众号模板事件消息发送状态枚举
+ * @Author 纪寒
+ * @Date 2024-03-25 14:38:27
+ * @Version 1.0
+ */
+@Getter
+public enum TemplateEventSendStatusEnum {
+ /**
+ * 成功
+ */
+ SUCCESS("success"),
+
+ /**
+ * 用户拒绝接收
+ */
+ REJECT("failed:user block"),
+
+ /**
+ * 发送失败
+ */
+ FAILED("failed:system failed"),
+ ;
+
+ final private String info;
+
+ TemplateEventSendStatusEnum(String info) {
+ this.info = info;
+ }
+}
diff --git a/postdischarge-common/src/main/java/com/xinelu/common/utils/http/HttpUtils.java b/postdischarge-common/src/main/java/com/xinelu/common/utils/http/HttpUtils.java
index 9159bb3b..1d5c3109 100644
--- a/postdischarge-common/src/main/java/com/xinelu/common/utils/http/HttpUtils.java
+++ b/postdischarge-common/src/main/java/com/xinelu/common/utils/http/HttpUtils.java
@@ -2,6 +2,16 @@ package com.xinelu.common.utils.http;
import com.xinelu.common.constant.Constants;
import com.xinelu.common.utils.StringUtils;
+import org.apache.http.Consts;
+import org.apache.http.HttpEntity;
+import org.apache.http.client.config.RequestConfig;
+import org.apache.http.client.methods.CloseableHttpResponse;
+import org.apache.http.client.methods.HttpPost;
+import org.apache.http.client.utils.HttpClientUtils;
+import org.apache.http.entity.StringEntity;
+import org.apache.http.impl.client.CloseableHttpClient;
+import org.apache.http.impl.client.HttpClients;
+import org.apache.http.util.EntityUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -207,4 +217,40 @@ public class HttpUtils {
return true;
}
}
+
+ /**
+ * 发送json格式的POST类型的http请求
+ *
+ * @param url 请求地址
+ * @param param json格式的请求参数
+ * @return String 返回值信息
+ */
+ public static String sendPostJson(String url, String param) {
+ String result = null;
+ CloseableHttpClient httpClient = null;
+ CloseableHttpResponse response = null;
+ try {
+ httpClient = HttpClients.createDefault();
+ // 字符串编码
+ StringEntity entity = new StringEntity(param, Consts.UTF_8);
+ // 设置content-type
+ entity.setContentType("application/json");
+ HttpPost httpPost = new HttpPost(url);
+ httpPost.setConfig(RequestConfig.custom().setSocketTimeout(10000).setConnectTimeout(10000).build());
+ // 防止被当成攻击添加的
+ httpPost.setHeader("User-Agent", "Mozilla/5.0 (Windows NT 6.2; Win64; x64) AppleWebKit/537.36 (KHTML,like Gecko) Chrome/54.0.2840.87 Safari/537.36");
+ // 接收参数设置
+ httpPost.setHeader("Accept", "application/json");
+ httpPost.setEntity(entity);
+ response = httpClient.execute(httpPost);
+ HttpEntity httpEntity = response.getEntity();
+ result = EntityUtils.toString(httpEntity);
+ } catch (Exception e) {
+ log.warn("post请求发送失败,请求路径:[{}],请求参数:[{}],异常信息:[{}]", url, param, e);
+ } finally {
+ HttpClientUtils.closeQuietly(response);
+ HttpClientUtils.closeQuietly(httpClient);
+ }
+ return result;
+ }
}
\ No newline at end of file
diff --git a/postdischarge-manage/src/main/java/com/xinelu/manage/domain/officialaccounttemplateevent/OfficialAccountTemplateEvent.java b/postdischarge-manage/src/main/java/com/xinelu/manage/domain/officialaccounttemplateevent/OfficialAccountTemplateEvent.java
new file mode 100644
index 00000000..0b1d7bd6
--- /dev/null
+++ b/postdischarge-manage/src/main/java/com/xinelu/manage/domain/officialaccounttemplateevent/OfficialAccountTemplateEvent.java
@@ -0,0 +1,119 @@
+package com.xinelu.manage.domain.officialaccounttemplateevent;
+
+import com.fasterxml.jackson.annotation.JsonFormat;
+import com.xinelu.common.annotation.Excel;
+import com.xinelu.common.core.domain.BaseEntity;
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.AllArgsConstructor;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import lombok.NoArgsConstructor;
+import org.apache.commons.lang3.builder.ToStringBuilder;
+import org.apache.commons.lang3.builder.ToStringStyle;
+
+import java.time.LocalDateTime;
+
+/**
+ * 微信公众号模板信息事件推送对象 official_account_template_event
+ *
+ * @author xinelu
+ * @date 2024-03-25
+ */
+@Data
+@AllArgsConstructor
+@NoArgsConstructor
+@EqualsAndHashCode(callSuper = true)
+@ApiModel(value = "微信公众号模板信息事件推送对象", description = "official_account_template_event")
+public class OfficialAccountTemplateEvent extends BaseEntity {
+ private static final long serialVersionUID = -8437491233815143821L;
+ /**
+ * 主键id
+ */
+ private Long id;
+
+ /**
+ * 患者信息表id
+ */
+ @ApiModelProperty(value = "患者信息表id")
+ @Excel(name = "患者信息表id")
+ private Long patientId;
+
+ /**
+ * 患者姓名
+ */
+ @ApiModelProperty(value = "患者姓名")
+ @Excel(name = "患者姓名")
+ private String patientName;
+
+ /**
+ * 微信用户openid
+ */
+ @ApiModelProperty(value = "微信用户openid")
+ @Excel(name = "微信用户openid")
+ private String openid;
+
+ /**
+ * 微信公众号id
+ */
+ @ApiModelProperty(value = "微信公众号id")
+ @Excel(name = "微信公众号id")
+ private String officialAccountAppId;
+
+ /**
+ * 发送时间,即:事件创建时间,yyyy-MM-dd HH:mm:ss
+ */
+ @ApiModelProperty(value = "发送时间,即:事件创建时间,yyyy-MM-dd HH:mm:ss")
+ @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
+ @Excel(name = "发送时间,即:事件创建时间,yyyy-MM-dd HH:mm:ss", width = 30, dateFormat = "yyyy-MM-dd")
+ private LocalDateTime sendTime;
+
+ /**
+ * 消息类型是事件,固定取值为:event
+ */
+ @ApiModelProperty(value = "消息类型是事件,固定取值为:event")
+ @Excel(name = "消息类型是事件,固定取值为:event")
+ private String msgType;
+
+ /**
+ * 事件为模板消息发送结束,固定取值为:TEMPLATESENDJOBFINISH
+ */
+ @ApiModelProperty(value = "事件为模板消息发送结束,固定取值为:TEMPLATESENDJOBFINISH")
+ @Excel(name = "事件为模板消息发送结束,固定取值为:TEMPLATESENDJOBFINISH")
+ private String eventType;
+
+ /**
+ * 消息id
+ */
+ @ApiModelProperty(value = "消息id")
+ @Excel(name = "消息id")
+ private String msgId;
+
+ /**
+ * 发送状态,成功:success,用户拒绝接收:failed:user block,发送失败(非用户拒绝):failed:system failed
+ */
+ @ApiModelProperty(value = "发送状态,成功:success,用户拒绝接收:failed:user block,发送失败")
+ @Excel(name = "发送状态,成功:success,用户拒绝接收:failed:user block,发送失败", readConverterExp = "非=用户拒绝")
+ private String status;
+
+
+ @Override
+ public String toString() {
+ return new ToStringBuilder(this, ToStringStyle.MULTI_LINE_STYLE)
+ .append("id", getId())
+ .append("patientId", getPatientId())
+ .append("patientName", getPatientName())
+ .append("openid", getOpenid())
+ .append("officialAccountAppId", getOfficialAccountAppId())
+ .append("sendTime", getSendTime())
+ .append("msgType", getMsgType())
+ .append("eventType", getEventType())
+ .append("msgId", getMsgId())
+ .append("status", getStatus())
+ .append("createBy", getCreateBy())
+ .append("createTime", getCreateTime())
+ .append("updateBy", getUpdateBy())
+ .append("updateTime", getUpdateTime())
+ .toString();
+ }
+}
diff --git a/postdischarge-manage/src/main/java/com/xinelu/manage/mapper/officialaccounttemplateevent/OfficialAccountTemplateEventMapper.java b/postdischarge-manage/src/main/java/com/xinelu/manage/mapper/officialaccounttemplateevent/OfficialAccountTemplateEventMapper.java
new file mode 100644
index 00000000..ef4d97f4
--- /dev/null
+++ b/postdischarge-manage/src/main/java/com/xinelu/manage/mapper/officialaccounttemplateevent/OfficialAccountTemplateEventMapper.java
@@ -0,0 +1,61 @@
+package com.xinelu.manage.mapper.officialaccounttemplateevent;
+
+import com.xinelu.manage.domain.officialaccounttemplateevent.OfficialAccountTemplateEvent;
+
+import java.util.List;
+
+/**
+ * 微信公众号模板信息事件推送Mapper接口
+ *
+ * @author xinelu
+ * @date 2024-03-25
+ */
+public interface OfficialAccountTemplateEventMapper {
+ /**
+ * 查询微信公众号模板信息事件推送
+ *
+ * @param id 微信公众号模板信息事件推送主键
+ * @return 微信公众号模板信息事件推送
+ */
+ OfficialAccountTemplateEvent selectOfficialAccountTemplateEventById(Long id);
+
+ /**
+ * 查询微信公众号模板信息事件推送列表
+ *
+ * @param officialAccountTemplateEvent 微信公众号模板信息事件推送
+ * @return 微信公众号模板信息事件推送集合
+ */
+ List selectOfficialAccountTemplateEventList(OfficialAccountTemplateEvent officialAccountTemplateEvent);
+
+ /**
+ * 新增微信公众号模板信息事件推送
+ *
+ * @param officialAccountTemplateEvent 微信公众号模板信息事件推送
+ * @return 结果
+ */
+ int insertOfficialAccountTemplateEvent(OfficialAccountTemplateEvent officialAccountTemplateEvent);
+
+ /**
+ * 修改微信公众号模板信息事件推送
+ *
+ * @param officialAccountTemplateEvent 微信公众号模板信息事件推送
+ * @return 结果
+ */
+ int updateOfficialAccountTemplateEvent(OfficialAccountTemplateEvent officialAccountTemplateEvent);
+
+ /**
+ * 删除微信公众号模板信息事件推送
+ *
+ * @param id 微信公众号模板信息事件推送主键
+ * @return 结果
+ */
+ int deleteOfficialAccountTemplateEventById(Long id);
+
+ /**
+ * 批量删除微信公众号模板信息事件推送
+ *
+ * @param ids 需要删除的数据主键集合
+ * @return 结果
+ */
+ int deleteOfficialAccountTemplateEventByIds(Long[] ids);
+}
diff --git a/postdischarge-manage/src/main/java/com/xinelu/manage/service/officialaccounttemplateevent/IOfficialAccountTemplateEventService.java b/postdischarge-manage/src/main/java/com/xinelu/manage/service/officialaccounttemplateevent/IOfficialAccountTemplateEventService.java
new file mode 100644
index 00000000..27d77114
--- /dev/null
+++ b/postdischarge-manage/src/main/java/com/xinelu/manage/service/officialaccounttemplateevent/IOfficialAccountTemplateEventService.java
@@ -0,0 +1,61 @@
+package com.xinelu.manage.service.officialaccounttemplateevent;
+
+import com.xinelu.manage.domain.officialaccounttemplateevent.OfficialAccountTemplateEvent;
+
+import java.util.List;
+
+/**
+ * 微信公众号模板信息事件推送Service接口
+ *
+ * @author xinelu
+ * @date 2024-03-25
+ */
+public interface IOfficialAccountTemplateEventService {
+ /**
+ * 查询微信公众号模板信息事件推送
+ *
+ * @param id 微信公众号模板信息事件推送主键
+ * @return 微信公众号模板信息事件推送
+ */
+ OfficialAccountTemplateEvent selectOfficialAccountTemplateEventById(Long id);
+
+ /**
+ * 查询微信公众号模板信息事件推送列表
+ *
+ * @param officialAccountTemplateEvent 微信公众号模板信息事件推送
+ * @return 微信公众号模板信息事件推送集合
+ */
+ List selectOfficialAccountTemplateEventList(OfficialAccountTemplateEvent officialAccountTemplateEvent);
+
+ /**
+ * 新增微信公众号模板信息事件推送
+ *
+ * @param officialAccountTemplateEvent 微信公众号模板信息事件推送
+ * @return 结果
+ */
+ int insertOfficialAccountTemplateEvent(OfficialAccountTemplateEvent officialAccountTemplateEvent);
+
+ /**
+ * 修改微信公众号模板信息事件推送
+ *
+ * @param officialAccountTemplateEvent 微信公众号模板信息事件推送
+ * @return 结果
+ */
+ int updateOfficialAccountTemplateEvent(OfficialAccountTemplateEvent officialAccountTemplateEvent);
+
+ /**
+ * 批量删除微信公众号模板信息事件推送
+ *
+ * @param ids 需要删除的微信公众号模板信息事件推送主键集合
+ * @return 结果
+ */
+ int deleteOfficialAccountTemplateEventByIds(Long[] ids);
+
+ /**
+ * 删除微信公众号模板信息事件推送信息
+ *
+ * @param id 微信公众号模板信息事件推送主键
+ * @return 结果
+ */
+ int deleteOfficialAccountTemplateEventById(Long id);
+}
diff --git a/postdischarge-manage/src/main/java/com/xinelu/manage/service/officialaccounttemplateevent/impl/OfficialAccountTemplateEventServiceImpl.java b/postdischarge-manage/src/main/java/com/xinelu/manage/service/officialaccounttemplateevent/impl/OfficialAccountTemplateEventServiceImpl.java
new file mode 100644
index 00000000..f9546e1b
--- /dev/null
+++ b/postdischarge-manage/src/main/java/com/xinelu/manage/service/officialaccounttemplateevent/impl/OfficialAccountTemplateEventServiceImpl.java
@@ -0,0 +1,90 @@
+package com.xinelu.manage.service.officialaccounttemplateevent.impl;
+
+import com.xinelu.manage.domain.officialaccounttemplateevent.OfficialAccountTemplateEvent;
+import com.xinelu.manage.mapper.officialaccounttemplateevent.OfficialAccountTemplateEventMapper;
+import com.xinelu.manage.service.officialaccounttemplateevent.IOfficialAccountTemplateEventService;
+import org.springframework.stereotype.Service;
+
+import javax.annotation.Resource;
+import java.time.LocalDateTime;
+import java.util.List;
+
+/**
+ * 微信公众号模板信息事件推送Service业务层处理
+ *
+ * @author xinelu
+ * @date 2024-03-25
+ */
+@Service
+public class OfficialAccountTemplateEventServiceImpl implements IOfficialAccountTemplateEventService {
+ @Resource
+ private OfficialAccountTemplateEventMapper officialAccountTemplateEventMapper;
+
+ /**
+ * 查询微信公众号模板信息事件推送
+ *
+ * @param id 微信公众号模板信息事件推送主键
+ * @return 微信公众号模板信息事件推送
+ */
+ @Override
+ public OfficialAccountTemplateEvent selectOfficialAccountTemplateEventById(Long id) {
+ return officialAccountTemplateEventMapper.selectOfficialAccountTemplateEventById(id);
+ }
+
+ /**
+ * 查询微信公众号模板信息事件推送列表
+ *
+ * @param officialAccountTemplateEvent 微信公众号模板信息事件推送
+ * @return 微信公众号模板信息事件推送
+ */
+ @Override
+ public List selectOfficialAccountTemplateEventList(OfficialAccountTemplateEvent officialAccountTemplateEvent) {
+ return officialAccountTemplateEventMapper.selectOfficialAccountTemplateEventList(officialAccountTemplateEvent);
+ }
+
+ /**
+ * 新增微信公众号模板信息事件推送
+ *
+ * @param officialAccountTemplateEvent 微信公众号模板信息事件推送
+ * @return 结果
+ */
+ @Override
+ public int insertOfficialAccountTemplateEvent(OfficialAccountTemplateEvent officialAccountTemplateEvent) {
+ officialAccountTemplateEvent.setCreateTime(LocalDateTime.now());
+ return officialAccountTemplateEventMapper.insertOfficialAccountTemplateEvent(officialAccountTemplateEvent);
+ }
+
+ /**
+ * 修改微信公众号模板信息事件推送
+ *
+ * @param officialAccountTemplateEvent 微信公众号模板信息事件推送
+ * @return 结果
+ */
+ @Override
+ public int updateOfficialAccountTemplateEvent(OfficialAccountTemplateEvent officialAccountTemplateEvent) {
+ officialAccountTemplateEvent.setUpdateTime(LocalDateTime.now());
+ return officialAccountTemplateEventMapper.updateOfficialAccountTemplateEvent(officialAccountTemplateEvent);
+ }
+
+ /**
+ * 批量删除微信公众号模板信息事件推送
+ *
+ * @param ids 需要删除的微信公众号模板信息事件推送主键
+ * @return 结果
+ */
+ @Override
+ public int deleteOfficialAccountTemplateEventByIds(Long[] ids) {
+ return officialAccountTemplateEventMapper.deleteOfficialAccountTemplateEventByIds(ids);
+ }
+
+ /**
+ * 删除微信公众号模板信息事件推送信息
+ *
+ * @param id 微信公众号模板信息事件推送主键
+ * @return 结果
+ */
+ @Override
+ public int deleteOfficialAccountTemplateEventById(Long id) {
+ return officialAccountTemplateEventMapper.deleteOfficialAccountTemplateEventById(id);
+ }
+}
diff --git a/postdischarge-manage/src/main/resources/mapper/manage/officialaccounttemplateevent/OfficialAccountTemplateEventMapper.xml b/postdischarge-manage/src/main/resources/mapper/manage/officialaccounttemplateevent/OfficialAccountTemplateEventMapper.xml
new file mode 100644
index 00000000..eeade5db
--- /dev/null
+++ b/postdischarge-manage/src/main/resources/mapper/manage/officialaccounttemplateevent/OfficialAccountTemplateEventMapper.xml
@@ -0,0 +1,185 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ select id, patient_id, patient_name, openid, official_account_app_id, send_time, msg_type, event_type, msg_id, status, create_by, create_time, update_by, update_time from official_account_template_event
+
+
+
+
+
+
+
+ insert into official_account_template_event
+
+ patient_id,
+
+ patient_name,
+
+ openid,
+
+ official_account_app_id,
+
+ send_time,
+
+ msg_type,
+
+ event_type,
+
+ msg_id,
+
+ status,
+
+ create_by,
+
+ create_time,
+
+ update_by,
+
+ update_time,
+
+
+
+ #{patientId},
+
+ #{patientName},
+
+ #{openid},
+
+ #{officialAccountAppId},
+
+ #{sendTime},
+
+ #{msgType},
+
+ #{eventType},
+
+ #{msgId},
+
+ #{status},
+
+ #{createBy},
+
+ #{createTime},
+
+ #{updateBy},
+
+ #{updateTime},
+
+
+
+
+
+ update official_account_template_event
+
+ patient_id =
+ #{patientId},
+
+ patient_name =
+ #{patientName},
+
+ openid =
+ #{openid},
+
+ official_account_app_id =
+ #{officialAccountAppId},
+
+ send_time =
+ #{sendTime},
+
+ msg_type =
+ #{msgType},
+
+ event_type =
+ #{eventType},
+
+ msg_id =
+ #{msgId},
+
+ status =
+ #{status},
+
+ create_by =
+ #{createBy},
+
+ create_time =
+ #{createTime},
+
+ update_by =
+ #{updateBy},
+
+ update_time =
+ #{updateTime},
+
+
+ where id = #{id}
+
+
+
+ delete from official_account_template_event where id = #{id}
+
+
+
+ delete from official_account_template_event where id in
+
+ #{id}
+
+
+
\ No newline at end of file
diff --git a/postdischarge-mobile/src/main/java/com/xinelu/mobile/controller/MobileTestController.java b/postdischarge-mobile/src/main/java/com/xinelu/mobile/controller/MobileTestController.java
index aae18f01..ad840f07 100644
--- a/postdischarge-mobile/src/main/java/com/xinelu/mobile/controller/MobileTestController.java
+++ b/postdischarge-mobile/src/main/java/com/xinelu/mobile/controller/MobileTestController.java
@@ -37,4 +37,12 @@ public class MobileTestController {
public String getOfficialAccountAccessToken() {
return weChatOfficialAccountUtils.getWeChatOfficialAccountAccessToken();
}
+
+ /**
+ * 测试微信公众号模板消息发送
+ */
+ @GetMapping("/sendOfficialAccountTemplate")
+ public void sendOfficialAccountTemplateMessage() {
+ weChatOfficialAccountUtils.sendOfficialAccountTemplateMessage();
+ }
}
diff --git a/postdischarge-mobile/src/main/java/com/xinelu/mobile/controller/wechatofficialaccountcallback/WeChatOfficialAccountCallbackController.java b/postdischarge-mobile/src/main/java/com/xinelu/mobile/controller/wechatofficialaccountcallback/WeChatOfficialAccountCallbackController.java
index c48451dc..225dfdf6 100644
--- a/postdischarge-mobile/src/main/java/com/xinelu/mobile/controller/wechatofficialaccountcallback/WeChatOfficialAccountCallbackController.java
+++ b/postdischarge-mobile/src/main/java/com/xinelu/mobile/controller/wechatofficialaccountcallback/WeChatOfficialAccountCallbackController.java
@@ -4,12 +4,15 @@ import com.xinelu.common.config.WeChatOfficialAccountConfig;
import com.xinelu.common.utils.aes.AesException;
import com.xinelu.common.utils.aes.WXBizMsgCrypt;
import com.xinelu.mobile.dto.wechatappletcallback.MessageSignDTO;
+import com.xinelu.mobile.service.wechatofficialaccountcallback.WeChatOfficialAccountCallbackService;
+import com.xinelu.mobile.utils.XmlUtil;
+import com.xinelu.mobile.vo.wechatofficialaccountcallback.WeChatOfficialAccountEventPushVO;
import lombok.extern.slf4j.Slf4j;
-import org.springframework.web.bind.annotation.GetMapping;
-import org.springframework.web.bind.annotation.RequestMapping;
-import org.springframework.web.bind.annotation.RestController;
+import org.apache.commons.lang3.StringUtils;
+import org.springframework.web.bind.annotation.*;
import javax.annotation.Resource;
+import java.util.Objects;
/**
* @Description 院后微信公众号事件回调控制器
@@ -23,6 +26,8 @@ import javax.annotation.Resource;
public class WeChatOfficialAccountCallbackController {
@Resource
private WeChatOfficialAccountConfig weChatOfficialAccountConfig;
+ @Resource
+ private WeChatOfficialAccountCallbackService weChatOfficialAccountCallbackService;
/**
* 院后微信公众号回调验证方法
@@ -33,10 +38,40 @@ public class WeChatOfficialAccountCallbackController {
*/
@GetMapping
public String getWeChatOfficialAccountCallBack(MessageSignDTO messageSignDTO) throws AesException {
+ //解密微信报文信息并验证微信公众号与服务器之间是否正常通信
WXBizMsgCrypt wxCpt = new WXBizMsgCrypt(weChatOfficialAccountConfig.getOfficialAccountToken(), weChatOfficialAccountConfig.getOfficialAccountEncodingAesKey(), weChatOfficialAccountConfig.getOfficialAccountAppId());
String verifyMessage = wxCpt.verifyUrl(messageSignDTO.getSignature(), messageSignDTO.getTimestamp(), messageSignDTO.getNonce(), messageSignDTO.getEchostr());
log.info("院后微信公众号回调设置验证URL成功,验证信息:verifyMessage = [{}]", verifyMessage);
return verifyMessage;
}
+
+ /**
+ * 院后微信公众号模板消息事件回调处理
+ *
+ * @param signature 签名
+ * @param timestamp 时间戳
+ * @param nonce 随机字符串
+ * @param postData 事件报文内容
+ * @throws AesException 异常信息
+ */
+ @PostMapping
+ public void handleWeChatOfficialAccountCallBack(@RequestParam("signature") String signature,
+ @RequestParam("timestamp") String timestamp,
+ @RequestParam("nonce") String nonce,
+ @RequestBody String postData) throws AesException {
+ //解密微信报文信息并验证微信公众号与服务器之间是否正常通信
+ WXBizMsgCrypt wxCpt = new WXBizMsgCrypt(weChatOfficialAccountConfig.getOfficialAccountToken(), weChatOfficialAccountConfig.getOfficialAccountEncodingAesKey(), weChatOfficialAccountConfig.getOfficialAccountAppId());
+ String verifyMessage = wxCpt.verifyUrl(signature, timestamp, nonce, postData);
+ WeChatOfficialAccountEventPushVO eventPush = (WeChatOfficialAccountEventPushVO) XmlUtil.fromXml(verifyMessage, WeChatOfficialAccountEventPushVO.class);
+ if (Objects.isNull(eventPush)) {
+ log.info("院后微信公众号模板消息事件xml数据转换失败,请求信息为: [{}]", verifyMessage);
+ return;
+ }
+ if (StringUtils.isBlank(eventPush.getToUserName()) || StringUtils.isBlank(eventPush.getEvent()) || StringUtils.isBlank(eventPush.getMsgType())) {
+ log.info("院后微信公众号模板消息事件解析事件数据为空!");
+ return;
+ }
+ weChatOfficialAccountCallbackService.handleOfficialAccountTemplateEvent(eventPush);
+ }
}
diff --git a/postdischarge-mobile/src/main/java/com/xinelu/mobile/service/wechatofficialaccountcallback/WeChatOfficialAccountCallbackService.java b/postdischarge-mobile/src/main/java/com/xinelu/mobile/service/wechatofficialaccountcallback/WeChatOfficialAccountCallbackService.java
new file mode 100644
index 00000000..27e4c650
--- /dev/null
+++ b/postdischarge-mobile/src/main/java/com/xinelu/mobile/service/wechatofficialaccountcallback/WeChatOfficialAccountCallbackService.java
@@ -0,0 +1,18 @@
+package com.xinelu.mobile.service.wechatofficialaccountcallback;
+
+import com.xinelu.mobile.vo.wechatofficialaccountcallback.WeChatOfficialAccountEventPushVO;
+
+/**
+ * @Description 院后微信公众号事件回调service
+ * @Author 纪寒
+ * @Date 2024-03-25 14:52:03
+ * @Version 1.0
+ */
+public interface WeChatOfficialAccountCallbackService {
+ /**
+ * 院后微信公众号模板消息事件回调处理
+ *
+ * @param eventPushVO 模板消息事件回调数据
+ */
+ void handleOfficialAccountTemplateEvent(WeChatOfficialAccountEventPushVO eventPushVO);
+}
diff --git a/postdischarge-mobile/src/main/java/com/xinelu/mobile/service/wechatofficialaccountcallback/impl/WeChatOfficialAccountCallbackServiceImpl.java b/postdischarge-mobile/src/main/java/com/xinelu/mobile/service/wechatofficialaccountcallback/impl/WeChatOfficialAccountCallbackServiceImpl.java
new file mode 100644
index 00000000..0f68d8af
--- /dev/null
+++ b/postdischarge-mobile/src/main/java/com/xinelu/mobile/service/wechatofficialaccountcallback/impl/WeChatOfficialAccountCallbackServiceImpl.java
@@ -0,0 +1,65 @@
+package com.xinelu.mobile.service.wechatofficialaccountcallback.impl;
+
+import com.xinelu.common.exception.ServiceException;
+import com.xinelu.common.utils.DateUtils;
+import com.xinelu.manage.domain.officialaccounttemplateevent.OfficialAccountTemplateEvent;
+import com.xinelu.manage.domain.patientinfo.PatientInfo;
+import com.xinelu.manage.mapper.officialaccounttemplateevent.OfficialAccountTemplateEventMapper;
+import com.xinelu.manage.mapper.patientinfo.PatientInfoMapper;
+import com.xinelu.mobile.service.wechatofficialaccountcallback.WeChatOfficialAccountCallbackService;
+import com.xinelu.mobile.vo.wechatofficialaccountcallback.WeChatOfficialAccountEventPushVO;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.commons.lang3.StringUtils;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+
+import javax.annotation.Resource;
+import java.util.Objects;
+
+/**
+ * @Description 院后微信公众号事件回调service实现
+ * @Author 纪寒
+ * @Date 2024-03-25 14:55:53
+ * @Version 1.0
+ */
+@Service
+@Slf4j
+public class WeChatOfficialAccountCallbackServiceImpl implements WeChatOfficialAccountCallbackService {
+
+ @Resource
+ private PatientInfoMapper patientInfoMapper;
+ @Resource
+ private OfficialAccountTemplateEventMapper officialAccountTemplateEventMapper;
+
+ /**
+ * 院后微信公众号模板消息事件回调处理
+ *
+ * @param eventPushVO 模板消息事件回调数据
+ */
+ @Transactional(rollbackFor = Exception.class)
+ @Override
+ public void handleOfficialAccountTemplateEvent(WeChatOfficialAccountEventPushVO eventPushVO) {
+ //查询患者信息
+ PatientInfo patientInfo = patientInfoMapper.getPatientInfoByOpenId(eventPushVO.getFromUserName());
+ if (Objects.isNull(patientInfo)) {
+ log.info("当前患者信息不存在,微信用户openid为:{}", eventPushVO.getFromUserName());
+ return;
+ }
+ OfficialAccountTemplateEvent templateEvent = new OfficialAccountTemplateEvent();
+ templateEvent.setPatientId(Objects.isNull(patientInfo.getId()) ? null : patientInfo.getId());
+ templateEvent.setPatientName(StringUtils.isBlank(patientInfo.getPatientName()) ? "" : patientInfo.getPatientName());
+ templateEvent.setOpenid(eventPushVO.getFromUserName());
+ templateEvent.setOfficialAccountAppId(StringUtils.isBlank(eventPushVO.getToUserName()) ? "" : eventPushVO.getToUserName());
+ templateEvent.setSendTime(StringUtils.isBlank(eventPushVO.getCreateTime()) ? null : DateUtils.timestampToLocalDateTime(Long.parseLong(eventPushVO.getCreateTime()) * 1000L));
+ templateEvent.setMsgType(StringUtils.isBlank(eventPushVO.getMsgType()) ? "" : eventPushVO.getMsgType());
+ templateEvent.setEventType(StringUtils.isBlank(eventPushVO.getEvent()) ? "" : eventPushVO.getEvent());
+ templateEvent.setMsgId(StringUtils.isBlank(eventPushVO.getMsgId()) ? "" : eventPushVO.getMsgId());
+ templateEvent.setStatus(StringUtils.isBlank(eventPushVO.getStatus()) ? "" : eventPushVO.getStatus());
+ int insertTemplateEventCount = officialAccountTemplateEventMapper.insertOfficialAccountTemplateEvent(templateEvent);
+ if (insertTemplateEventCount < 0) {
+ log.error("院后微信公众号模板事件推送,新增模板事件消息信息失败,信息为:[{}]", templateEvent);
+ throw new ServiceException("院后微信公众号模板事件推送记录信息失败!");
+ }
+ log.info("院后微信公众号模板事件推送处理成功!");
+ }
+}
diff --git a/postdischarge-mobile/src/main/java/com/xinelu/mobile/utils/WeChatOfficialAccountUtils.java b/postdischarge-mobile/src/main/java/com/xinelu/mobile/utils/WeChatOfficialAccountUtils.java
index ccfc4b0a..6c3a3f93 100644
--- a/postdischarge-mobile/src/main/java/com/xinelu/mobile/utils/WeChatOfficialAccountUtils.java
+++ b/postdischarge-mobile/src/main/java/com/xinelu/mobile/utils/WeChatOfficialAccountUtils.java
@@ -6,11 +6,14 @@ import com.xinelu.common.constant.Constants;
import com.xinelu.common.entity.AccessToken;
import com.xinelu.common.exception.ServiceException;
import com.xinelu.common.utils.http.HttpUtils;
+import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;
import javax.annotation.Resource;
+import java.util.LinkedHashMap;
+import java.util.Map;
import java.util.Objects;
import java.util.concurrent.TimeUnit;
@@ -20,6 +23,7 @@ import java.util.concurrent.TimeUnit;
* @Date 2024-03-21 13:42:31
* @Version 1.0
*/
+@Slf4j
@Component
public class WeChatOfficialAccountUtils {
@@ -68,4 +72,62 @@ public class WeChatOfficialAccountUtils {
}
return accessToken;
}
+
+ /**
+ * 微信公众号模板消息发送
+ */
+ public void sendOfficialAccountTemplateMessage() {
+ //获取微信公众号的accessToken
+ String accessToken = this.getWeChatOfficialAccountAccessToken();
+ //定义模板内容,公众模板内容
+ Map paramsMap = new LinkedHashMap<>();
+ paramsMap.put("touser", "oHBuH5T90TghJdYKfBlxE4fhayBc");
+ paramsMap.put("template_id", "WUCYtSbH-QFRV_fMcfmn86QLsz1zo881QW7fQNTWOjc");
+ //微信小程序跳转内容
+ Map miniprogramMap = new LinkedHashMap<>();
+ miniprogramMap.put("appid", "wxdc32268eca6b78f9");
+ miniprogramMap.put("pagepath", "pages/startup/startup");
+ //微信小程序模板data内容
+ Map dataMap = new LinkedHashMap<>();
+ dataMap.put("phrase7", "泉医陪护服务");
+ dataMap.put("character_string3", "000026315412331612100");
+ dataMap.put("time6", "2024-03-25 16:21:32");
+ dataMap.put("time10", "2024-03-27 10:00:00");
+ dataMap.put("thing11", "济南市槐荫区首诺城市之光东座22楼E10");
+ paramsMap.put("miniprogram", miniprogramMap);
+ paramsMap.put("data", dataMap);
+ //拼接请求地址并发送
+ String messageUrl = Constants.OFFICIAL_ACCOUNT_TEMPLATE_SEND_URL + accessToken;
+ String param = JSON.toJSONString(paramsMap);
+ String result = HttpUtils.sendPostJson(messageUrl, param);
+ //返回参数映射
+ AccessToken errCode = JSON.parseObject(result, AccessToken.class);
+ if (Objects.nonNull(errCode) && Objects.nonNull(errCode.getErrcode())) {
+ switch (errCode.getErrcode()) {
+ case Constants.SUCCESS_ERROR_CODE:
+ log.info("发送消息成功!");
+ break;
+ case Constants.INVALID_CREDENTIAL_ACCESS_TOKEN_ISINVALID_OR_NOT_LATEST:
+ log.error("取 access_token 时 AppSecret 错误,或者 access_token 无效!");
+ break;
+ case Constants.INVALID_OPENID:
+ log.error("不合法的 OpenId!");
+ break;
+ case Constants.INVALID_ACCESS_TOKEN:
+ log.error("合法的 access_token!");
+ break;
+ case Constants.INVALID_TEMPLATE_ID:
+ log.error("不合法的 template_id!");
+ break;
+ case Constants.ARGUMENT_INVALID:
+ log.error("参数无效!");
+ break;
+ case Constants.DENY_SUBSCRIPTION:
+ log.error("用户拒接订阅!");
+ break;
+ default:
+ break;
+ }
+ }
+ }
}
diff --git a/postdischarge-mobile/src/main/java/com/xinelu/mobile/vo/wechatofficialaccountcallback/WeChatOfficialAccountEventPushVO.java b/postdischarge-mobile/src/main/java/com/xinelu/mobile/vo/wechatofficialaccountcallback/WeChatOfficialAccountEventPushVO.java
new file mode 100644
index 00000000..b5930da6
--- /dev/null
+++ b/postdischarge-mobile/src/main/java/com/xinelu/mobile/vo/wechatofficialaccountcallback/WeChatOfficialAccountEventPushVO.java
@@ -0,0 +1,60 @@
+package com.xinelu.mobile.vo.wechatofficialaccountcallback;
+
+import lombok.Data;
+import org.simpleframework.xml.Element;
+import org.simpleframework.xml.Root;
+
+import java.io.Serializable;
+
+/**
+ * @Description 微信公众号模板消息事件推送实体类
+ * @Author 纪寒
+ * @Date 2024-03-25 13:36:17
+ * @Version 1.0
+ */
+@Root(name = "xml", strict = false)
+@Data
+public class WeChatOfficialAccountEventPushVO implements Serializable {
+ private static final long serialVersionUID = 4329284826265109369L;
+ /**
+ * 公众号微信号
+ */
+ @Element(name = "ToUserName", required = false)
+ private String toUserName;
+
+ /**
+ * 接收模板消息的用户的openid
+ */
+ @Element(name = "FromUserName", required = false)
+ private String fromUserName;
+
+ /**
+ * 创建时间
+ */
+ @Element(name = "CreateTime", required = false)
+ private String createTime;
+
+ /**
+ * 消息类型是事件
+ */
+ @Element(name = "MsgType", required = false)
+ private String msgType;
+
+ /**
+ * 事件为模板消息发送结束
+ */
+ @Element(name = "Event", required = false)
+ private String event;
+
+ /**
+ * 消息id
+ */
+ @Element(name = "MsgID", required = false)
+ private String msgId;
+
+ /**
+ * 发送状态为,成功:success,用户拒绝接收:failed:user block,发送失败(非用户拒绝):failed:system failed
+ */
+ @Element(name = "Status", required = false)
+ private String status;
+}