5. 페이징 처리를 위한 TodoMapper
- Todo 데이터 수가 많아지면 목록 페이지를 가져올 때 많은 시간과 자원이 소모됨
- 많은 데이터를 보여주는 작업은 페이징 처리를 해서 최소한의 데이터들을 보여주는 방식 선호
- 페이징 처리에서 중요한 것은 데이터베이스에서 필요한 데이터만 가져오도록 하는 것
- MySQL, MariaDB에서는 limit라는 기능을 이용해서 비교적 쉽게 페이징 처리 구현 가능
1) 페이징을 위한 SQL 연습
- 더미 데이터 추가: 기존에 데이터베이스에 있던 데이터를 여러번 복사하여 생성
insert into tbl_todo (title, dueDate, writer) (select title, dueDate, writer from tbl_todo);
- limit 실습
- MariaDB / MySQL에서 페이징 처리를 위해 select의 마지막 부분에 limit 처리를 이용
- limit뒤에는 하나 또는 두 개의 값 전달
- 첫번째 값: 건너뛰는 데이터 수(skip)
- 두번째 값: 가져오는 데이터 수(fetch)
- 하나의 값만 전달할 때: 가져오는 데이터 수만 전달
- 먼저 가장 마지막에 등록된 데이터부터 순차적으로 보여지도록 tno를 기준으로 내림차순 정렬
select * from tbl_todo order by tno desc limit 10;

- 처음 10개를 건너뛰고 나온 다음 10개를 출력하면 처음 10개의 마지막 숫자 4579 다음의 숫자인 4578에서 시작
select * from tbl_todo order by tno desc limit 10, 10;

- 위와 같은 규칙으로
- 1페이지: limit 10;
- 2페이지: limit 10, 10;
- 3페이지: limit 20, 10;
- 4페이지: limit 30, 10;
- ....
- limit의 단점
- limit 뒤에 식 사용 불가, 오직 값만 주어야 함(limit (2-1)*10, 10; 등의 식은 실행되지 않음)
- count의 필요성
- 페이징 처리를 하기 위해 전체 데이터의 개수도 필요
- 전체 데이터의 개수는 페이지 번호를 구성할 때 필요(30개의 데이터가 있으면 3페이지까지 출력해야하는 등)
2) 페이지 퍼리를 위한 DTO
- 페이지 퍼리는 현재 페이지 번호, 한 페이지당 보여주는 데이터 개수가 기본적으로 필요
- 2개의 숫자를 매번 전달할 수도 있지만 확장을 고려하여 별도의 DTO로 만들어 두는 것이 좋음
- dto 패키지에 PageRequestDTO 클래스 정의
// PageRequestDTO
package org.zerock.springex.dto;
import lombok.*;
import javax.validation.constraints.Max;
import javax.validation.constraints.Min;
import javax.validation.constraints.Positive;
@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;
// limit에서 사용하는 건너뛰기의 수
public int getSkip() {
return (page-1) * 10;
}
}
3) TodoMapper의 목록 처리
- TodoMapper 인터페이스는 PageRequestDTO를 파라미터로 처리하는 selectList()를 추가
// TodoMapper
package org.zerock.springex.mapper;
import ...
public interface TodoMapper {
...
List<TodoVO> selectList(PageRequestDTO pageRequestDTO);
}
<!-- TodoMapper.xml -->
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTO Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace = "org.zerock.springex.mapper.TodoMapper">
...
<select id = "selectList" resultType = "org.zerock.springex.domain.TodoVO">
<!-- MyBatis는 기본적으로 getXXX, setXXX를 통해 작동하므로 #{skip}은 getSkip()을 호출하게됨 -->
select * from tbl_todo order by tno desc limit #{skip}, #{size}
</select>
</mapper>
- TodoMapperTests에 테스트 코드를 작성하여 selectList() 작동 확인
// TodoMapperTests
@Test
public void testSelectList() {
PageRequestDTO pageRequestDTO = PageRequestDTO.builder()
.page(1)
.size(10)
.build();
List<TodoVO> voList = todoMapper.selectList(pageRequestDTO);
voList.forEach(vo -> log.info(vo));
}

