이번에는 쇼핑몰의 상품관리에 관련된 업무를 구현해보았다. 이전까지 구현했던 게시판, 파일업로드와 크게 다른 점은 없지만 구현하면서 새롭게 알게되는 내용을 위주로 복습 정리해볼 계획이다.
1. DB(Oracle) 상품 테이블 생성 및 레코드 입력 SQL
CREATE TABLE tbl_product (
product_id NUMBER, -- 상품 번호
product_name VARCHAR2(50), -- 상품 이름
product_price NUMBER DEFAULT 0, -- 상품 가격
product_desc VARCHAR2(500), -- 상품 상세설명
product_url VARCHAR2(500), -- 상품 사진
PRIMARY KEY(product_id)
);
상품 테이블 생성, 상품 번호 기본키 설정
INSERT INTO tbl_product VALUES (1,'나이키',100000,'나이키 2017년 신상제품입니다.','nike.jpg');
INSERT INTO tbl_product VALUES (2,'아디다스',80000,'아디다스의 스테디 셀러!','adidas.jpg');
INSERT INTO tbl_product VALUES (3,'뉴발란스',110000,'뉴발란스의 2016년 최고의 신발','newbalance.jpg');
INSERT INTO tbl_product VALUES (4,'푸마',98000,'푸마 30프로 특가할인 제품입니다.','puma.jpg');
INSERT INTO tbl_product VALUES (5,'팀버랜드',150000,'팀버랜드 스테디 셀러! 특별할인 중입니다.','timberland.png');
INSERT INTO tbl_product VALUES (6,'락포트',99000,'편안한 로퍼 락포트입니다.','rockport.jpg');
INSERT INTO tbl_product VALUES (7,'리복',120000,'2017 신상 퓨리 입고되었습니다.','reebok.jpg');
INSERT INTO tbl_product VALUES (8,'컨버스',60000,'컨버스 특가할인 중입니다.','converse.jpg');
상품 레코드 입력
2. View - 상품 전체 목록 및 상품 상세보기 화면
productList.jsp(상품 전체 목록)
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>상품 목록</title>
<%@ include file="../include/header.jsp" %>
</head>
<body>
<%@ include file="../include/menu.jsp" %>
<h2>상품목록</h2>
<table border="1">
<tr>
<th>상품ID번호</th>
<th>상품이미지</th>
<th>상품명</th>
<th>가격</th>
</tr>
<c:forEach var="row" items="${list}">
<tr>
<td>
${row.productId}
</td>
<td>
<a href="${path}/shop/product/detail/${row.productId}">
<img src="${path}/images/${row.productUrl}" width="120ox" height="110px">
</a>
</td>
<td>
<a href="${path}/shop/product/detail/${row.productId}">${row.productName}</a>
</td>
<td>
<fmt:formatNumber value="${row.productPrice}" pattern="###,###,###"/>
</td>
</tr>
</c:forEach>
</table>
</body>
</html>
상품 목록 화면에서 상품ID번호, 상품 이미지, 상품명, 가격을 리스트로 출력
<fmt:formatNumber value="${row.productPrice}" pattern="###,###,###"/>
- JSTL
fmt
태그를 사용하여 숫자 포맷을 변경해주었다. 상품가격의 가독성을 높이기 위해 숫자3자리마다 콤마(,)를 찍어주도록 처리
<a href="${path}/shop/product/detail/${row.productId}">
- 상품이미지와 상품명을 클릭하면 해당 상품의 상세 화면으로 이동할 수 있도록
<a href>
태그로 링크
프로젝트의 디렉토리에 존재하는 이미지 파일을 view에 출력해주기 위해서는 servlet-context.xml
에 아래와 같은 설정이 필요하다. 실제 리소스가 저장된 경로를 링크할 수 도 있지만 외부에 리소스가 실제로 저장된 경로를 감추기 위해서이다.
<!-- mapping : 가상 경로(상대경로), location : 리소스가 실제로 저장된 경로 -->
<resources mapping="/images/**" location="/WEB-INF/views/images/"/>
productDetail.jsp(상품 상세보기)
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>상품 상세정보</title>
<%@ include file="../include/header.jsp" %>
</head>
<body>
<%@ include file="../include/menu.jsp" %>
<h2>상품 상세정보</h2>
<table border="1">
<tr>
<td>
<img src="${path}/images/${vo.productUrl}" width="340" height="300">
</td>
<td>
<table border="1" style="height: 300px; width: 400px;">
<tr align="center">
<td>상품명</td>
<td>${vo.productName}</td>
</tr>
<tr align="center">
<td>가격</td>
<td><fmt:formatNumber value="${vo.productPrice}" pattern="###,###,###"/></td>
</tr>
<tr align="center">
<td>상품소개</td>
<td>${vo.productDesc}</td>
</tr>
<tr align="center">
<td colspan="2">
<form name="form1" method="post" action="${path}/shop/cart/insert.do">
<input type="hidden" name="productId" value="${vo.productId}">
<select name="amount">
<c:forEach begin="1" end="10" var="i">
<option value="${i}">${i}</option>
</c:forEach>
</select> 개
<input type="submit" value="장바구니에 담기">
</form>
<a href="${path}/shop/product/list.do">상품목록</a>
</td>
</tr>
</table>
</td>
</tr>
</table>
</body>
</html>
<fmt:formatNumber value="${vo.productPrice}" pattern="###,###,###"/>
- JSTL
fmt
태그를 사용하여 숫자 포맷을 변경해주었다. 상품가격의 가독성을 높이기 위해 숫자3자리마다 콤마(,)를 찍어주도록 처리
<a href="${path}/shop/product/list.do">상품목록</a>
: 상품목록으로 이동그 외에 내용은 장바구니 기능구현 포스팅에서 설명
3. MybatisMapper
productMapper : 상품 페이지 관련 mapper
<mapper namespace="product">
<!-- 01. 상품 전체 목록 -->
<select id="listProduct" resultType="com.example.spring02.model.shop.dto.ProductVO">
SELECT
product_id AS productId,
product_name AS productName,
product_price AS productPrice,
product_desc AS productDesc,
product_url AS productUrl
FROM tbl_product
ORDER BY product_name
</select>
<!-- 02. 상품 상세보기 -->
<select id="detailProduct" resultType="com.example.spring02.model.shop.dto.ProductVO">
SELECT
product_id AS productId,
product_name AS productName,
product_price AS productPrice,
product_desc AS productDesc,
product_url AS productUrl
FROM tbl_product
WHERE product_id = #{productId}
</select>
</mapper>
상품 전체 목록 select쿼리
- DB의 칼럼명과 java에서 처리하는 변수명이 일치하지 않기 때문에
alias
로 매칭시켜주었다.- 전체 목록을 상품명 오름차순으로 정렬
상품 상세보기 select쿼리
- 전체목록과 동일하게
alias
로 변수명과 칼럼값을 매칭시켜주고,WHERE
조건절로 해당상품명만 조회할 수 있게 처리
4. DTO/VO
ProductVO : 상품 관련VO
public class ProductVO {
private int productId; // 상품번호
private String productName; // 상품이름
private int productPrice; // 상품가격
private String productDesc; // 상품 상세정보
private String productUrl; // 상품이미지 경로
private MultipartFile productPhoto; // 상품이미지파일
// Getter, Setter, toString() 생략
// ....
}
상품관련 VO
5. Controller(흐름제어)
ProductController : 상품 관련 페이지 매핑
@Controller
@RequestMapping("shop/product/*")
public class ProductController {
@Inject
ProductService productService;
// 1. 상품 전체 목록
@RequestMapping("/list.do")
public ModelAndView list(ModelAndView mav) {
mav.setViewName("/shop/productList");
mav.addObject("list", productService.listProduct());
return mav;
}
// 2. 상품 상세보기
@RequestMapping("/detail/{productId}")
public ModelAndView detail(@PathVariable("productId") int productId, ModelAndView mav){
mav.setViewName("/shop/productDetail");
mav.addObject("vo", productService.detailProduct(productId));
return mav;
}
}
@RequestMapping("/list.do")
: 상품 전체 목록 페이지 매핑
- 리턴타입을
ModelAndView
로 설정하여 view의 이름과 Service에서 가져온 리스트 객체를 리턴
@RequestMapping("/detail/{productId}")
: 상품 상세보기 페이지 매핑
- 페이지 맵핑은 하나의 URL이 하나의 고유한 리소스를 대표(Rest)할 수 있도록 처리해
- 리턴타입을
ModelAndView
로 설정하여 view의 이름과 service에서 가져온 상품 객체를 리턴
6. Service(비지니스 로직, DB연동 이외의 핵심업무처리)
ProductServiceImpl : ProductService인터페이스를 구현한 클래스
@Service
public class ProductServiceImpl implements ProductService {
@Inject
ProductDAO productDao;
// 01. 상품목록
@Override
public List<ProductVO> listProduct() {
return productDao.listProduct();
}
// 02. 상품상세
@Override
public ProductVO detailProduct(int productId) {
return productDao.detailProduct(productId);
}
// 03. 상품수정
@Override
public void updateProduct(ProductVO vo) {
// TODO Auto-generated method stub
}
// 04. 상품삭제
@Override
public void deleteProduct(int productId) {
// TODO Auto-generated method stub
}
}
listProduct()
: 상품관련DAO(ProductDAO
)의 목록 메서드 호출
detailProduct(int productId)
: 상품관련DAO(ProductDAO
)의 상세보기 메서드 호출
7. DAO(비지니스로직, DB연동 작업처리)
ProductDAOImpl - ProductDAO인터페이스를 구현한 클래스
@Repository
public class ProductDAOImpl implements ProductDAO {
@Inject
SqlSession sqlSession;
// 01. 상품목록
@Override
public List<ProductVO> listProduct() {
return sqlSession.selectList("product.listProduct");
}
// 02. 상품상세
@Override
public ProductVO detailProduct(int productId) {
return sqlSession.selectOne("product.detailProduct", productId);
}
// 03. 상품수정
@Override
public void updateProduct(ProductVO vo) {
// TODO Auto-generated method stub
}
// 04. 상품삭제
@Override
public void deleteProduct(int productId) {
// TODO Auto-generated method stub
}
}
전체 상품 목록을 select조회한 결과를 리턴
상품상세 정보를 select조회한 결과를 리턴