본문 바로가기

Server Programming/Spring Boot Backend Programming

4장-3. 스프링 Web MVC 구현 (2) 페이징 처리 (+ 백틱)

반응형

요구사항

페이징 처리

 


페이징

  1. DTO
    • PageRequestDTO
    • PageResponseDTO
  2.  TodoMapper -limit(), count()
    • TodoMapper의 목록 처리
    • TodoMapper의 count 처리
  3. TodoService
  4. TodoController
  5. 목록 페이지 JSP 작성
  6. CRUD 연동

limit을 이용한 페이징 구현 원리

많은 데이터 -> 페이징 처리를 통해 최소한의 데이터만을 출력

 

: DB에서 필요한 데이터만 가져와 SQL 입출력을 최소화한다.

 

-MySQL, MariaDB에서는 limit이라는 기능을 이용해 페이징 처리가 가능하다.

 

limit()

  • 파라미터를 하나 혹은 두개를 받는다.
    • 하나일 경우 : select * from tbl_todo order by tno desc limit 10;
      -> 가져오는 데이터 수만을 이용 [첫 페이지]
    • 두개일 경우 : select * from tbl_todo order by tno desc limit 10, 10;
      -> 건너뛰는 데이터 수와 가져오는 데이터 수 [첫 페이지를 제외한 페이지]

따라서, skip할 데이터의 수는 : (i-1)페이지*10로 첫 페이지를 제외한 페이지에 표현식을 적용한다.

  1. select * from tbl_todo order by tno desc limit 10;
  2. select * from tbl_todo order by tno desc limit 10, 10;
  3. select * from tbl_todo order by tno desc limit 20, 10;
  4. select * from tbl_todo order by tno desc limit 30, 10;
  5. select * from tbl_todo order by tno desc limit 40, 10;

하지만, limit의 경우 식을 사용할 수 없고, 반드시 값만 받을 수 있기 때문에

select * from tbl_todo order by tno desc limit(2-1*10), 10;

과 같은 SQL문은 처리가 불가능하다.

 

 

count()

limit과 함께 페이징을 구현하기 위해 사용하는 전체 데이터 수를 반환하는 함수

전체 데이터 수를 이용해 마지막 페이징 번호를 알 수 있다.

 

 


PageRequestDTO와 PageResponseDTO

javax.validation을 이용해 데이터의 구간을 지정할 수 있다.

 

1. PageRequestDTO 작성

  • page : 현재 페이지 번호
    • 1페이지 ~ (전체 데이터 수/size)까지
    • 기본값 @Builder.default, @Min 최소 1, @Positive 양수만 가능
  • size : 한 페이지당 보여주는 데이터 수
    • 설정가능한 한 페이지당 보여줄 데이터 개수 
    • 한 페이지당 10개에서 ~100개까지
    • 기본값 @Builder.default, @Min 최소 10 ~ @Max 최대 100, @Positive 양수만 가능
  • getSkip() : limit에서 사용하는 건너뛰는 페이지 수를 반환하는 메서드

-DTO이므로, : @Data (@Getter, @Setter, @ToString)

-DTO, VO는 파라미터를 모두 갖거나 하나도 없을 때 생성자 생성 : @NoArgsConstructor, @AllArgsConstructor

-Builder 패턴을 이용해 객체 생성 : @Builder

 

@Builder
@Data
@AllArgsConstructor
@NoArgsConstructor
public class PageRequestDTO {

    @Builder.Default
    @Min(value = 1)
    @Positive
    private int page = 1;

    @Builder.Default
    @Min(value = 10)
    @Max(value = 100)
    @Positive
    private int size = 10;

    public int getSkip(){

        return (page -1) * 10;
    }
}

 

2. PageResponseDTO 작성

-직접 DTO를 작성하는 것보다 생성자를 이용해 안전하게 처리하는 것을 목적으로 작성한다.

-@Getter : 생성자를 이용하므로, 직접 Setter를 작성할 필요가 없다.

-@Builder :  PageRequestDTO와 List<TodoDTO>, 전체 데이터 개수를 이용한 생성자 작성하는 어노테이션

 

PageResponseDTO 구성 요소

  • TodoDTO의 목록
  • 전체 데이터 수
  • 페이지 번호의 처리를 위한 데이터들 (시작 페이지 번호 / 끝 페이지 번호)

 

 

