-
학원 day51. namespace, pagination, 주소표기법, 장바구니 기능기록 2022. 11. 17. 01:05
기타.
- webapp 폴더 밑에 파일이 있어야 브라우저에 나온다.
- 항상 vo먼저 만들기
- vo -> jsp -> xml -> ibatis 등록 -> dao -> jsp
- 이미지파일은 모두 resources/images 밑에 들어가니까 db안에 이미지파일명만 들어간다.
오늘 실수 한 것.
- 부적절한 식별자 : 쿼리에 book_on_sell인데 book_onSell이라고 적음..
book_discount_price인데 book_discountPrice라고 적음..
=> vo클래스 말고 데이터베이스 테이블 보면서 적자!!
- from키워드가 없습니다. : 쿼리에 , 빠뜨렸다... (신경썼는데 중간에 수정하면서 빠뜨림..)
=> 쿼리문 작성 후에 데이터베이스에 복붙해서 실제로 실행되는지 확인하기!!
- there is no statement :
1. 아이디 앞에 네임스페이스 붙였는지 확인한다.
2. ibatis에 xml 등록했는지 확인한다!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
3. xml의 아이디와 Dao에서 아이디가 같은지 확인한다.
- 이미지 가져오기 코드 :
<td><img src="../resources/images/image-1.jpg" class="img-thumbnail"></td>
▼
<td><img src="../resources/images/<%=book.getImage() %>"
class="img-thumbnail"></td>
namespace 활용하기 (SQL구문에서 아이디의 충돌 방지 목적
1. ibatis-config.xml에 아래의 설정을 추가한다.
<!-- SQL 구문에 네임스페이스 사용을 활성화한다. -->
<settings useStatementNamespaces="true" /> // ibatis는 기본적으로 namespace를 비활성화하기 때문에 transactionManager 코드 위에 붙여준다.2. books.xml, boards.xml, reviews.xml, users.xml에서 네임스페이스를 지정한다.
<sqlMap namespace="books">
3. BookDao.java, BoardDao.java, ReviewDao.java, UserDao.java에서 아이디 이름 앞에 books.를 적는다.
public int getTotalRows() {
return (Integer) SqlMapper.selectOne("books.getTotalRows");
페이징처리에 Pagination 클래스 적용하기
- 옵션이 3개
첫번째는, 한 화면에 표시되는 행의 갯수, 페이지번호 갯수가 정해져있는 옵션
두번째는, 한 화면에 표시되는 페이지번호 갯수만 정해져있는 옵션
세번째는, 모든 갯수를 변경할 수 있는 옵션
- 요청한 페이지 번호의 조회 시작번호와 끝번호를 반환하는 메소드가 있어서 외부 jsp에서 식을 적을 필요가 없다.
package com.sample.util; public class Pagination { private int rows; // 한 화면에 표시되는 데이터 갯수 private int pages; // 한 화면에 표시되는 페이지번호 갯수 private int currentPage; // 요청한 페이지 번호 private int totalRows; // 전체 데이터 갯수 /** * 요청한 페이지번호, 전체 데이터 갯수를 전달받아서 Pagination객체를 초기화한다. * <p>한 화면에 표시되는 데이터 갯수는 10개다. * <p>한 화면에 표시되는 페이지번호 갯수는 5개다. * @param currentPage 요청한 페이지 번호 * @param totalRows 전체 데이터 갯수 */ public Pagination(int currentPage, int totalRows) { this(currentPage, totalRows, 10, 5); } /** * 요청한 페이지번호, 전체 데이터 갯수, 한 화면에 표시할 행의 갯수를 전달받아서 Pagination객체를 초기화한다. * <p>한 화면에 표시되는 페이지번호 갯수는 5개다. * @param currentPage 요청한 페이지 번호 * @param totalRows 전체 데이터 갯수 * @param rows 한 화면에 표시되는 행의 갯수 */ public Pagination(int currentPage, int totalRows, int rows) { this(currentPage, totalRows, rows, 5); } /** * 요청한 페이지번호, 전체 데이터 갯수, 한 화면에 표시할 행의 갯수, 한 화면에 표시할 페이지번호 갯수를 전달받아서 Pagination객체를 초기화한다. * @param currentPage 요청한 페이지 번호 * @param totalRows 전체 데이터 갯수 * @param rows 한 화면에 표시되는 행의 갯수 * @param pages 한 화면에 표시되는 페이지번호 갯수 */ public Pagination(int currentPage, int totalRows, int rows, int pages) { this.currentPage = currentPage; this.totalRows = totalRows; this.rows = rows; this.pages = pages; } /** * 요청한 페이지번호의 조회 시작번호를 반환한다. * @return */ public int getBegin() { return (currentPage - 1)*rows + 1; } /** * 요청한 페이지번호의 조회 끝번호를 반환한다. * @return */ public int getEnd() { return currentPage*rows; } /** * 총 페이지 갯수를 반환한다. * @return */ public int getTotalPages() { return (int) Math.ceil((double) totalRows/rows); } /** * 총 페이지 블록 갯수를 반환한다. * @return */ public int getTotalBlocks() { return (int) Math.ceil((double) getTotalPages()/pages); } /** * 요청한 페이지번호가 속한 페이지 블록 번호를 반환한다. * @return */ public int getCurrentPageBlock() { return (int) Math.ceil((double) currentPage/pages); } /** * 요청한 페이지번호가 속한 페이지 블록의 시작 페이지 번호를 반환한다. * @return */ public int getBeginPage() { return (getCurrentPageBlock() - 1)*pages + 1; } /** * 요청한 페이지번호가 속한 페이지 블록의 끝 페이지 번호를 반환한다. * @return */ public int getEndPage() { return getCurrentPageBlock() == getTotalBlocks() ? getTotalPages() : getCurrentPageBlock()*pages; } /** * 첫 페이지인지 여부를 반환한다. * @return 첫 페이지이면 true를 반환한다. */ public boolean isFirst() { return currentPage <= 1; } /** * 끝 페이지인지 여부를 반환한다. * @return 끝 페이지이면 true를 반환한다. */ public boolean isLast() { return currentPage >= getTotalPages(); } /** * 이전 페이지 번호를 반환한다. * @return */ public int getPrevPage() { return currentPage - 1; } /** * 다음 페이지번호를 반환한다. * @return */ public int getNextPage() { return currentPage + 1; } }
<books.xml> 쿼리에서 parameterClass="map"이 아닌 "com.sample.util.Pagination"이라고 적기.
- #begin#, #end#는 그대로다. # # 안에 적는 것은 사실 getter메소드의 이름이었다. get은 생략
<sqlMap namespace="books"> <select id="getTotalRows" resultClass="int"> select count(*) from sample_board_books </select> <select id="getBooks" parameterClass="com.sample.util.Pagination" resultClass="com.sample.vo.Book"> select book_no as no, book_title as title, book_author as author, book_publisher as publisher, book_description as description, book_image as image, book_price as price, book_discount_price as discountPrice, book_stock as stock, book_on_sell as onSell, 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_description, book_image, book_price, book_discount_price, book_stock, book_on_sell, book_created_date, book_updated_date from sample_board_books) where row_numbers between #begin# and #end# </select>
< BookDao.java > 에서 매개변수로 Pagination pagination을 적기
@SuppressWarnings("unchecked") public List<Book> getBooks(Map<String, Object> param) { return (List<Book>) SqlMapper.selectList("getBooks", param); } 위의 코드를 아래 코드로 변경 @SuppressWarnings("unchecked") public List<Book> getBooks(Pagination pagination) { return (List<Book>) SqlMapper.selectList("books.getBooks", pagination); }
< list.jsp > 에서 확실히 코드가 간결해짐을 확인할 수 있다.
<% int currentPage = StringUtils.stringToInt(request.getParameter("page"), 1); int rows = 5; int begin = (currentPage - 1)*rows + 1; int end = currentPage*rows; Map<String, Object> param = new HashMap<>(); param.put("begin", begin); param.put("end", end); BookDao bookDao = new BookDao(); List<Book> bookList = bookDao.getBooks(param); %> 위의 코드를 아래코드로 변경한다. <% // 요청파라미터에서 요청한 페이지번호를 조회한다. int currentPage = StringUtils.stringToInt(request.getParameter("page"), 1); // BookDao객체를 생성한다. BookDao bookDao = new BookDao(); // 총 데이터 갯수를 조회한다. int totalRows = bookDao.getTotalRows(); // 페이징처리에 필요한 정보를 제공하는 Pagination객체를 생성한다. Pagination pagination = new Pagination(currentPage, totalRows, 5, 5); // 요청한 페이지 범위에 해당하는 책목록을 조회한다. List<Book> bookList = bookDao.getBooks(pagination); %>
- 목록을 줄 때에도 map을 만들 필요 없이 pagination 안에 begin이랑 end가 있어서 pagination객체를 넣는다.
< list.jsp > 의 페이지네비게이션 부분
<% // 총 게시글 갯수를 조회한다. int totalRows = bookDao.getTotalRows(); if (totalRows >= 1) { // 총 페이지 갯수, 총 페이지 블록갯수, 현재 페이지블록번호, 시작페이지번호, 끝 페이지번호를 계산한다. int pages = 5; int totalPages = (int) Math.ceil((double) totalRows/rows); int totalBlocks = (int) Math.ceil((double) totalPages/pages); int currentPageBlock = (int) Math.ceil((double) currentPage/pages); int beginPage = (currentPageBlock - 1)*pages + 1; int endPage = currentPageBlock == totalBlocks ? totalPages : currentPageBlock*pages; %> <div aria-label="navigation"> <ul class="pagination justify-content-center"> <li class="page-item"><a class="page-link <%=currentPage <= 1 ? "disabled" : "" %>" href="list.jsp?page=<%=currentPage - 1 %>">이전</a></li> <% for (int number = beginPage; number <= endPage; number++) { %> <li class="page-item"><a class="page-link <%=currentPage == number ? "active" : "" %>" href="list.jsp?page=<%=number %>"><%=number %></a></li> <% } %> <li class="page-item"><a class="page-link <%=currentPage >= totalPages ? "disabled" : "" %>" href="list.jsp?page=<%=currentPage + 1 %>">다음</a></li> </ul> </div> <% } %> 위의 코드가 아래처럼 변경된다. <% if (totalRows >= 0) { %> <div aria-label="navigation"> <ul class="pagination justify-content-center"> <li class="page-item"> <a class="page-link <%=pagination.isFirst() ? "disabled" : "" %>" href="list.jsp?page=<%=pagination.getPrevPage()%>">이전</a> </li> <% for (int number = pagination.getBeginPage(); number <= pagination.getEndPage(); number++) { %> <li class="page-item"><a class="page-link <%=currentPage == number ? "active" : "" %>" href="list.jsp?page=<%=number %>"><%=number %></a></li> <% } %> <li class="page-item"> <a class="page-link <%=pagination.isLast() ? "disabled" : "" %>" href="list.jsp?page=<%=pagination.getNextPage() %>">다음</a> </li> </ul> </div> <% } %>
주소 표기법
절대경로 표기법
- 경로가 "/"로 시작하는 경로
- url 주소에서 "http://localhost"를 제외한 전체 경로를 작성하는 것
- 절대경로는 현재 페이지의 URL 주소와 상관없이 요청URL의 주소를 작성하는 것
* 모든 페이지에 공통으로 포함되는 내비바의 주소는 절대경로로 지정한다.
* 요청 URL : http://localhost/web-board/home.jsp
<a href="/web-board/home.jsp">홈</a>
* 요청 URL : http://localhost/web-board/book/list.jsp
<a href="/web-board/book/list.jsp">국내도서</a>
상대경로 표기법
- 경로가 "/"로 시작하지 않는 경로
- 상대경로는 현재 페이지의 URL 주소를 기준으로 요청URL의 주소를 작성하는 것
- 현재 페이지의 URL 주소에서 맨 마지막 "/"까지의 경로가 기준이 되는 주소다.
현재 페이지의 URL : http://localhost/web-board/home.jsp -> 기준 : http://localhost/web-board/
현재 페이지의 URL : http://localhost/web-board/board/list.jsp -> 기준 : http://localhost/web-board/board/
* 현재 페이지의 URL : http://localhost/web-board/home.jsp
* 요청 URL : http://localhost/web-board/about.jsp
* 절대경로 : <a href="/web-board/about.jsp">소개</a>
* 상대경로 : <a href="about.jsp">소개</a>
* 현재 페이지의 URL : http://localhost/web-board/home.jsp
* 요청 URL : http://localhost/web-board/board/list.jsp
* 절대경로 : <a href="/web-board/board/list.jsp">게시판</a>
* 상대경로 : <a href="board/list.jsp">게시판</a>
* 현재 페이지의 URL : http://localhost/web-board/book/list.jsp
* 요청 URL : http://localhost/web-board/book/detail.jsp?no=100
* 절대경로 : <a href="/web-board/book/detail.jsp?no=100">이것이 자바다</a>
* 상대경로 : <a href="detail.jsp?no=100">이것이 자바다</a>
* 현재 페이지의 URL : http://localhost/web-board/book/list.jsp
* 요청 URL : http://localhost/web-board/home.jsp
* 절대경로 : <a href="/web-board/home.jsp">홈</a>
* 상대경로 : <a href="../home.jsp?no=100">홈</a>
* 현재 페이지의 URL : http://localhost/web-board/book/list.jsp
* 요청 URL : http://localhost/web-board/cart/list.jsp
* 절대경로 : <a href="/web-board/cart/list.jsp">장바구니</a>
* 상대경로 : <a href="../cart/list.jsp">장바구니</a>-------------------------------------------------------------------------------------------------------------------- 상대경로 표기법 예시 ==================================================================================================================== 현재 URL : http://localhost/web-board/home.jsp 요청 URL : http://localhost/web-board/about.jsp 기준 : http://localhost/web-board/ + "about.jsp" <a href="about.jsp"> -------------------------------------------------------------------------------------------------------------------- 현재 URL : http://localhost/web-board/home.jsp 요청 URL : http://localhost/web-board/board/list.jsp 기준 : http://localhost/web-board/ + "board/list.jsp" <a href="board/list.jsp"> -------------------------------------------------------------------------------------------------------------------- 현재 URL : http://localhost/web-board/board/list.jsp 요청 URL : http://localhost/web-board/board/detail.jsp?no=100 기준 : http://localhost/web-board/board/ + "detail.jsp?no=100" <a href="detail.jsp?no=100"> -------------------------------------------------------------------------------------------------------------------- 현재 URL : http://localhost/web-board/board/list.jsp 요청 URL : http://localhost/web-board/home.jsp 기준 : http://localhost/web-board/board/ + "../home.jsp" <a href="../home.jsp"> http://localhost/web-board/ + "home.jsp" -------------------------------------------------------------------------------------------------------------------- 현재 URL : http://localhost/web-board/board/list.jsp 요청 URL : http://localhost/home.jsp 기준 : http://localhost/web-board/board/ + "../../home.jsp" <a href="../../home.jsp"> http://localhost/ + "home.jsp" -------------------------------------------------------------------------------------------------------------------- 현재 URL : http://localhost/web-board/board/list.jsp 요청 URL : http://localhost/web-board/cart/list.jsp 기준 : http://localhost/web-board/board/ + "../cart/list.jsp" <a href="../cart/list.jsp"> http://localhost/web-board/ + "cart/list.jsp" --------------------------------------------------------------------------------------------------------------------
기준은 현재 페이지의 URL 맨 마지막 슬래시까지이다.
기준 경로에서 경로 하나를 탈락시킬 때 ../를 작성한다
기준 경로에서 경로 두 개를 탈락시킬 때 ../../를 작성한다.
장바구니에 아이템 담기 기능
public class CartItem { private int no; private int bookNo; private String userId; private int amount; private Date createdDate; private Date updatedDate; public CartItem() {} public CartItem(int bookNo, String userId) { this.bookNo = bookNo; this.userId = userId; } public int getNo() { return no; } public void setNo(int no) { this.no = no; } public int getBookNo() { return bookNo; } public void setBookNo(int bookNo) { this.bookNo = bookNo; } public String getUserId() { return userId; } public void setUserId(String userId) { this.userId = userId; } public int getAmount() { return amount; } public void setAmount(int amount) { this.amount = amount; } public Date getCreatedDate() { return createdDate; } public void setCreatedDate(Date createdDate) { this.createdDate = createdDate; } public Date getUpdatedDate() { return updatedDate; } public void setUpdatedDate(Date updatedDate) { this.updatedDate = updatedDate; } }
- 기본생성자 외의 생성자를 추가할 때는 앞에 기본생성자를 반드시 적어줘야 ibatis에서 오류가 나지 않는다.
< carts.xml > <sqlMap namespace="carts"> <insert id="insertCartItem" parameterClass="com.sample.vo.CartItem"> insert into sample_board_book_cart_items (item_no, book_no, user_id) values (sample_carts_seq.nextval, #bookNo#, #userId#) </insert> </sqlMap>
< CartItemDao.java > public class CartItemDao { public void insertCartItem(CartItem cartItem) { SqlMapper.insert("carts.insertCartItem", cartItem); }
< addItem.jsp > <% // 장바구니 아이템정보를 저장하기 위해서 책번호(요청 파라미터에서 획득), // 사용자아이디(세션에 저장된 사용자정보에서 획득)가 필요함 // HttpSession객체에 "loginedUser"라는 이름을 저장된 사용자 정보를 조회한다.(user/login.jsp에서 저장해 둔 것) User user = (User) session.getAttribute("loginedUser"); if (user == null) { /* 현재 URL : http://localhost/web-board/cart/addItem.jsp?bookNo=10021 요청 URL : http://localhost/web-board/user/loginform.jsp?error=deny 기준 URL : http://localhost/web-board/cart/ 상대경로 : ../user/loginform.jsp?error=deny */ response.sendRedirect("../user/loginform.jsp?error=deny"); return; } // 요청파라미터에서 책번호 조회 int bookNo = StringUtils.stringToInt(request.getParameter("bookNo")); // 사용자 아이디 조회 String userId = user.getId(); // CartItem 객체를 생성하고, 책번호와 사용자아이디를 저장한다. CartItem cartItem = new CartItem(bookNo, userId); // CartItemDao객체를 생성하고, addCartItem(CartItem cartItem) 메소드를 실행해서 장바구니 아이템을 저장시킨다. CartItemDao cartItemDao = new CartItemDao(); cartItemDao.insertCartItem(cartItem); // 재요청 URL을 응답으로 보낸다. /* 현재 URL : http://localhost/web-board/cart/addItem.jsp?bookNo=10021 요청 URL : http://localhost/web-board/cart/list.jsp 기준 URL : http://localhost/web-board/cart/ 상대경로 : list.jsp */ response.sendRedirect("list.jsp"); %>
장바구니 리스트 조회하기 기능
- 장바구니 리스트를 구현하기 위해서 sample_board_book_cart_items 테이블과 sample_board_books테이블을 조인해야 한다. 따라서, Dto 클래스를 정의해야 한다.
public class CartItemDto { private int itemNo; // sample_board_book_cart_items의 item_no private int bookNo; // sample_board_book_cart_items의 book_no private String userId; // sample_board_book_cart_items의 user_id private String title; // sample_board_books의 book_title private String image; // sample_board_books의 book_image private int amount; // sample_board_book_cart_items의 item_amount private int price; // sample_board_books의 book_price private int discountPrice; // sample_board_books의 book_discount_price private Date createdDate; // sample_board_book_cart_items의 item_created_date private Date updatedDate; // sample_board_book_cart_items의 item_updated_date public CartItemDto() {} public int getItemNo() { return itemNo; } public void setItemNo(int itemNo) { this.itemNo = itemNo; } public int getBookNo() { return bookNo; } public void setBookNo(int bookNo) { this.bookNo = bookNo; } public String getUserId() { return userId; } public void setUserId(String userId) { this.userId = userId; } public String getTitle() { return title; } public void setTitle(String title) { this.title = title; } public String getImage() { return image; } public void setImage(String image) { this.image = image; } public int getAmount() { return amount; } public void setAmount(int amount) { this.amount = amount; } public int getPrice() { return price; } public void setPrice(int price) { this.price = price; } public int getDiscountPrice() { return discountPrice; } public void setDiscountPrice(int discountPrice) { this.discountPrice = discountPrice; } public Date getCreatedDate() { return createdDate; } public void setCreatedDate(Date createdDate) { this.createdDate = createdDate; } public Date getUpdatedDate() { return updatedDate; } public void setUpdatedDate(Date updatedDate) { this.updatedDate = updatedDate; } @Override public String toString() { return "CartItemDto [itemNo=" + itemNo + ", bookNo=" + bookNo + ", userId=" + userId + ", title=" + title + ", image=" + image + ", amount=" + amount + ", price=" + price + ", discountPrice=" + discountPrice + ", createdDate=" + createdDate + ", updatedDate=" + updatedDate + "]"; } }
< carts.xml > <select id="getCartItemsByUserId" parameterClass="string" resultClass="com.sample.dto.CartItemDto"> select A.item_no as itemNo, A.book_no as bookNo, A.user_id as userId, B.book_title as title, B.book_image as image, A.item_amount as amount, B.book_price as price, B.book_discount_price as discountPrice, A.item_created_date as createdDate, A.item_updated_date as updatedDate from sample_board_book_cart_items A, sample_board_books B where A.book_no = B.book_no and A.user_id = #value# </select> </sqlMap>
< CartItemDao.java > @SuppressWarnings("unchecked") public List<CartItemDto> getCartItemsByUserId(String userId) { return (List<CartItemDto>) SqlMapper.selectList("carts.getCartItemsByUserId", userId); }
< list.jsp > <% //HttpSession객체에 "loginedUser"라는 이름을 저장된 사용자 정보를 조회한다.(user/login.jsp에서 저장해 둔 것) User user = (User) session.getAttribute("loginedUser"); if (user == null) { response.sendRedirect("../user/loginform.jsp?error=deny"); return; // // 이코드가 실행이 안되면(로그인이 안되면) 아래의 코드가 의미가 없으니까 빨리 끝내라는 의미 } %> <!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> <style type="text/css"> img.img-thumbnail {width: 53px; height: 68px;} </style> </head> <body> <jsp:include page="../common/header.jsp"> <jsp:param name="menu" value="cart"/> </jsp:include> <div class="container my-3"> <h1 class="mb-3 fs-4 border p-2 bg-light">장바구니 리스트</h1> <% // CartItemDao 객체를 생성하고, getCartItemsByUserId(String userId) 메소드를 실행해서 장바구니 아이템 목록을 조회한다. CartItemDao cartItemDao = new CartItemDao(); List<CartItemDto> dtoList = cartItemDao.getCartItemsByUserId(user.getId()); %> <p>장바구니 목록을 확인하세요.</p> <table class="table"> <colgroup> <col width="5%"> <col width="10%"> <col width="*"> <col width="10%"> <col width="15%"> <col width="15%"> <col width="10%"> </colgroup> <thead> <tr> <th><input type="checkbox"></th> <th></th> <th>제목</th> <th>수량</th> <th>가격</th> <th>구매가격</th> <th></th> </tr> </thead> <tbody> <% if (dtoList.isEmpty()) { %> <tr> <td colspan="7" class="text-center">장바구니에 저장된 책이 없습니다.</td> </tr> <% } else { for (CartItemDto dto : dtoList) { %> <tr class="align-middle"> <td><input type="checkbox" name="itemNo" value="<%=dto.getItemNo() %>" /></td> <td><img src="../resources/images/<%=dto.getImage() %>" class="img-thumbnail"></td> <td><a href="../book/detail.jsp?no=<%=dto.getBookNo() %>" class="text-decoration-none"><%=dto.getTitle() %></a></td> <td><%=dto.getAmount() %> 권</td> <td> <strong class="text-danger"><%=StringUtils.numberToText(dto.getDiscountPrice()) %> 원</strong> <small>(<%=StringUtils.numberToText(dto.getPrice()) %> 원)</small> </td> <td><strong class="text-danger"><%=StringUtils.numberToText(dto.getAmount()*dto.getDiscountPrice()) %> 원</strong></td> <td> <a href="deleteItem.jsp?itemNo=<%=dto.getItemNo() %>" class="btn btn-secondary btn-sm">삭제</a> <a href="" class="btn btn-primary btn-sm">구매</a> </td> </tr> <% } } %> </tbody> </table> <div class=""> <a href="" class="btn btn-secondary btn-sm" >전체 삭제</a> <a href="" class="btn btn-secondary btn-sm" >전체 구매</a> </div> </div> </body> </html>
'기록' 카테고리의 다른 글
학원 day53. 서블릿, 필터, 첨부파일 업로드 (0) 2022.11.18 학원 day52. merge into문, 장바구니 리스트 삭제하기, include, 암호화 (0) 2022.11.18 학원 day50. 회원가입, 로그인/로그아웃, 게시글 수정/삭제 (0) 2022.11.15 학원 day49. 게시판 리뷰 기능, 쿠키/세션, JSP 주요객체 (0) 2022.11.14 학원 day48. 게시판 만들기 실습, 페이지 네비게이션 (0) 2022.11.12