이번 시간에는 물품과 물품들의 이미지 정보를 불러와 고객들이 주문을 할 수 있게 구성하고,
주문을 한 뒤에는 마이페이지의 4번째 주문내역
의 목록에서 주문정보를 확인 가능하도록 기능을 구현 해보겠다.
먼저 상품을 보여주는 메인 화면은 지난번 프론트엔드 학습 시간에 BootStrap예제를 이용하여 만들었다.
<div class="grid">
<c:forEach var="obj" items="${list}">
<a href="product.do?itemno=${obj.no}">
<div class="item">
<c:if test="${obj.imageNo != 0}">
<img src="${pageContext.request.contextPath}/item/image?no=${obj.imageNo}"
style="width:100%; height:150px">
</c:if>
<c:if test="${obj.imageNo == 0}">
<img src="${pageContext.request.contextPath}/resources/images.png"
style="width:100%; height:150px">
</c:if>
물품명 : ${obj.name}<br/>
가격 : ${obj.price}원<br/>
내용 : ${obj.content}<br/>
</div>
</a>
</c:forEach>
</div>
그리드 박스 안에는 각 상품들의 제일 처음 등록된 사진과, 상품 설명들이 같이 출력되도록 코드를 구성했다.
또한 각각 이미지번호를 부여받아 서로 다른 이미지들이 나오도록 <c:forEach>
태그 사용했고, 만일 사진이 등록되지 않을시 기본이미지가 출력되도록 c:if문을 구성했다.
또한 화면에는 그리드 박스들이 일정한 간격을 유지하여 나오도록 위와같이 CSS의 스타일을 지정해줬다.
<style>
.grid {
display: grid;
grid-template-columns: 1fr 1fr 1fr 1fr;
column-gap: 10px;
row-gap: 10px;
}
.item {
padding: 10px;
border: 1px solid #cccccc;
min-height: 300px;
}
a {
text-decoration: none;
color: #111111;
}
a:hover .item {
color: blue;
border: 1px solid blue;
}
</style>
지금까지는 물품 따로, 이미지 따로 DB에 저장해주었기 때문에, 외래키로 두가지 테이블을 묶어주고자 물품 DTO
에 이미지번호
를 저장할 변수를 생성해준다.
private long imageNo; // 대표 이미지번호를 저장할 임시변수
그 다음으로는 itemImageMapper
에 item당 imageNo가 제일 작은 것을 반환하는 쿼리문 작성해주었다.
// 물품 이미지번호를 가장 작은것을 반환하며, 없을시 0을 반환.
// 홈페이지 물품 이미지용
@Select ( value = {
" SELECT NVL(min(no),0) ",
" FROM itemimage ",
" WHERE itemno = #{itemno} "
} )
public long selectItemImageMinOne(@Param("itemno") long itemno);
그리고 이렇게 Select된 물품들의 정보들을 CustomerHome 컨트롤러에서 반복문을 사용하여 list
명칭에 결과를 담아 customer_home.jsp로 전송시켜 모두 출력되도록 구성해줬다.
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
List<Item> list = MyBatisContext.getSqlSession().getMapper(ItemMapper.class)
.selectItemListAll();
for(Item item: list) {
// 먼저 대표 이미지번호를 저장해둘 변수를 Item dto에 생성해준뒤,
// itemImageMapper에 이미지넘버를 불러오는 mapper를 작성한다.
// mapper를 호출하여 해당물품의 가장 먼저 등록했던 이미지번호 1개를 가져온다.
long imageNo = MyBatisContext.getSqlSession()
.getMapper(ItemImageMapper.class)
.selectItemImageMinOne(item.getNo());
item.setImageNo(imageNo);
}
request.setAttribute("list", list);
request.getRequestDispatcher("/WEB-INF/customer/home.jsp").forward(request, response);
}
주문 정보들을 표시하기 위해 먼저 DB에 테이블부터 만들어주었다.
-- 시퀀스 생성
CREATE SEQUENCE SEQ_PURCHASE_NO START WITH 1001 INCREMENT BY 1 NOCACHE NOMAXVALUE;
-- 테이블생성
CREATE TABLE purchase
(
no number default seq_purchase_no.nextval not null,
cnt NUMBER,
itemno NUMBER,
customerid VARCHAR2(50),
regdate TIMESTAMP DEFAULT CURRENT_DATE,
PRIMARY KEY(no),
FOREIGN KEY(itemno) REFERENCES item(no),
FOREIGN KEY(customerid) REFERENCES memtb(id)
);
package webdto;
import java.util.Date;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
import lombok.ToString;
@Getter
@Setter
@ToString
@NoArgsConstructor
@AllArgsConstructor
public class Purchase {
private long no; // 시퀀스 사용
private long cnt;
private long itemno;
private String customerid;
private Date regdate; // 자동으로 들어감.
}
package webmapper;
import java.util.List;
import org.apache.ibatis.annotations.Insert;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;
import org.apache.ibatis.annotations.Select;
import webdto.Purchase;
import webdto.PurchaseView;
@Mapper
public interface PurchaseMapper {
// 주문 등록
@Insert ( value = {
" INSERT INTO purchase( cnt, itemno, customerid) ",
" VALUES( #{obj.cnt}, #{obj.itemno}, #{obj.customerid} ) "
} )
public int insertPurchase(@Param("obj") Purchase obj);
// -------------------------------------------------------------------------
// 현재 로그인한 사용자가 주문한 내역 조회
@Select ( value = {
" SELECT * FROM PURCHASE ",
" WHERE customerid =#{id} "
} )
public List<Purchase> selectPurchaseMember(@Param("id") String id);
// -------------------------------------------------------------------------
// 주문 + 고객 + 물품 조인한 VIEW 만들기
// 주문번호, 주문일자, 주문자아이디, 주문자이름, 물품명, 물품가격
@Select( value = {
" SELECT * FROM purchaseview WHERE customerid=#{id} "
} )
public List<PurchaseView> selectPurchaseViewMember(@Param("id") String id);
}
그리고 주문정보의 경우에는 마이페이지의 4번째 항목을 사용하여 출력했다.
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>
<body style="color: rgba(123, 123, 102, 0.5);">
<div id="layoutAuthentication">
<div id="layoutAuthentication_content">
<main>
<div class="container">
<div class="row justify-content-center">
<div class="col-lg">
<div class="card shadow-lg border-0 rounded-lg mt-5 mb-5">
<div class="card-header">
<h3 class="text-left font-weight-light my-4">주문내역 조회하기</h3>
</div>
<div class="card-body">
<form class="form-inline d-flex justify-content-first"
method="GET" th:action="@{/board/boardList}"
th:value="${param.searchText}">
</form>
<table class="table">
<thead>
<tr>
<th scope="col">주문번호</th>
<th scope="col">물품번호</th>
<th scope="col">주문수량</th>
<th scope="col">주문자 아이디</th>
<th scope="col">주문날짜</th>
</tr>
</thead>
<tbody>
<c:forEach var="obj" items="${list}">
<tr>
<td>${obj.no}</td>
<td>${obj.itemno}</td>
<td>${obj.cnt}</td>
<td>${obj.customerid}</td>
<td>${obj.regdate}</td>
</tr>
</c:forEach>
</tbody>
</table>
<hr />
<div class="col-auto pull-end">
<ul id="pagination-demo"
class="pagination-sm d-flex justify-content-center"></ul>
</div>
</div>
</div>
</div>
</div>
</div>
</main>
</div>
</div>
위의 내용을
<c:if test="${param.menu == 4}">
<jsp:include page="../customer_menu/menu4.jsp"></jsp:include>
</c:if>
Mypage에서 불러오는 식으로 추가했다.
지금까지는 로그인 유효성을 검사하기 위한 Filter를 하나만 생성해두고 사용했다.
하지만, 물품 주문화면과 같은 경우 사용자가 도달한 화면에서 로그인 후 다시 홈화면으로 되돌아간다면 접근성의 면에서도 다소 불편함이 존재하기 때문에 로그인의 이전 화면으로 다시 되돌아 갈 수 있도록 아래의 이전 세션 이동용 필터를 추가하였다.
package filter;
import java.io.IOException;
import jakarta.servlet.Filter;
import jakarta.servlet.FilterChain;
import jakarta.servlet.ServletException;
import jakarta.servlet.ServletRequest;
import jakarta.servlet.ServletResponse;
import jakarta.servlet.annotation.WebFilter;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import jakarta.servlet.http.HttpSession;
// home(0) -> login(x) OR logout(x) -> home(o)
// board(o) -> login(x) -> board(O)
// 로그인후 이전페이지 이동을 위한 필터
/* 필터를 사용할 주소창을 입력 */
@WebFilter(urlPatterns = { "/customer/*"})
public class UrlFilter implements Filter {
@Override
public void doFilter(ServletRequest arg0, ServletResponse arg1, FilterChain arg2)
throws IOException, ServletException {
HttpServletRequest request = (HttpServletRequest) arg0; // arg0은 request
HttpSession httpSession = request.getSession();
String uri = request.getRequestURI();
if ( !uri.contains("login.do") && !uri.contains("logout.do")) { // 세션에 등록된 UID 객체가 없으면 다시 로그인 페이지로 보냄.
// home.do => null => queryString이 null임.
// product.do?itemno=33 => itemno=33 => queryString이 itemno=33임.('?'는 없음!)
String queryString = request.getQueryString();
if(queryString == null) {
httpSession.setAttribute("url", request.getRequestURI());
System.out.println("url 필터 : " + request.getRequestURI());
}
else {
httpSession.setAttribute("url", request.getRequestURI()+"?"+queryString);
System.out.println("url 필터 : " + request.getRequestURI()+"?"+queryString);
}
}
// UID가 존재할 시 원래 수항하는 페이지로 이동
arg2.doFilter(arg0, arg1);
}
}