20-修改商户用户信息接口.md 18 KB

Web端修改商户用户信息接口文档

模块概述

本模块提供商户用户信息修改功能,支持修改昵称、姓名、身份证号、账号简介、头像等个人信息。接口采用部分更新策略,只更新提供的非空字段。


接口信息

修改商户用户信息

接口详情

  • 接口名称: 修改商户用户信息
  • 接口路径: POST /merchantUser/updateMerchantUserInfo
  • 请求方式: POST
  • Content-Type: application/json
  • 接口描述: 修改指定商户用户的个人信息,支持部分字段更新
  • 登录验证: ✅ 需要(使用 @LoginRequired 注解)

请求参数

请求体(JSON格式)

参数名 类型 必填 说明 示例值
id Integer 用户ID 12345
nickName String 昵称 "小明的店铺"
name String 真实姓名 "张三"
idCard String 身份证号 "110101199001011234"
accountBlurb String 账号简介 "专业提供优质服务"
headImg String 头像URL "https://example.com/avatar.jpg"

注意:

  • id 字段必须提供
  • 其他字段均为可选,只需提供需要修改的字段
  • 未提供的字段不会被更新

请求示例

示例1: 修改昵称和头像

POST /merchantUser/updateMerchantUserInfo
Content-Type: application/json
Authorization: Bearer YOUR_TOKEN

{
    "id": 12345,
    "nickName": "小明的店铺",
    "headImg": "https://example.com/avatar.jpg"
}
curl -X POST "http://localhost:8080/merchantUser/updateMerchantUserInfo" \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer YOUR_TOKEN" \
  -d '{
    "id": 12345,
    "nickName": "小明的店铺",
    "headImg": "https://example.com/avatar.jpg"
  }'

示例2: 修改真实姓名和身份证号

{
    "id": 12345,
    "name": "张三",
    "idCard": "110101199001011234"
}

示例3: 只修改账号简介

{
    "id": 12345,
    "accountBlurb": "专业提供优质服务,欢迎光临"
}

示例4: 修改所有信息

{
    "id": 12345,
    "nickName": "小明的店铺",
    "name": "张三",
    "idCard": "110101199001011234",
    "accountBlurb": "专业提供优质服务",
    "headImg": "https://example.com/avatar.jpg"
}

响应参数

成功响应

{
    "code": 200,
    "success": true,
    "data": true,
    "msg": "修改成功"
}

响应字段说明

字段名 类型 说明
code Integer 状态码, 200表示成功
success Boolean 是否成功
data Boolean 修改结果, true表示成功
msg String 提示信息

失败响应

1. 用户ID为空

{
    "code": 500,
    "success": false,
    "data": null,
    "msg": "修改失败:用户ID不能为空"
}

2. 修改失败(数据库更新失败)

{
    "code": 500,
    "success": false,
    "data": false,
    "msg": "修改失败"
}

3. 未登录或登录过期

{
    "code": 500,
    "success": false,
    "data": null,
    "msg": "请先登录"
}

4. 系统异常

{
    "code": 500,
    "success": false,
    "data": null,
    "msg": "修改失败:{异常信息}"
}

业务逻辑说明

更新流程

┌─────────────────────────────────────────────┐
│  1. 接收请求参数                              │
│  StoreUser对象(包含id和待更新字段)         │
└─────────────────┬───────────────────────────┘
                  ↓
┌─────────────────────────────────────────────┐
│  2. 登录验证(AOP切面)                      │
│  - 验证Token                                 │
│  - 验证用户类型                              │
└─────────────────┬───────────────────────────┘
                  ↓
┌─────────────────────────────────────────────┐
│  3. 参数验证                                  │
│  检查用户ID是否为空                          │
└─────────────────┬───────────────────────────┘
                  ↓
┌─────────────────────────────────────────────┐
│  4. 构建更新对象                              │
│  创建新的StoreUser对象                       │
│  设置id字段                                  │
└─────────────────┬───────────────────────────┘
                  ↓
