# Web端检查支付密码接口文档

## 模块概述

本模块提供商户用户支付密码检查功能，支持检查用户是否设置了支付密码，以及可选的密码验证功能。

---

## 接口信息

### 检查是否设置支付密码

#### 接口详情

- **接口名称**: 检查是否设置支付密码
- **接口路径**: `GET /merchantUser/checkPayPassword`
- **请求方式**: GET
- **接口描述**: 检查指定商户用户是否设置了支付密码，并可选择验证密码是否正确
- **登录验证**: ❌ 不需要（公开接口）

---

## 请求参数

| 参数名 | 类型 | 必填 | 说明 | 示例值 |
|--------|------|------|------|--------|
| storeUserId | String | 是 | 用户ID | "114" |
| password | String | 否 | 支付密码（如果提供则验证密码是否正确） | "123456" |

**参数说明**：
- `storeUserId`: 商户用户的唯一标识ID
- `password`: 
  - 如果不提供，只检查用户是否设置了支付密码
  - 如果提供，除了检查是否设置，还会验证密码是否正确

---

## 请求示例

### 示例1: 只检查是否设置支付密码

```http
GET /merchantUser/checkPayPassword?storeUserId=114
```

```bash
curl "http://localhost:8080/merchantUser/checkPayPassword?storeUserId=114"
```

### 示例2: 检查并验证支付密码

```http
GET /merchantUser/checkPayPassword?storeUserId=114&password=123456
```

```bash
curl "http://localhost:8080/merchantUser/checkPayPassword?storeUserId=114&password=123456"
```

---

## 响应参数

### 成功响应（通用格式）

```json
{
    "code": 200,
    "success": true,
    "data": {
        "code": 200,
        "message": "...",
        "data": "true/false"
    },
    "msg": "操作成功"
}
```

### 响应字段说明

| 字段名 | 类型 | 说明 |
|--------|------|------|
| code | Integer | HTTP状态码 |
| success | Boolean | 是否成功 |
| data | Map | 详细结果数据 |
| data.code | Integer | 业务状态码（固定为200） |
| data.message | String | 结果描述信息 |
| data.data | String | 验证结果（"true"或"false"） |
| msg | String | 提示信息 |

**data.data 字段值说明**：
- `"true"`: 用户已设置支付密码（且密码验证通过，如果提供了password参数）
- `"false"`: 用户未设置支付密码或密码验证失败

---

## 响应示例

### 场景1: 用户已设置支付密码（不验证密码）

**请求**:
```
GET /merchantUser/checkPayPassword?storeUserId=114
```

**响应**:
```json
{
    "code": 200,
    "success": true,
    "data": {
        "code": 200,
        "message": "用户已设置支付密码",
        "data": "true"
    },
    "msg": "操作成功"
}
```

---

### 场景2: 用户未设置支付密码

**请求**:
```
GET /merchantUser/checkPayPassword?storeUserId=114
```

**响应**:
```json
{
    "code": 200,
    "success": true,
    "data": {
        "code": 200,
        "message": "用户未设置支付密码",
        "data": "false"
    },
    "msg": "操作成功"
}
```

---

### 场景3: 用户不存在

**请求**:
```
GET /merchantUser/checkPayPassword?storeUserId=999999
```

**响应**:
```json
{
    "code": 200,
    "success": true,
    "data": {
        "code": 200,
        "message": "未查询到用户",
        "data": "false"
    },
    "msg": "操作成功"
}
```

---

### 场景4: 密码验证成功

**请求**:
```
GET /merchantUser/checkPayPassword?storeUserId=114&password=123456
```

**响应**:
```json
{
    "code": 200,
    "success": true,
    "data": {
        "code": 200,
        "message": "用户已设置支付密码",
        "data": "true"
    },
    "msg": "操作成功"
}
```

---

### 场景5: 密码验证失败

**请求**:
```
GET /merchantUser/checkPayPassword?storeUserId=114&password=wrong_password
```

**响应**:
```json
{
    "code": 200,
    "success": true,
    "data": {
        "code": 200,
        "message": "密码错误",
        "data": "false"
    },
    "msg": "操作成功"
}
```

---

### 场景6: 系统异常

**响应**:
```json
{
    "code": 500,
    "success": false,
    "data": null,
    "msg": "查询失败：{异常信息}"
}
```

---

## 业务逻辑说明

### 处理流程