PageResponseDTO 구현

  • page : 현재 페이지 번호
  • size : 한 페이지당 보여주는 데이터 수
  • total : 전체 데이터 수
  • start : 시작 페이지 번호
  • end : 마지막 페이지 번호

  • prev : 이전 페이지 존재 여부
  • next : 이후 페이지 존재 여부

  • dtoList : 현재 페이지의 객체들을 담은 리스트
  • @Builder 어노테이션을 이용해 작성한 생성자
    • page, size는 DTO를 통해, total과 dtolist는 직접 받는다.
    • start, end의 경우, 열 개의 페이지 번호를 제공한다고 가정해
      먼저 마지막 페이지를 구하고 마지막 페이지를 통해 start 페이지를 찾는다.

      -> end : 올림한 (현재 페이지/10.0) * 10
      -올림을 하는 이유는 페이지는 데이터가 하나라도 존재한다면 페이지 수가 필요하기 때문이다.
      -> start : 마지막 페이지로부터 -9번째

    • 중요한건 마지막 페이지가 존재하지 않을 수도 있다는 것이다
      -> 페이지 개수가 10개보다 적을 수도 있기 때문에, 직접 마지막 번호를 구해 비교한다.

      last : 올림한 (전체 페이지수/한 페이지당 보여주는 데이터 수)
      -올림을 하는 이유는 페이지는 데이터가 하나라도 존재한다면 페이지 수가 필요하기 때문이다.
      end : last변수를 이용해 마지막 페이지 번호가 last번호보다 크면 last번호를 마지막 번호로 지정한다.
    • prev : 1페이지보다 크면 이전 페이지가 존재하고,
      next : 전체 데이터 수가 마지막 페이지 * 한 페이지당 보여주는 데이터 수 보다 크면 다음 페이지가 존재한다.
package org.zerock.springex.dto;

import lombok.Builder;
import lombok.Getter;
import lombok.ToString;

import java.util.List;

@Getter
@ToString
public class PageResponseDTO<E> {

    private int page;
    private int size;
    private int total;

    //시작 페이지 번호
    private int start;
    //끝 페이지 번호
    private int end;

    //이전 페이지의 존재 여부
    private boolean prev;
    //다음 페이지의 존재 여부
    private boolean next;

    private List<E> dtoList;

    @Builder(builderMethodName = "withAll")
    public PageResponseDTO(PageRequestDTO pageRequestDTO, List<E> dtoList, int total){

        this.page = pageRequestDTO.getPage();
        this.size = pageRequestDTO.getSize();

        this.total = total;
        this.dtoList = dtoList;

        this.end =   (int)(Math.ceil(this.page / 10.0 )) *  10;

        this.start = this.end - 9;

        int last =  (int)(Math.ceil((total/(double)size)));

        this.end =  end > last ? last: end;

        this.prev = this.start > 1;

        this.next =  total > this.end * this.size;

    }

}

 


TodoMapper

  1. PageRequestDTO를 이용해 목록 처리
  2. PageRequestDTO를 이용해 페이지 번호 구성

 

1. TodoMapper에서 PageRequestDTO를 이용해 목록 처리

 

(1) selectList() 메서드 추가

   <select id="selectList" resultType="org.zerock.springex.domain.TodoVO">
        select * from tbl_todo order by tno desc limit #{skip}, #{size};
    </select>

-> limit 함수를 이용해 SQL문 작성

 

(2) 테스트 코드 작성

    @Test
    public void testSelectPaging(){
        PageRequestDTO pageRequestDTO= PageRequestDTO.builder()
                .page(1)
                .size(10)
                .build();
        List<TodoVO> voList=todoMapper.selectList(pageRequestDTO);

        voList.forEach(vo -> log.info(vo));
    }

 

2. PageRequestDTO를 이용해 페이지 번호 구성

(1) TodoMapper에 getCount() 추가

-추후에 검색 기능 추가를 위해 PageRequestDTO를 파라미터로 받는다.

    int getCount(PageRequestDTO pageRequestDTO);

 

    <select id="getCount" resultType="int">
        select count(tno) from tbl_todo;
    </select>

 

(2) 테스트 코드 작성

    @Test
    public void testGetCount(){
        PageRequestDTO pageRequestDTO= PageRequestDTO.builder()
                .page(1)
                .size(10)
                .build();
        int count = todoMapper.getCount(pageRequestDTO);
        log.info(count);
    }

TodoService

-PageRequestDTO를 파라미터로 받아, PageResponsDTO를 반환타입으로 하는 getList() 작성

-List<TodoDTO>, total, PageRequestDTO를 파라미터로 전달해 PageResponseDTO 생성자 호출

 

