수업내용/Web

[2022.11.10.목] 도서 수정, 삭제, 페이징 처리하기

주니어주니 2022. 11. 10. 19:07

 

 

* 가격 형식, 날짜 형식

 

StringUtils 클래스 추가 -> numberToText, dateToText 정의 

가격, 날짜 부분을 모두 stringUtils를 씌움 

 

package com.sample.util;

import java.text.DecimalFormat;
import java.text.SimpleDateFormat;
import java.util.Date;

public class StringUtils {

	private static final DecimalFormat decimalFormat = new DecimalFormat("#,###.##");
	private static final SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy년 M월 d일");
	
	/**
	 * Date를 "2022년 11월 10일" 형식의 문자열로 변환해서 반환한다.
	 * @param date 날짜
	 * @return 연월일 형식의 문자열, 날짜가 null이면 빈 문자열 반환
	 */
	
	public static String dateToText(Date date) {
		if(date==null) {
			return "";
		}
		return simpleDateFormat.format(date);
	}
	
	/**
	 * 정수를 3자리마다 ,가 포함된 문자열로 변환해서 반환한다.
	 * @param number 정수
	 * @return ,가 포함된 문자열
	 */
	public static String numberToText(long number) {
		return decimalFormat.format(number);
	}
	
	/**
	 * 실수를 소수점 3번째 자리에서 반올림하고, 정수부는 3자리마다 ,가 포함된 문자열로 변환해서 반환한다.
	 * @param number 실수
	 * @return ,가 포함된 문자열(소수점 3번째 자리에서 반올림) 
	 */
	public static String numberToText(double number) {
		return decimalFormat.format(number);
	}
	
	
}

 

 

- Book의 detail.jsp 의 등록일자를 날짜형식으로 표시 

 

<tr>
	<th>등록일자</th>
	<td><%=StringUtils.dateToText(book.getCreatedDate()) %></td>
</tr>

 

- Book 의 list.jsp와 detail.jsp의 가격을 가격 형식, 효과 주기 

 

<tr>
	<th>가격</th>
	<td><%=StringUtils.numberToText(book.getPrice()) %> 원</td>
	<th>할인가격</th>
	<td>
	    <strong class="text-danger"><%=StringUtils.numberToText(book.getDiscountPrice()) %> 원</strong>
	</td>
</tr>

 

 

 

 


 

 

 

* 할인율 계산 

Product 객체의 getter, setter 부분에 계산식 추가

 

- Product 

 

public int getDiscountPrice() {
	return (int) (price*(1-discountRate));
}
public int getDiscountPerCent() {
	return (int) (discountRate*100);
}

 

 

- Product의 detail.jsp의 할인율 표시

 

<th>할인가격</th>
<td>
   <strong class="text-danger"><%=StringUtils.numberToText(product.getDiscountPrice()) %> 원</strong> 
   <small class="text-danger">(<%=product.getDiscountPerCent() %>%)</small>
</td>

 

 

 


 

 

* 판매여부 표시 

 

 

* Product -> 판매여부가 "y"이면 "판매중", "y"가 아니면 "재고없음" 표시 

 

- Product 의 list.jsp와 detail.jsp의 판매여부를 배지로 표시 

 

<td>
<%
   if("y".equals(product.getOnSell())) {
%>
   <span class="badge text-bg-primary">판매중</span>
<%
   } else {
%>
   <span class="badge text-bg-secondary">재고없음</span>
<%
   }
%>
</td>

 

 

 

 

 

 

 

* Book -> 재고가 0보다 많으면 "판매중", 0이면 "재고없음" 표시 

 

- Book 

 

public boolean isOnSell() {
	return stock > 0;
}

 

- Book의 detail.jsp에서 판매 배지 표시 

 

<th>판매여부</th>
<td>
	<%
		if(book.isOnSell()){
	%>
		<span class="badge text-bg-primary">판매중</sapn>	
	<%
		} else {
	%>
		<span class="badge text-bg-secondary">재고없음</span>	
	<% 
		}
	%>
