Spring MVC 게시판 만들기 6편: 댓글 기능과 예외 처리 마스터하기
💡 시리즈 완결편!
마지막으로 댓글 기능과 예외 처리를 다루며, 전체 시리즈를 마무리합니다.
🎯 한눈에 보기
| 주제 | 핵심 내용 |
|---|---|
| ReplyService | 댓글 CRUD 비즈니스 로직 |
| 커스텀 예외 | HTTP 상태 코드 + 에러 메시지 |
| 예외 처리 | try-catch로 안전한 코드 작성 |
📌 이번 편에서 배울 것
마지막 편에서는 댓글 기능과 예외 처리를 알아봅니다:
- ReplyService의 CRUD 로직
- 커스텀 예외 클래스 만들기
- 예외 발생 시 처리 방법
🗂️ 댓글 관련 파일 구조
📁 org/zerock/
├── 📁 dto/
│ ├── ReplyDTO.java # 댓글 데이터
│ └── ReplyListPaginDTO.java # 댓글 목록 + 페이징
├── 📁 mapper/
│ └── ReplyMapper.java # 매퍼 인터페이스
├── 📁 service/
│ ├── ReplyService.java # 비즈니스 로직
│ └── 📁 exeption/
│ └── ReplyExeption.java # 커스텀 예외
└── 📁 resources/mapper/
└── ReplyMapper.xml # SQL 쿼리
📦 ReplyDTO (댓글 데이터)
@Data
@Builder
@AllArgsConstructor
@NoArgsConstructor
public class ReplyDTO {
private int rno; // 댓글 번호
private Long bno; // 게시글 번호 (어떤 글의 댓글인지)
private String replyText; // 댓글 내용
private String replyer; // 댓글 작성자
private LocalDateTime replyDate; // 작성일
private LocalDateTime updateDate; // 수정일
private boolean delflag; // 삭제 여부
}
⚠️ 커스텀 예외 클래스