┌─────────────────────────────────────────────┐
│  5. 部分字段更新逻辑                          │
│  IF nickName != null AND nickName != ""      │
│    THEN 设置nickName                         │
│  IF name != null AND name != ""              │
│    THEN 设置name                             │
│  IF idCard != null AND idCard != ""          │
│    THEN 设置idCard                           │
│  IF accountBlurb != null AND accountBlurb != ""│
│    THEN 设置accountBlurb                     │
│  IF headImg != null AND headImg != ""        │
│    THEN 设置headImg                          │
└─────────────────┬───────────────────────────┘
                  ↓
┌─────────────────────────────────────────────┐
│  6. 执行数据库更新                            │
│  storeUserMapper.updateById(storeUser)       │
└─────────────────┬───────────────────────────┘
                  ↓
┌─────────────────────────────────────────────┐
│  7. 返回结果                                  │
│  updateResult > 0 → 成功                     │
│  updateResult = 0 → 失败                     │
└─────────────────────────────────────────────┘

部分更新策略

接口采用部分更新(Partial Update)策略:

  1. 只更新提供的字段:

    • 只有非空(not null 且 not empty)的字段才会被更新
    • 未提供的字段保持原值不变
  2. 空字符串处理:

    • 空字符串 "" 被视为无效值,不会更新数据库
    • 使用 StringUtils.isNotEmpty() 进行判断
  3. Null值处理:

    • null 值的字段不会被更新
    • 如果需要清空某个字段,需要在业务层面另行处理

字段说明

1. nickName(昵称)

  • 用途: 商户用户的显示名称
  • 示例: "小明的店铺"、"张三商户"
  • 约束: 字符串类型,可为中英文

2. name(真实姓名)

  • 用途: 商户的真实姓名
  • 示例: "张三"、"李四"
  • 约束: 通常用于实名认证

3. idCard(身份证号)

  • 用途: 商户的身份证号码
  • 示例: "110101199001011234"
  • 约束: 18位身份证号
  • 安全: 敏感信息,需要加密存储和传输

4. accountBlurb(账号简介)

  • 用途: 商户账号的简要介绍
  • 示例: "专业提供优质服务"
  • 约束: 文本类型,可较长

5. headImg(头像)


数据库操作

涉及的表

store_user(商户用户表)

更新SQL:

UPDATE store_user
SET 
    nick_name = ? (如果提供),
    name = ? (如果提供),
    id_card = ? (如果提供),
    account_blurb = ? (如果提供),
    head_img = ? (如果提供)
WHERE id = ?

说明:

  • 使用 MyBatis-Plus 的 updateById 方法
  • 只更新非空字段(动态SQL)
  • 自动填充更新时间(如果配置了自动填充)

业务场景

场景1: 新用户完善个人信息

背景: 用户刚注册,需要完善个人信息

请求:

{
    "id": 12345,
    "nickName": "小明的店铺",
    "name": "张三",
    "idCard": "110101199001011234",
    "accountBlurb": "专业提供优质服务"
}

预期:

  • 所有提供的字段都被成功更新
  • 返回 "修改成功"

场景2: 用户修改头像

背景: 用户只想更换头像

请求:

{
    "id": 12345,
    "headImg": "https://example.com/new_avatar.jpg"
}

预期:

  • 只有 headImg 字段被更新
  • 其他字段保持不变
  • 返回 "修改成功"

场景3: 用户修改昵称

背景: 用户想要更改显示昵称

请求:

{
    "id": 12345,
    "nickName": "新店铺名称"
}

预期:

  • 只有 nickName 字段被更新
  • 返回 "修改成功"

场景4: 批量修改多个字段

背景: 用户一次性修改多个信息

请求:

{
    "id": 12345,
    "nickName": "小明的优质店铺",
    "accountBlurb": "专业提供优质服务,欢迎光临",
    "headImg": "https://example.com/avatar.jpg"
}

预期:

  • 三个字段都被成功更新
  • 返回 "修改成功"

场景5: ID不存在

背景: 提供的用户ID在数据库中不存在

请求:

{
    "id": 999999,
    "nickName": "测试店铺"
}

预期:

  • 数据库更新影响行数为0
  • 返回 "修改失败"

场景6: 未提供ID

背景: 请求中没有提供用户ID

请求:

{
    "nickName": "测试店铺"
}

预期:

  • 抛出异常:"用户ID不能为空"
  • 返回错误信息

安全考虑

1. 登录验证

