diff --git a/README.md b/README.md new file mode 100644 index 0000000..0b29bda --- /dev/null +++ b/README.md @@ -0,0 +1,60 @@ +# 使用加签SDK的用法说明 + +新建一个对象```AssetCloudRequest()``` + +- ```url```:完整的请求路径 http://platform.assetcloud.org.cn/dev-api/+请求路径; + +- ```key```、```secret```:平台获取的key和secret + +Get调用方法: + +```java +AssetCloudRequest request = new AssetCloudRequest(); +request.setUrl(""); +request.setKey(""); +request.setSecret(""); +request.setHttpMethods(HttpMethods.GET); +HttpRequestUtil.send(request); +``` + +Post调用方法: +```java +AssetCloudRequest request = new AssetCloudRequest(); +request.setUrl(""); +request.setKey(""); +request.setSecret(""); +request.setBody(""); +request.setHttpMethods(HttpMethods.POST); +HttpRequestUtil.send(request); +``` + +Delete调用方法: + +```java +AssetCloudRequest request = new AssetCloudRequest(); +request.setUrl(""); +request.setKey(""); +request.setSecret(""); +request.setHttpMethods(HttpMethods.DELETE); +HttpRequestUtil.send(request); +``` + +Put调用方法: +```java +AssetCloudRequest request = new AssetCloudRequest(); +request.setUrl(""); +request.setKey(""); +request.setSecret(""); +request.setBody(""); +request.setHttpMethods(HttpMethods.Put); +HttpRequestUtil.send(request); +``` +返回结果为:```AssetCloudResponse``` + +| 字段 | 类型 | 说明 | +| ------- | ------- | -------- | +| code | int | 状态码 | +| success | Boolean | 是否成功 | +| data | T | 承载数据 | +| msg | String | 返回消息 | + diff --git a/pom.xml b/pom.xml new file mode 100644 index 0000000..f727e9b --- /dev/null +++ b/pom.xml @@ -0,0 +1,39 @@ + + + 4.0.0 + + cn.org.assetcloud + assetcloud-authorization + 1.1 + + + + + org.projectlombok + lombok + 1.18.12 + provided + + + + commons-codec + commons-codec + 1.11 + + + + org.apache.httpcomponents + httpclient + 4.4.1 + + + + com.alibaba + fastjson + 1.2.70 + + + + \ No newline at end of file diff --git a/src/main/java/cn/org/assetcloud/HttpRequestUtil.java b/src/main/java/cn/org/assetcloud/HttpRequestUtil.java new file mode 100644 index 0000000..c37fed9 --- /dev/null +++ b/src/main/java/cn/org/assetcloud/HttpRequestUtil.java @@ -0,0 +1,67 @@ +package cn.org.assetcloud; + +import cn.org.assetcloud.entity.*; +import cn.org.assetcloud.exception.HttpProcessException; +import cn.org.assetcloud.util.AssetSignUtil; +import cn.org.assetcloud.util.StringUtil; +import com.alibaba.fastjson.JSONObject; +import org.apache.commons.codec.digest.HmacUtils; + +/** + * @author Juxiu Ren Jianchao + */ +public class HttpRequestUtil { + + public static AssetCloudResponse send(AssetCloudRequest request) throws HttpProcessException { + String result = ""; + if (request.getHttpMethods() == HttpMethods.POST) { + result = AssetSignUtil.post(buildConfig(handleRequest(request))); + } else if (request.getHttpMethods() == HttpMethods.GET) { + result = AssetSignUtil.get(buildConfig(handleRequest(request))); + } + JSONObject json = JSONObject.parseObject(result); + AssetCloudResponse r = new AssetCloudResponse(); + r.setCode(json.getIntValue("code")); + r.setData(json.get("data")); + r.setMsg(json.getString("msg")); + r.setSuccess(json.getBoolean("success")); + return r; + } + + private static HttpConfig buildConfig(AssetCloudRequest request) { + HttpConfig httpConfig = HttpConfig.custom(); + HttpHeader headers = HttpHeader.custom().other("key", request.getKey()); + httpConfig.headers(headers.build()); + httpConfig.url(request.getUrl()); + if (request.getHttpMethods() == HttpMethods.POST) { + httpConfig.method(HttpMethods.POST); + httpConfig.json(request.getBody()); + } + return httpConfig; + } + + private static AssetCloudRequest handleRequest(AssetCloudRequest request) throws HttpProcessException { + String url = request.getUrl(); + String key = request.getKey(); + String secret = request.getSecret(); + //判空 + if (StringUtil.isBlank(url) || StringUtil.isBlank(key) || StringUtil.isBlank(secret)) { + throw new HttpProcessException("url key secret can not be null or empty"); + } + //毫秒级时间 + long localTime = System.currentTimeMillis(); + StringBuilder sb = new StringBuilder(); + if (!url.contains("?")) { + sb.append(url).append("?timestamp=").append(localTime); + } else { + sb.append(url).append("×tamp=").append(localTime); + } + //加签 + String shaUrl = sb.toString(); + String sha = HmacUtils.hmacSha256Hex(secret,shaUrl.substring(shaUrl.indexOf("?") + 1)); + sb.append("&sign=").append(sha); + request.setUrl(sb.toString()); + return request; + } + +} diff --git a/src/main/java/cn/org/assetcloud/builder/Hcb.java b/src/main/java/cn/org/assetcloud/builder/Hcb.java new file mode 100644 index 0000000..6f66515 --- /dev/null +++ b/src/main/java/cn/org/assetcloud/builder/Hcb.java @@ -0,0 +1,48 @@ +package src.main.java.cn.org.assetcloud.builder; + +import org.apache.http.client.config.RequestConfig; +import org.apache.http.impl.client.HttpClientBuilder; + +/** + * @author Juxiu Ren Jianchao + */ +public class Hcb extends HttpClientBuilder { + + public boolean isSetPool=false; + + + private Hcb(){} + public static Hcb custom(){ + return new Hcb(); + } + + /** + * 设置超时时间 + * + * @param timeout 超市时间,单位-毫秒 + * @return 返回当前对象 + */ + @Deprecated + public Hcb timeout(int timeout){ + return timeout(timeout, true); + } + + /** + * 设置超时时间以及是否允许网页重定向(自动跳转 302) + * + * @param timeout 超时时间,单位-毫秒 + * @param redirectEnable 自动跳转 + * @return 返回当前对象 + */ + @Deprecated + public Hcb timeout(int timeout, boolean redirectEnable){ + // 配置请求的超时设置 + RequestConfig config = RequestConfig.custom() + .setConnectionRequestTimeout(timeout) + .setConnectTimeout(timeout) + .setSocketTimeout(timeout) + .setRedirectsEnabled(redirectEnable) + .build(); + return (Hcb) this.setDefaultRequestConfig(config); + } +} diff --git a/src/main/java/cn/org/assetcloud/entity/AssetCloudRequest.java b/src/main/java/cn/org/assetcloud/entity/AssetCloudRequest.java new file mode 100644 index 0000000..0d85d31 --- /dev/null +++ b/src/main/java/cn/org/assetcloud/entity/AssetCloudRequest.java @@ -0,0 +1,22 @@ +package src.main.java.cn.org.assetcloud.entity; + +import lombok.Data; + +/** + * @author JuXiu Ren Jianchao + */ +@Data +public class AssetCloudRequest { + + private static final long serialVersionUID = 1L; + + private String url; + + private String key; + + private String secret; + + private String body; + + private HttpMethods httpMethods; +} diff --git a/src/main/java/cn/org/assetcloud/entity/AssetCloudResponse.java b/src/main/java/cn/org/assetcloud/entity/AssetCloudResponse.java new file mode 100644 index 0000000..dccdbf3 --- /dev/null +++ b/src/main/java/cn/org/assetcloud/entity/AssetCloudResponse.java @@ -0,0 +1,35 @@ +package src.main.java.cn.org.assetcloud.entity; + +import lombok.AllArgsConstructor; +import lombok.Data; + +import java.io.Serializable; + +/** + * @author Juxiu Ren Jianchao + */ +@Data +public class AssetCloudResponse implements Serializable { + + private static final long serialVersionUID = 1L; + + /** + *状态码 + */ + private int code; + + /** + *是否成功 + */ + private Boolean success; + + /** + * 承载数据 + */ + private T data; + + /** + * 返回消息 + */ + private String msg; +} diff --git a/src/main/java/cn/org/assetcloud/entity/HttpConfig.java b/src/main/java/cn/org/assetcloud/entity/HttpConfig.java new file mode 100644 index 0000000..3a0c676 --- /dev/null +++ b/src/main/java/cn/org/assetcloud/entity/HttpConfig.java @@ -0,0 +1,336 @@ +package src.main.java.cn.org.assetcloud.entity; + +import org.apache.http.Header; +import org.apache.http.client.HttpClient; +import org.apache.http.client.config.RequestConfig; +import org.apache.http.protocol.HttpContext; + +import java.io.OutputStream; +import java.nio.charset.Charset; +import java.util.HashMap; +import java.util.Map; + +/** + * @author Juxiu Ren Jianchao + */ +public class HttpConfig { + + private HttpConfig(){}; + + /** + * 获取实例 + * @return 返回当前对象 + */ + public static HttpConfig custom(){ + return new HttpConfig(); + } + + /** + * HttpClient对象 + */ + private HttpClient client; + + /** + * Header头信息 + */ + private Header[] headers; + + /** + * 是否返回response的headers + */ + private boolean isReturnRespHeaders; + + /** + * 请求方法 + */ + private HttpMethods method=HttpMethods.GET; + + /** + * 请求方法名称 + */ + private String methodName; + + /** + * 用于cookie操作 + */ + private HttpContext context; + + /** + * 传递参数 + */ +// private Map map; + + /** + * 以json格式作为输入参数 + */ + private String json; + + /** + * 输入输出编码 + */ + private String encoding= Charset.defaultCharset().displayName(); + + /** + * 输入编码 + */ + private String inenc; + + /** + * 输出编码 + */ + private String outenc; + + /** + * 设置RequestConfig + */ + private RequestConfig requestConfig; + + /** + * 解决多线程下载时,strean被close的问题 + */ + private static final ThreadLocal outs = new ThreadLocal(); + + /** + * 解决多线程处理时,url被覆盖问题 + */ + private static final ThreadLocal urls = new ThreadLocal(); + + /** + * 解决多线程处理时,url被覆盖问题 + */ + private static final ThreadLocal> maps = new ThreadLocal>(); + + /** + * @param client HttpClient对象 + * @return 返回当前对象 + */ + public HttpConfig client(HttpClient client) { + this.client = client; + return this; + } + + /** + * @param url 资源url + * @return 返回当前对象 + */ + public HttpConfig url(String url) { + urls.set(url); + return this; + } + + /** + * @param headers Header头信息 + * @return 返回当前对象 + */ + public HttpConfig headers(Header[] headers) { + this.headers = headers; + return this; + } + + /** + * Header头信息(是否返回response中的headers) + * + * @param headers Header头信息 + * @param isReturnRespHeaders 是否返回response中的headers + * @return 返回当前对象 + */ + public HttpConfig headers(Header[] headers, boolean isReturnRespHeaders) { + this.headers = headers; + this.isReturnRespHeaders=isReturnRespHeaders; + return this; + } + + /** + * @param method 请求方法 + * @return 返回当前对象 + */ + public HttpConfig method(HttpMethods method) { + this.method = method; + return this; + } + + /** + * @param methodName 请求方法 + * @return 返回当前对象 + */ + public HttpConfig methodName(String methodName) { + this.methodName = methodName; + return this; + } + + /** + * @param context cookie操作相关 + * @return 返回当前对象 + */ + public HttpConfig context(HttpContext context) { + this.context = context; + return this; + } + + /** + * @param map 传递参数 + * @return 返回当前对象 + */ + public HttpConfig map(Map map) { +// synchronized (getClass()) { +// if(this.map==null || map==null){ +// this.map = map; +// }else { +// this.map.putAll(map);; +// } +// } + Map m = maps.get(); + if(m==null || m==null || map==null){ + m = map; + }else { + m.putAll(map); + } + maps.set(m); + return this; + } + + /** + * @param json 以json格式字符串作为参数 + * @return 返回当前对象 + */ + public HttpConfig json(String json) { + this.json = json; + Map map = new HashMap(); + map.put("$ENTITY_JSON$", json); + maps.set(map); + return this; + } + /** + * @param encoding 输入输出编码 + * @return 返回当前对象 + */ + public HttpConfig encoding(String encoding) { + //设置输入输出 + inenc(encoding); + outenc(encoding); + this.encoding = encoding; + return this; + } + + /** + * @param inenc 输入编码 + * @return 返回当前对象 + */ + public HttpConfig inenc(String inenc) { + this.inenc = inenc; + return this; + } + + /** + * @param outenc 输出编码 + * @return 返回当前对象 + */ + public HttpConfig outenc(String outenc) { + this.outenc = outenc; + return this; + } + + /** + * @param out 输出流对象 + * @return 返回当前对象 + */ + public HttpConfig out(OutputStream out) { + outs.set(out); + return this; + } + + /** + * 设置超时时间 + * + * @param timeout 超市时间,单位-毫秒 + * @return 返回当前对象 + */ + public HttpConfig timeout(int timeout){ + return timeout(timeout, true); + } + + /** + * 设置超时时间以及是否允许网页重定向(自动跳转 302) + * + * @param timeout 超时时间,单位-毫秒 + * @param redirectEnable 自动跳转 + * @return 返回当前对象 + */ + public HttpConfig timeout(int timeout, boolean redirectEnable){ + // 配置请求的超时设置 + RequestConfig config = RequestConfig.custom() + .setConnectionRequestTimeout(timeout) + .setConnectTimeout(timeout) + .setSocketTimeout(timeout) + .setRedirectsEnabled(redirectEnable) + .build(); + return timeout(config); + } + + /** + * 设置代理、超时时间、允许网页重定向等 + * + * @param requestConfig 超时时间,单位-毫秒 + * @return 返回当前对象 + */ + public HttpConfig timeout(RequestConfig requestConfig){ + this.requestConfig = requestConfig; + return this; + } + + public HttpClient client() { + return client; + } + + public Header[] headers() { + return headers; + } + public boolean isReturnRespHeaders() { + return isReturnRespHeaders; + } + + public String url() { + return urls.get(); + } + + public HttpMethods method() { + return method; + } + + public String methodName() { + return methodName; + } + + public HttpContext context() { + return context; + } + + public Map map() { +// return map; + return maps.get(); + } + + public String json() { + return json; + } + + public String encoding() { + return encoding; + } + + public String inenc() { + return inenc == null ? encoding : inenc; + } + + public String outenc() { + return outenc == null ? encoding : outenc; + } + + public OutputStream out() { + return outs.get(); + } + + public RequestConfig requestConfig() { + return requestConfig; + } +} diff --git a/src/main/java/cn/org/assetcloud/entity/HttpHeader.java b/src/main/java/cn/org/assetcloud/entity/HttpHeader.java new file mode 100644 index 0000000..d5e8ab8 --- /dev/null +++ b/src/main/java/cn/org/assetcloud/entity/HttpHeader.java @@ -0,0 +1,200 @@ +package src.main.java.cn.org.assetcloud.entity; + +import org.apache.http.Consts; +import org.apache.http.Header; +import org.apache.http.message.BasicHeader; + +import java.util.HashMap; +import java.util.Map; + +/** + * @author Juxiu Ren Jianchao + */ +public class HttpHeader { + + /** + * Http头信息 + * + */ + private static class HttpReqHead { + public static final String ACCEPT = "Accept"; + public static final String ACCEPT_CHARSET = "Accept-Charset"; + public static final String ACCEPT_ENCODING = "Accept-Encoding"; + public static final String ACCEPT_LANGUAGE = "Accept-Language"; + public static final String ACCEPT_RANGES = "Accept-Ranges"; + public static final String AUTHORIZATION = "Authorization"; + public static final String CACHE_CONTROL = "Cache-Control"; + public static final String CONNECTION = "Connection"; + public static final String COOKIE = "Cookie"; + public static final String CONTENT_LENGTH = "Content-Length"; + public static final String CONTENT_TYPE = "Content-Type"; + public static final String DATE= "Date"; + public static final String EXPECT = "Expect"; + public static final String FROM = "From"; + public static final String HOST = "Host"; + public static final String IF_MATCH = "If-Match "; + public static final String IF_MODIFIED_SINCE = "If-Modified-Since"; + public static final String IF_NONE_MATCH = "If-None-Match"; + public static final String IF_RANGE = "If-Range"; + public static final String IF_UNMODIFIED_SINCE = "If-Unmodified-Since"; + public static final String KEEP_ALIVE = "Keep-Alive"; + public static final String MAX_FORWARDS = "Max-Forwards"; + public static final String PRAGMA = "Pragma"; + public static final String PROXY_AUTHORIZATION = "Proxy-Authorization"; + public static final String RANGE = "Range"; + public static final String REFERER = "Referer"; + public static final String TE = "TE"; + public static final String UPGRADE = "Upgrade"; + public static final String USER_AGENT = "User-Agent"; + public static final String VIA = "Via"; + public static final String WARNING = "Warning"; + } + + /** + * 常用头信息配置 + * + * + */ + public static class Headers{ + public static final String APP_FORM_URLENCODED="application/x-www-form-urlencoded"; + public static final String TEXT_PLAIN="text/plain"; + public static final String TEXT_HTML="text/html"; + public static final String TEXT_XML="text/xml"; + public static final String TEXT_JSON="text/json"; + public static final String CONTENT_CHARSET_ISO_8859_1 = Consts.ISO_8859_1.name(); + public static final String CONTENT_CHARSET_UTF8 = Consts.UTF_8.name(); + public static final String DEF_PROTOCOL_CHARSET = Consts.ASCII.name(); + public static final String CONN_CLOSE = "close"; + public static final String KEEP_ALIVE = "keep-alive"; + public static final String EXPECT_CONTINUE = "100-continue"; + } + + private HttpHeader() {}; + + public static HttpHeader custom() { + return new HttpHeader(); + } + + + /** + * head信息 + */ + private Map headerMaps = new HashMap(); + + /** + * 自定义header头信息 + * + * @param key header-key + * @param value header-value + * @return 返回当前对象 + */ + public HttpHeader other(String key, String value) { + headerMaps.put(key, new BasicHeader(key, value)); + return this; + } + /** + * 指定客户端能够接收的内容类型 + * 例如:Accept: text/plain, text/html + * + * @param accept accept + * @return 返回当前对象 + */ + public HttpHeader accept(String accept) { + headerMaps.put(HttpReqHead.ACCEPT, + new BasicHeader(HttpReqHead.ACCEPT, accept)); + return this; + } + + /** + * 浏览器可以接受的字符编码集 + * 例如:Accept-Charset: iso-8859-5 + * + * @param acceptCharset accept-charset + * @return 返回当前对象 + */ + public HttpHeader acceptCharset(String acceptCharset) { + headerMaps.put(HttpReqHead.ACCEPT_CHARSET, + new BasicHeader(HttpReqHead.ACCEPT_CHARSET, acceptCharset)); + return this; + } + + /** + * 指定浏览器可以支持的web服务器返回内容压缩编码类型 + * 例如:Accept-Encoding: compress, gzip + * + * @param acceptEncoding accept-encoding + * @return 返回当前对象 + */ + public HttpHeader acceptEncoding(String acceptEncoding) { + headerMaps.put(HttpReqHead.ACCEPT_ENCODING, + new BasicHeader(HttpReqHead.ACCEPT_ENCODING, acceptEncoding)); + return this; + } + + /** + * 浏览器可接受的语言 + * 例如:Accept-Language: en,zh + * + * @param acceptLanguage accept-language + * @return 返回当前对象 + */ + public HttpHeader acceptLanguage(String acceptLanguage) { + headerMaps.put(HttpReqHead.ACCEPT_LANGUAGE, + new BasicHeader(HttpReqHead.ACCEPT_LANGUAGE, acceptLanguage)); + return this; + } + + /** + * 可以请求网页实体的一个或者多个子范围字段 + * 例如:Accept-Ranges: bytes + * + * @param acceptRanges accept-ranges + * @return 返回当前对象 + */ + public HttpHeader acceptRanges(String acceptRanges) { + headerMaps.put(HttpReqHead.ACCEPT_RANGES, + new BasicHeader(HttpReqHead.ACCEPT_RANGES, acceptRanges)); + return this; + } + + /** + * HTTP授权的授权证书 + * 例如:Authorization: Basic QWxhZGRpbjpvcGVuIHNlc2FtZQ== + * + * @param authorization authorization + * @return 返回当前对象 + */ + public HttpHeader authorization(String authorization) { + headerMaps.put(HttpReqHead.AUTHORIZATION, + new BasicHeader(HttpReqHead.AUTHORIZATION, authorization)); + return this; + } + /** + * 获取head信息 + * + * @return String + */ + private String get(String headName) { + if (headerMaps.containsKey(headName)) { + return headerMaps.get(headName).getValue(); + } + return null; + } + + /** + * 返回header头信息 + * + * @return 返回构建的header头信息数组 + */ + public Header[] build() { + Header[] headers = new Header[headerMaps.size()]; + int i = 0; + for (Header header : headerMaps.values()) { + headers[i] = header; + i++; + } + headerMaps.clear(); + headerMaps = null; + return headers; + } +} diff --git a/src/main/java/cn/org/assetcloud/entity/HttpMethods.java b/src/main/java/cn/org/assetcloud/entity/HttpMethods.java new file mode 100644 index 0000000..1b331b6 --- /dev/null +++ b/src/main/java/cn/org/assetcloud/entity/HttpMethods.java @@ -0,0 +1,58 @@ +package src.main.java.cn.org.assetcloud.entity; + +/** + * @author Juxiu Ren Jianchao + */ +public enum HttpMethods { + /** + * 求获取Request-URI所标识的资源 + */ + GET(0, "GET"), + /** + * 向指定资源提交数据进行处理请求(例如提交表单或者上传文件)。数据被包含在请求体中。 + * POST请求可能会导致新的资源的建立和/或已有资源的修改 + */ + POST(1, "POST"), + /** + * 向服务器索要与GET请求相一致的响应,只不过响应体将不会被返回。 + * 这一方法可以在不必传输整个响应内容的情况下,就可以获取包含在响应消息头中的元信息 + * 只获取响应信息报头 + */ + HEAD(2, "HEAD"), + /** + * 向指定资源位置上传其最新内容(全部更新,操作幂等) + */ + PUT (3, "PUT"), + /** + * 请求服务器删除Request-URI所标识的资源 + */ + DELETE (4, "DELETE"), + /** + * 请求服务器回送收到的请求信息,主要用于测试或诊断 + */ + TRACE(5, "TRACE"), + + /** + * 向指定资源位置上传其最新内容(部分更新,非幂等) + */ + PATCH (6, "PATCH"), + /** + * 返回服务器针对特定资源所支持的HTTP请求方法。 + * 也可以利用向Web服务器发送'*'的请求来测试服务器的功能性 + */ + OPTIONS (7, "OPTIONS"),; + + private int code; + private String name; + + private HttpMethods(int code, String name){ + this.code = code; + this.name = name; + } + public String getName() { + return name; + } + public int getCode() { + return code; + } +} diff --git a/src/main/java/cn/org/assetcloud/entity/HttpResult.java b/src/main/java/cn/org/assetcloud/entity/HttpResult.java new file mode 100644 index 0000000..a32e0ee --- /dev/null +++ b/src/main/java/cn/org/assetcloud/entity/HttpResult.java @@ -0,0 +1,125 @@ +package src.main.java.cn.org.assetcloud.entity; + +import org.apache.http.Header; +import org.apache.http.HttpResponse; +import org.apache.http.ProtocolVersion; +import org.apache.http.StatusLine; + +import java.io.Serializable; + +/** + * @author Juxiu Ren Jianchao + */ +public class HttpResult implements Serializable { + private static final long serialVersionUID = -6368281080581808792L; + + /** + * 执行结果-body + */ + private String result; + + /** + * 状态码-statusCode + */ + private int statusCode; + + /** + * 状态行-StatusLine + */ + private StatusLine statusLine; + + /** + * 请求头信息 + */ + private Header[] reqHeaders; + + /** + * 响应头信息 + */ + private Header[] respHeaders; + + /** + * 协议版本 + */ + private ProtocolVersion protocolVersion; + + /** + * HttpResponse结果对象 + */ + private HttpResponse resp; + + public HttpResult(HttpResponse resp) { + this.statusLine = resp.getStatusLine(); + this.respHeaders = resp.getAllHeaders(); + this.protocolVersion = resp.getProtocolVersion(); + this.statusCode = resp.getStatusLine().getStatusCode(); + this.resp = resp; + } + + /** + * 从返回的头信息中查询指定头信息 + * + * @param name 头信息名称 + * @return + */ + public Header getHeaders(final String name) { + Header[] headers = this.resp.getHeaders(name); + return headers!=null && headers.length>0?headers[0]:null; + } + + public String getResult() { + return result; + } + + public void setResult(String result) { + this.result = result; + } + + public int getStatusCode() { + return statusCode; + } + + public void setStatusCode(int statusCode) { + this.statusCode = statusCode; + } + + public StatusLine getStatusLine() { + return statusLine; + } + + public void setStatusLine(StatusLine statusLine) { + this.statusLine = statusLine; + } + + public Header[] getReqHeaders() { + return reqHeaders; + } + + public void setReqHeaders(Header[] reqHeaders) { + this.reqHeaders = reqHeaders; + } + + public Header[] getRespHeaders() { + return respHeaders; + } + + public void setRespHeaders(Header[] respHeaders) { + this.respHeaders = respHeaders; + } + + public ProtocolVersion getProtocolVersion() { + return protocolVersion; + } + + public void setProtocolVersion(ProtocolVersion protocolVersion) { + this.protocolVersion = protocolVersion; + } + + public HttpResponse getResp() { + return resp; + } + + public void setResp(HttpResponse resp) { + this.resp = resp; + } +} diff --git a/src/main/java/cn/org/assetcloud/exception/HttpProcessException.java b/src/main/java/cn/org/assetcloud/exception/HttpProcessException.java new file mode 100644 index 0000000..777d631 --- /dev/null +++ b/src/main/java/cn/org/assetcloud/exception/HttpProcessException.java @@ -0,0 +1,28 @@ +package src.main.java.cn.org.assetcloud.exception; + +/** + * @author Juxiu Ren Jianchao + */ +public class HttpProcessException extends Exception { + private static final long serialVersionUID = -2749168865492921426L; + + public HttpProcessException(Exception e){ + super(e); + } + + /** + * @param msg 消息 + */ + public HttpProcessException(String msg) { + super(msg); + } + + /** + * @param message 异常消息 + * @param e 异常 + */ + public HttpProcessException(String message, Exception e) { + super(message, e); + } + +} \ No newline at end of file diff --git a/src/main/java/cn/org/assetcloud/util/AssetSignUtil.java b/src/main/java/cn/org/assetcloud/util/AssetSignUtil.java new file mode 100644 index 0000000..d2a2925 --- /dev/null +++ b/src/main/java/cn/org/assetcloud/util/AssetSignUtil.java @@ -0,0 +1,481 @@ +package src.main.java.cn.org.assetcloud.util; + +import cn.org.assetcloud.builder.Hcb; +import cn.org.assetcloud.entity.HttpConfig; +import cn.org.assetcloud.entity.HttpMethods; +import cn.org.assetcloud.entity.HttpResult; +import cn.org.assetcloud.exception.HttpProcessException; +import cn.org.assetcloud.util.Utils; +import org.apache.http.Header; +import org.apache.http.HttpEntity; +import org.apache.http.HttpResponse; +import org.apache.http.NameValuePair; +import org.apache.http.client.HttpClient; +import org.apache.http.client.methods.*; +import org.apache.http.protocol.HttpContext; +import org.apache.http.util.EntityUtils; + +import java.io.IOException; +import java.io.OutputStream; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; + + +/** + * @author JuXiu Ren Jianchao + */ +public class AssetSignUtil { + /** + * 默认采用的http协议的HttpClient对象 + */ + private static HttpClient client4HTTP; + + /** + * 默认采用的https协议的HttpClient对象 + */ + private static HttpClient client4HTTPS; + + static{ + client4HTTP = Hcb.custom().build(); + } + /** + * 判定是否开启连接池、及url是http还是https
+ * 如果已开启连接池,则自动调用build方法,从连接池中获取client对象
+ * 否则,直接返回相应的默认client对象
+ * + * @param config 请求参数配置 + * @throws HttpProcessException http处理异常 + */ + private static void create(HttpConfig config) throws HttpProcessException { + if(config.client()==null){ + if(config.url().toLowerCase().startsWith("https://")){ + config.client(client4HTTPS); + }else{ + config.client(client4HTTP); + } + } + } + /** + * 以Get方式,请求资源或服务 + * + * @param client client对象 + * @param url 资源地址 + * @param headers 请求头信息 + * @param context http上下文,用于cookie操作 + * @param encoding 编码 + * @return 返回处理结果 + * @throws HttpProcessException http处理异常 + */ + public static String get(HttpClient client, String url, Header[] headers, HttpContext context, String encoding) throws HttpProcessException { + return get(HttpConfig.custom().client(client).url(url).headers(headers).context(context).encoding(encoding)); + } + /** + * 以Get方式,请求资源或服务 + * + * @param config 请求参数配置 + * @return 返回结果 + * @throws HttpProcessException http处理异常 + */ + public static String get(HttpConfig config) throws HttpProcessException { + return send(config.method(HttpMethods.GET)); + } + + //------------------------------------------------------------------------- + //------------------------------------------------------------------------- + //------------------------------------------------------------------------- + + /** + * 请求资源或服务 + * + * @param config 请求参数配置 + * @return 返回处理结果 + * @throws HttpProcessException http处理异常 + */ + public static String send(HttpConfig config) throws HttpProcessException { + return fmt2String(execute(config), config.outenc()); + } + + /** + * 以Post方式,请求资源或服务 + * + * @param client client对象 + * @param url 资源地址 + * @param headers 请求头信息 + * @param parasMap 请求参数 + * @param context http上下文,用于cookie操作 + * @param encoding 编码 + * @return 返回处理结果 + * @throws HttpProcessException http处理异常 + */ + public static String post(HttpClient client, String url, Header[] headers, Map parasMap, HttpContext context, String encoding) throws HttpProcessException { + return post(HttpConfig.custom().client(client).url(url).headers(headers).map(parasMap).context(context).encoding(encoding)); + } + /** + * 以Post方式,请求资源或服务 + * + * @param config 请求参数配置 + * @return 返回处理结果 + * @throws HttpProcessException http处理异常 + */ + public static String post(HttpConfig config) throws HttpProcessException { + return send(config.method(HttpMethods.POST)); + } + + /** + * 以Put方式,请求资源或服务 + * + * @param client client对象 + * @param url 资源地址 + * @param parasMap 请求参数 + * @param headers 请求头信息 + * @param context http上下文,用于cookie操作 + * @param encoding 编码 + * @return 返回处理结果 + * @throws HttpProcessException http处理异常 + */ + public static String put(HttpClient client, String url, MapparasMap,Header[] headers, HttpContext context,String encoding) throws HttpProcessException { + return put(HttpConfig.custom().client(client).url(url).headers(headers).map(parasMap).context(context).encoding(encoding)); + } + /** + * 以Put方式,请求资源或服务 + * + * @param config 请求参数配置 + * @return 返回处理结果 + * @throws HttpProcessException http处理异常 + */ + public static String put(HttpConfig config) throws HttpProcessException { + return send(config.method(HttpMethods.PUT)); + } + + /** + * 以Delete方式,请求资源或服务 + * + * @param client client对象 + * @param url 资源地址 + * @param headers 请求头信息 + * @param context http上下文,用于cookie操作 + * @param encoding 编码 + * @return 返回处理结果 + * @throws HttpProcessException http处理异常 + */ + public static String delete(HttpClient client, String url, Header[] headers, HttpContext context,String encoding) throws HttpProcessException { + return delete(HttpConfig.custom().client(client).url(url).headers(headers).context(context).encoding(encoding)); + } + /** + * 以Delete方式,请求资源或服务 + * + * @param config 请求参数配置 + * @return 返回处理结果 + * @throws HttpProcessException http处理异常 + */ + public static String delete(HttpConfig config) throws HttpProcessException { + return send(config.method(HttpMethods.DELETE)); + } + + /** + * 以Patch方式,请求资源或服务 + * + * @param client client对象 + * @param url 资源地址 + * @param parasMap 请求参数 + * @param headers 请求头信息 + * @param context http上下文,用于cookie操作 + * @param encoding 编码 + * @return 返回处理结果 + * @throws HttpProcessException http处理异常 + */ + public static String patch(HttpClient client, String url, MapparasMap, Header[] headers, HttpContext context,String encoding) throws HttpProcessException { + return patch(HttpConfig.custom().client(client).url(url).headers(headers).map(parasMap).context(context).encoding(encoding)); + } + /** + * 以Patch方式,请求资源或服务 + * + * @param config 请求参数配置 + * @return 返回处理结果 + * @throws HttpProcessException http处理异常 + */ + public static String patch(HttpConfig config) throws HttpProcessException { + return send(config.method(HttpMethods.PATCH)); + } + + /** + * 以Head方式,请求资源或服务 + * + * @param client client对象 + * @param url 资源地址 + * @param headers 请求头信息 + * @param context http上下文,用于cookie操作 + * @param encoding 编码 + * @return 返回处理结果 + * @throws HttpProcessException http处理异常 + */ + public static String head(HttpClient client, String url, Header[] headers, HttpContext context,String encoding) throws HttpProcessException { + return head(HttpConfig.custom().client(client).url(url).headers(headers).context(context).encoding(encoding)); + } + /** + * 以Head方式,请求资源或服务 + * + * @param config 请求参数配置 + * @return 返回处理结果 + * @throws HttpProcessException http处理异常 + */ + public static String head(HttpConfig config) throws HttpProcessException { + return send(config.method(HttpMethods.HEAD)); + } + + /** + * 以Options方式,请求资源或服务 + * + * @param client client对象 + * @param url 资源地址 + * @param headers 请求头信息 + * @param context http上下文,用于cookie操作 + * @param encoding 编码 + * @return 返回处理结果 + * @throws HttpProcessException http处理异常 + */ + public static String options(HttpClient client, String url, Header[] headers, HttpContext context,String encoding) throws HttpProcessException { + return options(HttpConfig.custom().client(client).url(url).headers(headers).context(context).encoding(encoding)); + } + /** + * 以Options方式,请求资源或服务 + * + * @param config 请求参数配置 + * @return 返回处理结果 + * @throws HttpProcessException http处理异常 + */ + public static String options(HttpConfig config) throws HttpProcessException { + return send(config.method(HttpMethods.OPTIONS)); + } + + /** + * 以Trace方式,请求资源或服务 + * + * @param client client对象 + * @param url 资源地址 + * @param headers 请求头信息 + * @param context http上下文,用于cookie操作 + * @param encoding 编码 + * @return 返回处理结果 + * @throws HttpProcessException http处理异常 + */ + public static String trace(HttpClient client, String url, Header[] headers, HttpContext context, String encoding) throws HttpProcessException { + return trace(HttpConfig.custom().client(client).url(url).headers(headers).context(context).encoding(encoding)); + } + /** + * 以Trace方式,请求资源或服务 + * + * @param config 请求参数配置 + * @return 返回处理结果 + * @throws HttpProcessException http处理异常 + */ + public static String trace(HttpConfig config) throws HttpProcessException { + return send(config.method(HttpMethods.TRACE)); + } + + /** + * 请求资源或服务,返回HttpResult对象 + * + * @param config 请求参数配置 + * @return 返回HttpResult处理结果 + * @throws HttpProcessException http处理异常 + */ + public static HttpResult sendAndGetResp(HttpConfig config) throws HttpProcessException { + Header[] reqHeaders = config.headers(); + //执行结果 + HttpResponse resp = execute(config); + HttpResult result = new HttpResult(resp); + result.setResult(fmt2String(resp, config.outenc())); + result.setReqHeaders(reqHeaders); + return result; + } + /** + * 请求资源或服务 + * + * @param config 请求参数配置 + * @return 返回HttpResponse对象 + * @throws HttpProcessException http处理异常 + */ + private static HttpResponse execute(HttpConfig config) throws HttpProcessException { + create(config); + HttpResponse resp = null; + + try { + //创建请求对象 + HttpRequestBase request = getRequest(config.url(), config.method()); + + //设置超时 + request.setConfig(config.requestConfig()); + + //设置header信息 + request.setHeaders(config.headers()); + + //判断是否支持设置entity(仅HttpPost、HttpPut、HttpPatch支持) + if(HttpEntityEnclosingRequestBase.class.isAssignableFrom(request.getClass())){ + List nvps = new ArrayList(); + + if(request.getClass()==HttpGet.class) { + //检测url中是否存在参数 + //注:只有get请求,才自动截取url中的参数,post等其他方式,不再截取 + config.url(Utils.checkHasParas(config.url(), nvps, config.inenc())); + } + + //装填参数 + HttpEntity entity = Utils.map2HttpEntity(nvps, config.map(), config.inenc()); + + //设置参数到请求对象中 + ((HttpEntityEnclosingRequestBase)request).setEntity(entity); + + }else{ + int idx = config.url().indexOf("?"); + } + //执行请求操作,并拿到结果(同步阻塞) + resp = (config.context()==null)?config.client().execute(request) : config.client().execute(request, config.context()) ; + + if(config.isReturnRespHeaders()){ + //获取所有response的header信息 + config.headers(resp.getAllHeaders()); + } + //获取结果实体 + return resp; + + } catch (IOException e) { + throw new HttpProcessException(e); + } + } + + //------------------------------------------------------------------------- + //------------------------------------------------------------------------- + //------------------------------------------------------------------------- + + /** + * 转化为字符串 + * + * @param resp 响应对象 + * @param encoding 编码 + * @return 返回处理结果 + * @throws HttpProcessException http处理异常 + */ + private static String fmt2String(HttpResponse resp, String encoding) throws HttpProcessException { + String body = ""; + try { + if (resp.getEntity() != null) { + // 按指定编码转换结果实体为String类型 + body = EntityUtils.toString(resp.getEntity(), encoding); + }else{//有可能是head请求 + body =resp.getStatusLine().toString(); + } + EntityUtils.consume(resp.getEntity()); + } catch (IOException e) { + throw new HttpProcessException(e); + }finally{ + close(resp); + } + return body; + } + /** + * 转化为数字 + * + * @param resp 响应对象 + * @return 返回处理结果 + * @throws HttpProcessException http处理异常 + */ + private static int fmt2Int(HttpResponse resp) throws HttpProcessException { + int statusCode; + try { + statusCode = resp.getStatusLine().getStatusCode(); + EntityUtils.consume(resp.getEntity()); + } catch (IOException e) { + throw new HttpProcessException(e); + }finally{ + close(resp); + } + return statusCode; + } + + /** + * 转化为流 + * + * @param resp 响应对象 + * @param out 输出流 + * @return 返回输出流 + * @throws HttpProcessException http处理异常 + */ + public static OutputStream fmt2Stream(HttpResponse resp, OutputStream out) throws HttpProcessException { + try { + resp.getEntity().writeTo(out); + EntityUtils.consume(resp.getEntity()); + } catch (IOException e) { + throw new HttpProcessException(e); + }finally{ + close(resp); + } + return out; + } + + /** + * 根据请求方法名,获取request对象 + * + * @param url 资源地址 + * @param method 请求方式 + * @return 返回Http处理request基类 + */ + private static HttpRequestBase getRequest(String url, HttpMethods method) { + HttpRequestBase request = null; + switch (method.getCode()) { + case 0: + // HttpGet + request = new HttpGet(url); + break; + case 1: + // HttpPost + request = new HttpPost(url); + break; + case 2: + // HttpHead + request = new HttpHead(url); + break; + case 3: + // HttpPut + request = new HttpPut(url); + break; + case 4: + // HttpDelete + request = new HttpDelete(url); + break; + case 5: + // HttpTrace + request = new HttpTrace(url); + break; + case 6: + // HttpPatch + request = new HttpPatch(url); + break; + case 7: + // HttpOptions + request = new HttpOptions(url); + break; + default: + request = new HttpPost(url); + break; + } + return request; + } + /** + * 尝试关闭response + * + * @param resp HttpResponse对象 + */ + private static void close(HttpResponse resp) { + try { + if(resp == null) return; + //如果CloseableHttpResponse 是resp的父类,则支持关闭 + if(CloseableHttpResponse.class.isAssignableFrom(resp.getClass())){ + ((CloseableHttpResponse)resp).close(); + } + } catch (IOException e) { + e.printStackTrace(); + } + } +} diff --git a/src/main/java/cn/org/assetcloud/util/StringUtil.java b/src/main/java/cn/org/assetcloud/util/StringUtil.java new file mode 100644 index 0000000..3325af7 --- /dev/null +++ b/src/main/java/cn/org/assetcloud/util/StringUtil.java @@ -0,0 +1,10 @@ +package src.main.java.cn.org.assetcloud.util; + +/** + * @author Juxiu Ren Jianchao + */ +public class StringUtil { + public static boolean isBlank(String s) { + return s == null || "".equals(s.trim()); + } +} diff --git a/src/main/java/cn/org/assetcloud/util/Utils.java b/src/main/java/cn/org/assetcloud/util/Utils.java new file mode 100644 index 0000000..d7bdae1 --- /dev/null +++ b/src/main/java/cn/org/assetcloud/util/Utils.java @@ -0,0 +1,149 @@ +package src.main.java.cn.org.assetcloud.util; + +import org.apache.http.HttpEntity; +import org.apache.http.NameValuePair; +import org.apache.http.client.entity.UrlEncodedFormEntity; +import org.apache.http.entity.ByteArrayEntity; +import org.apache.http.entity.ContentType; +import org.apache.http.entity.FileEntity; +import org.apache.http.entity.StringEntity; +import org.apache.http.message.BasicNameValuePair; + +import java.io.File; +import java.io.UnsupportedEncodingException; +import java.util.Arrays; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +/** + * @author Juxiu Ren Jianchao + */ +public class Utils { + public static final String ENTITY_STRING="$ENTITY_STRING$"; + public static final String ENTITY_JSON="$ENTITY_JSON$"; + public static final String ENTITY_FILE="$ENTITY_FILEE$"; + public static final String ENTITY_BYTES="$ENTITY_BYTES$"; + public static final String ENTITY_INPUTSTREAM="$ENTITY_INPUTSTREAM$"; + public static final String ENTITY_SERIALIZABLE="$ENTITY_SERIALIZABLE$"; + public static final String ENTITY_MULTIPART="$ENTITY_MULTIPART$"; + private static final List SPECIAL_ENTITIY = Arrays.asList(ENTITY_STRING, ENTITY_JSON, ENTITY_BYTES, ENTITY_FILE, ENTITY_INPUTSTREAM, ENTITY_SERIALIZABLE, ENTITY_MULTIPART); + + /** + * 检测url是否含有参数,如果有,则把参数加到参数列表中 + * + * @param url 资源地址 + * @param nvps 参数列表 + * @param encoding 编码 + * @return 返回去掉参数的url + * @throws UnsupportedEncodingException 不支持的编码异常 + */ + public static String checkHasParas(String url, List nvps, String encoding) throws UnsupportedEncodingException { + // 检测url中是否存在参数 + if (url.contains("?") && url.indexOf("?") < url.indexOf("=")) { + Map map = buildParas(url.substring(url.indexOf("?") + 1)); + map2HttpEntity(nvps, map, encoding); + url = url.substring(0, url.indexOf("?")); + } + return url; + } + /** + * + * 参数转换,将map中的参数,转到参数列表中 + * + * @param nvps 参数列表 + * @param map 参数列表(map) + * @param encoding 编码 + * @return 返回HttpEntity + * @throws UnsupportedEncodingException 不支持的编码异常 + */ + public static HttpEntity map2HttpEntity(List nvps, Map map, String encoding) throws UnsupportedEncodingException { + HttpEntity entity = null; + if(map!=null && map.size()>0){ + boolean isSpecial = false; + // 拼接参数 + for (Map.Entry entry : map.entrySet()) { + if(SPECIAL_ENTITIY.contains(entry.getKey())){ + //判断是否在之中 + isSpecial = true; + if(ENTITY_STRING.equals(entry.getKey())){ + //string + entity = new StringEntity(String.valueOf(entry.getValue()), encoding); + break; + }else if(ENTITY_JSON.equals(entry.getKey())){ + entity = new StringEntity(String.valueOf(entry.getValue()), encoding); + String contentType = "application/json"; + if (encoding != null) { + contentType += ";charset=" + encoding; + } + ((StringEntity) entity).setContentType(contentType); + break; + }else if(ENTITY_BYTES.equals(entry.getKey())){ + //file + entity = new ByteArrayEntity((byte[])entry.getValue()); + break; + }else if(ENTITY_FILE.equals(entry.getKey())){ + //file + if(File.class.isAssignableFrom(entry.getValue().getClass())){ + entity = new FileEntity((File)entry.getValue(), ContentType.APPLICATION_OCTET_STREAM); + }else if(entry.getValue().getClass()==String.class){ + entity = new FileEntity(new File((String) entry.getValue()), ContentType.create("text/plain", "UTF-8")); + } + break; + }else if(ENTITY_INPUTSTREAM.equals(entry.getKey())){ + //inputstream +// entity = new InputStreamEntity(); + break; + }else if(ENTITY_SERIALIZABLE.equals(entry.getKey())){ + //serializeable +// entity = new SerializableEntity() + break; + }else { + nvps.add(new BasicNameValuePair(entry.getKey(), String.valueOf(entry.getValue()))); + } + }else{ + nvps.add(new BasicNameValuePair(entry.getKey(), String.valueOf(entry.getValue()))); + } + } + if(!isSpecial) { + entity = new UrlEncodedFormEntity(nvps, encoding); + } + } + return entity; + } + + /** + * 生成参数 + * 参数格式:k1=v1&k2=v2 + * + * @param paras 参数列表 + * @return 返回参数列表(map) + */ + public static Map buildParas(String paras){ + String[] p = paras.split("&"); + String[][] ps = new String[p.length][2]; + int pos = 0; + for (int i = 0; i < p.length; i++) { + pos = p[i].indexOf("="); + ps[i][0]=p[i].substring(0,pos); + ps[i][1]=p[i].substring(pos+1); + pos = 0; + } + return buildParas(ps); + } + /** + * 生成参数 + * 参数类型:{{"k1","v1"},{"k2","v2"}} + * + * @param paras 参数列表 + * @return 返回参数列表(map) + */ + public static Map buildParas(String[][] paras){ + // 创建参数队列 + Map map = new HashMap(); + for (String[] para: paras) { + map.put(para[0], para[1]); + } + return map; + } +}