목차 | |
1. | modify, delete |
2. | paging, search |
1. modify, delete
▣ modify.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c "%>
<jsp:include page="../layout/header.jsp"/>
<body>
<div class="container-md">
<h1>Board Modify Page...</h1>
<form action="/board/update" method="post">
<div class="mb-3">
<label for="n" class="form-label">no.</label>
<input type="hidden" name="bno" value="${bvo.bno }">
<input type="text" class="form-control" id="n" value="${bvo.bno}" readonly>
</div>
<div class="mb-3">
<label for="t" class="form-label">title</label>
<input type="text" class="form-control" id="t" name="title" value="${bvo.title}">
</div>
<div class="mb-3">
<label for="w" class="form-label">writer</label>
<input type="text" class="form-control" id="w" value="${bvo.writer}" readonly>
<span class="bodge text-bg-Info">${bvo.regDate}</span>
</div>
<div class="mb-3">
<label for="c" class="form-label">content</label>
<textarea class="form-control" id="c" rows="3" name="content">${bvo.content}</textarea>
</div>
<button type="submit" class="btn btn-success">modify</button>
<a href="/board/list"><button type="button" class="btn btn-danger">list</button></a>
</form>
</div>
</body>
<jsp:include page="../layout/footer.jsp"/>
▣ detail.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c "%>
<jsp:include page="../layout/header.jsp"/>
<body>
<div class="container-md">
<h1>Board Detail Page...</h1>
<div class="mb-3">
<label for="t" class="form-label">title</label>
<input type="text" class="form-control" id="t" value="${bvo.title}" readonly>
</div>
<div class="mb-3">
<label for="w" class="form-label">writer</label>
<input type="text" class="form-control" id="w" value="${bvo.writer}" readonly>
<span class="bodge text-bg-Info">${bvo.regDate}</span>
</div>
<div class="mb-3">
<label for="c" class="form-label">content</label>
<textarea class="form-control" id="c" rows="3" readonly>${bvo.content}</textarea>
</div>
<a href="/board/modify?bno=${bvo.bno }"><button type="button" class="btn btn-success">modify</button></a>
<a href="/board/delete?bno=${bvo.bno }"><button type="button" class="btn btn-danger">delete</button></a>
</div>
</body>
<jsp:include page="../layout/footer.jsp"/>
▷ 출력
2. paging, search
[day03]
detail :
list 페이지에서 bno 하나를 전달하여 해당 객체(DB에서)를 detail 페이지로 전송
list => pagination
한 페이지에 목록을 다 나태내기 힘들 때 사용
- 한 페이지에 10개의 게시물 표현
- 전체 게시글의 수에 계산되어 페이지네이션 값들이 결정이 됨
DB 상에서 => limit 시작번지, 개수
1 => limit 0, 10 => 0번지부터 10개 => 0번지부터 9번지까지
2 => limit 10, 10 => 10번지부터 10개 => 10번지부터 19번지까지
3 => limit 20, 10 => 20번지부터 10개 => 20번지부터 29번지까지
...
pageNo 페이지네이션 번호
getPageStart =>시작번지
qty => 개수
----------------------
PagingHandler
한 페이지에 나오는 페이지네이션 개수 : 10개 => qty
한 페이지에 나오는 페이지네이션 시작번호 : 1 11 21 ... 181
한 페이지에 나오는 페이지네이션 끝번호: 10 20 30 ... 181
이전, 다음의 노출여부 boolean
전체 페이지 수 : DB에서 조회해 와야하는 값 (매개변수로 받아오기)
현재 페이지 번호 : pagingVO pageNo 사용 (매개변수로 받아오기)
진짜 마지막 페이지 끝 번호
----------------------
select * from board where is_del = 'N' and #{type} like '%"${keyword}"%'
order by bno desc limit #{pageStart}, #{qty}
'%"${keyword}"%' => '% "${keyword}" %'
concat('%', "${keyword}", '%')
▣ BoardController.java
package com.ezen.spring.controller;
import java.util.List;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import com.ezen.spring.domain.BoardVO;
import com.ezen.spring.domain.PagingVO;
import com.ezen.spring.handler.PagingHandler;
import com.ezen.spring.service.BoardService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
@Slf4j
@RequiredArgsConstructor
@RequestMapping("/board/*")
@Controller
public class BoardController {
// 생성자 주입시 객체는 final로 생성
private final BoardService bsv;
// return void => 온 경로 그대로 리턴 /board/register => /board/register.jsp
@GetMapping("/register")
public void register() {}
@PostMapping("/insert")
public String insert(BoardVO bvo) {
log.info(">>> insert bvo > {}", bvo);
int isOk = bsv.insert(bvo);
log.info(">>> insert > {}", isOk > 0 ? "OK" : "FAIL");
// /WEB-INF/views/.jsp (x)
// 컨트롤러의 mapping 위치로 연결할 때 redirect:/board/list
return "redirect:/";
}
@GetMapping("/list")
public String list(Model m, PagingVO pgvo) {
// request.setAttrbute()
// Model 객체가 해당 일을 대신해줌.
// PagingVO pgvo = new PagingVO();
List<BoardVO> list = bsv.getList(pgvo);
// totalcount 구해서 PagingHandler에 매개변수로 전달
int totalCount = bsv.getTotal(pgvo);
PagingHandler ph = new PagingHandler(totalCount, pgvo);
log.info(">>> totalCount > {}", totalCount);
m.addAttribute("list",list);
m.addAttribute("ph",ph);
return "/board/list";
}
@PostMapping("/update")
public String update(BoardVO bvo) {
int isOk = bsv.modify(bvo);
log.info(">>> update > {}", isOk > 0 ? "OK" : "FAIL");
// detail.jsp로 이동 X => controller detail mapping으로 이동 => redirect:/
return "redirect:/board/detail?bno="+bvo.getBno();
}
// @ requestParam("bno") int bno => 전달되는 파라미터가 여러 개일 경우 이름을 명시
// return void : 요청 경로로 응답을 그대로 보냄. /board/detail => /board/detail.jsp
@GetMapping({"/detail", "/modify"})
public void detail(int bno, Model m) {
// bno에 해당하는 BoardVO 객체를 DB에서 가져와서 모델로 전달
BoardVO bvo = bsv.getDetail(bno);
m.addAttribute("bvo", bvo);
// return "/board/detail";
}
@GetMapping("/delete")
public String delete(int bno) {
int isOk = bsv.delete(bno);
log.info(">>> delete > {}", isOk > 0 ? "OK" : "FAIL");
return "redirect:/board/list";
}
}
▣ BoardService.java
package com.ezen.spring.service;
import java.util.List;
import com.ezen.spring.domain.BoardVO;
import com.ezen.spring.domain.PagingVO;
public interface BoardService {
int insert(BoardVO bvo);
List<BoardVO> getList(PagingVO pgvo);
BoardVO getDetail(int bno);
int modify(BoardVO bvo);
int delete(int bno);
int getTotal(PagingVO pgvo);
}
▣ BoardServiceImpl.java
package com.ezen.spring.service;
import java.util.List;
import org.springframework.stereotype.Service;
import com.ezen.spring.dao.BoardDAO;
import com.ezen.spring.domain.BoardVO;
import com.ezen.spring.domain.PagingVO;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
@RequiredArgsConstructor
@Slf4j
@Service
public class BoardServiceImpl implements BoardService{
private final BoardDAO bdao;
@Override
public int insert(BoardVO bvo) {
// TODO Auto-generated method stub
return bdao.insert(bvo);
}
@Override
public List<BoardVO> getList(PagingVO pgvo) {
// TODO Auto-generated method stub
return bdao.getList(pgvo);
}
@Override
public BoardVO getDetail(int bno) {
// TODO Auto-generated method stub
return bdao.getDetail(bno);
}
@Override
public int modify(BoardVO bvo) {
// TODO Auto-generated method stub
return bdao.update(bvo);
}
@Override
public int delete(int bno) {
// TODO Auto-generated method stub
return bdao.delete(bno);
}
@Override
public int getTotal(PagingVO pgvo) {
// TODO Auto-generated method stub
return bdao.getTotal(pgvo);
}
}
▣ BoardDAO.java
package com.ezen.spring.dao;
import java.util.List;
import com.ezen.spring.domain.BoardVO;
import com.ezen.spring.domain.PagingVO;
public interface BoardDAO {
int insert(BoardVO bvo);
List<BoardVO> getList(PagingVO pgvo);
BoardVO getDetail(int bno);
int update(BoardVO bvo);
int delete(int bno);
int getTotal(PagingVO pgvo);
}
▣ boardMapper.xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"https://mybatis.org/dtd/mybatis-3-mapper.dtd">
<!-- DAOImpl() 없음. => namespace="다오인터페이스명" id="메서드명" -->
<mapper namespace="com.ezen.spring.dao.BoardDAO">
<insert id="insert">
insert into board(title, writer, content)
values(#{title}, #{writer}, #{content})
</insert>
<select id="getList" resultType="com.ezen.spring.domain.BoardVO">
select * from board where is_del = 'N'
<include refid="search"></include>
order by bno desc limit #{pageStart}, #{qty}
</select>
<select id="getDetail" resultType="com.ezen.spring.domain.BoardVO">
select * from board where bno = #{bno}
</select>
<update id="update">
update board set title = #{title}, content = #{content} where bno = #{bno}
</update>
<update id="delete">
update board set is_del = 'Y' where bno = #{bno}
</update>
<select id="getTotal" resultType="int">
select count(bno) from board where is_del = 'N'
<include refid="search"></include>
</select>
<!-- search 동적 쿼리 -->
<!--
select * from board
where is_del = 'N' and title like concat('%', keyword, '%') or writer like concat('%', keyword, '%') )
order by bno desc
limit #{pageStart}, #{qty}
-->
<sql id="search">
<if test="type!=null">
<trim prefix="and(" suffix=")" suffixOverrides="or">
<foreach collection="typeToArray" item="type">
<trim suffix="or">
<choose>
<when test="type == 't'.toString()">
title like concat('%', #{keyword}, '%')
</when>
<when test="type == 'w'.toString()">
writer like concat('%', #{keyword}, '%')
</when>
<when test="type == 'c'.toString()">
content like concat('%', #{keyword}, '%')
</when>
</choose>
</trim>
</foreach>
</trim>
</if>
</sql>
</mapper>
▣ PagingVO.java
package com.ezen.spring.domain;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.Setter;
import lombok.ToString;
@Getter
@Setter
@ToString
@AllArgsConstructor
public class PagingVO {
private int pageNo; // 페이지네이션 번호
private int qty; // 한 페이지에 표시되는 페이지 수
// search 변수 포함
private String type;
private String keyword;
// 첫 리스트시 기본적으로 설정될 값
public PagingVO() {
this.pageNo = 1;
this.qty = 10;
}
public PagingVO(int pageNo, int qty) {
this.pageNo = pageNo;
this.qty = qty;
}
// DB에서 사용될 시작번지 구하기
// select * from board limit 번지, 개수
// 1page limit 0, 10 => 2page limit 10, 10 => 3page limit 20, 10
public int getPageStart() {
return (this.pageNo - 1) * this.qty;
}
// type의 복합 타입을 각각 검색하기 위해 배열로 생성
// type == twc [t, w, c]
public String[] getTypeToArray() {
return this.type == null ? new String[] {} : this.type.split("");
}
}
▣ PagingHandler.java
package com.ezen.spring.handler;
import com.ezen.spring.domain.PagingVO;
import lombok.Getter;
import lombok.Setter;
import lombok.ToString;
@Getter
@Setter
@ToString
public class PagingHandler {
private int qty; // 한 페이지에 나오는 페이지네이션 개수 : 10개
private int startPage; // 한 페이지에 나오는 페이지네이션 시작번호 : 1 11 21 ... 181
private int endPage; // 한 페이지에 나오는 페이지네이션 끝번호: 10 20 30 ... 181
private boolean prev;
private boolean next;
private int totalCount; // 전체 페이지 수 : DB에서 조회해 와야하는 값 (매개변수로 받아오기)
private PagingVO pgvo; // 현재 페이지 번호 : pagingVO pageNo 사용 (매개변수로 받아오기)
private int realEndPage;
// 생성자에서 모든 값들이 계산되어 설정되어야 함.
public PagingHandler(int totalCount, PagingVO pgvo) {
this.qty = 10;
this.pgvo = pgvo;
this.totalCount = totalCount;
// 1~10 / 11~20 / 21~30 ...
// pageNo => 1 2 3 .. 10 => 1~10
// pageNo => 11 12 13 ... 20 => 11~20
// 1 2 3 ... 10 => endPage는 변함없이 10
// 11 12 13 ... 20 => 20
// 1 / 10개 => 0.1 결과를 올림 => 1 * 10 => 10
// 11 / 10 => 1.1 결과를 올림(ceil) => 2 * 10 => 20
// 정수 / 정수 => 정수 형변환을 해서 소수점을 유지
this.endPage = (int)Math.ceil(pgvo.getPageNo() / (double)qty) * qty;
this.startPage = endPage - 9;
// 실제 마지막 페이지
// 전체 글수 / 한 페이지에 표시되는 게시글 수 (올림)
// 11 / 10 => 2페이지 1.1 (올림) => 2
this.realEndPage = (int)Math.ceil(totalCount /(double)pgvo.getQty());
// 이전, 다음 여부
this.prev = this.startPage > 1; // 1 11 21 31
this.next = this.endPage < this.realEndPage;
if(endPage > realEndPage) {
this.endPage = realEndPage;
}
}
}
▣ list.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c"%>
<jsp:include page="../layout/header.jsp"/>
<div class="container-md">
<h1>Board List Page...</h1>
<hr>
<!-- search line -->
<div class="container-fluid">
<form action="/board/list" method="get" class="d-flex" role="search">
<select class="form-select" name="type" id="inputGroupSelect01">
<option ${ph.pgvo.type == null ? 'selected' : '' }>Choose...</option>
<option value="t" ${ph.pgvo.type eq 't' ? 'selected' : '' }>title</option>
<option value="w" ${ph.pgvo.type eq 'w' ? 'selected' : '' }>writer</option>
<option value="c" ${ph.pgvo.type eq 'c' ? 'selected' : '' }>content</option>
<option value="tw" ${ph.pgvo.type eq 'tw' ? 'selected' : '' }>title + writer</option>
<option value="wc" ${ph.pgvo.type eq 'wc' ? 'selected' : '' }>writer + content</option>
<option value="tc" ${ph.pgvo.type eq 'tc' ? 'selected' : '' }>content + title</option>
<option value="twc">all</option>
</select>
<input class="form-control me-2" name="keyword" type="search" placeholder="Search" value="${ph.pgvo.keyword}" aria-label="Search">
<input type="hidden" name="pageNo" value="1">
<input type="hidden" name="qty" value="${ph.pgvo.qty }">
<button type="submit" class="btn btn-primary position-relative">
search
<span class="position-absolute top-0 start-100 translate-middle badge rounded-pill bg-danger">
${ph.totalCount }
</span>
</button>
</form>
<%-- ${ph } --%>
</div>
<table class="table table-hover">
<thead>
<tr>
<th scope="col">#</th>
<th scope="col">title</th>
<th scope="col">writer</th>
<th scope="col">regDate</th>
<th scope="col">readCount</th>
</tr>
</thead>
<tbody>
<c:forEach items="${list}" var="bvo">
<tr>
<td>${bvo.bno }</td>
<td><a href="/board/detail?bno=${bvo.bno }">${bvo.title }</a></td>
<td>${bvo.writer }</td>
<td>${bvo.regDate }</td>
<td>${bvo.readCount }</td>
</tr>
</c:forEach>
</tbody>
</table>
<!-- pagination line -->
<!-- << >> : 값이 false disabled -->
<nav aria-label="Page navigation example">
<ul class="pagination justify-content-center">
<li class="page-item ${ph.prev eq false ? 'disabled' : ''}">
<a class="page-link" href="/board/list?pageNo=${ph.startPage-1 }&qty=${ph.pgvo.qty}&type=${ph.pgvo.type}&keyword=${ph.pgvo.keyword}" aria-label="Previous">
<span aria-hidden="true">«</span>
</a>
</li>
<c:forEach begin="${ph.startPage }" end="${ph.endPage }" var="i">
<li class="page-item ${ph.pgvo.pageNo eq i ? 'active' : ''}"><a class="page-link" href="/board/list?pageNo=${i }&qty=${ph.pgvo.qty}&type=${ph.pgvo.type}&keyword=${ph.pgvo.keyword}">${i }</a></li>
</c:forEach>
<!-- <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 ${ph.next eq false ? 'disabled' : ''}" >
<a class="page-link" href="/board/list?pageNo=${ph.endPage+1}&qty=${ph.pgvo.qty}&type=${ph.pgvo.type}&keyword=${ph.pgvo.keyword}" aria-label="Next">
<span aria-hidden="true">»</span>
</a>
</li>
</ul>
</nav>
<a href="/"><button type="submit" class="btn btn-success">list</button></a>
</div>
<jsp:include page="../layout/footer.jsp"/>
▷ 출력
'Java > Spring' 카테고리의 다른 글
Spring 기초(scheduler) - AWS 풀스택 과정 70일차 (0) | 2024.11.04 |
---|---|
Spring 기초(file) - AWS 풀스택 과정 69일차 (0) | 2024.11.01 |
Spring 기초(comment) - AWS 풀스택 과정 68일차 (0) | 2024.10.31 |
Spring 설정 및 기초2 - AWS 풀스택 과정 66일차 (0) | 2024.10.29 |
Spring 설정 및 기초 - AWS 풀스택 과정 65일차 (0) | 2024.10.28 |