주노 님의 블로그

20240821 본캠프 28일차 TIL 본문

TIL

20240821 본캠프 28일차 TIL

juno0432 2024. 8. 21. 22:21

본캠프 28일차 내용 간단요약

  • 09:00 ~ 10:00 : 코드카타
  • 10:00 ~ 12:00 : 팀 회의
  • 12:00 ~ 13:00 : 점심시간
  • 13:00 ~ 13:30 : 튜터님 피드백
  • 13:30 ~ 14:00 : 팀원 회의
  • 14:00 ~ 15:00 : 질문
  • 15:00 ~ 18:00 : 공부
  • 18:00 ~ 19:00 : 저녁시간
  • 19:00 ~ 20:00 : 공부
  • 20:00 ~ 21:00 : TIL 작성

오늘 해야할 일 ✔️ 🔺 ❌

✔️2주차 강의 6까지 듣기

 

 

다시 집중할수있고 리프레시했잖앙?!

 


강의

더보기

RestTemplate

  • 서버 간의 http 통신을 쉽게 처리 할 수 있는 스프링 프레임워크의 도구이며, 클라이언트에서 다른 서버의 API를 호출할때 사용도니다.

    사용법

    restTemplate 초기화
    private final RestTemplate restTemplate;
    
    public RestTemplateService(RestTemplateBuilder restTemplateBuilder) 
    {
        this.restTemplate = restTemplateBuilder.build();
    }
    restTemplate는 불러오는 방법이 살짝 다르다.

    래는 일반적인 의존성 주입 방식과는달리
    private final RestTemplate restTemplate; 선언을 하고.

    @RequiredArgsConstructor 어노테이션을 적용하면 됐지만
    지금 restTemplate는 매개변수로 RestTemplateBuilder를 사용하여 받아와야한다.

    build는 restTemplate를 반환하는것을 볼 수 있다.
     
    클라이언트 통신

    postMan에서 
    http://localhost:8080/api/client/get-call-obj?query=Mac
    위 요청을 하게되면

    클라이언트 측인
    @GetMapping("/get-call-obj")
    public ItemDto getCallObject(String query) {
        return restTemplateService.getCallObject(query);
    }

    이쪽으로 오게된다.
    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();
    }

    클라이언트는 특정 경로로 메세지를 보내게되며, 서버간 통신을 수행한다.
    UriComponentsBuilder를 사용하여 동적으로 URL과 쿼리 파라미터를 생성할 수있다.
    restTemplate.getForEntity를 통해 서버에 Get요청을 보내게 된다.


    서버측 로직
    클라이언트측에서 path를 정의한대로  get-call-obj path로 진입하게 된다.
    @GetMapping("/get-call-obj")
    public Item getCallObject(@RequestParam String query) {
        return itemService.getCallObject(query);
    }


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

    클라이언트의 쿼리를 받아 내부 데이터에서 해당하는 항목을 검색 후 결과를 반환한다
    for문을 돌아 내가 던진 쿼리랑 title이 맞으면 item 객체를 가져온다

    다시 클라이언트로 돌아와서

        ResponseEntity<ItemDto> responseEntity = restTemplate.getForEntity(uri, ItemDto.class);
    
        log.info("statusCode = " + responseEntity.getStatusCode());
    
        return responseEntity.getBody();

    서버에서 전달해준 값을 받아
    ResponseEntity에 담기게되고
    getBody를 해서 내용을 가져온다. 
  • 요청이 여러개라면??
    RestTemplate를 이용하여 서버에서 여러개의 JSON객체를 포함하는 정보를 받아오는경우
    클라이언트측에서 이를 처리하기위해 JSON데이터를 JAVA객체로 변환하는 과정이 필요하다.

    클라이언트 측 로직
    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());
    }

    요청은 기존 로직이랑 비슷하지만, fromJSONtoItems메서드를 반환해준다.

    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;
    }

    문자열 정보를 JSONObject로 바꾼다
    왜 JSON으로 바꿀까?

    서버에서 반환하는 방식이 Json형식이기 때문이다.
    JSONObject에서 item 배열을 꺼내기 위해 getJSONArray로 키값을 꺼낸다
    JSONArray로 for문을 돌며 상품을 하나씩 itemDto로 변환을 하여 list에 삽입한다

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

    반환결과는 json형식이다.

  • Post요청
    클라이언트 측
    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();
    }

    queryParam이 아닌 pathvariable 방식으로 전송도 가능하다 {}넣으면 된다
    그리고 postForentity를 사용하여 post하면된다.
    첫번째 파라미터 : uri
    두번째 파라미터 : body에 넣을 객체
    세번째 파라미터 : 전달받을 데이터랑 매핑할 방법

    서버측
    @PostMapping("/post-call/{query}")
    public Item postCall(@PathVariable String query, @RequestBody UserRequestDto requestDto) {
        return itemService.postCall(query, requestDto);
    }

    서버 측에서는 pathVariable 형식으로 클라이언트에서 날라온 query를 받고 있는것을 볼 수 있다.
  • RestTemplate의 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());
        }

    위 메서드를 만들어준다.
    요청 url을 만들고

    RequestEntity를 만들어서 헤더에다가 토큰을 전달해준다.
    post(uri)를 통해 post요청을 보내며 uri는 요청할 url이다
    header을 통해 요청해드에 x-authorization 이라는 이름으로 토큰값을 추가해주고
    body를 통해 요청 본문에 user객체를 보내준다.

    exchange는 responseENtity를 통해 요청을 보내며 타입은 String이다.
    fromJsonItems를 받아와서 json형태를 처리한다.

    controller에서 쿠키를 받는다

     request header나 responseheader에 token을 넣을수있다.
    키에 해당하는 authorization을 넣으면 된다. 

    서버측
    @PostMapping("/exchange-call")
    public ItemResponseDto exchangeCall(@RequestHeader("X-Authorization") String token, @RequestBody UserRequestDto requestDto) {
        return itemService.exchangeCall(token, requestDto);
    }


    requestHeader를 사용해서 클라이언트가 전송한 데이터의 헤더값을 읽어온다.
    클라이언트가 전송한 본문 데이터를 UserRequestDto 객체로 변환하여 받는다

    http://localhost:8080/api/client/exchange-call
    에다가 
    body에  key : Authorization value :  juno1234를 넣어본다.

    반환 이 정상적으로 되며,

    token = juno1234
    토큰을 정상적으로 받은것을 확인 할 수 있다.

    요약
    클라이언트는 requestEntity를 사용하여 요청 헤더에 토큰을 넣어 서버로 전달함
    서버는 @RequestHeader를 사용하여 헤더값을 받아옴
    RestTemplate의 exchange를 이용하면 URI, 헤더, 바디를 한꺼번에 처리할 수 있음!!

  • 네이버 API 사용해보기

    RestTemplate를 써봤으니까 진짜 외부 서버에서 데이터를 가져와보자
    공공데이터포탈이나 각 대기업들은 각자 편리한 api를 사람들에게 사용 할 수 있게 제공해주고있다
    https://developers.naver.com/products/intro/plan/

    이용신청 과정
    애플리케이션을 등록 버튼을 클릭한다.

    허가가 나면 개인에게 클라이언트 id와 클라이언트 secret를 발급받는다

    client id와 secret key를 사용하여 이제 api를 사용해본다.

    https://developers.naver.com/docs/serviceapi/search/shopping/shopping.md#%EC%87%BC%ED%95%91

    대부분 제공하는 api는 위처럼 문서로 설명이되어있으며 대부분 사용법을 따르면 쓸 수 있다.

    사용해보기

    postman으로 이제 사용해보도록 하자

    https://openapi.naver.com/v1/search/shop.json?query=macbook

    쇼핑에서의 매북을 검색하는 url예제이다.
    https://openapi.naver.com/v1/search/shop.json
    요청 url 설명대로 json으로 반환하는 방식을 사용하고
    파라미터는 쿼리로 


    요청헤더에 방금 발급받은 클라이언트 아이디와 시크릿값을 추가한다.



    맥북 관련 자료가 모두 뜨게된다.!

    현재 네이버의 동작이 우리가 그동안 만들었던 서버측 동작이랑 유사하다
    그럼 위 내용을 postman이 아닌 

    클라이언트 측 수정


    네이버 검색 api를 호출하여 restTemplate를 이용해 데이터를 가져와보자
    public List<ItemDto> searchItems(String query) {
        // 요청 URL 만들기
        URI uri = UriComponentsBuilder
                .fromUriString("https://openapi.naver.com")
                .path("/v1/search/shop.json")
                .queryParam("display", 15)
                .queryParam("query", query)
                .encode()
                .build()
                .toUri();
        log.info("uri = " + uri);

    URI를 사용하여 검색 API의 URL을 구성하며
    한번에 15개 어떤내용을 받아올지 파라미터를 설정한다
    RequestEntity<Void> requestEntity = RequestEntity
            .get(uri)
            .header("X-Naver-Client-Id", "Client-Id")
            .header("X-Naver-Client-Secret", "Client-Secret")
            .build();

    RequestEntity를 사용해 요청 헤더에 네이버 api의 클라이언트 id와 키를 추가하여 객체를 생성한다.

 

 

 


오늘의 회고 & 12시간 몰입했는가? 

어흑흑.. 거의 놀아버린 나..

내일은빡세게 하고 바로 과제 들어가야지..

과제하면서 복습하는게 좋아보이는 느낌...!

'TIL' 카테고리의 다른 글

20240823 본캠프 30일차 TIL  (0) 2024.08.23
20240822 본캠프 29일차 TIL  (0) 2024.08.22
20240819 본캠프 26일차 TIL  (0) 2024.08.19
20240817 주말에도 나와버린 나 TIL  (0) 2024.08.17
20240816 내배캠 25일차 TIL  (0) 2024.08.17