Files
core/.workbuddy/memory/2026-04-07.md
赵忠林 ed9c59dae6 fix(qrLogin): 修正二维码场景值传递问题
- 将 scene 参数由 "token=" + token 改为直接传 token
- 确保 scene 为字符串且长度不超过 32 字符
- 便于小程序端通过 router.params.scene 获取 token
- 优化注释说明二维码参数限制和使用方式
2026-04-07 21:14:44 +08:00

8.5 KiB
Raw Blame History

2026-04-07 工作记录

微信扫码登录问题修复

  1. 修复了UserSyncService中tenant_id字段名问题从tenantId改为tenant_id
  2. 同时发送两种格式的tenant_id字段确保兼容性
  3. 修改了WxOfficialController在同步前从数据库重新加载用户对象
  4. 添加了详细的调试日志便于问题排查

待解决问题

  1. websopy侧app_user_cache同步失败tenant_id为null
  2. 扫码成功后需跳转到强制绑定手机号页面
  3. 注册成功后应跳转到控制台/console

websopy-pc前端修改需求分析

  1. 状态检查逻辑更新需处理新的nextAction字段bind_phone, redirect, login等
  2. 新增绑定手机号页面:用于新用户绑定手机号流程
  3. 页面跳转逻辑:登录成功/绑定成功后跳转到/console
  4. API调用更新:适应新的响应字段格式

前端代码已完成的修改

  1. API接口修改

    • 更新QRLoginStatusResult接口新增nextAction、redirectUrl、successMessage、needBindPhone等字段
    • 修改checkQRLoginStatus函数使用真实后端API调用
    • 新增bindPhoneForQrLogin函数处理绑定手机号API调用
    • 修改generateQRLoginToken函数使用真实后端API调用
  2. 状态管理修改

    • 更新auth store接口添加bindPhoneForQRLogin方法
    • 修改checkQRStatus方法支持新的返回字段处理
    • 添加绑定手机号处理逻辑
  3. 组件修改

    • 创建BindPhone组件用于处理需要绑定手机号的场景
    • 修改QRLogin组件支持根据nextAction显示不同UI自动处理绑定手机号流程
    • 组件现在可以正确处理:
      • nextAction: 'bind_phone' → 显示绑定手机号表单
      • nextAction: 'redirect' → 自动跳转到/console
      • needBindPhone: true → 显示绑定提示
  4. 完整流程支持

    • 用户扫码登录 → 后端返回nextAction: 'bind_phone' → 前端显示绑定手机号页面
    • 用户输入手机号和验证码 → 调用绑定手机号API → 绑定成功后自动登录并跳转/console
    • 用户已有手机号 → 后端返回nextAction: 'redirect' → 前端自动跳转到/console

后端修改完成

  1. QrLoginStatusResponse新增字段
    • nextAction: 下一步操作指示
    • redirectUrl: 跳转URL当nextAction为redirect时
    • successMessage: 成功消息
  2. QrLoginServiceImpl逻辑更新
    • 用户没有手机号时nextAction设为bind_phone
    • 用户有手机号且登录成功时nextAction设为redirectredirectUrl设为/console

扫码登录用户同步时机修改 (01:58)

修改内容

  1. WxOfficialController.java - 移除新用户注册时立即同步的代码

    • processWxUser() 方法中,新用户创建后不再立即同步到 websopy
    • findOrCreateUserForOauth() 方法中同样处理
  2. QrLoginServiceImpl.java - 在绑定手机号成功后同步

    • 新增 UserSyncService 注入
    • 在 bindPhone() 方法中,绑定手机号成功后从数据库重新加载用户并同步

目的

确保用户数据同步到 websopy 时,手机号字段已有值,避免无效的缓存数据。

MQ消息队列实现 (02:40)

创建的文件

  1. SyncMessage.java - 统一消息实体

    • 位置: com.gxwebsoft.common.mq.message
    • 支持 USER_SYNC, TENANT_SYNC 等消息类型
    • 支持 CREATE, UPDATE, DELETE 事件类型
  2. SyncMessageProducer.java - 消息生产者接口

    • 位置: com.gxwebsoft.common.mq.producer
    • 预留抽象层便于将来切换到RocketMQ
  3. RabbitMQConfig.java - RabbitMQ配置类

    • 位置: com.gxwebsoft.common.mq.config
    • 定义交换机、队列、死信队列
    • 配置JSON序列化
  4. RabbitMQSyncProducer.java - RabbitMQ生产者实现

    • 位置: com.gxwebsoft.common.mq.producer.impl
    • 实现确认回调和Return回调
  5. UserSyncConsumer.java - 用户同步消费者

    • 位置: com.gxwebsoft.common.mq.consumer
    • 监听用户同步消息调用UserSyncService同步到websopy
    • 支持重试机制和死信队列