</td>

 

 

 

 

 


 

 


* 삭제 

 

 

0. 재고가 없는 경우에만 삭제 버튼 활성화, 재고 있으면 삭제 버튼 비활성화

1. detail.jsp의 삭제버튼 링크에서  delete.jsp?bookNo=책번호 URL을 서버로 보내서 도서정보 삭제 요청

2. 톰캣이 요청메시지를 분석해서 URL의 쿼리스트링값을 HttpServletRequest에 요청파라미터로 저장

3. 톰캣은 요청파라미터값이 저장된 HttpServletRequest 객체, HttpServletResponse 객체를 delete.jsp의 _jspService(request, response)를 실행할 때 전달

4. delete.jsp에서는 요청파라미터값 조회 

 

 

 

- xml에서 delete SQL 추가

 

<delete id="deleteBookByNo" parameterClass="int">
	delete from
		sample_books
	where 
		book_no = #value#
</delete>

 

- DAO 에서 delete 메소드 추가 

 

public void deleteBookByNo(int no) {
	SqlMapper.delete("deleteBookByNo", no);
}

 

- detail.jsp의 <table> 아래 부분에 삭제버튼 추가, 버튼의 링크에서 delete.jsp로 요청

 

<div>
<a href="delete.jsp?bookNo=<%=book.getNo() %>" class="btn btn-danger <%=book.isOnSell() ? "disabled" : ""%>">삭제</a>
</div>

 

- delete.jsp 

 

<%@page import="com.sample.dao.BookDao"%>
<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<%
	// 요청파라미터에서 책번호 조회 
	int bookNo = Integer.parseInt(request.getParameter("bookNo")); 

	// BookDao 객체를 생성해서 deleteBookByNo(int bookNo) 메소드를 실행시킨다. 
	BookDao bookDao = new BookDao();
	bookDao.deleteBookByNo(bookNo);
	
	// 재요청할 URL을 응답으로 보낸다.
	response.sendRedirect("list.jsp");

%>

 

 

 

 

 


 

 

 

* 수정 

 

 

 

1) 수정폼

 

1. detail.jsp의 수정버튼 링크에서 modifyform.jsp?bookNo=책번호 URL을 서버로 보내서 도서 수정폼 화면 요청

2. 톰캣이 요청메시지를 분석해서 URL의 쿼리스트링값을 HttpServletRequest에 요청파라미터로 저장

3. 톰캣은 요청파라미터값이 저장된 HttpServletRequest 객체, HttpServletResponse 객체를 modifyform.jsp의 _jspService(request, response)를 실행할 때 전달

4. modifyform.jsp에서는 요청파라미터값 조회

 

 

- detail.jsp의 수정버튼에서 수정폼 화면 요청

 

<a href="modifyform.jsp?bookNo=<%=book.getNo() %>" class="btn btn-warning">수정</a>

 

 

- modifyform.jsp 

 

수정폼에 원래값이 나와있어야 하니까

책정보를 조회해서 그 값을 입력필드 value에 꼭 넣어둬야함

이 modifyform 은 method="post", action="update.jsp"

-> post형식으로 입력폼 전체를 update.jsp로 요청

 

