# OCR 识别接口文档

## 接口概述

本接口提供阿里云 OCR（Optical Character Recognition，光学字符识别）服务，支持多种证件和文档的智能识别，包括身份证、营业执照、食品经营许可证等。

**接口路径**: `POST /ali/ocrRequestUrl`  
**接口描述**: 调用阿里云 OCR 识别服务，支持批量图片识别  
**请求方式**: POST  
**Content-Type**: application/json  
**登录验证**: ✅ 需要

---

## 请求参数

### 请求体 (JSON)

| 参数名 | 类型 | 必填 | 说明 | 示例值 |
|--------|------|------|------|--------|
| imageUrls | String | 是 | 图片URL地址，多个用逗号分隔 | `https://example.com/image1.jpg,https://example.com/image2.jpg` |
| ocrType | String | 是 | OCR识别类型 | `idCard`, `businessLicense`, `foodLicense` |
| storeId | String | 否 | 店铺ID（用于记录识别来源） | `103` |
| userId | String | 否 | 用户ID（用于记录识别来源） | `12345` |
| storeUserId | String | 否 | 店铺用户ID（用于记录识别来源） | `67890` |

### OCR 类型说明

| ocrType 值 | 识别类型 | 说明 |
|-----------|----------|------|
| `idCard` | 身份证识别 | 识别身份证正反面信息 |
| `businessLicense` | 营业执照识别 | 识别营业执照信息 |
| `foodLicense` | 食品经营许可证识别 | 识别食品经营许可证信息 |

---

## 请求示例

### 示例 1: 身份证识别（单张）

```http
POST /ali/ocrRequestUrl
Content-Type: application/json

{
    "imageUrls": "https://example.com/idcard-front.jpg",
    "ocrType": "idCard",
    "storeId": "103",
    "userId": "12345",
    "storeUserId": "67890"
}
```

```bash
curl -X POST "http://localhost:8080/ali/ocrRequestUrl" \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer YOUR_TOKEN" \
  -d '{
    "imageUrls": "https://example.com/idcard-front.jpg",
    "ocrType": "idCard",
    "storeId": "103"
  }'
```

---

### 示例 2: 营业执照识别（批量）

```http
POST /ali/ocrRequestUrl
Content-Type: application/json

{
    "imageUrls": "https://example.com/license1.jpg,https://example.com/license2.jpg",
    "ocrType": "businessLicense",
    "storeId": "103",
    "storeUserId": "67890"
}
```

---

### 示例 3: 食品经营许可证识别

```http
POST /ali/ocrRequestUrl
Content-Type: application/json

{
    "imageUrls": "https://example.com/food-license.jpg",
    "ocrType": "foodLicense",
    "storeId": "103"
}
```

---

## 响应参数

### 成功响应

#### 响应结构

```json
{
    "code": 200,
    "success": true,
    "data": [
        {
            // OCR识别结果（根据不同类型返回不同字段）
        }
    ],
    "msg": "操作成功"
}
```

---

### 身份证识别响应字段

```json
{
    "code": 200,
    "success": true,
    "data": [
        {
            "name": "张三",
            "gender": "男",
            "nationality": "汉",
            "birthDate": "19900101",
            "address": "北京市朝阳区XX街道XX号",
            "idNumber": "110101199001011234",
            "issueAuthority": "北京市公安局朝阳分局",
            "validDate": "2020.01.01-2030.01.01"
        }
    ],
    "msg": "操作成功"
}
```

#### 字段说明

| 字段名 | 类型 | 说明 |
|--------|------|------|
| name | String | 姓名 |
| gender | String | 性别 |
| nationality | String | 民族 |
| birthDate | String | 出生日期（格式：yyyyMMdd） |
| address | String | 地址 |
| idNumber | String | 身份证号码 |
| issueAuthority | String | 签发机关（反面） |
| validDate | String | 有效期限（反面） |

---

### 营业执照识别响应字段

```json
{
    "code": 200,
    "success": true,
    "data": [
        {
            "name": "北京XX科技有限公司",
            "creditCode": "91110000MA01ABC123",
            "legalPerson": "李四",
            "address": "北京市海淀区XX路XX号",
            "registerDate": "2020-01-01",
            "registerCapital": "100万元人民币",
            "businessScope": "技术开发、技术咨询...",
            "validPeriod": "2020-01-01至2040-01-01",
            "type": "有限责任公司",
            "establishDate": "2020-01-01"
        }
    ],
    "msg": "操作成功"
}
```

#### 字段说明

