diff --git a/frontend/src/components/view/admin/pgBoard/SampleBoardPage.vue b/frontend/src/components/view/admin/pgBoard/SampleBoardPage.vue new file mode 100644 index 0000000..5fe372b --- /dev/null +++ b/frontend/src/components/view/admin/pgBoard/SampleBoardPage.vue @@ -0,0 +1,381 @@ + + + + + + + + + + Total {{ $filters.numberFormat(boardList.length) }} + + + + 새 글 + + + + + + + + + + + + + + + + + + + + + + + + + 번호 + + 제목 + + 작성자 + + 등록일 + + + + + + + + 등록된 게시글이 없습니다. + + + + + {{ board.id }} + + + + {{ board.title }} + + + {{ board.author }} + + {{ formatDate(board.createdAt) }} + + + + + + + + + + Sample Board {{ mode === 'CREATE' ? '등록' : '수정' }} + + + + + + 번호 + + + + + + + 등록일 + + + + + + + + 제목 * + + + + + + + 작성자 * + + + + + + + 내용 * + + + + + + + 초기화 + + 저장 + + 삭제 + + + + + + + + + + + + diff --git a/src/main/java/com/samsung/sample/board/SampleBoardService.java b/src/main/java/com/samsung/sample/board/SampleBoardService.java new file mode 100644 index 0000000..a4ffe12 --- /dev/null +++ b/src/main/java/com/samsung/sample/board/SampleBoardService.java @@ -0,0 +1,18 @@ +package com.samsung.sample.board; // 샘플 게시판 서비스 패키지이다. + +import java.util.List; // 목록 반환을 위해 List 타입을 사용한다. + +import com.samsung.sample.board.entity.SampleBoard; // 샘플 게시판 엔티티를 사용한다. + +public interface SampleBoardService { // 샘플 게시판 비즈니스 로직 인터페이스이다. + + List getSampleBoardList(); // 게시글 목록 조회 기능이다. + + SampleBoard getSampleBoard(Integer id); // 게시글 상세 조회 기능이다. + + SampleBoard createSampleBoard(SampleBoard sampleBoard); // 게시글 등록 기능이다. + + SampleBoard updateSampleBoard(SampleBoard sampleBoard); // 게시글 수정 기능이다. + + void deleteSampleBoard(Integer id); // 게시글 삭제 기능이다. +} // 서비스 인터페이스 정의를 종료한다. diff --git a/src/main/java/com/samsung/sample/board/controller/SampleBoardController.java b/src/main/java/com/samsung/sample/board/controller/SampleBoardController.java new file mode 100644 index 0000000..258cedc --- /dev/null +++ b/src/main/java/com/samsung/sample/board/controller/SampleBoardController.java @@ -0,0 +1,87 @@ +package com.samsung.sample.board.controller; // 샘플 게시판 컨트롤러 패키지이다. + +import java.util.List; // 목록 반환을 위해 List 타입을 사용한다. + +import org.apache.commons.lang3.StringUtils; // 문자열 검증을 위해 StringUtils를 사용한다. +import org.springframework.stereotype.Controller; // 일반 컨트롤러 등록을 위해 Controller를 사용한다. +import org.springframework.web.bind.annotation.DeleteMapping; // 삭제 매핑을 사용한다. +import org.springframework.web.bind.annotation.GetMapping; // 조회 매핑을 사용한다. +import org.springframework.web.bind.annotation.PathVariable; // 경로 변수를 사용한다. +import org.springframework.web.bind.annotation.PostMapping; // 등록 매핑을 사용한다. +import org.springframework.web.bind.annotation.PutMapping; // 수정 매핑을 사용한다. +import org.springframework.web.bind.annotation.RequestBody; // 요청 본문 매핑을 사용한다. +import org.springframework.web.bind.annotation.ResponseBody; // 메서드 단위 응답 바디 처리를 사용한다. + +import com.samsung.sample.board.SampleBoardService; // 샘플 게시판 서비스 인터페이스를 사용한다. +import com.samsung.sample.board.entity.SampleBoard; // 샘플 게시판 엔티티를 사용한다. + +import io.swagger.v3.oas.annotations.Operation; // Swagger 요약 설명을 사용한다. +import jakarta.servlet.http.HttpServletRequest; // 페이지 포워딩 요청 정보를 사용한다. + +@Controller // 페이지 포워딩과 REST 응답을 함께 처리하는 컨트롤러를 등록한다. +public class SampleBoardController { // samples 테이블 CRUD API와 pgBoard 페이지 포워딩을 함께 처리하는 컨트롤러이다. + + private final SampleBoardService sampleBoardService; // 샘플 게시판 서비스이다. + + public SampleBoardController(SampleBoardService sampleBoardService) { // 생성자에서 서비스를 주입받는다. + this.sampleBoardService = sampleBoardService; // 주입받은 서비스를 필드에 저장한다. + } // 생성자를 종료한다. + + @GetMapping({"/admin/pgBoard/sampleBoardPage"}) // pgBoard 페이지 URL을 처리한다. + public String forwardSampleBoardPage(HttpServletRequest request) { // 요청 URL을 유지한 채 프론트 진입점으로 전달한다. + return "forward:/index.html?redirect=" + request.getRequestURI(); // 현재 요청 URI를 redirect 파라미터로 전달한다. + } // 포워딩 메서드를 종료한다. + + @ResponseBody // 목록 조회 결과를 JSON 본문으로 반환한다. + @Operation(summary = "샘플 게시판 목록 조회") // 게시글 목록 조회 API 설명이다. + @GetMapping("/pg-board/samples") // GET 목록 조회 경로를 매핑한다. + public List getSampleBoardList() { // 게시글 목록을 반환한다. + return sampleBoardService.getSampleBoardList(); // 서비스 목록 조회를 호출한다. + } // 목록 조회 메서드를 종료한다. + + @ResponseBody // 상세 조회 결과를 JSON 본문으로 반환한다. + @Operation(summary = "샘플 게시판 상세 조회") // 게시글 상세 조회 API 설명이다. + @GetMapping("/pg-board/samples/{id}") // GET 상세 조회 경로를 매핑한다. + public SampleBoard getSampleBoard(@PathVariable Integer id) { // 게시글 상세를 반환한다. + return sampleBoardService.getSampleBoard(id); // 서비스 상세 조회를 호출한다. + } // 상세 조회 메서드를 종료한다. + + @ResponseBody // 등록 결과를 JSON 본문으로 반환한다. + @Operation(summary = "샘플 게시판 등록") // 게시글 등록 API 설명이다. + @PostMapping("/pg-board/samples") // POST 등록 경로를 매핑한다. + public SampleBoard createSampleBoard(@RequestBody SampleBoard sampleBoard) { // 게시글을 등록한다. + validateSampleBoard(sampleBoard); // 요청 데이터를 검증한다. + return sampleBoardService.createSampleBoard(sampleBoard); // 서비스 등록을 호출한다. + } // 등록 메서드를 종료한다. + + @ResponseBody // 수정 결과를 JSON 본문으로 반환한다. + @Operation(summary = "샘플 게시판 수정") // 게시글 수정 API 설명이다. + @PutMapping("/pg-board/samples/{id}") // PUT 수정 경로를 매핑한다. + public SampleBoard updateSampleBoard(@PathVariable Integer id, @RequestBody SampleBoard sampleBoard) { // 게시글을 수정한다. + validateSampleBoard(sampleBoard); // 요청 데이터를 검증한다. + sampleBoard.setId(id); // 경로의 식별자를 엔티티에 설정한다. + return sampleBoardService.updateSampleBoard(sampleBoard); // 서비스 수정을 호출한다. + } // 수정 메서드를 종료한다. + + @ResponseBody // 삭제 결과를 HTTP 본문 없이 처리한다. + @Operation(summary = "샘플 게시판 삭제") // 게시글 삭제 API 설명이다. + @DeleteMapping("/pg-board/samples/{id}") // DELETE 삭제 경로를 매핑한다. + public void deleteSampleBoard(@PathVariable Integer id) { // 게시글을 삭제한다. + sampleBoardService.deleteSampleBoard(id); // 서비스 삭제를 호출한다. + } // 삭제 메서드를 종료한다. + + private void validateSampleBoard(SampleBoard sampleBoard) { // 등록 및 수정 요청 데이터를 검증한다. + if (sampleBoard == null) { // 요청 본문이 없는 경우를 확인한다. + throw new IllegalArgumentException("게시글 정보는 필수입니다."); // 필수 데이터 누락 예외를 발생시킨다. + } // null 검사 블록을 종료한다. + if (StringUtils.isBlank(sampleBoard.getTitle())) { // 제목 공백 여부를 확인한다. + throw new IllegalArgumentException("제목은 필수입니다."); // 제목 누락 예외를 발생시킨다. + } // 제목 검사 블록을 종료한다. + if (StringUtils.isBlank(sampleBoard.getContent())) { // 본문 공백 여부를 확인한다. + throw new IllegalArgumentException("내용은 필수입니다."); // 본문 누락 예외를 발생시킨다. + } // 본문 검사 블록을 종료한다. + if (StringUtils.isBlank(sampleBoard.getAuthor())) { // 작성자 공백 여부를 확인한다. + throw new IllegalArgumentException("작성자는 필수입니다."); // 작성자 누락 예외를 발생시킨다. + } // 작성자 검사 블록을 종료한다. + } // 검증 메서드를 종료한다. +} // 컨트롤러 정의를 종료한다. diff --git a/src/main/java/com/samsung/sample/board/dao/SampleBoardDao.java b/src/main/java/com/samsung/sample/board/dao/SampleBoardDao.java new file mode 100644 index 0000000..8e057a5 --- /dev/null +++ b/src/main/java/com/samsung/sample/board/dao/SampleBoardDao.java @@ -0,0 +1,40 @@ +package com.samsung.sample.board.dao; // 샘플 게시판 DAO 패키지이다. + +import java.util.List; // 목록 조회를 위해 List 타입을 사용한다. + +import org.apache.ibatis.session.SqlSession; // MyBatis SqlSession을 사용한다. +import org.springframework.stereotype.Repository; // DAO 빈 등록을 위해 Repository를 사용한다. + +import com.samsung.sample.board.entity.SampleBoard; // 샘플 게시판 엔티티를 사용한다. + +@Repository // 샘플 게시판 DAO를 스프링 빈으로 등록한다. +public class SampleBoardDao { // samples 테이블 CRUD를 처리하는 DAO이다. + + private static final String MAPPER = "sampleBoardMapper."; // MyBatis 매퍼 네임스페이스 접두어이다. + + private final SqlSession sqlSession; // MyBatis 세션 객체이다. + + public SampleBoardDao(SqlSession sqlSession) { // 생성자에서 의존성을 주입받는다. + this.sqlSession = sqlSession; // 주입받은 세션을 필드에 저장한다. + } // 생성자를 종료한다. + + public List selectSampleBoardList() { // 게시글 목록을 조회한다. + return sqlSession.selectList(MAPPER + "selectSampleBoardList"); // 매퍼의 목록 조회 쿼리를 실행한다. + } // 목록 조회 메서드를 종료한다. + + public SampleBoard selectSampleBoard(Integer id) { // 게시글 한 건을 조회한다. + return sqlSession.selectOne(MAPPER + "selectSampleBoard", id); // 매퍼의 단건 조회 쿼리를 실행한다. + } // 단건 조회 메서드를 종료한다. + + public void insertSampleBoard(SampleBoard sampleBoard) { // 게시글을 등록한다. + sqlSession.insert(MAPPER + "insertSampleBoard", sampleBoard); // 매퍼의 등록 쿼리를 실행한다. + } // 등록 메서드를 종료한다. + + public void updateSampleBoard(SampleBoard sampleBoard) { // 게시글을 수정한다. + sqlSession.update(MAPPER + "updateSampleBoard", sampleBoard); // 매퍼의 수정 쿼리를 실행한다. + } // 수정 메서드를 종료한다. + + public void deleteSampleBoard(Integer id) { // 게시글을 삭제한다. + sqlSession.delete(MAPPER + "deleteSampleBoard", id); // 매퍼의 삭제 쿼리를 실행한다. + } // 삭제 메서드를 종료한다. +} // DAO 정의를 종료한다. diff --git a/src/main/java/com/samsung/sample/board/entity/SampleBoard.java b/src/main/java/com/samsung/sample/board/entity/SampleBoard.java new file mode 100644 index 0000000..616b113 --- /dev/null +++ b/src/main/java/com/samsung/sample/board/entity/SampleBoard.java @@ -0,0 +1,19 @@ +package com.samsung.sample.board.entity; // 샘플 게시판 엔티티 패키지이다. + +import java.util.Date; // 생성일시 표현을 위해 Date 타입을 사용한다. + +import lombok.Data; // Lombok Data 어노테이션을 사용한다. + +@Data // 샘플 게시판 엔티티의 접근자 메서드를 자동 생성한다. +public class SampleBoard { // samples 테이블 한 건을 표현하는 엔티티이다. + + private Integer id; // 게시글 식별자이다. + + private String title; // 게시글 제목이다. + + private String content; // 게시글 본문이다. + + private String author; // 게시글 작성자이다. + + private Date createdAt; // 게시글 생성일시이다. +} // 엔티티 정의를 종료한다. diff --git a/src/main/java/com/samsung/sample/board/impl/SampleBoardServiceImpl.java b/src/main/java/com/samsung/sample/board/impl/SampleBoardServiceImpl.java new file mode 100644 index 0000000..a9e3a83 --- /dev/null +++ b/src/main/java/com/samsung/sample/board/impl/SampleBoardServiceImpl.java @@ -0,0 +1,46 @@ +package com.samsung.sample.board.impl; // 샘플 게시판 서비스 구현 패키지이다. + +import java.util.List; // 목록 반환을 위해 List 타입을 사용한다. + +import org.springframework.stereotype.Service; // 서비스 빈 등록을 위해 Service를 사용한다. + +import com.samsung.sample.board.SampleBoardService; // 샘플 게시판 서비스 인터페이스를 사용한다. +import com.samsung.sample.board.dao.SampleBoardDao; // 샘플 게시판 DAO를 사용한다. +import com.samsung.sample.board.entity.SampleBoard; // 샘플 게시판 엔티티를 사용한다. + +@Service // 샘플 게시판 서비스 구현체를 스프링 빈으로 등록한다. +public class SampleBoardServiceImpl implements SampleBoardService { // 샘플 게시판 서비스 구현체이다. + + private final SampleBoardDao sampleBoardDao; // 샘플 게시판 DAO이다. + + public SampleBoardServiceImpl(SampleBoardDao sampleBoardDao) { // 생성자에서 DAO를 주입받는다. + this.sampleBoardDao = sampleBoardDao; // 주입받은 DAO를 필드에 저장한다. + } // 생성자를 종료한다. + + @Override // 목록 조회 인터페이스 구현이다. + public List getSampleBoardList() { // 게시글 목록을 조회한다. + return sampleBoardDao.selectSampleBoardList(); // DAO 목록 조회를 호출한다. + } // 목록 조회 메서드를 종료한다. + + @Override // 상세 조회 인터페이스 구현이다. + public SampleBoard getSampleBoard(Integer id) { // 게시글 상세를 조회한다. + return sampleBoardDao.selectSampleBoard(id); // DAO 단건 조회를 호출한다. + } // 상세 조회 메서드를 종료한다. + + @Override // 등록 인터페이스 구현이다. + public SampleBoard createSampleBoard(SampleBoard sampleBoard) { // 게시글을 등록한다. + sampleBoardDao.insertSampleBoard(sampleBoard); // DAO 등록을 호출한다. + return sampleBoardDao.selectSampleBoard(sampleBoard.getId()); // 등록된 게시글을 다시 조회해 반환한다. + } // 등록 메서드를 종료한다. + + @Override // 수정 인터페이스 구현이다. + public SampleBoard updateSampleBoard(SampleBoard sampleBoard) { // 게시글을 수정한다. + sampleBoardDao.updateSampleBoard(sampleBoard); // DAO 수정을 호출한다. + return sampleBoardDao.selectSampleBoard(sampleBoard.getId()); // 수정된 게시글을 다시 조회해 반환한다. + } // 수정 메서드를 종료한다. + + @Override // 삭제 인터페이스 구현이다. + public void deleteSampleBoard(Integer id) { // 게시글을 삭제한다. + sampleBoardDao.deleteSampleBoard(id); // DAO 삭제를 호출한다. + } // 삭제 메서드를 종료한다. +} // 서비스 구현체 정의를 종료한다. diff --git a/src/main/resources/sql/mybatis/postgresql/mapper-mybatis-sample-board.xml b/src/main/resources/sql/mybatis/postgresql/mapper-mybatis-sample-board.xml new file mode 100644 index 0000000..6ecabf0 --- /dev/null +++ b/src/main/resources/sql/mybatis/postgresql/mapper-mybatis-sample-board.xml @@ -0,0 +1,45 @@ + + + + + + + + + + + + + + + + + SELECT id, title, content, author, created_at + FROM public.samples + ORDER BY id DESC + + + + SELECT id, title, content, author, created_at + FROM public.samples + WHERE id = #{id} + + + + INSERT INTO public.samples (title, content, author) + VALUES (#{title}, #{content}, #{author}) + + + + UPDATE public.samples + SET title = #{title}, + content = #{content}, + author = #{author} + WHERE id = #{id} + + + + DELETE FROM public.samples + WHERE id = #{id} + +