<%@page import="com.sample.vo.Book"%>
<%@page import="com.sample.dao.BookDao"%>
<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.2.2/dist/css/bootstrap.min.css" rel="stylesheet">
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.2.2/dist/js/bootstrap.bundle.min.js"></script>
<title>도서정보 변경</title>
</head>
<body>
	<div class="container py-5">
		<h1>도서 정보 수정폼</h1>
	
	<%
		// 요청파라미터 값을 조회한다.
		int bookNo = Integer.parseInt(request.getParameter("bookNo"));
	
		// 책 번호에 해당하는 책 객체를 조회한다.
		BookDao bookDao = new BookDao();
		Book book = bookDao.getBookByNo(bookNo);
	%>
		<p>도서 정보를 수정하고, 업데이트 하세요</p>
		<form class="bg-light border p-3" method="post" action="update.jsp">
			<!-- 
				hidden 필드
					- 화면에 표시되지 않는 폼 입력요소
					- 화면에 표시할 필요는 없지만 폼 입력값을 서버로 제출할 때 포함되어야 하는 값을 hidden 필드로 정의한다.
			 -->
			<input type="hidden" name="no" value="<%=book.getNo() %>" />
			<div class="mb-3">
				<label class="form-label">제목</label>
				<input type="text" class="form-control" name="title" value="<%=book.getTitle() %>"/>
			</div>
			<div class="mb-3">
				<label class="form-label">저자</label>
				<input type="text" class="form-control" name="author" value="<%=book.getAuthor() %>"/>
			</div>
			<div class="mb-3">
				<label class="form-label">출판사</label>
				<select class="form-select" name="publisher">
					<option value="" selected="selected" disabled="disabled"> 출판사를 선택하세요</option>
					<option value="한빛미디어" <%="한빛미디어".equals(book.getPublisher()) ? "selected" : "" %>> 한빛미디어</option>
					<option value="제이펍" <%="제이펍".equals(book.getPublisher()) ? "selected" : "" %>> 제이펍</option>
					<option value="위키북스" <%="위키북스".equals(book.getPublisher()) ? "selected" : "" %>> 위키북스</option>
					<option value="길벗" <%="길벗".equals(book.getPublisher()) ? "selected" : "" %>> 길벗</option>
					<option value="에이콘출판사" <%="에이콘출판사".equals(book.getPublisher()) ? "selected" : "" %>> 에이콘출판사</option>
					<option value="이지스퍼블리싱" <%="이지스퍼블리싱".equals(book.getPublisher()) ? "selected" : "" %>> 이지스퍼블리싱</option>
					<option value="인사이트" <%="인사이트".equals(book.getPublisher()) ? "selected" : "" %>> 인사이트</option>
					<option value="생능출판사" <%="생능출판사".equals(book.getPublisher()) ? "selected" : "" %>> 생능출판사</option>
				</select>
			</div>
			<div class="mb-3">
				<label class="form-label">가격</label>
				<input type="number" class="form-control" name="price" min="0"  value="<%=book.getPrice() %>"/>
			</div>
			<div class="mb-3">
				<label class="form-label">할인가격</label>
				<input type="number" class="form-control" name="discountPrice" min="0" value="<%=book.getDiscountPrice() %>"/>
			</div>
			<div class="mb-3">
				<label class="form-label">수량</label>
				<input type="number" class="form-control" name="stock" value="<%=book.getStock() %>" min="1" step="1" max=100 />
			</div>
			<div class="text-end">
				<a href="detail.jsp?bookNo=<%=book.getNo() %>" class="btn btn-secondary">취소</a>
				<button type="submit" class="btn btn-primary">수정</button>
			</div>
		</form>
	</div>
</body>
</html>

 

 

 

- update로 갈거야 

 

- xml 에서 update SQL

 

<update id="updateBook" parameterClass="com.sample.vo.Book">
	update
		sample_books
	set
		book_title = #title#,
		book_author = #author#,
		book_publisher = #publisher#,
		book_price = #price#,
		book_discount_price = #discountPrice#,
		book_stock = #stock#,
		book_updated_date = sysdate
	where 
		book_no = #no#
</update>

 

 

- Dao 

 

public void updateBook(Book book) {
	SqlMapper.update("updateBook", book);
}

 

 

- update.jsp

 

원본 조회 -> 객체를 생성해서 담지 않고 내가 지금 바꿀것만 바로 변경 ->Dao 에 업데이트쿼리를 여러개 x 

 

