본문 바로가기
웹개발/SpringBoot

@RequestBody를 적어야 됐던 일

by 철없는민물장어 2023. 5. 18.
728x90

회원가입할 때 중복유저가 있는 경우에는 에러메세지를 띄워 사용자가 봤으면 좋겠다는 생각을 했다.

우선 chatGPT한테 html과 JS 코드를 작성해달라고 했다.

 

{{>layouts/header}}
<h2>회원가입</h2>
<form id="signup-form" >
    <div class="mb-3">
        <label class="form-label">userId</label>
        <input type="text" class="form-control w-50" name="userId" placeholder="id">
    </div>
    <div class="mb-3">
        <label class="form-label">userPassword</label>
        <input type="text" class="form-control" name="password" placeholder="password">
    </div>
    <div class="mb-3">
        <label class="form-label">nickName</label>
        <input type="text" class="form-control" name="nickname" placeholder="nickName">
    </div>

    <button type="submit" class="btn btn-primary">save</button>
</form>

{{>layouts/footer}}

<script>
document.getElementById('signup-form').addEventListener('submit', function(event) {
    event.preventDefault();

    var formData = new FormData(event.target);
    var userDto = {
        userId: formData.get('userId'),
        password: formData.get('password'),
        nickname: formData.get('nickname')
    };

    fetch('/signUp', {
        method: 'POST',
        headers: {
            'Content-Type': 'application/json'
        },
        body: JSON.stringify(userDto)
    })
    .then(function(response) {
        if (response.ok) {
            alert('계정 생성 성공!');
            window.location.href = '/'; // or wherever you want to redirect
        } else {
            return response.text().then(function(message) {
                throw new Error(message);

            });
        }
    })
    .catch(function(error) {
        alert(error.message); // "중복된 id입니다." 메시지를 표시합니다.
<!--        alert("중복된 회원입니다"); // "중복된 id입니다." 메시지를 표시합니다.-->
    });
});
</script>

스크립트태그 안에서 fetch를 이용하여 post요청을 하도록 되어있다.

 

그럼 이제 컨트롤러에서 PostMapping해주면 되겠네. 하고 만들었는데?

    @PostMapping("/signUp")
    public String signUp(UserDto userDto){
        userService.addUser(userDto);
        return "redirect:/";
    }

(대략 이렇게 작성함)

뭐가..데이터가 비어있어서 회원엔티티를 만들수 없다는 에러메세지가 자꾸 뜬 것이다.

잘 입력했는데 왜그러지? 스크립트태그가 잘못써졌나? 

라고 생각했는데...

PostMapping하는 메소드에서 중요한걸 빼먹었다.

    @PostMapping("/signUp")
    public String signUp(@RequestBody UserDto userDto){
        userService.addUser(userDto);
        return "redirect:/";
    }

저기 userDto 파라미터 앞에 @RequestBody 를 빼먹었던 것이다. 이걸 붙이니까 잘 작동했다.

근데 저게 꼭 있어야했던건가? 라는 생각도 들었다. 왜냐면 최근에 내가 작성했던 코드들은 저걸 안적었었어서...

 

왜 안적었었지? 왜 안적었는데 잘 됐었던거지? 하고 찾아봤다.

 


1. @RequestBody를 안 적어놔도 잘 됐었던 것은...

{{>layouts/header}}

<form action="/forum/{{article.id}}/edit" method="post">
    <div class="mb-3">
        <label class="form-label">nickname</label>
        <input type="text" class="form-control w-25" name="nickname" placeholder="nickname" value="{{article.nickname}}" readonly>
    </div>
    <div class="mb-3">
        <label class="form-label">title</label>
        <input type="text" class="form-control" name="title" placeholder="title" value="{{article.title}}">
    </div>
    <div class="mb-3">
        <label class="form-label">content</label>
        <textarea class="form-control" name="content" rows="3" value="{{article.content}}"></textarea>
    </div>

    <button type="submit" class="btn btn-primary">save</button>
</form>


{{>layouts/footer}}

(DTO에는 nickname,title,content 속성이 있음)

 

이런 코드에서는 input들이 dto속성값과 일치하고, 폼데이터로 되어있어서 자동으로 DTO객체에 바인딩된다.

이 때는 @RequestBody가 없어도 되고, @ModelAttribute도 없어도 자동으로 됨.

 

근데,

2. @RequestBody가 필요한 경우

{{>layouts/header}}
<h2>회원가입</h2>
<form id="signup-form" >
    <div class="mb-3">
        <label class="form-label">userId</label>
        <input type="text" class="form-control w-50" name="userId" placeholder="id">
    </div>
    <div class="mb-3">
        <label class="form-label">userPassword</label>
        <input type="text" class="form-control" name="password" placeholder="password">
    </div>
    <div class="mb-3">
        <label class="form-label">nickName</label>
        <input type="text" class="form-control" name="nickname" placeholder="nickName">
    </div>

    <button type="submit" class="btn btn-primary">save</button>
</form>

{{>layouts/footer}}

<script>
document.getElementById('signup-form').addEventListener('submit', function(event) {
    event.preventDefault();

    var formData = new FormData(event.target);
    var userDto = {
        userId: formData.get('userId'),
        password: formData.get('password'),
        nickname: formData.get('nickname')
    };

    fetch('/signUp', {
        method: 'POST',
        headers: {
            'Content-Type': 'application/json'
        },
        body: JSON.stringify(userDto)
    })
    .then(function(response) {
        if (response.ok) {
            alert('계정 생성 성공!');
            window.location.href = '/'; // or wherever you want to redirect
        } else {
            return response.text().then(function(message) {
                throw new Error(message);

            });
        }
    })
    .catch(function(error) {
        alert(error.message); // "중복된 id입니다." 메시지를 표시합니다.
<!--        alert("중복된 회원입니다"); // "중복된 id입니다." 메시지를 표시합니다.-->
    });
});
</script>

여기서는 <form>안에 뭐라뭐라 적혀있긴 하지만, 결국에 form데이터로 전송하지 않고 fetch를 이용하여 JSON객체를 보낸다. 이렇게 JSON데이터로 보낼 때는 @RequestBody 어노테이션을 부착해야 Dto로 바인딩 할 수 있다.

 

728x90

댓글