오늘 만들 것
이번 글에서는 게시글을 수정하는 예제입니다.
게시물 수정은 앞서 연습했던 게시물 호출과 게시물 작성을 모두 활용합니다.
작동 순서를 보면 무슨 뜻인지 이해할 수 있습니다.
1. 게시물 번호와 비밀번호를 이용해 게시물을 불러옵니다.
2. 불러온 게시물이 없다면 오류를 반환합니다.
3. 불러온 게시물이 있다면 사용자가 전달한 글 내용을 불러온 객체에 담습니다.
4. 게시물 객체를 DB로 전달하여 글을 갱신합니다.
5. 완료됨을 반환합니다.
1번이 게시물 호출, 4번이 게시물 작성을 활용하는 것을 알 수 있습니다.
게시물 수정까지 진행하면 게시판 API의 핵심은 모두 진행했다고 봐도 무방합니다!
게시물 수정 API, 지금 시작합니다.
시작
이번 글은 Lab05의 코드에 게시물 호출 API를 추가하는 예제입니다.
Lab05는 이전 글에서 확인할 수 있습니다.
별도의 프로젝트에서 진행하고자 하면, Lab05와 동일하게 프로젝트를 생성한 뒤 코드를 복사해서 준비합니다.
Lab05의 코드를 그대로 사용한다면 아래 예제 코드의 패키지명에 유의합니다.
아래 예제 코드는 별도의 프로젝트를 생성하는 방식으로 진행합니다.
DAO 수정
다음 경로의 파일을 아래와 같이 편집합니다: /src/main/java/YOUR/DOMAIN/ARTIFACT/dao/BoardDAO.java
package net.jetalab.spreinglab06.dao;
import net.jetalab.spreinglab06.dto.BoardDTO;
public interface BoardDAO {
int newBoard(BoardDTO param) throws Exception;
BoardDTO getBoard(BoardDTO param) throws Exception;
int editBoard(BoardDTO param) throws Exception;
}
7번째 줄: 다양한 방식으로 게시물을 불러오기 위해 getBoard()
메소드가 BoardDTO
형의 파라미터를 받도록 수정했습니다.
8번째 줄: 게시물 내용을 받아서 수정하는 editBoard()
메소드가 추가되었습니다.
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.spreinglab06.dao.BoardDAO">
<insert id="newBoard" parameterType="net.jetalab.spreinglab06.dto.BoardDTO" useGeneratedKeys="true" keyProperty="seq">
INSERT INTO lab06(`title`, `contents`, `author`, `password`)
VALUES (#{title}, #{contents}, #{author}, #{password})
</insert>
<select id="getBoard" parameterType="net.jetalab.spreinglab06.dto.BoardDTO" resultType="net.jetalab.spreinglab06.dto.BoardDTO">
SELECT `seq`, `title`, `contents`, `author`, `reads`
FROM lab06
WHERE `seq` = #{seq}
<if test="password != null">
AND `password` = #{password}
</if>
AND `deleted` = 'N'
</select>
<update id="editBoard" parameterType="net.jetalab.spreinglab06.dto.BoardDTO">
UPDATE lab06
SET `title` = #{title}
, `contents` = #{contents}
, `author` = #{author}
WHERE `seq` = #{seq}
</update>
</mapper>
<select id="getBoard" />
가 수정되었습니다.
11번째 줄: 파라미터로 BoardDTO
객체를 받도록 수정했습니다.
14번째 줄: 전달받은 파라미터의 객체의 seq
를 구체적으로 호출합니다.
15번째 줄 ~ 17번째 줄: 파라미터 객체에 password
가 있다면 AND
조건을 추가합니다. 이 부분은 별도의 글에서 조금 더 자세히 설명합니다.
21번째 줄부터 27번째 줄까지가 추가되었습니다.
21번째 줄: 파라미터로 BoardDTO
객체를 받도록 선언합니다.
22번째 줄 ~ 26번째 줄: 파라미터로 받은 객체에서 변수를 불러와 UPDATE
문을 만들어냅니다.
Controller 생성
PUT
으로 수정할 글 내용을 받을 Controller를 생성합니다.
다음 경로에 아래 코드를 작성하여 저장합니다: /src/main/java/YOUR/DOMAIN/ARTIFACT/controller/BoardController.java
package net.jetalab.spreinglab06.controller;
import net.jetalab.spreinglab06.dao.BoardDAO;
import net.jetalab.spreinglab06.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.spreinglab06.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);
}
}
각 메소드의 이름이 변경되었습니다.
이제 더 이상 파라미터로 구분이 되지 않기 때문에, 호출 메소드를 앞에 붙이기로 합니다.
GET /board/{seq}
가 수정되었습니다.
35번째 줄 ~ 36번째 줄: BoardDTO
형 객체로 파라미터를 넘기기 위해 새 객체를 만들어서 seq
를 지정합니다.
40번째 줄: BoardDTO
형 객체인 파라미터를 전달합니다.
46번째 줄부터 62번째 줄까지가 추가되었습니다.
48번째 줄 ~ 50번째 줄: 올바르지 않은 요청이라면 오류를 반환합니다.
53번째 줄: 사용자가 입력한 seq
와 password
를 이용해 게시물을 조회합니다.
54번째 줄: 조회된 게시물이 없다면 Not Found
오류를 반환합니다.
56번째 줄 ~ 58번째 줄: 조회된 게시물에 사용자가 입력한 새 제목과 내용, 글쓴이를 저장합니다.
59번째 줄: 새 게시물 정보를 저장합니다.
테스트
먼저 수정할 글을 호출해봅니다.
이제 수정할 글 내용을 입력해서 수정을 요청해봅니다.
이 때, 만약 비밀번호가 틀리면 오류를 반환합니다.
비밀번호가 올바르다면 정상적으로 처리됩니다.
이제 게시글을 다시 호출하면 정상적으로 수정된 것을 확인할 수 있습니다.
DB에도 수정된 내용이 잘 저장되어 있습니다.
*
이번 포스트에서 Dynamic SQL (동적 SQL)의 개념이 등장했습니다.
처음 접하는 경우 어렵게 느껴질 수 있기 때문에 한 번 짚고 넘어갈 필요가 있습니다.
이 글에서 설명하기엔 분량이 꽤 길어질 것 같아서
다음 포스트에서 설명하도록 하겠습니다.
예제 코드
본 포스트의 예제 코드는 GitHub에 공개되어 있습니다.
https://github.com/jETA-Kor/sp-re-ing/tree/master/lab06