Notice
Recent Posts
Recent Comments
Link
«   2024/12   »
1 2 3 4 5 6 7
8 9 10 11 12 13 14
15 16 17 18 19 20 21
22 23 24 25 26 27 28
29 30 31
Archives
Today
Total
관리 메뉴

개발자되기 프로젝트

댓글기능 오류 수정, @ModelAttribute 실패 본문

Project/블로그 게시판 만들기

댓글기능 오류 수정, @ModelAttribute 실패

Seung__ 2021. 10. 6. 22:22

1. 현상


현재 댓글을 저장하면 Server로 바인딩이 되지 않는다.

2021-10-06 20:20:21.581 DEBUG 31980 --- [nio-8080-exec-1] org.hibernate.SQL                        : 
    insert 
    into
        comment
        (content, member_id, parent_id, post_id, comment_id) 
    values
        (?, ?, ?, ?, ?)
2021-10-06 20:20:21.585  INFO 31980 --- [nio-8080-exec-1] p6spy                                    : #1633519221585 | took 2ms | statement | connection 13| url jdbc:h2:tcp://localhost/~/blog
insert into comment (content, member_id, parent_id, post_id, comment_id) values (?, ?, ?, ?, ?)
insert into comment (content, member_id, parent_id, post_id, comment_id) values (NULL, 1, NULL, 2, 4);

 

 

2. 원인 분석


  • Controller어느 부분에너 문제가 발생하는지 확인해 보자.
  • controller에 들어와서 addComment()가 실행된 직후 log를 찍어보자.
@Controller
@Slf4j
@RequiredArgsConstructor
@RequestMapping("/comments")
public class CommentController {

    private final CommentService commentService;
    private final SessionManager sessionManager;
    private final MemberService memberService;
    private final PostService postService;

    @PostMapping("/new")
    public String addComment(@RequestParam("postId") Long postId, @ModelAttribute("comment") CommentDto commentDto,
                             HttpServletRequest request, RedirectAttributes redirectAttributes){

        log.info("Comment Controller 시작.");
        log.info("commentDto:{}", commentDto.toString());
        log.info("commentDto content:{}", commentDto.getContent());

        MemberDto memberDto = (MemberDto) sessionManager.getSession(request);
        Member member = memberService.findMemberById(memberDto.getId());
        Post post = postService.findPostById(postId);

        Comment comment = dtoToComment(commentDto);
        comment.setMember(member);
        comment.setPost(post);

        commentService.saveComment(comment);
        redirectAttributes.addAttribute("postId", postId);
        return "redirect:/posts/{postId}";
    }

    public Comment dtoToComment(CommentDto commentDto){
        return new Comment(commentDto.getContent());
    }
}
  • 여기서 getContent()가 null이면 애초에 바인딩이 안되는 것.
2021-10-06 20:35:56.079  INFO 20980 --- [nio-8080-exec-6] hello.blog.web.CommentController
: Comment Controller 시작.

2021-10-06 20:35:56.079  INFO 20980 --- [nio-8080-exec-6] hello.blog.web.CommentController 
: commentDto:hello.blog.web.dto.CommentDto@140fb076

2021-10-06 20:35:56.079  INFO 20980 --- [nio-8080-exec-6] hello.blog.web.CommentController 
: commentDto:null
  • ㅎㅎㅎㅎㅎnull이다 
  • 그런데 요청을 보내면 data는 요청 메시지에 담겨서 넘어간다..흠..

 

 

3. 객체가 아니라 String으로 직접 받아보자.


  • 기존에는 Controller에서 객체를 넘겨서 th:object="${commentDto}"를 활용했다.
  • input에는 th:field="*{content}" 를 활용했다. 
  • 이번에는 String으로 직접 받아보자! name=""에 입력한 값을  가지고 field와 바인딩 할 수 있다.
<form action="post.html" th:action="@{/comments/new?postId={id}(id=${post.id})}" th:object="${commentDto}" method="post">
    <div class="form-group">
        <label for="commentString" class="form-label">댓글</label>
        <input type="text" class="form-control" name="commentString" id="commentString" placeholder="댓글을 입력">
    </div>
    <button type="submit" class="btn btn-primary" >Submit</button>

</form>
  • Controller에서는 @RequestParam("name") 을 통해 받으면 된다.
    @PostMapping("/new")
    public String addComment(@RequestParam("postId") Long postId, @RequestParam("commentString") String commentString,
                             HttpServletRequest request, RedirectAttributes redirectAttributes){

        log.info("Comment Controller 시작.");
        log.info("commentString: {}", commentString);
        //log.info("commentDto:{}", commentDto.toString());
        //log.info("commentDto content:{}", commentDto.getContent());

        MemberDto memberDto = (MemberDto) sessionManager.getSession(request);
        Member member = memberService.findMemberById(memberDto.getId());
        Post post = postService.findPostById(postId);

        //Comment comment = dtoToComment(commentDto);
        Comment comment= new Comment(commentString);
        comment.setMember(member);
        comment.setPost(post);

        commentService.saveComment(comment);
        redirectAttributes.addAttribute("postId", postId);
        return "redirect:/posts/{postId}";
    }

 

 