```
┌─────────────────────────────────────────────┐
│  1. 接收请求参数                              │
│  - storeUserId (必填)                        │
│  - password (可选)                           │
└─────────────────┬───────────────────────────┘
                  ↓
┌─────────────────────────────────────────────┐
│  2. 根据用户ID查询用户信息                    │
│  storeUserMapper.selectById(storeUserId)     │
└─────────────────┬───────────────────────────┘
                  ↓
┌─────────────────────────────────────────────┐
│  3. 检查用户是否存在                          │
│  IF storeUser == null                        │
│    RETURN "未查询到用户", data="false"       │
└─────────────────┬───────────────────────────┘
                  ↓
┌─────────────────────────────────────────────┐
│  4. 检查是否设置了支付密码                    │
│  IF payPassword == null                      │
│    RETURN "用户未设置支付密码", data="false" │
└─────────────────┬───────────────────────────┘
                  ↓
┌─────────────────────────────────────────────┐
│  5. 如果提供了password参数，验证密码          │
│  IF password != null                         │
│    IF password != payPassword                │
│      RETURN "密码错误", data="false"         │
└─────────────────┬───────────────────────────┘
                  ↓
┌─────────────────────────────────────────────┐
│  6. 验证通过                                  │
│  RETURN "用户已设置支付密码", data="true"    │
└─────────────────────────────────────────────┘
```

### 验证逻辑详解

#### 步骤1: 用户存在性检查
```java
StoreUser storeUser = storeUserMapper.selectById(storeUserId);
if (storeUser == null) {
    // 用户不存在
    return {"message": "未查询到用户", "data": "false"};
}
```

#### 步骤2: 支付密码设置检查
```java
if (storeUser.getPayPassword() == null) {
    // 用户未设置支付密码
    return {"message": "用户未设置支付密码", "data": "false"};
}
```

#### 步骤3: 密码验证（可选）
```java
if (password != null) {
    if (!password.equals(storeUser.getPayPassword())) {
        // 密码错误
        return {"message": "密码错误", "data": "false"};
    }
}
// 验证通过
return {"message": "用户已设置支付密码", "data": "true"};
```

---

## 数据库查询

### 涉及的表

#### store_user（商户用户表）

**查询SQL**:
```sql
SELECT * FROM store_user WHERE id = ?
```

**使用字段**:
- `id`: 用户ID
- `pay_password`: 支付密码

---

## 业务场景

### 场景1: 支付前检查

**背景**: 用户发起支付操作前，先检查是否设置了支付密码

**请求**:
```
GET /merchantUser/checkPayPassword?storeUserId=114
```

**响应处理**:
```javascript
if (response.data.data === "true") {
    // 已设置支付密码，弹出密码输入框
    showPasswordInput();
} else {
    // 未设置支付密码，引导用户设置
    showSetPasswordTip();
}
```

---

### 场景2: 提现前验证

**背景**: 用户申请提现时，验证支付密码是否正确

**请求**:
```
GET /merchantUser/checkPayPassword?storeUserId=114&password=123456
```

**响应处理**:
```javascript
if (response.data.data === "true") {
    // 密码验证通过，允许提现
    proceedWithdrawal();
} else {
    // 密码验证失败，提示错误
    showError(response.data.message);
}
```

---

### 场景3: 修改支付密码前验证

**背景**: 用户修改支付密码前，验证旧密码是否正确

**请求**:
```
GET /merchantUser/checkPayPassword?storeUserId=114&password=old_password
```

**响应处理**:
```javascript
if (response.data.data === "true") {
    // 旧密码正确，允许修改
    showChangePasswordForm();
} else if (response.data.message === "密码错误") {
    // 旧密码错误
    showError("原密码错误，请重新输入");
} else {
    // 其他错误
    showError(response.data.message);
}
```

---

### 场景4: 忘记密码判断

**背景**: 用户点击"忘记密码"，判断是否已设置过密码

**请求**:
```
GET /merchantUser/checkPayPassword?storeUserId=114
```

**响应处理**:
```javascript
if (response.data.data === "false" && 
    response.data.message === "用户未设置支付密码") {
    // 从未设置过密码，引导设置
    showSetPasswordPage();
} else {
    // 已设置密码，进入重置流程
    showResetPasswordPage();
}
```

---

## 前端集成示例

### Vue.js 示例

```javascript
// API调用方法
async checkPayPassword(userId, password = null) {
    try {
        const params = { storeUserId: userId };
        if (password) {
            params.password = password;
        }
        
        const response = await axios.get('/merchantUser/checkPayPassword', {
            params: params
        });
        
        if (response.data.success) {
            const result = response.data.data;
            return {
                hasPassword: result.data === "true",
                message: result.message
            };
        }
        
        return { hasPassword: false, message: "查询失败" };
    } catch (error) {
        console.error("检查支付密码失败:", error);
        return { hasPassword: false, message: "网络错误" };
    }
}

// 使用示例1: 检查是否设置支付密码
async function checkIfPasswordSet() {
    const result = await checkPayPassword("114");
    if (result.hasPassword) {
        console.log("用户已设置支付密码");
    } else {
        console.log("用户未设置支付密码:", result.message);
    }
}

// 使用示例2: 验证支付密码
async function verifyPayPassword(password) {
    const result = await checkPayPassword("114", password);
    if (result.hasPassword) {
        console.log("密码验证成功");
        return true;
    } else {
        console.log("密码验证失败:", result.message);
        return false;
    }
}
```

