夏眠鱼

May 06, 2016

实体化请求参数

找个理由

获取「新闻列表」的请求地址,一般我们是这样写的:

1
String url = MobileApi.GET_NEWSES + "?channelID=" + mChannelID + "pageNo=" + mPageNo + "&pageSize=30";

这种写法其实不利于项目的后期维护,如果项目大规模地更改接口字段名,就要一个个文件去查找修改,单查找这步就消耗了很多时间,这显然不符合程序员懒惰的特性。我的做法是把请求参数实体化,并放到一个package下统一管理,以后要修改,直接去package下找到对应的参数(实体类)修改就可以了。

实体化请求参数后的写法:

1
2
NewsParam param = new NewsParam(mChannelID, mPageNo);
String url = MobileApi.GET_NEWSES + ParamFormatter.toUri(param);

具体实现

假设「获取新闻列表」请求接口地址为:http:localhost/getNewses?channelID=&pageNo=&pageSize

接口参数映射

1
2
3
4
5
6
7
public class MobileApi {

public static final String HOST = "http:localhost/";

// 获取新闻列表
public static finsl String GET_NEWSES = HOST + "getNewses";
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
public class NewsParam {

// 栏目ID
@SerializedName("channelID")
private int mChannelID;

// 页码
@SerializedName("pageNo")
private int mPageNo;

// 每页大小,这里固定是30条
@SerializedName("pageSize")
private int mPageSize = 30;

public NewsParam() {}

public NewsParam(int channelID, int pageNo) {
mChannelID = channelID;
mPageNo = pageNo;
}

// getting and setters
}

使用 Gson 的注解 SerializedName 将接口字段名称映射为自定义名称,如 channelID 映射为 mChannelID,这样如果接口字段名称改了,只需修改 SerializedName 的值即可,是不是很方便。

参数类型转换

做了接口参数名称映射后,下一步就是对 Get / Post 请求参数做类型转换了,我们把类型转换工作放到 ParamFormatter 中处理,下面是它的具体实现:

1
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
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
public class ParamFormatter {

/**
* 转换成json
* @return
*/
public static String toJson(Object object) {
return new Gson().toJson(object);
}

/**
* 转换成uri
*
* @return
*/
public static String toUri(Object object) {
return generateUri("?", object);
}

/**
* 转换成多个参数拼接
*
* @return
*/
private static String generateUri(String prefix, Object object) {
StringBuffer uriSb = new StringBuffer();

JSONObject jsonObject = null;
Iterator<String> keys = null;

try {
jsonObject = new JSONObject(toJson(object));
keys = jsonObject.keys();

while (keys.hasNext()) {
String key = keys.next();
Object value = jsonObject.get(key);

key = URLEncoder.encode(key);
value = URLEncoder.encode(String.valueOf(value));

uriSb.append("&").append(key).append("=").append(value);
uriSb.replace(0, 1, prefix);
}
} catch (JSONException e) {
e.printStackTrace();
}

return uriSb.toString();
}

/**
* 转换成Map
*
* @return
*/
@SuppressWarnings("unchecked")
public static Map<String, String> toMap(Object object) {
Map<String, String> map = new HashMap<String, String>();

JSONObject jsonObject = null;
Iterator<String> keys = null;

try {
jsonObject = new JSONObject(toJson(object));
keys = jsonObject.keys();

while (keys.hasNext()) {
String key = keys.next();
String value = String.valueOf(jsonObject.get(key));
map.put(key, value);
}
} catch (JSONException e) {
e.printStackTrace();
}

return map;
}

// 后续可以添加各种格式的转换...
}

零件组装

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
public class NewsFragment extends CommonFragment {

private NewsParam mNewsParam;

@Override
protected void initVariables(Bundle savedInstanceState) {
mNewsParam = new NewsParam();
}

@Override
protected String getUrl(int channelID, int pageNo) {
mNewsParam.setChannelID(channelID);
mNewsParam.setPageNo(pageNo);
return MobileApi.GET_NEWSES + ParamFormatter.toUri(mNewsParam);
}
}

OLDER > < NEWER