接口使用 @LoginRequired 注解进行登录验证:

  • ✅ 验证JWT Token的有效性
  • ✅ 验证用户类型为 storePlatform
  • ✅ 检查Token是否在Redis中存在(未过期/未注销)

2. 身份验证

建议:

  • 前端应验证当前登录用户只能修改自己的信息
  • 可以在业务层添加用户ID匹配验证
  • 管理员可能需要特殊权限修改其他用户信息

3. 数据验证

建议:

  • 身份证号格式验证(18位数字)
  • 昵称长度限制(如1-20个字符)
  • 头像URL格式验证
  • 防止SQL注入(MyBatis-Plus已处理)
  • 防止XSS攻击(前端需处理)

4. 敏感信息

身份证号:

  • ⚠️ 高度敏感信息
  • 建议加密存储
  • 日志中应脱敏显示
  • HTTPS传输

日志记录

日志级别

接口记录了详细的日志信息:

// INFO级别 - 请求日志
log.info("MerchantUserController.updateMerchantUserInfo?storeUser={}", storeUser);

// INFO级别 - 业务开始
log.info("MerchantUserServiceImpl.updateMerchantUserInfo - 开始修改商户用户信息: userId={}", userId);

// DEBUG级别 - 字段更新
log.debug("MerchantUserServiceImpl.updateMerchantUserInfo - 更新昵称: {}", nickName);

// INFO级别 - 业务完成
log.info("MerchantUserServiceImpl.updateMerchantUserInfo - 修改完成: userId={}, success={}", userId, success);

// ERROR级别 - 异常日志
log.error("MerchantUserController.updateMerchantUserInfo ERROR: {}", e.getMessage(), e);

日志脱敏

建议对敏感字段进行脱敏:

// 身份证号脱敏
String maskedIdCard = idCard.replaceAll("(\\d{6})\\d{8}(\\d{4})", "$1********$2");
log.debug("更新身份证号: {}", maskedIdCard); // 110101********1234

异常处理

异常场景

异常情况 HTTP状态码 返回code 返回msg
用户ID为空 200 500 "修改失败:用户ID不能为空"
数据库更新失败 200 500 "修改失败"
未登录 200 500 "请先登录"
系统异常 200 500 "修改失败:{异常信息}"

测试用例

测试场景1: 正常修改单个字段

前置条件:

  • 用户已登录
  • 用户ID存在

请求:

{
    "id": 12345,
    "nickName": "新昵称"
}

预期结果:

  • HTTP 200
  • 返回 {"success": true, "msg": "修改成功"}
  • 数据库中该用户的 nick_name 字段被更新

测试场景2: 正常修改多个字段

请求:

{
    "id": 12345,
    "nickName": "新昵称",
    "name": "新姓名",
    "headImg": "https://example.com/new.jpg"
}

预期结果:

  • 所有提供的字段都被更新
  • 其他字段保持不变

测试场景3: 用户ID不存在

请求:

{
    "id": 999999,
    "nickName": "测试"
}

预期结果:

  • HTTP 200
  • 返回 {"success": false, "msg": "修改失败"}
  • 数据库无变化

测试场景4: 用户ID为空

请求:

{
    "nickName": "测试"
}

预期结果:

  • HTTP 200
  • 返回 {"success": false, "msg": "修改失败:用户ID不能为空"}

测试场景5: 未登录

前置条件:

  • 不携带Token或Token无效

预期结果:

  • HTTP 200
  • 返回 {"success": false, "msg": "请先登录"}

测试场景6: 空字符串字段

请求:

{
    "id": 12345,
    "nickName": "",
    "name": "张三"
}

预期结果:

  • nickName 不会被更新(空字符串被忽略)
  • name 会被更新为 "张三"
  • 返回 "修改成功"

性能优化

1. 数据库优化

确保 store_user 表的主键有索引:

-- 主键索引(通常自动创建)
ALTER TABLE store_user ADD PRIMARY KEY (id);

2. 更新策略

  • ✅ 使用 MyBatis-Plus 的 updateById 方法(基于主键更新,性能高)
  • ✅ 动态SQL,只更新非空字段
  • ✅ 避免全表扫描

3. 缓存策略