| 字段名 | 类型 | 说明 |
|--------|------|------|
| name | String | 企业名称 |
| creditCode | String | 统一社会信用代码 |
| legalPerson | String | 法定代表人 |
| address | String | 注册地址 |
| registerDate | String | 注册日期 |
| registerCapital | String | 注册资本 |
| businessScope | String | 经营范围 |
| validPeriod | String | 营业期限 |
| type | String | 企业类型 |
| establishDate | String | 成立日期 |

---

### 食品经营许可证识别响应字段

```json
{
    "code": 200,
    "success": true,
    "data": [
        {
            "licenseName": "食品经营许可证",
            "businessLicenseName": "北京XX餐饮有限公司",
            "businessAddress": "北京市朝阳区XX街XX号",
            "legalPerson": "王五",
            "creditCode": "91110000MA01XYZ456",
            "businessItem": "热食类食品制售",
            "licenseNumber": "JY11234567890123",
            "validPeriod": "2020-01-01至2025-01-01",
            "issueDate": "2020-01-01",
            "issueAuthority": "北京市朝阳区市场监督管理局"
        }
    ],
    "msg": "操作成功"
}
```

#### 字段说明

| 字段名 | 类型 | 说明 |
|--------|------|------|
| licenseName | String | 许可证名称 |
| businessLicenseName | String | 经营者名称 |
| businessAddress | String | 经营场所 |
| legalPerson | String | 法定代表人（负责人） |
| creditCode | String | 社会信用代码 |
| businessItem | String | 经营项目 |
| licenseNumber | String | 许可证编号 |
| validPeriod | String | 有效期限 |
| issueDate | String | 发证日期 |
| issueAuthority | String | 发证机关 |

---

### 失败响应

```json
{
    "code": 500,
    "success": false,
    "data": null,
    "msg": "身份证识别失败" // 或其他错误信息
}
```

#### 常见错误信息

| 错误信息 | 原因 | 解决方案 |
|---------|------|---------|
| OCR识别返回结果为空 | 图片质量差或格式错误 | 上传清晰的图片 |
| 身份证识别失败 | 图片不是身份证或无法识别 | 检查图片内容 |
| 营业执照识别失败 | 图片不是营业执照或无法识别 | 检查图片内容 |
| 图片URL无法访问 | 图片链接失效或网络问题 | 检查图片URL |
| OCR识别异常 | 系统异常或参数错误 | 检查请求参数 |

---

## 业务流程

### 识别流程图

```
用户上传图片 
    ↓
前端获取图片URL
    ↓
调用 /ali/ocrRequestUrl 接口
    ↓
根据 ocrType 选择识别策略
    ↓
调用阿里云OCR服务
    ↓
解析识别结果
    ↓
保存识别记录到数据库
    ↓
返回识别结果
```

### 核心业务逻辑

1. **参数接收**: 接收图片URL列表和识别类型
2. **策略选择**: 根据 ocrType 选择对应的识别策略
3. **批量识别**: 遍历图片URL列表，逐一调用阿里云OCR
4. **结果解析**: 解析阿里云返回的JSON数据
5. **数据存储**: 保存识别结果到 `ocr_image_upload` 表
6. **结果返回**: 返回识别结果数组

---

## 技术实现

### 技术架构

```
Controller层 (AliController)
    ↓
Service层 (AliApi)
    ↓
策略模式 (OcrStrategy)
    ├── IdCardOcrStrategy (身份证识别)
    ├── BusinessLicenseOcrStrategy (营业执照识别)
    └── FoodManageLicenseOcrStrategy (食品许可证识别)
    ↓
阿里云OCR API
```

### 关键类说明

| 类名 | 说明 | 路径 |
|------|------|------|
| AliController | 控制器，接收请求 | `shop.alien.store.controller.AliController` |
| AliApi | 服务类，业务逻辑 | `shop.alien.store.util.ali.AliApi` |
| OcrStrategy | 策略接口 | `shop.alien.store.util.ali.ocr.OcrStrategy` |
| AbstractOcrStrategy | 策略抽象类 | `shop.alien.store.util.ali.ocr.AbstractOcrStrategy` |
| IdCardOcrStrategy | 身份证识别策略 | `shop.alien.store.util.ali.ocr.strategy.IdCardOcrStrategy` |
| BusinessLicenseOcrStrategy | 营业执照识别策略 | `shop.alien.store.util.ali.ocr.strategy.BusinessLicenseOcrStrategy` |
| FoodManageLicenseOcrStrategy | 食品许可证识别策略 | `shop.alien.store.util.ali.ocr.strategy.FoodManageLicenseOcrStrategy` |

### 核心代码