4) TodoMapper의 count 처리
- 화면에 페이지 번호들을 구성하기 위해 전체 데이터수 확인 필요
- TodoMapper에 getCount() 추가하고, 검색을 대비해 PageRequestDTO를 파라미터로 받도록 설계
// TodoMapper
package org.zerock.springex.mapper;
import ...
public interface TodoMapper {
...
int getCount(PageRequestDTO pageRequestDTO);
}
- TodoMappe.xml은 우선 전체 개수를 반환하도록 구성
<!-- TodoMapper.xml -->
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTO Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace = "org.zerock.springex.mapper.TodoMapper">
...
<select id = "getCount" resultType = "int">
select count(tno) from tbl_todo
</select>
</mapper>
6. 목록 데이터를 위한 DTO와 서비스 계층
- TodoMapper에서 TodoVO의 목록과 전체 데이터 수를 가져온다면 이를 서비스 계층에서 한 번에 담아서 처리하도록 DTO를 구성하는 것이 좋음
- PageResponseDTO라는 이름으로 생성하고 다음의 데이터와 기능을 가지도록 구성
- TodoDTO 목록
- wjscp epdlxj tn
- 페이지 번호 처리를 위한 데이터(시작 페이지 번호 / 끝 페이지 번호)
// PageResponseDTO
package org.zerock.springex.dto;
import java.util.List;
// 제네릭을 이용해서 설계
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;
}
- 제네릭을 이용하는 이유는 나중에 다른 종류의 객체를 이용해서 PageResponseDTO를 구성할 수 있도록 하기 위함
- PageResponseDTO는 여러 정보를 생성자를 이용해서 받아서 처리하는 것이 안전
예를 들어, PageRequestDTO에 있는 page, size 값이 필요하고, TodoDTO 목록 데이터와 전체 데이터 개수도 필요
// PageResponseDTO
package org.zerock.springex.dto;
import ...
public class PageResponseDTO<E> {
...
// PageResponseDTO의 생성자
@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;
}
}
1) 페이지 번호의 계산
- 페이지 번호를 계산하려면 우선 현재 페이지의 번호(page)가 필요
- 현재 페이지가 1~10 사이인 경우, 시작 페이지는 1, 마지막 페이지는 10
- 현재 페이지가 11~20 사이인 경우, 시작 페이지는 11, 마지막 페이지는 20
- 마지막 페이지 / 시작 페이지 번호의 계산
- 마지막 페이지 먼저 구하기
// 현재 페이지(page)를 10으로 나눈 값을 올림 처리한 후 * 10
this.end = (int)(Math.ceil(this.page / 10.0)) * 10;
// 결과
1 / 10 ====> 0.1 =="올림"==> 1 =="*10"==> 10
11 / 10 ====> 1.1 =="올림"==> 2 =="*10"==> 20
10 / 10 ====> 1 =="올림"==> 1 =="*10"==> 10
- 시작 페이지는 마지막 페이지에서 - 9
this.start = this.end - 9;
- 마지막 페이지의 경우 전체 개수(total)를 고려
게시물을 10개씩 보여주는 경우, 전체 개수가 75라면 마지막 페이지는 8이 되어야 함
int last = (int)(Math.ceil(total / (double)size));
// 결과
123 / 10.0 ====> 12.3 =="올림"==> 13
100 / 10.0 ====> 10.0 =="올림"==> 10
75 / 10.0 ====> 7.5 =="올림"==> 8
- 마지막 페이지(end)가 last보다 크면 last가 end값으로 되어야 함
this.end = end > last ? last : end
- 이전(prev) / 다음(next)의 계산
- 이전 페이지의 존재 여부는 다음 페이지(start)가 1이 아니면 무조건 true
- 다음 페이지(next)는 마지막 페이지(end)와 페이지당 개수(size)를 곱한 값보다 전체 개수가 더 많은지를 보고 판단
this.prev = this.start > 1;
this.next = total > this.end * this.size;
- 최종 PageResponseDTO 코드
// PageResponseDTO
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;
// PageResponseDTO의 생성자
@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;
}
}
2) TodoService / TodoServiceImpl
- TodoService와 TodoServiceImpl에서 PageResponseDTO를 반환 타입으로 지정해서 getList() 구성(기존의 getAll()을 대체)
// TodoService
package org.zerock.springex.service;
import org.zerock.springex.dto.TodoDTO;
import org.zerock.springex.dto.PageRequestDTO;
import org.zerock.springex.dto.PageResponseDTO;
// import java.util.List;
// register는 여러 개의 파라미터 대신 TodoDTO로 묶어서 전달받음
public interface TodoService {
void register(TodoDTO todoDTO);
// List<TodoDTO> getAll();
PageResponseDTO<TodoDTO> getList(PageRequestDTO pageRequestDTO);
TodoDTO getOne(Long tno);
void remove(Long tno);
void modify(TodoDTO todoDTO);
}
// TodoServiceImpl
package org.zerock.springex.service;
import ...
public class TodoServiceImpl implements TodoService {
...
// @Override
// public List<TodoDTO> getAll() {
// // stream의 map()을 이용해서 TodoVOfmf TodoDTO로 변경
// // collect()를 이용해서 List<TodoDTO>로 묶어줌
// List<TodoDTO> dtoList = todoMapper.selectAll().stream()
// .map(vo -> modelMapper.map(vo, TodoDTO.class))
// .collect(Collectors.toList());
// return dtoList;
// }
@Override
public PageResponseDTO<TodoDTO> getList(PageRequestDTO pageRequestDTO) {
List<TodoVO> voList = todoMapper.selectList(pageRequestDTO);
List<TodoDTO> dtoList = voList.stream()
.map(vo -> modelMapper.map(vo, TodoDTO.class))
.collect(Collectors.toList());
int total = todoMapper.getCount(pageRequestDTO);
PageResponseDTO<TodoDTO> pageResponseDTO = PageResponseDTO.<TodoDTO>withAll()
.dtoList(dtoList)
.total(total)
.pageRequestDTO(pageRequestDTO)
.build();
return pageResponseDTO;
}
}
- 테스트
- TodoServiceTests에서 다음의 코드 작성
- TodoController에서 getAll()을 사용하는 부분 삭제 후 테스트 진행
// TodoController
package org.zerock.springex.controller;
import ...
public class TodoController {
...
@RequestMapping("/list")
public void list(Model model) {
log.info("todo list.......");
// model.addAttribute("dtoList", todoService.getAll());
}
...
}
// TodoServiceTests
package org.zerock.springex.service;
import ...
public class TodoServiceTests {
...
@Test
public void testPaging() {
PageRequestDTO pageRequestDTO = PageRequestDTO.builder().page(1).size(10).build();
PageResponseDTO<TodoDTO> responseDTO = todoService.getList(pageRequestDTO);
log.info(responseDTO);
responseDTO.getDtoList().stream().forEach(todoDTO -> log.info(todoDTO));
}
}

