본문 바로가기
Programming/Spring Boot

[실습] 스프링부트(Spring Boot)로 공지사항/게시판 구현하기 - REST API(Controller, Service) 구현하기

by 돌방로그 2023. 1. 31.


오늘의 Spring Boot 실습 목표는 "공지사항/게시판 만들어보기!" 입니다.
본 게시글에서 다루는 사항은 공지사항/게시판의 기능을 구현하기 위해 REST API로 DB를 CRUD하는 코드를 구현 및 테스트하는 과정입니다.


공지사항/게시판 구현하기 - REST API 구현 및 테스트

사전 준비

아래 사항에 대해서 사전 준비가 완료되지 않으신 분들은 아래 링크를 참조하여 사전 준비를 진행합니다.

 

혹시라도 아래 개념이 잘 기억나지 않으시는 분들은 관련 링크를 참조하시기 바랍니다.

 


파일 구조

Notice User 테이블과 FE(Front-end)인 뷰(View)와 연결되기 위해 작업해야할 파일은 총 2개입니다.

아래 폴더/파일 트리 구조와 호출 흐름도는 Notice User 테이블이 전체 구현이 완료된 후 갖춰질 구조입니다.

작업할 파일에 대한 간략한 설명은 아래를 참고하시면 됩니다.

  • NoticeUserService
    • 목적: REST API의 호출 결과를 처리하기 위한 비즈니스 로직이 담겨져 있는 파일
    • 경로: src\main\java\...\notice\service
  • NoticeUserController
    • 목적: FE(Front-end)의 뷰와 연결되는 최상위 파일로 REST API와 매핑되는 함수가 구현되어 있는 파일
    • 경로: src\main\java\...\notice\controller

 

API

[실습] 스프링부트(Spring Boot)로 공지사항/게시판 구현하기 - DB, API 기획/설계하기의 API 섹션을 참조해주세요.

 


소스 코드

NoticeUserService

Notice User 테이블에 대한 비즈니스 로직을 처리하는 구문으로 테이블에서 데이터를 가져오기 전과 가져온 후에 대한 처리를 하는 코드입니다.

TODO 사항으로 마크해둔 Exception 처리는 별도의 포스팅을 통해 다룰 예정입니다.

 

전체 코드가 궁금하신 분들은 아래 더보기를 클릭하여 확인해주시길 바랍니다.

더보기
package com.logsjejustone.webapiserver.notice.service;

import com.logsjejustone.webapiserver.notice.domain.NoticeUser;
import com.logsjejustone.webapiserver.notice.repository.NoticeUserRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Service;

import java.time.LocalDateTime;
import java.util.List;
import java.util.Optional;

@Service
public class NoticeUserService {

    @Autowired
    private NoticeUserRepository noticeUserRepository;
    private LocalDateTime localDateTime = LocalDateTime.now();

    // CREATE
    public ResponseEntity<NoticeUser> PostNotice(NoticeUser noticeUser) {
        noticeUser.setUpdateDatetime(localDateTime);
        noticeUser.setRegisterDatetime(localDateTime);

        this.noticeUserRepository.save(noticeUser);

        return ResponseEntity.ok().build();
    }

    // READ
    public List<NoticeUser> GetNotices() {
        return this.noticeUserRepository.findAll();
    }

    // UPDATE
    public ResponseEntity<NoticeUser> PutNoticeById(NoticeUser noticeUser, Integer id) {
        Optional<NoticeUser> optNoticeUser = this.noticeUserRepository.findById(id);

        if(optNoticeUser.isEmpty()) {
            System.out.println("[ERROR:PutNoticeById] There is no data of id(" + id + ")");
            // TODO: 'throw Exception' 구문으로 변경해야 함
            return ResponseEntity.notFound().build();
        }
        else {
            NoticeUser afterNoticeUser = optNoticeUser.get();
            System.out.println("afterNoticeUser: " + afterNoticeUser.toString());

            afterNoticeUser.setUpdateDatetime(localDateTime);
            afterNoticeUser.setUpdateEmployeeNo(noticeUser.getUpdateEmployeeNo());

            // 사용자가 변경 가능한 데이터
            afterNoticeUser.setCategory(noticeUser.getCategory());
            afterNoticeUser.setTitle(noticeUser.getTitle());
            afterNoticeUser.setContent(noticeUser.getContent());

            this.noticeUserRepository.save(afterNoticeUser);
        }

        return ResponseEntity.ok().build();
    }