<%@page import="com.sample.vo.Book"%>
<%@page import="com.sample.dao.BookDao"%>
<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<% 
	// modifyform.jsp에서 제출한 폼입력값을 전부 조회한다. 
	int no = Integer.parseInt(request.getParameter("no"));
	String title = request.getParameter("title");
	String author = request.getParameter("author");
	String publisher = request.getParameter("publisher");
	int price = Integer.parseInt(request.getParameter("price"));
	int discountPrice = Integer.parseInt(request.getParameter("discountPrice"));
	int stock = Integer.parseInt(request.getParameter("stock"));

	// 책 번호로 책정보를 조회한다.
	BookDao bookDao = new BookDao();
	Book book = bookDao.getBookByNo(no);
	
	// 데이터베이스에 조회한 책정보를 수정폼에서 제출한 값으로 변경한다. 
	book.setTitle(title);
	book.setAuthor(author);
	book.setPublisher(publisher);
	book.setPrice(price);
	book.setDiscountPrice(discountPrice);
	book.setStock(stock);
	
	// BookDao 객체의 updateBook(Book book) 메소드를 실행해서 변경된 책정보를 반영시킨다. 
	bookDao.updateBook(book);
	
	// 이 JSP는 추가/변경/삭제 중 하나를 수행하므로 재요청 URL을 응답으로 보낸다. 
	response.sendRedirect("list.jsp");
%>

 

 

 

 

 


 

 

* 페이징 처리 (많은 항목을 최신순 10개씩 보이게 하기) 

 

 

페이징 처리 1) 페이지번호에 맞는 데이터 출력하기

 

1. 한 화면에 표시할 행의 개수 결정
          final int rows = 10;


2. 현재 페이지 번호 조회
          int currentPage = Integer.parseInt(request.getParameter("page"));


3. 현재 페이지 번호에 맞는 조회범위 게산 (1~10, 11~20, ...)
          int begin = (currentPage - 1)*rows + 1;
          int end = currentPage*rows; 


4. Map객체를 생성해서 조회범위 저장
          Map<String, Object> param = new HashMap();
          param.put("begin", begin);
          param.put("end", end);

5. 현재 페이지번호에 맞는 책 목록을 조회하기 위해서 BookDao 객체 생성
          BookDao bookDao = new BookDao();


6. 현재 페이지번호에 맞는 책 목록 반환
          List<Book> bookList = bookDao.getBooks(param);

 

 

 

- xml 에서 페이지 번호에 맞는 책목록 반환하는 SQL 

<select id="getBooks" parameterClass="map" resultClass="com.sample.vo.Book">
      select
         book_no as no,
         book_title as title,
         book_author as author,
         book_publisher as publisher,
         book_price as price,
         book_discount_price as discountPrice,
         book_stock as stock,
         book_created_date as createdDate,
         book_updated_date as updatedDate
      from
         (select 
            row_number() over (order by book_no desc) row_numbers, 
            book_no, book_title, book_author, book_publisher, book_price, book_discount_price,
            book_stock, book_created_date, book_updated_date
          from
             sample_books)
      where
         row_numbers between #begin# and #end#      
  </select>

 

- DAO 에서 페이지 번호에 맞는 책목록 반환하는 메소드 

 

	@SuppressWarnings("unchecked")
	public List<Book> getBooks(Map<String, Object> param){
		return (List<Book>) SqlMapper.selectList("getBooks", param);
	}

 

- list.jsp 의 윗부분

 

<h1>도서 리스트</h1>
		
<%
		// 페이징 처리하기
			
		// 1. 한 화면에 표시할 행의 갯수를 결정하기
		final int rows = 10;
		
		// 2. 현재 페이지 번호를 조회하기
		int currentPage = Integer.parseInt(request.getParameter("page"));
			
		// 3. 현재 페이지 번호에 맞는 조회범위 계산하기
		int begin = (currentPage - 1)*rows + 1;
		int end = currentPage*rows;
			
		// 4. Map객체를 생성해서 조회범위를 저장한다.
		Map<String, Object> param = new HashMap<>();
		param.put("begin", begin);
		param.put("end", end);		
			
		// 현재 페이지번호에 맞는 책 목록을 조회하기 위해서 BoardDao객체를 생성한다.
		BookDao bookDao = new BookDao();
		// BoardDao객체의 getAllBooks() 메소드를 실행해서 현재 페이지번호에 맞는 책 목록을 반환받는다.
		List<Book> books = bookDao.getBooks(param);