#### Controller 层

```java
@ApiOperation("调用OCR识别接口")
@PostMapping("/ocrRequestUrl")
public R ocrRequestUrl(@RequestBody Map<String, String> params) {
    try {
        return aliApi.ocrRequestParams(params);
    } catch (Exception e) {
        return R.fail(e.getMessage());
    }
}
```

#### Service 层

```java
public R ocrRequestParams(Map<String, String> params) throws Exception {
    // 根据 ocrType 获取对应的识别策略
    OcrStrategy strategy = ocrStrategyFactory.getStrategy(params.get("ocrType"));
    // 执行识别
    return strategy.recognizeParams(params);
}
```

#### 策略实现（以身份证为例）

```java
@Override
public R recognizeParams(Map<String, String> params) throws Exception {
    String[] imageUrls = params.get("imageUrls").split(",");
    JSONArray resultArray = new JSONArray();
    
    for (String imageUrl : imageUrls) {
        // 创建阿里云OCR客户端
        Client client = createOcrClient();
        
        // 创建识别请求
        RecognizeIdcardRequest request = new RecognizeIdcardRequest()
                .setUrl(imageUrl);
        
        // 调用识别接口
        RecognizeIdcardResponse response = client.recognizeIdcardWithOptions(
                request, new RuntimeOptions());
        
        // 解析结果
        RecognizeIdcardResponseBody body = response.getBody();
        JSONObject jsonObject = JSONObject.parseObject(body.getData());
        
        // 保存识别记录
        OcrImageUpload ocrImageUpload = new OcrImageUpload();
        ocrImageUpload.setImageUrl(imageUrl);
        ocrImageUpload.setOcrResult(jsonObject.getJSONObject("data").toJSONString());
        ocrImageUpload.setOcrType(OcrTypeEnum.ID_CARD.getCode());
        saveOcrImage(ocrImageUpload);
        
        // 添加到结果集
        resultArray.add(jsonObject.getJSONObject("data"));
    }
    
    return R.data(resultArray);
}
```

---

## 数据库设计

### ocr_image_upload 表

OCR识别记录表，用于保存每次识别的结果。

| 字段名 | 类型 | 说明 |
|--------|------|------|
| id | INT | 主键ID |
| user_id | VARCHAR | 用户ID |
| store_id | VARCHAR | 店铺ID |
| store_user_id | VARCHAR | 店铺用户ID |
| image_url | VARCHAR | 图片URL |
| ocr_result | TEXT | OCR识别结果（JSON格式） |
| ocr_type | VARCHAR | OCR类型 |
| create_time | DATETIME | 创建时间 |
| update_time | DATETIME | 更新时间 |

---

## 配置说明

### 阿里云 OCR 配置

在 `application.yml` 中配置阿里云 OCR 参数：

```yaml
ali:
  ocr:
    accessKeyId: YOUR_ACCESS_KEY_ID
    accessKeySecret: YOUR_ACCESS_KEY_SECRET
    endpoint: ocr-api.cn-hangzhou.aliyuncs.com
```

### 配置项说明

| 配置项 | 说明 | 示例值 |
|--------|------|--------|
| accessKeyId | 阿里云访问密钥ID | `LTAI4G...` |
| accessKeySecret | 阿里云访问密钥Secret | `xxx...` |
| endpoint | OCR服务端点 | `ocr-api.cn-hangzhou.aliyuncs.com` |

---

## 使用限制

### 图片要求

| 项目 | 要求 |
|------|------|
| **格式** | JPG、PNG、BMP、PDF |
| **大小** | 不超过 4MB |
| **分辨率** | 建议大于 600x600 像素 |
| **清晰度** | 图片清晰，无模糊、反光 |
| **完整性** | 证件信息完整，无遮挡 |

### 调用限制

| 项目 | 限制 |
|------|------|
| **QPS限制** | 根据阿里云账户配置 |
| **并发数** | 建议不超过10个并发请求 |
| **批量数量** | 单次请求建议不超过5张图片 |

---

## 注意事项

### 1. 图片URL要求

⚠️ **图片URL必须可公网访问**

```java
// ✅ 正确：公网可访问的URL
"imageUrls": "https://cdn.example.com/image.jpg"

// ❌ 错误：本地路径
"imageUrls": "file:///C:/Users/image.jpg"

// ❌ 错误：内网地址
"imageUrls": "http://192.168.1.100/image.jpg"
```

### 2. 批量识别建议

⚠️ **批量识别时注意错误处理**

```java
// 当前实现：遇到错误会中断整个批量
// 建议：改进为部分失败不影响其他图片识别
```

