ReplyController
package com.tenco.blog_v3.reply;
import com.tenco.blog_v3.user.User;
import jakarta.servlet.http.HttpSession;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
@RequiredArgsConstructor
@Controller
public class ReplyController {
private final ReplyService replyService;
private final HttpSession session;
// 댓글 생성 기능 만들기
@PostMapping("/api/replies")
public String save(ReplyDTO.SaveDTO reqDTO) {
// 로그인 여부 확인
User sessionUser = (User) session.getAttribute("sessionUser");
if(sessionUser == null) {
return "redirect:/login-form";
}
replyService.saveReply(reqDTO, sessionUser);
return "redirect:/board/"+ reqDTO.getBoardId();
}
// 댓글 삭제
@DeleteMapping("/api/replies/{id}")
public String delete(@PathVariable(name = "boardId") Integer boardId, @PathVariable(name = "replyId") Integer replyId) {
// 삭제도 권한 확인
User sessionUser = (User) session.getAttribute("sessionUser");
if(sessionUser == null) {
return "redirect:/login-from";
}
replyService.deleteReply(replyId, sessionUser.getId(), boardId);
return "redirect:/board/" + boardId;
}
}
Reply
package com.tenco.blog_v3.reply;
import com.tenco.blog_v3.board.Board;
import com.tenco.blog_v3.user.User;
import jakarta.persistence.*;
import lombok.*;
import org.hibernate.annotations.CreationTimestamp;
import java.time.LocalDateTime;
@Getter
@Setter
@NoArgsConstructor
@AllArgsConstructor
@Builder
@Entity
@Table(name = "reply_tb")
@ToString(exclude = {"user", "board"}) // 연관된 엔티티를 제외하여 순환 참조 방지 및 보안 강화 때문에 사용한다.
public class Reply {
// 일반적으로 id는 Long 타입을 사용하는 것을 권장한다.
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer id;
// null 값이 들어올 수 없어! - 기본 값을 null 허용
@Column(nullable = false)
private String comment;
// 단방향 관계 설계 -> User 엔티티에는 Reply 정보가 없다!!!
@ManyToOne(fetch = FetchType.LAZY) // 지연 로딩
@JoinColumn(name = "user_id")
private User user;
// 양방향 매핑 (FK 주인은 댓글(Reply 이다)
@ManyToOne(fetch = FetchType.LAZY) // 지연 로딩
@JoinColumn(name = "board_id")
private Board board;
// JPA 엔티티에서 데이터베이스에 저장할 필요가 없는 필드를 정의할 때 사용한다.
@Transient
private boolean isReplyOwner;
@Builder.Default
private String status = "ACTIVE"; // 댓글 상태 (ACTIVE, DELETED)
@CreationTimestamp // 엔티티가 생성될 때 자동으로 현재 시간으로 설정
@Column(name = "created_at")
private LocalDateTime createdAt;
/**
* 엔티티가 데이터베이스에 영속화 되기 전에 호출 되는 메서드가 있다면 사용한다.
* @PrePersist 어노테이션은 JPA 라이프 사이클 이벤트 중 하나로 엔티가 영속화 되기전에 실행 된다.
*/
@PrePersist
protected void onCreate() {
if(this.status == null) {
this.status = "ACTIVE";
}
if (this.createdAt == null) {
this.createdAt = LocalDateTime.now();
}
}
}
ReplyDTO
package com.tenco.blog_v3.reply;
import com.tenco.blog_v3.board.Board;
import com.tenco.blog_v3.user.User;
import lombok.Getter;
import lombok.Setter;
public class ReplyDTO {
@Getter
@Setter
public static class SaveDTO {
private Integer boardId;
private String comment;
// DTO --> JPA 영속성 컨텍스트로 저장 한다.. 엔티티로 변환 해야 한다.
public Reply toEntity(User sessionUser, Board board) {
return Reply.builder()
.comment(comment)
.board(board)
.user(sessionUser)
.build();
}
}
}
ReplyJPARepository
package com.tenco.blog_v3.reply;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.query.Param;
import java.util.List;
// 어노테이션 생략 가능 -> IoC 처리 됨
public interface ReplyJPARepository extends JpaRepository<Reply, Integer> {
// 기본적인 주요 메서드 제공 받음 (구현체를 만들어 준다)
// 1. 커스텀 쿼리를 만들어 본다. 어노테이션 사용
// boardId 를 통해서 리플정보를 조회하는 기능
@Query("select r from Reply r where r.board.id = :boardId")
List<Reply> findByBoardId(@Param("boardId") Integer boardId); // 알아서 메서드의 바디를 만들어 준다.
}
ReplyService
'Spring boot' 카테고리의 다른 글
JWT 인터셉터 적용 (1) | 2024.11.07 |
---|---|
JDBC란 뭘까? - 1 (1) | 2024.11.07 |
JwtUtil 만들어 보기 (3) | 2024.11.06 |
JWT란 뭘까? (0) | 2024.11.06 |
RestAPI 컨트롤러 요청과 응답 (0) | 2024.11.06 |