JPA

스프링 부트 요청과 응답 동작 방식(PUT 방식)

yoooon1212 2024. 9. 27. 17:26

 

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"
                    }
                ]
}

 

 

userDTO2
package com.tenco.demo_v1.dto;

import java.util.List;

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

import lombok.Data;
import lombok.ToString;

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

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

	// 비 정적 내부 클래스(none-static inner classes)
	// -> 비 정적 내부 클래스는 외부 클래스의 인스턴스가 필요함.
	// OR 외부 클래스로 빼기
	// 스프링부트 DTO 설계 시 내부 클래스는 static 내부 클래스로 만들자

	// 정적(static) 내부 클래스
	@Data
	@ToString
	@JsonNaming(value = PropertyNamingStrategies.SnakeCaseStrategy.class)
	static class CarDTO {
		private String name;
		@JsonProperty("car_number") // 카멜 형식으로 변환
		private String carNumber;
	}

}

 

 

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.UserDTO2;


@RestController // IoC (싱글톤 패턴)
public class PutApiController {

	/*
	 * 주소 설계 
	 * http://localhost:8080/put/demo1/100
	 * 
	 * @return JSON
	 */	
	
	@PutMapping("/put/demo1/{id}")
	public UserDTO2 putMethodName(@PathVariable(name = "id") String id, 
			@RequestBody UserDTO2 dto) {
		
		System.out.println("id:" + id);
		System.out.println("userDTO:" + dto.toString());
		
		// 메시지 컨버터 동작(JSON이라서 뷰리졸버가 동작하지 않음) 
		// -> userDTO2 -> JSON 반환 해서  -> 클라이언트에 응답 처리
		
		return dto;
	}
	
//	@PutMapping("/put/demo1/{id}")
//	public UserDTO2 putMethodName(@PathVariable(name = "id") String id) {
//		
//		System.out.println("id:" + id);
//		
//		// 메시지 컨버터 동작(JSON이라서 뷰리졸버가 동작하지 않음) 
//		// -> userDTO2 -> JSON 반환 해서  -> 클라이언트에 응답 처리
//		
//		return null;
//	}
}

 

 

💡 non-static inner classes

오류 원인 확인

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

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

해결 방법
1. 내부 클래스를 정적(static)으로 변경
비정적 내부 클래스를 정적(static) 내부 클래스로 변경하면, 외부 클래스의 인스턴스 없이도 내부 클래스의 인스턴스를 생성할 수 있습니다.

2. 외부 클래스로 이동
내부 클래스를 별도의 외부 클래스로 이동시키는 방법도 있습니다. 이를 통해 Jackson이 객체를 생성할 때 문제없이 생성할 수 있습니다. 

 

 

 Test 결과