Skip to content

Commit ee71fa5

Browse files
Sean-LLfengyizhu
authored andcommitted
feat: 港澳台居民居住证 protocol
1 parent fc23d3f commit ee71fa5

File tree

5 files changed

+289
-0
lines changed

5 files changed

+289
-0
lines changed
Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
package com.ke.bella.openapi.protocol.ocr;
2+
3+
import java.util.HashSet;
4+
import java.util.Set;
5+
6+
/**
7+
* OCR证件字段命名规范
8+
* 定义所有允许使用的OCR字段名称(超集)
9+
*/
10+
public class OcrFieldNamingStandard {
11+
12+
/**
13+
* 所有允许使用的字段名称(超集)
14+
* 所有OCR响应类的字段名必须在此集合中
15+
*/
16+
private static final Set<String> ALLOWED_FIELD_NAMES = new HashSet<>();
17+
18+
static {
19+
// 个人信息字段
20+
ALLOWED_FIELD_NAMES.add("name"); // 姓名
21+
ALLOWED_FIELD_NAMES.add("sex"); // 性别
22+
ALLOWED_FIELD_NAMES.add("nationality"); // 民族
23+
ALLOWED_FIELD_NAMES.add("birth_date"); // 出生日期
24+
25+
// 地址信息字段
26+
ALLOWED_FIELD_NAMES.add("address"); // 地址/住址
27+
28+
// 证件信息字段
29+
ALLOWED_FIELD_NAMES.add("idcard_number"); // 证件号/身份证号/公民身份号码
30+
31+
// 签发信息字段
32+
ALLOWED_FIELD_NAMES.add("issue_authority"); // 签发机关
33+
ALLOWED_FIELD_NAMES.add("valid_date_start"); // 有效期开始
34+
ALLOWED_FIELD_NAMES.add("valid_date_end"); // 有效期结束
35+
36+
// 银行卡字段
37+
ALLOWED_FIELD_NAMES.add("card_number"); // 银行卡号
38+
ALLOWED_FIELD_NAMES.add("bank_name"); // 银行名称
39+
ALLOWED_FIELD_NAMES.add("card_type"); // 卡类型
40+
ALLOWED_FIELD_NAMES.add("valid_date"); // 有效期
41+
42+
// 特殊字段
43+
ALLOWED_FIELD_NAMES.add("eep_number"); // 通行证号
44+
45+
}
46+
47+
/**
48+
* 检查字段名是否允许使用
49+
*
50+
* @param fieldName 字段名
51+
*
52+
* @return true 如果字段名在允许列表中
53+
*/
54+
public static boolean isAllowedFieldName(String fieldName) {
55+
return ALLOWED_FIELD_NAMES.contains(fieldName);
56+
}
57+
58+
/**
59+
* 获取所有允许的字段名
60+
*
61+
* @return 所有允许使用的字段名集合
62+
*/
63+
public static Set<String> getAllAllowedFieldNames() {
64+
return new HashSet<>(ALLOWED_FIELD_NAMES);
65+
}
66+
67+
/**
68+
* 添加新的允许字段名(用于扩展)
69+
*
70+
* @param fieldName 字段名
71+
*/
72+
public static void addAllowedFieldName(String fieldName) {
73+
ALLOWED_FIELD_NAMES.add(fieldName);
74+
}
75+
}
Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
package com.ke.bella.openapi.protocol.ocr.residencepermit;
2+
3+
import java.io.Serializable;
4+
5+
import com.fasterxml.jackson.annotation.JsonInclude;
6+
import com.fasterxml.jackson.annotation.JsonValue;
7+
import com.ke.bella.openapi.protocol.OpenapiResponse;
8+
9+
import lombok.AllArgsConstructor;
10+
import lombok.Builder;
11+
import lombok.Data;
12+
import lombok.EqualsAndHashCode;
13+
import lombok.Getter;
14+
import lombok.NoArgsConstructor;
15+
import lombok.experimental.SuperBuilder;
16+
17+
/**
18+
* OCR港澳台居民居住证识别响应
19+
*/
20+
@JsonInclude(JsonInclude.Include.NON_NULL)
21+
@EqualsAndHashCode(callSuper = true)
22+
@Data
23+
@NoArgsConstructor
24+
@SuperBuilder
25+
public class OcrResidencePermitResponse extends OpenapiResponse {
26+
private static final long serialVersionUID = 1L;
27+
28+
private String request_id; // 请求唯一标识
29+
private ResidencePermitSide side; // 居住证面类型
30+
private Object data; // 识别结果数据
31+
32+
/**
33+
* 居住证面类型枚举
34+
*/
35+
@Getter
36+
@AllArgsConstructor
37+
public enum ResidencePermitSide {
38+
PORTRAIT("portrait", "人像面"),
39+
NATIONAL_EMBLEM("national_emblem", "国徽面");
40+
41+
@JsonValue
42+
private final String code;
43+
private final String description;
44+
}
45+
46+
// 人像面数据结构
47+
@Data
48+
@Builder
49+
@NoArgsConstructor
50+
@AllArgsConstructor
51+
@JsonInclude(JsonInclude.Include.NON_NULL)
52+
public static class PortraitData implements Serializable {
53+
private static final long serialVersionUID = 1L;
54+
55+
private String name; // 姓名
56+
private String sex; // 性别
57+
private String birth_date; // 出生日期
58+
private String address; // 住址
59+
private String idcard_number; // 公民身份号码
60+
}
61+
62+
// 国徽面数据结构
63+
@Data
64+
@Builder
65+
@NoArgsConstructor
66+
@AllArgsConstructor
67+
@JsonInclude(JsonInclude.Include.NON_NULL)
68+
public static class NationalEmblemData implements Serializable {
69+
private static final long serialVersionUID = 1L;
70+
71+
private String issue_authority; // 签发机关
72+
private String valid_date_start; // 有效期开始日期
73+
private String valid_date_end; // 有效期结束日期
74+
private String eep_number; // 通行证号
75+
}
76+
}

