封装get post等请求
当你在项目中遇到一个需求,需要大量的调用各种参数不同并且响应返回也不同的外部API的时候,其中相同的部分和变化的部分有想过分离吗,不同的部分不外乎是请求参数和返回体,这两部分最后体现在就是每一个请求新加两个bean,请求的bean和返回的bean,其它执行调用外部API的部分都可以提取出来作为公共的功能。
定义一个请求类的接口
该接口中可以获取url,参数,返回response,返回实体类等信息.并且该接口利用泛型的方式为后续请求类和返回类的映射提前做好关联
public interface Request<T extends AbstractResponse> {
/**
* 获取响应对应的类型
*
* @return 需要解析成的对象类型
*/
Class<T> getResponseClass();
/**
* 获取请求地址
*
* @return 请求地址
*/
String getUrl();
/**
* 获取请求参数集合
*
* @return 请求参数集合
*/
Map<String, Object> getParamMap();
/**
* 获取请求令牌
*
* @return 请求令牌
*/
PlatformToken getToken();
/**
* 获取请求方式,枚举有:
* <li>GET,对应HTTP GET</li>
* <li>POST, 对应HTTP POST</li>
* <li>REQUEST_BODY,对应HTTP POST,但请求体是JSON、XML等自定义数据格式</li>
*
* @return 请求方式
*/
RequestMethod getRequestMethod();
/**
* 获取请求体
*
* @return 请求体
*/
String getBody();
}
定义AbstractResponse抽象类定义好返回体的基本格式
public abstract class AbstractResponse {
/** 响应代码 */
private Integer code;
/** 详细信息 */
private String message;
/** 完整报文 */
private String body;
/**
* 获取响应代码
*
* @return 响应代码
*/
public Integer getCode() {
return code;
}
/**
* 设置响应代码
*
* @param code
* 响应代码
*/
public void setCode(Integer code) {
this.code = code;
}
/**
* 获取详细信息
*
* @return 详细信息
*/
public String getMessage() {
return message;
}
/**
* 设置详细信息
*
* @param message
* 详细信息
*/
public void setMessage(String message) {
this.message = message;
}
/**
* 获取完整报文
*
* @return 完整报文
*/
public String getBody() {
return body;
}
/**
* 设置完整报文
*
* @param body
* 完整报文
*/
public void setBody(String body) {
this.body = body;
}
/**
* 判断请求是否是符合我们预期的,通常code为0的时候,这是正常的。
*
* @return 符合预期
*/
public boolean isSuccess() {
return code.equals(0);
}
/**
* 判断是不是未授权错误
*
* @return 状态码为1015、1016、4000
*/
public boolean isUnauthorized() {
return code.equals(1015) || code.equals(1016) || code.equals(4000);
}
}
然后我们写Request接口的实现类,实现类我们也用抽象来进行,为了后续扩展方便
public abstract class AbstracRequest<T extends AbstractResponse> implements Request<T> {
/** the base API URL */
private static final String API_URL = "https://baidu.com/api/v2/";
/** 请求参数 */
protected Map<String, Object> paramMap = new HashMap<>();
/** 请求令牌 */
protected PlatformToken token;
/**
* 使用token构造
*
* @param token
* 令牌
*/
public AbstractRequest(PlatformToken token) {
this.token = token;
}
/**
* 获取请求地址
*
* @return 请求地址
*/
@Override
public String getUrl() {
String urlPath = this.getUrlPath();
return urlPath.startsWith("http") ? urlPath : API_URL + urlPath;
}
/**
* 获取请求参数集合
*
* @return 请求参数集合
*/
@Override
public Map<String, Object> getParamMap() {
return paramMap;
}
/**
* 获取请求令牌
*
* @return 请求令牌
*/
@Override
public PlatformToken getToken() {
return token;
}
/**
* 获取请求体
*
* @return 请求体,默认 <code>null</code>
*/
@Override
public String getBody() {
return null;
}
/**
* 获取请求路径,可以是绝对路径
*
* @return 请求路径
*/
protected abstract String getUrlPath();
}
这样我们把请求和返回的大致结构以及请求方法确定下来,那么具体到某一个请求我们可以如下去进行,只要去继承AbstracRequest,并且把reponse具体的类确定下来就可以
public class ProductCreateRequest extends AbstractRequest<ProductResponse> {
/** 使用令牌构造 */
public ProductCreateRequest(PlatformToken token) {
super(token);
}
@Override
public Class<ProductResponse> getResponseClass() {
return ProductResponse.class;
}
@Override
public String getUrlPath() {
return "product/add";
}
@Override
public RequestMethod getRequestMethod() {
return RequestMethod.POST;
}
/**
* 设置标题
*
* @param name
* 标题
*/
public void setName(String name) {
paramMap.put("name", name);
}
/**
* 设置描述
*
* @param description
* 描述
*/
public void setDescription(String description) {
paramMap.put("description", description);
}
}
public class ProductResponse extends Response<ProductDataType> {
}
这样当我们具体执行get或者post请求的时候其实当我们初始化request的时候就已经把所有东西都确定好了
/**
* 执行GET或者POST请求
*
* @param req
* 请求体
* @param paramMap
* 请求参数
* @return 请求响应报文
*/
private <T extends AbstractResponse> String doGetOrPost(Request<T> req, Map<String, Object> paramMap) {
HttpRequest request = null;
// 获取相应处理
if (req.getRequestMethod() == RequestMethod.GET) {
request = getHttpRequest4Get(req.getUrl());
} else if (req.getRequestMethod() == RequestMethod.POST
|| req.getRequestMethod() == RequestMethod.REQUEST_BODY) {
request = getHttpRequest4Post(req.getUrl());
} else {
throw new IllegalArgumentException("暂不支持该方法:" + req.getRequestMethod());
}
// 补充参数
if (req.getRequestMethod() == RequestMethod.REQUEST_BODY) {
Map<String, Object> form = new HashMap<>(1);
form.put(ACCESS_TOKEN, paramMap.remove(ACCESS_TOKEN));
String url = HttpUtil.urlWithForm(request.getUrl(), form, CharsetUtil.CHARSET_UTF_8, false);
request.setUrl(url);
request.body(JSONObject.toJSONString(paramMap));
} else {
request.form(paramMap);
}
return request.execute().body();
}
这样后续如果新增调用外部API,你只需新增和ProductCreateRequest 一样的继承类就可以了,其它的代码不用动。