Spring 숙련 2주차 (1)

신성훈·2024년 5월 27일

TIL

목록 보기
25/162
post-thumbnail

오늘의 학습 키워드

  • RestTemplate

RestTemplate

  • Server To Server
    -Spring에서는 서버에서 다른 서버로 간편하게 요청할 수 있도록 RestTemplate 기능을 제공하고 있습니다

  • RestTemplate 사용방법

  1. Get 요청
  • 클라이언트 입장 서버
    1. RestTemplate을 주입

    private final RestTemplate restTemplate;
    // RestTemplateBuilder의 build()를 사용하여 RestTemplate을 생성합니다.
    public RestTemplateService(RestTemplateBuilder builder) {
    this.restTemplate = builder.build();
    }
    

    2. 요청 받은 검색어를 Query String 방식으로 Server 입장의 서버로 RestTemplate를 사용하여 요청
    public ItemDto getCallObject(String query) {
    	// 요청 URL 만들기
    	URI uri = UriComponentsBuilder
    			.fromUriString("http://localhost:7070")
    			.path("/api/server/get-call-obj")
    			.queryParam("query", query)
    			.encode()
    			.build()
    			.toUri();
    	log.info("uri = " + uri);
    	ResponseEntity<ItemDto> responseEntity = restTemplate.getForEntity(uri, ItemDto.class);
    	log.info("statusCode = " + responseEntity.getStatusCode());
    	return responseEntity.getBody();
    }

    -Spring의 UriComponentsBuilder를 사용해서 URI를 손쉽게 만들 수 있
    -RestTemplate의 getForEntity는 Get 방식으로 해당 URI의 서버에 요청을 진행
    ->첫 번째 파라미터에는 URI, 두 번째 파라미터에는 전달 받은 데이터와 매핑하여 인스턴스화할 클래스의 타입을 주면 된다.
    -요청의 결과값에 대해서 직접 JSON TO Object를 구현할 필요없이 RestTemplate을 사용하면 자동으로 처리
    ->response.getBody() 를 사용하여 두 번째 파라미터로 전달한 클래스 타입으로 자동 변환된 객체를 가져올 수 있다.

  • Server 입장 서버
    1. Server 입장의 서버에서 itemList를 조회하여 요청받은 검색어에 맞는 Item을 반환

    public Item getCallObject(String query) {
    	for (Item item : itemList) {
    		if(item.getTitle().equals(query)) {
    			return item;
    		}
    	}
    	return null;
    }

  1. 요청한 Item이 여러개 일 경우
  • 클라이언트 입장 서버

    // json
    implementation 'org.json:json:20230227'

    -Item List 조회

    public List<ItemDto> getCallList() {
    	// 요청 URL 만들기
    	URI uri = UriComponentsBuilder
    			.fromUriString("http://localhost:7070")
    			.path("/api/server/get-call-list")
    			.encode()
    			.build()
    			.toUri();
    	log.info("uri = " + uri);
    	ResponseEntity<String> responseEntity = restTemplate.getForEntity(uri, String.class);
    	log.info("statusCode = " + responseEntity.getStatusCode());
    	log.info("Body = " + responseEntity.getBody());
    	return fromJSONtoItems(responseEntity.getBody());
    }
    

    -결과 값이 다중 JSON으로 넘어오기 때문에 JSON To Object를 사용하지 않고 일단 String 값 그대로를 가져온다.

    -> Server 입장 서버의 ItemResponseDto는 아래의 JSON 형태로 변환되어 전달된다.

    {
    "items":[
    	{"title":"Mac","price":3888000},
    	{"title":"iPad","price":1230000},
    	{"title":"iPhone","price":1550000},
    	{"title":"Watch","price":450000},
    	{"title":"AirPods","price":350000}
     ]
    }

    -> JSON 처리를 도와주는 라이브러리를 추가하여 받아온 JSON 형태의 String을 처리

    public List<ItemDto> fromJSONtoItems(String responseEntity) {
    	JSONObject jsonObject = new JSONObject(responseEntity);
    	JSONArray items = jsonObject.getJSONArray("items");
    	List<ItemDto> itemDtoList = new ArrayList<>();
    	
       for (Object item : items) {
    		ItemDto itemDto = new ItemDto((JSONObject) item);
    		itemDtoList.add(itemDto);
    	}
    	return itemDtoList;
    }

    -> ItemDto에 받아온 JSONObject를 사용하여 초기화하는 생성자를 추가

    @Getter
    @NoArgsConstructor
    public class ItemDto {
    	private String title;
    	private int price;
       
    	public ItemDto(JSONObject itemJson) {
    		this.title = itemJson.getString("title");
    		this.price = itemJson.getInt("price");
    	}
    }

  • Server 입장의 서버
    -> Server 입장의 서버에서 itemList를 ItemResponseDto에 담아 반환

    public ItemResponseDto getCallList() {
    	ItemResponseDto responseDto = new ItemResponseDto();
    	for (Item item : itemList) {
    		responseDto.setItems(item);
    	}
    	return responseDto;
    }

  1. Post 요청
  • 클라이언트 입장 서버
    -요청 받은 검색어를 Query String 방식으로 Server 입장의 서버로 RestTemplate를 사용하여 요청

    public ItemDto postCall(String query) {
    	// 요청 URL 만들기
    	URI uri = UriComponentsBuilder
    			.fromUriString("http://localhost:7070")
    			.path("/api/server/post-call/{query}")
    			.encode()
    			.build()
    			.expand(query)
    			.toUri();
    	log.info("uri = " + uri);
    	User user = new User("Robbie", "1234");
    	ResponseEntity<ItemDto> responseEntity = restTemplate.postForEntity(uri, user, ItemDto.class);
    	log.info("statusCode = " + responseEntity.getStatusCode());
    	return responseEntity.getBody();
    }

    -UriComponentsBuilder의 expand를 사용하여 {query} 안의 값을 동적으로 처리한다.
    -RestTemplate의 postForEntity는 Post 방식으로 해당 URI의 서버에 요청을 진행한다.
    -> 첫 번째 파라미터에는 URI, 두 번째 파라미터에는 HTTP Body에 넣어줄 데이터를 넣는다.
    -> Java 객체를 두 번째 파라미터에 넣으면 자동으로 JSON 형태로 변환된다.
    -> 세 번째 파라미터에는 전달 받은 데이터와 매핑하여 인스턴스화할 클래스의 타입을 주면 된다.

  • Server 입장 서버
    -Server 입장의 서버에서 itemList를 조회하여 요청받은 검색어에 맞는 Item을 반환

    public Item postCall(String query, UserRequestDto userRequestDto) {
    	System.out.println("userRequestDto.getUsername() = " + userRequestDto.getUsername());
    	System.out.println("userRequestDto.getPassword() = " + userRequestDto.getPassword());
    	
       return getCallObject(query);
    }

    -전달 받은 HTTP Body의 User 데이터를 확인

  1. exchange
  • 클라이언트 입장 서버
    public List<ItemDto> exchangeCall(String token) {
    	// 요청 URL 만들기
    	URI uri = UriComponentsBuilder
    			.fromUriString("http://localhost:7070")
    			.path("/api/server/exchange-call")
    			.encode()
    			.build()
    			.toUri();
    	log.info("uri = " + uri);
    	User user = new User("Robbie", "1234");
    	RequestEntity<User> requestEntity = RequestEntity
    			.post(uri)
    			.header("X-Authorization", token)
    			.body(user);
    	ResponseEntity<String> responseEntity = restTemplate.exchange(requestEntity, String.class);
    	return fromJSONtoItems(responseEntity.getBody());
    }
    -> exchange 메서드의 첫 번째 파라미터에 RequestEntity 객체를 만들어 전달해주면 uri, header, body의 정보를 한번에 전달할 수 있다.
profile
조급해하지 말고, 흐름을 만들고, 기록하면서 쌓아가자.

0개의 댓글