4. 결과


  • view에서도 데이터가 잘 넘어갔고, 화면에 출력도 된다.

  • log를 통해서도 controller에 넘어온 값을 확인할 수 있다.
2021-10-06 21:04:25.968  INFO 30900 --- [nio-8080-exec-3] hello.blog.web.CommentController
: Comment Controller 시작.
2021-10-06 21:04:25.968  INFO 30900 --- [nio-8080-exec-3] hello.blog.web.CommentController
: commentString: 123
  • DB에도 댓글이 저장된 것을 확인할 수 있다.

 

 

5. 원인분석.


data를 바인딩 하는 방식을 바꿨더니 문제가 해결되었다.

 

그러면 기존 방식에는 어떤 문제가 있어서 적용이 안됐을까?

 

파라미터만 변경했더니 성공한 것으로 봐선 logic에는 문제가 없다.

 

@ModelAttribute는 댓글 말고도 회원가입, 게시글 작성에서도 활용했다. 

 

@ModelAttribute를 사용하는 방식은 동일햇다.

 

controller에서 빈 객체를 보내고 HTML form에서 th:object를 활용햇다.

 

이때 view에서 submit을 하면 th:field로 지정한 이름으로 httpMessageBody에 data를 넘긴다

(여기까지는 정상적으로 진행되었다.)

 

controller에서는 @ModelAttribute("name")으로 data를 받고 name와 객체의 필드명을 매핑하여 객체로 만든다.

(여기서 실패했다)

 

BindingResult를 사용해서 어떤 문제가 있었는지 확인해보자.

 

    @PostMapping("/new")
    public String addComment(@RequestParam("postId") Long postId, @ModelAttribute("commentDto") CommentDto commentDto, BindingResult bindingResult,
                             HttpServletRequest request, RedirectAttributes redirectAttributes){

        if(bindingResult.hasErrors()){
            bindingResult.getAllErrors().forEach(System.out::println);
        }
        log.info("Comment Controller 시작.");
        log.info("bindingResult: {}", bindingResult.toString());
2021-10-06 21:36:10.756  INFO 35456 --- [nio-8080-exec-3] hello.blog.web.CommentController
: Comment Controller 시작.

2021-10-06 21:36:10.757  INFO 35456 --- [nio-8080-exec-3] hello.blog.web.CommentController
: bindingResult: org.springframework.validation.BeanPropertyBindingResult: 0 errors

2021-10-06 21:36:10.757  INFO 35456 --- [nio-8080-exec-3] hello.blog.web.CommentController
: commentDto:hello.blog.web.dto.CommentDto@6e18cb81

2021-10-06 21:36:10.757  INFO 35456 --- [nio-8080-exec-3] hello.blog.web.CommentController
: commentDto content:null
  • 음... 에러가 없다.. 왜??
  • th:field를 잘못 지정한 것도 아니다..
<form action="post.html" th:action="@{/comments/new?postId={id}(id=${post.id})}" th:object="${commentDto}" method="post">
    <div class="form-group">
        <label for="commentString" class="form-label">댓글</label>
        <input type="text" class="form-control" th:field="*{content}" name="commentString" id="commentString" placeholder="댓글을 입력">
    </div>
    <button type="submit" class="btn btn-primary" >Submit</button>

</form>
@Getter
public class CommentDto {

    private Long id;
    private String content;
    private MemberDto member;
    private Long postId;
  • 그렇다면 data는 가지고 오나, CommentDto객체에 set을 못하는건가??
  • CommentDto에 Setter가 없는데.. 이때문인듯..?
  • 생성자는 기본생성자, allArgsConstructor가 있는데, 개별 setter가 필요한가 보다.
@Getter
@Setter
public class CommentDto {

    private Long id;
    private String content;
    private MemberDto member;
    private Long postId;
  • 어.. 된다. ㅋㅋㅋㅋㅋㅋ

  • 그렇다면 파라미터로 받을 content만 setter를 만들어 보자.
  • 잘된다/.

 

6. @ModelAttribute 바인딩 실패 원인!


  • Binding할 객체에 해당 파라미터의 Setter가 없었음!!!
  • 이 경우에는 html Form에서 commentDto.content가 넘어오는데, CommentDto의 content의 setter가 없어서.
  • @ModelAttribute에서 처리하지 못했따.zzzz

 

7. GitHub: 211006 Comment fix


 

GitHub - bsh6463/blog

Contribute to bsh6463/blog development by creating an account on GitHub.

github.com

 

'Project > 블로그 게시판 만들기' 카테고리의 다른 글

Test용 데이터 추가  (0) 2021.10.07
현재까지 진행 상황  (0) 2021.10.06
댓글 기능 추가  (0) 2021.10.06
글 삭제하기  (0) 2021.10.05
home 버튼 추가  (0) 2021.10.05
Comments