댓글 관련 에러를 위한 전용 예외 클래스입니다:
@Getter
public class ReplyExeption extends RuntimeException {
private int code; // HTTP 상태 코드
private String msg; // 에러 메시지
public ReplyExeption(int code, String msg) {
this.code = code;
this.msg = msg;
}
}
💡 왜 커스텀 예외?
- 에러 종류를 명확히 구분 가능
- HTTP 상태 코드를 함께 전달 가능
- 일관된 에러 처리 가능
🔧 ReplyService 분석
댓글 추가:
public void add(ReplyDTO replyDTO) {
try {
replyMapper.insert(replyDTO);
} catch (Exception e) {
throw new ReplyExeption(500, "댓글 추가 실패");
}
}
댓글 조회:
public ReplyDTO getOne(int rno) {
try {
return replyMapper.read(rno);
} catch (Exception e) {
throw new ReplyExeption(404, "Not Found");
}
}
댓글 수정:
public void modify(ReplyDTO replyDTO) {
try {
int count = replyMapper.update(replyDTO);
if (count == 0) {
throw new ReplyExeption(404, "Not Found");
}
} catch (Exception e) {
throw new ReplyExeption(500, "댓글 수정 실패");
}
}
댓글 삭제:
public void remove(int rno) {
try {
int count = replyMapper.delete(rno);
if (count == 0) {
throw new ReplyExeption(404, "Not Found");
}
} catch (Exception e) {
throw new ReplyExeption(500, "댓글 삭제 실패");
}
}
📋 댓글 목록 조회 (페이징)
public ReplyListPaginDTO listOfBoard(Long bno, int page, int size) {
try {
int skip = (page - 1) * size;
// 댓글 목록 조회
List<ReplyDTO> replyDTOList = replyMapper.listOfBoard(bno, skip, size);
// 전체 개수 조회
int count = replyMapper.countOfBoard(bno);
return new ReplyListPaginDTO(replyDTOList, count, page, size);
} catch (Exception e) {
throw new ReplyExeption(500, "댓글 목록 조회 실패");
}
}
flowchart LR
A["bno=42, page=1, size=5"] --> B["skip = 0"]
B --> C["listOfBoard(42, 0, 5)"]
C --> D["countOfBoard(42)"]
D --> E["ReplyListPaginDTO 반환"]
📄 ReplyMapper.xml
댓글 등록:
<insert id="insert">
<selectKey order="AFTER" keyProperty="rno" resultType="int">
SELECT LAST_INSERT_ID()
</selectKey>
INSERT INTO tbl_reply(bno, replyText, replyer)
VALUES (#{bno}, #{replyText}, #{replyer})
</insert>
댓글 목록 조회:
<select id="listOfBoard" resultType="org.zerock.dto.ReplyDTO">
SELECT * FROM tbl_reply
WHERE bno = #{bno} AND rno > 0
ORDER BY rno ASC
LIMIT #{limit} OFFSET #{skip}
</select>
댓글 수정:
<update id="update">
UPDATE tbl_reply
SET replyText = #{replyText}, updatedate = now()
WHERE rno = #{rno}
</update>
댓글 삭제:
<delete id="delete">
DELETE FROM tbl_reply WHERE rno = #{rno}
</delete>
💡 게시글은 소프트 삭제(delflag=true), 댓글은 실제 삭제(DELETE)를 사용합니다!
🔄 예외 처리 흐름
flowchart TB
Request["댓글 조회 요청"] --> Service["ReplyService.getOne()"]
Service --> Try{"try 블록"}
Try --> |성공| Return["ReplyDTO 반환"]
Try --> |실패| Catch["catch 블록"]
Catch --> Throw["throw ReplyExeption(404, 'Not Found')"]
Throw --> Handler["예외 처리기"]
Handler --> Response["에러 응답 반환"]
📝 시리즈 전체 요약
6편에 걸쳐 Spring MVC 게시판 프로젝트의 모든 부분을 살펴봤습니다!
flowchart TB
subgraph "1편: 전체 구조"
A1[기술 스택]
A2[폴더 구조]
A3[3-Tier 아키텍처]
end
subgraph "2편: Controller"
B1["@Controller"]
B2["@GetMapping/@PostMapping"]
B3[View Resolver]
end
subgraph "3편: Service"
C1["@Service"]
C2[DI]
C3[페이징 계산]
end
subgraph "4편: MyBatis"
D1[Mapper]
D2[XML]
D3[동적 SQL]
end
subgraph "5편: JSP"
E1[JSTL]
E2[Bootstrap]
E3[JavaScript]
end
subgraph "6편: 댓글"
F1[Reply CRUD]
F2[커스텀 예외]
F3[에러 처리]
end
| 편 | 핵심 내용 |
|---|---|
| 1편 | 전체 구조와 기술 스택 |
| 2편 | Controller가 요청을 받고 처리하는 과정 |
| 3편 | Service에서 비즈니스 로직 처리 |
| 4편 | MyBatis로 DB 연동 |
| 5편 | JSP에서 페이징과 검색 UI 구현 |
| 6편 | 댓글 기능과 예외 처리 |
🎯 핵심 키워드 정리
| 키워드 | 설명 |
|---|---|
| Spring MVC | Model-View-Controller 패턴 웹 프레임워크 |
| MyBatis | SQL과 Java를 연결하는 매퍼 프레임워크 |
| HikariCP | 빠른 데이터베이스 커넥션 풀 |
| DI | 의존성 주입 - Spring이 객체를 자동 연결 |
| DTO | 계층 간 데이터 전달 객체 |
| JSTL | JSP Standard Tag Library |
| 동적 SQL | 조건에 따라 변하는 SQL |
| 소프트 삭제 | 실제 삭제 대신 플래그로 표시 |
🏁 마무리
이 시리즈를 통해 Spring MVC 게시판의 전체 흐름을 이해하셨길 바랍니다!
사용자 요청
↓
DispatcherServlet (문지기)
↓
Controller (요청 처리)
↓
Service (비즈니스 로직)
↓
Mapper + MyBatis (DB 연동)
↓
JSP (화면 렌더링)
↓
사용자에게 응답! ✨
📚 시리즈 전체 목차
- [1편] 프로젝트 구조와 아키텍처 완벽 정리
- [2편] Spring MVC 컨트롤러와 요청 흐름 이해하기
- [3편] 서비스 계층과 비즈니스 로직 구현하기
- [4편] MyBatis와 데이터베이스 연동 완벽 가이드
- [5편] 페이징과 검색 기능 구현하기
- [6편] 댓글 기능과 예외 처리 마스터하기 ← 현재 글 (완결)
💬 질문이나 피드백이 있으시면 댓글로 남겨주세요!
이 시리즈가 도움이 되었다면 공유해주시면 감사하겠습니다 🙏