### React 示例

```javascript
import { useState } from 'react';
import axios from 'axios';

function PaymentComponent() {
    const [hasPassword, setHasPassword] = useState(false);
    const [message, setMessage] = useState('');
    
    // 检查支付密码
    const checkPayPassword = async (userId, password = null) => {
        try {
            const params = { storeUserId: userId };
            if (password) params.password = password;
            
            const response = await axios.get('/merchantUser/checkPayPassword', {
                params
            });
            
            if (response.data.success) {
                const result = response.data.data;
                setHasPassword(result.data === "true");
                setMessage(result.message);
                return result.data === "true";
            }
        } catch (error) {
            console.error('检查失败:', error);
            setMessage('查询失败');
        }
        return false;
    };
    
    return (
        <div>
            <button onClick={() => checkPayPassword("114")}>
                检查是否设置密码
            </button>
            <p>{message}</p>
        </div>
    );
}
```

---

## 安全考虑

### 1. 密码安全

⚠️ **重要安全建议**:
- 密码应该在数据库中**加密存储**（MD5、SHA256或BCrypt）
- 传输密码时应使用**HTTPS**协议
- 不要在日志中记录明文密码
- 考虑添加密码错误次数限制，防止暴力破解

### 2. 敏感信息保护

当前实现的安全措施：
- ✅ 日志中不记录明文密码（只记录是否提供了密码）
- ⚠️ 建议：密码应该加密存储
- ⚠️ 建议：添加密码错误次数限制

### 3. 参数验证

- ✅ 必填参数：`storeUserId`
- ✅ 可选参数：`password`
- ⚠️ 建议：添加参数格式验证（如用户ID格式、密码长度等）

### 4. 防暴力破解

**建议实现**:
```java
// 伪代码示例
if (password != null) {
    // 检查密码错误次数
    int errorCount = getPasswordErrorCount(storeUserId);
    if (errorCount >= 5) {
        return R.fail("密码错误次数过多，请稍后再试");
    }
    
    // 验证密码
    if (!password.equals(storeUser.getPayPassword())) {
        // 记录错误次数
        incrementPasswordErrorCount(storeUserId);
        return R.fail("密码错误");
    }
    
    // 成功后清除错误次数
    clearPasswordErrorCount(storeUserId);
}
```

---

## 日志记录

### 日志级别

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

```java
// INFO级别 - 请求日志
log.info("MerchantUserController.checkPayPassword?storeUserId={}, hasPassword={}", 
        storeUserId, password != null);

// INFO级别 - 业务开始
log.info("MerchantUserServiceImpl.checkPayPassword - 检查支付密码: storeUserId={}, hasPassword={}", 
        storeUserId, password != null);

// WARN级别 - 异常情况
log.warn("MerchantUserServiceImpl.checkPayPassword - 用户不存在: storeUserId={}", storeUserId);
log.warn("MerchantUserServiceImpl.checkPayPassword - 密码错误: storeUserId={}", storeUserId);

// INFO级别 - 业务完成
log.info("MerchantUserServiceImpl.checkPayPassword - 检查完成: storeUserId={}, result=true", storeUserId);

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

### 日志安全

**重要**:
- ✅ 不记录明文密码
- ✅ 只记录是否提供了密码（`hasPassword=true/false`）
- ✅ 用户ID可以记录（非敏感信息）

---

## 异常处理

### 异常场景

| 异常情况 | HTTP状态码 | 返回code | 返回data.message |
|----------|-----------|----------|------------------|
| 用户不存在 | 200 | 200 | "未查询到用户" |
| 未设置密码 | 200 | 200 | "用户未设置支付密码" |
| 密码错误 | 200 | 200 | "密码错误" |
| 系统异常 | 200 | 500 | "查询失败：{异常信息}" |

**注意**: 所有业务逻辑错误都返回HTTP 200，通过`data.data`字段判断实际结果。

---

## 测试用例

### 测试场景1: 正常检查（已设置密码）

**前置条件**:
- 用户ID=114存在
- 用户已设置支付密码

**请求**:
```
GET /merchantUser/checkPayPassword?storeUserId=114
```

**预期结果**:
```json
{
    "data": {
        "code": 200,
        "message": "用户已设置支付密码",
        "data": "true"
    }
}
```

---

### 测试场景2: 用户未设置密码

**前置条件**:
- 用户ID=114存在
- 用户未设置支付密码（pay_password为NULL）

**请求**:
```
GET /merchantUser/checkPayPassword?storeUserId=114
```

**预期结果**:
```json
{
    "data": {
        "code": 200,
        "message": "用户未设置支付密码",
        "data": "false"
    }
}
```

---

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

**前置条件**:
- 用户ID=999999不存在

**请求**:
```
GET /merchantUser/checkPayPassword?storeUserId=999999
```

**预期结果**:
```json
{
    "data": {
        "code": 200,
        "message": "未查询到用户",
        "data": "false"
    }
}
```

---

### 测试场景4: 密码验证成功

**前置条件**:
- 用户ID=114存在
- 支付密码为"123456"

**请求**:
```
GET /merchantUser/checkPayPassword?storeUserId=114&password=123456
```

**预期结果**:
```json
{
    "data": {
        "code": 200,
        "message": "用户已设置支付密码",
        "data": "true"
    }
}
```

---

### 测试场景5: 密码验证失败

**前置条件**:
- 用户ID=114存在
- 支付密码为"123456"

**请求**:
```
GET /merchantUser/checkPayPassword?storeUserId=114&password=wrong_password
```

**预期结果**:
```json
{
    "data": {
        "code": 200,
        "message": "密码错误",
        "data": "false"
    }
}
```

---

## 性能优化

### 1. 数据库索引

确保 `store_user` 表的主键有索引:

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

### 2. 查询优化

- ✅ 使用主键查询（性能最优）
- ✅ 只查询必要的字段

### 3. 缓存策略

对于频繁查询的用户信息，可以考虑使用Redis缓存:

```java
// 伪代码示例
String cacheKey = "user:pay_password:" + storeUserId;
String hasPassword = redisTemplate.opsForValue().get(cacheKey);

