YanFrp/src/main/java/top/octopusyan/manager/http/EasyHttp.java
2022-04-09 03:59:20 +08:00

576 lines
19 KiB
Java
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

package top.octopusyan.manager.http;
import okhttp3.*;
import top.octopusyan.manager.http.annotation.HttpHeader;
import top.octopusyan.manager.http.annotation.HttpIgnore;
import top.octopusyan.manager.http.annotation.HttpRename;
import top.octopusyan.manager.http.api.NotParamApi;
import top.octopusyan.manager.http.api.ParamApi;
import top.octopusyan.manager.http.api.PathParamApi;
import top.octopusyan.manager.http.api.RequestApi;
import top.octopusyan.manager.http.callback.NormalCallback;
import top.octopusyan.manager.http.listener.OnHttpListener;
import top.octopusyan.manager.http.model.CallProxy;
import top.octopusyan.manager.http.model.HttpHeaders;
import top.octopusyan.manager.http.model.HttpParams;
import top.octopusyan.manager.http.model.JsonBody;
import top.octopusyan.manager.http.config.BodyType;
import top.octopusyan.manager.http.config.HttpConstant;
import top.octopusyan.manager.http.request.IRequestHandler;
import top.octopusyan.manager.http.model.ResponseClass;
import java.io.File;
import java.io.InputStream;
import java.lang.reflect.Field;
import java.text.MessageFormat;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
/**
* @author : octopus yan
* @email : octopus_yan@foxmail.com
* @description : http 请求工具
* @create : 2022-4-1 15:14
*/
public class EasyHttp<Param, Result> {
/** 请求处理策略 */
private final IRequestHandler mHandler = HttpConfig.getInstance().getHandler();
/** 请求执行代理类 */
private CallProxy mCallProxy;
/** 请求标记 */
private String mTag;
/** 请求延迟 */
private long mDelayMillis;
/** 请求服务地址 */
private final String server = HttpConfig.getInstance().getServerPath();
/** 请求接口 */
private RequestApi<Param, Result> mRequestApi;
/** 请求参数 */
private Param param;
public static class Builder {
private String method;
private String apiPath;
private BodyType bodyType;
public <Param, Result> ParamRequest<Param, Result> api(ParamApi<Param, Result> api) {
return new ParamRequest<Param, Result>().api(api);
}
public <Result> UrlRequest<Result> api(NotParamApi<Result> api) {
return new UrlRequest<Result>().api(api);
}
public <Result> RestfulRequest<Result> api(PathParamApi<Result> api) {
return new RestfulRequest<Result>().api(api);
}
public <Param, Result> EasyHttp<Param, Result> api(RequestApi<Param, Result> api) {
return new EasyHttp<Param, Result>().api(api);
}
/**
* 无参数请求
*/
public <Result> UrlRequest<Result> build(ResponseClass<Result> result) {
if(apiPath == null) throw new IllegalArgumentException("请求接口地址为空!");
NotParamApi<Result> requestApi = new NotParamApi<>(apiPath, method, bodyType);
return new UrlRequest<Result>().api(requestApi);
}
/**
* 带参请求
* @param param 请求参数
*/
public <Param, Result> ParamRequest<Param, Result> build(Param param, ResponseClass<Result> result) {
ParamApi<Param, Result> requestApi = new ParamApi<>(apiPath, method, bodyType);
return new ParamRequest<Param, Result>().api(requestApi).param(param);
}
public Builder setMethod(String method) {
this.method = method;
return this;
}
public Builder setApiPath(String apiPath) {
this.apiPath = apiPath;
return this;
}
public Builder setBodyType(BodyType bodyType) {
this.bodyType = bodyType;
return this;
}
}
public static Builder builder(){
return new Builder();
}
protected EasyHttp<Param, Result> api(RequestApi<Param, Result> api) {
this.mRequestApi = api;
return this;
}
protected EasyHttp<Param, Result> param(Param param) {
this.param = param;
return this;
}
private RequestApi<Param, Result> getRequestApi() {
return mRequestApi;
}
private IRequestHandler getRequestHandler() {
return mHandler;
}
protected void path(String path) {
this.mRequestApi.setApi(path);
}
protected String getPath(){
return this.mRequestApi.getApi();
}
public String getTag() {
return mTag;
}
public void setTag(String mTag) {
this.mTag = mTag;
}
public long getDelayMillis() {
return mDelayMillis;
}
public void setDelayMillis(long mDelayMillis) {
this.mDelayMillis = mDelayMillis;
}
/**
* 执行异步请求
*/
public void request(OnHttpListener<Result> listener) {
if (mDelayMillis > 0) {
// 打印请求延迟时间
HttpLog.print("RequestDelay", String.valueOf(mDelayMillis));
}
StackTraceElement[] stackTrace = new Throwable().getStackTrace();
EasyUtils.postDelayed(() -> {
HttpLog.print(stackTrace);
mCallProxy = new CallProxy(createCall());
mCallProxy.enqueue(new NormalCallback(mCallProxy, mRequestApi, mHandler, listener));
}, mDelayMillis);
}
/**
* 执行同步请求
* @param responseClass 需要解析泛型的对象
* @return 返回解析完成的对象
* @throws Exception 如果请求失败或者解析失败则抛出异常
*/
public Result execute(ResponseClass<Result> responseClass) throws Exception {
if (mDelayMillis > 0) {
// 打印请求延迟时间
HttpLog.print("RequestDelay", String.valueOf(mDelayMillis));
Thread.sleep(mDelayMillis);
}
HttpLog.print(new Throwable().getStackTrace());
try {
mCallProxy = new CallProxy(createCall());
Response response = mCallProxy.execute();
return (Result) mHandler.requestSucceed(getRequestApi(), response, EasyUtils.getReflectType(responseClass));
} catch (Exception e) {
throw mHandler.requestFail(getRequestApi(), e);
}
}
/**
* 创建请求回调
*/
private Call createCall() {
String url = server + mRequestApi.getApi();
HttpParams params = new HttpParams();
HttpHeaders headers = new HttpHeaders();
BodyType type = mRequestApi.getBodyType();
if(param != null) setParam(params, headers, type);
return HttpConfig.getInstance().getClient().newCall(createRequest(url, mTag, params, headers, type));
}
private void setParam(HttpParams params, HttpHeaders headers, BodyType type){
List<Field> fields = new ArrayList<>();
Class<?> clazz = param.getClass();
do {
Field[] declaredFields = clazz.getDeclaredFields();
fields.addAll(0, Arrays.asList(declaredFields));
// 遍历获取父类的字段
clazz = clazz.getSuperclass();
} while (clazz != null && !Object.class.equals(clazz));
// 当前请求是否存在流参数
params.setMultipart(EasyUtils.isMultipart(fields));
// 如果参数中包含流参数并且当前请求方式不是表单的话
if (params.isMultipart() && type != BodyType.FORM) {
// 就强制设置成以表单形式提交参数
type = BodyType.FORM;
}
for (Field field : fields) {
// 允许访问私有字段
field.setAccessible(true);
try {
// 获取字段的对象
Object value = field.get(param);
// 获取字段的名称
String key;
HttpRename annotation = field.getAnnotation(HttpRename.class);
if (annotation != null) {
key = annotation.value();
} else {
key = field.getName();
// 如果是内部类则会出现一个字段名为 this$0 的外部类对象,会导致无限递归,这里要忽略掉,如果使用静态内部类则不会出现这个问题
// 和规避 Kotlin 自动生成的伴生对象https://github.com/getActivity/EasyHttp/issues/15
if (key.matches("this\\$\\d+") || "Companion".equals(key)) {
continue;
}
}
// 如果这个字段需要忽略,则进行忽略
if (field.isAnnotationPresent(HttpIgnore.class)) {
if (field.isAnnotationPresent(HttpHeader.class)) {
headers.remove(key);
} else {
params.remove(key);
}
continue;
}
// 前提是这个字段值不能为空(基本数据类型有默认的值,而对象默认的值为 null
if (EasyUtils.isEmpty(value)) {
// 遍历下一个字段
continue;
}
// 如果这是一个请求头参数
if (field.isAnnotationPresent(HttpHeader.class)) {
if (value instanceof Map) {
Map<?, ?> map = ((Map<?, ?>) value);
for (Object o : map.keySet()) {
if (o != null && map.get(o) != null) {
headers.put(String.valueOf(o), String.valueOf(map.get(o)));
}
}
} else {
headers.put(key, String.valueOf(value));
}
continue;
}
// 否则这就是一个普通的参数
switch (type) {
case FORM:
if (value instanceof Map) {
Map<?, ?> map = ((Map<?, ?>) value);
for (Object o : map.keySet()) {
if (o != null && map.get(o) != null) {
params.put(String.valueOf(o), map.get(o));
}
}
} else {
params.put(key, value);
}
break;
case JSON:
if (value instanceof List) {
// 如果这是一个 List 参数
params.put(key, EasyUtils.listToJsonArray(((List<?>) value)));
} else if (value instanceof Map) {
// 如果这是一个 Map 参数
params.put(key, EasyUtils.mapToJsonObject(((Map<?, ?>) value)));
} else if (EasyUtils.isBeanType(value)) {
// 如果这是一个 Bean 参数
params.put(key, EasyUtils.mapToJsonObject(EasyUtils.beanToHashMap(value)));
} else {
// 如果这是一个普通的参数
params.put(key, value);
}
break;
default:
break;
}
} catch (IllegalAccessException e) {
HttpLog.print(e);
}
}
}
/**
* 创建 okhttp 请求
*
* @param url 请求地址
* @param tag 标记
* @param params 参数
* @param headers 请求头
* @param type 参数提交方式
* @return okhttp 请求对象
*/
private Request createRequest(String url, String tag, HttpParams params, HttpHeaders headers, BodyType type) {
Request.Builder request = new Request.Builder();
if (tag != null) {
request.tag(tag);
}
// 添加请求头
if (!headers.isEmpty()) {
for (String key : headers.getNames()) {
request.addHeader(key, headers.get(key));
}
}
RequestBody body = null;
String requestUrl = "";
String httpMethod = getRequestApi().getMethod();
switch (httpMethod){
case HttpConstant.Method.GET:
HttpUrl.Builder builder = HttpUrl.get(url).newBuilder();
// 添加参数
if (!params.isEmpty()) {
for (String key : params.getNames()) {
builder.addEncodedQueryParameter(key, String.valueOf(params.get(key)));
}
}
HttpUrl link = builder.build();
requestUrl = String.valueOf(link);
request.url(link);
break;
case HttpConstant.Method.POST:
request.url(url);
requestUrl = url;
body = createBody(params, type);
break;
}
request.method(httpMethod, body);
HttpLog.print("RequestUrl", requestUrl);
HttpLog.print("RequestMethod", httpMethod);
// 打印请求头和参数的日志
if (HttpConfig.getInstance().isLogEnabled()) {
if (!headers.isEmpty() || !params.isEmpty()) {
HttpLog.print();
}
for (String key : headers.getNames()) {
HttpLog.print(key, headers.get(key));
}
if (!headers.isEmpty() && !params.isEmpty()) {
HttpLog.print();
}
for (String key : params.getNames()) {
HttpLog.print(key, String.valueOf(params.get(key)));
}
if (!headers.isEmpty() || !params.isEmpty()) {
HttpLog.print();
}
}
return getRequestHandler().requestStart(getRequestApi(), request.build());
}
/**
* 组装 RequestBody 对象
*/
private RequestBody createBody(HttpParams params, BodyType type) {
RequestBody body;
if (params.isMultipart() && !params.isEmpty()) {
MultipartBody.Builder builder = new MultipartBody.Builder();
builder.setType(MultipartBody.FORM);
for (String key : params.getNames()) {
Object object = params.get(key);
// 如果这是一个 File 对象
if (object instanceof File) {
MultipartBody.Part part = EasyUtils.createPart(key, (File) object);
if (part != null) {
builder.addPart(part);
}
continue;
}
// 如果这是一个 InputStream 对象
if (object instanceof InputStream) {
MultipartBody.Part part = EasyUtils.createPart(key, (InputStream) object);
if (part != null) {
builder.addPart(part);
}
continue;
}
// 如果这是一个自定义的 MultipartBody.Part 对象
if (object instanceof MultipartBody.Part) {
builder.addPart((MultipartBody.Part) object);
continue;
}
// 如果这是一个自定义的 RequestBody 对象
if (object instanceof RequestBody) {
builder.addFormDataPart(key, null, (RequestBody) object);
continue;
}
// 如果这是一个普通参数
builder.addFormDataPart(key, String.valueOf(object));
}
try {
body = builder.build();
} catch (IllegalStateException ignored) {
// 如果参数为空则会抛出异常Multipart body must have at least one part.
body = new FormBody.Builder().build();
}
} else if (type == BodyType.JSON) {
body = new JsonBody(params.getParams());
} else {
FormBody.Builder builder = new FormBody.Builder();
if (!params.isEmpty()) {
for (String key : params.getNames()) {
builder.add(key, String.valueOf(params.get(key)));
}
}
body = builder.build();
}
return body;
}
/**
* 根据 TAG 取消请求任务
*/
public static void cancel(Object tag) {
if (tag == null) {
return;
}
OkHttpClient client = HttpConfig.getInstance().getClient();
// 清除排队等候的任务
for (Call call : client.dispatcher().queuedCalls()) {
if (tag.equals(call.request().tag())) {
call.cancel();
}
}
// 清除正在执行的任务
for (Call call : client.dispatcher().runningCalls()) {
if (tag.equals(call.request().tag())) {
call.cancel();
}
}
}
/**
* 清除所有请求任务
*/
public static void cancel() {
OkHttpClient client = HttpConfig.getInstance().getClient();
// 清除排队等候的任务
for (Call call : client.dispatcher().queuedCalls()) {
call.cancel();
}
// 清除正在执行的任务
for (Call call : client.dispatcher().runningCalls()) {
call.cancel();
}
}
/**
* 无参数请求
*/
public static class UrlRequest<Result> extends EasyHttp<Void, Result> {
@Override
public UrlRequest<Result> api(RequestApi<Void, Result> api) {
super.api(api);
return this;
}
}
/**
* 路径参数请求
*/
public static class RestfulRequest<Result> extends EasyHttp<Void, Result> {
@Override
public RestfulRequest<Result> api(RequestApi<Void, Result> api) {
super.api(api);
return this;
}
/**
* @param params 路径参数
*/
public RestfulRequest<Result> pathParam(String... params) {
super.path(MessageFormat.format(getPath(), params));
return this;
}
}
/**
*
* 带参数请求
*
* @param <Param> 参数类型
* @param <Result> 返回结果类型
*/
public static class ParamRequest<Param, Result> extends EasyHttp<Param, Result> {
@Override
public ParamRequest<Param, Result> api(RequestApi<Param, Result> api) {
super.api(api);
return this;
}
@Override
public ParamRequest<Param, Result> param(Param param) {
super.param(param);
return this;
}
}
}