From c88b047d01361ca4f33f0f43782cef36a6c3f87c Mon Sep 17 00:00:00 2001 From: chenglijuan Date: Fri, 24 Apr 2026 09:31:22 +0800 Subject: [PATCH] =?UTF-8?q?=E5=AE=A1=E6=89=B9=E5=90=8C=E6=84=8F=E5=90=8E?= =?UTF-8?q?=EF=BC=8C=E6=8E=A8=E9=80=81=E8=AE=A2=E9=98=85=E6=B6=88=E6=81=AF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../controller/VisitorApprovalController.java | 68 +------------ .../mapper/VisitApplicationMapper.java | 3 + .../service/AppointmentService.java | 24 ++--- .../service/VisitorApprovalService.java | 98 +++++++++++++++++++ .../service/WxSubscribeMessageService.java | 21 ++-- .../mapper/VisitApplicationMapper.xml | 7 ++ 6 files changed, 132 insertions(+), 89 deletions(-) create mode 100644 src/main/java/com/example/mini_program/service/VisitorApprovalService.java diff --git a/src/main/java/com/example/mini_program/controller/VisitorApprovalController.java b/src/main/java/com/example/mini_program/controller/VisitorApprovalController.java index c41ae1b..98fd336 100644 --- a/src/main/java/com/example/mini_program/controller/VisitorApprovalController.java +++ b/src/main/java/com/example/mini_program/controller/VisitorApprovalController.java @@ -1,58 +1,28 @@ package com.example.mini_program.controller; -import com.example.mini_program.aes.WXBizMsgCrypt; -import com.example.mini_program.mapper.VisitApplicationMapper; -import org.json.JSONObject; -import org.json.XML; +import com.example.mini_program.service.VisitorApprovalService; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.beans.factory.annotation.Value; -import org.springframework.scheduling.annotation.Async; import org.springframework.web.bind.annotation.*; -import java.util.Set; -import java.util.concurrent.ConcurrentHashMap; @RestController @RequestMapping("/visitor") public class VisitorApprovalController { private static final Logger log = LoggerFactory.getLogger(VisitorApprovalController.class); - //发起文件审批时的审批编号,唯一标识一次审批 - private static final Set processedSet = ConcurrentHashMap.newKeySet(); - - @Value("${wx.corp.corpid:}") - private String corpId; - - @Value("${wx.corp.token:}") - private String token; - - @Value("${wx.corp.encodingAESKey:}") - private String encodingAESKey; - - @Value("${wx.corp.approval-template-id:}") - private String templateId; @Autowired - private VisitApplicationMapper visitApplicationMapper; + private VisitorApprovalService visitorApprovalService; /** * 验证URL有效性(GET请求) */ @GetMapping("/approval/callback") public String verifyUrl(@RequestParam(value = "msg_signature", required = false) String msgSignature, @RequestParam(value = "timestamp", required = false) String timestamp, @RequestParam(value = "nonce", required = false) String nonce, @RequestParam(value = "echostr", required = false) String echostr) { - log.info("URL验证请求: msgSignature={}, timestamp={}, nonce={}", msgSignature, timestamp, nonce); - - - try { - WXBizMsgCrypt wxcpt = new WXBizMsgCrypt(token, encodingAESKey, corpId); - return wxcpt.VerifyURL(msgSignature, timestamp, nonce, echostr); - } catch (Exception e) { - log.error("URL验证失败", e); - return "error: " + e.getMessage(); - } + return visitorApprovalService.verifyUrl(msgSignature, timestamp, nonce, echostr); } /** @@ -65,37 +35,7 @@ public class VisitorApprovalController { @RequestBody String requestBody) { System.out.println("----------------------------------"); // 异步处理,立即返回 - processApprovalAsync(msgSignature, timestamp, nonce, requestBody); + visitorApprovalService.processApprovalAsync(msgSignature, timestamp, nonce, requestBody); return "success"; } - /** - * 异步处理审批(解密 + 解析 + 处理) - */ - @Async - public void processApprovalAsync(String msgSignature, String timestamp, String nonce, String requestBody) { - try { - WXBizMsgCrypt wxcpt = new WXBizMsgCrypt(token, encodingAESKey, corpId); - String sMsg = wxcpt.DecryptMsg(msgSignature, timestamp, nonce, requestBody); - JSONObject jsonObject = XML.toJSONObject(sMsg).getJSONObject("xml"); - JSONObject approvalInfo = jsonObject.getJSONObject("ApprovalInfo"); - // 检查是否是目标审批模板且已通过 - if (!templateId.equals(approvalInfo.getString("TemplateId"))) { - log.info("模板【{}】非目标审批模板",approvalInfo.getString("TemplateId") ); - return; - } - log.info("审批回调报文: {}", jsonObject); - //审批编号(唯一标识每次发起的审批) - String spNo = approvalInfo.getString("SpNoStr"); - //审批状态 - int spStatus = approvalInfo.getInt("SpStatus"); - //审批同意 - if (2 == spStatus) { - visitApplicationMapper.updateStatusBySpNo(spNo, "approved", "审批同意"); - }else if(3 == spStatus){ - visitApplicationMapper.updateStatusBySpNo(spNo, "rejected", "审批拒绝"); - } - } catch (Exception e) { - log.error("处理审批失败", e); - } - } } diff --git a/src/main/java/com/example/mini_program/mapper/VisitApplicationMapper.java b/src/main/java/com/example/mini_program/mapper/VisitApplicationMapper.java index 88909a0..57f8144 100644 --- a/src/main/java/com/example/mini_program/mapper/VisitApplicationMapper.java +++ b/src/main/java/com/example/mini_program/mapper/VisitApplicationMapper.java @@ -25,6 +25,9 @@ public interface VisitApplicationMapper { */ List selectListByOpenid(@Param("openid") String openid); + + VisitApplication selectBySpNo(@Param("spNo") String spNo); + /** * 新增预约记录 * diff --git a/src/main/java/com/example/mini_program/service/AppointmentService.java b/src/main/java/com/example/mini_program/service/AppointmentService.java index 72607e5..6246e7f 100644 --- a/src/main/java/com/example/mini_program/service/AppointmentService.java +++ b/src/main/java/com/example/mini_program/service/AppointmentService.java @@ -76,14 +76,14 @@ public class AppointmentService { visitApplicationMapper.insert(record); log.info("创建预约成功, id={}", record.getId()); - // 推送订阅消息 - try { - wxSubscribeMessageService.sendSubscribeMessage( - record.getOpenid(), record.getName(), record.getReason(), - formatVisitTime(record), record.getArea(), "待审核"); - } catch (Exception e) { - log.error("订阅消息推送失败", e); - } +// // 推送订阅消息 +// try { +// wxSubscribeMessageService.sendSubscribeMessage( +// record.getOpenid(), record.getName(), record.getReason(), +// formatVisitTime(record), record.getArea(), "待审核"); +// } catch (Exception e) { +// log.error("订阅消息推送失败", e); +// } return record; } @@ -140,12 +140,4 @@ public class AppointmentService { return true; } - /** 拼接访问日期+时间 */ - private String formatVisitTime(VisitApplication record) { - String time = record.getVisitDate(); - if (record.getVisitTime() != null && !record.getVisitTime().isEmpty()) { - time = record.getVisitDate() + " " + record.getVisitTime(); - } - return time; - } } diff --git a/src/main/java/com/example/mini_program/service/VisitorApprovalService.java b/src/main/java/com/example/mini_program/service/VisitorApprovalService.java new file mode 100644 index 0000000..83a1b04 --- /dev/null +++ b/src/main/java/com/example/mini_program/service/VisitorApprovalService.java @@ -0,0 +1,98 @@ +package com.example.mini_program.service; + +import com.example.mini_program.aes.WXBizMsgCrypt; +import com.example.mini_program.entity.VisitApplication; +import com.example.mini_program.mapper.VisitApplicationMapper; +import lombok.extern.slf4j.Slf4j; +import org.json.JSONObject; +import org.json.XML; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.scheduling.annotation.Async; +import org.springframework.stereotype.Service; + +import java.util.Objects; + +@Slf4j +@Service +public class VisitorApprovalService { + + @Value("${wx.corp.corpid:}") + private String corpId; + + @Value("${wx.corp.token:}") + private String token; + + @Value("${wx.corp.encodingAESKey:}") + private String encodingAESKey; + + @Value("${wx.corp.approval-template-id:}") + private String templateId; + + @Autowired + private VisitApplicationMapper visitApplicationMapper; + @Autowired + private WxSubscribeMessageService wxSubscribeMessageService; + + public String verifyUrl(String msgSignature, String timestamp, String nonce, String echostr) { + log.info("URL验证请求: msgSignature={}, timestamp={}, nonce={}", msgSignature, timestamp, nonce); + try { + WXBizMsgCrypt wxcpt = new WXBizMsgCrypt(token, encodingAESKey, corpId); + return wxcpt.VerifyURL(msgSignature, timestamp, nonce, echostr); + } catch (Exception e) { + log.error("URL验证失败", e); + return "error: " + e.getMessage(); + } + } + + @Async + public void processApprovalAsync(String msgSignature, String timestamp, String nonce, String requestBody) { + try { + WXBizMsgCrypt wxcpt = new WXBizMsgCrypt(token, encodingAESKey, corpId); + String sMsg = wxcpt.DecryptMsg(msgSignature, timestamp, nonce, requestBody); + JSONObject jsonObject = XML.toJSONObject(sMsg).getJSONObject("xml"); + JSONObject approvalInfo = jsonObject.getJSONObject("ApprovalInfo"); + // 检查是否是目标审批模板且已通过 + if (!templateId.equals(approvalInfo.getString("TemplateId"))) { + log.info("模板【{}】非目标审批模板", approvalInfo.getString("TemplateId")); + return; + } + log.info("审批回调报文: {}", jsonObject); + //审批编号(唯一标识每次发起的审批) + String spNo = approvalInfo.getString("SpNoStr"); + //审批状态 + int spStatus = approvalInfo.getInt("SpStatus"); + //根据审批编号查询访客预约信息 + VisitApplication record = visitApplicationMapper.selectBySpNo(spNo); + if (Objects.isNull(record)) { + return; + } + //审批同意 + if (2 == spStatus) { + visitApplicationMapper.updateStatus(record.getId(), "approved", "审批同意"); + //发送订阅消息 + try { + wxSubscribeMessageService.sendSubscribeMessage(record.getOpenid(), record.getName(), record.getReason(), + formatVisitTime(record), record.getArea(), "审批同意"); + } catch (Exception e) { + log.error("订阅消息推送失败", e); + } + } else if (3 == spStatus) { + visitApplicationMapper.updateStatusBySpNo(spNo, "rejected", "审批拒绝"); + } + } catch (Exception e) { + log.error("处理审批失败", e); + } + } + + /** + * 拼接访问日期+时间 + */ + private String formatVisitTime(VisitApplication record) { + String time = record.getVisitDate(); + if (record.getVisitTime() != null && !record.getVisitTime().isEmpty()) { + time = record.getVisitDate() + " " + record.getVisitTime(); + } + return time; + } +} diff --git a/src/main/java/com/example/mini_program/service/WxSubscribeMessageService.java b/src/main/java/com/example/mini_program/service/WxSubscribeMessageService.java index 1e3aab0..bd669cd 100644 --- a/src/main/java/com/example/mini_program/service/WxSubscribeMessageService.java +++ b/src/main/java/com/example/mini_program/service/WxSubscribeMessageService.java @@ -14,13 +14,13 @@ import java.util.Map; /** * 微信小程序订阅消息服务 * 调用微信 /cgi-bin/message/subscribe/send 接口推送订阅消息 - * + *

* 模板字段映射: - * name1 (姓名) → 访客姓名 - * thing3 (事物) → 来访事由 - * date8 (日期) → 预约时间 - * thing10 (事物) → 到访区域 - * phrase18 (短语) → 审批状态 + * name1 (姓名) → 访客姓名 + * thing3 (事物) → 来访事由 + * date8 (日期) → 预约时间 + * thing10 (事物) → 到访区域 + * phrase18 (短语) → 审批状态 */ @Slf4j @Service @@ -38,7 +38,9 @@ public class WxSubscribeMessageService { @Value("${wx.miniapp.subscribe-template-id:}") private String templateId; - /** 获取小程序 access_token */ + /** + * 获取小程序 access_token + */ public String getAccessToken() { String url = String.format(GET_TOKEN_URL, wxMiniAppConfig.getAppid(), wxMiniAppConfig.getSecret()); try { @@ -57,12 +59,11 @@ public class WxSubscribeMessageService { * 所有字段不允许为空字符串(微信返回47003),name类型不接受纯数字 */ public void sendSubscribeMessage(String openid, String visitorName, String reason, - String visitTime, String area, String status) { + String visitTime, String area, String status) { if (templateId == null || templateId.isEmpty()) { log.warn("未配置 subscribe-template-id,跳过订阅消息推送"); return; } - String accessToken = getAccessToken(); String url = String.format(SEND_MSG_URL, accessToken); @@ -82,8 +83,10 @@ public class WxSubscribeMessageService { Map body = new HashMap<>(); body.put("touser", openid); body.put("template_id", templateId); + //点击模板卡片后的跳转页面,仅限本小程序内的页面。 body.put("page", "pages/records/records"); body.put("data", data); + //跳转小程序类型:developer为开发版;trial为体验版;formal为正式版;默认为正式版 body.put("miniprogram_state", "formal"); body.put("lang", "zh_CN"); diff --git a/src/main/resources/mapper/VisitApplicationMapper.xml b/src/main/resources/mapper/VisitApplicationMapper.xml index a6429f3..dec5934 100644 --- a/src/main/resources/mapper/VisitApplicationMapper.xml +++ b/src/main/resources/mapper/VisitApplicationMapper.xml @@ -43,6 +43,13 @@ ORDER BY create_time DESC + +