-List<TodoVO> : PageRequestDTO를 파라미터로 전달해, selectList() 호출 

-List<TodoDTO> : 스트림으로 List<TodoVO> -> List<TodoDTO> 변환

-total : PageRequestDTO를 파라미터로 전달해 getCount() 호출

 

(1) TodoService에 getList() 작성

PageResponseDTO getList(PageRequestDTO pageRequestDTO);

 

    @Override
    public PageResponseDTO getList(PageRequestDTO pageRequestDTO) {
        //PageRequestDTO를 통해 PageResponseDTO 생성자를 이용해 객체 생성해야하므로
        //PageResponseDTO의 생성자에 필요한 파라미터 :
        // TodoDTO의 목록, 전체 데이터 수, 페이지 번호의 처리를 위한 데이터들 (시작 페이지 번호 / 끝 페이지 번호)

        //1. List<TodoVO> -> List<TodoDTO>
        List<TodoVO> voList=todoMapper.selectList(pageRequestDTO);
        List<TodoDTO> dtoList=voList.stream()
                .map(vo -> modelMapper.map(vo, TodoDTO.class))
                .collect(Collectors.toList());

        //2. total
        int total = todoMapper.getCount(pageRequestDTO);

        //생성자를 이용해 객체 생성
        PageResponseDTO<TodoDTO> pageResponseDTO=
                PageResponseDTO.<TodoDTO>withAll()
                        .dtoList(dtoList)
                        .total(total)
                        //3. 페이지 번호의 처리를 위한 데이터들
                        .pageRequestDTO(pageRequestDTO)
                        .build();

        return pageResponseDTO;
    }

 

 

(2) 테스트 코드 작성

    @Test
    public void testPaging(){
        //PageResponseDTO의 생성자에 필요한 파라미터 :
        // TodoDTO의 목록, 전체 데이터 수, 페이지 번호의 처리를 위한 데이터들 (시작 페이지 번호 / 끝 페이지 번호)

        //페이지 번호의 처리를 위한 데이터들
        PageRequestDTO pageRequestDTO= PageRequestDTO.builder()
                .page(1)
                .size(10)
                .build();
        
        PageResponseDTO<TodoDTO> pageResponseDTO = todoService.getList(pageRequestDTO);
        
        log.info(pageResponseDTO);
        
        pageResponseDTO.getDtoList().stream().forEach(todoDTO -> log.info(todoDTO));
    }

TodoController

1. TodoController에서 list() 메서드 작성

-PageRequestDTO를 받아 @Valid을 이용해 검증하고, 검증에 걸리면 BindingResultSet에, 검증에 통과하면 Model에 담는다.

변경 전, list() 메서드

    @RequestMapping("/list")
    public void list(Model model){

        log.info("todo list.......");

        model.addAttribute("dtoList", todoService.getAll());
    }

 

변경 후, list() 메서드

-@Valid를 통해, 유효하지 않는 데이터가 전달되면 빌더패턴을 이용해 기본값으로 생성한 객체를 전달한다. (@Builder.default)

@GetMapping("/list")
    public void list(@Valid PageRequestDTO pageRequestDTO, BindingResult bindingResult, Model model){

        log.info(pageRequestDTO);

        if(bindingResult.hasErrors()){
            pageRequestDTO = PageRequestDTO.builder().build();
        }
        model.addAttribute("responseDTO", todoService.getList(pageRequestDTO));
    }

-list() 메서드가 기존의 dtoList가 아닌 PageResponseDTO를 반환하므로, list.jsp도 변경해야한다.

 


목록 페이지 JSP 작성

 

1. 목록 출력 부분을 dtoList에서 responseDTO.dtoList로 변경

   <c:forEach items="${responseDTO.dtoList}" var="dto">
                                <tr>
                                    <th scope="row"><c:out value="${dto.tno}"/></th>
                                    <td>
                                        <a href="/todo/read?tno=${dto.tno}" class="text-decoration-none">
                                            <c:out value="${dto.title}"/>
                                        </a>
                                    </td>
                                    <td><c:out value="${dto.writer}"/></td>
                                    <td><c:out value="${dto.dueDate}"/></td>
                                    <td><c:out value="${dto.finished}"/></td>
                                </tr>
                            </c:forEach>

 

2. 페이지 번호와 페이지 이동 처리

-페이지 이동 확인

http://localhost:8080/todo/list?page=2&size=10 으로 페이지 이동 확인

 

