为用户生成二维码
@PostMapping("/generate")public AjaxResult generateQrcode(@RequestParam Long userId) {try {SysUser user = userService.generateUserQrcode(userId);return AjaxResult.success(user);} catch (Exception e) {return AjaxResult.error("Failed to generate QR code: " + e.getMessage());}}
SysUser generateUserQrcode(Long userId) throws JsonProcessingException;
@Overridepublic SysUser generateUserQrcode(Long userId) throws JsonProcessingException {// 使用合适的 scene_idint sceneId = (int)(userId % 100000); // 确保在范围内// 1. 获取用户信息SysUser user = userMapper.selectUserById(userId);if (user == null) {throw new RuntimeException("用户不存在");}// 2. 调用微信接口生成永久二维码String accessToken = getAccessToken(); // 获取 access_tokenString qrcodeUrl = "https://api.weixin.qq.com/cgi-bin/qrcode/create?access_token=" + accessToken;// 创建永久二维码的请求Map<String, Object> scene = new HashMap<>();scene.put("scene_id", sceneId); // 使用合法的 sceneIdMap<String, Object> actionInfo = new HashMap<>();actionInfo.put("scene", scene);Map<String, Object> requestBodyMap = new HashMap<>();requestBodyMap.put("action_name", "QR_LIMIT_SCENE");requestBodyMap.put("action_info", actionInfo);ObjectMapper objectMapper = new ObjectMapper();String requestBody = objectMapper.writeValueAsString(requestBodyMap);RestTemplate restTemplate = new RestTemplate();String response = restTemplate.postForObject(qrcodeUrl, requestBody, String.class);// 使用 Jackson 解析返回的 JSON 字符串JsonNode jsonResponse = objectMapper.readTree(response);if (!jsonResponse.has("ticket")) {throw new RuntimeException("生成二维码失败,微信接口返回异常:" + jsonResponse.toString());}// 3. 获取二维码的 URL 和 TicketString ticket = jsonResponse.get("ticket").asText();System.out.println(""+ticket);String qrCodeUrl = "https://mp.weixin.qq.com/cgi-bin/showqrcode?ticket=" + ticket;// 4. 更新用户表中的二维码信息user.setQrUrl(qrCodeUrl); // 假设用户表中有 qrCodeUrl 字段// 更新用户表userMapper.updatesUserQrcode(userId, qrCodeUrl);// 5. 返回更新后的用户信息return user;}
@Update("UPDATE sys_user SET qr_url = #{qrUrl} WHERE user_id = #{userId}")void updatesUserQrcode(@Param("userId") Long userId, @Param("qrUrl") String qrUrl);
微信公众平台的 GET 请求,用于验证 token
private static final String TOKEN = "X4yZ7k9B3mVfD1nQ5tG8wL2pR7"; // 与微信公众号后台配置的 Token 保持一致// 微信公众平台的 GET 请求,用于验证 token@GetMapping("/event")public void verifyToken(@RequestParam String signature,@RequestParam String timestamp,@RequestParam String nonce,@RequestParam String echostr,HttpServletResponse response) {System.out.println("微信官方回调了我的这个接口");try {// 1. 将 token, timestamp, nonce 按字典序排序String[] arr = {TOKEN, timestamp, nonce};Arrays.sort(arr);// 2. 将三个参数拼接成字符串并进行 SHA1 加密StringBuilder content = new StringBuilder();for (String s : arr) {content.append(s);}String tempSignature = DigestUtils.sha1Hex(content.toString());// 3. 校验签名是否来自微信if (tempSignature.equals(signature)) {response.getWriter().write(echostr); // 验证成功,返回 echostr} else {response.getWriter().write("fail"); // 验证失败}} catch (IOException e) {e.printStackTrace();}}
微信公众平台的 POST 请求,接收事件推送
@PostMapping("/event")public void handleWechatEvents(@RequestBody String xmlData, HttpServletResponse response) {try {// 解析微信推送的XML数据Document document = DocumentHelper.parseText(xmlData);Element root = document.getRootElement();// 获取消息类型和事件类型String msgType = root.elementText("MsgType");String event = root.elementText("Event");String openId = root.elementText("FromUserName"); // 提取用户的 OpenID// 处理事件推送if ("event".equals(msgType)) {if ("subscribe".equals(event)) {// 处理用户首次关注公众号事件String eventKey = root.elementText("EventKey");if (eventKey != null && eventKey.startsWith("qrscene_")) {// 提取场景值中的 userIdString userId = eventKey.replace("qrscene_", "");System.out.println("用户通过二维码关注公众号,OpenID: " + openId + ", 用户ID: " + userId);handleSubscribeEvent(openId, userId);//根据userId 更新openId// 使用 MyBatis 查询后四位匹配的用户SysUser user = userService.queryByUserIdSuffix(userId);if(user != null){Long userIds = user.getUserId();//根据userId 更新openIdboolean flag = userService.updateByuserId(userIds,openId);System.out.println("userId1"+userIds);}} else {System.out.println("用户直接关注了公众号,OpenID: " + openId);handleSubscribeEvent(openId, null); // 如果没有场景值,userId 为 null}} else if ("unsubscribe".equals(event)) {// 处理用户取消关注事件System.out.println("用户取消关注公众号,OpenID: " + openId);handleUnsubscribeEvent(openId);} else if ("SCAN".equals(event)) {// 处理已关注用户扫描二维码事件String eventKey = root.elementText("EventKey");System.out.println("已关注用户扫描二维码,OpenID: " + openId + ", 场景值: " + eventKey);handleScanEvent(openId, eventKey);}}// 回复微信服务器,防止重试response.getWriter().write("success");} catch (Exception e) {e.printStackTrace();try {response.getWriter().write("fail");} catch (IOException ioException) {ioException.printStackTrace();}}}// 处理首次关注事件(附带二维码参数)private void handleSubscribeEvent(String openId, String userId) {if (userId != null) {// 处理通过带参数二维码关注的用户System.out.println("欢迎通过二维码关注的用户,OpenID: " + openId + ", 用户ID: " + userId);// 在这里可以将 openId 和 userId 保存到数据库,或者发送欢迎消息saveUserInfo(openId, userId);} else {// 处理直接关注的用户System.out.println("欢迎直接关注的用户,OpenID: " + openId);saveUserInfo(openId, null); // 如果没有场景值,可以不保存 userId}// 在这里可以发送欢迎消息}// 处理取消关注事件private void handleUnsubscribeEvent(String openId) {System.out.println("用户取消关注,OpenID: " + openId);// 在这里更新数据库,记录用户的取消关注行为updateUserStatus(openId, false);}// 处理已关注用户扫描二维码事件private void handleScanEvent(String openId, String eventKey) {String userId = extractUserIdFromEventKey(eventKey); // 提取用户IDSystem.out.println("已关注用户扫描二维码,OpenID: " + openId + ", 场景值: " + eventKey);System.out.println("已关注用户,场景值中提取的用户ID: " + userId);// 根据场景值和用户ID执行相应的业务逻辑saveScanEventInfo(openId, userId);}// 提取 userId 方法private String extractUserIdFromEventKey(String eventKey) {if (eventKey != null && !eventKey.isEmpty()) {try {// 尝试提取 userId (假设 eventKey 是数字形式的用户ID)return eventKey.replace("qrscene_", "");} catch (Exception e) {System.out.println("提取 userId 时发生错误: " + e.getMessage());}}return "未知用户ID";}// 模拟保存用户信息到数据库private void saveUserInfo(String openId, String userId) {// 在这里执行将 openId 和 userId 保存到数据库的操作System.out.println("保存用户信息到数据库,OpenID: " + openId + ", 用户ID: " + userId);}// 模拟更新用户状态(取消关注)private void updateUserStatus(String openId, boolean isActive) {// 在这里执行更新数据库中用户状态的操作System.out.println("更新用户状态为 " + (isActive ? "活跃" : "取消关注") + ",OpenID: " + openId);}// 保存二维码扫描事件的信息private void saveScanEventInfo(String openId, String userId) {// 在这里执行保存已关注用户扫描二维码后的事件信息的操作System.out.println("保存二维码扫描事件信息,OpenID: " + openId + ", 用户ID: " + userId);}