diff --git a/src/main/java/cokr/xit/foundation/web/WebClient.java b/src/main/java/cokr/xit/foundation/web/WebClient.java
index 6f7628b..f219d9f 100644
--- a/src/main/java/cokr/xit/foundation/web/WebClient.java
+++ b/src/main/java/cokr/xit/foundation/web/WebClient.java
@@ -21,7 +21,54 @@ import java.util.function.Consumer;
import cokr.xit.foundation.Assert;
import cokr.xit.foundation.data.JSON;
-/**
+/**서버와의 http 통신을 지원하는 유틸리티.
+ *
WebClient는 {@link #get(Consumer) GET}, 또는 {@link #post(Consumer) POST} 방식의 통신을 지원한다. {@link Request 요청의 설정}에 따라
+ *
- 동기 / 비동기
+ * - 텍스트 / 파일 다운로드 / JSON
+ *
+ * 으로 통신할 수 있다.
+ * 다음은 사용례이다.
+ * - 동기식 통신
+ *
// 텍스트
+ * try {
+ * HttpResponse{@code } hresp = new WebClient().get(req ->
+ * req.uri("http://xit.co.kr")
+ * );
+ * System.out.println(hresp.body());
+ * } catch (Exception e) {
+ * e.printStackTrace();
+ * }
+ * // 파일 다운로드
+ * try {
+ * HttpResponse{@code } hresp2 = new WebClient().get(req ->
+ * req.uri("http://www.xit.co.kr/images/project/homepage/mainVisual.png")
+ * .download(true)
+ * );
+ * InputStream input = hresp2.body(); // -> 파일 저장
+ * } catch (Exception e) {
+ * e.printStackTrace();
+ * }
+ *
+ * - 비동기식 통신
+ *
// 텍스트
+ * new WebClient().get(req ->
+ * req.uri("http://xit.co.kr")
+ * .async(true)
+ * .onResponse(hresp -> System.out.println(hresp.body())
+ * .onError(e -> e.printStackTrace())
+ * );
+ * // 파일 다운로드
+ * new WebClient().get(req ->
+ * req.uri("http://www.xit.co.kr/images/project/homepage/mainVisual.png")
+ * .async(true)
+ * .download(true)
+ * .onDownload(hresp -> {
+ * InputStream input = hresp.body(); // -> 파일 저장
+ * })
+ * .onError(e -> e.printStackTrace())
+ * );
+ *
+ *
* @author mjkhan
*/
public class WebClient {
@@ -37,26 +84,46 @@ public class WebClient {
private HttpClient.Redirect followRedirects = HttpClient.Redirect.NORMAL;
+ /**http 프로토콜의 버젼을 설정한다. 디폴트는 HTTP/2
+ * @param version http 프로토콜 버젼
+ * @return 현재 WebClient
+ */
public WebClient version(HttpClient.Version version) {
this.version = version;
return this;
}
+ /**응답 대기 시간(초)을 설정한다. 디폴트는 30초
+ * @param seconds 응답 대기 시간(초)
+ * @return 현재 WebClient
+ */
public WebClient timeout(int seconds) {
this.timeout = Duration.ofSeconds(seconds);
return this;
}
+ /**서버에 대한 인증을 처리할 경우 Authenticator를 설정한다.
+ * @param authenticator 인증 처리를 위한 Authenticator
+ * @return 현재 WebClient
+ */
public WebClient authenticator(Authenticator authenticator) {
this.authenticator = authenticator;
return this;
}
+ /**서버와 접속 시 프록시를 사용할 경우 proxy를 설정한다.
+ * @param proxy 서버 접속에 사용할 프록시 설정
+ * @return 현재 WebClient
+ */
public WebClient proxy(ProxySelector proxy) {
this.proxy = proxy;
return this;
}
+ /**서버의 응답이 redirect일 경우 대응 방법을 설정한다. 디폴트는 HttpClient.Redirect.NORMAL.
+ * @param redirect redirect 응답에 대한 대응 방법
+ * @return 현재 WebClient
+ */
public WebClient followRedirects(HttpClient.Redirect redirect) {
this.followRedirects = redirect;
return this;
@@ -76,20 +143,25 @@ public class WebClient {
return builder.build();
}
+ /**"GET" 방식의 요청을 전송한다.
+ * @param 요청의 body 핸들러 유형
+ * @param configurer "GET" 방식 요청의 설정자
+ * @return http 응답
+ */
@SuppressWarnings("unchecked")
- public HttpResponse get(Consumer configurer) {
- Config conf = new Config();
- configurer.accept(conf);
- HttpRequest hreq = conf.get();
+ public HttpResponse get(Consumer configurer) {
+ Request req = new Request();
+ configurer.accept(req);
+ HttpRequest hreq = req.get();
try {
- if (conf.download)
- return (HttpResponse)handleRequest(conf.async, hreq, HttpResponse.BodyHandlers.ofInputStream(), conf.downloadHandler);
+ if (req.download)
+ return (HttpResponse)handleRequest(req.async, hreq, HttpResponse.BodyHandlers.ofInputStream(), req.downloadHandler);
else
- return (HttpResponse)handleRequest(conf.async, hreq, HttpResponse.BodyHandlers.ofString(), conf.textHandler);
+ return (HttpResponse)handleRequest(req.async, hreq, HttpResponse.BodyHandlers.ofString(), req.textHandler);
} catch (Throwable e) {
- if (conf.async) {
- conf.errorHandler.accept(Assert.rootCause(e));
+ if (req.async) {
+ req.errorHandler.accept(Assert.rootCause(e));
return null;
} else
throw Assert.runtimeException(e);
@@ -109,26 +181,35 @@ public class WebClient {
}
}
+ /**"POST" 방식의 요청을 전송한다.
+ * @param 요청의 body 핸들러 유형
+ * @param configurer "POST" 방식 요청의 설정자
+ * @return http 응답
+ */
@SuppressWarnings("unchecked")
- public HttpResponse post(Consumer configurer) {
- Config conf = new Config();
- configurer.accept(conf);
- HttpRequest hreq = conf.post();
+ public HttpResponse post(Consumer configurer) {
+ Request req = new Request();
+ configurer.accept(req);
+ HttpRequest hreq = req.post();
try {
- if (conf.download)
- return (HttpResponse)handleRequest(conf.async, hreq, HttpResponse.BodyHandlers.ofInputStream(), conf.downloadHandler);
+ if (req.download)
+ return (HttpResponse)handleRequest(req.async, hreq, HttpResponse.BodyHandlers.ofInputStream(), req.downloadHandler);
else
- return (HttpResponse)handleRequest(conf.async, hreq, HttpResponse.BodyHandlers.ofString(), conf.textHandler);
+ return (HttpResponse)handleRequest(req.async, hreq, HttpResponse.BodyHandlers.ofString(), req.textHandler);
} catch (Throwable e) {
- if (conf.async) {
- conf.errorHandler.accept(Assert.rootCause(e));
+ if (req.async) {
+ req.errorHandler.accept(Assert.rootCause(e));
return null;
} else
throw Assert.runtimeException(e);
}
}
+ /**응답 유형이 다운로드한 파일일 경우, 해당 파일을 지정한 경로로 저장한다.
+ * @param inputStream 다운로드한 파일
+ * @param path 저장할 경로
+ */
public void write(InputStream inputStream, String path) {
try (
InputStream in = inputStream;
@@ -140,7 +221,23 @@ public class WebClient {
}
}
- public static class Config {
+ /**전송할 http 요청의 설정.
+ * Request로 다음 항목들을 설정한다.
+ *
- {@link #uri(String) uri}: 대상 서버의 uri
+ * - {@link #json(boolean) json}: 서버와 주고받는 데이터의 JSON 여부
+ * - {@link #async(boolean) async}: 서버와의 통신이 비동기인지 여부
+ * - {@link #download(boolean) download}: 응답이 파일 다운로드인지 여부
+ * - {@link #header(String, String) header}: http 헤더
+ * - {@link #data(String, Object) data}: 서버에 전송하는 데이터
+ *
+ * 서버와 비동기로 통신할 경우 다음 항목들을 설정한다.
+ * - {@link #onResponse(Consumer) onResponse}: 텍스트 응답 핸들러
+ * - {@link #onDownload(Consumer) onDownload}: 다운로드한 파일 핸들러
+ * - {@link #onError(Throwable) onError}: 오류 핸들러
+ *
+ * @author mjkhan
+ */
+ public static class Request {
private String uri;
private boolean
async,
@@ -160,56 +257,107 @@ public class WebClient {
t.printStackTrace(System.err);
};
- public Config header(String key, String value) {
+ /**요청의 헤더를 설정한다.
+ * @param key 헤더이름
+ * @param value 헤더값
+ * @return 현재 Request
+ */
+ public Request header(String key, String value) {
if (headers == null)
headers = new LinkedHashMap<>();
headers.put(key, value);
return this;
}
- public Config uri(String uri) {
+ /**요청의 uri를 설정한다.
+ * @param uri 요청 대상 서버의 uri
+ * @return 현재 Request
+ */
+ public Request uri(String uri) {
this.uri = uri;
return this;
}
- public Config charset(Charset charset) {
+ /**요청의 문자셋을 설정한다. 디폴트는 UTF-8.
+ * @param charset 요청의 문자셋
+ * @return 현재 Request
+ */
+ public Request charset(Charset charset) {
this.charset = charset;
return this;
}
- public Config async(boolean async) {
+ /**요청이 비동기인지 설정한다. 디폴트는 false(동기).
+ * @param async 요청의 비동기 여부
+ * - 요청이 비동기면 true
+ * - 요청이 동기면 false
+ *
+ * @return 현재 Request
+ */
+ public Request async(boolean async) {
this.async = async;
return this;
}
- public Config json(boolean json) {
+ /**데이터를 JSON으로 주고받는지 설정한다. 디폴트는 false.
+ * @param json 데이터의 JSON 여부
+ * - 데이터를 JSON으로 주고받으면 true
+ * - 그렇지 않으면 false
+ *
+ * @return 현재 Request
+ */
+ public Request json(boolean json) {
this.json = json;
return this;
}
- public Config download(boolean download) {
+ /**요청의 응답이 파일인지 설정한다. 디폴트는 false(텍스트).
+ * @param download
+ * - 응답으로 file을 다운받으면 true
+ * - 그렇지 않으면 false
+ *
+ * @return 현재 Request
+ */
+ public Request download(boolean download) {
this.download = download;
return this;
}
- public Config data(String key, Object value) {
+ /**요청으로 전달할 데이터를 설정한다.
+ * @param key 데이터 키(이름)
+ * @param value 데이터 값
+ * @return 현재 Request
+ */
+ public Request data(String key, Object value) {
if (data == null)
data = new LinkedHashMap<>();
data.put(key, value);
return this;
}
- public Config onResponse(Consumer> handler) {
+ /**비동기 요청의 텍스트 응답을 처리하는 핸들러를 설정한다.
+ * @param handler 비동기 요청의 텍스트 응답을 처리하는 핸들러
+ * @return 현재 Request
+ */
+ public Request onResponse(Consumer> handler) {
textHandler = handler;
return this;
}
- public Config onDownload(Consumer> handler) {
+ /**비동기 요청의 다운로드 파일을 처리하는 핸들러를 설정한다.
+ * @param handler 비동기 요청의 다운로드 파일을 처리하는 핸들러
+ * @return 현재 Request
+ */
+ public Request onDownload(Consumer> handler) {
downloadHandler = handler;
return this;
}
- public Config onError(Consumer handler) {
+ /**비동기 요청의 오류를 처리하는 핸들러를 설정한다.
+ * @param handler 오류 핸들러
+ * @return 현재 Request
+ */
+ public Request onError(Consumer handler) {
errorHandler = handler;
return this;
}