    // DELETE
    public ResponseEntity<NoticeUser> DeleteNoticeById(Integer id) {
        Optional<NoticeUser> optNoticeUser = this.noticeUserRepository.findById(id);

        if(optNoticeUser.isEmpty()) {
            System.out.println("[ERROR:DeleteNoticeById] There is no data of id(" + id + ")");
            // TODO: 'throw Exception' 구문으로 변경해야 함
            return ResponseEntity.notFound().build();
        }
        else {
            this.noticeUserRepository.delete(optNoticeUser.get());
        }
        return ResponseEntity.ok().build();
    }
}

 

CREATE

public ResponseEntity<NoticeUser> PostNotice(NoticeUser noticeUser) {
    noticeUser.setUpdateDatetime(localDateTime);
    noticeUser.setRegisterDatetime(localDateTime);

    this.noticeUserRepository.save(noticeUser);

    return ResponseEntity.ok().build();
}

 

 

READ

// 전체 데이터 조회
public List<NoticeUser> GetNotices() {
    return this.noticeUserRepository.findAll();
}
  • 있는 경우에만 데이터를 조회하며, 없는 경우에는 null을 리턴합니다.

 

UPDATE

public ResponseEntity<NoticeUser> PutNoticeById(NoticeUser noticeUser, Integer id) {
    Optional<NoticeUser> optNoticeUser = this.noticeUserRepository.findById(id);

    if(optNoticeUser.isEmpty()) {
        System.out.println("[ERROR:PutNoticeById] There is no data of id(" + id + ")");
        // TODO: 'throw Exception' 구문으로 변경해야 함
        return ResponseEntity.notFound().build();
    }
    else {
        NoticeUser afterNoticeUser = optNoticeUser.get();
        System.out.println("afterNoticeUser: " + afterNoticeUser.toString());

        afterNoticeUser.setUpdateDatetime(localDateTime);
        afterNoticeUser.setUpdateEmployeeNo(noticeUser.getUpdateEmployeeNo());

        // 사용자가 변경 가능한 데이터
        afterNoticeUser.setCategory(noticeUser.getCategory());
        afterNoticeUser.setTitle(noticeUser.getTitle());
        afterNoticeUser.setContent(noticeUser.getContent());

        this.noticeUserRepository.save(afterNoticeUser);
    }

    return ResponseEntity.ok().build();
}
  • 수정할 데이터가 테이블에 기 입력된 정보인지를 PK인 id를 기준으로 확인합니다.
  • 있는 경우에만 데이터를 수정하며, 없는 경우에는 Exception 처리를 진행합니다.

 

DELETE

public ResponseEntity<NoticeUser> DeleteNoticeById(Integer id) {
    Optional<NoticeUser> optNoticeUser = this.noticeUserRepository.findById(id);

    if(optNoticeUser.isEmpty()) {
        System.out.println("[ERROR:DeleteNoticeById] There is no data of id(" + id + ")");
        // TODO: 'throw Exception' 구문으로 변경해야 함
        return ResponseEntity.notFound().build();
    }
    else {
        this.noticeUserRepository.delete(optNoticeUser.get());
    }
    return ResponseEntity.ok().build();
}
  • 삭제할 데이터가 테이블에 존재하는 데이터인지 PK인 id를 기준으로 확인합니다.
  • 있는 경우에만 데이터를 삭제하며, 없는 경우에는 Exception 처리를 진행합니다.

 

NoticeUserController

Notice User 테이블에 대한 처리 로직을 호출하는 REST API가 매핑되는 코드입니다.

총 4개 API가 구현되어 있습니다.

  • CREATE: (POST: ~/notices)
  • READ: (GET: ~/notices)
  • UPDATE: (PUT: ~/notices/{id})
  • DELETE: (DELETE: ~/notices/{id})

 

아래는 전체 코드입니다.

package com.logsjejustone.webapiserver.notice.controller;

import com.logsjejustone.webapiserver.notice.domain.NoticeUser;
import com.logsjejustone.webapiserver.notice.service.NoticeUserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;

import java.util.List;

