[Spring] RestTemplate을 사용하여 json 요청
Server to Server http 통신에 사용되는 RestTemplate
public class RestTemplate extends InterceptingHttpAccessor implements RestOperations {
//사용가능한 http메서지 컨버터들을 담기 위한 리스트
private final List<HttpMessageConverter<?>> messageConverters;
public abstract class InterceptingHttpAccessor extends HttpAccessor {
public abstract class HttpAccessor {
RestTemplate 인스턴스 생성
- Empty Constructor
public RestTemplate() {
기본으로 사용가능한 http 메세지 컨버터들을 리스트로 초기화 및 프로젝트에서 추가해놓은 gson, jackson이 존재하는지 체크후 존재하면 메세지 컨버터 리스트에 추가
HttpAccessor 생성자에서 기본으로 사용될 http 요청 팩토리를 SimpleClientHttpRequestFactory로 설정
- RestTemplate이 사용할 http 요청 팩토리를 지정하는 생성자
public RestTemplate(ClientHttpRequestFactory requestFactory) {
앞서 살펴본 this()를 통해 모든 셋팅을 완료한 뒤 this.setRequestFactory(requestFactory)를 통해 http 요청 팩토리만 교체
- http 요청 팩토리로 HttpComponentsClientHttpRequestFactory를 사용할시 dependency 추가 필요
<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpclient</artifactId>
<version>4.5.2</version>
</dependency>
Http 헤더
특정 Http헤더는 하나의 값이 아닌 여러 값을 가질 수 있다.(ex 받을 수 있는 언어 accept 한국어,일본어,영어등등)
Map의 경우 특정 key에 하나의 값만 적용될 수 있기 때문에 Spring에서는 다음의 인터페이스와 구현 클래스를 제공
헤더 모방 예제
public class Program {
public static void main(String[] args) {
MultiValueMap<String, String> allHeader = new LinkedMultiValueMap<>();
allHeader.add("받을 수 있는 컨텐트 타입", "제이슨");
allHeader.add("받을 수 있는 컨텐트 타입", "이미지");
allHeader.add("지원되는 언어", "영어");
allHeader.add("지원되는 언어", "한국어");
}
}
Http헤더사용을 위해 HttpHeaders클래스를 지원하며 MultiValueMap을 상속했다.
헤더 추가시 하드 코딩시 발생할 수 있는 에러를 위해 HttpHeaders,MediaType의 상수를 사용하면 된다.
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
public class Program {
public static void main(String[] args) {
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_JSON);
//headers.set("Content-Type", "application/json");와 같음
}
}
http 메세지
http 메세지는 헤더와 바디로 구성되어 있다. HttpEntity클래스는 http메세지에 해당
HttpEntity생성시 타입변수를 지정해주면 해당 타입이 메세지 바디의 타입이 된다.
http 요청 메세지는 HttpEntity를 상속한 RequestEntity클래스
http 응답 메세지는 HttpEntity를 상속한 ResponseEntity클래스
uri를 생성하기 위해 UriComponentsBuilder
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;
import org.springframework.web.util.UriComponents;
import org.springframework.web.util.UriComponentsBuilder;
public class Program {
public static void main(String[] args) {
MultiValueMap<String, String> queryParams = new LinkedMultiValueMap<>();
queryParams.add("user", "kim");
queryParams.add("age", "20");
UriComponents uriComponents = UriComponentsBuilder.newInstance()
.scheme("http")
.host("localhost:8080")
.path("/test.do")
.queryParams(queryParams)
.build();
//public UriComponentsBuilder queryParams(@Nullable MultiValueMap<String, String> params) {
String url = uriComponents.toUriString();
System.out.println(url);
}
}
RestTemplate의 exchange메서드를 사용하여 json을 받아옴
http://jsonplaceholder.typicode.com/todos
에서 받은 json데이터를 받아보자
JSON 스펙에 해당하는 클래스
class Item {
private int userId;
private int id;
private String title = "";
private boolean completed;
public Item() {
}
public int getUserId() {
return userId;
}
public void setUserId(int userId) {
this.userId = userId;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
public boolean isCompleted() {
return completed;
}
public void setCompleted(boolean completed) {
this.completed = completed;
}
@Override
public String toString() {
return "Item{" +
"userId=" + userId +
", id=" + id +
", title='" + title + '\'' +
", completed=" + completed +
'}';
}
}
JSON요청
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.google.gson.reflect.TypeToken;
import org.springframework.http.*;
import org.springframework.http.converter.StringHttpMessageConverter;
import org.springframework.web.client.RestTemplate;
import org.springframework.web.util.UriComponents;
import org.springframework.web.util.UriComponentsBuilder;
import java.nio.charset.StandardCharsets;
import java.util.List;
public class Program {
public static void main(String[] args) {
//인스턴스 생성시 기본으로 StringHttpMessageConverter가 포함된다.
RestTemplate restTemplate = new RestTemplate();
int index = -1;
for (int i = 0; i < restTemplate.getMessageConverters().size(); i++) {
if (restTemplate.getMessageConverters().get(i) instanceof StringHttpMessageConverter) {
index = i;
}
}
if (index == -1) {
restTemplate.getMessageConverters().add(new StringHttpMessageConverter(StandardCharsets.UTF_8));
} else {
System.out.println("restTemplate의 http메세지 컨버터 리스트 필드의 " + index + "번 아이템에 포함됨");
System.out.println("utf-8인것으로 StringHttpMessageConverter로 교체");
System.out.println();
restTemplate.getMessageConverters().add(index, new StringHttpMessageConverter(StandardCharsets.UTF_8));
}
HttpHeaders httpHeaders = new HttpHeaders();
httpHeaders.setContentType(MediaType.APPLICATION_JSON);
HttpEntity<String> httpEntity = new HttpEntity<>(httpHeaders);
UriComponents uriComponents = UriComponentsBuilder.newInstance()
.scheme("http")
.host("jsonplaceholder.typicode.com")
.path("todos")
.build();
String urlString = uriComponents.toUriString();
//String.class로 T Body -> String Body
ResponseEntity<String> responseEntity = restTemplate.exchange(urlString, HttpMethod.GET, httpEntity, String.class);
HttpHeaders responseHeaders = responseEntity.getHeaders();
String responseBody = responseEntity.getBody();
System.out.println("http response header debugging start");
System.out.println(responseHeaders.toString());
System.out.println();
System.out.println("http response body(String) start");
System.out.println(responseBody);
System.out.println();
//JSON처리 작업
System.out.println("받은 JSON String을 Java객체로 변환");
GsonBuilder gsonBuilder = new GsonBuilder();
Gson gson = gsonBuilder.create();
//List.class로 넘기면 Gson은 gson패키지의 LinkedTreeMap인스턴스를 List에 담는다.
//List<LinkedTreeMap> itemList1 = gson.fromJson(responseBody, List.class);
//itemList1.forEach(obj -> System.out.println("LinkedTreeMap 인스턴스?: " + Boolean.toString(obj instanceof LinkedTreeMap)));
//방법1
System.out.println("방법1 start");
List<Item> itemList2 = gson.fromJson(responseBody, new TypeToken<List<Item>>() {
}.getType());
itemList2.forEach(item -> System.out.println(item));
System.out.println();
//방법2
System.out.println("방법2 start");
Item[] itemArray = gson.fromJson(responseBody, Item[].class);
for (int i = 0; i < itemArray.length; i++) {
System.out.println(itemArray[i]);
}
}
}
- Authorization
HttpHeaders httpHeaders = new HttpHeaders();
String bearerToken = "토큰 입력";
httpHeaders.setBearerAuth(bearerToken);