오늘 만들 것
이번 글에서는 게시판 구현의 마지막 단계인 게시글 삭제를 구현합니다.
게시글 삭제는 두 가지 방법을 사용할 수 있습니다.
실제로 DB에서 삭제하거나 삭제 표기를 하는 방법입니다.
이번 글에서는 주로 사용되는 방법인 삭제 표기를 진행합니다.
시작
이번 글은 Lab06의 코드에 기능을 추가하는 방식으로 진행합니다.
Lab06는 이전 글에서 확인할 수 있습니다.
별도의 프로젝트에서 진행하고자 하면, Lab06과 동일하게 프로젝트를 생성한 뒤 코드를 복사해서 준비합니다.
Lab06의 코드를 그대로 사용한다면 아래 예제 코드의 패키지명에 유의합니다.
아래 예제 코드는 별도의 프로젝트를 생성하는 방식으로 진행합니다.
SQL Mapper 수정
다음 경로의 파일을 아래와 같이 편집합니다: /src/main/resources/mappers/UserMapper.xml
<?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="net.jetalab.spreinglab08.dao.BoardDAO">
<insert id="newBoard" parameterType="net.jetalab.spreinglab08.dto.BoardDTO" useGeneratedKeys="true" keyProperty="seq">
INSERT INTO lab08(`title`, `contents`, `author`, `password`)
VALUES (#{title}, #{contents}, #{author}, #{password})
</insert>
<select id="getBoard" parameterType="net.jetalab.spreinglab08.dto.BoardDTO" resultType="net.jetalab.spreinglab08.dto.BoardDTO">
SELECT `seq`, `title`, `contents`, `author`, `reads`
FROM lab08
WHERE `seq` = #{seq}
<if test="password != null">
AND `password` = #{password}
</if>
AND `deleted` = 'N'
</select>
<update id="editBoard" parameterType="net.jetalab.spreinglab08.dto.BoardDTO">
UPDATE lab08
SET `password` = `password`
<if test="title != null">
, `title` = #{title}
</if>
<if test="contents != null">
, `contents` = #{contents}
</if>
<if test="author != null">
, `author` = #{author}
</if>
<if test="deleted != null">
, `deleted` = #{deleted}
</if>
WHERE `seq` = #{seq}
</update>
</mapper>
<update id="editBoard" />
가 수정되었습니다.
23번째 줄 ~ 35번째 줄: password
는 변경되지 않기에 그대로 두고, 변경이 요구된 항목만 변경되도록 설정합니다. 이렇게 구성하면 UserDTO
에 값이 존재하는 항목만 UPDATE
되도록 활용할 수 있고, 의도치 않은 데이터 손실을 피할 수 있습니다./p>
Controller 생성
DELETE
로 삭제할 글의 ID와 그 글의 암호를 받을 Controller를 생성합니다.
다음 경로에 아래 코드를 작성하여 저장합니다: /src/main/java/YOUR/DOMAIN/ARTIFACT/controller/BoardController.java
package net.jetalab.spreinglab08.controller;
import net.jetalab.spreinglab08.dao.BoardDAO;
import net.jetalab.spreinglab08.dto.BoardDTO;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;
@RestController
@EnableAutoConfiguration
@MapperScan(basePackages = "net.jetalab.spreinglab08.dao")
public class BoardController {
@Autowired
private BoardDAO boardDAO;
@RequestMapping(value = "/board", method = RequestMethod.POST)
public ResponseEntity<BoardDTO> postBoard(BoardDTO board) throws Exception {
if ((board.getAuthor() == null) || (board.getContents() == null) || (board.getPassword() == null) || (board.getTitle() == null)) {
return new ResponseEntity<>(HttpStatus.BAD_REQUEST);
}
boardDAO.newBoard(board);
return new ResponseEntity<>(board, HttpStatus.OK);
}
@RequestMapping(value = "/board/{seq}", method = RequestMethod.GET)
public ResponseEntity<BoardDTO> getBoard(@PathVariable("seq") final int seq) throws Exception {
BoardDTO param = new BoardDTO();
param.setSeq(seq);
/* TODO: 조회수 증가 */
BoardDTO board = boardDAO.getBoard(param);
if (board == null) return new ResponseEntity<>(HttpStatus.NOT_FOUND);
else return new ResponseEntity<>(board, HttpStatus.OK);
}
@RequestMapping(value = "/board/{seq}", method = RequestMethod.PUT)
public ResponseEntity<BoardDTO> putBoard(@PathVariable("seq") final int seq, BoardDTO param) throws Exception {
if ((param.getAuthor() == null) || (param.getContents() == null) || (param.getPassword() == null) || (param.getTitle() == null)) {
return new ResponseEntity<>(HttpStatus.BAD_REQUEST);
}
param.setSeq(seq); // 조회할 게시물 번호 지정
BoardDTO board = boardDAO.getBoard(param);
if (board == null) return new ResponseEntity<>(HttpStatus.NOT_FOUND);
board.setTitle(param.getTitle());
board.setContents(param.getContents());
board.setAuthor(param.getAuthor());
boardDAO.editBoard(board);
return new ResponseEntity<>(board, HttpStatus.OK);
}
@RequestMapping(value = "/board/{seq}", method = RequestMethod.DELETE)
public ResponseEntity<BoardDTO> deleteBoard(@PathVariable("seq") final int seq, BoardDTO param) throws Exception {
if (param.getPassword() == null) {
return new ResponseEntity<>(HttpStatus.BAD_REQUEST);
}
param.setSeq(seq); // 조회할 게시물 번호 지정
BoardDTO board = boardDAO.getBoard(param);
if (board == null) return new ResponseEntity<>(HttpStatus.NOT_FOUND);
board.setDeleted("Y");
boardDAO.editBoard(board);
return new ResponseEntity<>(HttpStatus.OK);
}
}
DELETE /board/{seq}
가 추가되었습니다.
66번째 줄 ~ 68번째 줄: password
가 없다면 올바르지 않은 요청으로 보고 오류를 반환합니다.
74번째 줄: 만약 조회된 게시물이 있다면 deleted
플래그를 삭제된 것으로 지정합니다.
테스트
먼저 삭제할 글을 호출해봅니다.
이제 삭제할 글 번호와 비밀번호를 입력해서 삭제를 요청해봅니다.
이 때, 만약 비밀번호가 틀리면 오류를 반환합니다.
비밀번호가 올바르다면 정상적으로 처리됩니다.
이제 게시글을 다시 호출하면 404 오류가 반환됩니다.
DB에도 삭제된 상태가 지정되어 있습니다.
예제 코드
본 포스트의 예제 코드는 GitHub에 공개되어 있습니다.