본문 바로가기

Spring boot/Blog 프로젝트 만들기(JPA)

PUT 방식에 이해 및 실습

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

 

 

주요 특징

전체 업데이트

  • PUT 요청은 클라이언트가 서버에 특정 리소스의 전체 데이터를 보내 해당 리소스를 완전히 대체하거나 새로 생성하는 요청이다. 즉, 리소스의 일부가 아닌 전체 데이터를 전송하여 갱신한다.

 

멱등성

  • PUT 요청은 멱등성을 가진다. 즉, 동일한 요청을 여러번 보내도 결과가 동일하다. 예를 들어 동일한 데이터를 PUT 요청으로 여러 번 보내도 리소스 상태는 변하지 않는다.

 

리소스 식별

  • PUT 요청은 URL을 통해 업데이트 할 리소스를 명확히 식별한다. 예를 들어 /user1/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; 
    }

}
728x90