(1) 화면에 페이지 이동을 위한 번호 출력

https://getbootstrap.kr/docs/5.1/components/pagination/

 

페이지네이션

여러 페이지에 일련의 관련 내용이 있음을 나타내는 페이지네이션을 사용한 문서와 예시입니다.

getbootstrap.kr

 

페이지네이션 기본 문법

<nav aria-label="Page navigation example">
  <ul class="pagination">
    <li class="page-item"><a class="page-link" href="#">Previous</a></li>
    <li class="page-item"><a class="page-link" href="#">1</a></li>
    <li class="page-item"><a class="page-link" href="#">2</a></li>
    <li class="page-item"><a class="page-link" href="#">3</a></li>
    <li class="page-item"><a class="page-link" href="#">Next</a></li>
  </ul>
</nav>

 

-list.jsp에 <table> 태그 다음에 <div>를 구성해 화면 작성

- responseDTO를 받아 <c:forEach>를 이용해 반복문 처리

  • <c:forEach>의 속성들은 EL 표현식을 이용해 처리한다.
    • begin : "${responseDTO.start}"
    • end : "${responseDTO.end}"
    • var : "num"
<div class="float-end">
    <ul class="pagination flex-wrap">

        <c:forEach begin="${responseDTO.start}" end="${responseDTO.end}" var="num">
            <li class="page-item">
                <a class="page-link" href="#">${num}</a></li>
        </c:forEach>

    </ul>

</div>

 

(2) 화면에 prev/next/현재 페이지 처리

- responseDTO를 받아 <c:if>를 이용해 조건문 처리

  • <c:if>의 속성들은 EL 표현식을 이용해 처리한다.
  • <c:if>를 이용하면 참이면, 수행하고 거짓이면 수행하지 않기 때문에 노출처리를 담당한다.
    • test : "${reponseDTO.prev}" / "${reponseDTO.next}"
      -> 해당 값이 참이라면 다음 문장 실행
<div class="float-end">
    <ul class="pagination flex-wrap">
        <c:if test="${responseDTO.prev}">
            <li class="page-item">
                <a class="page-link"}">Previous</a>
            </li>
        </c:if>

        <c:forEach begin="${responseDTO.start}" end="${responseDTO.end}" var="num">
            <li class="page-item">
                <a class="page-link">${num}</a></li>
        </c:forEach>

        <c:if test="${responseDTO.next}">
            <li class="page-item">
                <a class="page-link">Next</a>
            </li>
        </c:if>
    </ul>

</div>

 

(3) 페이지의 이벤트 처리

-자바스크립트를 이용해 화면에서 페이지 번호 클릭시 이동하는 처리

- <a>태그에 직접 onclick 적용하는 것보다, <ul>태그에 이벤트 처리하는 것이 코드의 중복을 방지할 수 있다.

 

(3-1) 각 페이지 번호 처리

-'data-' 속성을 이용해 필요한 속성 추가

-'data-num' 속성으로 페이지 번호를 보관하도록 구성

<div class="float-end">
    <ul class="pagination flex-wrap">
        <c:if test="${responseDTO.prev}">
            <li class="page-item">
                <a class="page-link" data-num="${responseDTO.start -1}">Previous</a>
            </li>
        </c:if>

        <c:forEach begin="${responseDTO.start}" end="${responseDTO.end}" var="num">
            <li class="page-item ${responseDTO.page == num? "active":""} ">
                <a class="page-link"  data-num="${num}">${num}</a></li>
        </c:forEach>

        <c:if test="${responseDTO.next}">
            <li class="page-item">
                <a class="page-link"  data-num="${responseDTO.end + 1}">Next</a>
            </li>
        </c:if>
    </ul>

</div>

 

(3-2) <ul>태그가 끝난 부분에 자바스크립트를 이용해 이벤트 처리 

-자바스크립트를 통해 이벤트 처리를 하는 이유:

각각의 데이터에 대해 미리 링크 처리를 하는 것이 아니라

<ul>태그에 이벤트를 등록하고, <a> 태그 클릭 시 해당 이벤트를 처리를 수행하도록 

 

<a> 태그 클릭시 이벤트 처리 동작 과정

  1. 해당 태그의 data-num 속성 값을 읽어온다.
  2. 현재 주소인 self.location을 변경한다.
  3. (``) 백틱를 이용해 문자열 결합에 '+'를 이용하지 않고, 문자열 결합을 수행한다.
    단, 백틱을 사용할 경우 EL 표현식이 아니기 때문에 "#{ ~ }"를 사용한다.
