20220929_thu
실습내용
- 상품등록 기능 구현
- 단, 사용하는 상품의 경우만 카테고리 셀렉트박스에 띄우도록 한다.
: 주의할 점, 위의 경우 좌측화면에서 사용여부를 변경시 디비에는 저장이 되지만, 우측화면의 경우는 변경사항이 반영이 안된다!- 등록된 카테고리들은 top파일 상단메뉴판에 나타나도록 한다.
- 권한설정 클릭시, 좌측화면 :회원목록(no,이름,권한,회원목록)
우측화면 :회원이름을 클릭할때마다 회원의 상세정보(모든) 페이지 구현
-> 목록을 띄우는 것은 그냥 띄우지만, 상세정보페이지는 페이지 이동없이 해야하므로 ajax 사용한다.- ajax 를 이용해서 상품등록할 때 '사용'중인 카테고리 셀렉트박스 조회하려면,
이전 사용여부버튼 클릭시 변경하는 함수가 있는 자바스크립트로 파일로 가서
다시 셀렉트 박스를 조회하도록 작성해줘야한다.
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.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;
/////////////////////////////////////////////////////
//관리자_첫화면 :상품등록 및 상세페이지 동시
@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";
}
}
<?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="adminMapper">
<resultMap type="Kh.study.shop.item.vo.CategoryVO" id="category">
<id column="CATE_CODE" property="cateCode"/>
<result column="CATE_NAME" property="cateName"/>
<result column="CATE_STATUS" property="cateStatus"/>
</resultMap>
<!-- 사용시 페이지 연결이 끊김. -->
<!-- <resultMap type="Kh.study.shop.item.vo.MemberVO" id="member">
<id column="MEMBER_ID" property="memberId"/>
<result column="MEMBER_PW" property="memberPw"/>
<result column="MEMBER_NAME" property="memberName"/>
<result column="MEMBER_ADDR" property="memberAddr"/>
<result column="ADDR_DETAIL" property="addrDetail"/>
<result column="MEMBER_EMAIL" property="memberEmail"/>
<result column="MEMBER_ROLE" property="memberRole"/>
<result column="MEMBER_STATUS" property="memberStatus"/>
</resultMap> -->
<!-- 카테고리 목록조회 -->
<!-- if문사용하여 사용여부가 사용인 것만 데리고 와서 상품등록 가능하도록 구현 -->
<!-- if 문 테스트 값안에는 빈값채울애(객체명)의 getter를 호출한다.-->
<!-- 단, 자료형은 항상 같아야한다. -->
<!-- 그런데 하나의 빈값만 채울때는 언더바파라매터를 사용하면 객체명이 아니어도 getter호출하지않고도사용가능하다 -->
<select id="cateListAll" resultMap="category">
SELECT
CATE_CODE
,CATE_NAME
,CATE_STATUS
FROM ITEM_CATECGORY
ORDER BY CATE_CODE
</select>
<select id="cateListUse" resultMap="category">
SELECT
CATE_CODE
,CATE_NAME
,CATE_STATUS
FROM ITEM_CATECGORY
WHERE CATE_STATUS = 'USE'
ORDER BY CATE_CODE
</select>
<!-- 카테고리 등록 -->
<insert id="regCate">
<selectKey resultType="String" keyProperty="cateCode" order="BEFORE">
SELECT 'CATE_' ||LPAD(NVL(MAX(TO_NUMBER(SUBSTR(CATE_CODE,6))),0)+1,3,0)
FROM ITEM_CATECGORY
</selectKey>
INSERT INTO ITEM_CATECGORY
(CATE_CODE,CATE_NAME)
VALUES
(#{cateCode},#{cateName})
</insert>
<!-- 카테고리 상태 변경 -->
<update id="changeStatus">
UPDATE ITEM_CATECGORY
SET CATE_STATUS = #{cateStatus}
WHERE CATE_CODE = #{cateCode}
</update>
<!-- 상품등록-->
<insert id="regItem">
<selectKey resultType="String" keyProperty="itemCode" order="BEFORE">
SELECT 'ITEM_' ||LPAD(NVL(MAX(TO_NUMBER(SUBSTR(ITEM_CODE,6))),0)+1,3,0)
FROM SHOP_ITEM
</selectKey>
INSERT INTO SHOP_ITEM
(ITEM_CODE
,ITEM_NAME
,ITEM_PRICE
,ITEM_COMMENT
,ITEM_STOCK
,CATE_CODE)
VALUES
(
#{itemCode}
,#{itemName}
,#{itemPrice}
,#{itemComment}
,#{itemStock}
,#{cateCode}
)
</insert>
<!-- 회원목록조회 -->
<!--<select id="selectMemberList" resultMap="member">
SELECT
MEMBER_ID
,MEMBER_PW
,MEMBER_NAME
,MEMBER_ADDR
,ADDR_DETAIL
,MEMBER_EMAIL
,MEMBER_ROLE
,MEMBER_STATUS
FROM SHOP_MEMBER
</select> -->
</mapper>
package Kh.study.shop.admin.service;
import java.util.List;
import Kh.study.shop.item.vo.CategoryVO;
import Kh.study.shop.item.vo.ItemVO;
public interface AdminService {
//카테고리 목록조회
List<CategoryVO> cateListAll( );
List<CategoryVO> cateListUse( );
//카테고리 등록
void regCate(CategoryVO categoryVO);
//카테 상태 변경
void changeStatus(CategoryVO categoryVO);
// 상품등록
void regItem(ItemVO itemVO);
}
package Kh.study.shop.admin.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.CategoryVO;
import Kh.study.shop.item.vo.ItemVO;
@Service("adminService")
public class AdminServiceImpl implements AdminService {
@Autowired//어노테이션으로 객체생성
private SqlSessionTemplate sqlSession;
//목록조회 all
@Override
public List<CategoryVO> cateListAll( ) {
return sqlSession.selectList("adminMapper.cateListAll");
}
//목록조회 use : 사용여부가 USE 인 것만 목록조회하여 상품등록하기위하여
@Override
public List<CategoryVO> cateListUse() {
return sqlSession.selectList("adminMapper.cateListUse");
}
//카테고리 등록
@Override
public void regCate(CategoryVO categoryVO) {
sqlSession.insert("adminMapper.regCate",categoryVO);
}
//카테 상태 변경
@Override
public void changeStatus(CategoryVO categoryVO) {
sqlSession.update("adminMapper.changeStatus",categoryVO);
}
//상품등록
@Override
public void regItem(ItemVO itemVO) {
sqlSession.insert("adminMapper.regItem",itemVO);
}
}
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org"
xmlns:layout="http://www.ultra.net.nz/thymeleaf/layout"
xmlns:sec="http://www.thymeleaf.org/extras/spring-security"
layout:decorate="~{layout/admin_layout}"><!-- 물결표시와 중괄호 문법은 선택적으로 사용가능하다. -->
<link href="/css/reg_item.css" rel="stylesheet">
<div layout:fragment="content">
<!-- 전체화면 -->
<div class="row">
<!-- 좌측화면 -->
<div class="col-5">
<div class="row">
<div class="col-12 mb-3"><!-- mb : margin-bottom / ms : margin-side -->
<h6>
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-text-left" viewBox="0 0 16 16">
<path fill-rule="evenodd" d="M2 12.5a.5.5 0 0 1 .5-.5h7a.5.5 0 0 1 0 1h-7a.5.5 0 0 1-.5-.5zm0-3a.5.5 0 0 1 .5-.5h11a.5.5 0 0 1 0 1h-11a.5.5 0 0 1-.5-.5zm0-3a.5.5 0 0 1 .5-.5h7a.5.5 0 0 1 0 1h-7a.5.5 0 0 1-.5-.5zm0-3a.5.5 0 0 1 .5-.5h11a.5.5 0 0 1 0 1h-11a.5.5 0 0 1-.5-.5z"/>
</svg>
CATEGORY MANAGE
</h6>
</div>
<div class="col-12 mb-3">
<form class="row g-3" th:action="@{/admin/regCate}" method="post">
<div class="col-8">
<input name="cateName" type="text" class="form-control" id="" placeholder="상품명를 입력하세요">
</div>
<div align="center" class="col-4">
<button type="submit" class="btn btn-light">
<!-- 등록버튼 안에 이미지 들고오기 단, 버튼태그만 가능하며 인풋태그는 불가능 -->
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-cart-check" viewBox="0 0 16 16">
<path d="M11.354 6.354a.5.5 0 0 0-.708-.708L8 8.293 6.854 7.146a.5.5 0 1 0-.708.708l1.5 1.5a.5.5 0 0 0 .708 0l3-3z"/>
<path d="M.5 1a.5.5 0 0 0 0 1h1.11l.401 1.607 1.498 7.985A.5.5 0 0 0 4 12h1a2 2 0 1 0 0 4 2 2 0 0 0 0-4h7a2 2 0 1 0 0 4 2 2 0 0 0 0-4h1a.5.5 0 0 0 .491-.408l1.5-8A.5.5 0 0 0 14.5 3H2.89l-.405-1.621A.5.5 0 0 0 2 1H.5zm3.915 10L3.102 4h10.796l-1.313 7h-8.17zM6 14a1 1 0 1 1-2 0 1 1 0 0 1 2 0zm7 0a1 1 0 1 1-2 0 1 1 0 0 1 2 0z"/>
</svg>
등록
</button>
</div>
</form>
</div>
<div class="col-12 mb-3">
<table class="table table-striped table-hover text-center">
<thead>
<tr>
<th scope="col">No.</th>
<th scope="col">카테코드</th>
<th scope="col">상품명</th>
<th scope="col">사용여부</th>
</tr>
</thead>
<!-- 목록조회 테이블 -->
<tbody>
<th:block th:if="${#lists.size(cateListAll) == 0}">
<tr>
<td colspan="4">게시글 목록이 없습니다.</td>
</tr>
</th:block>
<!-- if문을 그대로 사용하면서 문자열 부정문은 맨앞에 느낌표를 사용한다! -->
<!-- <th:block th:if="${!(#lists.size(cateList) eq 0)}"> -->
<th:block th:unless="${#lists.size(cateListAll) == 0}"> <!-- 등호대신 eq 도 가능하다 -->
<th:block th:each="cateList, status : ${cateListAll}"><!-- 행번호추출하는 방법 status추가하기 -->
<tr>
<td th:text="${status.count}"></td><!-- 행번호추출 -->
<td th:text="${cateList.cateCode}" ></td>
<td th:text="${cateList.cateName}" ></td>
<td>
<!-- 라디오값을 타임리프로 데이터 넘기는 방법?? -->
<!-- 1. 라디오값을 중복이아닌 단 하나만 선택되도록하려면 name값을 동일하게 부여한다 -->
<!-- 2. 각 선택한 라디오값마다 다른 값을 부여해서 다음 페이지에 데이터를 갖고가려한다. -->
<!-- 3. 타임리프로 라디오값 넘기는 방법은 status를 사용해서 행번호를 각각 매겨준다.그래야 각각 다른 값을 갖기때문-->
<!-- 4. 각각의 사용여부의 값이 check된 값인지 확인하기위해서, 새로고침해도 진짜 본인의값인지(사용/미사용)알려면
카테리스트의 status값이 use인지 unuse인지에 따라 체크되도록 만들어 확인해볼수있다. -->
<!-- ajax 함수로 클릭시 이동할 때 변수명 가져가는 방법 -->
<!-- 함수명 괄호안에 변수명은 항상 대괄호 두개 안에 기존방식대로 넣어준다!! -->
<div class="form-check form-check-inline">
<input class="form-check-input " type="radio" th:name="|cateStatus_${status.count}|"
id="use" value="USE" th:checked="${cateList.cateStatus eq 'USE'}"
th:onclick="changeStatus([[${cateList.cateCode}]], 'USE');" >
<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="|cateStatus_${status.count}|"
id="unuse" value="UNUSE" th:checked="${cateList.cateStatus eq 'UNUSE'}"
th:onclick="changeStatus([[${cateList.cateCode}]], 'UNUSE');" >
<label class="form-check-label" for="inlineRadio2">미사용</label>
</div>
</td>
</tr>
</th:block>
</th:block>
</tbody>
</table>
</div>
</div>
</div>
<!-- 우측화면 -->
<div style="background-color: #F2F2F2;" class="col-5 ms-5">
<!-- 사용중인 카테고리만 뜨도록 구현 -->
<!-- 셀렉트박스 데이터값 넘길 때 주의할 점-->
<!-- 셀렉트 박스 내에 여러데이터값이 존재하기때문에-->
<!-- 네임값 뿐만아니라 value값을 전달해줘야 선택한 해당 값만을 들고간다-->
<!-- 그렇지 않으면, 부적합열 열111이라는 null값이 발생한다-->
<!-- <th:block th:if="${cateList.cateCode =='USE'}"> -->
<!-- th:if="${cateList.cateCode =='USE'}" -->
<div class="col-12 mb-3">
<h5>
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-text-left" viewBox="0 0 16 16">
<path fill-rule="evenodd" d="M2 12.5a.5.5 0 0 1 .5-.5h7a.5.5 0 0 1 0 1h-7a.5.5 0 0 1-.5-.5zm0-3a.5.5 0 0 1 .5-.5h11a.5.5 0 0 1 0 1h-11a.5.5 0 0 1-.5-.5zm0-3a.5.5 0 0 1 .5-.5h7a.5.5 0 0 1 0 1h-7a.5.5 0 0 1-.5-.5zm0-3a.5.5 0 0 1 .5-.5h11a.5.5 0 0 1 0 1h-11a.5.5 0 0 1-.5-.5z"/>
</svg>
Registration Item
</h5>
</div>
<form class="row g-3" th:action="@{/admin/regItem}" method="post" th:object="${itemVO}">
<div class="col-12">
<label class="form-label" for="cateCode">Category</label>
<select class="form-select" th:field="*{cateCode}">
<option th:each="cateList: ${cateListUse}" th:text="${cateList.cateName}" th:value="${cateList.cateCode}"></option>
</select>
</div>
<div class="col-12">
<label class="form-label" for="itemName">Item Name</label>
<input class="form-control" type="text" th:field="*{itemName}">
</div>
<div class="col-6">
<label class="form-label">Item Price</label>
<input class="form-control" type="text" th:field="*{itemPrice}">
</div>
<div class="col-6">
<label class="form-label">Item Stock</label>
<input class="form-control" type="number" min="1" th:field="*{itemStock}">
</div>
<div class="col-12">
<label class="form-label">Item Comment</label>
<textarea class="form-control" rows="3" style="resize: none;" th:field="*{itemComment}"></textarea>
</div>
<div align="center">
<button type="submit" class="btn btn-light mt-1" >
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-check-square-fill" viewBox="0 0 16 16">
<path d="M2 0a2 2 0 0 0-2 2v12a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V2a2 2 0 0 0-2-2H2zm10.03 4.97a.75.75 0 0 1 .011 1.05l-3.992 4.99a.75.75 0 0 1-1.08.02L4.324 8.384a.75.75 0 1 1 1.06-1.06l2.094 2.093 3.473-4.425a.75.75 0 0 1 1.08-.022z"/>
</svg>
상품등록
</button>
</div>
</form>
</div>
</div>
<!-- 반드시 해당되는 div 태그 안에 있어야 실행이 된다. -->
<script src="https://code.jquery.com/jquery-latest.min.js"></script>
<script type="text/javascript" th:src="@{/js/layout/reg_item.js}"></script>
</div>
</html>
//사용여부(USE,UNUSE)라디오 버튼 클릭 시 진행
function changeStatus(cateCode, status){
const result = confirm('상품의 상태를 변경할까요?');
if(result){
//1) ajax start
$.ajax({
url: '/admin/changeStatus', //요청경로
type: 'post',
data: {'cateStatus':status,'cateCode':cateCode}, //필요한 데이터
success: function(result) {
alert('상태를 변경했습니다');
//[셀렉트박스 목록 다시 조회]
// 사용여부를 변경하면,
// 우측화면 셀렉트박스에서도 디비저장된 부분이 연동되어 조회되어야한다.(변경 후,사용중인 카테목록들만)
// ajax안에 ajax를 사용해야한다.
// 하지만, 위의 처럼 적으면 복잡하다
// 또다시 적으면 코딩이 복잡하니 간략히 사용위해 함수 하나 만들어서 해당 함수만 사용한다.
selectCategoryListInUseAjax();
},
error: function() {
alert('실패');
}
});
//1) ajax end
}
}
/////////////////////////////////////////////////////////////////////////////////////////////
//카테고리 사용여부 변경 후 실행되는 ajax 함수
// (해당 함수가 실행되는 사용중인 카테고리 목록을 다시 조회한다.)
function selectCategoryListInUseAjax(){
//ajax start
$.ajax({
url: '/admin/selectCategoryListInUseAjax', //요청경로
type: 'post',
data: {}, //필요한 데이터
success: function(result) {
// 삭제해주고 다시 만들어야하는 셀렉트문
//<select class="form-select" th:field="*{cateCode}">
//<option th:each="cateList: ${cateListUse}" th:text="${cateList.cateName}" th:value="${cateList.cateCode}"></option>
//</select>
// 셀렉트박스안에 있는 조회문을 다시 삭제 후,
// 셀렉트박스를 빈값을 준 뒤, 다시 만들어줘야한다.
const selectBox = document.querySelector('#cateCode');
selectBox.innerHTML = '';
let str = '';
for(const cateList of result){
// 백팁으로 감싸면 모두 문자열은 문자열 변수는 변수대로 인식한다(js문법)
str += `<option value="${cateList.cateCode}">${cateList.cateName}</option>`;
}
selectBox.insertAdjacentHTML('beforeend',str);
// afterbegin : 내가 선택한 셀렉트박스가 시작한 직후에
// beforeend : 내가 선택한 셀렉트박스가 끝나기 직전에 (둘이같다)
},
error: function() {
alert('실패');
}
});
//ajax end
}
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<div th:fragment="side">
<div style="color: #367E18;" >
<ul><a th:href="@{/admin/regCate}">상품등록</a> </ul>
<ul><a th:href="@{/admin/setItem}">상품관리</a></ul>
<ul><a th:href="@{/admin/setMemberRole}">회원권한설정</a></ul>
<ul><a th:href="@{/admin/setMenu}">메뉴관리</a></ul>
</div>
</div>
</html>
package Kh.study.shop.admin.controller;
@Controller
@RequestMapping("/admin")
public class AdminController {
////////////////////////////////////////////////////
@Resource(name = "adminService")
private AdminService adminService;
@Resource(name = "memberService")
private MemberService memberService;
/////////////////////////////////////////////////////
//관리자_첫화면 :상품등록 및 상세페이지 동시
@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";
}
}
<?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="memberMapper">
<!-- 패키지명 클래스명 -->
<resultMap type="Kh.study.shop.member.vo.MemberVO" id="selectMember">
<id column="MEMBER_ID" property="memberId"/>
<result column="MEMBER_PW" property="memberPw"/>
<result column="MEMBER_NAME" property="memberName"/>
<result column="MEMBER_ADDR" property="memberAddr"/>
<result column="ADDR_DETAIL" property="addrDetail"/>
<result column="MEMBER_EMAIL" property="memberEmail"/>
<result column="MEMBER_ROLE" property="memberRole"/>
<result column="MEMBER_STATUS" property="memberStatus"/>
</resultMap>
<!-- 회원가입 -->
<!-- 기본값 있는 관리자여부 제외 모두 입력해야함
회원상태는 회원가입하면 기본적으로 활성화상태이기때문에 ACTIVE 입력-->
<!-- 시큐리티 적용시, 디비 변경하면서 권한도 회원가입시 insert해야한다. -->
<!-- Enum 파일을 사용하면서, 회원상태를 단순히 문자열이 아닌 변수로 받도록한다. -->
<insert id="join">
INSERT INTO SHOP_MEMBER
(MEMBER_ID
,MEMBER_PW
,MEMBER_NAME
,MEMBER_ADDR
,ADDR_DETAIL
,MEMBER_EMAIL
,MEMBER_STATUS
,MEMBER_ROLE)
VALUES (#{memberId}
,#{memberPw}
,#{memberName}
,#{memberAddr}
,#{addrDetail}
,#{memberEmail}
,#{memberStatus}
,#{memberRole})
</insert>
<!-- 로그인 -->
<!-- 시큐리티 적용시, pw값은 조건절 포함시키지않는다 아이디값만 !!! -->
<!-- 그리고 항상 비밀번호값도 조회를 해야 비교를하여 로그인처리가 가능하다! -->
<select id="login" resultMap="selectMember">
SELECT MEMBER_ID , MEMBER_ROLE , MEMBER_PW
FROM SHOP_MEMBER
WHERE MEMBER_ID = #{memberId}
</select>
<!-- 만약 adminMapper에서 member 매퍼를 사용하고 싶을 때는 -->
<!-- resultMap에서 [매퍼명.resultMap]의 ID값 으로 사용하면 가능하다. -->
<!-- 회원권한은 영어가 아닌 한글로 일반회원/관리자 로 나타나도록 디코드 함수 사용한다 -->
<!-- 목록조회-->
<select id="selectMemberList" resultMap="selectMember">
SELECT
MEMBER_ID
,MEMBER_NAME
,DECODE(MEMBER_ROLE,'MEMBER','일반회원','ADMIN','관리자') AS MEMBER_ROLE
FROM SHOP_MEMBER
ORDER by MEMBER_NAME
</select>
<!-- 상세조회 -->
<select id="selectMemberDetail" resultMap="selectMember">
SELECT
MEMBER_ID
,MEMBER_PW
,MEMBER_NAME
,MEMBER_ADDR
,ADDR_DETAIL
,MEMBER_EMAIL
,MEMBER_ROLE
,MEMBER_STATUS
FROM SHOP_MEMBER
WHERE MEMBER_ID = #{memberId}
</select>
</mapper>
package Kh.study.shop.member.service;
public interface MemberService {
//회원가입
void join(MemberVO memberVO);
//로그인
MemberVO login(MemberVO memberVO);
//목록조회
List<MemberVO> selectMemberList();
//상세조회
MemberVO selectMemberDetail(String memberId);
}
package Kh.study.shop.member.service;
@Service("memberService")
public class MemberServiceImpl implements MemberService {
@Autowired//어노테이션으로 객체생성
private SqlSessionTemplate sqlSession;
//join
@Override
public void join(MemberVO memberVO) {
sqlSession.insert("memberMapper.join", memberVO);
}
//login
@Override
public MemberVO login(MemberVO memberVO) {
return sqlSession.selectOne("memberMapper.login",memberVO);
}
//목록조회
@Override
public List<MemberVO> selectMemberList() {
return sqlSession.selectList("memberMapper.selectMemberList");
}
//상세조회
@Override
public MemberVO selectMemberDetail(String memberId) {
return sqlSession.selectOne("memberMapper.selectMemberDetail",memberId);
}
}
<!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">
<!-- style 은 적용시키려면 div태그 안에서 !!-->
<style>
#scrollTest {
/* 스크롤 형성 */
/* : 기본적 가로세로 모두 설정됨 */
/* overflow: scroll; */
overflow-y: scroll; /* y축만(세로) */
}
::-webkit-scrollbar {
width: 10px;
}
::-webkit-scrollbar-track {
background: #eeeeee;
border-radius: 5px;
}
::-webkit-scrollbar-thumb {
/* background: linear-gradient(#c2e59c, #64b3f4); */
background: #dcdcdc;
/* background: #0d6efd; */
border-radius: 5px;
}
</style>
<div class="row">
<!-- 좌측화면 -->
<div class="col-5">
<div class="row">
<div class="col-12 mb-3">
<h6>SET MEMBER ROLE</h6>
</div>
<div class="col-12 mb-3">
<!-- 스크롤 만들기 -->
<div id="scrollTest"
style="width: 430px; height: 400px; background-color: white;">
회원 목록
<table class="table table-striped table-hover text-center">
<colgroup>
<col width="10%">
<col width="30%">
<col width="30%">
<col width="30%">
</colgroup>
<thead>
<tr><!-- th는 글자진한 td 와 같다 -->
<th scope="col">No.</th>
<th scope="col">회원명</th>
<th scope="col">회원ID</th>
<th scope="col">권한</th>
</tr>
</thead>
<!-- 목록조회 테이블 -->
<tbody>
<th:block th:if="${#lists.size(memberList) == 0}">
<tr>
<td colspan="4">등록된 회원이 없습니다.</td>
</tr>
</th:block>
<th:block th:unless="${#lists.size(memberList) == 0}">
<th:block th:each="memberInfo , status : ${memberList}">
<tr>
<!-- 넘버 데이터 추출하는 방법 (1) -->
<!-- 위의 status를 변수선언하여 사용하는 방법 -->
<td th:text="${status.count}"></td>
<!-- 넘버 데이터 추출하는 방법 (2) 뒤에 문자만 붙여도 가능하다 -->
<!-- <td th:text="${memberInfoStat.count}"></td> -->
<td th:text="${memberInfo.memberId}"></td>
<td th:text="${memberInfo.memberName}"
th:onclick="showDetailmemberInfo([[${memberInfo.memberId}]])"></td>
<td th:text="${memberInfo.memberRole}"></td>
</tr>
</th:block>
</th:block>
</tbody>
</table>
</div>
</div>
</div>
</div>
<!-- 좌측화면 -끝- -->
<!-- 우측화면 -->
<div style="background-color: #F2F2F2;" class="col-5 ms-5">
<div class="col-12 mb-3">
<h5>Member Detail Information</h5>
</div>
<!-- <form class="row g-3" th:action="@{/admin/updateMemberRole}" method="post" th:object="${memberVO}"> -->
<div class="col-6" id="detailDiv">
<!-- <div class="row">
<div class="col"></div>
</div> -->
<!-- <div>memberId: ${result.memberId}</div>
<div>memberPw: ${result.memberPw}</div>
<div>memberName: ${result.memberName}</div>
<div>memberAddr: ${result.memberAddr}</div>
<div>addrDetail: ${result.addrDetail}</div>
<div>memberEmail: ${result.memberEmail}</div>
<div>memberRole: ${result.memberRole}</div>
<div>memberStatus: ${result.memberStatus}</div> -->
</div>
<!-- </form> -->
<!-- 우측화면 -끝- -->
</div>
</div>
<!-- 반드시 해당되는 div 태그 안에 있어야 실행이 된다. -->
<script src="https://code.jquery.com/jquery-latest.min.js"></script>
<script type="text/javascript"
th:src="@{/js/layout/set_member_role.js}"></script>
</div>
</html>
//회원목로조회에서 회원이름 클릭 시 진행
function showDetailmemberInfo(memberId) {
//학생이름 클릭하면 이벤트 발생 하여 함수 실행
//1) ajax start
$.ajax({
url: '/admin/showDetailmemberInfo', //요청경로
type: 'post',
data: { 'memberId': memberId }, //필요한 데이터
success: function(result) {
let str = ''; // 문자열 상자 만들기
str += `<div>memberId: ${result.memberId}</div>
<div>memberName: ${result.memberName}</div>
<div>memberAddr: ${result.memberAddr}</div>
<div>addrDetail: ${result.addrDetail}</div>
<div>memberEmail: ${result.memberEmail}</div>
<div>memberRole: ${result.memberRole}</div>
<div>memberStatus: ${result.memberStatus}</div>`;
const detailDiv = document.querySelector('#detailDiv');
detailDiv.innerHTML = ''; // 다른 학생이름 클릭시 다시 지워주고 넣어주기위해서 빈값만들기
detailDiv.insertAdjacentHTML('beforeend',str);
},
error: function() {
alert('실패');
}
});
//1) ajax end
}