[Springboot] 게시판 프로젝트-2

조히고닝·2023년 4월 3일
0

점프 투 스프링부트를 보고 게시판을 따라 만드는 프로젝트이다.

3-15의 추가기능을 모두 구현하는 것을 목표로 한다.

초보자라서 코드컨벤션이나 클린코드보다는 기능 구현을 목적으로 작성하였습니다.

Github : Joyfulgwon🕺

💡 생성해야 할 부분 : Comment 도메인. 컨트롤러, 서비스, 엔티티, 리포지토리, 검증을 하기 위한 댓글 폼

Untitled

개인적으로 세운 전제조건

  • 댓글은 질문이 아닌 답변에 달린다. 질문에는 이미 답변이 달릴 수 있으므로 댓글 필요없음.
  • 댓글은 수정과 삭제가 불가능하다. (이 부분은 나중에 추가해도 됨)

주의사항

  • 올바른 답변과 댓글이 매핑되어야 함

참고사항

  • Question에 Answer가 달리는 것과 마찬가지의 기능으로 구현하면 될 듯.
  • Answer 도메인의 코드들 대부분 복사붙여넣기로 구현가능

Comment

@Entity
@Getter
@Setter
public class Comment {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
    @Column(columnDefinition = "TEXT")
    private String content;

    private LocalDateTime createTime;
    @ManyToOne
    private SiteUser author;

    @ManyToOne
    private Answer answer;

}

id, 내용, 생성일자, 작성자를 가짐, answer와 매핑되어야 하므로 해당 answer도 가짐.

CommentController

@Controller
@RequestMapping("/comment")
@RequiredArgsConstructor
public class CommentController {
    private final QuestionService questionService;
    private final UserService userService;
    private final AnswerService answerService;
    private final CommentService commentService;
    @PreAuthorize("isAuthenticated()")
    @PostMapping("/create/{id}")
    public String createAnswer(Model model, @PathVariable("id") Integer id, @Valid CommentForm commentForm, BindingResult bindingResult, Principal principal, RedirectAttributes re) {
        SiteUser user = this.userService.getUser(principal.getName());
        Answer answer = this.answerService.getAnswer(id);
        Question question =answer.getQuestion();

        if (bindingResult.hasErrors()) {
            model.addAttribute("answer", answer);
            return "question_detail";
        }
        int page = question.getAnswerList().size() / 10;
        re.addAttribute("answerPage", page);
        Comment comment = this.commentService.create(answer,commentForm.getContent(),user);
        model.addAttribute("comment",comment);
        return String.format("redirect:/question/detail/%s#answer_%s", answer.getQuestion().getId(), answer.getId());
    }
}

작성자, 답변, 질문까지 각각의 도메인 서비스에 요청해서 받아옴.

댓글 달려도 질문 상세 페이지에 다시 연결되야 해서 질문까지 가져왔음.

CommentService

@Service
@RequiredArgsConstructor
public class CommentService {
    private final CommentRepository commentRepository;
    public Comment create(Answer answer, String content, SiteUser author) {
        Comment comment = new Comment();
        comment.setContent(content);
        comment.setAuthor(author);
        comment.setCreateTime(LocalDateTime.now());
        comment.setAnswer(answer);
        this.commentRepository.save(comment);
        return comment;
    }
}

객체 생성해서 필드에 값넣고 저장요청.

CommentRepository

스프링-데이터-JPA에게 모든걸 맡기고 구현 안함.

question_detail.html : 답변 작성 코드 가져다가 약간 수정

<!--            댓글작성, 댓글 표시-->
            <div class="mt-5 ">
                <form th:action="@{|/comment/create/${answer.id}|}" th:object="${commentForm}" method="post"
                      class="my-3">
                    <div th:replace="~{form_errors :: formErrorsFragment}"></div>
                    <textarea sec:authorize="isAnonymous()" disabled th:field="*{content}" placeholder="로그인을 먼저 해주세요"
                              class="form-control" rows="1"></textarea>
                    <textarea sec:authorize="isAuthenticated()" placeholder="댓글을 등록해주세요" th:field="*{content}"
                              class="form-control"
                              rows="1"></textarea>

                    <div class="text-end">
                        <input type="submit" value="댓글 등록" class="btn btn-primary my-2">
                    </div>
                </form>
            </div>
            <div class="card border-info">
                <div class="card-header bg-light" th:text="|${#lists.size(answer.commentList)}개의 댓글이 있습니다.|"></div>
                <div class="card" th:each="comment : ${answer.commentList}">
                    <div class="card-body d-flex justify-content-between">
                        <div class="card-text" th:text="${comment.content}"></div>
                        <div class=" d-flex flex-column bg-light">
                            <div th:text="${comment.author.username}"></div>
                            <div th:text="${#temporals.format(comment.createTime, 'yyyy-MM-dd HH:mm')}"></div>
                        </div>
                    </div>
                </div>
            </div>

검색조건에 댓글 추가 : QuestionService

private Specification<Question> search(String kw) {
        return new Specification<>() {
            private static final long serialVersionUID = 1L;
            @Override
            public Predicate toPredicate(Root<Question> q, CriteriaQuery<?> query, CriteriaBuilder cb) {
                query.distinct(true);  // 중복을 제거
                Join<Question, SiteUser> u1 = q.join("author", JoinType.LEFT);
                Join<Question, Answer> a = q.join("answerList", JoinType.LEFT);
                Join<Answer, SiteUser> u2 = a.join("author", JoinType.LEFT);
                Join<Answer,Comment> c = a.join("commentList", JoinType.LEFT);
                Join<Comment,SiteUser> u3 = c.join("author", JoinType.LEFT);
                return cb.or(cb.like(q.get("subject"), "%" + kw + "%"), // 제목
                        cb.like(q.get("content"), "%" + kw + "%"),      // 내용
                        cb.like(u1.get("username"), "%" + kw + "%"),    // 질문 작성자
                        cb.like(a.get("content"), "%" + kw + "%"),      // 답변 내용
                        cb.like(u2.get("username"), "%" + kw + "%"), //답변 작성자
                        cb.like(c.get("content"),"%"+kw+"%"), //댓글 내용
                        cb.like(u3.get("username"), "%" + kw + "%")); //댓글 작성자
            }
        };
    }

결과

댓글 내용이나 작성자를 기준으로 댓글을 검색 할 수 있게 되었음.

  • 나중에 검색창 필터적용 만들어야함

0개의 댓글