본문으로 바로가기

PUT 방식에 이해 및 실습

category Spring boot 2024. 10. 1. 09:20
학습 목표
1. PUT 방식에 이해 및 실습
2. DTO 만들어 보기

 

 

PUT 방식은 HTTP 메서드 중 하나로, 리소스를 생성하거나 업데이트할 때 사용됩니다. 주로 RESTful API에서 특정 리소스를 완전히 대체하거나 수정할 때 사용됩니다.

 

주요 특징

  • 전체 업데이트:
    • PUT 요청은 클라이언트가 서버에 특정 리소스의 전체 데이터를 보내 해당 리소스를 완전히 대체하거나 새로 생성하는 요청입니다. 즉, 리소스의 일부가 아닌 전체 데이터를 전송하여 갱신합니다.
  • 멱등성:
    • PUT 요청멱등성을 가집니다. 즉, 동일한 요청을 여러 번 보내도 결과가 동일합니다. 예를 들어, 동일한 데이터를 PUT 요청으로 여러 번 보내도 리소스 상태는 변하지 않습니다.
  • 리소스 식별:
    • PUT 요청URL을 통해 업데이트할 리소스를 명확히 식별합니다. 예를 들어, /users/1 URL로 PUT 요청을 보내면, ID가 1인 사용자를 업데이트하거나, 해당 리소스가 존재하지 않으면 새로 생성합니다.

요청 데이터

{
	"name" : "mike",
	"age" : 30, 
	"car_list" : [
                	{
                        "name" : "M3",
                        "car_number" : "22너 3341"
                    },
                    {
                        "name" :  "R8",
                        "car_number" : "33너 1234"
                    }
                ]
}
package com.tenco.demo_v1.dto;

import java.util.List;

import com.fasterxml.jackson.databind.PropertyNamingStrategies;
import com.fasterxml.jackson.databind.annotation.JsonNaming;

import lombok.Data;

@Data
@JsonNaming(value = PropertyNamingStrategies.SnakeCaseStrategy.class)
public class UserDTO {

    private String name; 
    private Integer age; 
    //@JsonProperty("car_list")
    private List<CarDTO> carList; 

    // 비 정적 내부 클래스 
    class CarDTO {
        private String name; 
        //@JsonProperty("car_number")
        private String carName; 
    }

}

PutApiController 생성

package com.tenco.demo_v1.controller;

import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RestController;

import com.tenco.demo_v1.dto.UserDTO;

@RestController // IoC (싱글톤 패턴으로 관리 됨 )
public class PutApiController {

    /**
     * 주소설계 
     * <http://localhost:8080/put/demo1/100>
     * 
     * @return JSON 
     */

     @PutMapping("/put/demo1/{id}")
     public UserDTO putMethodName(@PathVariable(name = "id") String id, 
                                                            @RequestBody UserDTO userDTO) {
         System.out.println("id : " + id);
         System.out.println("userDTO  " + userDTO.toString());
         // 메세지 컨버터 동작  (UserDTO) ->> JSON 반환을 해서 ---> 클라이언트에 응답처리 한다. 
         return userDTO;
     }

    //  @PutMapping("/put/demo1/{id}")
    //  public UserDTO putMethodName(@PathVariable(name = "id") String id) {
    //      System.out.println("id : " + id);
    //      // System.out.println("userDTO  " + userDTO.toString());
    //      // 메세지 컨버터 동작  (UserDTO) ->> JSON 반환을 해서 ---> 클라이언트에 응답처리 한다. 
    //      return null;
    //  }

}

 

💡 non-static inner classes

오류 원인 확인

비정적 내부 클래스:

  • 자바에서 비정적 내부 클래스는 외부 클래스의 인스턴스와 연결되어야만 인스턴스화될 수 있습니다. 즉, 내부 클래스는 외부 클래스의 인스턴스가 필요합니다.
  • Jackson이 JSON 데이터를 객체로 변환할 때, 내부 클래스의 인스턴스를 생성하려 하지만, 비정적 내부 클래스는 외부 클래스의 인스턴스 없이는 생성할 수 없으므로 오류가 발생합니다.

기본 생성자:

  • Jackson은 JSON 데이터를 자바 객체로 변환할 때, **기본 생성자(파라미터가 없는 생성자)**를 사용해 객체를 생성합니다. 하지만 비정적 내부 클래스는 외부 클래스의 참조를 필요로 하기 때문에, 기본 생성자로 생성할 수 없습니다

해결 방법:

  1. 내부 클래스를 정적(static)으로 변경 비정적 내부 클래스를 정적(static) 내부 클래스로 변경하면, 외부 클래스의 인스턴스 없이도 내부 클래스의 인스턴스를 생성할 수 있습니다.
  2. 외부 클래스로 이동 내부 클래스를 별도의 외부 클래스로 이동시키는 방법도 있습니다. 이를 통해 Jackson이 객체를 생성할 때 문제없이 생성할 수 있습니다. 

 

UserDTO 수정하기

package com.tenco.demo_v1.dto;

import java.util.List;

import com.fasterxml.jackson.databind.PropertyNamingStrategies;
import com.fasterxml.jackson.databind.annotation.JsonNaming;

import lombok.Data;
import lombok.Getter;
import lombok.ToString;

@Data
@JsonNaming(value = PropertyNamingStrategies.SnakeCaseStrategy.class)
public class UserDTO {

    private String name; 
    private Integer age; 
    //@JsonProperty("car_list")
    private List<CarDTO> carList; 

    // 비 정적(static)  내부 클래스 (x)
    // 스프링 부트 DTO 설계시 내부 클래스는 static 내부 클래스로 만들자 
    @Getter // 반드시 있어야 한다. !!! 
    @ToString
    @JsonNaming(value = PropertyNamingStrategies.SnakeCaseStrategy.class)
    static class  CarDTO {
        private String name; 
        //@JsonProperty("car_number")
        private String carName; 
    }

}