- 1 페이지이므로 마지막 페이지(end)는 10, 이전 페이지(prev)는 없음, 다음 페이지(next)는 있음
3) TodoController와 JSP 처리
- TodoController의 list()에서 PageRequestDTO를 파라미터로 처리
- Model에 PageResponseDTO의 테이처들을 담을 수 있도록 변경
// TodoController
package org.zerock.springex.controller;
import ...
public class TodoController {
...
// Valid를 이용해 잘못된 파라미터 값들이 들어오는 경우 page는 1, size는 10으로 고정된 값을 처리하도록 구성
@RequestMapping("/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));
}
...
}
- Model에 responseDTO라는 이름으로 PageResponseDTO를 담아주었기 때문에 list.jsp는 기존의 코드를 많이 수정해야 함
<!-- list.jsp -->
<!-- 목록을 출력하는 부분에서 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>
- 프로젝트 실행 뒤 '/todo/list' 경로에서 1페이지에 해당하는 데이터들이 출력되는 것을 확인

4) 페이지 이동 확인
- 화면을 추가로 개발하기 전에 'todo/list?page=xx&size=xx'를 호출해서 결과가 정상적으로 처리되는지 확인

- 'todo/list?page=12'를 호출하면 그냥 '/todo/list'를 호출했을 때 4588로 시작하는 1페이지가 출력되는 것과 다르게 4478로 시작하는 12페이지가 출력되는 것을 확인

