오늘은 이미지 파일을 첨부하는 방법과 간편하게 페이징 처리를 하는 방법 그리고 장바구니에 아이템을 추가하는 기능에 대해 배웠다.
먼저,
webapp/book 폴더 생성
webapp/cart 폴더 생성
webapp/resources/images 폴더 생성
images 폴더 안에 image 파일 넣기
book폴더에 detail.jsp와 list.jsp 복사하기
완성본
cart폴더에 list.jsp 복사하기
완성본 (로그인 해야만 장바구니 버튼이 활성화된다.)
테이블 작성
CREATE TABLE "SAMPLE_BOARD_BOOKS"
( "BOOK_NO" NUMBER(6,0) PRIMARY KEY,
"BOOK_TITLE" VARCHAR2(255) NOT NULL,
"BOOK_AUTHOR" VARCHAR2(255) NOT NULL,
"BOOK_PUBLISHER" VARCHAR2(255) NOT NULL,
"BOOK_DESCRIPTION" VARCHAR2(2000),
"BOOK_IMAGE" VARCHAR2(100),
"BOOK_PRICE" NUMBER(10,0),
"BOOK_DISCOUNT_PRICE" NUMBER(10,0),
"BOOK_STOCK" NUMBER(10,0),
"BOOK_ON_SELL" CHAR(1) DEFAULT 'Y',
"BOOK_CREATED_DATE" DATE DEFAULT SYSDATE,
"BOOK_UPDATED_DATE" DATE DEFAULT SYSDATE
);
CREATE TABLE SAMPLE_BOARD_BOOK_CART_ITEMS (
ITEM_NO NUMBER(6) PRIMARY KEY,
BOOK_NO NUMBER(6) REFERENCES SAMPLE_BOARD_BOOKS (BOOK_NO),
USER_ID VARCHAR2(20) REFERENCES SAMPLE_BOARD_USERS (USER_ID),
ITEM_AMOUNT NUMBER(3) DEFAULT 1,
ITEM_CREATED_DATE DATE DEFAULT SYSDATE,
ITEM_UPDATED_DATE DATE DEFAULT SYSDATE
);
데이터 생성
Insert into SAMPLE_BOARD_BOOKS (BOOK_NO,BOOK_TITLE,BOOK_AUTHOR,BOOK_PUBLISHER,BOOK_IMAGE, BOOK_DESCRIPTION,BOOK_PRICE,BOOK_DISCOUNT_PRICE,BOOK_STOCK,BOOK_ON_SELL,BOOK_CREATED_DATE,BOOK_UPDATED_DATE) values (100011,'서울 수도권 아파트 지금 사야 합니다.','함태식','황금부엉이','image-13.jpg','2014년 하반기부터 오르기 시작한 부동산 시장은 지금까지 8년째 상승세를 이어오고 있다. 덕분에 ‘이미 고점에 다다랐는데 지금 사면 상투를 잡는 것’이라며 폭락론을 내놓는 전문가도 상당히 많다. 그들의 말대로라면 PIR(소득 대비 주택가격 비율)이 사상 최고치여서, 금리 인상으로 대출자의 부담이 늘어서, 세금 폭탄에 못 이긴 매물들이 쏟아질 거라서 곧 부동산가격이 폭락할 것만 같다. 이 책의 저자이자 부동산 유튜버 ‘얼음공장’은 시장의 방향을 결정하는 건 금리 인상이나 정부 정책이 아닌 수요와 공급이라고 강력하게 말한다.',19500,17550,20,'Y',to_date('2022-11-10','YYYY-MM-DD'),to_date('2022-11-10','YYYY-MM-DD'));
Insert into SAMPLE_BOARD_BOOKS (BOOK_NO,BOOK_TITLE,BOOK_AUTHOR,BOOK_PUBLISHER,BOOK_IMAGE, BOOK_DESCRIPTION,BOOK_PRICE,BOOK_DISCOUNT_PRICE,BOOK_STOCK,BOOK_ON_SELL,BOOK_CREATED_DATE,BOOK_UPDATED_DATE) values (100012,'ETS 토익 정기시험 기출문제집 1000 READING','ETS','YBM','image-14.jpg','이 책에는 정기시험 기출문제 7세트와 ETS 토익 예상문제 3세트가 수록되어 있다. 시험에 나온 토익 문제로 실전 감각을 키우고, 동일한 난이도의 예상문제로 시험에 확실하게 대비하자! ETS 예상문제도 실제 시험과 동일한 문항 유형 및 난이도 등 기출과 싱크로율 100% 스펙을 특징으로 한다.',18000,16200,20,'Y',to_date('2022-11-10','YYYY-MM-DD'),to_date('2022-11-10','YYYY-MM-DD'));
Insert into SAMPLE_BOARD_BOOKS (BOOK_NO,BOOK_TITLE,BOOK_AUTHOR,BOOK_PUBLISHER,BOOK_IMAGE, BOOK_DESCRIPTION,BOOK_PRICE,BOOK_DISCOUNT_PRICE,BOOK_STOCK,BOOK_ON_SELL,BOOK_CREATED_DATE,BOOK_UPDATED_DATE) values (100013,'럭키 드로우','드로우 앤드류','다산북스','image-15.jpg','20대의 드로우앤드류가 끝이 보이지 않던 무기력을 빠져나와 30대가 되어 자신만의 일을 찾기까지 무수히 당겨온 ‘레버’들을 엮은 첫 번째 책. 우연히 발견한 인턴십 포스터를 보곤 충동적으로 미국 LA에 날아가 디자인 일을 시작한 이후부터 다시 한국에 돌아와 거액의 연봉을 거절하고 상위 1% 밀레니얼 프리워커로 거듭나기까지의 모든 이야기를 담았다',16000,14400,20,'Y',to_date('2022-11-10','YYYY-MM-DD'),to_date('2022-11-10','YYYY-MM-DD'));
Insert into SAMPLE_BOARD_BOOKS (BOOK_NO,BOOK_TITLE,BOOK_AUTHOR,BOOK_PUBLISHER,BOOK_IMAGE, BOOK_DESCRIPTION,BOOK_PRICE,BOOK_DISCOUNT_PRICE,BOOK_STOCK,BOOK_ON_SELL,BOOK_CREATED_DATE,BOOK_UPDATED_DATE) values (100014,'ETS 토익 정기시험 기출문제집 1000 LISTENING','ETS','YBM','image-16.jpg','이 책에는 정기시험 기출문제 7세트와 ETS 예상문제 3세트가 수록되어 있다. 시험에 나온 토익 문제로 실전 감각을 키우고, 동일한 난이도의 예상문제로 시험에 확실하게 대비하자! ETS 예상문제도 실제 시험과 동일한 성우, 문항 유형 및 난이도 등 기출문제와 싱크로율 100% 스펙을 특징으로 한다.',18000,16200,20,'Y',to_date('2022-11-10','YYYY-MM-DD'),to_date('2022-11-10','YYYY-MM-DD'));
Insert into SAMPLE_BOARD_BOOKS (BOOK_NO,BOOK_TITLE,BOOK_AUTHOR,BOOK_PUBLISHER,BOOK_IMAGE, BOOK_DESCRIPTION,BOOK_PRICE,BOOK_DISCOUNT_PRICE,BOOK_STOCK,BOOK_ON_SELL,BOOK_CREATED_DATE,BOOK_UPDATED_DATE) values (100015,'해커스 토익 기출 보카','데이비드 조','해커스어학연구소','image-17.jpg','주제별 연상암기로 쉽고 재미있게 단어 학습이 가능하며 최신 기출 단어 및 출제포인트 수록했다. 목표 점수대별 필수 단어로 맞춤 학습을 할 수 있으며 출제율 높은 핵심 단어만 골라 효율적으로 학습할 수 있다. 토익 신유형 대비 [토익 필수 이디엄 표현]을 수록했고 실전 감각을 키우는 토익 실전문제 13회분을 제공(교재 3회+온라인 10회)한다.',12000,10800,20,'Y',to_date('2022-11-10','YYYY-MM-DD'),to_date('2022-11-10','YYYY-MM-DD'));
Insert into SAMPLE_BOARD_BOOKS (BOOK_NO,BOOK_TITLE,BOOK_AUTHOR,BOOK_PUBLISHER,BOOK_IMAGE, BOOK_DESCRIPTION,BOOK_PRICE,BOOK_DISCOUNT_PRICE,BOOK_STOCK,BOOK_ON_SELL,BOOK_CREATED_DATE,BOOK_UPDATED_DATE) values (100016,'오늘 밤, 세계에서 이 사랑이 사라진다 해도','이치조 미사키','모모','image-18.jpg','밤에 자고 일어나면 기억이 리셋되는 ‘선행성 기억상실증’을 앓는 소녀 히노 마오리와 무미건조한 인생을 살고 있는 평범한 고등학생 가미야 도루의 풋풋하고 애틋한 사랑 이야기. 선행성 기억상실증이라는 익숙한 소재를 매우 수준 높은 청춘 소설로 탄생시켰다는 극찬을 받으며 제26회 전격소설대상 ‘미디어워크스문고상’을 수상한 이 작품은 간질간질한 청춘의 로맨스를 전혀 예측할 수 없는 국면으로 끌고 가, 깐깐하고 엄격한 심사위원 모두를 눈물 흘리게 만들었다는 흥미로운 뒷이야기를 남긴 소설이기도 하다.',14000,12600,20,'Y',to_date('2022-11-10','YYYY-MM-DD'),to_date('2022-11-10','YYYY-MM-DD'));
Insert into SAMPLE_BOARD_BOOKS (BOOK_NO,BOOK_TITLE,BOOK_AUTHOR,BOOK_PUBLISHER,BOOK_IMAGE, BOOK_DESCRIPTION,BOOK_PRICE,BOOK_DISCOUNT_PRICE,BOOK_STOCK,BOOK_ON_SELL,BOOK_CREATED_DATE,BOOK_UPDATED_DATE) values (100017,'고양이 해결사 깜냥 4','홍민정','창비','image-19.jpg','출간 즉시 어린이 분야 1위를 기록한 화제의 베스트셀러 『고양이 해결사 깜냥』이 네 번째 책으로 돌아왔다. 겨울을 맞은 떠돌이 고양이 깜냥이 매서운 추위를 피해 향한 곳은 시내의 자그마한 눈썰매장이다. 깜냥은 야간 근무 중인 안전 요원 덕분에 따뜻한 하룻밤을 보낸다. 그런데 다음 날, 눈썰매장에 성가신 일들이 하나씩 터진다. 깜냥은 고양이 해결사로서 능력을 톡톡히 발휘할 수 있을까?',10000,9000,20,'Y',to_date('2022-11-10','YYYY-MM-DD'),to_date('2022-11-10','YYYY-MM-DD'));
Insert into SAMPLE_BOARD_BOOKS (BOOK_NO,BOOK_TITLE,BOOK_AUTHOR,BOOK_PUBLISHER,BOOK_IMAGE, BOOK_DESCRIPTION,BOOK_PRICE,BOOK_DISCOUNT_PRICE,BOOK_STOCK,BOOK_ON_SELL,BOOK_CREATED_DATE,BOOK_UPDATED_DATE) values (100018,'돈의 속성','김승호','스노우폭스북스','image-20.jpg','2020년 베스트셀러 종합 1위! 경제경영 17주 연속 1위! 깨어있는 독자들이 선택한 2021년 최장기 베스트셀러! 『돈의 속성』 200쇄 돌파 기념, 추가 메시지를 담다! 최상위 부자 김승호가 말하는 돈에 대한 통찰과 철학 이 책은 초판 발행 후, 경제경영 필도서로 자리매김한 『돈의 속성』 200쇄 기념 개정증보판이다. 200쇄에 맞춰 코로나19로 바뀐 경제상황과 돈에 관한 김승호 회장의 추가 메시지를 담았다.',18000,16200,20,'Y',to_date('2022-11-10','YYYY-MM-DD'),to_date('2022-11-10','YYYY-MM-DD'));
Insert into SAMPLE_BOARD_BOOKS (BOOK_NO,BOOK_TITLE,BOOK_AUTHOR,BOOK_PUBLISHER,BOOK_IMAGE, BOOK_DESCRIPTION,BOOK_PRICE,BOOK_DISCOUNT_PRICE,BOOK_STOCK,BOOK_ON_SELL,BOOK_CREATED_DATE,BOOK_UPDATED_DATE) values (100019,'오은영의 화해','오은영','코리아닷컴','image-21.jpg','겉으로는 아무렇지도 않은 듯 살아가지만, 우리 모두는 마음속에 자신을 찌르는 가시를 안고 살아간다. 우리 중 누구도 아프지 않은 사람이 있을까? 부모와 자녀, 그 절대적인 관계 속에서도 때론 미움이, 고통이, 원망이, 그리고 죄책감이 자라나 내면에 해결되지 않은 상처로 남기도 한다. 그 상처 때문에 많은 사람이 이유도 모르는 채 삶이 고통스럽고 버거움에 힘겨워한다.',16000,14400,20,'Y',to_date('2022-11-10','YYYY-MM-DD'),to_date('2022-11-10','YYYY-MM-DD'));
Insert into SAMPLE_BOARD_BOOKS (BOOK_NO,BOOK_TITLE,BOOK_AUTHOR,BOOK_PUBLISHER,BOOK_IMAGE, BOOK_DESCRIPTION,BOOK_PRICE,BOOK_DISCOUNT_PRICE,BOOK_STOCK,BOOK_ON_SELL,BOOK_CREATED_DATE,BOOK_UPDATED_DATE) values (100020,'나태주, 시간의 쉼표','나태주','서울문화사','image-22.jpg','짧고, 쉽고, 단출한 글자만으로 우리의 마음에 큰 위로를 전하는 이 시대 가장 따뜻한 시인, 나태주의 글과 그림으로 구성된 일력이 출간되었다. 작은 탁상달력 형태인 이 책은 1월 1일부터 12월 31일까지의 숫자가 나태주 시인의 손글씨로 적혀 있어, 시인 특유의 친근한 온정을 그대로 느낄 수 있게 한다. 한국인이 사랑하는 시집 『꽃을 보듯 너를 본다』, 『혼자서도 별인 너에게』 등에 수록된 주옥같은 시들 중 그날그날에 어울리는 시구들을 정선하여 구성했다.',17000,15300,20,'Y',to_date('2022-11-10','YYYY-MM-DD'),to_date('2022-11-10','YYYY-MM-DD'));
Insert into SAMPLE_BOARD_BOOKS (BOOK_NO,BOOK_TITLE,BOOK_AUTHOR,BOOK_PUBLISHER,BOOK_IMAGE, BOOK_DESCRIPTION,BOOK_PRICE,BOOK_DISCOUNT_PRICE,BOOK_STOCK,BOOK_ON_SELL,BOOK_CREATED_DATE,BOOK_UPDATED_DATE) values (100021,'잘했고 잘하고 있고 잘 될 것이다','정영욱','부크럼','image-23.jpg','『참 애썼다 그것으로 되었다』 『나를 사랑하는 연습』 등 이전 도서를 통해 40만 부가량의 판매량을 기록한 에세이 작가 정영욱의 새로운 책이 출간되었다. 작가 정영욱은 이번 책을 통해 당신의 과거와 현재, 그리고 미래를 응원한다. 책을 통해 연결되어 있는 우리는 서로의 얼굴을 알지 못한다. 나이도 성별도, 심지어 이름조차 알지 못한다. 하지만 아무것도 모르기에 예측할 수 있는 것들이 있다. ',15000,13500,20,'Y',to_date('2022-11-10','YYYY-MM-DD'),to_date('2022-11-10','YYYY-MM-DD'));
Insert into SAMPLE_BOARD_BOOKS (BOOK_NO,BOOK_TITLE,BOOK_AUTHOR,BOOK_PUBLISHER,BOOK_IMAGE, BOOK_DESCRIPTION,BOOK_PRICE,BOOK_DISCOUNT_PRICE,BOOK_STOCK,BOOK_ON_SELL,BOOK_CREATED_DATE,BOOK_UPDATED_DATE) values (100022,'종목 선정 나에게 물어봐','김정수','하음출판사','image-1.jpg','년 동안 12번의 깡통, 누적 손절매액 11억 원, 하루 최대 손절매액 5억 4천만 원, 코로나 사태로 인한 주가 대폭락 시 손절매액 3억 6천만 원… 그러나 2020년 6월 매매 재개 후 매월 흑자 실현, 2021년 13억 이익 실현! 그 기법이 궁금하다면?9년 동안 5백만 개 이상 차트 판독, 9년 동안 5만 건 이상 실제 매매, 하루 최대 매매 건수 191건, 하루 차트 1000개 이상 판독, 1초에 차트 1개 판독!불사조 김정수의 『종목 선정 나에게 물어봐』가 답이다',26000,23400,20,'Y',to_date('2022-11-10','YYYY-MM-DD'),to_date('2022-11-10','YYYY-MM-DD'));
Insert into SAMPLE_BOARD_BOOKS (BOOK_NO,BOOK_TITLE,BOOK_AUTHOR,BOOK_PUBLISHER,BOOK_IMAGE, BOOK_DESCRIPTION,BOOK_PRICE,BOOK_DISCOUNT_PRICE,BOOK_STOCK,BOOK_ON_SELL,BOOK_CREATED_DATE,BOOK_UPDATED_DATE) values (100000,'불편한 편의점','김호연','남우옆의자','image-2.jpg','2013년 세계문학상 우수상 수상작 『망원동 브라더스』로 데뷔한 후 일상적 현실을 위트 있게 그린 경쾌한 작품과 인간의 내밀한 욕망을 기발한 상상력으로 풀어낸 스릴러 장르를 오가며 독자적인 작품 세계를 쌓아올린 작가 김호연. 그의 다섯 번째 장편소설 『불편한 편의점』이 출간되었다. 『불편한 편의점』은 청파동 골목 모퉁이에 자리 잡은 작은 편의점을 무대로 힘겨운 시대를 살아가는 우리 이웃들의 삶의 속내와 희로애락을 따뜻하고 유머러스하게 담아낸 작품이다',15000,13500,20,'Y',to_date('2022-11-10','YYYY-MM-DD'),to_date('2022-11-10','YYYY-MM-DD'));
Insert into SAMPLE_BOARD_BOOKS (BOOK_NO,BOOK_TITLE,BOOK_AUTHOR,BOOK_PUBLISHER,BOOK_IMAGE, BOOK_DESCRIPTION,BOOK_PRICE,BOOK_DISCOUNT_PRICE,BOOK_STOCK,BOOK_ON_SELL,BOOK_CREATED_DATE,BOOK_UPDATED_DATE) values (100001,'물고기는 존재하지 않는다.','룰러 밀러','곰출판','image-3.jpg','‘방송계의 퓰리처상’으로 불리는 피버디상(Peabody Awards)을 수상한 과학 전문기자 룰루 밀러의 경이로운 논픽션 《물고기는 존재하지 않는다》는 여러 언론 매체에서 ‘2020년 최고의 책’으로 선정할 만큼 수많은 찬사를 받은 화제의 베스트셀러다. 집착에 가까울 만큼 자연계에 질서를 부여하려 했던 19세기 어느 과학자의 삶을 흥미롭게 좇아가는 이 책은 어느 순간 독자들을 혼돈의 한복판으로 데려가서 우리가 믿고 있던 삶의 질서에 관해 한 가지 의문을 제기한다. ',16500,14850,20,'Y',to_date('2022-11-10','YYYY-MM-DD'),to_date('2022-11-10','YYYY-MM-DD'));
Insert into SAMPLE_BOARD_BOOKS (BOOK_NO,BOOK_TITLE,BOOK_AUTHOR,BOOK_PUBLISHER,BOOK_IMAGE, BOOK_DESCRIPTION,BOOK_PRICE,BOOK_DISCOUNT_PRICE,BOOK_STOCK,BOOK_ON_SELL,BOOK_CREATED_DATE,BOOK_UPDATED_DATE) values (100002,'세븐 테크','김기명,김상균','지식하우스','image-4.jpg','인공지능, 블록체인, 가상현실, 로봇, 사물인터넷, 클라우드 컴퓨팅, 그리고 메타버스까지! 디지털 혁명의 필수교양을 위해 각 분야 최고 전문가 8인이 한자리에 모였다. 당신은 이것들이 어떻게 연결되는지, 세상을 어떻게 바꿀지 정말 알고 있는가?',18000,16200,20,'Y',to_date('2022-11-10','YYYY-MM-DD'),to_date('2022-11-10','YYYY-MM-DD'));
Insert into SAMPLE_BOARD_BOOKS (BOOK_NO,BOOK_TITLE,BOOK_AUTHOR,BOOK_PUBLISHER,BOOK_IMAGE, BOOK_DESCRIPTION,BOOK_PRICE,BOOK_DISCOUNT_PRICE,BOOK_STOCK,BOOK_ON_SELL,BOOK_CREATED_DATE,BOOK_UPDATED_DATE) values (100003,'웰 씽킹 WEALTHINKINGS','켈리 최','다산북스','image-6.jpg','지방의 가난한 농가에서 태어난 흙수저 중의 흙수저, 열여섯 나이에 낮엔 소녀공으로 밤엔 야간 고등학교로 주경야독, 난독증이 심해 제대로 읽을 수 없는 삶, 사업 실패로 남은 건 10억 원의 빚. 그런 그녀에게 어떤 희망이 있었을까? 차라리 죽는 게 더 낫다고 생각한 날들의 연속이었다. 하지만 몇 년 뒤, 그녀는 6천 개의 일자리를 창출하고 세계 12개국 30개가 넘는 비즈니스와 계열사를 거느린 글로벌 기업 회장으로 다시 태어났다',16000,14400,20,'Y',to_date('2022-11-10','YYYY-MM-DD'),to_date('2022-11-10','YYYY-MM-DD'));
Insert into SAMPLE_BOARD_BOOKS (BOOK_NO,BOOK_TITLE,BOOK_AUTHOR,BOOK_PUBLISHER,BOOK_IMAGE, BOOK_DESCRIPTION,BOOK_PRICE,BOOK_DISCOUNT_PRICE,BOOK_STOCK,BOOK_ON_SELL,BOOK_CREATED_DATE,BOOK_UPDATED_DATE) values (100004,'잘 살아라 그게 최고의 복수다.','권민창','마인드셋','image-5.jpg','힘들게 살아가지만, 결코 포기하지는 않는. 누군가가 좋은 조언을 하거나 해결책을 제시해주면 그 조언과 해결책을 스펀지처럼 흡수해 자신의 인생에 적용하고 발전할 준비가 될 잠재력이 충만한 사람들을 위한 권민창 작가의 냉정하고도 현실적인 인생 조언. 인생 전반의 다양한 고민들을 갖고 힘들게 살아가는 사람들을 위해, 그 고민들을 해결하기 위한 방법들을 담은 ‘인생 공략집’이다',15000,13500,20,'Y',to_date('2022-11-10','YYYY-MM-DD'),to_date('2022-11-10','YYYY-MM-DD'));
Insert into SAMPLE_BOARD_BOOKS (BOOK_NO,BOOK_TITLE,BOOK_AUTHOR,BOOK_PUBLISHER,BOOK_IMAGE, BOOK_DESCRIPTION,BOOK_PRICE,BOOK_DISCOUNT_PRICE,BOOK_STOCK,BOOK_ON_SELL,BOOK_CREATED_DATE,BOOK_UPDATED_DATE) values (100005,'달러구트 꿈 백화점 합본호','이미예','패토리나인','image-7.jpg','한국형 판타지의 새로운 장르를 연 이미예 작가의 판타지 소설 『달러구트 꿈 백화점』이 1, 2권 통합 100만 부 판매를 기념해 특별 합본호로 출간됐다. 지난 2020년 7월, 1권 출간 이후 ‘힐링 판타지’라는 찬사를 받은 이 책은 2021년 7월, 2권 출간 직후부터 베스트셀러 1위를 차지하며 독자들의 사랑을 입증하였으며 출간 후 1년 4개월 만에 1, 2권 통합 100만 부를 판매하는 기록을 세웠다.',23000,20700,20,'Y',to_date('2022-11-10','YYYY-MM-DD'),to_date('2022-11-10','YYYY-MM-DD'));
Insert into SAMPLE_BOARD_BOOKS (BOOK_NO,BOOK_TITLE,BOOK_AUTHOR,BOOK_PUBLISHER,BOOK_IMAGE, BOOK_DESCRIPTION,BOOK_PRICE,BOOK_DISCOUNT_PRICE,BOOK_STOCK,BOOK_ON_SELL,BOOK_CREATED_DATE,BOOK_UPDATED_DATE) values (100006,'돈의 심리학','모건 하우징','인플루엔셜','image-8.jpg','월스트리트저널에서 10년 넘게 금융과 투자에 대한 글을 써온 칼럼니스트이자 콜라보레이티브 펀드 파트너로 활동중인 모건 하우절의 첫 책이다. 출간 즉시 아마존 투자 분야 1위를 차지했고 개인 투자자부터 전문 컨설턴트까지 극찬 세례를 받으며 명실상부 ‘2020 아마존 최고의 금융도서’로 평가받는다.',19500,17550,20,'Y',to_date('2022-11-10','YYYY-MM-DD'),to_date('2022-11-10','YYYY-MM-DD'));
Insert into SAMPLE_BOARD_BOOKS (BOOK_NO,BOOK_TITLE,BOOK_AUTHOR,BOOK_PUBLISHER,BOOK_IMAGE, BOOK_DESCRIPTION,BOOK_PRICE,BOOK_DISCOUNT_PRICE,BOOK_STOCK,BOOK_ON_SELL,BOOK_CREATED_DATE,BOOK_UPDATED_DATE) values (100007,'부자 아빠 가난한 아빠','로버트 기요사키','민음인','image-9.jpg','1997년 미국에서 처음 출간된 이래 전 세계 51가지 언어로 109개국에서 출판되어 4000만 부(국내 350만 부)가 판매된 경제경영 재테크 분야 최고의 밀리언셀러 ‘부자 아빠 가난한 아빠’ 시리즈. 20년의 세월을 통해 검증된 부자들의 돈과 투자에 대한 지침들과 오늘날의 시대상에 맞춘 새로운 정보들이 추가된 『부자 아빠 가난한 아빠 20주년 특별 기념판』이 ㈜민음인에서 출간되었다. ',16000,14400,20,'Y',to_date('2022-11-10','YYYY-MM-DD'),to_date('2022-11-10','YYYY-MM-DD'));
Insert into SAMPLE_BOARD_BOOKS (BOOK_NO,BOOK_TITLE,BOOK_AUTHOR,BOOK_PUBLISHER,BOOK_IMAGE, BOOK_DESCRIPTION,BOOK_PRICE,BOOK_DISCOUNT_PRICE,BOOK_STOCK,BOOK_ON_SELL,BOOK_CREATED_DATE,BOOK_UPDATED_DATE) values (100008,'진짜 쓰는 실무 엑셀','전진권','제이펍','image-10.jpg','오랜 시간 엑셀은 수많은 발전을 거듭하였고, Office 365에서 Microsoft 365로 브랜드명을 변경하기까지 다양한 기능, 특히 동적 배열 함수가 추가되면서 매크로를 사용하지 않고도 많은 부분을 해결할 수 있도록 개선되었다. 이 책에서 소개하는 제대로 된 실무 활용 기능을 익힌다면 방대한 데이터에서 특정 자료를 취합하고 분석하기, 분석된 자료를 한눈에 보기 좋게 시각화하기, 반복되는 작업을 효율적으로 개선하기 등 회사에서 원하는 엑셀 사용 능력을 충분히 뛰어넘을 수 있을 것이다.',21000,18900,20,'Y',to_date('2022-11-10','YYYY-MM-DD'),to_date('2022-11-10','YYYY-MM-DD'));
Insert into SAMPLE_BOARD_BOOKS (BOOK_NO,BOOK_TITLE,BOOK_AUTHOR,BOOK_PUBLISHER,BOOK_IMAGE, BOOK_DESCRIPTION,BOOK_PRICE,BOOK_DISCOUNT_PRICE,BOOK_STOCK,BOOK_ON_SELL,BOOK_CREATED_DATE,BOOK_UPDATED_DATE) values (100009,'미드나잇 라이브러리','매트 헤이그','인플루엔셜','image-11.jpg','매트 헤이그의 소설 『미드나잇 라이브러리』는 2021년 4월 출간 이후 10개월 만에 30만 독자의 마음을 사로잡으며 눈물과 웃음, 가슴 뭉클한 감동을 선사하고 있다. 죽기로 결심한 주인공 ‘노라 시드’가 삶과 죽음 사이에 존재하는 미스터리한 도서관 ‘미드나잇 라이브러리’에서 눈을 뜨며 인생의 두 번째 기회를 얻는 이 소설은, 노라의 가장 완벽한 삶을 찾는 모험을 따라가며 ‘살아 있음’과 ‘살아가는 것’에 대한 깊은 통찰을 보여준다.',15000,13500,20,'Y',to_date('2022-11-10','YYYY-MM-DD'),to_date('2022-11-10','YYYY-MM-DD'));
Insert into SAMPLE_BOARD_BOOKS (BOOK_NO,BOOK_TITLE,BOOK_AUTHOR,BOOK_PUBLISHER,BOOK_IMAGE, BOOK_DESCRIPTION,BOOK_PRICE,BOOK_DISCOUNT_PRICE,BOOK_STOCK,BOOK_ON_SELL,BOOK_CREATED_DATE,BOOK_UPDATED_DATE) values (100010,'이상한 과자 가게 전천당','히로시마 레이코','길벗스쿨','image-12.jpg','여느 날과 다름없이 행운의 동전을 가진 손님들이 전천당을 찾아온다. 열대 과일을 너무 좋아하는 아이는 〈열대 붕어빵〉을, 잘 맞는 옷을 쉽게 고르고 싶은 남자는 〈딱 맞아 땅콩〉을, 좋은 친구를 사귀고 싶은 학생은 〈베프 측정기〉를 고르는 등 간절한 소원이 담긴 물건들을 하나씩 고른다.',11500,10350,20,'Y',to_date('2022-11-10','YYYY-MM-DD'),to_date('2022-11-10','YYYY-MM-DD'));
COMMIT;
데이터가 들어간 모습
게시글이 없는데 5번까지 나온다. 그 문제를 해결하기 위해
<%
// 총 게시글 갯수를 조회한다.
int totalRows = boardDao.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문을 새로 추가하고 맨 밑에 <% } %>를 추가한다.
완성본
게시글이 하나라도 있어야 리스트가 생긴다.
여기서 이미지는 아까 IMAGE폴더에 받은 IMAGE파일이다.
<tbody> <tr class="align-middle"> <td><img src="../resources/images/image-1.jpg" class="img-thumbnail"></td> <td><a href="detail.jsp?no=1" class="text-decoration-none">ETS 토익 정기시험 기출문제집 1000 READING</a></td> <td>ETS</td> <td>YBM</td> <td>18,000 원</td> <td>10 권</td> </tr>
이미지 폴더명은 DB에 넣지 않아도 된다. (전체 경로를 다 적지 않아도 된다.)
책 객체 만들기
Book.java
Dao 만들기
BookDao.java
mappers에서 복사해서 books.xml 만들기
ibatis.config에 books.xml 추가하기
국내도서를 눌렀을 때 5권만 나오게 페이징 처리하기
요청한 페이지에 맞는 데이터 출력하기
페이지 내비게이션 출력하기
1. 전체 데이터 갯수 조회하기
int totalRows = bookDao.getTotalRows();
2. 전체 페이지 갯수 계산하기
3. 전체 페이지 블록 갯수 계산하기
4. 요청한 페이지가 속한 현재 페이지 블록 계산하기
5. 요청한 페이지가 속한 페이지 블록의 시작 페이지번호와 끝 페이지번호 계산하기
6. 페이지 내비게이션 출력하기
namespce : 같은 이름을 가진 클래스를 참조할 수 있으므로 그 공간을 나누는 것(이름의 충돌을 방지하기 위한 장치)
ibatis에서 SQL 구문 이름 충돌 방지하기 1. ibatis-config.xml에 아래의 설정을 추가한다. <!-- SQL 구문에 네임스페이스 사용을 활성화한다. --> <settings useStatementNamespaces="true" /> 2. board.xml, book.xml, reviews.xml, users.xml에서 네임스페이스를 지정한다. board.xml <sqlMap namespace="boards"> book.xml <sqlMap namespace="books"> reviews.xml <sqlMap namespace="reviews"> user.xml <sqlMap namespace="users"> 3. BoardDao.java, BookDao.java, ReviewDao.java, UserDao.java에서 네임스페이스를 사용한다. BoardDao.java public int getTotalRows() { return (Integer) SqlMapper.selectOne("boards.getTotalRows"); BookDao.java public int getTotalRows() { return (Integer) SqlMapper.selectOne("books.getTotalRows"); ReviewDao.java public void deleteReview(int reviewNo) { SqlMapper.delete("reviews.deleteReview", reviewNo); UserDao.java public User getUserById(String id) { return (User) SqlMapper.selectOne("users.getTotalRows", id);
ibatis.config sql 구문 맨 위에 적기
<!-- SQL 구문에 네임스페이스 사용을 활성화한다. -->
<settings useStatementNamespaces="true" />
Pagination이라는 객체를 만들어서 페이징 처리를 관리한다.
```
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;
}
}
where
row_numbers between #begin# and #end#
</select>
@SuppressWarnings("unchecked")
public List<Book> getBooks(Pagination pagination) {
return (List<Book>) SqlMapper.selectList("books.getBooks", pagination);
}
<tbody>
<%
// 요청파라미터에서 요청한 페이지번호를 조회한다.
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);
%>
<%
if (bookList.isEmpty()) {
%>
<tr><td class="text-center" colspan="6"> 게시글 정보가 없습니다. </td></tr>
<%
} else {
for (Book book : bookList) {
%>
<tr class="align-middle">
<td><img src="../resources/images/<%=book.getImage() %>" class="img-thumbnail"></td>
<td><a href="detail.jsp?no=<%=book.getNo() %>" class="text-decoration-none"><%=book.getTitle() %></a></td>
<td><%=book.getAuthor() %></td>
<td><%=book.getPublisher() %></td>
<td><%=book.getPrice() %> 원</td>
<td><%=book.getStock() %> 권</td>
</tr>
<%
}
}
%>
</tbody>
</table>
<%
// 총 게시글 갯수를 조회한다.
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>
<%
}
%>
상세 정보 화면 구현하기
detail.jsp
<%
int bookNo = StringUtils.stringToInt(request.getParameter("no"));
BookDao bookDao = new BookDao();
Book book = bookDao.getBookByNo(bookNo);
%>
<tbody>
<tr>
<th>도서번호</th>
<td><%=book.getNo() %></td>
<th>등록일</th>
<td><%=book.getCreatedDate() %></td>
</tr>
<tr>
<th>제목</th>
<td colspan="3"><%=book.getTitle() %></td>
</tr>
<tr>
<th>저자</th>
<td><%=book.getAuthor() %></td>
<th>출판사</th>
<td><%=book.getPublisher() %></td>
</tr>
<tr>
<th>할인가격</th>
<td><strong class="text-danger"><%=StringUtils.numberToText(book.getDiscountPrice()) %></strong> 원</td>
<th>가격</th>
<td><strong><%=StringUtils.numberToText(book.getPrice()) %></strong> 원</td>
</tr>
<tr>
<th>재고수량</th>
<td><%=book.getStock() %> 권</td>
<th>판매여부</th>
<td><%="Y".equals(book.getOnSell()) ? "판매중" : "재고없음" %></td>
</tr>
<tr>
<th>소개</th>
<td colspan="3"><%=book.getDescription() %></td>
</tr>
</tbody>
주소표기법
절대경로 표기법
- 경로가 "/"로 시작하는 경로
- 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 : http://localhost/web-board/home.jsp
요청 URL : http://localhost/web-board/about.jsp
절대 경로 : 소개
상대 경로 : 소개
현재 페이지의 URL : http://localhost/web-board/home.jsp
요청 URL : http://localhost/web-board/board/list.jsp
절대 경로 : 게시판
상대 경로 : 게시판
현재 페이지의 URL : http://localhost/web-board/book/list.jsp
요청 URL : http://localhost/web-board/book/detail.jsp?no=100
절대 경로 : 게시판
상대 경로 : 게시판
../를 붙이면 경로 중 하나가 탈락된다.
../../을 붙이면 경로 중 두개가 탈락된다.
addItems에 코딩
addItems 코딩
![](https://velog.velcdn.com/images/hcw0709/post/ba94676d-6fc7-4f20-afec-82f5c59d5aad/image.png)
CREATE SEQUENCE SAMPLE_CARTS_SEQ NOCACHE;
시퀀스를 생성해 값을 담아준다.
> 장바구니 목록 추가 기능 구현하기
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;
}
}
public class CartItemDao {
public void addCartItem(CartItem cartItem) {
SqlMapper.insert("carts.insertCartItem", cartItem);
}
}
insert into sample_board_book_cart_items (item_no, book_no, user_id) values (sample_carts_seq.nextval, #bookNo#, #userId#)
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/
상대경로 : ../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.addCartItem(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;
}
}
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#
public class CartItemDao {
@SuppressWarnings("unchecked")
public List getCartItemsByUserId(String userId) {
return (List) SqlMapper.selectList("carts.getCartItemsByUserId", userId);
}
}
list.jsp
<%
User user = (User) session.getAttribute("loginedUser");
if (user == null) {
response.sendRedirect("../user/loginform.jsp?error=deny");
return;
}
%>
<%
// CartItemDao 객체를 생성하고, getCartItemsByUserId(String userId)메소드를 실행해서 장바구니 아이템 목록을 조회한다.
CartItemDao cartItemDao = new CartItemDao();
List 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.getDiscountPrice()*dto.getAmount()) %> 원</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>