修改的文件

  1. pom.xml - 添加 spring-boot-starter-amqp 依赖
  2. UserSyncService.java - 添加Map参数的重载方法
  3. QrLoginServiceImpl.java - 改用MQ发送消息
  4. application.yml - 添加RabbitMQ配置

使用方式

配置 sync.mq.enabled: false 可临时禁用MQ回退到原有直接同步方式。

websopy 端 MQ 消费者实现 (02:50)

创建的文件

  1. SyncMessage.java - websopy 端消息实体

    • 位置: com.gxwebsoft.common.mq.message
    • 简化版,复用 server-api 发来的消息格式
  2. RabbitMQConfig.java - websopy 端 RabbitMQ 配置

    • 位置: com.gxwebsoft.common.mq.config
    • 配置交换机、队列、死信队列
  3. SyncMessageConsumer.java - websopy 端消息消费者

    • 位置: com.gxwebsoft.common.mq.consumer
    • 监听 USER_SYNC 消息,调用 AppUserCacheService 保存/更新/删除用户

修改的文件

  1. pom.xml - 添加 spring-boot-starter-amqp 依赖
  2. application.yml - 添加 RabbitMQ 连接配置和开关

工作流程

server-api (生产者) -> RabbitMQ -> websopy-java (消费者) -> AppUserCacheService

Spring Boot启动错误修复 (03:01)

问题描述

服务器启动失败,错误信息显示objectMapper bean定义冲突

The bean 'objectMapper', defined in class path resource [com/gxwebsoft/common/mq/config/RabbitMQConfig.class], could not be registered. 
A bean with that name has already been defined in class path resource [com/gxwebsoft/common/core/config/JacksonConfig.class] and overriding is disabled.

根本原因

  1. JacksonConfig.java 定义了 @Primary objectMapper() bean第22行
  2. RabbitMQConfig.javamessageConverter(ObjectMapper objectMapper) 方法会被Spring误认为正在定义另一个objectMapper bean
  3. Spring Boot 2.5.15默认禁止bean定义覆盖

修复方案(双保险)

  1. 代码修复修改RabbitMQConfig.java中的messageConverter方法

    // 修改前(有问题的参数注入):
    @Bean
    public MessageConverter messageConverter(ObjectMapper objectMapper) {
        return new Jackson2JsonMessageConverter(objectMapper);
    }
    
    // 修改后直接在方法内创建ObjectMapper
    @Bean
    public MessageConverter messageConverter() {
        ObjectMapper objectMapper = new ObjectMapper();
        objectMapper.registerModule(new JavaTimeModule());
        objectMapper.disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS);
        objectMapper.disable(SerializationFeature.WRITE_DATE_TIMESTAMPS_AS_NANOSECONDS);
        objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
        return new Jackson2JsonMessageConverter(objectMapper);
    }
    
  2. 配置修复在所有application配置文件中启用bean定义覆盖

    • application.yml: 添加 spring.main.allow-bean-definition-overriding: true
    • application-dev.yml: 在现有的 spring.main.allow-circular-references 下添加
    • application-prod.yml: 在数据源配置区域添加

影响

修复后服务器应能正常启动MQ消息队列和扫码登录功能均可正常工作。

技术细节

  • 问题源于Spring的bean解析机制带有参数的@Bean方法会被Spring尝试解析参数
  • 修改后的方案消除了参数依赖避免Spring误解
  • 启用bean定义覆盖作为安全备份确保即使有其他bean冲突也能启动

Hutool库API兼容性修复 (21:07)

问题描述

编译错误:HttpResponse 类没有 bytes() 方法

/Users/gxwebsoft/JAVA/com.gxwebsoft.core/src/main/java/com/gxwebsoft/auto/service/impl/QrLoginServiceImpl.java:156:19
java: cannot find symbol
  symbol:   method bytes()
  location: class cn.hutool.http.HttpResponse

原因分析

  • 项目使用的是Hutool 5.8.25版本
  • 在Hutool 5.x版本中HttpResponse类没有bytes()方法
  • 正确的方法应该是bodyBytes()用于获取二进制响应,或body()用于获取字符串响应

修复方法

修改 QrLoginServiceImpl.java 第156行

// 修改前错误的API
.execute().bytes();

// 修改后正确的API
.execute().bodyBytes();

影响

修复后项目可以成功编译,微信小程序码生成功能可以正常工作。

版本兼容性说明

  • Hutool 4.x版本可能支持.bytes()方法
  • Hutool 5.x版本使用.bodyBytes().body()方法
  • 项目中使用的是Hutool 5.8.25应保持API一致性