SPRING REST
GET
GET으로 원하는 데이터 요청하는 방법 2가지
- @RequestParam
- @PathVariable
@GetMapping(path="/echo/{message}")
public String echo(
@PathVariable(name = "message") String msg,
@PathVariable int age, // integer, int 중 integer은 null 으로 초기화, int는 0으로 초기화 지금은 int가 맞음
@PathVariable boolean isMan
){
System.out.println("echo message:"+msg);
return msg;
}
// <http://localhost:8080/api/book?category=IT&issuedYear=2023&issued-month=01&issued_day=31>
@GetMapping(path="/book")
public queryParam(
@RequestParam String category,
POST
- 데이터 생성 요청
- HTTP BODY로 데이터를 요청 받아서 처리 @RequestBody
- POST니까 @PostMapping("/post") 어노테이션으로 처리
Controller
public class UserApiController {
@PostMapping("/user")
public void user(
@RequestBody UserRequest userRequest
){
System.out.println(userRequest);
}
}
DTO (UserRequest)
//Lombok
@Data // 클래스가 가지고 있는 메서드 자동 생성
@AllArgsConstructor // 전체 파라미터 자동 생성(기본 생성자가 없어짐)
@NoArgsConstructor // 기본생성자를 달아줌
@JsonNaming(PropertyNamingStrategies.SnakeCaseStrategy.class)
public class UserRequest {
private String name;
private String phoneNumber;
private String email;
private Boolean isKorean ;
}
primitive(기본형) 타입, reference(참조형) 타입이 있는데 DTO 사용할 때는 null 값이 들어올 수도 있기 때문에 reference 타입, 객체 타입을 사용해야 한다. (int, boolean 같은 기본형 타입은 안됨)
JSON
- KEY : VALUE 형식
- String, Number, Boolean, Object {}, Array [] 모두 가능
isKorean"으로 JSON 요청을 보내도 setter에서 Korean만 남는 문제
🤔질문 : "Boolean 타입 필드를 선언하면, getter를 먼저 만들고, getter를 참고해서 setter를 만들기 때문에 setter 이름에서 is를 떼는거냐? 그리고 이건 Boolean 타입일 때만 이런가?"
✅답 : 아님. getter를 참고해서 setter를 만드는 순서가 아니고, Java Bean 명세(스펙)에 따라 각각 독립적으로 규칙을 적용하는 거. 즉, Boolean 타입이면 "getter"는 isXxx(), "setter"는 setXxx() 이 패턴을 따르는 거. 순서로 따지는 게 아니라 타입이 Boolean이면 이렇게 규칙적으로 만드는 거
핵심 원인
Java Bean 규약(JavaBean Specification) 때문.
- Java에서는 "Boolean 타입의 필드"에 대해 getter, setter 메서드 이름을 만들 때 특별 규칙이 있음.
- Boolean 타입 필드는 보통 is로 시작하는 getter를 자동으로 기대 (isKorean()).
- 그런데 setter를 만들 때는 set + 필드 이름의 첫 글자를 대문자로 만들어야 함.
- 그런데 이때 is를 빼버리고 뒤에 있는 이름만 붙여서 처리하는 문제가 발생.
즉,
private Boolean isKorean;
이면 Java Bean 규약에 따라:
getter | isKorean() |
setter | setKorean(Boolean korean) |
setIsKorean(Boolean isKorean)이 아니라 setKorean(Boolean korean)이 만들어진다!!
다시 요약하면
- Boolean isKorean 필드를 선언하면,
- setter는 setKorean(Boolean korean) 형태로 만들어진다.
- is가 제거되고 나머지(Korean)만 setter 이름으로 사용된다.
그래서 "isKorean"이라는 JSON 필드가 들어오면, 매핑할 때 Korean 필드(setter 기준)를 찾으려다가 꼬임.
정리
상황 설명
필드명 isKorean | boolean 타입 필드 |
getter 이름 | isKorean() |
setter 이름 | setKorean(Boolean korean) |
문제 | JSON에서 "isKorean"을 그대로 쓰면 매칭이 꼬인다 (setter를 못 찾을 수 있다). |
해결 방법은?
1. 필드명을 korean으로 아예 바꾸기
private Boolean korean;
이렇게 하면 getter는 isKorean(), setter는 setKorean(Boolean korean) 정상 생성된다. 깔끔해.
2. @JsonProperty로 명시적으로 매핑하기
@JsonProperty("is_korean")
private Boolean isKorean;
이렇게 하면 JSON 쪽 이름과 Java 쪽 이름을 매칭 강제할 수 있어.
예시 코드를 보여줄게
@Data
@AllArgsConstructor
@NoArgsConstructor
public class UserRequest {
private String name;
private String phoneNumber;
private String email;
@JsonProperty("is_korean")
private Boolean isKorean;
}
요렇게 하면, 요청 JSON이
json
코드 복사
{
"name": "spring boot",
"phone_number": "111",
"email": "JAVA",
"is_korean": true}
일 때, isKorean 필드에 잘 매핑돼.
결론
- Java Bean 규약 때문에 Boolean 필드는 is를 빼고 setter 이름이 만들어진다.
- 이로 인해 JSON 필드명과 매칭이 어긋날 수 있다.
- 해결하려면 @JsonProperty를 붙이거나 필드명을 명확히 조정해야 한다.
@JsonNaming(PropertyNamingStrategies.SnakeCaseStrategy.class) 필요한 이유
- POST 요청 Body는 JSON으로 들어오고,
- UserRequest 클래스는 Java 객체로 매핑(deserialization)되어야 함.
- JSON 키는 snake_case(is_korean)인데, Java 필드는 camelCase(isKorean)로 되어 있음.
=> 문제: Jackson(자바 JSON 라이브러리)이 기본적으로 camelCase 기준으로 JSON을 해석한다.
따라서 is_korean을 제대로 읽지 못하고 isKorean에 값을 매핑하지 못하는 문제가 생긴다.
그럼 왜 @JsonNaming(PropertyNamingStrategies.SnakeCaseStrategy.class)가 필요한가?
@JsonNaming(PropertyNamingStrategies.SnakeCaseStrategy.class)를 붙이면,
Jackson이 "snake_case JSON ↔ camelCase Java" 변환 규칙을 자동으로 적용하도록 설정하는 거야.
- 즉, is_korean JSON 필드를 isKorean Java 필드로 자동 매칭해준다.
- 변환 규칙이 없으면 Jackson은 "is_korean이라는 이름" 을 그대로 찾으려 하고, 못 찾으니까 매핑 실패하는 것.
요약
JSON Java 매핑 여부 (기본) 매핑 여부 (@JsonNaming 적용 시)
is_korean | isKorean | ❌ (매칭 실패) | ✅ (매칭 성공) |
- 기본: JSON의 snake_case 키와 Java의 camelCase 필드가 다르기 때문에 매칭 실패
- @JsonNaming 적용 시: snake_case ↔ camelCase 변환이 적용되어 매칭 성공
추가 참고
- Spring Boot는 내부적으로 Jackson을 사용해서 JSON을 파싱한다.
- Jackson의 기본 작동은 "필드 이름을 정확히 맞춰야 한다"는 것이고, naming strategy를 주지 않으면 변환을 안 해줘.
- 글로벌 설정으로 application.yml에도 snake_case 전략을 적용할 수 있지만, 클래스별로 다르게 하고 싶으면 @JsonNaming을 쓰는 게 맞다.
PUT
- 데이터가 없으면 추가, 있다면 수정
- @PutMapping 사용
- put도 post와 마찬가지로 http body로 정보를 받는다.
@Slf4j // log 사용하기 위한 어노테이션
@RestController
@RequestMapping("/api")
public class PutApiController {
@PutMapping("/put")
public void put(
@RequestBody
UserRequest userRequest
){
System.out.println();
log.info("Request : {}", userRequest);
}
}
System.out.println(); 과 log 의 차이
- sout 은 바로바로 출력하기에 느리고, 출력이 끝날 때까지 프로그램 흐름이 잠깐 멈춤(블로킹)
- log는 버퍼를 가지고 있어서 버퍼에 저장한 후, 버퍼가 쌓이면 출력 가능해서, 고급 설정하면 비동기 방식(논블락킹)으로 실행될 수 있음, (log도 기본은 동기 처리임), 확장성, 관리성이 좋음
Delete
- GET 요청 방식과 같다고 생각하자.
//http://localhost:8080/api/user/abcd/delete
@DeleteMapping(path = {
"/user/{userName}/delete",
"/user/{userName}/del"
}) //path 쓰면 두개 이상 가능
public void delete(@PathVariable String userName){
log.info("user-name:{}",userName);
}
}
'Spring > Spring Boot' 카테고리의 다른 글
[Spring Boot] 직렬화, 역직렬화 해주는 Object Mapper 톺아보자! (0) | 2025.04.30 |
---|---|
[Spring Boot] 응답(response) 만들기! (0) | 2025.04.29 |