- size까지 설정하여 '/todo/list/page=12&size=20'을 호출한 결과 4478로 시작하는 12페이지에 20개의 데이터가 출력되는 것을 확인
- 화면에 페이지 이동을 위한 번호 출력
- 부트스트랩의 pagination 컴포넌트 적용
- list.jsp의 <table> 태그가 끝난 후에 <div> 구성하여 다음과 같이 화면 작성
<!-- list.jsp -->
</table>
<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>


- 화면에서 prev / next / 현재 페이지 표시
<!-- list.jsp -->
<div class = "float-end">
<ul class = "pagination flex-wrap">
<!-- previous 버튼 -->
<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">
<!-- ${responseDTO.page == num? "active":""} 를 추가하여 현재 페이지 표시 처리 -->
<li class = "page-item ${responseDTO.page == num? "active":""}"><a class = "page-link" href = "#">${num}</a></li>
</c:forEach>
<!-- next 버튼 -->
<c:if test = "${responseDTO.next}">
<li class = "${responseDTO.next}">
<a class = "page-link">Next</a>
</li>
</c:if>
</ul>
</div>
- 1페이지 ~ 10페이지는 Previous 버튼은 없고 Next 버튼은 출력됨

- 11페이지부터는 Previous 버튼과 Next 버튼이 모두 출력됨

- 마지막 페이지에는 Previous 버튼만 출력됨

- 페이지의 이벤트 처리
- 페이지의 번호를 누르면 이동하는 처리는 자바스크립트 이용
<ul class = "pagination flex-wrap">
<!-- previous 버튼 -->
<c:if test = "${responseDTO.prev}">
<li class = "page-item">
<!-- Previous 버튼에는 data-num - 1의 값이 저장되도록 설정 -->
<a class = "page-link" data-num = "${responseDTO.start - 1}">Previous</a>
</li>
</c:if>
<!-- 페이지 버튼 -->
<c:forEach begin = "${responseDTO.start}" end = "${responseDTO.end}" var = "num">
<!-- "${responseDTO.page == num? "active":""}" 를 추가하여 현재 페이지 표시 처리 -->
<!-- data-num이라는 속성을 추가하여 페이지 번호를 보관하도록 구성 -->
<li class = "page-item ${responseDTO.page == num? "active":""}"><a class = "page-link" data-num = "${num}">${num}</a></li>
</c:forEach>
<!-- next 버튼 -->
<c:if test = "${responseDTO.next}">
<li class = "${responseDTO.next}">
<!-- Next 버튼에는 data-num + 1의 값이 저장되도록 설정 -->
<a class = "page-link" data-num = "${responseDTO.end + 1}">Next</a>
</li>
</c:if>
</ul>
</div>
<!-- 페이지 번호 눌렀을 때 이벤트 처리 -->
<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>
- 브라우저에서 각 페이지 번호의 data-num부분에 각 페이지 번호 값이 저장됨을 확인
- Next 버튼에는 그 다음의 페이지 번호가 저장됨을 확인

