[Java+SpringBoot+JPA] 테이블 조인을 활용한 댓글 기능+좋아요/싫어요(2)
2024. 1. 11. 22:52ㆍPratice/CRUD
반응형
🟢 CommentEntity
▪️ FetchType : 연관 엔티티를 어떻게 가져올 것인지를 지정
▪️ FetchType.LAZY : 연관 엔티티가 필요할 때 로딩
(즉, 처음에는 연관 엔티티를 가져오지 않고, 실제로 엔티티에 접근할 때 가져옴)
@Entity
@Getter @Setter @ToString @Builder
@AllArgsConstructor @NoArgsConstructor
@Table(name = "comment")
@SequenceGenerator(
name = "comment_SEQ",
sequenceName = "comment_SEQ",
initialValue = 1,
allocationSize = 1)
public class CommentEntity extends BaseEntity{
@Id
@GeneratedValue (strategy = GenerationType.SEQUENCE, generator = "comment_SEQ")
@Column(name = "commentId")
private Integer commentId; //댓글번호
@Lob
@Column(name = "comment", nullable = false, length = 500)
private String comment; //댓글내용
@ColumnDefault("0")
@Column(name = "goodcnt")
private int goodcnt; //좋아요
@ColumnDefault("0")
@Column(name = "badcnt")
private int badcnt; //싫어요
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "sid")
private StudyEntity studyEntity; //게시글 조인 (수강과목)
}
🟢 CommentDTO
외래키 변수로 선언
@Getter
@Setter
@Builder
@AllArgsConstructor
@NoArgsConstructor
public class CommentDTO extends BaseEntity {
private Integer commentId; //번호
@NotEmpty (message = "내용은 필수 입력입니다.")
private String comment; //댓글내용
private int goodcnt; //좋아요
private int badcnt; //싫어요
private LocalDate credate; //등록날짜
private LocalDateTime modidate; //수정날짜
private int sid; //게시글 번호(외래키)
}
🟢 CommentRepository
▪️ 부모테이블에 해당하는 레코드 조회
▪️ sid에 해당하는 댓글을 역순 정렬 (commentid 기준)
@Repository
public interface CommentRepositroty extends JpaRepository <CommentEntity, Integer> {
//부모테이블에 해당하는 레코드 조회
@Query("SELECT u FROM CommentEntity u WHERE u.studyEntity.sid=:sid")
List<CommentEntity> findByStudyId (Integer sid);
//댓글 정렬 기준
@Query("SELECT u FROM CommentEntity u WHERE u.studyEntity.sid = :sid ORDER BY u.commentId DESC")
List<CommentEntity> findByStudyIdOrderByCommentIdDesc(Integer sid);
}
▪️ 좋아요, 싫어요 기능
//좋아요
@Modifying
@Query("UPDATE CommentEntity u SET u.goodcnt=u.goodcnt+1 WHERE u.commentId =:commentId")
void goodcnt (@Param("commentId") Integer commentId);
//싫어요
@Modifying
@Query("UPDATE CommentEntity u SET u.badcnt=u.badcnt+1 WHERE u.commentId =:commentId")
void badcnt (@Param("commentId") Integer commentId);
🟢 CommentService
▪️ 댓글 등록/목록 : 부모테이블의 레코드 번호 조회
▪️ 댓글 좋아요/싫어요/삭제 : 댓글 번호 조회
▪️ 댓글 등록 번호 기준 역순 정렬
@Service
@Transactional
@RequiredArgsConstructor
public class CommentService {
private final StudyRepository studyRepository;
private final CommentRepositroty commentRepositroty;
private final ModelMapper modelMapper = new ModelMapper();
//댓글 등록
//부모테이블의 레코드 번호 필요 (Intger sid)
public CommentEntity insert(Integer sid, CommentDTO commentDTO) throws Exception {
//부모테이블에서 해당 레코드 조회
Optional<StudyEntity> data = studyRepository.findById(sid);
StudyEntity result = data.orElseThrow();
//댓글 등록
//DTO로 받아서 Entity로 변환 후, 전달
CommentEntity commentEntity = modelMapper.map(commentDTO, CommentEntity.class);
//부모 레코드 정보 추가
commentEntity.setStudyEntity(result);
//댓글 저장
commentRepositroty.save(commentEntity);
return commentEntity;
}
//댓글 목록
public List<CommentDTO> list(Integer sid) throws Exception {
List<CommentEntity> commentEntityList = commentRepositroty.findByStudyIdOrderByCommentIdDesc(sid);
List<CommentDTO> commentDTOS = commentEntityList.stream()
.map(commentEntity -> modelMapper.map(commentEntity, CommentDTO.class))
.collect(Collectors.toList());
return commentDTOS;
}
//좋아요
public void goodCnt(Integer commentId) throws Exception {
commentRepositroty.goodcnt(commentId);
}
//싫어요
public void badCnt(Integer commentId) throws Exception {
commentRepositroty.badcnt(commentId);
}
//삭제
public void delete(Integer commentId) throws Exception {
commentRepositroty.deleteById(commentId);
}
}
🟢 CommentController
▪️ StudyController 상세페이지조회 메서드에 댓글 관련 내용 추가
▪️ 댓글등록 할 때, 부모테이블의 Id 필요 / RedirectAttributes로 리다이렉트 해주기
▪️ 댓글 좋아요/싫어요/삭제 할 때는 댓글번호(commentId)도 필요
더보기
//상세 폼
@GetMapping("/studydetail")
public String detailForm(int sid, Model model) throws Exception {
//게시글 불러 오기
StudyDTO studyDTO = studyService.findOne(sid);
//댓글 불러오기
List<CommentDTO> commentDTOS = commentService.list(sid);
//전달
model.addAttribute("studyDTO", studyDTO);
model.addAttribute("commentDTOS", commentDTOS);
return "/study/detail";
}
@Controller
@RequiredArgsConstructor
public class CommentController {
private final CommentService commentService;
//댓글등록
//수강과목의 id필요
@PostMapping("/commentinsert")
public String insertForm(int sid, CommentDTO commentDTO, RedirectAttributes redirectAttributes, Model model) throws Exception {
commentService.insert(sid, commentDTO);
//studydetail 엔드포인트로 id 매개변수를 사용하여 리다이렉트
redirectAttributes.addAttribute("sid", sid);
return "redirect:/studydetail";
}
//좋아요
@GetMapping("/commentgoodcnt")
public String goodcntProc(int sid, Integer commentId, RedirectAttributes redirectAttributes) throws Exception {
commentService.goodCnt(commentId);
redirectAttributes.addAttribute("sid", sid);
return "redirect:/studydetail";
}
//싫어요
@GetMapping("/commentbadcnt")
public String badcnt(int sid, Integer commentId, RedirectAttributes redirectAttributes) throws Exception {
commentService.badCnt(commentId);
redirectAttributes.addAttribute("sid", sid);
return "redirect:/studydetail";
}
//삭제 폼
@GetMapping("/commentdelete")
public String deleteForm(int sid, Integer commentId, RedirectAttributes redirectAttributes) throws Exception {
commentService.delete(commentId);
redirectAttributes.addAttribute("sid", sid);
return "redirect:/studydetail";
}
}
🟢 detail.html
▪️ 댓글 등록을 위해서는 hidden으로 부모테이블 레코드 조회
▪️ 좋아요/싫어요 수 0으로 초기화
▪️ 좋아요/싫어요/삭제를 위해서는 댓글, 부모레코드 id 필요
<!-- 댓글 영역 시작 -->
<div class="card mt-3 mb-3">
<div class="card-header">댓글</div>
<div class="card-body">
<div class="card-body">
<form th:action="@{/commentinsert}" method="post">
<input type="hidden" name="sid" th:value="${studyDTO.sid}">
<div class="mb-1 mt-1">
<textarea class="form-control" rows="3" id="comment" name="comment"></textarea>
</div>
<input type="hidden" name="goodcnt" value="0">
<input type="hidden" name="badcnt" value="0">
<button type="submit" class="btn btn-primary mt-1">댓글 등록</button>
</form>
</div>
</div>
<div class="card-footer">
<div class="card mt-2 mb-2" th:each="data:${commentDTOS}">
<div class="card-header">
작성일 : <span th:text="${#temporals.format(data.credate, 'yyyy-MM-dd')}"></span><br>
<a th:href="@{/commentgoodcnt(sid=${studyDTO.sid}, commentId=${data.commentId})}">좋아요</a> : <span th:text="${data.goodcnt}"></span>
<a th:href="@{/commentbadcnt(sid=${studyDTO.sid}, commentId=${data.commentId})}">싫어요</a> : <span th:text="${data.badcnt}"></span>
</div>
<div class="card-body"><span th:text="${data.comment}"></span></div>
<div class="card-footer">
<button type="button" class="btn btn-primary" >수정</button>
<button type="button" class="btn btn-danger" th:onclick="|location.href='@{/commentdelete(sid=${studyDTO.sid}, commentId=${data.commentId})}'|">삭제</button>
</div>
</div>
</div>
</div>
<!-- 댓글 영역 끝 -->
반응형
'Pratice > CRUD' 카테고리의 다른 글
[Java+SpringBoot+JPA] 테이블 조인 / 댓글 수정 기능 (0) | 2024.01.12 |
---|---|
[Java+SpringBoot+JPA] 테이블 조인을 활용한 댓글 기능(1) (1) | 2024.01.11 |
[Java+SpringBoot+JPA] 이미지 삽입을 활용한 게시판 만들기 (1) | 2024.01.09 |
[Java+SpringBoot+JPA] To do List 게시판 만들기 (시작일/마감일 설정) (1) | 2024.01.09 |
[Java+SpringBoot+JPA] 기본 CRUD 구현하기 (6) 조회수 증가 기능 (0) | 2024.01.02 |