package top.octopusyan.common.http; import okhttp3.*; import top.octopusyan.common.http.annotation.HttpHeader; import top.octopusyan.common.http.annotation.HttpIgnore; import top.octopusyan.common.http.annotation.HttpRename; import top.octopusyan.common.http.api.NotParamApi; import top.octopusyan.common.http.api.ParamApi; import top.octopusyan.common.http.api.PathParamApi; import top.octopusyan.common.http.api.RequestApi; import top.octopusyan.common.http.callback.NormalCallback; import top.octopusyan.common.http.listener.OnHttpListener; import top.octopusyan.common.http.model.CallProxy; import top.octopusyan.common.http.model.HttpHeaders; import top.octopusyan.common.http.model.HttpParams; import top.octopusyan.common.http.model.JsonBody; import top.octopusyan.common.http.config.BodyType; import top.octopusyan.common.http.config.HttpConstant; import top.octopusyan.common.http.request.IRequestHandler; import top.octopusyan.common.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 { /** 请求处理策略 */ 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 mRequestApi; /** 请求参数 */ private Param param; public static class Builder { private String method; private String apiPath; private BodyType bodyType; public ParamRequest api(ParamApi api) { return new ParamRequest().api(api); } public UrlRequest api(NotParamApi api) { return new UrlRequest().api(api); } public RestfulRequest api(PathParamApi api) { return new RestfulRequest().api(api); } public EasyHttp api(RequestApi api) { return new EasyHttp().api(api); } /** * 无参数请求 */ public UrlRequest build(ResponseClass result) { if(apiPath == null) throw new IllegalArgumentException("请求接口地址为空!"); NotParamApi requestApi = new NotParamApi<>(apiPath, method, bodyType); return new UrlRequest().api(requestApi); } /** * 带参请求 * @param param 请求参数 */ public ParamRequest build(Param param, ResponseClass result) { ParamApi requestApi = new ParamApi<>(apiPath, method, bodyType); return new ParamRequest().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 api(RequestApi api) { this.mRequestApi = api; return this; } protected EasyHttp param(Param param) { this.param = param; return this; } private RequestApi 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 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 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 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 extends EasyHttp { @Override public UrlRequest api(RequestApi api) { super.api(api); return this; } } /** * 路径参数请求 */ public static class RestfulRequest extends EasyHttp { @Override public RestfulRequest api(RequestApi api) { super.api(api); return this; } /** * @param params 路径参数 */ public RestfulRequest pathParam(Object... params) { super.path(MessageFormat.format(getPath(), params)); return this; } } /** * * 带参数请求 * * @param 参数类型 * @param 返回结果类型 */ public static class ParamRequest extends EasyHttp { @Override public ParamRequest api(RequestApi api) { super.api(api); return this; } @Override public ParamRequest param(Param param) { super.param(param); return this; } } }