- 페이지 번호를 눌러 각 페이지로 이동 가능
- 조회 페이지로의 이동
- 기존에는 목록에서 제목을 눌러 조회 페이지로 이동
- 이때 단순히 tno만 전달하여 '/todo/read?tno=1'과 같은 방식으로 이동
- 페이지 번호가 붙을 때는 page와 size를 같이 전달해주어야 조회 페이지에서 다시 목록으로 이동할 때 기존 페이지를 볼 수 있게 됨
// PageRequestDTO
package org.zerock.springex.dto;
import ...
public class PageRequestDTO {
...
private String link;
public int getSkip() {
return (page-1) * 10;
}
// GET 방식으로 페이지 이동에 필요한 링크 생성
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 -->
<c:forEach items = "${responseDTO.dtoList}" var = "dto">
<tr>
<th scope = "row"><c:out value = "${dto.tno}"/></th>
<!-- 링크 주소에 PageRequestDTO에서 생성한 link부분 추가 -->
<td><a href = "/todo/read?tno=${dto.tno}&${pageRequestDTO.link}" 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>
- 코드 수정 후 4페이지의 4554번 데이터를 조회하면 주소에 다음과 같이 page=4&size=10이 같이 전달됨

- 조회에서 목록으로
- 4페이지의 데이터를 조회한 후 다시 목록으로 돌아갈 때, 1페이지 목록이 아닌 4페이지 목록으로 돌아갈 수 있도록 설정
- 조회 화면에서는 기존과 달리 PageRequestDTO를 추가로 이용하도록 TodoController를 수정해야함
// TodoController
package org.zerock.springex.controller;
import ...
public class TodoController {
...
// read() 메서드에 PageRequestDTO 파라미터를 추가
@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.jsp -->
...
<script>
...
document.querySelector(".btn-secondary").addEventListener("click", function(e){
self.location = "/todo/list?${pageRequestDTO.link}";
}, false)
</script>
...
- 조회에서 수정으로
- 조회화면에서 수정화면으로 이동할 때도 현재 페이지 정보를 유지해야해서 링크 처리 부분 수정
<!-- list.jsp -->
...
<script>
document.querySelector(".btn-primary").addEventListener("click", function(e){
self.location = `/todo/modify?tno=${dto.tno}&${pageRequestDTO.link}`
}, false)
...
</script>
...
- Modify 버튼 클릭 시 page 번호와 size 까지 같이 전달된 주소로 이동

- 수정 화면에서의 링크 처리
- 수정 화면에서 다시 목록으로 돌아가는 링크 처리
- TodoController의 read() 메서드는 GET 방식으로 동작하는 'todo/modify'에 동일하게 처리하게 되므로 JSP에서 PageRequestDTO를 사용할 수 있음
<!-- modify.jsp -->
<script>
...
document.querySelector(".btn-secondary").addEventListener("click", function(e) {
e.preventDefault()
e.stopPropagation()
// List 버튼을 누르는 자바스크립트 이벤트 부분을 다음과 같이 변경
self.location = `todo/list${pageRequestDTO.link}`
}, false);
</script>
- 수정 / 삭제 처리 후 페이지 이동
- 실제 수정 / 삭제 작업은 POST 방식으로 처리되고 삭제 처리된 후에는 다시 목록으로 이동
- 수정 화면에서 <form> 태그로 데이터를 전송할 때 페이지와 관련된 정보를 같이 추가해서 전달해야함
- modify.jsp의 <input type = 'hidden'>을 이용
<!-- modify.jsp -->
...
<form action = "/todo/modify" method = "post">
<input type = "hidden" name = "page" value = "${pageRequestDTO.page}">
<input type = "hidden" name = "size" value = "${pageRequestDTO.size}">
...

- TodoController에서 POST 방식으로 이루어지는 삭제처리에도 PageRequestDTO를 이용해서 <form>태그로 전송되는 태그들을 수집
- 수정 후 목록 페이지로 이동할 때 page는 무조건 1페이지로 이동해서 size 정보를 활용
// TodoController
package org.zerock.springex.controller;
import ...
public class TodoController {
...
@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";
}
...
}
- 정상적으로 삭제되고 삭제 후에는 목록 페이지로 이동됨을 확인


- 수정 처리 후 이동
- 수정 후에 목록으로 이동할 때는 페이지 정보를 이용해야 하므로 TodoController의 modify()에서는 PageRequestDTO를 받아서 처리하도록 변경
/ TodoController
package org.zerock.springex.controller;
import ...
public class TodoController {
...
@PostMapping("/modify")
// PageRequestDTO를 파라미터로 추가
public String modify(PageRequestDTO pageRequestDTO,
@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);
// page와 size를 받아 리다이렉트 되도록 처리
redirectAttributes.addAttribute("page", pageRequestDTO.getPage());
redirectAttributes.addAttribute("size", pageRequestDTO.getSize());
return "redirect:/todo/list";
}
}
- 수정 후, 정상적으로 원래 목록 페이지로 이동하는지 확인


'back-end > Java' 카테고리의 다른 글
[자바 웹 개발 워크북] 5.1 - 스프링 부트 (0) | 2023.03.14 |
---|---|
[자바 웹 개발 워크북] 4.4 - 스프링 Web MVC 구현하기(5) (0) | 2023.02.22 |
[자바 웹 개발 워크북] 4.4 - 스프링 Web MVC 구현하기(3) (0) | 2023.02.15 |
[자바 웹 개발 워크북] 4.4 - 스프링 Web MVC 구현하기(2) (0) | 2023.02.14 |
[자바 웹 개발 워크북] 4.4 - 스프링 Web MVC 구현하기(1) (0) | 2023.02.09 |