검색처리 게시판 예제
◻️ Criteria.java
package org.zerock.domain;
import lombok.Getter;
import lombok.Setter;
import lombok.ToString;
@ToString
@Setter
@Getter
public class Criteria {
private int pageNum;
private int amount;
private String type;
private String keyword;
public Criteria() {
this(1, 10);
}
public Criteria(int pageNum, int amount) {
this.pageNum = pageNum;
this.amount = amount;
}
public String[] getTypeArr() {
return type == null ? new String[] {} : type.split("");
}
}
🔩 resources / Mapper.xml
<select id="getListWithPaging" resultType="org.zerock.domain.BoardVO">
<![CDATA[
select
bno, title, content, writer, regdate, updatedate
from
(
-- 최신순 정렬 및 rownum으로 페이징
select /*+INDEX_DESC(tbl_board pk_board) */
rownum rn, bno, title, content, writer, regdate, updatedate
from
tbl_board
where
]]>
<trim prefix="(" suffix=") AND " prefixOverrides="OR">
<foreach item='type' collection="typeArr">
<trim prefix="OR">
<choose>
<when test="type == 'T'.toString()">
title like '%'||#{keyword}||'%'
</when>
<when test="type == 'C'.toString()">
content like '%'||#{keyword}||'%'
</when>
<when test="type == 'W'.toString()">
writer like '%'||#{keyword}||'%'
</when>
</choose>
</trim>
</foreach>
</trim>
<![CDATA[
-- 페이지 끝 번호까지 조회
rownum <= #{pageNum} * #{amount}
)
-- 현재 페이지 시작 번호 이후부터 출력
where rn > (#{pageNum} -1) * #{amount}
]]>
</select>
<select id="getTotalCount" resultType="int">
select count(*) from tbl_board where
<include refid="criteria"></include>
bno > 0
</select>
🖱️ BoardServiceImpl.java
@Override
public int getTotal(Criteria cri) {
return mapper.getTotalCount(cri);
}
🧑💼 Controller.java
@GetMapping("/list")
public void getList(Criteria cri, Model model) {
model.addAttribute("list", service.getList(cri));
model.addAttribute("pageMaker", new PageDTO(cri, service.getTotal(cri)));
}
@PostMapping("/modify")
public String modify(BoardVO board,
@ModelAttribute("cri") Criteria cri,
RedirectAttributes rttr) {
service.modify(board);
rttr.addAttribute("pageNum", cri.getPageNum());
rttr.addAttribute("amount", cri.getAmount());
rttr.addAttribute("type", cri.getType());
rttr.addAttribute("keyword", cri.getKeyword());
return "redirect:/board/list";
}
@PostMapping("/remove")
public String remove(@RequestParam("bno") Long bno,
@ModelAttribute("cri") Criteria cri,
RedirectAttributes rttr) {
service.remove(bno);
rttr.addAttribute("pageNum", cri.getPageNum());
rttr.addAttribute("amount", cri.getAmount());
rttr.addAttribute("type", cri.getType());
rttr.addAttribute("keyword", cri.getKeyword());
return "redirect:/board/list";
}
컨트롤러 흐름
- 목록 조회:
getList()에 Criteria cri 객체 전달하여 페이징/검색된 목록 반환
- 페이지 정보 유지: 수정/삭제 후 기존 검색 조건과 페이지 정보 유지
@ModelAttribute("cri"): Criteria 객체 자동 바인딩
RedirectAttributes: 리다이렉트 시 파라미터 전달
- Post-Redirect-Get 패턴에서 주로 사용
- 4가지 파라미터 전달: pageNum, amount, type, keyword
@RedirectAttributes vs @RequestParam vs @ModelAttribute
| 특성 | @RedirectAttributes | @RequestParam | @ModelAttribute |
|---|
| 용도 | 리다이렉트 시 데이터 전달 | 요청 파라미터 바인딩 | 객체 바인딩 및 모델 데이터 추가 |
| 데이터 수명 | 리다이렉트 이후 한 번의 요청까지만 유지 | 현재 요청 내에서만 유지 | 현재 요청 내에서 유지되며 뷰로 자동 전달 |
| 처리 데이터 형태 | addAttribute(): String 값 | 단일 값 | 복잡한 객체 |
| URL 노출 | URL에 노출됨 | URL에 노출됨 | URL에 노출되지 않음 |
| 사용 예시 | rttr.addAttribute("page", 1) | @RequestParam("id") Long id | @ModelAttribute("user") User user |
| 항목 | <select> | <input type="hidden"> |
|---|
| 사용자 입력 | 사용자가 직접 선택 | 사용자 입력 없음 |
| 화면 표시 | 보임 (UI 요소) | 안 보임 |
| 용도 | 사용자로부터 선택 받기 | 자동으로 값 유지/전송 |
| 주 사용처 | 검색 조건, 폼 입력 | 페이징, 상태 유지, 자바스크립트 제어 |