- Builder 패턴을 활용한 RestTemplateBuilder
- Spring의 IoC를 활용한 싱글톤 RestTemplate
- RestTemplate의 Customizing
- RestTemplateBuilder 상속을 통한 기능 확장
[ 구조 ]
TaehyeonRestTemple = RestTemplateBuilder + Taehyeon's Function // Builder-pattern
|
|- HttpClient
| ㄴ Connection Pool
|- HttpComponentsClientHttpRequestFactory
| ㄴ Time Out
ㄴ CustomRestTemplateCustomizer
ㄴ Logging
@Autowired
private TaehyeonRestTempleBuilder taehyeonRestTempleBuilder;
/** GET 요청 예시(String return) **/
String result = taehyeonRestTempleBuilder
.requestUriAndPath(DATA_BASE_URL
, "/VilageFcstInfoService_2.0/getVilageFcst"
, new LinkedMultiValueMap<>() {{
add("serviceKey", SERVICE_KEY);
add("pageNo", "1");
add("dataType", "JSON");
add("base_date", "20220207");
add("base_time", "1200");
add("nx", "57");
add("ny", "127");
}})
.getForObject();
/** GET 요청 예시 **/
ResponseEntity<Object> result = taehyeonRestTempleBuilder
.headers(new HashMap<>(){
{
put("X-Auth-Token", authKey);
}
})
.requestUriAndPath(crowdworksDefaultUrl
, "/project/output"
, new LinkedMultiValueMap<>() {{
add("queryingField", "");
add("queryingWord", "");
add("dataStatus", "");
add("edited", "");
add("rangingField", "");
add("page", String.valueOf(page));
}})
.get();
/** POST 요청 예시 **/
ResponseEntity<Object> result = taehyeonRestTempleBuilder
.contentType(MediaType.APPLICATION_JSON)
.body(loginInfo)
.requestUriAndPath(apiUrl, loginpath, null)
.post();
/** PATCH 요청 예시 **/
ResponseEntity<Object> result = taehyeonRestTempleBuilder
.headers(new HashMap<>(){{
put("X-Auth-Token", authKey);
}})
.requestUriAndPath(apiUrl, authPath, null)
.patch();
- 비즈니스 로직에서 구현하던 RestTemplate 생성과 처리 부분을 분리
- 추후 연계 시스템 개발에서도 해당 모듈을 사용하여 단순히 호출만을 통한 처리를 할 수 있게끔 개발
- Spring과 디자인 패턴을 공부하고 있는 것을 복습하며 실적용을 노림
- RestTemplate의 ConnectionPool 설정을 통해 3-Hankshake의 지연을 줄임
(연계 서버이므로 API 호출 서버가 keep-alive 상태임을 가정 ) - 기존의 Resttemplate 과 Custom한 TaehyeonRestTemplate을 공존하여 Client의 선택에 따라 사용할 수 있도록 개발
- jar 라이브러리화 하여 추후 연계 서버 개발시 개발 시간을 단축
- 회사 연계 공통 모듈로 사용할 수 있게??? :D
-
2022-02-22
- 프로젝트 Init
- Builder patter 초기 동작 코드 작성
- Get 요청시의 parameter를 명시적으로 주입하기 위해 MultiValueMap 과 UriComponentsBuilder를 활용하여 요청 URI를 생성
- 모듈 자체 Exception 생성 (수정 보완필요)
-
2022-02-23
- RestTemplate이 Connection Pool이 없이 요청할때마다 3-HandShack를 진행한다는 것을 공부, 이에 따라 Connection Pool을 설정하여 오버헤드를 줄임
- application.properties 를 통한 Connection Pool과 TimeOut 설정을 할 수 있게 설정
- 초기의 TaehyeonRestTemplateBuilder의 코드에 Connection Pool과 TimeOut 설정을 하여 Bean 생성을 하려고 하였으나 ' RestTemplateBuilder를 사용한 RestTemplate 설정 방법 : https://www.baeldung.com/spring-rest-template-builder ' 을 보고 Customizing Logging을 추가 및 각 기능을 분리 시킨 Bean으로 생성하여 주입되어 Application Context가 자동 관리 되도록 함
- RestTempleBuilder의 생성자에 CustomRestTemplateCustomizer가 parm으로 주입되는데 이에 따른 TaehyeonRestTemplateBuilder를 RestTemplateBuilder를 상속 받아 기능을 확장 시키는 방향으로 전환
- (중요!!) 상속받은 Builder를 통한 build를 시키면 return이 super의 RestTemplate 이고, sub의 TaehyeonRestTempleBuilder로 casting이 안됨.
해당 문제는 Builder 형태로 생성하고 마지막에 Casting을 하는 것이 아닌, Casting 한 Builder를 생성하고 생성한 객체에서 추가적인 작업을 진행
(때문에 알고있던 Upcasting과 DownCasting 다시 공부....) - 새롭게 만들어낸 TaehyeonRestTemplate과 기존의 RestTemplate을 공용으로 사용할 수 있도록 2가지 type의 Bean 생성하는 방향으로 생각중
- 테스트 코드 추가
-
2022-02-25
- Default RestTemplate Bean 추가 하여 Client가 선택적으로 사용할 수 있게 수정
- TestCode에 기존 방식과 TaehyeonRestTemplate 방식 비교 코드 추가
- RestTemplate Get 요청시 String 으로 parameter를 주입시 자동 Encoding 처리 되어 요청 [해결]
parmeter 를 URI로 주입하여 Encoding 되지 않게 처리
restTemplate.getForObject(new URI(URLDecoder.decode(requestUri.toString(), "UTF-8")), String.class);
- 상속받은 Builder를 통한 build를 시키면 return이 super의 RestTemplate 이고, sub의 TaehyeonRestTempleBuilder로 casting이 안됨 [해결]
Casting 한 Builder를 생성하고 생성한 객체에서 추가적인 작업을 진행
//불가능
TaehyeonRestTempleBuilder taehyeonRestTempleBuilder = (TaehyeonRestTempleBuilder)new TaehyeonRestTempleBuilder(customRestTemplateCustomizer())
.requestFactory(() -> new BufferingClientHttpRequestFactory(factory))
.additionalMessageConverters(new StringHttpMessageConverter(Charset.forName("UTF-8")));
// 가능
TaehyeonRestTempleBuilder taehyeonRestTempleBuilder = new TaehyeonRestTempleBuilder(customRestTemplateCustomizer());
taehyeonRestTempleBuilder.requestFactory(() -> new BufferingClientHttpRequestFactory(factory))
.additionalMessageConverters(new StringHttpMessageConverter(Charset.forName("UTF-8")));
-
TaehyeonRestTempleBuilder 는 Builder인가 RestTemplate 인가.....?
-
RestTemple를 통해 Get 요청시 MessageConverter 오류**[해결]**
- TaehyeonRestTemplateBuilder은 "additionalMessageConverters(new StringHttpMessageConverter(Charset.forName("UTF-8")));" 만으로 Response Message Converting이 정상 이루어 졌지만, 기본 RestTemplateBuilder에도 똑같이 하였으나 Converting 오류 발생
혹시 몰라 TaehyeonRestTemplate 에도 MessageCoverter 설정 추가
// 오류 메세지
org.springframework.web.client.UnknownContentTypeException: Could not extract response: no suitable HttpMessageConverter found for response type [class java.lang.Object] and content type [application/json;charset=UTF-8]
// 해결 코드
RestTemplate restTemplate1 =restTemplateBuilder
.additionalMessageConverters(new StringHttpMessageConverter(Charset.forName("UTF-8")))
.build(); // restemplate 생성
List<HttpMessageConverter<?>> messageConverters = new ArrayList<>();
MappingJackson2HttpMessageConverter converter = new MappingJackson2HttpMessageConverter();
converter.setSupportedMediaTypes(Collections.singletonList(MediaType.ALL)); //converter 설정
messageConverters.add(converter);
restTemplate1.setMessageConverters(messageConverters); // messageConverter 직접 추가