Notice
Recent Posts
Recent Comments
Link
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
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 |
Tags
- transaction
- springdatajpa
- http
- Android
- Servlet
- 스프링
- 자바
- db
- JPQL
- 스프링 핵심 원리
- Thymeleaf
- spring
- 백준
- Spring Boot
- 알고리즘
- jpa
- Greedy
- QueryDSL
- JDBC
- 스프링 핵심 기능
- SpringBoot
- 김영한
- java
- kotlin
- 그리디
- Exception
- Proxy
- pointcut
- 인프런
- AOP
Archives
- Today
- Total
개발자되기 프로젝트
댓글기능 오류 수정, @ModelAttribute 실패 본문
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
'Project > 블로그 게시판 만들기' 카테고리의 다른 글
Test용 데이터 추가 (0) | 2021.10.07 |
---|---|
현재까지 진행 상황 (0) | 2021.10.06 |
댓글 기능 추가 (0) | 2021.10.06 |
글 삭제하기 (0) | 2021.10.05 |
home 버튼 추가 (0) | 2021.10.05 |
Comments