%>

 

 

 

 

 

페이징 처리 2) 페이지 내비게이션 표시 (이전, 1, 2, 3, 4, 5, 다음)

 

 

1. 한 화면에 표시할 페이지번호 개수 결정하기  ( 한 화면에 5페이지씩만 보여줄거야 )

     int pages = 5;

 

2. 전체 데이터행의 개수 조회

          int totalRows = bookDao.getTotalRows();

 

3.  전체 페이지 개수 계산

          int totalPages = (int) (Math.ceil( (double) totalRows / rows ))

          ( 실수로 나눠야 ceil을 할 수 있음 -> 이걸 다시 정수로 변환 -> 총 페이지 수 ) 

 

2. 총 페이지 블록의 개수 계산하기 ( 총 6페이진데 5페이지씩만 보여줄거면 -> 2 페이지 블록 필요 ) 

     int totalPageBlocks = (int) Math.ceil( (double) totalPages / pages ) 

 

3. 현재 페이지블록 계산하기 ( 1 ~ 5 페이지는 1페이지 블록, 6~ 나머지는 2페이지 블록 ) 

     int currnetPageBlock = (int ) Math.ceil( (double) curremtPage / pages ) 

 

4. 현재 페이지블록에 맞는 시작페이지번호와 끝페이지번호를 계산하기 

     int beginPage = (currentPageBlock - 1) *pages + 1;

     int endPage = currentPageBlock*pages; 

     if (currentPageBlock == totalPageBlocks ) { 

                 endPage = totalPages;

     } 

 

5. 페이지 내비게이션 출력

          <%

                for (int number = 1; number <= totalPages; number) {

         %> 

                    <li class="page-item"><a class="page-link" href="#">1</a></li>

         <%

              }

        %>

 

 

 

 

- xml 에서 전체 행 개수 조회하는 SQL 

 

<select id="getTotalRows" resultClass="int">
	select
		count(*)
	from
		sample_books
</select>

 

 

- Dao 에서 전체 행 개수 조회하는 메소드 

 

public int getTotalRows() {
	return (Integer) SqlMapper.selectOne("getTotalRows");
}

 

 

 

		<%
			// 페이지 내비게이션 표시 
			
			// 1. 한 화면에 표시할 페이지번호 개수 결정 
			int pages = 5;
		
			// 2. 전체 책 개수 조회 
			int totalRows = bookDao.getTotalRows();
			
			// 3. 전체 페이지 개수 조회
			int totalPages = (int) Math.ceil((double) totalRows/rows);
			
			// 4. 전체 페이지 블록 개수 계산 
			int totalPageBlocks = (int) Math.ceil((double) totalPages/pages);
			
			// 5. 현재 페이지가 속한 페이지 블록 계산
			int currentPageBlock = (int) Math.ceil((double) currentPage/pages);
			
			// 6. 현재 페이지블록의 시작페이지번호와 끝 페이지번호 계산 
			int beginPage = (currentPageBlock - 1)*pages + 1;
			int endPage = currentPageBlock == totalPageBlocks ? totalPages : currentPageBlock*pages;
		%>
		
		<div aria-label="navigation">
			<ul class="pagination justify-content-center">
				<li class="page-item <%=currentPage <= 1 ? "disabled" : "" %>">
					<a class="page-link" href="list.jsp?page=<%=currentPage - 1 %>">이전</a>
				</li>
		<%
			for (int number = beginPage; number <= endPage; number++) {
		%>
				<li class="page-item <%=currentPage == number ? "active" : "" %>">
					<a class="page-link" href="list.jsp?page=<%=number %>"><%=number %></a>
				</li>
		<%
			}
		%>
				<li class="page-item <%=currentPage >= totalPages ? "disabled" : "" %>">
					<a class="page-link" href="list.jsp?page=<%=currentPage + 1%>">다음</a></li>
			</ul>
		</div>