<script>
    document.querySelector(".pagination").addEventListener("click", function (e) {
            e.preventDefault()
            e.stopPropagation()

            const target = e.target


            if(target.tagName !== 'A') {
                return
            }
            const num = target.getAttribute("data-num")

            self.location = `/todo/list?page=\${num}` //백틱(` `)을 이용해서 템플릿 처리
        },false)
</script>

 


CRUD 연동

PageRequestDTO를 활용해 페이지 이동처리

 

(1) 조회 페이지로의 이동 처리

  • PageRequestDTO 변경
  • list.jsp 변경

 

PageRequestDTO 변경

-페이지 이동정보를 담는 문자열 변수인 쿼리스트링 link 추가 -> "page=1&size=10"

-페이지 이동정보를 전달하는 getLink() 메서드 작성

@Builder
@Data
@AllArgsConstructor
@NoArgsConstructor
public class PageRequestDTO {

    @Builder.Default
    @Min(value = 1)
    @Positive
    private int page = 1;

    @Builder.Default
    @Min(value = 10)
    @Max(value = 100)
    @Positive
    private int size = 10;
	private String link;


    public int getSkip(){

        return (page -1) * 10;
    }

    public String getLink() {
        if(link == null){
            StringBuilder builder = new StringBuilder();

            builder.append("page=" + this.page);

            builder.append("&size=" + this.size);
            link = builder.toString();
        }
        return link;
    }
}

 

 

list.jsp 변경

-PageRequestDTO의 link 변수를 이용해, 기존 링크에 page와 size를 추가한 페이지 이동 링크 처리

 

변경 전, list.jsp

  <c:forEach items="${responseDTO.dtoList}" var="dto">
    <tr>
        <th scope="row"><c:out value="${dto.tno}"/></th>
        <td>
            <a href="/todo/read?tno=${dto.tno}" class="text-decoration-none">
                <c:out value="${dto.title}"/>
            </a>
        </td>
        <td><c:out value="${dto.writer}"/></td>
        <td><c:out value="${dto.dueDate}"/></td>
        <td><c:out value="${dto.finished}"/></td>
    </tr>
</c:forEach>

변경 후, list.jsp

 <c:forEach items="${responseDTO.dtoList}" var="dto">
    <tr>
        <th scope="row"><c:out value="${dto.tno}"/></th>
        <td>
            <a href="/todo/read?tno=${dto.tno}&${pageRequestDTO.link}" class="text-decoration-none" data-tno="${dto.tno}">
                <c:out value="${dto.title}"/>
            </a>
        </td>
        <td><c:out value="${dto.writer}"/></td>
        <td><c:out value="${dto.dueDate}"/></td>
        <td><c:out value="${dto.finished}"/></td>
    </tr>
</c:forEach>

 

(2) 조회에서 목록으로 이동 처리

  • TodoController 변경
  • read.jsp 이벤트 처리

TodoController 변경

 

변경 전, read()

@GetMapping({"/read", "/modify"})
public void read(Long tno, Model model){

    TodoDTO todoDTO = todoService.getOne(tno);
    log.info(todoDTO);

    model.addAttribute("dto", todoDTO );

}

 

변경 후, read()

    @GetMapping({"/read", "/modify"})
    public void read(Long tno, PageRequestDTO pageRequestDTO, Model model){

        TodoDTO todoDTO = todoService.getOne(tno);
        log.info(todoDTO);

        model.addAttribute("dto", todoDTO );

    }

 

read.jsp 이벤트 처리

-'List' 버튼 링크 변경

 

변경 전, 'List' 버튼 이동 링크

document.querySelector(".btn-secondary").addEventListener("click", function(e){
    self.location = "/todo/list";
},false)

 

변경 후, 'List' 버튼 이동 링크

//목록 페이지로 이동하는 이벤트 처리
document.querySelector(".btn-secondary").addEventListener("click", function(e){

    self.location = "/todo/list?${pageRequestDTO.link}"

},false)

 

(3) 조회에서 수정으로 이동 처리

  • read.jsp 이벤트 처리

변경 전, 'Modify' 버튼 이동 링크

document.querySelector(".btn-primary").addEventListener("click", function(e){
    self.location = "/todo/modify?tno="+${dto.tno}
},false)

 

변경 후, 'Modify' 버튼 이동 링크