### 3. 数据隐私

⚠️ **敏感信息处理**

- 识别结果包含个人身份信息，需妥善保存
- 建议加密存储敏感字段
- 遵守数据保护法规

### 4. 成本控制

⚠️ **接口调用成本**

- 阿里云OCR按调用次数计费
- 建议添加调用频率限制
- 避免重复识别相同图片

---

## 错误处理

### 异常类型

| 异常类型 | 说明 | 处理方式 |
|---------|------|---------|
| TeaException | 阿里云API异常 | 记录日志，返回友好提示 |
| Exception | 通用异常 | 记录详细日志，返回错误信息 |
| NullPointerException | 空指针异常 | 参数校验，防止空值 |

### 异常处理代码

```java
try {
    // OCR识别逻辑
} catch (TeaException error) {
    log.error("OCR识别失败: code={}, message={}", 
              error.getCode(), error.getMessage());
    return R.fail("身份证识别失败");
} catch (Exception error) {
    log.error("OCR识别异常", error);
    return R.fail("身份证识别异常");
}
```

---

## 性能优化建议

### 1. 图片预处理

```java
// 建议：上传前压缩图片
- 控制图片大小在 1MB 以内
- 分辨率调整到 1200x1200 左右
- 使用 JPG 格式（压缩率更高）
```

### 2. 异步处理

```java
// 建议：批量识别时使用异步
@Async
public CompletableFuture<R> recognizeAsync(String imageUrl) {
    // 异步识别逻辑
}
```

### 3. 缓存机制

```java
// 建议：相同图片不重复识别
@Cacheable(value = "ocrResult", key = "#imageUrl")
public R recognizeWithCache(String imageUrl, String ocrType) {
    // 识别逻辑
}
```

---

## 测试建议

### 测试场景

| 测试场景 | 测试目的 | 预期结果 |
|---------|---------|---------|
| **正常识别** | 验证识别准确性 | 返回正确的识别结果 |
| **图片模糊** | 验证容错能力 | 返回友好错误提示 |
| **批量识别** | 验证批量处理 | 所有图片都能识别 |
| **无效URL** | 验证参数校验 | 返回错误信息 |
| **并发请求** | 验证并发安全 | 结果正确，无遗漏 |

### 测试用例

```bash
# 测试1：身份证识别
curl -X POST "http://localhost:8080/ali/ocrRequestUrl" \
  -H "Content-Type: application/json" \
  -d '{
    "imageUrls": "https://example.com/idcard.jpg",
    "ocrType": "idCard",
    "storeId": "103"
  }'

# 测试2：营业执照批量识别
curl -X POST "http://localhost:8080/ali/ocrRequestUrl" \
  -H "Content-Type: application/json" \
  -d '{
    "imageUrls": "https://example.com/license1.jpg,https://example.com/license2.jpg",
    "ocrType": "businessLicense",
    "storeId": "103"
  }'
```

---

## 相关接口

### 其他 OCR 接口

| 接口路径 | 说明 | 区别 |
|---------|------|------|
| GET /ali/ocrRequest | OCR识别方式一 | 通过图片ID识别 |
| POST /ali/ocrRequestByBase64 | OCR识别方式二 | 通过Base64编码识别 |
| POST /ali/secondClient | 二手委托人识别 | 专用于二手业务 |

---

## 更新日志

### v1.0 (2025-11-18)

**初始版本**：
- ✅ 支持身份证识别
- ✅ 支持营业执照识别
- ✅ 支持食品经营许可证识别
- ✅ 支持批量图片识别
- ✅ 自动保存识别记录
- ✅ 采用策略模式设计

**开发团队**：lyx

---

### v1.1 (预计)

**计划功能**：
- 🔜 增加图片缓存机制
- 🔜 支持异步批量识别
- 🔜 增加识别结果校验
- 🔜 优化错误处理逻辑
- 🔜 增加调用频率限制

---

## 相关文档

- [阿里云OCR API文档](https://help.aliyun.com/document_detail/442275.html)
- [身份证识别文档](https://help.aliyun.com/document_detail/442322.html)
- [营业执照识别文档](https://help.aliyun.com/document_detail/442338.html)

---

## 联系方式

| 角色 | 负责内容 | 联系方式 |
|------|---------|---------|
| 后端开发 | 接口开发与维护 | - |
| 技术负责人 | 技术方案审核 | - |
| 产品经理 | 业务需求对接 | - |

---

**文档版本**: v1.0  
**最后更新**: 2025-11-28  
**维护人员**: AI Assistant  
**接口状态**: ✅ 已上线