api/server/pom.xml

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -301,6 +301,12 @@
301301
<artifactId>oapi-sdk</artifactId>
302302
<version>2.4.19</version>
303303
</dependency>
304+
<dependency>
305+
<groupId>org.reflections</groupId>
306+
<artifactId>reflections</artifactId>
307+
<version>0.10.2</version>
308+
<scope>test</scope>
309+
</dependency>
304310
</dependencies>
305311

306312
<build>
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
package com.ke.bella.openapi.protocol.ocr;
2+
3+
import com.ke.bella.openapi.protocol.IProtocolAdaptor;
4+
import com.ke.bella.openapi.protocol.ocr.residencepermit.OcrResidencePermitResponse;
5+
6+
public interface OcrResidencePermitAdaptor<T extends OcrProperty> extends IProtocolAdaptor {
7+
8+
OcrResidencePermitResponse residencePermit(OcrRequest request, String url, T property);
9+
10+
@Override
11+
default String endpoint() {
12+
return "/v1/ocr/residence_permit";
13+
}
14+
}
Lines changed: 118 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,118 @@
1+
package com.ke.bella.openapi.protocol.ocr;
2+
3+
import static org.junit.Assert.assertTrue;
4+
5+
import java.io.Serializable;
6+
import java.lang.reflect.Field;
7+
import java.lang.reflect.Modifier;
8+
import java.util.ArrayList;
9+
import java.util.List;
10+
import java.util.Set;
11+
12+
import org.junit.Test;
13+
import org.reflections.Reflections;
14+
15+
import com.ke.bella.openapi.protocol.OpenapiResponse;
16+
17+
/**
18+
* OCR证件字段命名规范测试
19+
* 验证所有字段名是否在允许的超集中
20+
*/
21+
public class OcrFieldNamingStandardTest {
22+
23+
/**
24+
* 自动扫描所有OCR数据类
25+
*/
26+
private List<Class<?>> findAllOcrDataClasses() {
27+
List<Class<?>> classes = new ArrayList<>();
28+
29+
Reflections reflections = new Reflections("com.ke.bella.openapi.protocol.ocr");
30+
Set<Class<? extends OpenapiResponse>> responseClasses = reflections.getSubTypesOf(OpenapiResponse.class);
31+
32+
for (Class<?> responseClass : responseClasses) {
33+
for (Class<?> innerClass : responseClass.getDeclaredClasses()) {
34+
if(innerClass.getSimpleName().endsWith("Data") &&
35+
Modifier.isStatic(innerClass.getModifiers()) &&
36+
Modifier.isPublic(innerClass.getModifiers()) &&
37+
Serializable.class.isAssignableFrom(innerClass)) {
38+
classes.add(innerClass);
39+
}
40+
}
41+
}
42+
43+
return classes;
44+
}
45+
46+
/**
47+
* 主测试: 验证所有OCR字段命名规范
48+
*/
49+
@Test
50+
public void testAllOcrResponseFieldNamingStandard() {
51+
System.out.println("=== OCR字段命名规范验证 ===\n");
52+
53+
// 1. 打印允许的字段名超集
54+
Set<String> allowedFields = OcrFieldNamingStandard.getAllAllowedFieldNames();
55+
System.out.println("允许的字段名超集(" + allowedFields.size() + "个):");
56+
for (String field : allowedFields) {
57+
System.out.println(" - " + field);
58+
}
59+
System.out.println();
60+
61+
// 2. 打印扫描到的类
62+
List<Class<?>> ocrDataClasses = findAllOcrDataClasses();
63+
System.out.println("扫描到的OCR数据类(" + ocrDataClasses.size() + "个):");
64+
for (Class<?> clazz : ocrDataClasses) {
65+
System.out.println(" - " + clazz.getName());
66+
}
67+
System.out.println();
68+
69+
// 3. 验证每个类的字段是否符合要求
70+
List<String> violations = new ArrayList<>();
71+
72+
for (Class<?> clazz : ocrDataClasses) {
73+
System.out.println("检查: " + clazz.getSimpleName());
74+
Field[] fields = clazz.getDeclaredFields();
75+
76+
for (Field field : fields) {
77+
String fieldName = field.getName();
78+
79+
// 跳过特殊字段
80+
if(fieldName.equals("serialVersionUID") ||
81+
fieldName.startsWith("$") ||
82+
fieldName.equals("INSTANCE")) {
83+
continue;
84+
}
85+
86+
// 检查字段是否在超集中
87+
if(!OcrFieldNamingStandard.isAllowedFieldName(fieldName)) {
88+
String violation = clazz.getSimpleName() + "." + fieldName;
89+
violations.add(violation);
90+
System.out.println(" ❌ " + fieldName + " - 不在超集中");
91+
} else {
92+
System.out.println(" ✅ " + fieldName);
93+
}
94+
}
95+
System.out.println();
96+
}
97+
98+
// 结果汇总
99+
System.out.println("=== 验证结果 ===");
100+
System.out.println("总类数: " + ocrDataClasses.size());
101+
System.out.println("不符合规范的字段数: " + violations.size());
102+
103+
if(!violations.isEmpty()) {
104+
System.out.println("\n不符合规范的字段:");
105+
for (String violation : violations) {
106+
System.out.println(" ❌ " + violation);
107+
}
108+
System.out.println("\n提示: 请在 OcrFieldNamingStandard 中添加缺失的字段名");
109+
}
110+
111+
// 断言
112+
assertTrue(
113+
"发现 " + violations.size() + " 个字段不在允许的超集中",
114+
violations.isEmpty());
115+
116+
System.out.println("\n✅ 所有字段命名规范验证通过!");
117+
}
118+
}

0 commit comments

Comments
 (0)