- 将 scene 参数由 "token=" + token 改为直接传 token - 确保 scene 为字符串且长度不超过 32 字符 - 便于小程序端通过 router.params.scene 获取 token - 优化注释说明二维码参数限制和使用方式
8.5 KiB
2026-04-07 工作记录
微信扫码登录问题修复
- 修复了UserSyncService中tenant_id字段名问题(从tenantId改为tenant_id)
- 同时发送两种格式的tenant_id字段确保兼容性
- 修改了WxOfficialController,在同步前从数据库重新加载用户对象
- 添加了详细的调试日志便于问题排查
待解决问题
- websopy侧app_user_cache同步失败(tenant_id为null)
- 扫码成功后需跳转到强制绑定手机号页面
- 注册成功后应跳转到控制台/console
websopy-pc前端修改需求分析
- 状态检查逻辑更新:需处理新的nextAction字段(bind_phone, redirect, login等)
- 新增绑定手机号页面:用于新用户绑定手机号流程
- 页面跳转逻辑:登录成功/绑定成功后跳转到/console
- API调用更新:适应新的响应字段格式
前端代码已完成的修改
-
API接口修改:
- 更新QRLoginStatusResult接口,新增nextAction、redirectUrl、successMessage、needBindPhone等字段
- 修改checkQRLoginStatus函数,使用真实后端API调用
- 新增bindPhoneForQrLogin函数,处理绑定手机号API调用
- 修改generateQRLoginToken函数,使用真实后端API调用
-
状态管理修改:
- 更新auth store接口,添加bindPhoneForQRLogin方法
- 修改checkQRStatus方法,支持新的返回字段处理
- 添加绑定手机号处理逻辑
-
组件修改:
- 创建BindPhone组件:用于处理需要绑定手机号的场景
- 修改QRLogin组件:支持根据nextAction显示不同UI,自动处理绑定手机号流程
- 组件现在可以正确处理:
- nextAction: 'bind_phone' → 显示绑定手机号表单
- nextAction: 'redirect' → 自动跳转到/console
- needBindPhone: true → 显示绑定提示
-
完整流程支持:
- 用户扫码登录 → 后端返回nextAction: 'bind_phone' → 前端显示绑定手机号页面
- 用户输入手机号和验证码 → 调用绑定手机号API → 绑定成功后自动登录并跳转/console
- 用户已有手机号 → 后端返回nextAction: 'redirect' → 前端自动跳转到/console
后端修改完成
- QrLoginStatusResponse新增字段:
- nextAction: 下一步操作指示
- redirectUrl: 跳转URL(当nextAction为redirect时)
- successMessage: 成功消息
- QrLoginServiceImpl逻辑更新:
- 用户没有手机号时,nextAction设为bind_phone
- 用户有手机号且登录成功时,nextAction设为redirect,redirectUrl设为/console
扫码登录用户同步时机修改 (01:58)
修改内容
-
WxOfficialController.java - 移除新用户注册时立即同步的代码
- processWxUser() 方法中,新用户创建后不再立即同步到 websopy
- findOrCreateUserForOauth() 方法中同样处理
-
QrLoginServiceImpl.java - 在绑定手机号成功后同步
- 新增 UserSyncService 注入
- 在 bindPhone() 方法中,绑定手机号成功后从数据库重新加载用户并同步
目的
确保用户数据同步到 websopy 时,手机号字段已有值,避免无效的缓存数据。
MQ消息队列实现 (02:40)
创建的文件
-
SyncMessage.java - 统一消息实体
- 位置:
com.gxwebsoft.common.mq.message - 支持 USER_SYNC, TENANT_SYNC 等消息类型
- 支持 CREATE, UPDATE, DELETE 事件类型
- 位置:
-
SyncMessageProducer.java - 消息生产者接口
- 位置:
com.gxwebsoft.common.mq.producer - 预留抽象层,便于将来切换到RocketMQ
- 位置:
-
RabbitMQConfig.java - RabbitMQ配置类
- 位置:
com.gxwebsoft.common.mq.config - 定义交换机、队列、死信队列
- 配置JSON序列化
- 位置:
-
RabbitMQSyncProducer.java - RabbitMQ生产者实现
- 位置:
com.gxwebsoft.common.mq.producer.impl - 实现确认回调和Return回调
- 位置:
-
UserSyncConsumer.java - 用户同步消费者
- 位置:
com.gxwebsoft.common.mq.consumer - 监听用户同步消息,调用UserSyncService同步到websopy
- 支持重试机制和死信队列
- 位置:
修改的文件
- pom.xml - 添加 spring-boot-starter-amqp 依赖
- UserSyncService.java - 添加Map参数的重载方法
- QrLoginServiceImpl.java - 改用MQ发送消息
- application.yml - 添加RabbitMQ配置
使用方式
配置 sync.mq.enabled: false 可临时禁用MQ,回退到原有直接同步方式。
websopy 端 MQ 消费者实现 (02:50)
创建的文件
-
SyncMessage.java - websopy 端消息实体
- 位置:
com.gxwebsoft.common.mq.message - 简化版,复用 server-api 发来的消息格式
- 位置:
-
RabbitMQConfig.java - websopy 端 RabbitMQ 配置
- 位置:
com.gxwebsoft.common.mq.config - 配置交换机、队列、死信队列
- 位置:
-
SyncMessageConsumer.java - websopy 端消息消费者
- 位置:
com.gxwebsoft.common.mq.consumer - 监听 USER_SYNC 消息,调用 AppUserCacheService 保存/更新/删除用户
- 位置:
修改的文件
- pom.xml - 添加 spring-boot-starter-amqp 依赖
- 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.
根本原因
- JacksonConfig.java 定义了
@Primary objectMapper()bean(第22行) - RabbitMQConfig.java 的
messageConverter(ObjectMapper objectMapper)方法会被Spring误认为正在定义另一个objectMapperbean - Spring Boot 2.5.15默认禁止bean定义覆盖
修复方案(双保险)
-
代码修复:修改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); } -
配置修复:在所有application配置文件中启用bean定义覆盖
- application.yml: 添加
spring.main.allow-bean-definition-overriding: true - application-dev.yml: 在现有的
spring.main.allow-circular-references下添加 - application-prod.yml: 在数据源配置区域添加
- application.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一致性