一、一个常见场景
有时候 我们的系统需要对接第三方的系统,其返回一般都会有一个比较统一的格式,如下所示:
{
code : ...,
message : ...,
data : ...
}
具体返回的数据,可能是这样的:
{
code : 0,
message : success,
data : {
userId : "001",
userName : "nep"
}
}
{
code : 0,
message : success,
data :
[
{
bookNum : "XCN003",
bookName : "小说",
price : 29.9
}
{
bookNum : "XCN004",
bookName : "诗歌",
price : 69.9
}
]
}
观察data部分,可以看到,最外层json 格式是固定的,而data里边的数据,是每个接口返回是不同的。
那么,对于数据的返回类型的构建,顺理成章地成了这样:
首先,data部分的实体类 User、Book
public class User{
private String userId;
private String userName;
// get、set
}
public class Book{
private String bookNum;
private String bookName;
private BigDecimal price;
// get、set
}
然后就是最外层:
- 公共的基类
public class AppHttpResponse {
private String code;
private String message;
// get、set
}
- 里层data,根据接口类型来
//第一个接口,查询user的
QueryUserResponse extends AppHttpResponse{
private User data;
// get、set
}
//第二个接口,查询book的
QueryBookResponse extends AppHttpResponse{
private List<Book> data;
// get、set
}
现在,我们需要一个请求方法。在springboot工程中,我们可以这样写:
// 这是公共的请求方法
@Component
public class AppHttpClient {
@Value("${http.baseUrl}")
private String baseUrl;
public String sendPostRequest(String code,Map<String, Object> params){
// 构建请求头
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_JSON);
// 构建请求体(参数)
MultiValueMap<String, Object> multiValueMap = new LinkedMultiValueMap<>();
for (Map.Entry entry : params.entrySet()) {
multiValueMap.add(entry.getKey().toString(),entry.getValue());
}
HttpEntity<MultiValueMap<String, Object>> requestEntity = new HttpEntity<>(multiValueMap, headers);
// 请求类型。这里用 post 请求
HttpMethod method = HttpMethod.POST;
RestTemplate client = new RestTemplate();
ResponseEntity<String> response = client.exchange(baseUrl + code, method, requestEntity,String.class);
return response.getBody();
}
}
然后,在controller中的调用:
controller{
Map<String,Object> params_queryUser = new HashMap();
params_queryUser.put("userId", "1");
String result = client.sendPostRequest("queryUser",params_queryUser);
// 转换
QueryUserResponse queryUserResponse = JSON.parseObject(result,QueryUserResponse.class);
Map<String,Object> params_queryBook = new HashMap();
params_queryBook.put("bookNum", "1");
String result2 = client.sendPostRequest("queryBook",params_queryBook);
// 转换
QueryBookResponse queryBookResponse = JSON.parseObject(result2,QueryBookResponse.class);
}
二、使用泛型,优化代码
上面的代码其实也没什么问题,功能上都ok。但是,这里数据获取与数据转换,分为了2步。我们知道,代码讲求简洁高效,那么能不能一步到位呢?我们将“获取数据”与“转化数据”合成一个整体,获取来的数据直接转化为对应的数据类型。这里可以考虑使用泛型。下面看代码:
// 修改统一请求方法,直接返回对应数据类型
@Component
public class AppHttpClient {
@Value("${http.baseUrl}")
private String baseUrl;
public <T>T sendPostRequest(String code,Map<String, Object> params, Class<T> clz){
// 构建请求头
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_JSON);
// 构建请求体(参数)
MultiValueMap<String, Object> multiValueMap = new LinkedMultiValueMap<>();
for (Map.Entry entry : params.entrySet()) {
multiValueMap.add(entry.getKey().toString(),entry.getValue());
}
HttpEntity<MultiValueMap<String, Object>> requestEntity = new HttpEntity<>(multiValueMap, headers);
// 请求类型。这里用 post 请求
HttpMethod method = HttpMethod.POST;
RestTemplate client = new RestTemplate();
ResponseEntity<String> response = client.exchange(baseUrl + code, method, requestEntity,String.class);
// 根据 clz 转换成对应类,并返回
T t = JSON.parseObject(response.getBody(),clz);
return t;
}
}
其实,最后一步转化 JSON.parseObject 可以省掉,RestTemplate提供类似方法,如下:
@Component
public class AppHttpClient {
@Value("${http.baseUrl}")
private String baseUrl;
public <T>T sendPostRequest(String code,Map<String, Object> params, Class<T> clz){
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_JSON);
HttpEntity requestEntity = new HttpEntity<>(params, headers);
RestTemplate client = new RestTemplate();
T t = client.postForObject(gridUrl+code,requestEntity,clz);
return t;
}
}
再看controller中的代码,是不是简洁清晰了点呢
controller{
Map<String,Object> params_queryUser = new HashMap();
params_queryUser.put("userId", "1");
QueryUserResponse queryUserResponse = client.sendPostRequest("queryUser",params_queryUser,QueryUserResponse.class);
Map<String,Object> params_queryBook = new HashMap();
params_queryBook.put("bookNum", "1");
QueryBookResponse queryBookResponse = client.sendPostRequest("queryBook",params_queryBook,QueryBookResponse.class);
}
三、泛型方法
简单了解下泛型方法的定义:
public <T>T method(Class<T> clz){
T t = clz.newInstance();
return t;
}
这里 T 即代表所传入的 clz 。泛型方法的入参中,必有一个Class clz。方法的返回类型为T,且前面带有,是不可少的。