20221004_tue
지난시간 내용 정리
- 상품 재고수량 변경 기능 구현
- 상품 판매상태 변경 기능 구현
재고수량 변경 및 상품 판매상태 변경 기능 구현
- item_manage.html
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org"
xmlns:layout="http://www.ultra.net.nz/thymeleaf/layout"
layout:decorate="~{layout/admin_layout}"
xmlns:sec="http://www.thymeleaf.org/extras/spring-security">
<div layout:fragment="content">
<div class="row">
<div class="col">
<h1>상품관리페이지</h1>
<div class="row"><!-- 좌우측화면 담고있는 화면 -->
<!-- 검색 -->
<div class="col-12 mb-5">
<div>
<table class="table table-striped table-hover">
<tr>
<td> 카테고리 </td>
<td colspan="2">
<select >
<option th:each="cateList : ${cateListAll}" th:text="${cateList.cateName}"></option>
</select>
</td>
<td>상품명</td>
<td><input type="text"> </td>
<td>재고</td>
<td><input type="number" > </td>
</tr>
<tr>
<td>등록일</td>
<td><input type="date"></td>
<td><input type="date"></td>
<td>상태</td>
<td colspan="3">
<input type="radio" value="전체" th:text="전체" checked="checked">
<input type="radio" value="판매중" th:text="판매중">
<input type="radio" value="매진" th:text="매진">
</td>
</tr>
</table>
</div>
<div align="center">
<button class="btn btn-outline-secondary" type="submit">검색</button>
</div>
</div>
<!-- 목록테이블 제목줄 -->
<div class="col-12 mb-5">
<table class="table table-striped table-hover">
<colgroup>
<col width="*%">
<col width="10%">
<col width="20%">
<col width="10%">
<col width="20%">
<col width="20%">
<col width="20%">
</colgroup>
<thead>
<tr>
<th>No.</th>
<th>카테고리</th>
<th>상품명</th>
<th>가격</th>
<th>재고</th>
<th>등록일</th>
<th>상태</th>
</tr>
</thead>
<tbody>
<th:block th:if="${#lists.size(regItemList) == 0}">
<tr>
<td colspan="7"> 조회된 목록이 없습니다.</td>
</tr>
</th:block>
<th:block th:unless="${#lists.size(regItemList) == 0}">
<th:block th:each="regItemInfo , status : ${regItemList}" >
<tr>
<td th:text="${status.count}"></td>
<td th:text="${regItemInfo.cateName}"></td>
<td th:text="${regItemInfo.itemName}"></td>
<td th:text="${regItemInfo.itemPrice}"></td>
<td>
<div class="input-group mb-3">
<input id="itemStocks" type="number" th:value="${regItemInfo.itemStock}" class="form-control stockInput"
aria-label="Recipient's username" aria-describedby="button-addon2">
<!-- 타임리프로 데이터 던질때 주의할 점: 대괄호 두개 달러 중괄호 사용하기 -->
<!-- 단, 데이터를 던질때 value값 itemstock을 던지면 변경한 숫자가 넘어가는것이아니라
원래 있던 변경 재고값이 넘어가는 것이기때문에 itemcode값을 던져야한다.-->
<!-- this 를 넘기면 내가 뭔가 액션을 취한 (변경버튼클릭했을 때의 그 값)이 넘어간다.-->
<button class="btn btn-outline-secondary" type="submit" id="button-addon2"
th:onclick="changeStock([[${regItemInfo.itemCode}]] ,this);" >변경</button>
</div>
</td>
<td th:text="${regItemInfo.regDate}"></td>
<!-- 라디오값-->
<!-- 변수와 문자열을 동시에 사용하기위해서 -->
<!-- 네임값에 버티컬바 두개를 넣으면 편히 넣어 데이터넘길수있다. -->
<td id="itemStatusId">
<div class="form-check form-check-inline">
<input class="form-check-input " type="radio" th:name="|itemStatus_${status.count}|"
id="onSale" value="ON_SALE" th:checked="${regItemInfo.itemStatus eq '판매중'}"
th:onclick="changeItemStatus([[${regItemInfo.itemCode}]], 'ON_SALE');" >
<label class="form-check-label" for="inlineRadio1">판매중</label>
</div>
<div class="form-check form-check-inline">
<input class="form-check-input " type="radio" th:name="|itemStatus_${status.count}|"
id="soldOut" value="SOLD_OUT" th:checked="${regItemInfo.itemStatus eq '매진'}"
th:onclick="changeItemStatus([[${regItemInfo.itemCode}]],'SOLD_OUT');" >
<label class="form-check-label" for="inlineRadio2">매진</label>
</div>
</td>
</tr>
</th:block>
</th:block>
</tbody>
</table>
</div>
</div>
</div>
</div>
<!-- 수량 변경 후 실행되는 modal창 -->
<!-- Modal -->
<div class="modal fade" id="updateStockModal" tabindex="-1" aria-labelledby="exampleModalLabel" aria-hidden="true">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-body">
<div class="row mb-3">
<div class="col">
상품수량을 변경했습니다.
</div>
</div>
<div class="row">
<!-- text-end: 글자 우측정렬 btn-sm: 작은 버튼-->
<div class="col text-end">
<button type="button" class="btn btn-primary btn-sm" data-bs-dismiss="modal"
style="--bs-btn-padding-y: .25rem; --bs-btn-padding-x: 1.5rem; --bs-btn-font-size: 1rem;" >확인</button>
</div>
</div>
</div>
</div>
</div>
</div>
<!-- modal -->
<!-- 상품상태 변경 후 실행되는 modal창 -->
<!-- Modal -->
<div class="modal fade" id="updateStatusModal" tabindex="-1" aria-labelledby="exampleModalLabel" aria-hidden="true">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-body">
<div class="row mb-3">
<div class="col">
상품 판매상태를 변경했습니다.
</div>
</div>
<div class="row">
<div class="col text-end">
<button type="button" class="btn btn-primary btn-sm" data-bs-dismiss="modal"
style="--bs-btn-padding-y: .25rem; --bs-btn-padding-x: 1.5rem; --bs-btn-font-size: 1rem;" >확인</button>
</div>
</div>
</div>
</div>
</div>
</div>
<!-- modal -->
<!-- 반드시 해당되는 div 태그 안에 있어야 실행이 된다. -->
<script src="https://code.jquery.com/jquery-latest.min.js"></script>
<script type="text/javascript" th:src="@{/js/layout/item_manage.js}"></script>
</div>
</html>
- 태그선택 요소
const itemStock = selectedTag.parentElemnet.previousElemnetSibling.children[0].vlaue;
const itemStock = document.querySelectorAll('.stockInput');
const itemStock1 = selectedTag.parentElemnet.children[0].vlaue;
const itemStock = selectedTag.closest('td').querySelector('.stockInput').vlaue;
//-------------------상품(판매)여부 라디오 버튼 클릭시 진행되는 함수---------------------------------//
function changeItemStatus(itemCode, status){
$.ajax({
url: '/admin/changeItemStatus', //요청경로
type: 'post',
data: {'itemStatus':status,'itemCode':itemCode}, //필요한 데이터
success: function(result) {
const modal = new bootstrap.Modal('#updateStatusModal');
modal.show();
},
error: function() {
alert('실패');
}
});
}
//--------------------------재고 수량변경 버튼 클릭시 진행되는 함수---------------------------------//
function changeStock(itemCode, selectedTag){
const itemStock = selectedTag.closest('td').querySelector('#itemStocks').value;
//1) ajax start
$.ajax({
url: '/admin/changeStock', //요청경로
type: 'post',
data: {'itemCode':itemCode ,'itemStock':itemStock}, //필요한 데이터
success: function(result) {
// -- alert창 띄우는 ver.
// alert('수량을 변경했습니다');
// -- modal창 띄우는 ver.
// 버튼을 클릭했을 때가 아니라 원했을 때 띄우기
const modal = new bootstrap.Modal('#updateStockModal');
modal.show();
},
error: function() {
alert('실패');
}
});
//1) ajax end
}
package Kh.study.shop.admin.controller;
import java.util.List;
import javax.annotation.Resource;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import Kh.study.shop.admin.service.AdminService;
import Kh.study.shop.item.service.ItemService;
import Kh.study.shop.item.vo.CategoryVO;
import Kh.study.shop.item.vo.ItemVO;
import Kh.study.shop.member.service.MemberService;
import Kh.study.shop.member.vo.MemberVO;
@Controller
@RequestMapping("/admin")
public class AdminController {
////////////////////////////////////////////////////
@Resource(name = "adminService")
private AdminService adminService;
@Resource(name = "memberService")
private MemberService memberService;
@Resource(name = "itemService")
private ItemService itemService;
/////////////////////////////////////////////////////
//관리자_첫화면 :상품등록 및 상세페이지 동시
@GetMapping("/regCate")
public String admin(Model model, ItemVO itemVO) {
//전체 카테고리 목록조회(좌측화면에만 데이터 뿌리기)
model.addAttribute("cateListAll",adminService.cateListAll());
//'사용' 중 카테고리 목록 조회(우측화면 상품등록시 적용되도록)
model.addAttribute("cateListUse",adminService.cateListUse());
return "content/admin/reg_item";
}
//카테고리 등록
@PostMapping("/regCate")
public String regCate(CategoryVO categoryVO) {
adminService.regCate(categoryVO);
// 카테고리 등록 후, 다시 첫화면 페이지로 이동
return "redirect:/admin/regCate";
}
//카테고리상태 변경(ajax실행)
//ajax사용하는 이유! 페이지이동없이하려고!!
// -> 그래서 페이지이동 리턴값이 없다!
@ResponseBody
@PostMapping("/changeStatus")
public void changeStatus(CategoryVO categoryVO) {
//상태변경하기
adminService.changeStatus(categoryVO);
}
// 사용중 카테고리 목록 조회(ajax사용)
@ResponseBody
@PostMapping("/selectCategoryListInUseAjax")
public List<CategoryVO> selectCategoryListInUseAjax() {
//사용중 카테고리 목록 재조회
List<CategoryVO> cateList = adminService.cateListUse();
return cateList;
}
//실제 상품등록
@PostMapping("/regItem")
public String reg(ItemVO itemVO) {
adminService.regItem(itemVO);
return "redirect:/admin/regCate";//관리자 첫화면
}
//회원권한설정클릭시 첫화면
@GetMapping("/setMemberRole")
public String setMemberRoleProccess(Model model,MemberVO memberVO) {
model.addAttribute("memberList",memberService.selectMemberList());
return "content/admin/set_member_role" ;
}
// (ajax)회원 상세정보조회
@ResponseBody
@PostMapping("/showDetailmemberInfo")
public MemberVO showDetailmemberInfo(String memberId) {
MemberVO memberInfo = memberService.selectMemberDetail(memberId);
return memberInfo;
}
//상세조회 후 수정하기
@PostMapping("/updateMemberRole")
public String updateMemberRole(MemberVO memberVO) {
// 수정쿼리문
return "redirect:/admin/setMemberRole";
}
//상품관리 클릭시
@GetMapping("/itemManage")
public String itemManage(Model model, ItemVO itemVO) {
// 등록된 상품목록조회
model.addAttribute("regItemList", itemService.selectRegItemList());
// 카테고리 목록조회
model.addAttribute("cateListAll",adminService.cateListAll());
return "content/admin/item_manage";
}
//(ajax) 수량 변경
@ResponseBody
@PostMapping("/changeStock")
public void changeStock(ItemVO itemVO) {
itemService.updateStock(itemVO);
}
//(ajax) 상품판매여부 변경
@ResponseBody
@PostMapping("/changeItemStatus")
public void changeItemStatus(ItemVO itemVO) {
itemService.updateStautus(itemVO);
}
}
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<!--해당 파일에 모든 쿼리문을 작성 -->
<mapper namespace="itemMapper">
<!-- 패키지명 클래스명 -->
<resultMap type="Kh.study.shop.item.vo.ItemVO" id="item">
<id column="ITEM_CODE" property="itemCode"/>
<result column="ITEM_NAME" property="itemName"/>
<result column="ITEM_PRICE" property="itemPrice"/>
<result column="ITEM_COMMENT" property="itemComment"/>
<result column="REG_DATE" property="regDate"/>
<result column="ITEM_STOCK" property="itemStock"/>
<result column="ITEM_STATUS" property="itemStatus"/>
<result column="CATE_CODE" property="cateCode"/>
<result column="CATE_NAME" property="cateName"/>
<result column="CATE_STATUS" property="cateStatus"/>
</resultMap>
<!-- 상품목록조회 -->
<select id="selectItemList" resultMap="item">
SELECT
ITEM_CODE
,ITEM_NAME
,ITEM_PRICE
,ITEM_COMMENT
,REG_DATE
,ITEM_STOCK
,CATE_CODE
FROM SHOP_ITEM
ORDER by ITEM_CODE
</select>
<!-- 상품관리 페이지 이동시 -->
<!-- 상품+카테고리 함께 목록조회 -->
<!-- 조건검색기능 -->
<!-- 조건절 AND로 계속 연결된다.-->
<!-- 대소문자 구분없이 -->
<!-- <= 사용시, 부등호를 태그로 인식하기때문에 -->
<!-- less than: $lt; greater than : $gt; -->
<!-- 날짜비교 중요한사항! -->
<!-- ! 그대로 컬러명사용하는 것이아니라 형변환(TO_CHAR)하여 진행해야 비교가 온전히 가능하다-->
<!-- 모든 값은 if문으로 넣어 사용해야한다. -->
<select id="selectRegItemList" resultMap="item">
SELECT
ITEM_CODE
,ITEM_NAME
,ITEM_PRICE
,to_char(REG_DATE, 'YYYY-MM-DD') REG_DATE
,ITEM_STOCK
,SHOP_ITEM.CATE_CODE
,CATE_NAME
,DECODE(ITEM_STATUS,'ON_SALE','판매중','매진') ITEM_STATUS
FROM SHOP_ITEM,ITEM_CATECGORY
WHERE SHOP_ITEM.CATE_CODE = ITEM_CATECGORY.CATE_CODE
<!-- <if test="">
AND SHOP_ITEM.CATE_CODE = #{cateCode}
</if>
<if test="">
AND UPPER(ITEM_NAME) LIKE UPPER('%#{itemName}%')
</if>
<if test="">
AND ITEM_STOCK <= #{itemStock}
</if>
<if test="">
AND TO_CHAR(REG_DATE,'YYYY-DD-MM') >= '#{regDate}'
</if>
<if test="">
AND TO_CHAR(REG_DATE,'YYYY-DD-MM') <= '#{regDate}'
</if>
<if test="">
AND ITEM_STATUS = 'ON_SALE'
</if> -->
</select>
<!-- 재고 수량 변경 -->
<update id="updateStock" >
UPDATE SHOP_ITEM
SET
ITEM_STOCK = #{itemStock}
WHERE ITEM_CODE = #{itemCode}
</update>
<!-- 상품상태 여부 변경 -->
<update id="updateStautus" >
UPDATE SHOP_ITEM
SET
ITEM_STATUS = #{itemStatus}
WHERE ITEM_CODE = #{itemCode}
</update>
</mapper>
package Kh.study.shop.item.service;
public interface ItemService {
List<ItemVO> selectItemList();
List<ItemVO> selectRegItemList();
void updateStock(ItemVO itemVO);
void updateStautus(ItemVO itemVO);
}
package Kh.study.shop.item.service;
import java.util.List;
import org.mybatis.spring.SqlSessionTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import Kh.study.shop.item.vo.ItemVO;
@Service("itemService")
public class ItemServiceImpl implements ItemService {
@Autowired
private SqlSessionTemplate sqlSession;
@Override
public List<ItemVO> selectItemList() {
return sqlSession.selectList("itemMapper.selectItemList");
}
@Override
public List<ItemVO> selectRegItemList() {
return sqlSession.selectList("itemMapper.selectRegItemList");
}
@Override
public void updateStock(ItemVO itemVO) {
sqlSession.update("itemMapper.updateStock",itemVO);
}
@Override
public void updateStautus(ItemVO itemVO) {
sqlSession.update("itemMapper.updateStautus",itemVO);
}
}
컬렉션 프레임워크(데이터 모음)
: 모두 데이터를 여러개 저장할 수 있는 상자들과 같다
- List : 순번이 존재하고 중복데이터 저장이 가능하다.
- Set : 순번이 존재하지 않고 중복데이터 저장이 불가능하다.
ex) 핸드폰 1개당 중복데이터 저장 불가능 단 하나의 데이터저장만 가능- Map : 데이터가 키와 value값이라는 하나의 싸움으로 이루어져있다.
오늘 실습내용
- 재고수량 변경 및 상품 판매상태 변경 기능 구현
- 1)alert창을 띄우지 않고 modal창으로 만들어서 버튼클릭시 진행되도록 구현하기
- 2)상품관리 페이지의 검색조건에서 카테고리 목록 데이터 조회하기
- 3)등록일 시작날짜는 한달 전 날짜가 세팅, 마지막날짜는 오늘이 기본날짜로 세팅하기
: 자바스크립트,자바 모두 가능 -> 자바에서 하도록 기능구현하기
: shop프로젝트 내 생성