2026. 4. 1. 17:31ㆍ대우개발원 수업 내용/spring boot, framework
1. 검색 및 페이징 데이터 객체 고도화 (PageRequestDTO)
- 파라미터 문자열 자동 생성 기능 추가: page, size, types, keyword 등 여러 검색 조건을 하나의 쿼리 스트링으로 결합하는 getLink() 메서드 구현.
- 검색 조건 필드 확장: 제목(t), 작성자(w), 완료 여부(finished), 시작/종료 날짜(from, to)를 수집하기 위한 필드 구성 및 유효성 검사 적용.
2. MyBatis 동적 SQL 및 검색 로직 처리 (TodoMapper.xml)
- 검색용 SQL 조각 분리: <sql id="search"> 태그를 사용하여 중복되는 검색 로직을 공통화하고 재사용성 높임.
- 동적 쿼리 제어: <if>, <foreach>, <trim> 태그를 활용하여 사용자가 선택한 검색 조건이 있을 때만 WHERE 절이 생성되도록 목록 조회 및 개수 조회(getCount) 쿼리 수정.
3. 컨트롤러 상태 유지 및 파라미터 수집 (TodoController)
- 매개변수 일원화: 상세 조회(read) 및 수정(modify) 메서드에서 PageRequestDTO를 인자로 받아 목록에서 넘어온 상태 값을 자동으로 수집하도록 수정.
- 리다이렉트 경로 보완: 수정/삭제 처리 후 목록으로 돌아갈 때 RedirectAttributes와 getLink()를 호출하여 기존 검색어와 페이지 번호가 URL에 유지되도록 경로 설정.
4. JSP 화면 인터페이스 및 자바스크립트 제어 (list/read/modify.jsp)
- 검색 UI 상태 복구: 목록 페이지 상단에 검색 폼을 배치하고, 입력했던 검색어와 체크박스 상태가 유지되도록 JSTL 삼항 연산자 적용.
- 폼 제출 방식 페이징: 페이지 번호 클릭 시 단순 이동이 아닌 자바스크립트 form.submit()을 사용하여 기존 검색 조건을 포함해 전송하는 로직 구현.
- URL 경로 최적화: 상세 보기나 수정 페이지 이동 시 자바스크립트 템플릿 리터럴을 활용해 ${pageRequestDTO.link}를 결합하는 방식 도입.
5. 단위 테스트를 통한 기능 검증 (TodoMapperTests)
- 다중 조건 검색 테스트: PageRequestDTO 빌더를 통해 임의의 키워드, 타입, 날짜 범위를 설정한 뒤 DB에서 조건에 맞는 데이터 개수와 리스트가 일치하는지 확인하는 testSelectSearch 코드 수행.
modify.jsp
페이징(Pagination) 상태 유지 기능
사용자가 글을 보다가 수정, 삭제, 또는 목록으로 돌아갈 때 원래 보던 페이지를 잃어버리지 않도록 다음 두 가지가 디테일하게 추가
1. 수정/삭제 시 페이지 정보 전달 (input type="hidden")
첫 번째 코드는 form 태그 안에 page와 size 값을 숨겨서 서버로 보냄 덕분에 글을 수정하거나
삭제한 뒤에 무조건 1페이지로 초기화되지 않고, 작업 직전에 머물던 페이지 번호를 서버가 기억하여 그 자리로 돌려보낼 수 있음
2. 목록(List) 복귀 시 기존 검색/페이지 조건 유지 (pageRequestDTO.link)
목록 버튼을 눌렀을 때 단순히 /todo/list 기본 주소로 이동하는 것이 아니라, 뒤에 ?${pageRequestDTO.link}를 붙여서 이동
이를 통해 현재 페이지 번호는 물론, 한 페이지당 볼 게시물 수나 검색 조건 등 기존 상태를 그대로 달고 목록으로 복귀
read.jsp
상세 조회 페이지(Read) 자바스크립트 개선 사항
사용자가 게시물을 읽고 수정(Modify)을 하거나 목록(List)으로 돌아갈 때,
기존에 머물던 페이지 번호를 기억하게 만드는 것이 핵심.
1. 수정(Modify) 화면으로 넘어갈 때
self.location = `/todo/modify?tno=${dto.tno}&${pageRequestDTO.link}`
* 글 번호(`tno`)와 함께 현재 페이지 정보가 담긴 `${pageRequestDTO.link}`를 쿼리 스트링으로 묶어서 같이 보냄.
* 자바스크립트의 백틱(`` ` ``) 기호를 활용해 템플릿 리터럴 방식으로 코드를 더 깔끔하게 수정.
* 단순히 글 번호만 넘기면 수정을 마친 후 무조건 전체 목록의 1페이지로 튕겨버리는 불편 해결.
* 수정 페이지에서도 내가 몇 페이지에서 넘어왔는지 기억할 수 있는 완벽한 구조.
2. 목록(List) 화면으로 돌아갈 때
self.location = "/todo/list?${pageRequestDTO.link}"
* 이동할 URL 뒤에 기존 페이지 번호, 사이즈 등의 상태 정보 파라미터(`?${pageRequestDTO.link}`)를 달아서 서버로 보냄.
* 아무런 조건 없이 이동하면 내가 5페이지의 글을 읽고 목록 버튼을 눌러도 다시 1페이지부터 찾아봐야 하는 불편 방지.
* 글을 읽고 목록으로 돌아가더라도, 원래 보던 그 페이지 위치 그대로 정확하게 복귀.
요약
단순히 화면만 이동시키는 것을 넘어, `pageRequestDTO.link`를 활용해 파라미터 전달.
화면 이동 간에 데이터가 끊기지 않도록 사용자 경험(UX)을 매끄럽게 개선한 코드.
PageRequestDTO.java
두 코드의 가장 큰 차이점은 페이징 상태 유지를 위한 쿼리 스트링(Query String) 자동 생성 기능 추가.
JSP나 자바스크립트 화면에서 페이지 이동 시 파라미터를 쉽게 전달하기 위해 설계된 개선
PageRequestDTO 클래스 개선 사항
페이징 처리를 하다 보면 전체 목록, 상세 조회, 수정 화면을 오갈 때마다 현재 페이지 번호(page)와 데이터 개수(size)를
URL에 계속 달고 다녀야 하는 불편 발생.
이를 쉽게 해결하기 위해 파라미터 문자열을 객체 내부에서 미리 만들어주는 기능 추가.
1. link 변수 및 getLink() 메서드 추가
private String link; 변수를 선언하여 조합된 쿼리 스트링을 저장할 공간 마련.
getLink() 메서드를 호출하면 page=현재페이지&size=현재사이즈 형태의 문자열을 자동으로 생성하여 반환.
2. StringBuilder를 활용한 문자열 조립
getLink() 내부에서 StringBuilder를 사용해 page 값과 size 값을 안전하고 빠르게 결합.
한 번 만들어진 문자열은 link 변수에 저장되어, 화면에서 여러 번 호출해도 다시 생성하지 않고 기존 값을 반환하는 효율적인 구조.
요약
화면(View)단에서 페이지 이동 링크를 만들 때 /todo/list?page=${dto.page}&size=${dto.size} 처럼
길고 복잡하게 파라미터를 이어 붙이던 불편 해결.
이제 /todo/list?${pageRequestDTO.link} 처럼 짧고 직관적으로 페이징 상태 유지가 가능한 발전된 코드
TodoController.java
게시글 조회 및 삭제 시 페이징(Pagination) 상태를 유지하기 위한 파라미터 처리 로직 추가.
화면 이동 간에 사용자가 설정했던 페이지 사이즈나 위치 정보를 잃어버리는 현상을 방지하기 위해 컨트롤러 단을 보완한 개선
1. 조회 및 수정 화면(read, modify) GET 매핑 메서드 개선
기존에는 매개변수로 Long tno, Model model만 받아서 단순히 글 번호만 처리하던 방식.
두 번째 코드에서는 PageRequestDTO pageRequestDTO 매개변수를 새롭게 추가하여 목록 페이지에서
넘어올 때의 page와 size 파라미터를 자동으로 수집하도록 수정.
이로써 화면(JSP) 쪽으로 페이징 정보를 전달하여 목록 복귀 시 기존 상태를 유지할 수 있게 만들어주는 뼈대 코드.
2. 삭제(remove) POST 매핑 메서드 개선
기존 코드는 글 삭제 후 무조건 기본 /todo/list 경로로 리다이렉트되어 사용자가 보던 페이징 조건이 완전히 초기화되는 불편.
두 번째 코드에서는 삭제 작업 시에도 PageRequestDTO를 매개변수로 받아 기존의 상태 값을 기억하도록 수정.
삭제 처리가 끝난 후 RedirectAttributes를 활용해 page 값은 1로 세팅하고, size 값은 사용자가 보던 pageRequestDTO.getSize()를 그대로 넣어서 목록으로 보내주는 방식으로 개선.
데이터가 삭제되어 기존 페이지 번호에 글이 없을 수 있는 오류를 막기 위해 안전하게 1페이지로 이동시키면서도,
한 번에 볼 게시물 개수(size) 설정은 그대로 유지시켜주는 코드
요약
두 번째 코드는 상세 조회나 삭제를 수행할 때 URL에 담겨오는 페이징 조건(page, size)이 끊기지 않도록, 컨트롤러의 매개변수로 PageRequestDTO를 적극 활용해 사용자 경험(UX)을 끌어올린 발전된 코드.
TodoMapper.xml
MyBatis의 동적 태그를 활용한 다중 검색(Search) 및 필터링 기능 추가.
페이징 처리 시 검색 조건에 맞는 데이터만 정확하게 불러오도록 SQL 쿼리를 동적으로 생성하는 로직이 결합된 개선 코드.
공통 검색 쿼리 분리 (sql 태그 도입)
검색 조건을 처리하는 복잡한 로직을 매번 작성하지 않고 재사용하기 위해 sql 태그를 사용하여 search라는 이름으로 분리한 코드.
if, foreach, trim 등의 동적 태그를 사용해 제목(t), 작성자(w) 검색은 물론 완료 여부,
날짜 구간 필터링까지 상황에 맞게 WHERE 절이 알아서 조립되도록 수정.
목록 조회 쿼리(selectList) 개선
단순히 전체 데이터를 잘라오던 기존 쿼리에 include 태그를 삽입.
이를 통해 사용자가 선택한 검색 조건에 일치하는 데이터들 안에서만 지정된 개수(limit)만큼 가져오도록 작동하는 코드.
전체 데이터 개수 조회 쿼리(getCount) 개선
단순히 테이블 전체 행의 개수만 세던 쿼리에도 동일하게 include 태그를 추가.
검색 조건이 걸려 데이터가 줄어들었을 때, 전체 개수가 아닌 검색된 데이터의 개수를 정확히 세어
하단 페이징 번호가 알맞게 출력되도록 보완된 필수 수정.
요약
단순한 데이터 목록 조회에서 벗어나, 다양한 조건의 검색과 필터링을 유연하게 처리하는
동적 쿼리(Dynamic SQL) 기반으로 업그레이드된 코드.
list.jsp
목록 화면(List) 상단에 다중 검색(Search) 및 필터링을 위한 UI 폼(Form) 영역 추가.
사용자가 원하는 조건으로 데이터를 검색하고, 그 상태를 화면 이동 간에도 계속 유지할 수 있도록 뷰(JSP) 개선한 코드.
검색(Search) 폼 UI 추가
완료 여부(finished), 검색 조건(types - 제목, 작성자), 검색어(keyword), 날짜 구간(from, to)을 입력받을 수 있는
form 태그 영역을 목록 테이블 상단에 새롭게 배치.
검색 버튼(Submit)을 누르면 해당 조건들이 GET 방식으로 서버에 전송되어 조건에 맞는 데이터만 화면에 출력되도록 수정.
검색 조건 및 페이징 상태 유지
단순히 검색 창만 만든 것이 아니라, 검색 후 화면이 새로고침 되어도 내가 입력했던 검색어와 체크박스 상태가
화면에 그대로 남아있도록 개선.
value 속성에 pageRequestDTO의 데이터를 바인딩하고, JSTL 삼항 연산자를 활용해 기존 설정값을 폼에
다시 채워 넣어주는 친절한 코드.
상세 조회(Read) 링크 파라미터 연결
기존에는 제목을 눌러 상세 보기로 이동할 때 글 번호(tno)만 전달하여, 목록으로 돌아왔을 때 공들여 설정한
검색 조건이 모두 초기화되는 불편.
a 태그의 링크 주소 뒤에 페이징 및 검색 정보가 하나로 뭉쳐진 ${pageRequestDTO.link}를 덧붙여서,
글을 읽고 목록으로 돌아와도 검색 상태가 그대로 유지되도록 완벽하게 수정.
초기화(Clear) 버튼 및 자바스크립트 추가
검색 조건이 너무 복잡하게 얽히거나 처음부터 다시 전체 목록을 보고 싶을 때를 대비해 초기화 버튼 추가.
버튼 클릭 시 자바스크립트 이벤트를 통해 URL의 모든 파라미터를 지우고 깨끗한 기본 목록 경로(/todo/list)로
되돌려주는 편의성 개선.
요약
단순한 목록 출력 화면을 넘어, 복합적인 검색 기능을 제공하고 화면을 이동해도 사용자의 검색 조건과 페이지 번호를 끝까지 기억하도록 뷰(View) 템플릿과 자바스크립트를 정교하게 연결한 발전된 코드.
TodoMapperTests.java
@Test
public void testSelectSearch(){
PageRequestDTO pageRequestDTO = PageRequestDTO.builder()
.page(1)
.size(10)
.types(new String[]{"t","m"})
.keyword("에러")
.finished(true)
.from(LocalDate.of(2026,05,01))
.to(LocalDate.of(2026,05,31))
.build();
log.info(todoMapper.getCount(pageRequestDTO));
List<TodoVO> voList = todoMapper.selectList(pageRequestDTO);
voList.forEach(vo -> log.info(vo));
}
아래 코드를 추가

정상적으로 실행됨

검색기능이 제대로 실행됨
'대우개발원 수업 내용 > spring boot, framework' 카테고리의 다른 글
| 자바 스프링 부트 1일차 b01 (0) | 2026.04.01 |
|---|---|
| 자바 프레임 워크 11일차 springex_web 검색 및 데이터 보존 페이징처리 (1) | 2026.04.01 |
| 자바프레임워크 9일차 springex_web 페이징 처리 (0) | 2026.03.30 |
| 자바 프레임워크 8일차 springex_web(Read, Delete, Update) (0) | 2026.03.27 |
| 자바 프레임워크 7일차 springex_web(Spring MVC & 데이터베이스 연동 핵심 기능 구현) (0) | 2026.03.26 |