if (hasPassword == null) {
    // 查询数据库
    StoreUser storeUser = storeUserMapper.selectById(storeUserId);
    hasPassword = storeUser.getPayPassword() != null ? "true" : "false";
    
    // 缓存结果（TTL: 5分钟）
    redisTemplate.opsForValue().set(cacheKey, hasPassword, 5, TimeUnit.MINUTES);
}
```

**注意**: 如果使用缓存，在用户设置或修改支付密码时需要清除缓存。

---

## 注意事项

### 1. 返回值格式

⚠️ **特殊格式**: 本接口返回的`data`字段是一个Map对象，而不是简单的布尔值。

```json
// 外层R对象
{
    "code": 200,
    "success": true,
    "data": {              // <- Map对象
        "code": 200,
        "message": "...",
        "data": "true/false"  // <- 字符串，不是布尔值
    }
}
```

### 2. 字符串类型

⚠️ `data.data` 字段的值是**字符串类型**（`"true"`或`"false"`），不是布尔类型。

**正确判断**:
```javascript
// ✅ 正确
if (response.data.data.data === "true") { ... }

// ❌ 错误
if (response.data.data.data === true) { ... }
```

### 3. 密码安全

⚠️ **强烈建议**:
- 数据库中的密码应该加密存储
- 传输过程使用HTTPS
- 添加密码错误次数限制
- 不在日志中记录明文密码

### 4. 参数可选性

⚠️ `password` 参数是可选的:
- 不提供：只检查是否设置
- 提供：检查并验证密码

---

## 迁移说明

### 原接口（app端）

- **服务**: `alien-store`
- **路径**: `/alienStore/store/user/havePayPassword`
- **Controller**: `StoreUserController`
- **Service**: `StoreUserService.havePayPassword()`

### 新接口（web端）

- **服务**: `alien-store-platform`
- **路径**: `/merchantUser/checkPayPassword`
- **Controller**: `MerchantUserController`
- **Service**: `MerchantUserService.checkPayPassword()`

### 差异说明

| 项目 | app端 | web端 | 说明 |
|------|-------|-------|------|
| 接口路径 | `/havePayPassword` | `/checkPayPassword` | 更符合web端命名规范 |
| 参数类型 | String | String | 保持一致 |
| 返回类型 | R\<Map\> | R\<Map\> | 保持一致 |
| 业务逻辑 | ✅ | ✅ | 完全复用 |
| 日志记录 | 基础 | 详细 | 增强日志记录 |
| 登录验证 | 无 | 无 | 公开接口 |

### 复用的核心组件

1. **Mapper**: `StoreUserMapper`
2. **Entity**: `StoreUser`
3. **业务逻辑**: 完全复用

---

## 更新日志

### 2025-11-17

**新增接口**:
- ✅ `GET /merchantUser/checkPayPassword` - 检查是否设置支付密码

**核心功能**:
- ✅ 检查用户是否存在
- ✅ 检查是否设置支付密码
- ✅ 可选的密码验证功能
- ✅ 返回统一格式的Map对象
- ✅ 详细日志记录
- ✅ 完善异常处理

**涉及文件**:
- `MerchantUserController.java` - 更新
- `MerchantUserService.java` - 更新
- `MerchantUserServiceImpl.java` - 更新

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

**开发人员**: ssk

---

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






