본문 바로가기

Program/Spring

Clone_Project -1 (Cookie, 페이징 처리, 글 상세 → 이전 글 목록 페이지)

22.10.28 - Clone_Project -1 (Cookie, 페이징 처리, 글 상세 → 이전 글 목록 페이지)

IntelliJ 단축키


함수 안에 for문이나 함수로 뺄 수 있는거 Ctrl+ Alt + m

Clone


https://github.com/soongu/spring_webprj4.git

Cookie

Service

package com.project.web_prj.board.service;

import com.project.web_prj.board.domain.Board;
import com.project.web_prj.board.repository.BoardRepository;
import lombok.RequiredArgsConstructor;
import lombok.extern.log4j.Log4j2;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.util.WebUtils;

import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.List;

@Service
@Log4j2
@RequiredArgsConstructor
public class BoardService {

    private final BoardRepository repository;

    // 게시물 등록 요청 중간 처리
    public boolean saveService(Board board) {
        log.info("save service start - {}", board);
        return repository.save(board);
    }

    // 게시물 전체 조회 요청 중간 처리
    public List<Board> findAllService() {
        log.info("findAll service start");
        List<Board> boardList = repository.findAll();

        // 목록 중간 데이터처리
        processConverting(boardList);

        return boardList;
    }

    private void processConverting(List<Board> boardList) {
        for (Board b : boardList) {
            convertDateFormat(b);
            substringTitle(b);
        }
    }

    private void convertDateFormat(Board b) {
        Date date = b.getRegDate();
        SimpleDateFormat sdf = new SimpleDateFormat("yy-MM-dd a hh:mm");
        b.setPrettierDate(sdf.format(date));
    }

    private void substringTitle(Board b) {

        // 만약에 글제목이 5글자 이상이라면
        // 5글자만 보여주고 나머지는 ...처리
        String title = b.getTitle();
        if (title.length() > 5) {
            String subStr = title.substring(0, 5);
            b.setShortTitle(subStr + "...");
        } else {
            b.setShortTitle(title);
        }

    }

    // 게시물 상세 조회 요청 중간 처리
    @Transactional
    public Board findOneService(Long boardNo, HttpServletResponse response, HttpServletRequest request) {
        log.info("findOne service start - {}", boardNo);
        Board board = repository.findOne(boardNo);

        // 해당 게시물 번호에 해당하는 쿠키가 있는지 확인
        // 쿠키가 없으면 조회수를 상승시켜주고 쿠키를 만들어서 클라이언트에 전송
        makeViewCount(boardNo, response, request);

        return board;
    }

    private void makeViewCount(Long boardNo, HttpServletResponse response, HttpServletRequest request) {
        // 쿠키를 조회 - 해당 이름의 쿠키가 있으면 쿠키가 들어오고 없으면 null이 들어옴
        Cookie foundCookie = WebUtils.getCookie(request, "b" + boardNo);

        if (foundCookie == null) {
            repository.upViewCount(boardNo);

            Cookie cookie = new Cookie("b" + boardNo, String.valueOf(boardNo));// 쿠키 생성
            cookie.setMaxAge(60); // 쿠키 수명 설정
            cookie.setPath("/board/content"); // 쿠키 작동 범위

            response.addCookie(cookie); // 클라이언트에 쿠키 전송
        }
    }

    // 게시물 삭제 요청 중간 처리
    public boolean removeService(Long boardNo) {
        log.info("remove service start - {}", boardNo);
        return repository.remove(boardNo);
    }

    // 게시물 수정 요청 중간 처리
    public boolean modifyService(Board board) {
        log.info("modify service start - {}", board);
        return repository.modify(board);
    }
}