@RestController
@RequestMapping("/api/notices")
@CrossOrigin(origins = "http://localhost:8081")
public class NoticeUserController {
    @Autowired
    private NoticeUserService noticeUserService;

    // CREATE
    @PostMapping("")
    public ResponseEntity<NoticeUser> PostNotice(@RequestBody NoticeUser noticeUser) {
        System.out.println("[NoticeUser:PostNotice] " + noticeUser);

        return this.noticeUserService.PostNotice(noticeUser);
    }

    // READ
    @GetMapping("")
    public List<NoticeUser> GetNotices() {
        System.out.println("[NoticeUser:GetNotices] ");
        return this.noticeUserService.GetNotices();
    }

    // UPDATE
    @PutMapping("/{id}")
    public ResponseEntity<NoticeUser> PutNoticeById(@RequestBody NoticeUser noticeUser, @PathVariable Integer id) {
        System.out.println("[NoticeUser:PutNoticeById] " + noticeUser);

        return this.noticeUserService.PutNoticeById(noticeUser, id);
    }

    // DELETE
    @DeleteMapping("/{id}")
    public ResponseEntity<NoticeUser> DeleteNoticeById(@PathVariable Integer id) {
        System.out.println("[NoticeUser:DeleteNoticeById] " + id);

        return this.noticeUserService.DeleteNoticeById(id);
    }
}

 


테스트

테스트는 Postman으로 Controller에 구현한 REST API를 호출하여 해당 로직이 정상적으로 결과를 도출하는지를 확인합니다. 테스트는 Postman으로 테스트하였으며, Postman 관련 사항은 링크를 참조해주세요.

 

테스트를 위한 관련 툴의 상태는 아래와 같이 구성되어야 합니다.

  • Postman: API Test 구동 및 결과 확인
  • IntelliJ: Server 구동
  • MySQL Workbench: API Test 결과 확인

테스트 하기 전 DB 상태는 아래 이미지와 같이 어떠한 테이블도 없는 상태입니다.

 

CREATE

DB Query로는 INSERT 구문에 해당하는 동작으로 Postman에서 POST로 설정하여 테스트합니다.

총 2개의 데이터를 순차적으로 POST 구문을 실행하여 테스트합니다.

 

Postman (API Test)

CASE #1 데이터 하나씩 입력하는 경우 (POST: localhost:8080/notices)

좌: 1번 데이터 우: 2번 데이터

  • 우측 중앙부에 초록색으로 '200 OK'로 정상적으로 API 통신되었음을 확인할 수 있음

 

Results

  • SELECT문으로 notice_user 테이블에 정상적으로 2개의 데이터가 입력된 것을 확인

 

READ

DB Query로는 SELECT 구문에 해당하는 동작으로 Postman에서 GET로 설정하여 테스트합니다.

 

Postman (API Test)

CASE #1 전체 데이터를 가져오는 경우 (GET: localhost:8080/notices)

  • 우측 중앙부에 초록색으로 '200 OK'로 정상적으로 API 통신되었음을 확인할 수 있음
  • 하단에 위치한 Body 부분에서 GET한 전체 데이터를 JSON 타입으로 확인할 수 있음

 

UPDATE

DB Query로는 UPDATE 구문에 해당하는 동작으로 Postman에서 PUT로 설정하여 테스트합니다.

 

Postman (API Test)

CASE #1 특정 데이터를 수정하는 경우 (PUT: localhost:8080/notices/{id})

  • 우측 중앙부에 초록색으로 '200 OK'로 정상적으로 API 통신되었음을 확인할 수 있음

 

Results

  • SELECT문으로 notice_user 테이블에 id가 2인 데이터의 타이틀이 '제 3회'에서 '제 2회'로 변경된 것을 확인

 

DELETE

DB Query로는 DELETE 구문에 해당하는 동작으로 Postman에서 DELETE로 설정하여 테스트합니다.

 

Postman (API Test)

CASE #1 특정 데이터를 삭제하는 경우 (DELETE: localhost:8080/notices/{id})

  • 우측 중앙부에 초록색으로 '200 OK'로 정상적으로 API 통신되었음을 확인할 수 있음

 

Results

  • SELECT문으로 notice_user 테이블에 id가 1인 데이터가 삭제된 것을 확인

 

 


References

 

 

댓글