D+66::shop_관리자페이지(계속)/Ajax사용

Am.Vinch·2022년 9월 30일
0

20220929_thu

실습내용

  • 상품등록 기능 구현
  • 단, 사용하는 상품의 경우만 카테고리 셀렉트박스에 띄우도록 한다.
    : 주의할 점, 위의 경우 좌측화면에서 사용여부를 변경시 디비에는 저장이 되지만, 우측화면의 경우는 변경사항이 반영이 안된다!
  • 등록된 카테고리들은 top파일 상단메뉴판에 나타나도록 한다.
  • 권한설정 클릭시, 좌측화면 :회원목록(no,이름,권한,회원목록)
    우측화면 :회원이름을 클릭할때마다 회원의 상세정보(모든) 페이지 구현
    -> 목록을 띄우는 것은 그냥 띄우지만, 상세정보페이지는 페이지 이동없이 해야하므로 ajax 사용한다.
  • ajax 를 이용해서 상품등록할 때 '사용'중인 카테고리 셀렉트박스 조회하려면,
    이전 사용여부버튼 클릭시 변경하는 함수가 있는 자바스크립트로 파일로 가서
    다시 셀렉트 박스를 조회하도록 작성해줘야한다.

SHOP_관리자페이지

프로젝트 파일 추가 생성

상품등록 기능 구현

Controller

  • adminController
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";
	}
	 
}

Mapper

  • admin-mapper
<?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> 

Service

  • adminService
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);
}

serviceImpl

  • adminServiceImpl
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);
	}
	
	
}

html

  • reg_item.html
<!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>

js

Ajax 사용

  • reg_item.js
//사용여부(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
}

회원권한설정 기능 구현

  • side.html
    : '회원권한설정' 클릭시, 회원권한설정 페이지로 경로설정
<!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>
  • AdminController
    : 이동한 페이지를 getMapping 어노테이션 이용하여 위와 일치하게 이동경로설정
    : 회원목록조회 쿼리를 실행하도록 만들어 컨트롤러에 가져온다.
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";
	}
	 
}
  • adminMapper,service,servicemipl
<?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> 
  • MemberService
package Kh.study.shop.member.service;

public interface MemberService {
	//회원가입
	void join(MemberVO memberVO);
	//로그인
	MemberVO login(MemberVO memberVO);
	//목록조회
	List<MemberVO> selectMemberList();
	//상세조회
	MemberVO selectMemberDetail(String memberId);
}
  • MemberServiceImpl
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);
	}

}
  • set_member_role html
    : 페이지를 좌측,우측화면으로 구성하여 그려준다.
    : 스크롤바를 적용시키려면 css는 반드시 div태그 안에 있어야한다!!!!
<!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>
  • set_member_role.js
//회원목로조회에서 회원이름 클릭 시 진행 
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

}

profile
Dev.Vinch

0개의 댓글