일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | 5 | ||
6 | 7 | 8 | 9 | 10 | 11 | 12 |
13 | 14 | 15 | 16 | 17 | 18 | 19 |
20 | 21 | 22 | 23 | 24 | 25 | 26 |
27 | 28 | 29 | 30 |
Tags
- JDBC
- crud
- Oracle
- 생활코딩
- API
- ddit
- 자바
- 단축키
- python
- FastAPI
- 맥
- 자바문제
- pyqt
- Error
- 컬렉션프레임워크
- 객체지향
- jsp
- 이클립스
- 대덕인재개발원
- Java
- nodejs
- 반복문
- servlet
- ibatis
- html
- spring
- Homebrew
- Mac
- 배열
- Android
Archives
- Today
- Total
romworld
Spring 14 - 페이징 처리, 검색 기능, 계층형 쿼리, LOOP을 이용한 UPDATE 쿼리문 본문
1. 페이징 처리를 구현해보자
2. 검색을 할 수 있다
3. 계층형 쿼리 실행
페이징 처리를 위한
<AticlePage.java> 파일을 만든다.
package kr.or.ddit.util;
import java.util.List;
import kr.or.ddit.vo.LprodVO;
//페이징 관련 정보 + 게시글 데이터
public class ArticlePage<T> {
// 전체글 수
private int total;
// 현재 페이지 번호
private int currentPage;
// 전체 페이지 수
private int totalPages;
// 시작 페이지 번호
private int startPage;
// 종료 페이지 번호
private int endPage;
// 블록 크기
private int blockSize;
// 글 데이터
private List<T> content;
// 생성자(Constructor) : 페이징 정보를 생성 및 초기화
// size : 한 화면에 보여질 행의 수
public ArticlePage(int total, int currentPage, int size
, List<T> content) {
this.total = total;
this.currentPage = currentPage;
this.content = content;
// 만약 글 수가 0일 때
if(total==0) {
totalPages = 0;
startPage = 0;
endPage = 0;
}else {// 전체 글 수가 1 이상일 때
// 1) 전체 페이지 구하기 시작 -----
// 전체 페이지 수 = 전체글 수 / 한 화면에 보여질 목록의 행 수
totalPages = total/size;
// 전체글 수 % 한 화면에 보여질 목록의 행 수
// => 0이 아니면(나머지가 있다면)? 페이지를 1증가
if(total%size>0) {
totalPages++;
}
//1) 전체 페이지 구하기 끝 -----
//2) 시작 페이지 구하기 시작 -----
// 시작페이지 = 현재페이지/ 페이지크기*페이지크기 + 1
// 1set : [1][2][3][4][5]다음
// 2set : 이전[6][7][8][9][10]다음
// 3set : 이전[11][12]
startPage = currentPage / 5 * 5 + 1;
// 현재페이지 % 페이지크기 => 0일 때 보정
if(currentPage % 5 ==0) {
// 페이지크기를 빼줌
startPage -= 5;
}
//2) 시작 페이지 구하기 끝 -----
//3) 종료 페이지 구하기 시작 -----
// 종료페이지번호 = 시작페이지번호 + (페이지크기 -1)
endPage = startPage + (5 - 1);
// 종료페이지번호 > 전체페이지수보다 클 때 보정
if(endPage > totalPages) {
endPage = totalPages;
}
//3) 종료 페이지 구하기 끝 -----
}
}//end ArticlePage 생성자
public int getTotal() {
return total;
}
public void setTotal(int total) {
this.total = total;
}
public int getCurrentPage() {
return currentPage;
}
public void setCurrentPage(int currentPage) {
this.currentPage = currentPage;
}
public int getTotalPages() {
return totalPages;
}
public void setTotalPages(int totalPages) {
this.totalPages = totalPages;
}
public int getStartPage() {
return startPage;
}
public void setStartPage(int startPage) {
this.startPage = startPage;
}
public int getEndPage() {
return endPage;
}
public void setEndPage(int endPage) {
this.endPage = endPage;
}
public int getBlockSize() {
return blockSize;
}
public void setBlockSize(int blockSize) {
this.blockSize = blockSize;
}
public List<T> getContent() {
return content;
}
public void setContent(List<T> content) {
this.content = content;
}
// 데이터가 없으면 전체 글의 수는 0
public boolean hasNoArticles() {
return total == 0;
}
// 데이터가 있으면
public boolean hasArticles() {
return total > 0;
}
}
<LprodController.java>
- list 메서드를 페이징 처리하기위해 수정해주자.
- 우선 전체 행의 수 구하기
- 한 페이지에 보여질 행의 수 구하기
// 요청URI : /lprod/list?currentPage=3
//1)요청파라미터 : currentPage=2
//2)요청파라미터 : 없을 때 ---> 이 두 가지 처리를 다 해줘야 함
// required : 필수있지 아닌지
// defalutValue : 없을 때 기본 값 -> 1일경우 1페이지로 간주함
// currentPage=2 파라미터의 타입은 String , 하지만 int 타입의 매개변수로 자동 형변환 가능 (스프링에서 지원함)
@RequestMapping(value="/list",method=RequestMethod.GET)
public ModelAndView list(ModelAndView mav,
@RequestParam(value="currentPage", required=false, defaultValue="1") int currentPage) {
// 검색 조건
Map<String, String> map = new HashMap<String, String>();
//1) 전체 행의 수 구하기(total)
int total = this.lprodService.getTotal();
//2) 한 페이지에 보여질 행의 수(size)
int size = 10;
//map{"size":"10","currentPage":"1"}
map.put("size", size+"");
map.put("currentPage", currentPage+"");
log.info("map :" + map);
List<LprodVO> lprodVOList = this.lprodService.list(map);
// 페이징 처리 전.. data
//mav.addObject("data", lprodVOList);
// 페이징 처리 후
mav.addObject("data"
, new ArticlePage<LprodVO>(total, currentPage, size, lprodVOList));
// jsp 경로
// tiles-config.xml의
// */*은 lprod/list와 {1}/{2}.jsp에 의해 lprod/list.jsp가 forwarding됨
mav.setViewName("lprod/list");
return mav;
}
<lprod_SQL.xml>
- 전체행의 수 구하는 쿼리
<!-- 전체 행의 수 (total) -->
<select id="getTotal" resultType="int">
SELECT COUNT(*) FROM LPROD
</select>
<lprodDao.java>
// 전체 행의 수 (total)
// <select id="getTotal" resultType="int">
public int getTotal() {
return this.sqlSessionTemplate.selectOne("lprod.getTotal");
}
<lprodService.java>
// 전체 행의 수 (total)
public int getTotal();
<lprodServiceImpl.java>
// 전체 행의 수 (total)
@Override
public int getTotal() {
return this.lprodDao.getTotal();
}
리스트 매개변수에 Map 추가 dao,service,serviceImpl 전부 고쳐주자
그리고 list 쿼리문도 변경
<lprodDao.java>
public List<LprodVO> list(Map<String, String> map){
return this.sqlSessionTemplate.selectList("lprod.list",map);
}
<lprodService.java>
// 메소드 시그니처
public List<LprodVO> list(Map<String, String> map);
<lprodServiceImple.java>
@Override
public List<LprodVO> list(Map<String, String> map){
return this.lprodDao.list(map);
}
우선 LPROD 테이블에 실습 데이터를 많이 집어넣어보자
<SQL Developer>
/* pl/sql
package
user function 사용자 정의함수
stored procedure 저장 프로시저
trigger
anonymous block 익명의 블록
*/
/
DECLARE
MAX_ID NUMBER;
BEGIN
--가장 마지막 번호 + 1
SELECT NVL(MAX(LPROD_ID),0)+1 INTO MAX_ID
FROM LPROD;
FOR I IN 701..900 LOOP
INSERT INTO LPROD(LPROD_ID, LPROD_GU, LPROD_NM)
VALUES(I,
'P' || TRIM(TO_CHAR(I,'000')),
'새롬이'||I);
END LOOP;
COMMIT;
END;
/
--32를 P032로..
SELECT 'P' || TRIM(TO_CHAR(701,'000')) FROM DUAL;
--123을 P123으로..
SELECT 'P' || TRIM(TO_CHAR(900,'000')) FROM DUAL;
/* 서브쿼리
SELECT: SCALAR
FROM : INLINE VIEW
WHERE : NESTED
*/
/
WITH U AS(
SELECT ROW_NUMBER() OVER (ORDER BY T.LPROD_ID DESC) RNUM
,T.*
FROM
(
SELECT LPROD_ID, LPROD_GU, LPROD_NM
FROM LPROD
) T
)
SELECT U.*
FROM U
WHERE U.RNUM BETWEEN 51 AND 60;
/
실행시켜보자
<여기서 만약 LPROD_NM의 내용을 반복문으로 수정하고 싶다면!>
DECLARE
BEGIN
FOR I IN 701..900 LOOP
update LPROD
set LPROD_NM = '새롬이'||(select substr(LPROD_NM,4) from lprod where LPROD_ID=I)
where LPROD_ID=I;
END LOOP;
END;
<lprod_SQL.xml>
- list 쿼리문 수정
<select id="list" parameterType="hashMap" resultType="lprodVO">
WITH U AS(
SELECT ROW_NUMBER() OVER (ORDER BY T.LPROD_ID DESC) RNUM
,T.*
FROM
(
SELECT LPROD_ID, LPROD_GU, LPROD_NM
FROM LPROD
) T
)
SELECT U.*
FROM U
WHERE U.RNUM BETWEEN (#{currentPage}*#{size})-(#{size}-1)
AND (#{currentPage}*#{size})
</select>
<LprodVO.java>
- private int rnum; 추가
- getter/setter , toString 도 다시 정의한다.
package kr.or.ddit.vo;
import java.util.Arrays;
import java.util.List;
import org.springframework.web.multipart.MultipartFile;
public class LprodVO {
private int rnum;
private int lprodId;
private String lprodGu;
private String lprodNm;
private MultipartFile[] uploadFile;
// 상품분류 : 첨부파일 = 1: N
private List<AttachVO> attachVOList;
public LprodVO() {
}
public LprodVO(int lprodId) {
this.lprodId = lprodId;
}
public int getLprodId() {
return lprodId;
}
public void setLprodId(int lprodId) {
this.lprodId = lprodId;
}
public String getLprodGu() {
return lprodGu;
}
public void setLprodGu(String lprodGu) {
this.lprodGu = lprodGu;
}
public String getLprodNm() {
return lprodNm;
}
public void setLprodNm(String lprodNm) {
this.lprodNm = lprodNm;
}
public MultipartFile[] getUploadFile() {
return uploadFile;
}
public void setUploadFile(MultipartFile[] uploadFile) {
this.uploadFile = uploadFile;
}
public List<AttachVO> getAttachVOList() {
return attachVOList;
}
public void setAttachVOList(List<AttachVO> attachVOList) {
this.attachVOList = attachVOList;
}
public int getRnum() {
return rnum;
}
public void setRnum(int rnum) {
this.rnum = rnum;
}
@Override
public String toString() {
return "LprodVO [rnum=" + rnum + ", lprodId=" + lprodId + ", lprodGu=" + lprodGu + ", lprodNm=" + lprodNm
+ ", uploadFile=" + Arrays.toString(uploadFile) + ", attachVOList=" + attachVOList + "]";
}
}
<list.jsp>
- data를 고쳐주자
- <c:forEach var="lprodVO" items="${data.content}" varStatus="stat">
<!--
1) 페이징 이전
List<LprodVO> lprodVOList
mav.addObject("data", lprodVOList);
2) 페이징 이후
mav.addObject("data", new ArticlePage<LprodVO>(total, currentPage, size, lprodVOList));
ArticlePage에서 List<LprodVO> lprodVOList 꺼내야한다.
즉 private List<T> content; 를 꺼내오자
data는 ArticlePage이고
data.content는 ArticlePage의 content멤버변수
viv : 포이치 비브
stat.count : 1부터 시작
stat.index : 0부터 시작
-->
<c:forEach var="lprodVO" items="${data.content}" varStatus="stat">
<tr
<c:if test="${stat.count%2!=0}">class="odd"</c:if>
<c:if test="${stat.count%2==0}">class="even"</c:if>
>
<td class="sorting_1">${lprodVO.rnum}</td>
<td>${lprodVO.lprodId}</td>
<td>${lprodVO.lprodGu}</td>
<td><a href="/lprod/detail?lprodGu=${lprodVO.lprodGu}">${lprodVO.lprodNm}</a></td>
</tr>
</c:forEach>
우선 재기동하고 실행시켜 보자
- localhost/lprod/list?currentPage=7
- 숫자를 바꿔서 넣어보면 페이징 처리가 된 것을 볼 수 있다
페이지 이동하기
<list.jsp>
- 현재페이지를 active 시킨다.
- Previous, Next 없을 때 비활성화하기 (disabled)
<div class="row">
<div class="col-sm-12 col-md-5">
<div class="dataTables_info" id="dataTable_info" role="status"
aria-live="polite">Showing 1 to 10 of 57 entries</div>
</div>
<!-- EL태그 정리
== : eq(equal)
!= : ne(not equal)
< : lt(less than)
> : gt(greater than)
<= : le(less equal)
>= : ge(greater equl)
-->
<div class="col-sm-12 col-md-7">
<div class="dataTables_paginate paging_simple_numbers"
id="dataTable_paginate">
<ul class="pagination">
<li class="paginate_button page-item previous
<c:if test='${data.startPage <6}' >disabled</c:if>
" id="dataTable_previous">
<a href="/lprod/list?currentPage=${data.startPage-5}"
aria-controls="dataTable" data-dt-idx="0" tabindex="0"
class="page-link">Previous</a></li>
<c:forEach var="pNo" begin="${data.startPage}" end="${data.endPage}">
<li class="paginate_button page-item
<c:if test='${param.currentPage==pNo}'>active</c:if>
">
<a href="/lprod/list?currentPage=${pNo}"
aria-controls="dataTable" data-dt-idx="1" tabindex="0"
class="page-link">${pNo}</a></li>
</c:forEach>
<li class="paginate_button page-item next
<c:if test='${data.endPage == data.totalPages}'>disabled</c:if>
" id="dataTable_next">
<a href="/lprod/list?currentPage=${data.startPage+5}" aria-controls="dataTable" data-dt-idx="7" tabindex="0"
class="page-link">Next</a></li>
</ul>
</div>
</div>
</div>
BOOK도 페이징 처리 해보자!
<SQL Developer>에서 데이터를 추가해준다.
DECLARE
MAX_ID NUMBER;
BEGIN
SELECT NVL(MAX(BOOK_ID),0)+1 INTO MAX_ID
FROM BOOK;
FOR I IN 50..250 LOOP
INSERT INTO BOOK(BOOK_ID, TITLE, CATEGORY, PRICE, INSERT_DATE, CONTENT)
VALUES(I,'제목'||I,'소설',12000,SYSDATE,'내용'||I);
END LOOP;
COMMIT;
END;
<bookController.java>
- LPROD와 마찬가지로 list메서드 수정 ( getTotal())
- public int getTotal(String keyword)
// 1)요청URI : /list
// 요청파라미터 : {}
// 2)요청URI : /list?keyword=새롬이
// 요청파라미터 : {"keyword" :"새롬이"
// 요청 파라미터 : {}
// 방식 : get
// 스프링에서 요청파라미터를 매개변수로 받을 수 있음
//required=false 파라미터가 넘어오는 게 없을 수도 있다.
@RequestMapping(value="/list",method=RequestMethod.GET)
public ModelAndView list(ModelAndView mav,
@RequestParam(value="keyword", required=false) String keyword,
@RequestParam(value="currentPage", required=false, defaultValue="1") int currentPage) {
// 검색 조건
Map<String, String> map = new HashMap<String, String>();
//1) 전체 행의 수 구하기 (total)
int total = this.bookService.getTotal(keyword);
//2) 한 페이지에 보여질 행의 수 (size)
int size = 10;
map.put("size", size+"");
map.put("currentPage",currentPage+"");
map.put("keyword", keyword);
List<BookVO> bookVOList = this.bookService.list(map);
log.info("bookVOList : " + bookVOList);
//1) 페이징 전
// 데이터
//mav.addObject("data", bookVOList);
//2)페이징 후
mav.addObject("data", new ArticlePage<BookVO>(total, currentPage, size, bookVOList));
// jsp(뷰) : book폴더에 있는 list.jsp를 forwarding(jsp를 해석, 컴파일하여 html로 리턴)
mav.setViewName("book/list");
return mav;
}
dao, service 똑같이 map 파라미터를 바꿔주고 getTotal()메서드를 추가해준다.
<book_SQL.xml>
1. 전체 행의 수를 구하는 쿼리문
<!-- 전체 행의 수 (total) -->
<select id="getTotal" resultType="int">
SELECT COUNT(*) FROM BOOK
</select>
2. 검색기능은 중복으로 사용하기 때문에 따로 빼준다.
<sql id="where">
<!-- 검색 -->
<if test="keyword!=null and keyword!=''">
AND(
TITLE LIKE '%' || #{keyword} || '%'
OR CATEGORY LIKE '%' || #{keyword} || '%'
OR CONTENT LIKE '%' || #{keyword} || '%'
)
</if>
</sql>
3. list 와 getTotal 쿼리문에 include 한다.
- <include refid="where"></include>
- 이때 WHERE 1 =1 를 꼭 써주도록 한다.
<select id="list" parameterType="hashMap" resultType="bookVO">
WITH T AS(
SELECT ROW_NUMBER() OVER(ORDER BY BOOK_ID DESC) RNUM
, BOOK_ID, TITLE, CATEGORY, PRICE, INSERT_DATE, CONTENT
FROM BOOK
WHERE 1 = 1
<include refid="where"></include>
)
SELECT T.RNUM, T.BOOK_ID, T.TITLE, T.CATEGORY, T.PRICE
, T.INSERT_DATE, T.CONTENT
FROM T
WHERE T.RNUM BETWEEN (#{currentPage}*#{size})-(#{size}-1)
AND (#{currentPage}*#{size})
</select>
<!-- 전체 행의 수 (total) -->
<select id="getTotal" parameterType="String" resultType="int">
SELECT COUNT(*) FROM BOOK
WHERE 1 = 1
<include refid="where"></include>
</select>
<list.jsp>
- <c:forEach var="bookVO" items="${data.content}" varStatus="stat"> data.content를 해주어야만 리스트가 나온다.
- 테이블 안에 tfoot 태그 작성
- 꼭 tr , td안에 작성해준다.
- keyword 검색시 페이징도 같이 처리해준다.
<%@ page language="java" contentType="text/html;charset=UTF-8"%>
<%@taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<%@taglib prefix="fmt" uri="http://java.sun.com/jsp/jstl/fmt" %>
<!DOCTYPE html>
<html>
<head>
<script type="text/javascript" src="/resources/js/jquery.3.6.0.js"></script>
<title>도서관리시스템</title>
</head>
<body>
<!-- 검색 시작 -->
<p>
<!--
action 속성 및 그 값이 생략 시 , 현재 URI(/list)를 재요청.
method는 GET(form 태그의 기본 HTTP 메소드는 GET임)
-->
<!-- <form action="/list" method="get"> -->
<form>
<input type="text" name="keyword" value="${param.keyword}"
placeholder="검색어를 입력해주세요." />
<!-- /list?keyword=새롬이 -->
<input type="submit" value="검색" />
</form>
</p>
<!-- 검색 끝 -->
<p>
<table border="1">
<thead>
<tr>
<th>번호</th>
<th>제목</th>
<th>카테고리</th>
<th>가격</th>
</tr>
</thead>
<!--
forEach태그? 배열(String[][],int[][],Collection(List,Set)또는
Map(HashTable, HashMap, SortedMap)에 저장되어 있는 값들을
순차적으로 처리할 때 사용함. 자바의 for, do-while을 대신하여 사용
data : mav.addObject("data", bookVOList)
data : List<BookVO>
var : 변수(variable)
items : 아이템(배열, Collection, Map)
varStatus : 루프 정보르 담은 객체
- index : 루프(반복) 실행 시 현재 인덱스(0부터 시작)
- count : 실행 회수(1부터 시작, 보통 행번호를 출력)
-->
<tbody>
<c:forEach var="bookVO" items="${data.content}" varStatus="stat">
<tr>
<td>${bookVO.rnum}</td>
<td><a href="/detail?bookId=${bookVO.bookId}">${bookVO.title}</a></td>
<td>${bookVO.category}</td>
<td><fmt:formatNumber type="number" maxFractionDigits="3"
value="${bookVO.price}" /></td>
</tr>
</c:forEach>
</tbody>
<tfoot>
<tr>
<td colspan="4">
<!-- 페이지 넘기기 -->
<ul class="pagination">
<li class="paginate_button page-item previous
<c:if test='${data.startPage <6}' >disabled</c:if>
" id="dataTable_previous">
<a href="/list?currentPage=${data.startPage-5}"
aria-controls="dataTable" data-dt-idx="0" tabindex="0"
class="page-link">Previous</a></li>
<c:forEach var="pNo" begin="${data.startPage}" end="${data.endPage}">
<li class="paginate_button page-item
<c:if test='${param.currentPage==pNo}'>active</c:if>
">
<a href="/list?currentPage=${pNo}"
aria-controls="dataTable" data-dt-idx="1" tabindex="0"
class="page-link">${pNo}</a></li>
</c:forEach>
<li class="paginate_button page-item next
<c:if test='${data.endPage == data.totalPages}'>disabled</c:if>
" id="dataTable_next">
<a href="/list?currentPage=${data.startPage+5}" aria-controls="dataTable" data-dt-idx="7" tabindex="0"
class="page-link">Next</a></li>
</ul>
<!-- 페이지 넘기기 끝 -->
</td>
</tr>
</tfoot>
</table>
</p>
<p>
<a href="/create">책 생성</a>
</p>
</body>
</html>
LPROD 에도 검색 기능을 만들자!
Book에서 했던 방식과 똑같이 keyword를 사용한다.
dao,service에서는 getTotal(String keyword) 파라미터에 keyword를 넣어준다.
<LprodController.java>
// 요청URI : /lprod/list?currentPage=3
//1)요청파라미터 : currentPage=2
//2)요청파라미터 : 없을 때 ---> 이 두 가지 처리를 다 해줘야 함
// required : 필수있지 아닌지
// defalutValue : 없을 때 기본 값 -> 1일경우 1페이지로 간주함
// currentPage=2 파라미터의 타입은 String , 하지만 int 타입의 매개변수로 자동 형변환 가능 (스프링에서 지원함)
@RequestMapping(value="/list",method=RequestMethod.GET)
public ModelAndView list(ModelAndView mav,
@RequestParam(value="currentPage", required=false, defaultValue="1") int currentPage,
@RequestParam(value="size", required=false, defaultValue="10") int size,
@RequestParam(value="keyword", required=false) String keyword
) {
//검색 조건
Map<String,String> map = new HashMap<String, String>();
//1) 전체 행의 수 구하기(total)
int total = this.lprodService.getTotal(keyword);
//3) 한 페이지에 보여질 행의 수(size)
// int size = 10;
//map{"size":"10","currentPage":"1","keyword":""}
map.put("size", size+"");
map.put("currentPage", currentPage+"");
map.put("keyword", keyword);
log.info("map : " + map);
List<LprodVO> lprodVOList = this.lprodService.list(map);
//페이징 처리 전.. data
//mav.addObject("data", lprodVOList);
//페이징 처리 후..
mav.addObject("data"
, new ArticlePage<LprodVO>(total, currentPage, size, lprodVOList));
//jsp경로
//tiles-config.xml의
// */*은 lprod/list와 {1}/{2}.jsp에 의해 lprod/list.jsp가 forwarding됨
mav.setViewName("lprod/list");
return mav;
}
<lprod_SQL.xml>
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<!-- namespace : xml 파일이 여러개일 수 있으므로
이를 구별하기 위한 식별 용도로 사용 -->
<mapper namespace="lprod">
<!-- LPROD : ATTACH : 1 : N -->
<resultMap type="lprodVO" id="lprodMap">
<result property="lprodGu" column="LPROD_GU"/>
<result property="lprodId" column="LPROD_ID" />
<result property="lprodNm" column="LPROD_NM" />
<collection property="attachVOList" resultMap="attachMap"></collection>
</resultMap>
<resultMap type="attachVO" id="attachMap">
<result property="etpId" column="ETP_ID"/>
<result property="seq" column="SEQ"/>
<result property="filename" column="FILENAME"/>
<result property="filesize" column="FILESIZE"/>
<result property="thumbnail" column="THUMBNAIL"/>
<result property="regdate" column="REGDATE"/>
</resultMap>
<sql id="where">
<!-- 검색 -->
<if test="keyword!=null and keyword!=''">
AND(
LPROD_GU LIKE '%' || #{keyword} || '%'
OR LPROD_NM LIKE '%' || #{keyword} || '%'
)
</if>
</sql>
<!-- //map{"size":"10","currentPage":"1"} -->
<select id="list" parameterType="hashMap" resultType="lprodVO">
WITH U AS(
SELECT ROW_NUMBER() OVER (ORDER BY T.LPROD_ID DESC) RNUM
,T.*
FROM
(
SELECT LPROD_ID, LPROD_GU, LPROD_NM
FROM LPROD
WHERE 1 = 1
<include refid="where"></include>
) T
)
SELECT U.*
FROM U
WHERE U.RNUM BETWEEN (#{currentPage}*#{size})-(#{size}-1)
AND (#{currentPage}*#{size})
</select>
<!-- 상품분류 자동생성 -->
<select id="getLprodId" resultType="int">
SELECT NVL(MAX(TO_NUMBER(LPROD_ID)),0)+1 FROM LPROD
</select>
<!-- 상품분류코드 자동생성 -->
<select id="getLprodGu" resultType="String">
SELECT SUBSTR(MAX(LPROD_GU),1,1) || (SUBSTR(MAX(LPROD_GU),2) + 1)
FROM LPROD
</select>
<!-- 상품분류 정보를 입력 -->
<insert id="createPost" parameterType="lprodVO">
<selectKey order="BEFORE" keyProperty="lprodId" resultType="int">
SELECT NVL(MAX(LPROD_ID),0)+1 FROM LPROD
</selectKey>
INSERT INTO LPROD(LPROD_ID, LPROD_GU, LPROD_NM)
VALUES(#{lprodId},(SELECT SUBSTR(MAX(LPROD_GU),1,1) || (SUBSTR(MAX(LPROD_GU),2) + 1)
FROM LPROD),#{lprodNm})
</insert>
<!-- 상품분류 상세보기 -->
<select id="detail" parameterType="lprodVO" resultMap="lprodMap">
SELECT A.LPROD_ID, A.LPROD_GU, A.LPROD_NM,
B.SEQ, B.FILENAME, B.FILESIZE, B.THUMBNAIL, B.REGDATE, B.ETP_ID
FROM LPROD A LEFT JOIN ATTACH B ON(A.LPROD_GU = B.ETP_ID)
WHERE A.LPROD_GU = #{lprodGu}
</select>
<!-- 상품분류 정보변경 -->
<update id="updatePost" parameterType="lprodVO">
UPDATE LPROD
SET LPROD_NM = #{lprodNm}
WHERE LPROD_GU = #{lprodGu}
</update>
<!-- 상품분류 정보 삭제 -->
<delete id="deletePost" parameterType="lprodVO">
DELETE FROM LPROD
WHERE LPROD_GU = #{lprodGu}
</delete>
<!-- 첨부파일 등록 -->
<insert id="uploadFormAction" parameterType="attachVO">
<selectKey resultType="int" order="BEFORE" keyProperty="seq" >
SELECT NVL(MAX(SEQ),0)+1 FROM ATTACH
</selectKey>
INSERT INTO ATTACH(SEQ, FILENAME, FILESIZE, THUMBNAIL, REGDATE)
VALUES(
#{seq},#{filename},#{filesize},#{thumbnail},SYSDATE
)
</insert>
<!-- 다중 insert 시 update 태그를 사용
파라미터 : List<AttachVO attachVOList
insert, update, delete의 경우 resultType은 생략
separator=" " : 공백으로 구분
-->
<update id="createPostAttach" parameterType="java.util.List">
<!--
order="BEFORE"는 foreach 태그 실행 전에 selectKey부터 실행
-->
<selectKey resultType="int" order="BEFORE" keyProperty="seq">
SELECT NVL(MAX(SEQ),0)+1 FROM ATTACH
</selectKey>
<!-- index : 반복 시 index값. 0부터 시작. -->
<foreach collection="list" item="attachVO"
open="INSERT ALL" close="SELECT * FROM DUAL" separator=" "
index="idx" >
INTO ATTACH(SEQ, FILENAME, FILESIZE, THUMBNAIL, REGDATE, ETP_ID)
VALUES(#{idx}+#{seq},#{attachVO.filename},#{attachVO.filesize},#{attachVO.thumbnail},sysdate,
#{attachVO.etpId})
</foreach>
</update>
<!-- 전체 행의 수 (total) -->
<select id="getTotal" resultType="int">
SELECT COUNT(*) FROM LPROD
WHERE 1 = 1
<include refid="where"></include>
</select>
</mapper>
<list.jsp>
option value 고정
검색어 고정
<%@ page language="java" contentType="text/html;charset=UTF-8"%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>
<!-- Page Heading -->
<h1 class="h3 mb-2 text-gray-800">Tables</h1>
<p class="mb-4">
DataTables is a third party plugin that is used to generate the demo
table below. For more information about DataTables, please visit the <a
target="_blank" href="https://datatables.net">official DataTables
documentation</a>.
</p>
<!-- DataTales Example -->
<div class="card shadow mb-4">
<div class="card-header py-3">
<h6 class="m-0 font-weight-bold text-primary">DataTables Example</h6>
</div>
<div class="card-body">
<div class="table-responsive">
<div id="dataTable_wrapper" class="dataTables_wrapper dt-bootstrap4">
<div class="row" style="width:100%;">
<!-- action="/lprod/list" method="get" 생략가능
요청URI : /lprod/list?keyword=새롬이¤tPage=2&size=10
-->
<form name="frm" id="frm" action="/lprod/list" method="get"
style="width:100%;">
<div class="col-sm-12 col-md-6" style="float:left;">
<div class="dataTables_length" id="dataTable_length">
<label>Show <select name="size"
aria-controls="dataTable"
class="custom-select custom-select-sm form-control form-control-sm">
<option <c:if test="${param.size == 10}">selected</c:if>value="10" >10</option>
<option value="25" <c:if test="${param.size == 25}">selected</c:if>>25</option>
<option value="50" <c:if test="${param.size == 50}">selected</c:if>>50</option>
<option value="100" <c:if test="${param.size == 100}">selected</c:if>>100</option></select> entries
</label>
</div>
</div>
<div class="col-sm-12 col-md-6" style="float:right;">
<div id="dataTable_filter" class="dataTables_filter">
<label>Search:<input type="search"
name="keyword"
value="${param.keyword}"
class="form-control form-control-sm"
placeholder="검색어를 입력해주세요"
aria-controls="dataTable" /></label>
<button type="submit" class="btn btn-primary">검색</button>
</div>
</div>
</form>
</div>
<div class="row">
<div class="col-sm-12">
<table class="table table-bordered dataTable" id="dataTable"
width="100%" cellspacing="0" role="grid"
aria-describedby="dataTable_info" style="width: 100%;">
<thead>
<tr role="row">
<th class="sorting sorting_asc" tabindex="0"
aria-controls="dataTable" rowspan="1" colspan="1"
aria-sort="ascending"
aria-label="순번: activate to sort column descending"
style="width: 64.75px;">순번</th>
<th class="sorting" tabindex="0" aria-controls="dataTable"
rowspan="1" colspan="1"
aria-label="상품분류 아이디: activate to sort column ascending"
style="width: 80.6094px;">상품분류 아이디</th>
<th class="sorting" tabindex="0" aria-controls="dataTable"
rowspan="1" colspan="1"
aria-label="상품분류 구분: activate to sort column ascending"
style="width: 55.7969px;">상품분류 구분</th>
<th class="sorting" tabindex="0" aria-controls="dataTable"
rowspan="1" colspan="1"
aria-label="상품분류 명: activate to sort column ascending"
style="width: 30.1719px;">상품분류 명</th>
</tr>
</thead>
<tbody>
<!--
1) 페이징 이전
List<LprodVO> lprodVOList
mav.addObject("data", lprodVOList);
2) 페이징 이후
mav.addObject("data", new ArticlePage<LprodVO>(total, currentPage, size, lprodVOList));
ArticlePage에서 List<LprodVO> lprodVOList 꺼내야한다.
즉 private List<T> content; 를 꺼내오자
data는 ArticlePage이고
data.content는 ArticlePage의 content멤버변수
viv : 포이치 비브
stat.count : 1부터 시작
stat.index : 0부터 시작
-->
<c:forEach var="lprodVO" items="${data.content}" varStatus="stat">
<tr
<c:if test="${stat.count%2!=0}">class="odd"</c:if>
<c:if test="${stat.count%2==0}">class="even"</c:if>
>
<td class="sorting_1">${lprodVO.rnum}</td>
<td>${lprodVO.lprodId}</td>
<td>${lprodVO.lprodGu}</td>
<td><a href="/lprod/detail?lprodGu=${lprodVO.lprodGu}">${lprodVO.lprodNm}</a></td>
</tr>
</c:forEach>
</tbody>
</table>
</div>
</div>
<div class="row">
<div class="col-sm-12 col-md-5">
<div class="dataTables_info" id="dataTable_info" role="status"
aria-live="polite">Showing 1 to 10 of 57 entries</div>
</div>
<!-- EL태그 정리
== : eq(equal)
!= : ne(not equal)
< : lt(less than)
> : gt(greater than)
<= : le(less equal)
>= : ge(greater equl)
-->
<div class="col-sm-12 col-md-7">
<div class="dataTables_paginate paging_simple_numbers"
id="dataTable_paginate">
<ul class="pagination">
<li class="paginate_button page-item previous
<c:if test='${data.startPage <6}' >disabled</c:if>
" id="dataTable_previous">
<!-- &keyword=${param.keyword} -->
<a href="/lprod/list?currentPage=${data.startPage-5}&keyword=${param.keyword}"
aria-controls="dataTable" data-dt-idx="0" tabindex="0"
class="page-link">Previous</a></li>
<c:forEach var="pNo" begin="${data.startPage}" end="${data.endPage}">
<li class="paginate_button page-item
<c:if test='${param.currentPage==pNo}'>active</c:if>
">
<a href="/lprod/list?currentPage=${pNo}&keyword=${param.keyword}"
aria-controls="dataTable" data-dt-idx="1" tabindex="0"
class="page-link">${pNo}</a></li>
</c:forEach>
<li class="paginate_button page-item next
<c:if test='${data.endPage == data.totalPages}'>disabled</c:if>
" id="dataTable_next">
<a href="/lprod/list?currentPage=${data.startPage+5}&keyword=${param.keyword}" aria-controls="dataTable" data-dt-idx="7" tabindex="0"
class="page-link">Next</a></li>
</ul>
</div>
</div>
</div>
<div class="row">
<!-- 요청URI : /lprod/create
방식 : GET
-->
<a href="/lprod/create" class="btn btn-primary btn-icon-split">
<span class="icon text-white-50">
<i class="fas fa-flag"></i>
</span>
<span class="text">상품분류 추가</span>
</a>
</div>
</div>
</div>
</div>
</div>
'Spring' 카테고리의 다른 글
Spring 16 - LPROD에 파일 다운로드 하기 (0) | 2023.02.02 |
---|---|
Spring 15 - 파일 다운로드 , Ajax 연습 (0) | 2023.02.02 |
Spring 13 - 1:N 관계 테이블(BOOK,LPROD)을 이용하여 상세화면 구현 (0) | 2023.01.31 |
Spring 12 - Book 테이블도 파일업로드 해보자 (0) | 2023.01.30 |
Spring 11 - LPROD, ATTACH 테이블 연결 (일대다 관계 ResultMap 사용) + 한글깨짐 해결하기 (0) | 2023.01.30 |
Comments