페이징처리

  • SQL

      --MySQL, MariaDB
    
      <select id="findAll" resultMap="boardMap">
              SELECT * FROM tbl_board
              ORDER BY board_no DESC
              LIMIT #{start},#{amount};
         </select>
      -- 10페이지씩 0부터 10까지
      --#{start} => getStart 메소드를 호출한다. 
  • Page.java

      package com.project.web_prj.common.paging;
    
      import lombok.AllArgsConstructor;
      import lombok.Getter;
      import lombok.ToString;
    
      @ToString @Getter
      @AllArgsConstructor
      // 페이지 정보 클래스
      public class Page {
    
          private int pageNum; // 페이지 번호
          private int amount; // 한 페이지당 배치할 게시물 수
    
          public Page() {
      /*
                  아래의 코드를 설정을 안하면 500에러 즉 sql문법 오류가 뜸=> 값이 나오지 않음
      */
              this.pageNum = 1;
              this.amount = 10;
          }
    
          public int getStart(){
              return (pageNum -1) * amount;
          }
    
      // URL 주소창에 http://localhost:8183/board/list?pageNum=2으로 입력하면 setter가 작동
      //왜 굳이 lombok으로 설정을 안했는가? if문을 처리하기 위해 
          public void setPageNum(int pageNum) {
              if (pageNum <= 0 || pageNum > Integer.MAX_VALUE) {
                  this.pageNum = 1;
                  return;
              }
              this.pageNum = pageNum;
          }
    
          public void setAmount(int amount) {
              if (amount < 10 || amount > 100) {
                  this.amount = 10;
                  return;
              }
              this.amount = amount;
          }
      }
  • PageMaker.java

      package com.project.web_prj.common.paging;
    
      import lombok.Getter;
      import lombok.Setter;
      import lombok.ToString;
    
      // 페이지 렌더링 정보 생성
      @Setter
      @Getter
      @ToString
      public class PageMaker {
    
          // 한번에 그려낼 페이지 수
          private static final int PAGE_COUNT = 10;
    
          // 렌더링시 페이지 시작값, 페이지 끝값
          private int beginPage, endPage;
    
          // 이전, 다음 버튼 활성화 여부
          private boolean prev, next;
    
          private Page page; // 현재 위치한 페이지 정보
          private int totalCount; // 총 게시물 수
    
          public PageMaker(Page page, int totalCount) {
              this.page = page;
              this.totalCount = totalCount;
              makePageInfo();
          }
    
          // 페이지 정보 생성 알고리즘
          private void makePageInfo() {
    
              //1. endPage 계산
              // 올림처리 (현재 위치한 페이지번호 / 한 화면에 배치할 페이지수 ) *  한 화면에 배치할 페이지 수
              this.endPage = (int) (Math.ceil(page.getPageNum() / (double)PAGE_COUNT) * PAGE_COUNT);
    
              //2. beginPage 계산
              this.beginPage = endPage - PAGE_COUNT + 1;
    
              /*
    
              - 총 게시물수가 237개고, 한 화면당 10개의 게시물을 배치하고 있다면
                페이지 구간은
    
                1 ~ 10페이지 구간 : 게시물 100개
                11 ~ 20페이지 구간: 게시물 100개
                21 ~ 24페이지 구간: 게시물 37개
    
              - 마지막 페이지 구간에서는 보정이 필요함.
    
              - 마지막 구간 끝페이지 보정 공식:
                올림처리(총 게시물 수 / 한 페이지당 배치할 게시물 수)
    
               */
              int realEnd = (int)Math.ceil((double) totalCount / page.getAmount());
    
              // 그러면 끝 페이지보정은 언제 일어나야 하는가
              // 마지막 페이지 구간에서 일어날수도 있고 아닐수도 있다
              if (realEnd < endPage) {
                  this.endPage = realEnd;
              }
    
              // 이전 버튼 활성화 여부
              this.prev = beginPage > 1;
    
              // 다음 버튼 활성화 여부
              this.next = endPage < realEnd;
          }
      }
    
  • Service.java

      // 게시물 전체 조회 요청 중간 처리 with paging
          public Map<String, Object> findAllService(Page page) {
              log.info("findAll service start");
    
              Map<String, Object> findDataMap = new HashMap<>();
    
              List<Board> boardList = repository.findAll(page);
              // 목록 중간 데이터 처리
              processConverting(boardList);
    
              findDataMap.put("bList", boardList);
              findDataMap.put("tc", repository.getTotalCount());
    
              return findDataMap;
          }
  • Controller.java

      // 게시물 목록 요청
          @GetMapping("/list")
          public String list(Page page, Model model) {
              log.info("controller request /board/list GET! - page: {}", page);
    
              Map<String, Object> boardMap = boardService.findAllService(page);
              log.debug("return data - {}", boardMap);
    
              // 페이지 정보 생성
              PageMaker pm = new PageMaker(page, (Integer) boardMap.get("tc"));
    
              model.addAttribute("bList", boardMap.get("bList"));
              model.addAttribute("pm", pm);
    
              return "board/board-list";
          }
  • board-list.jsp

      <!-- 페이지 버튼 영역 -->
                      <nav aria-label="Page navigation example">
                          <ul class="pagination pagination-lg pagination-custom">
    
                              <c:if test="${pm.prev}">
                                  <li class="page-item"><a class="page-link"
                                          href="/board/list?pageNum=${pm.beginPage - 1}&amount=${pm.page.amount}">prev</a></li>
                              </c:if>
                                                      <!--for(int n=1; n<=10; n++)-->
                              <c:forEach var="n" begin="${pm.beginPage}" end="${pm.endPage}" step="1">
                                  <li data-page-num="${n}" class="page-item">
                                      <a class="page-link" href="/board/list?pageNum=${n}&amount=${pm.page.amount}">${n}</a>
                                  </li>
                              </c:forEach>
    
                              <c:if test="${pm.next}">
                                  <li class="page-item"><a class="page-link"
                                          href="/board/list?pageNum=${pm.endPage + 1}&amount=${pm.page.amount}">next</a></li>
                              </c:if>
    
                          </ul>
                      </nav>

글 상세에서 이전 목록으로

  • Controller

      // 게시물 상세 조회 요청
          @GetMapping("/content/{boardNo}")
          public String content(@PathVariable Long boardNo
                  , Model model, HttpServletResponse response, HttpServletRequest request
                  , @ModelAttribute("p") Page page //받은걸 바로 p에 담는다
          ) {
              log.info("controller request /board/content GET! - {}", boardNo);
              Board board = boardService.findOneService(boardNo, response, request);
              log.info("return data - {}", board);
              model.addAttribute("b", board);
              return "board/board-detail";
          }
  • detail.jsp

      //목록버튼
              $listBtn.onclick = e => {
                  location.href = '/board/list?pageNum=${p.pageNum}&amount=${p.amount}';
              };