Intro
Spring Boot 프로젝트 진행 중 REST API로 개발하다가 Thymeleaf 사용 차 @Controller 어노테이션으로 변경한 일이 있었다. 모여서 회의하다가 Server Side Rendering와 Client Side Rendering에 대한 개념 등 조금 더 알아보기로 했다.
그 중 난 @RequestBody와 @ModelAttribute의 차이점과 언제 활용할 수 있는 지에 대해 알아본 내용을 바탕으로 팀 기술 문서 자료를 준비했다.
컨텐츠 주제
- @RequestBody VS @ModelAttribute 차이점, 유사점 등등 각각 특징 등을 비교해서 포스팅 해주세요.
- 이때 해당 작업은 어떨 때 구분해서 사용 되는지에 대해서 설명해주고! 해당 작업을 사용한 예시 코드도 좀 부탁드려요.
- 또한 setter를 필요로 하는 작업과 아닌 작업에 대해서도 언급해주세요!
목차
1. @RequestBody
2. @ModelAttribute
3. @RequestBody VS @ModelAttribute 차이점
@RequestBody
🧙🏼♂️ @RequestBody란?
@RequestBody
는 HTTP 요청 본문(body)을 읽어와서 객체로 변환합니다. 주로 JSON 또는 XML 형태의 데이터를 전송하고, 해당 데이터를 객체로 변환할 때 사용합니다.
body에 담은 값을 변환하기 때문에, GET 이 아닌 POST 방식에서만 사용이 가능합니다. GET 방식은 Header에 값을 담아서 보내기 때문이에요.
🎈 예시를 통해 알아보기
간단한 예시를 통해 알아봅시다.
클라이언트가 다음과 같은 JSON 형식의 데이터를 서버에게 전송한다고 가정해봅시다:
{
"id": 1,
"name": "Yerin Park",
"age": 20
}
이 데이터를 받아서 처리하는 간단한 코드 예시입니다.
🧑🏼 Person
public class Person {
private Long id;
private String name;
private int age;
// and so on...
}
🎮 Controller
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class PersonController {
@PostMapping("/person")
public String createPerson(@RequestBody Person person) {
// person 객체로 전송된 데이터 반환
return "What is your name? : " + person.getName();
}
}
Controller에서 JSON 데이터를 Person
객체로 변환합니다.
클라이언트가 POST 요청으로 "/person" endpoint에 JSON 데이터를 전송하면, Spring은 해당 JSON 데이터를 Person
객체로 변환하고 Controller method에 주입합니다. 이때 변환 작업은 MappingJackson2HttpMessageConverter
를 통해 요청 본문을 객체로 역직렬화합니다. 이후 Controller method에서는 person
객체를 활용하여 비즈니스 로직을 수행할 수 있습니다.
👩🏼🍳 활용법
@Valid
또는 Spring의 @Validated
어노테이션과 함께 사용 가능하며, 유효성 검사 오류는 기본적으로 400 (BAD_REQUEST) 응답으로 처리됩니다.
다른 매개변수에 @Constraint
어노테이션이 있으면 HandlerMethodValidationException이 발생할 수 있습니다.
👨🏼💻 예시 코드
@PostMapping("/accounts")
public void handle(@Valid @RequestBody Account account, Errors errors) {
// ...
}
@ModelAttribute
🧙🏼♂️ @ModelAttribute란?
@ModelAttribute
는 요청 파라미터를 모델 객체에 바인딩하는 역할을 합니다. 클라이언트가 전송한 HTTP 파라미터 및 HTTP 본문(body)의 내용을 해당 객체의 Setter 함수를 통해 1:1로 객체에 데이터를 바인딩합니다. 여기서 HTTP Body 내용은 multipart/form-data 형태이고, 변수 타입이나 변수명 등 바인딩 가능한지 검증 작업이 이루어집니다. 만약, 클라이언트로부터 전송된 데이터를 모델 객체에 바인딩하는 도중에 에러가 발생하면 Spring은 BindException
을 던집니다.
@ModelAttribute
는 주로 JSP에서 Form 안에 input 값을 담아 보낼 때 유용하게 사용합니다.
📎 데이터 바인딩
@ModelAttribute
는 요청 파라미터를 모델 객체의 필드에 바인딩하는 역할을 합니다. Setter 함수는 해당 필드에 값을 설정하는데 사용됩니다.
🎈 예시를 통해 알아보기
🧑🏼 User
public class User {
private String username;
private int age;
// Getters and setters
}
🎮 Controller
@Controller
public class UserController {
@GetMapping("/userForm")
public String getUserForm(Model model) {
model.addAttribute("user", new User());
return "userForm";
}
@PostMapping("/saveUser")
public String saveUser(@ModelAttribute("user") User user) {
// 여기서 user 객체를 이용하여 저장 로직을 수행
System.out.println("Saved user: " + user.getUsername() + ", Age: " + user.getAge());
return "redirect:/userForm";
}
}
여기서 getUserForm
은 사용자에게 입력 폼을 보여주기 위한 메서드입니다.
ModelAttribute
를 사용하여 빈 User
객체를 모델에 추가하고, saveUser
메서드는 이 폼에서 입력된 데이터를 받아와서 실제로 저장하는 역할을 합니다.
📄 userForm.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>User Form</title>
</head>
<body>
<h1>User Form</h1>
<form action="/saveUser" method="post">
<label for="username">Username:</label>
<input type="text" id="username" name="username" required>
<br>
<label for="age">Age:</label>
<input type="number" id="age" name="age" required>
<br>
<button type="submit">Save</button>
</form>
</body>
</html>
사용자가 username
과 age
를 입력하고 "Save" 버튼을 누르면, 이 정보는 @ModelAttribute
를 사용하여 자동으로 User
객체로 바인딩되어 saveUser
메서드에 전달됩니다. 이렇게 하면 컨트롤러에서는 매우 간편하게 모델 객체를 생성하고 데이터를 전달받을 수 있습니다.
👩🏼🍳 활용법 및 주의사항
- 보안 및 모델 객체 디자인 시 특별한 주의가 필요합니다.
- ⚠️
@ModelAttribute
의 보안 취약점 주의 사항@ModelAttribute
는 클라이언트로부터 전송된 데이터를 모델 객체에 자동으로 바인딩합니다. 이때 클라이언트가 악의적으로 조작한 데이터를 모델 객체에 주입할 수 있는 보안 취약점이 발생할 수 있습니다.- 예를 들어, 모델 객체에 불필요한 속성이나 비즈니스 로직을 담고 있다면 클라이언트가 이를 이용하여 악의적인 행동을 할 수 있습니다.
- 데이터 바인딩 오류 및 유효성 검사*
- 데이터 바인딩 중에 클라이언트로부터 전송된 데이터 형식이나 값이 잘못된 경우
MethodArgumentNotValidException
이 발생합니다. 이 예외는 클라이언트의 잘못된 입력으로부터 서버를 보호하는 데 중요합니다. @Valid
어노테이션을 사용하면 데이터 바인딩 이후 자동으로 유효성 검사가 적용됩니다. 이를 통해 클라이언트의 잘못된 입력에 대한 유효성을 검증할 수 있습니다.@PostMapping("/update") public String update(@ModelAttribute("user") @Valid User user, BindingResult result) { if (result.hasErrors()) { // 데이터 바인딩 오류 또는 유효성 검사 오류 발생 return "errorPage"; } // 정상적인 처리 userService.updateUser(user); return "successPage"; }
- 결론*
- 모델 객체는 클라이언트로부터 전송된 데이터에 필요한 속성만을 가지고 있어야 합니다.
- 불필요한 속성을 제거하고, 필요한 경우에는 데이터를 적절히 검증하여 사용해야 합니다.
- 모델 객체 구성 시 비즈니스 로직에 따라 신중히 결정합니다.
- ⚠️
- 데이터 바인딩 오류가 발생하면 기본적으로
MethodArgumentNotValidException
이 발생하며, 필요에 따라 컨트롤러 메서드에서 이를 처리할 수 있습니다. @Valid
어노테이션을 사용하여 데이터 바인딩 후 자동으로 유효성 검사를 적용할 수 있습니다.
@RequestBody VS @ModelAttribute 차이점
@RequestBody
와 @ModelAttribute
는 두 개 모두 Spring 프레임워크에서 웹 애플리케이션 개발 시 사용되는 어노테이션입니다. 컨트롤러 메서드의 매개변수로 사용되어, HTTP 요청 데이터를 Java 객체로 변환하여 사용할 수 있게 합니다.
그러나, HTTP 요청을 처리하는 방식에서 차이가 있습니다. 다음 분류 표로 비교해보겠습니다.
@RequestBody | @ModelAttribute | |
---|---|---|
JSON/XML 데이터 전송 | RESTful API에서 JSON 또는 XML 데이터를 전송할 때 사용 | HTML 폼 데이터를 전송하고자 할 때 사용 |
데이터 바인딩 방식 | 요청 본문(body)을 읽어와 객체로 변환 | 요청 파라미터를 모델 객체의 필드에 바인딩 |
유효성 검사 | 기본적으로 지원되며, @Valid 어노테이션을 사용하여 유효성 검사 가능 | 명시적으로 @Valid 어노테이션을 추가해야 유효성 검사 가능 |
인스턴스 생성 방식 | 객체 생성을 위한 기본 생성자 또는 "primary constructor" 사용 | 객체 생성을 위한 기본 생성자 사용 |
속성 바인딩 설정 | 요청 본문을 객체로 변환하는 과정에서는 속성 바인딩 설정이 덜 필요 | 특정 필드만 바인딩하도록 속성 바인딩 설정 가능 |
👷🏼♂️ Setter를 필요로 하는 작업
- @RequestBody: 생성자를 통해 객체를 초기화하는 경우가 많기 때문에 일반적으로 setter가 필요하지 않습니다.
- @ModelAttribute: 스프링이 객체를 생성하고 필드에 값을 할당하기 위해 setter를 사용합니다.
이러한 기준을 고려하여 @RequestBody
와 @ModelAttribute
를 적절하게 선택하면 됩니다.
'Project' 카테고리의 다른 글
AngularJS로 만든 포트폴리오 웹사이트 1일차 (0) | 2024.11.04 |
---|---|
[프로젝트 회고] 대용량 데이터 처리 프로젝트(최저 가격 검색 시스템) (0) | 2024.08.11 |
[Naver API] 검색 API 사용해보기 (0) | 2023.10.09 |
[OpenCV] 앱 개발 일지 (0) | 2023.08.09 |
EC2 서버에 올라간 Spring Boot와 React 연동 시 CORS 설정 (0) | 2023.07.13 |