• 카테고리

    질문 & 답변
  • 세부 분야

    백엔드

  • 해결 여부

    미해결

한번만 질문 봐주십쇼..

24.04.10 22:07 작성 조회수 88

0

학습하는 분들께 도움이 되고, 더 좋은 답변을 드릴 수 있도록 질문전에 다음을 꼭 확인해주세요.

1. 강의 내용과 관련된 질문을 남겨주세요.
2. 인프런의 질문 게시판과 자주 하는 질문(링크)을 먼저 확인해주세요.
(자주 하는 질문 링크: https://bit.ly/3fX6ygx)
3. 질문 잘하기 메뉴얼(링크)을 먼저 읽어주세요.
(질문 잘하기 메뉴얼 링크: https://bit.ly/2UfeqCG)

질문 시에는 위 내용은 삭제하고 다음 내용을 남겨주세요.
=========================================
[질문 템플릿]
1. 강의 내용과 관련된 질문인가요? (예/아니오)
2. 인프런의 질문 게시판과 자주 하는 질문에 없는 내용인가요? (예/아니오)
3. 질문 잘하기 메뉴얼을 읽어보셨나요? (예/아니오)

[질문 내용]
여기에 질문 내용을 남겨주세요.

안녕하세요 검증 부분을 수강하고 프로젝트에 적용하는데 잘 모르겠는 부분이 생겨서 질문드립니다

@PostMapping("/blog/post")
public String addOrUpdate(@ModelAttribute RequestPost requestPost, BindingResult bindingResult, Model model){

    requestPostValidation.validate(requestPost,bindingResult);

    if(bindingResult.hasErrors()){
        System.out.println(bindingResult);
        model.addAttribute("post",requestPost);
        return "addOrUpdate";
    }

    if(requestPost.getId()==null){
        postService.savePost(requestPost.toPost());
        return "redirect:/blog";
    }
    else{
        postService.updatePost(requestPost);
        ResponsePost post = new ResponsePost(postService.findById(requestPost.getId()));
        model.addAttribute("post",post);
        return "redirect:/blog/post/"+post.getId();
    }
}

이게 컨트롤러부분이고

@Component
public class RequestPostValidation implements Validator {
    @Override
    public boolean supports(Class<?> clazz) {
        return RequestPost.class.isAssignableFrom(clazz);
    }

    @Override
    public void validate(Object target, Errors errors) {
        RequestPost requestPost = (RequestPost)target;

        if(!StringUtils.hasText(requestPost.getTitle())){
            errors.rejectValue("title","noTitle");
        }
        if(!StringUtils.hasText(requestPost.getContent())){
            errors.rejectValue("content","noContent");
        }
    }
}

이게 검증하는 클래스입니다

noTitle.requestPost.title=제목은 필수입니다.
noContent.requestPost.content=내용은 필수입니다.

에러 메시지는 이렇게 만들어 줬구요

<form action="/blog/post" method="POST" th:object="${post}">
    <input type="text" th:value="${post.id}" name="id" style="visibility: hidden;">
    <h3>제목</h3>
    <input th:if="${post.id==null}" type="text" placeholder="제목 입력하시오" th:value="${post.title}" name="title">
    <input th:if="${post.id!=null}" type="text" th:value="${post.title}" name="title">
    <div th:errors="*{title}">
        제목 오류
    </div>
    <h3>내용</h3>
    <textarea th:if="${post.id==null}" placeholder="내용 입력하시오" th:text="${post.content}" name="content"></textarea>
    <textarea th:if="${post.id!=null}" th:text="${post.content}" name="content"></textarea>
    <div th:errors="*{content}">
        내용 오류
    </div>
    <br>
    <div class="center">
        <input th:if="${post.id==null}" type="submit" value="등록">
        <input th:if="${post.id!=null}" type="submit" value="수정">
        <input th:if="${post.id==null}" type="button" th:onclick="|location.href='@{/blog}'|" value="취소">
        <input th:if="${post.id!=null}" type="button" th:onclick="|location.href='@{/blog/post/{id}(id=${post.id})}'|" value="취소">
    </div>
</form>

 

이게 뷰 부분입니다

1.컨트롤러에서 @ModelAttribute RequestPost requestPost 를 통해서 form 정보를 받는데 @ModelAttribute니까 Model에 requestPost 객체가 저장된다고 알고 있습니다

 

2.그런데 뷰 에서 form이 th:object="${post}"로 되어있어서 model.addAttribute("post",requestPost)로 post이름으로 requestPost 객체를 넣었습니다

 

3.그럼 제 생각에는 Model에 post이름으로 requestPost 객체가 있으니까 th:object="${post}" 매핑되어서 th:errors="*{title}" 를 통해 title필드가 문제가 있으면 오류메시지가 출력될거라 생각했는데 안됩니다.

 

4.여러가지를 시도를 해봤는데 model.addAttribute("post",requestPost) 를 하지 않고 @ModelAttribute("post")RequestPost requestPost 를 하고 메시지를 noTitle.post.title=제목은 필수입니다. 로 바꾸니까 그제서야 출력이 되더라고요

 

5.이게 BindingResult랑 Model에 저장된 객체의 이름이 달라서 이런 일이 발생하는 건가요? 제 생각으로는 model.addAttribute("post",requestPost) 하면 Model에 이름이 post로 저장이 되서 th:object="${post}"랑 매핑은 되는데 th:errors="*{title}"이거는 post 이름으로 BindingResult에서 객체이름을 찾는데 제가 올린코드에서는 requestPost로 저장되어 있어서 못찾는 건가요?

 

질문을 깔끔하게 하려고 여러번 지웠다 썻다 하는데도 난잡해서 죄송합니다.

 

제일 궁금한건 컨트롤러에서 @ModelAttribute RequestPost requestPost,BindingResult bindingResult 이렇게 인자를 받고 model.addAttribute("post",requestPost) 해서 뷰로 넘겼을때 th:object="${post}"를 하면 post이름으로 객체를 찾아서 requestPost랑 매핑은 되는데 th:errors="*{title}"를 통해서 오류를 검사할때는 BindingResult에서 post이름으로 객체를 찾아서 오류 출력하는데 현재 BindingResult에는 requestPost로 객체이름이 저장되어 있으니까 출력하지 못하는 걸까요?

 

한번만 봐주시면 감사하겠습니다..

답변 2

·

답변을 작성해보세요.

0

안녕하세요. 김민재님

@ModelAttribute RequestPost requestPost와 같이 이름을 생략해서 작성하면 requestPost라는 이름으로 모든 것이 매핑됩니다. (첫글자는 소문자)

따라서 오류가 제대로 출력되지 않습니다.

감사합니다.

0

인프런 AI 인턴님의 프로필

인프런 AI 인턴

2024.04.10

안녕하세요, 인프런 AI 인턴입니다. 김민재님.

관련하여 질문자님이 겪고 계시는 문제에 대해 비슷한 상황을 경험한 다른 학습자의 질문과 해당 질문에 대한 답변 내용을 찾았습니다.

  • th:object, @ModelAttribute 관련 질문에서는 th:object@ModelAttribute 사이의 관계와 이름을 명시적으로 지정하는 방법에 대해 설명되어 있습니다. @ModelAttribute("post") RequestPost requestPost 사용 시 post라는 이름으로 모델에 객체가 저장되며, 뷰에서는 th:object를 사용해 이 객체를 참조한다는 내용입니다. 학습자가 질문한 상황과 유사한 부분에서 도움을 줄 수 있을 것 같으니 내용을 확인하면 도움이 될 것입니다.

이와 관련하여 핵심 포인트는 @ModelAttribute에 명시적으로 객체의 이름을 지정하는 것과 이 이름을 뷰에서 th:object로 참조하여 사용하는 것이 중요합니다. 이렇게 해서 BindingResult와 연결된 객체를 제대로 관리할 수 있게 됩니다. th:errors가 제대로 동작하기 위해서는 BindingResult가 참조하는 객체와 th:object를 통해 참조하는 객체가 동일해야 합니다.

다만, 귀하의 상황과 완벽히 일치하는 예시나 케이스를 보장할 수는 없으며, 제공된 링크와 설명을 참조하여 상황에 맞게 적용해 보시기 바랍니다.

저는 질문자님의 이해를 돕고자 지식공유자님의 기존 답변을 참고하여 유사한 답변 링크를 추천해드리고 있습니다.
현재 베타 기능으로 답변이 만족스럽지 않을 수 있는 점 양해 부탁드립니다. 🙏
추가적으로 궁금한 점이 있으시면, 이어서 질문해 주세요. 곧 지식공유자께서 답변해 주실 것입니다.