package com.zy.common.utils; import okhttp3.*; import java.io.IOException; import java.util.Map; import java.util.Optional; import java.util.concurrent.TimeUnit; /** * Http协议客户端 * @author luxiaotao * @date 2018-9-27 */ public class HttpHandler { private static final Integer DEFAULT_TIMEOUT_SECONDS = 5; private static final MediaType MEDIA_TYPE_JSON = MediaType.parse("application/json;charset=utf-8"); private static final MediaType MEDIA_TYPE_FORM = MediaType.parse("application/x-www-form-urlencoded;charset=utf-8"); private String uri; private String path; private String json; private Map params; private Map headers; private boolean https; private Integer timeout; private TimeUnit timeUnit; private boolean useFormUrlEncoded; // 新增:标识是否使用x-www-form-urlencoded格式 public HttpHandler(Builder builder){ this.uri = builder.uri; this.path = builder.path; this.json = builder.json; this.params = builder.params; this.headers = builder.headers; this.https = builder.https; this.timeout = builder.timeout; this.timeUnit = builder.timeUnit; this.useFormUrlEncoded = builder.useFormUrlEncoded; // 新增 } /** * GET请求执行 * @return the HttpHandler response */ public String doGet() throws IOException { String url = paramsToUrl(uri, path, params, https); Request.Builder headerBuilder = new Request.Builder(); if (headers != null && headers.size()>0){ for (Map.Entry entry : headers.entrySet()){ headerBuilder.addHeader(entry.getKey(), String.valueOf(entry.getValue())); } } Request request = headerBuilder.url(url).build(); Response response = getClient(timeout, timeUnit).newCall(request).execute(); return response.isSuccessful() ? response.body().string() : null; } /** * POST请求执行 * @return the HttpHandler response */ public String doPost() throws IOException { Request request; Request.Builder headerBuilder = new Request.Builder(); // 设置请求头 if (headers != null && headers.size()>0){ for (Map.Entry entry : headers.entrySet()){ headerBuilder.addHeader(entry.getKey(), String.valueOf(entry.getValue())); } } // 根据useFormUrlEncoded标志选择请求体格式 if (useFormUrlEncoded) { // 使用x-www-form-urlencoded格式[1,2,6](@ref) FormBody.Builder formBuilder = new FormBody.Builder(); if (params != null && !params.isEmpty()) { // 添加表单参数[2,6,7](@ref) for (Map.Entry entry : params.entrySet()) { formBuilder.add(entry.getKey(), String.valueOf(entry.getValue())); } } else if (json != null && !json.isEmpty()) { // 如果提供了json字符串,尝试解析为键值对(简单实现) // 注意:这里需要根据实际情况调整json解析逻辑 String formattedParams = parseJsonToFormData(json); if (formattedParams != null) { String[] pairs = formattedParams.split("&"); for (String pair : pairs) { String[] keyValue = pair.split("=", 2); if (keyValue.length == 2) { formBuilder.add(keyValue[0], keyValue[1]); } } } } FormBody formBody = formBuilder.build(); request = headerBuilder .url((https?"https://":"http://")+uri+path) .post(formBody) .build(); } else { // 原有的JSON格式处理 if (json == null || "".equals(json)){ FormBody.Builder builder = new FormBody.Builder(); for (Map.Entry entry : params.entrySet()){ builder.add(entry.getKey(), String.valueOf(entry.getValue())); } FormBody body = builder.build(); request = headerBuilder .url((https?"https://":"http://")+uri+path) .post(body) .build(); } else { RequestBody body = RequestBody.create(MEDIA_TYPE_JSON, json); Request.Builder builder = headerBuilder.url((https?"https://":"http://")+uri+path); builder.header("Content-Type", "application/json;charset=UTF-8"); request = builder.post(body).build(); } } Call call = getClient(timeout, timeUnit).newCall(request); Response response = call.execute(); return response.body().string(); } /** * 将JSON字符串转换为表单数据格式(简易实现) * @param json JSON字符串 * @return 表单数据字符串 */ private String parseJsonToFormData(String json) { // 简易实现:移除JSON的大括号和引号,替换冒号为等号,逗号为& // 注意:对于复杂JSON需要更完善的解析逻辑 return json.replaceAll("[{}\"]", "") .replaceAll(":", "=") .replaceAll(",", "&"); } /** * get请求参数拼接方法 * @return 请求行 */ private String paramsToUrl(String uri, String path, Map params, boolean isHttps) { StringBuilder res = new StringBuilder(); res.append(isHttps ? "https://" : "http://"); res.append(uri); if (path.length() > 0 && !(path.charAt(0) == '/')){ res.append("/"); } res.append(path); Optional.ofNullable(params).ifPresent( args -> { res.append("?"); args.forEach((key, value) -> { res.append(key); res.append("="); res.append(value); res.append("&"); }); } ); String url = res.toString(); if ("&".equals(url.substring(url.length()-1, url.length()))){ url = url.substring(0, url.length()-1); } return url; } /** * 获取 okHttpClient * @return the HttpHandler instance */ private OkHttpClient getClient(Integer timeout, TimeUnit timeUnit){ return new OkHttpClient .Builder() .connectTimeout(timeout, timeUnit) .readTimeout(timeout, timeUnit) .build(); } /** * Http协议报文建造者 */ public static class Builder { private String uri; private String path; private String json; private Map params; private Map headers; private boolean https; private Integer timeout; private TimeUnit timeUnit; private boolean useFormUrlEncoded; // 新增:标识是否使用x-www-form-urlencoded格式 { // 默认5s超时 timeout = DEFAULT_TIMEOUT_SECONDS; timeUnit = TimeUnit.SECONDS; path = ""; useFormUrlEncoded = false; // 默认使用JSON格式 } /** * 建造器 * @return the HttpHandler instance */ public HttpHandler build(){ if (null == this.uri || "".equals(this.uri)){ throw new RuntimeException("uri is null"); } if (this.uri.startsWith("http://")){ this.uri = this.uri.substring(6,uri.length()); } else if (this.uri.startsWith("https://")){ this.uri = this.uri.substring(7,uri.length()); } return new HttpHandler(this); } public Builder setUri(String uri) { this.uri = uri; return this; } public Builder setPath(String path) { if (!path.startsWith("/")){ path = "/" + path; } this.path = path; return this; } public Builder setTimeout(Integer timeout, TimeUnit timeUnit) { this.timeout = timeout; this.timeUnit = timeUnit; return this; } public Builder setParams(Map params) { this.params = params; return this; } public Builder setHeaders(Map headers) { this.headers = headers; return this; } public Builder setHttps(boolean https) { this.https = https; return this; } public Builder setJson(String json) { this.json = json; return this; } // 新增方法:设置使用x-www-form-urlencoded格式 public Builder setUseFormUrlEncoded(boolean useFormUrlEncoded) { this.useFormUrlEncoded = useFormUrlEncoded; return this; } } }