🎀 对象字段
# 封装字段
我们在之前的《URL 参数》、《请求头》和《请求体》等章节中学习过,URL 参数、请求头参数、请求体中的数据字段,乃至用于接受服务端返回的响应数据,都可以封装到自定义的对象中,如下所示:
public class MyUser {
private String userId;
private String userName;
// Getters, Setters
}
2
3
4
5
6
7
8
9
10
该自定义的MyUser
类型,可以作为 Query 参数,请求头参数,以及请求体数据的字段
// 作为 Query 参数
@Get("http://localhost:8080/user/info")
String getUserInfo(@Query MyUser myUser);
// 产生请求:
// http://localhost:8080/user/info?userId=xx&userName=xxx
// Query 参数名和 Java 字段名一致
// 作为请求头
@Get("http://localhost:8080/user/info2")
String getUserInfo2(@Header MyUser myUser);
// 产生请求:
// http://localhost:8080/user/info2
// Headers:
// userId: xx
// userName: xxx
// 请求头参数名和 Java 字段名一致
// 作为 Body 数据
@Post(url = "http://localhost:8080/user", contentType="application/json")
String submitUserInfo(@Body MyUser myUser);
// 产生请求:
// http://localhost:8080/user
// Body: {"userName": "xxx", "userId": "xx"}
// JSON Body 字段名和 Java 字段名一致
// 注:这里可能乱序了
// 乃至其他数据格式的的 Body 数据
@Post(url = "http://localhost:8080/user", contentType="application/x-www-form-urlencoded")
String submitUserInfo(@Body MyUser myUser);
// 产生请求:
// http://localhost:8080/user
// Body: userName=xxx&userId=xx
// Form Body 字段名和 Java 字段名一致
// 注:这里可能乱序了
// 以及接受响应数据
@Post(url = "http://localhost:8080/user/{0}")
MyUser getUser(String userId);
// 响应 Response Body:
// {"userId": "xx", "userName": "xxx"}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
# 两大问题
以上代码,都可以毫无问题的顺利执行,但如果发送和接受的数据字段名和自定义类型中的字段名不同呢?该如何处理?(比如: 要发送的请求参数为 user_id 和 user_name 这种 snake_case 风格)
当然,您可以把 Java 类型中的字段名也改成这种下划线蛇形风格,但这不符合 Java 的命名规范,强行蛇形会显得十分违和。况且除了蛇形,还有 Pascal 命名、纯大写命名、以及古早的匈牙利命名等等。总不能有多少风格就定义多少 Java 类吧?
此外,还有另一大麻烦,就是乱序问题,您在 MyUser 中定义的顺序是: 先 userId, 再 userName,可发送出去的却是: {"userName": "xxx", "userId": "xx"},巧的是此时正好用了加密或签名算法,此类算法又恰好对字段顺序敏感,字段顺序稍微变化以下,产生的签名就大为不同。而它能不能按您设想的顺序纯粹靠运气,那这样一来岂不是自定义 Java 类就不能用了?
对于这两大问题,在 Forest 中虽然也没有直接提供任何 api 或注解,但能借助 JSON 框架来解决此类问题。
# 配置 JSON 框架
第一步,先要确认在项目中,Forest 使用的是哪个 JSON 框架作为请求的数据转换器,确认的方法如下:
- 如果在项目中, Fastjson2、Fastjson、Jackson、Gson 这四个框架中只依赖了其中一个,那就会以这个框架为 JSON 转换器
- 如果在项目中,同时依赖了其中多个框架,那么按 Fastjson2 > Fastjson > Jackson > Gson 这样的优先级来判断,Forest 会以优先级最高的框架作为 JSON 转换器
- 如果在项目中明确配置了全局 JSON 转换器,那就一定以这个框架为准
推荐使用 第 3 种方法,因为现实世界的项目中,往往会依赖很多种 JSON 框架,很多情况下是通过不同的第三方依赖传递过来的,比如 springboot 就会传递依赖 Jackson。时间长了,很难搞清楚到底依赖了哪个 JSON 框架。
但通过全局配置,就能很清楚地排除掉这种不确定性。具体如果配置请参见《配置全局转换器》
# 指定字段别名
完成上面步骤后,就可以使用 当前 JSON 转换器 的 JSON 框架所提供的 注解 来指定别名了
这里以 Fastjson2 / Fastjson 为例进行说明 (与 Jackson 和 Gson 的用法类似):
// 使用 Fastjson2 / Fastjson 框架注解来指定字段别名
// 若 Forest 的 JSON 转换器是其他 JSON 框架,请使用相应框架的注解
public class MyUser {
@JSONField(name = "user_id")
private String userId;
@JSONField(name = "user_name")
private String userName;
// Getters, Setters
}
2
3
4
5
6
7
8
9
10
11
12
此时,再用 MyUser 类型作为参数就会以 别名 进行序列化和反序列化了,不管是作为 URL 参数、请求头参数、Body 数据字段,还是用于接受 Response 数据,它都能 Work
// 作为 Query 参数
@Get("http://localhost:8080/user/info")
String getUserInfo(@Query MyUser myUser);
// 产生请求:
// http://localhost:8080/user/info?user_name=xxx&user_id=xx
// 按 snake_case 进行命名 query 参数
// 注:这里可能乱序了
// 作为请求头
@Get("http://localhost:8080/user/info2")
String getUserInfo2(@Header MyUser myUser);
// 产生请求:
// http://localhost:8080/user/info2
// Headers:
// user_name: xxx
// user_id: xx
// 按 snake_case 进行命名请求头参数
// 注:这里可能乱序了
// 作为 Body 数据
@Post(url = "http://localhost:8080/user", contentType="application/json")
String submitUserInfo(@Body MyUser myUser);
// 产生请求:
// http://localhost:8080/user
// Body: {"user_name": "xxx", "user_id": "xx"}
// 按 snake_case 进行命名 JSON Body 字段名
// 注:这里可能乱序了
// 乃至其他数据格式的的 Body 数据
@Post(url = "http://localhost:8080/user", contentType="application/x-www-form-urlencoded")
String submitUserInfo(@Body MyUser myUser);
// 产生请求:
// http://localhost:8080/user
// Body: user_name=xxx&user_id=xx
// 按 snake_case 进行命名 Form Body 字段名
// 注:这里可能乱序了
// 以及接受响应数据
@Post(url = "http://localhost:8080/user/{0}")
MyUser getUser(String userId);
// 响应 Response Body:
// {"user_id": "xx", "user_name": "xxx"}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
# 指定顺序
JSON 框架的注解除了能指定别名,同样能指定顺序:
// 使用 Fastjson2 / Fastjson 框架注解来指定字段顺序
public class MyUser {
@JSONField(name = "user_id", ordinal = 1)
private String userId;
@JSONField(name = "user_name", ordinal = 2)
private String userName;
// Getters, Setters
}
2
3
4
5
6
7
8
9
10
11
此时进行数据的序列化,就不会出现乱序问题
// 作为 Query 参数
@Get("http://localhost:8080/user/info")
String getUserInfo(@Query MyUser myUser);
// 产生请求:
// http://localhost:8080/user/info?user_id=xx&user_name=xxx
// 按 snake_case 进行命名 query 参数
// 没有乱序
// 作为请求头
@Get("http://localhost:8080/user/info2")
String getUserInfo2(@Header MyUser myUser);
// 产生请求:
// http://localhost:8080/user/info2
// Headers:
// user_id: xx
// user_name: xxx
// 按 snake_case 进行命名请求头参数
// 没有乱序
// 作为 Body 数据
@Post(url = "http://localhost:8080/user", contentType="application/json")
String submitUserInfo(@Body MyUser myUser);
// 产生请求:
// http://localhost:8080/user
// Body: {"user_id": "xx", "user_name": "xxx"}
// 按 snake_case 进行命名 JSON Body 字段名
// 没有乱序
// 乃至其他数据格式的的 Body 数据
@Post(url = "http://localhost:8080/user", contentType="application/x-www-form-urlencoded")
String submitUserInfo(@Body MyUser myUser);
// 产生请求:
// http://localhost:8080/user
// Body: user_id=xx&user_name=xxx
// 按 snake_case 进行命名 Form Body 字段名
// 没有乱序
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
对于 Fastjson2 / Fastjson 注解的其他用法,以及其他 JSON 框架的用法,可以阅读相关框架的官网文档