-
ch4 - 방명록 프로젝트 톺아보기SpringBoot 2023. 12. 28. 17:42
(책 - 코드로 배우는 스프링 부트 웹 프로젝트)
https://github.com/uqualid/SBW-ex4-guestbook
프로젝트 파일 구성 html과 css의 경우 제공되는 탬플릿을 따라 구성되어 있고, 외에는 여타 프로젝트와 동일하게
entity, DTO, repository, service(+ Impl) , controller로 구성되어 있다)
GuestBook entity 구성
변수명 속성 게스트북 아이디 gno Long, PK 제목 title String 내용 content String 작성자 writer String 생성시간 regDateLocalDateTime 수정시간 modDate LocalDateTime 생성시간과 수정시간은 BaseEntity 추상 클래스에서
AuditingEntityListener를 통해 자동으로 설정될 수 있게 구성되어 있다Repositorypackage com.example.guestbook.repository; import com.example.guestbook.entity.Guestbook; import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.data.querydsl.QuerydslPredicateExecutor; public interface GuestbookRepository extends JpaRepository<Guestbook, Long>, QuerydslPredicateExecutor<Guestbook> { }
repository에서는 JpaRepository를 상속받아 JpaRepository에 이미 구성되어 있는 인터페이스를 활용하도록 하였고 Spring Data Jpa에서 Querydsl을 활용할 수 있는 QuerydslPredicateExecutor도 함께 상속받았다
dto의 경우 Guestbook, PageRequest, PageResult DTO로 구성되어 있는데GuestbookDTO의 경우 기본 Guestbook 엔티티 관련 속성만 포함되어 있고
Page DTO의 경우 목록 구현을 위한 요소들이 주로 구성되어 있다
package com.example.guestbook.dto; import lombok.AllArgsConstructor; import lombok.Builder; import lombok.Data; import org.springframework.data.domain.PageRequest; import org.springframework.data.domain.Pageable; import org.springframework.data.domain.Sort; @Builder @AllArgsConstructor @Data public class PageRequestDTO { private int page; private int size; private String type; private String keyword; public PageRequestDTO(){ this.page = 1; this.size = 10; } public Pageable getPageable(Sort sort){ return PageRequest.of(page -1, size, sort); } }
package com.example.guestbook.dto; import lombok.Data; import org.springframework.data.domain.Page; import org.springframework.data.domain.Pageable; import java.util.List; import java.util.function.Function; import java.util.stream.Collectors; import java.util.stream.IntStream; @Data public class PageResultDTO<DTO, EN> { //DTO리스트 private List<DTO> dtoList; //총 페이지 번호 private int totalPage; //현재 페이지 번호 private int page; //목록 사이즈 private int size; //시작 페이지 번호, 끝 페이지 번호 private int start, end; //이전, 다음 private boolean prev, next; //페이지 번호 목록 private List<Integer> pageList; public PageResultDTO(Page<EN> result, Function<EN, DTO> fn){ dtoList = result.stream().map(fn).collect(Collectors.toList()); totalPage = result.getTotalPages(); makePageList(result.getPageable()); } private void makePageList(Pageable pageable){ this.page = pageable.getPageNumber() +1; //0부터 시작이므로 1 추가 this.size = pageable.getPageSize(); //temp end page int tempEnd = (int)(Math.ceil(page/10.0)) * 10; start = tempEnd - 9; prev = start > 1; end = totalPage > tempEnd ? tempEnd : totalPage; next = totalPage > tempEnd; pageList = IntStream.rangeClosed(start,end).boxed().collect(Collectors.toList()); } }
GuestbookService에서는 dto와 entity 간의 변환을 돕는
dto to entity와 entity to dto 외에 기본 CRUD 관련 기능을 모두 Impl 클래스에서 override 하여 구현하고 있는데
사실 이 부분은 그냥 Service 내에서 구현해 줘도 된다... 고 알고 있음
register - 등록
read - 단일 열람(읽기)
remove - 삭제
modify - 수정
getList - 목록 / QBaseEntity(Querydsl query type) 를 통해 검색 조건에 따른 Guestbook 목록을 결과로 보여주고 있음controllerpackage com.example.guestbook.controller; import com.example.guestbook.dto.GuestbookDTO; import com.example.guestbook.dto.PageRequestDTO; import com.example.guestbook.service.GuestbookService; import lombok.RequiredArgsConstructor; import lombok.extern.log4j.Log4j2; import org.springframework.stereotype.Controller; import org.springframework.ui.Model; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.ModelAttribute; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.servlet.mvc.support.RedirectAttributes; @Controller @RequestMapping("/guestbook") @Log4j2 @RequiredArgsConstructor // 자동 주입 annotation public class GuestbookController { private final GuestbookService service; // final 선언 @GetMapping("/") public String index(){ return "redirect:/guestbook/list"; } @GetMapping({"/list"}) public void list(PageRequestDTO pageRequestDTO, Model model){ log.info("list............" + pageRequestDTO); model.addAttribute("result", service.getList(pageRequestDTO)); } @GetMapping("/register") public void register(){ log.info("register get..."); } @PostMapping("/register") public String registerPost(GuestbookDTO dto, RedirectAttributes redirectAttributes){ log.info("dto..." + dto); //새로 추가된 엔티티의 번호 Long gno = service.register(dto); redirectAttributes.addFlashAttribute("msg", gno); return "redirect:/guestbook/list"; } @GetMapping({"/read", "/modify"}) public void read(long gno, @ModelAttribute("requestDTO") PageRequestDTO requestDTO, Model model){ log.info("gno: " +gno); GuestbookDTO dto = service.read(gno); model.addAttribute("dto", dto); } @PostMapping("/remove") public String remove(long gno, RedirectAttributes redirectAttributes){ log.info("gno: ", gno); service.remove(gno); redirectAttributes.addFlashAttribute("msg", gno); return "redirect:/guestbook/list"; } @PostMapping("/modify") public String modify(GuestbookDTO dto, @ModelAttribute("requestDTO") PageRequestDTO requestDTO, RedirectAttributes redirectAttributes){ log.info("post modify....................................."); log.info("dto: " + dto); service.modify(dto); redirectAttributes.addAttribute("page", requestDTO.getPage()); redirectAttributes.addAttribute("type", requestDTO.getType()); redirectAttributes.addAttribute("keyword", requestDTO.getKeyword()); redirectAttributes.addAttribute("gno", dto.getGno()); return "redirect:/guestbook/read"; } }
각 기능에 따른 REST API 처리 방법과 링크를 구분해 요청을 처리한다
ApplicationTests 실행 후에 볼 수 있는 목록 페이지는 이러하다
10개 단위로 글을 볼 수 있으며 각 게시글 번호에 하이퍼링크가 부여되어 있어 단일 조회가 가능하다
초기 페이지 우측의 REGISTER 버튼을 누르면 글을 작성할 수 있으며 제목, 내용, 작성자를 입력한다
앞서 언급한 바와 같이 생성 시간/ 수정 시간은 자동으로 부여된다
검색 시에는 키워드를 구분하여 원하는 게시글을 찾을 수 있다
단일 조회 시에 나오는 화면으로 Modify 버튼을 클릭하면 게시글을 수정 혹은 가능하다
(List는 초기 목록 화면으로)
Modify 버튼 선택 시의 화면인데, html 상에서 textarea와 readonly를 구분하여 수정이 가능한 영역을 구분할 수 있다'SpringBoot' 카테고리의 다른 글
Part 4(Ch 7, 8, 9) - M:N(다대다) 관계와 파일 업로드 처리 (0) 2024.01.15 ch5, 6 - N:1(다대일 관계) 처리하기(+ @RestController와 JSON 처리) (0) 2024.01.02 ch2 - Spring Data JPA (0) 2023.12.21 [5주차] 댓글 CRUD 구현 (0) 2023.12.04 [4주차] 지난 피드백 반영, Git에 코드 올리기 (0) 2023.11.30