댓글 테이블 생성
create table tb_comment (
id bigint not null auto_increment comment '댓글 번호 (PK)'
, post_id bigint not null comment '게시글 번호 (FK)'
, content varchar(1000) not null comment '내용'
, writer varchar(20) not null comment '작성자'
, delete_yn tinyint(1) not null comment '삭제 여부'
, created_date datetime not null default CURRENT_TIMESTAMP comment '생성일시'
, modified_date datetime comment '최종 수정일시'
, primary key(id)
) comment '댓글';
제약 조건 생성
게시글 tb_post과 댓글 tb_comment 은 각각 1:n의 관계까 되어야 하며, 관계를 매핑해주기 위해 FK 제약조건을 추가해준다
alter table tb_comment add constraint fk_post_comment foreign key(post_id) references tb_post(id);
테이블 구조 확인
show full columns from tb_comment; -- 테이블 구조 확인 1 (코멘트 포함)
desc tb_comment; -- 테이블 구조 확인 2
제약 조건 조회
select *
from information_schema.table_constraints
where table_name = 'tb_comment';
- 댓글 요청 클래스 생성
댓글 생성과 수정에 사용할 요청 클래스 생성. 댓글도 게시글과 마찬가지로 request와 response용 클래스를 분리해서 데이터를 처리함
package com.study.domain.comment;
import lombok.AccessLevel;
import lombok.Getter;
import lombok.NoArgsConstructor;
@Getter
@NoArgsConstructor(access = AccessLevel.PROTECTED)
public class CommentRequest {
private Long id; // 댓글 번호 (PK)
private Long postId; // 게시글 번호 (FK)
private String content; // 내용
private String writer; // 작성자
}
@Getter: 롬복이 제공하는 기능, 클래스의 모든 멤버 변수에 대한 get()메서드를 만들어준다
@NOArgsConstructor (access = AccessLevel.PROTECTED) : 클래스의 기본 생성자를 만들어준다. access 속성을 이용해 객체 생성을 protected로 제한한다.
- 댓글 응답 response 클래스 생성하기
package com.study.domain.comment;
import lombok.Getter;
import java.time.LocalDateTime;
@Getter
public class CommentResponse {
private Long id; // 댓글 번호 (PK)
private Long postId; // 게시글 번호 (FK)
private String content; // 내용
private String writer; // 작성자
private Boolean deleteYn; // 삭제 여부
private LocalDateTime createdDate; // 생성일시
private LocalDateTime modifiedDate; // 최종 수정일시
}
- 댓글 Mapper 인터페이스 생성하기
package com.study.domain.comment;
import org.apache.ibatis.annotations.Mapper;
import java.util.List;
@Mapper
public interface CommentMapper {
/**
* 댓글 저장
* @param params - 댓글 정보
*/
void save(CommentRequest params);
/**
* 댓글 상세정보 조회
* @param id - PK
* @return 댓글 상세정보
*/
CommentResponse findById(Long id);
/**
* 댓글 수정
* @param params - 댓글 정보
*/
void update(CommentRequest params);
/**
* 댓글 삭제
* @param id - PK
*/
void deleteById(Long id);
/**
* 댓글 리스트 조회
* @param params - search conditions
* @return 댓글 리스트
*/
List<CommentResponse> findAll(CommentSearchDto params);
/**
* 댓글 수 카운팅
* @param params - search conditions
* @return 댓글 수
*/
int count(CommentSearchDto params);
}
@Mapper : 해당 인터페이스가 db와 통신하는 인터페이스임을 의미. mapper인터페이스는 xml mapper에서 메서드명과 동일한 id를 가진 sql쿼리를 찾아 실행한다.
save() : 댓글을 생성하는 insert 쿼리를 호출한다. 파라미터로 전달받는params에 저장할 댓글 정보가 담긴다
findById() : id(pk) 를 기준으로 특정 댓글의 상세 정보를 조회하는 select 쿼리를 호출한다. 쿼리가 실행되면 응답 xomment response 클래스 객체의 각 멤버 변수에 결괏값이 매핑된다
update() : 댓글을 수정하는update 쿼리를 호출한다. save() 와 마찬가지로 요청 클래스의 객체를 이용해 댓글 정보를 업데이트 한다.
deleteById() : id(pk)를 기준으로 특정 댓글을 삭제하는 update쿼리를 호출한다. 테이블에서 실제로 데이터를 delete하지 않고 삭제 여부 칼럼의 상태 값을 0 에서 1로 업데이트 한다.
findAll(0 : 게시글 번호 post id 를 기준으로 특정 게시글에 등록된 댓글 목록을 조회하는 select 쿼리를 호출한다.
count(): 게시글 번호post_ id 를 기준으로 특정 게시글에 등록된 댓글 수를 조회하는 select 쿼리를 호출한다. 페이징을 적용하면서 사용한다.
- 댓글 XML mapper생성
mapper 인터페이스에 연결할 xml mapper 생성.
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.study.domain.comment.CommentMapper">
<!-- tb_comment 테이블 전체 컬럼 -->
<sql id="commentColumns">
id
, post_id
, content
, writer
, delete_yn
, created_date
, modified_date
</sql>
<!-- 댓글 저장 -->
<insert id="save" parameterType="com.study.domain.comment.CommentRequest" useGeneratedKeys="true" keyProperty="id">
INSERT INTO tb_comment (
<include refid="commentColumns" />
) VALUES (
#{id}
, #{postId}
, #{content}
, #{writer}
, 0
, NOW()
, NULL
)
</insert>
<!-- 댓글 상세정보 조회 -->
<select id="findById" parameterType="long" resultType="com.study.domain.comment.CommentResponse">
SELECT
<include refid="commentColumns" />
FROM
tb_comment
WHERE
id = #{value}
</select>
<!-- 댓글 수정 -->
<update id="update" parameterType="com.study.domain.comment.CommentRequest">
UPDATE tb_comment
SET
modified_date = NOW()
, content = #{content}
, writer = #{writer}
WHERE
id = #{id}
</update>
<!-- 댓글 삭제 -->
<delete id="deleteById" parameterType="long">
UPDATE tb_comment
SET
delete_yn = 1
WHERE
id = #{id}
</delete>
<!-- 댓글 리스트 조회 -->
<select id="findAll" parameterType="com.study.domain.comment.CommentSearchDto" resultType="com.study.domain.comment.CommentResponse">
SELECT
<include refid="commentColumns" />
FROM
tb_comment
WHERE
delete_yn = 0
AND post_id = #{postId}
ORDER BY
id DESC
LIMIT #{pagination.limitStart}, #{recordSize}
</select>
<!-- 댓글 수 카운팅 -->
<select id="count" parameterType="com.study.domain.comment.CommentSearchDto" resultType="int">
SELECT
COUNT(*)
FROM
tb_comment
WHERE
delete_yn = 0
AND post_id = #{postId}
</select>
</mapper>
- 댓글 서비스 클래스 생성
비즈니스 로직을 담당하는 서비스 레이어.
package com.study.domain.comment;
import com.study.common.paging.Pagination;
import com.study.common.paging.PagingResponse;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import javax.transaction.Transactional;
import java.util.Collections;
import java.util.List;
@Service
@RequiredArgsConstructor
public class CommentService {
private final CommentMapper commentMapper;
/**
* 댓글 저장
* @param params - 댓글 정보
* @return Generated PK
*/
@Transactional
public Long saveComment(final CommentRequest params) {
commentMapper.save(params);
return params.getId();
}
/**
* 댓글 상세정보 조회
* @param id - PK
* @return 댓글 상세정보
*/
public CommentResponse findCommentById(final Long id) {
return commentMapper.findById(id);
}
/**
* 댓글 수정
* @param params - 댓글 정보
* @return PK
*/
@Transactional
public Long updateComment(final CommentRequest params) {
commentMapper.update(params);
return params.getId();
}
/**
* 댓글 삭제
* @param id - PK
* @return PK
*/
@Transactional
public Long deleteComment(final Long id) {
commentMapper.deleteById(id);
return id;
}
/**
* 댓글 리스트 조회
* @param params - search conditions
* @return list & pagination information
*/
public PagingResponse<CommentResponse> findAllComment(final CommentSearchDto params) {
int count = commentMapper.count(params);
if (count < 1) {
return new PagingResponse<>(Collections.emptyList(), null);
}
Pagination pagination = new Pagination(count, params);
List<CommentResponse> list = commentMapper.findAll(params);
return new PagingResponse<>(list, pagination);
}
}
'JAVA > SpringBoot' 카테고리의 다른 글
게시판 프로젝트 - REST API 방식으로 댓글 등록 기능 구현 (0) | 2023.11.06 |
---|---|
게시판 프로젝트 - REST API 방식 (0) | 2023.11.06 |
게시판 - CRUD 글 등록 , 조회, 상세 페이지 조회, 삭제 (1) | 2023.11.06 |
게시판 프로젝트 2, CRUD (0) | 2023.11.06 |
IntelliJ, SpringBoot, MariaDB, Thymeleaf, MyBatis로 만드는 게시판 1 (0) | 2023.11.06 |