document.querySelector(".btn-primary").addEventListener("click", function(e){

    self.location = `/todo/modify?tno=${dto.tno}&${pageRequestDTO.link}`

},false)

 

(4) 수정 화면에서의 링크 처리

  • modify.jsp 이벤트 처리

modify.jsp 이벤트 처리

 

변경 전, 'List' 버튼 이동 링크

document.querySelector(".btn-secondary").addEventListener("click",function(e) {

    e.preventDefault()
    e.stopPropagation()

    self.location = "/todo/list";

},false);

 

변경 후, 'List' 버튼 이동 링크

document.querySelector(".btn-secondary").addEventListener("click",function(e) {

    e.preventDefault()
    e.stopPropagation()

    self.location = "/todo/list?${pageRequestDTO.link}"

},false);

 

(5) 수정/삭제 처리 후 페이지 이동 처리 (PRG 패턴)

  • modify.jsp에서 PageReqeustDTO 데이터 전달
  • TodoController에서 전달받은 PageReqeustDTO를 이용해 remove() 메서드에서 페이지 이동 처리

modify.jsp에서 PageReqeustDTO 데이터 전달

<form action="/todo/modify" method="post">
    <input type="hidden" name="page" value="${pageRequestDTO.page}}">
    <input type="hidden" name="size" value="${pageRequestDTO.size}}">

 

TodoController에서 전달받은 PageReqeustDTO를 이용해 remove() 메서드에서 페이지 이동 처리

 

처음 remove()

@PostMapping("/remove")
public String remove(Long tno, RedirectAttributes redirectAttributes){

    log.info("-------------remove------------------");
    log.info("tno: " + tno);

    todoService.remove(tno);

    return "redirect:/todo/list";
}

 

변경 전, remove()

@PostMapping("/remove")
public String remove(Long tno, PageRequestDTO pageRequestDTO, RedirectAttributes redirectAttributes){

    log.info("-------------remove------------------");
    log.info("tno: " + tno);

    todoService.remove(tno);

    return "redirect:/todo/list?" + pageRequestDTO.getLink();
}

 

변경 후, remove()

-삭제 처리에 PageRequestDTO를 이용해 <form> 태그 정보를 수집해 목록 페이지 이동시 page는 1페이지로 이동해서 size정보 활용

@PostMapping("/remove")
public String remove(Long tno, PageRequestDTO pageRequestDTO, RedirectAttributes redirectAttributes){

    log.info("-------------remove------------------");
    log.info("tno: " + tno);

    todoService.remove(tno);

    redirectAttributes.addAttribute("page", 1);
    redirectAttributes.addAttribute("size", pageRequestDTO.getSize());
    return "redirect:/todo/list";
}

 

(6) 수정 처리 후 이동 처리 (PRG 패턴)

  • TodoController에서 전달받은 PageReqeustDTO를 이용해 modify() 메서드에서 페이지 이동 처리

TodoController에서 전달받은 PageReqeustDTO를 이용해 modify() 메서드에서 페이지 이동 처리

 

변경 전, modify()

@PostMapping("/modify")
public String modify(@Valid TodoDTO todoDTO,
                     BindingResult bindingResult,
                     RedirectAttributes redirectAttributes){

    if(bindingResult.hasErrors()) {
        log.info("has errors.......");
        redirectAttributes.addFlashAttribute("errors", bindingResult.getAllErrors() );
        redirectAttributes.addAttribute("tno", todoDTO.getTno() );
        return "redirect:/todo/modify";
    }

    log.info(todoDTO);

    todoService.modify(todoDTO);

    return "redirect:/todo/list";
}

 

변경 후, modify()

-수정 후 목록 이동시에 PageRequestDTO를 이용해 page와 size정보를 유지할 수 있도록 구성

@PostMapping("/modify")
public String modify(@Valid TodoDTO todoDTO,
                     PageRequestDTO pageRequestDTO,
                     BindingResult bindingResult,
                     RedirectAttributes redirectAttributes){

    if(bindingResult.hasErrors()) {
        log.info("has errors.......");
        redirectAttributes.addFlashAttribute("errors", bindingResult.getAllErrors() );
        redirectAttributes.addAttribute("tno", todoDTO.getTno() );
        return "redirect:/todo/modify";
    }

    log.info(todoDTO);

    todoService.modify(todoDTO);

    redirectAttributes.addAttribute("page", pageRequestDTO.getPage());
    redirectAttributes.addAttribute("size", pageRequestDTO.getSize());

    return "redirect:/todo/list";
}

 

반응형