如果用户信息频繁读取,建议:

  • 使用Redis缓存用户信息
  • 更新成功后清除对应的缓存
  • 缓存Key: store:user:{userId}

    // 伪代码示例
    @Override
    public boolean updateMerchantUserInfo(StoreUser storeUser) {
    boolean success = storeUserMapper.updateById(storeUser);
    if (success) {
        // 清除缓存
        redisTemplate.delete("store:user:" + storeUser.getId());
    }
    return success;
    }
    

注意事项

1. 部分更新

  • ⚠️ 接口只更新提供的非空字段
  • ⚠️ 未提供的字段保持原值
  • ⚠️ 空字符串 "" 不会更新数据库

2. 必填字段

  • ⚠️ id 字段必须提供
  • ⚠️ 至少提供一个需要更新的字段(否则更新无意义)

3. 字段长度

建议在前端和后端都进行字段长度验证:

  • 昵称: 1-50个字符
  • 姓名: 2-20个字符
  • 身份证号: 18位
  • 账号简介: 0-200个字符

4. 敏感信息

  • ⚠️ 身份证号是敏感信息,需要特别保护
  • ⚠️ 建议加密存储
  • ⚠️ 日志中应脱敏
  • ⚠️ 使用HTTPS传输

5. 并发更新

在高并发场景下,可能需要考虑:

  • 使用乐观锁(version字段)
  • 使用分布式锁
  • 处理更新冲突

迁移说明

原接口(app端)

  • 服务: alien-store
  • 路径: /alienStore/store/user/setUserInfo
  • Controller: StoreUserController
  • Service: StoreUserService.setUserInfo()

新接口(web端)

  • 服务: alien-store-platform
  • 路径: /merchantUser/updateMerchantUserInfo
  • Controller: MerchantUserController
  • Service: MerchantUserService.updateMerchantUserInfo()

差异说明

项目 app端 web端 说明
接口路径 /setUserInfo /updateMerchantUserInfo 更符合web端命名规范
登录验证 无明确标注 ✅ 有(@LoginRequired 增加统一登录验证
参数类型 StoreUser StoreUser 保持一致
返回类型 R<Boolean> R<Boolean> 保持一致
业务逻辑 完全复用
日志记录 基础 详细 增强日志记录

复用的核心组件

  1. Mapper: StoreUserMapper
  2. Entity: StoreUser
  3. Util: StringUtils (Apache Commons Lang3)

扩展功能建议

1. 字段验证

可以添加更详细的字段验证:

// 身份证号验证
if (StringUtils.isNotEmpty(idCard)) {
    if (!IdCardValidator.isValid(idCard)) {
        throw new RuntimeException("身份证号格式不正确");
    }
}

// 昵称长度验证
if (StringUtils.isNotEmpty(nickName)) {
    if (nickName.length() > 50) {
        throw new RuntimeException("昵称长度不能超过50个字符");
    }
}

2. 审计日志

记录用户信息修改的审计日志:

// 保存修改记录
AuditLog auditLog = new AuditLog();
auditLog.setUserId(storeUser.getId());
auditLog.setAction("UPDATE_USER_INFO");
auditLog.setDetails(JSONObject.toJSONString(storeUser));
auditLog.setOperateTime(new Date());
auditLogMapper.insert(auditLog);

3. 变更通知

当关键信息修改时,发送通知:

// 如果修改了身份证号,发送通知
if (StringUtils.isNotEmpty(storeUser.getIdCard())) {
    notificationService.send(userId, "您的身份证号已更新");
}

更新日志

2025-11-17

新增接口:

  • POST /merchantUser/updateMerchantUserInfo - 修改商户用户信息

核心功能:

  • ✅ 支持部分字段更新
  • ✅ 动态SQL,只更新非空字段
  • ✅ 登录验证(@LoginRequired
  • ✅ 详细日志记录
  • ✅ 完善异常处理
  • ✅ 参数验证(用户ID)

涉及文件:

  • MerchantUserController.java - 更新
  • MerchantUserService.java - 更新
  • MerchantUserServiceImpl.java - 更新

代码质量:

  • ✅ Linter检查:无错误
  • ✅ 日志记录:详细
  • ✅ 异常处理:完善
  • ✅ 代码注释:完整

开发人员: ssk


文档版本: v1.0
最后更新: 2025-11-17
维护人员: ssk