:: Dev/Spring

[Sp-re-ing] 06 - 게시판 구현하기 (3) - 게시물 수정 API

jETA 2020. 3. 17. 10:00
반응형

오늘 만들 것

이번 글에서는 게시글을 수정하는 예제입니다.

 

게시물 수정은 앞서 연습했던 게시물 호출과 게시물 작성을 모두 활용합니다.

작동 순서를 보면 무슨 뜻인지 이해할 수 있습니다.

 

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번째 줄: 사용자가 입력한 seqpassword를 이용해 게시물을 조회합니다.

54번째 줄: 조회된 게시물이 없다면 Not Found오류를 반환합니다.

56번째 줄 ~ 58번째 줄: 조회된 게시물에 사용자가 입력한 새 제목과 내용, 글쓴이를 저장합니다.

59번째 줄: 새 게시물 정보를 저장합니다.

 

테스트

먼저 수정할 글을 호출해봅니다.

예전에 작성한 글이 잘 보관되고 있습니다.

 

이제 수정할 글 내용을 입력해서 수정을 요청해봅니다.

이 때, 만약 비밀번호가 틀리면 오류를 반환합니다.

아래 Status를 보면 404 Not Found가 반환됩니다.

 

비밀번호가 올바르다면 정상적으로 처리됩니다.

이번엔 200 OK가 반환되었습니다.

 

이제 게시글을 다시 호출하면 정상적으로 수정된 것을 확인할 수 있습니다.

비밀번호는 일부러 노출하지 않습니다.

 

DB에도 수정된 내용이 잘 저장되어 있습니다.

비밀번호는 여기 잘 있습니다.

 

*

이번 포스트에서 Dynamic SQL (동적 SQL)의 개념이 등장했습니다.

처음 접하는 경우 어렵게 느껴질 수 있기 때문에 한 번 짚고 넘어갈 필요가 있습니다.

 

이 글에서 설명하기엔 분량이 꽤 길어질 것 같아서

다음 포스트에서 설명하도록 하겠습니다.

 

예제 코드

본 포스트의 예제 코드는 GitHub에 공개되어 있습니다.

https://github.com/jETA-Kor/sp-re-ing/tree/master/lab06

 

참고 문서

반응형