I T H

[포트폴리오 프로젝트 6] 관리자메뉴 - 사용자관리 페이지 구현 본문

Spring MyPortfolio Project

[포트폴리오 프로젝트 6] 관리자메뉴 - 사용자관리 페이지 구현

thdev 2024. 1. 24. 10:40
이번 챕터에서는 그리드 API를 이용하여
사용자 리스트를 조회하고 관리하는 관리자 페이지를 구현하고자 한다.
진행하기 전에 메인 페이지의 메뉴 구성을 변경해보자.
결과 화면을 먼저 확인하면 아래와 같이 로그인을 하지 않은 경우의 메뉴 구성과
관리자 계정으로 로그인한 경우의 메뉴 구성을 확인할 수 있다.

 

메뉴 구성을 동적으로 변경하여 주기 위해서 다양한 방법이 있겠지만 2가지 방법에 대해서 사용해보고자 한다. 두 방법 모두 별도의 라이브러리를 주입해주어야 사용이 가능하다

1. JSTL 태그를 이용한 세션 정보 확인을 통한 메뉴 show/hidden 처리 

<dependency>
    <groupId>javax.servlet</groupId>
    <artifactId>jstl</artifactId>
    <version>${javax.servlet.jsp.jstl-version}</version>
</dependency>

2.  스프링 시큐리티 태그를 이용한 메뉴 show/hidden 처리

<!-- taglib -->
		<dependency>
			<groupId>org.springframework.security</groupId>
			<artifactId>spring-security-taglibs</artifactId>
			<version>${org.springframework.security-version}</version>
		</dependency>

 

- Pom.xml 파일에 의존성 주입을 완료한 이후 메뉴가 선언되어 있는 src\main\webapp\resources\inc\top.jsp 파일을 편집하여 준다. 상단에 태그 사용을 위한 선언문을 작성

 

[ top.jsp ]

 메뉴 구성이 되어있는 jsp 파일을 수정한다.

<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>
<%@ taglib prefix="sec" uri="http://www.springframework.org/security/tags"%>

<header id="header">
	<div id="head" class="parallax" parallax-speed="2">
		<h1 id="logo" class="text-center">
			<img id="profileImg" class="img-circle" src="" alt="">
			<span id="profileName" class="title"></span>
			<span id="profileJob" class="tagline"></span>
			<span class="tagline"><a id="profileEmail" href=""></a></span>
		</h1>
	</div>

	<nav class="navbar navbar-default navbar-sticky">
		<div class="container-fluid">
			
			<div class="navbar-header">
				<button type="button" class="navbar-toggle" data-toggle="collapse" data-target="#bs-example-navbar-collapse-1"> <span class="sr-only">Toggle navigation</span> <span class="icon-bar"></span> <span class="icon-bar"></span> <span class="icon-bar"></span> </button>
			</div>
			
			<div class="navbar-collapse collapse">
				
				<ul class="nav navbar-nav">
					<li class="active"><a href="/">Home</a></li>
					<li><a href="about.do">About</a></li>
					<li><a href="/qna.do">Q&A</a></li>
					
				<!-- 로그인한 권한이 관리자 권한일 때만 메뉴 보여지도록 처리 -->	
					<sec:authorize access="hasAnyRole('ROLE_ADMIN')">
					<!-- 관리자권한은 /admin/** 접속이 가능하도록 설정을 하였으므로 url을 아래와 같이 /admin으로 시작하도록 설정하는 것 까먹지 말기  -->
						<li><a href="/admin/user.do">사용자관리</a></li>
						<li><a href="/admin/main.do">프로필관리</a></li>
						<li><a href="/admin/portfolio.do">포트폴리오관리</a></li>
					</sec:authorize>
					<!-- 세션 정보를 통해 userId 로그인 정보가 없을 때 -->
					<!-- 
					<c:if test="${userId == null}"> 
					<li><a href="/register.do">회원가입</a></li>
					<li><a href="/login">로그인</a></li>
					</c:if>
					-->
					<!-- 시큐리티 태그를 통해서도 위와 동일한 효과를 낼 수 있다. -->
					<sec:authorize access="isAnonymous()">
						<li><a href="/register.do">회원가입</a></li>
						<li><a href="/login">로그인</a></li>
					</sec:authorize>
					
					<sec:authorize access="isAuthenticated()">
						<li><a href="/logout">로그아웃</a></li>
					</sec:authorize>
					
					<!-- Drop down 기능 -->
					<!-- <li class="dropdown">
							<a href="#" class="dropdown-toggle" data-toggle="dropdown">More Pages <b class="caret"></b></a>
							<ul class="dropdown-menu">
								<li><a href="sidebar-left.html">Left Sidebar</a></li>
								<li><a href="sidebar-right.html">Right Sidebar</a></li>
								<li><a href="single.html">Blog Post</a></li>
							</ul>
						</li> -->
				</ul>
			
			</div><!--/.nav-collapse -->			
		</div>	
	</nav>
</header>

 

여기까지 작성하고 메인 페이지를 새로고침하여 보면 로그인하지 않은 경우, 관리자/일반 사용자로 로그인한 경우의 메뉴 구성이 다르게 보이는 것을 확인할 수 있다.

 

[ 결과화면 ]

- 로그인 하지 않은 상태의 메뉴 구성

 

- 관리자로 로그인한 경우의 메뉴 구성

[ 관리자 페이지 구현하기  사용자 관리 페이지 ]

사용자 관리 페이지에는 아래와 같은 API를 사용한다.

-    모달창(팝업) : 팝업창을 통한 사용자 정보 신규 등록 / 수정

 http://github.com/kylefox/jquery-modal 참고하여 API 예제 및 파일 다운로드

-    그리드 : 테이블 형태의 그리드 API를 통해 사용자 리스트를 조회

 https://ui.toast.com/tui-grid 참고하여 API 예제 및 파일 다운로드

 

-  관련하여 js, css 파일들을 가져와서 프로젝트 폴더 내에 붙여넣기 해야 한다.

파일이 프로젝트 내에 모두 등록된 후에 Js, css 파일을 프로젝트에 적용하기 위해 incJs.jsp / header.jsp 파일을 각각 수정하여 준다.

 

작성자는 cdn방식으로 열어서 따로 js, css파일을 만들고 이클립스 폴더안에 저장시켰다.

-  modal 팝업창 오픈시  z-index 값을 높게 주어 맨앞으로 오거나 사이즈 조절 등은 jquery.modal.css에서 조절하면서 사용하면됨. 

[ incJs.jsp ]

[ header.jsp ]

 

본격적으로 화면 UI를 작성하고 사용자 조회, 수정, 삭제 등의 CRUD 작업을 진행한다.

아래와 같이 jsp, js 파일을 하나씩 신규로 추가한다.

 

 

[ userList.jsp ] - src\main\webapp\WEB-INF\views\userList.jsp

<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html lang="kr">
<%@include file="/resources/inc/header.jsp"%>

<style>
.row{
	justify-content: center; 
	 display: flex;
	 padding: 5px;
}
.row2 {
	justify-content: center; 
	/* display: flex; 균등분할하는기능*/ 
	padding: 5px;
}
</style>
<body class="home">
<%@include file="/resources/inc/top.jsp"%>

<main id="main">
	<div class="container">
		<div class="section featured topspace">
        	<h2 class="section-title"><span>사용자 관리 페이지</span></h2>

                    <div class="row">
                        <div class="col-md-2">
                            <small>사용자 아이디</small>
                            <input type="text" class="form-control txtCondition" id="txtId" value="" placeholder="" required>
                        </div>
                        <div class="col-md-2">
                            <small>성명</small>
                            <input type="text" class="form-control txtCondition" id="txtName" value="" placeholder="" required>
                        </div>
                        <div class="col-md-2">
                            <small>권한</small>
                            <select id="cmbAuth" class="form-control">
                                <option value="">전체</option>
                                <option value="1">일반사용자</option>
                                <option value="2">관리자</option>
                            </select>
                        </div>
                        <!-- 버튼 -->
                        <div class="col-md-6" style="text-align: right;">
                            <a id="btnSearch" class="btn btn-warning">조회</a>
                            <a id="btnRemove" class="btn btn-danger">삭제</a>
                            <a id="btnSave" class="btn btn-success">추가</a>
                        </div>
                    </div>

                    <br/>

                    <p>1개 행을 더블클릭하면 사용자 정보를 수정 가능합니다.</p>

                    <!--  그리드 사용  -->
                    <!-- div 태그에 아이디를 작성하여 놓고 스크립트 파일 내에서 해당 아이디를 호출하면 그리드 정보를 세팅한다. -->
                    <div id="grid"></div>
			
		</div> <!-- / section -->
	
	</div>	<!-- /container -->

</main>

<!-- 팝업 영역 -->
<div id="ex1" class="modal" style="height:530px;">
	<p id="modalLabel">신규 사용자 등록</p>
    
    <div class="row2">
    	<div class="col-md-12">
        	<small>아이디</small>
            <input type="text" class="form-control" id="txtPopId" value="" placeholder="아이디 입력" required>
        </div>
        <div class="col-md-12">
        	<small>비밀번호</small>
            <input type="password" class="form-control" id="txtPopPwd" value="" placeholder="비밀번호 입력" required>
        </div>
       <div class="col-md-12">
      		<small>사용자 권한</small>
            <select class="form-control" id="cmbPopUserAuth">
           		<option value="1">일반사용자</option>
            	<option value="2">관리자</option>
            </select>
        </div>
        <div class="col-md-12">
			<small>사용자명</small>
			<input type="text" class="form-control popTxt" id="txtPopName" value="" placeholder="사용자명 입력">
		</div>
        <div class="col-md-12">
           	<small>전화번호</small>
            <input type="number" class="form-control popTxt" id="txtPopTel" min="0" placeholder="전화번호 입력" value="">
        </div>
        <div class="col-md-12">
           	<small>이메일</small>
            <input type="email" class="form-control popTxt" id="txtPopMail" placeholder="이메일 입력" value="">
	</div>
  </div>
	
	<hr/>
	<a id="btnSaveUser" class="btn btn-warning">저장</a>
	<a id="btnModifyUser" class="btn btn-danger" style="display: none;">수정</a>
  	<a href="#" class="btn btn-success" rel="modal:close">닫기</a>
</div>

<%@include file="/resources/inc/footer.jsp"%>
<%@include file="/resources/inc/incJs.jsp"%>

<!-- page script -->
<script src="/resources/views/userList.js"></script>

</body>
</html>

[ userList.js ] - src\main\webapp\resources\views\userList.js

- 해당 스크립트 파일에서의 특이사항은 그리드 API를 호출하여 테이블 (tr,td) 대신 그리드를 사용하여 데이터를 세팅하는 부분이다.

- 그리드를 세팅하기 위해서는 그리드 설정 정보를 담기 위한 객체변수(변수)를 스크립트 전역변수로 설정

 

-  컬럼 (columns) 정보를 쿼리에서 조회한 컬럼명과 일치시킨 후 데이터를 세팅하여 준다.

 

 

- 추가로 그리드 데이터에서 1개 행을 더블 클릭하면 이벤트가 발생하도록 처리하여 주었다.

- 팝업이 호출되어 더블 클릭한 사용자 정보를 수정할 수 있도록 하였다.

[ userList.js ]

/**
 * register.js
 * @author thevalue
 * @since 2023
 * @DESC 관리자 - 사용자 관리 화면 스크립트
 */

 (function(){
	 
	 function UserList(){
		 
		//private variables
		 var grid = null; //그리드 객체를 담기위한 변수
		 
		//초기화 메서드
		function _init(){
			//이벤트 처리 함수 호출
			bindEvent();
			
			//등록된 사용자 리스트 조회
			findUserInfo()
		}
		
		function bindEvent(){
			//조회 버튼 클릭 이벤트
			$(".txtCondition").keydown(function(key) {
				//엔터키 쳤을때 이벤트
				if (key.keyCode == 13) {
					findUserInfo();
				}
			});
			$("#btnSearch").on("click", function(){
				findUserInfo();
			});
			
			//삭제버튼 클릭 이벤트 - 체크박스에 체크한 항목의 사용자를 삭제할 수 있도록 한다.
			$("#btnRemove").on("click", function(){
				var checkedRow = grid.getCheckedRows();
				console.log(checkedRow);
				if(checkedRow.length <= 0){
					alert("삭제할 항목을 선택하시기 바랍니다.");
					return;
				}
				saveUserInfoRemove(checkedRow);
			});
			
			//추가 버튼 클릭 이벤트 - 팝업창을 오픈하여 사용자를 추가하거나 수정할 수 있도록 한다.
			$("#btnSave").on("click", function(){
				$("#modalLabel").html("신규 사용자 등록");
				$("#ex1").modal({
					clickClose: false
				});//모달(팝업) 창 오픈
				
				$("#btnModifyUser").hide();
				$("#btnSaveUser").show();
				
				$("#txtPopId").attr("readOnly", false); //편집 가능하도록
				
				// 이미 입력된 정보가 있을 수 있으므로
				// 각 항목을 초기화
				$(".popTxt").val("");
			});
			
			// 사용자 등록 버튼 클릭 이벤트
			$("#btnSaveUser").on("click", function(){
				saveUserInfo();
			})
			
			//팝업창 내에서 수정 버튼 클릭 이벤트
			$("#btnModifyUser").on("click", function(){
				saveModifyUserInfo();
			})
			
		}
		
		//등록된 사용자 리스트 조회
		function findUserInfo(){
			var obj = {
				userId: $("#txtId").val(),
				userName: $("#txtName").val(),
				userAuth: $("#cmbAuth").val()
			};
			cfFind("/admin/findUserInfo.do", obj, function(data){
				console.log("data", data);
				setGrid(data);
				
			}, true, "POST");
			
		}
		
		// 체크한 사용자 정보 삭제
		function saveUserInfoRemove(obj){
			console.log(obj);
			var result = confirm("삭제하시겠습니까?");
			if(result){
				cfSave("/admin/saveUserInfoRemove.do", obj, function(data){
					if(data.success){
						alert("사용자 정보가 삭제되었습니다.");
						findUserInfo(); //사용자 정보 재조회
					} else {
						alert("사옹자 정보 삭제 실패하였습니다. 확인 후 다시 등록하시기 바랍니다.");
					}
				}, true, "POST");
			}
		}
		
		//신규 입력한 사용자 정보 저장
		function saveUserInfo(){
			var obj = setParam();
			
			if(!obj){
				return;
			}
			
			var result = confirm("저장하시겠습니까?");
			if(result){
				var subObj = {
					userId: $("#txtPopId").val(),
					userName: "",
					userAuth: ""
				};
				cfFind("/admin/findUserInfo.do", subObj, function(subdata){
					if(subdata.length > 0){
						alert("이미 등록된 사용자 아이디 입니다.");
                        return;
					} else {
						console.log(obj);
						cfSave("/admin/saveUserInfo.do", obj, function(data){
							if(data.success){
								alert("사용자 정보가 등록되었습니다.");
								
								//각 항목 초기화
								$(".popTxt").val("");
								//modal 팝업창 닫기
								$.modal.close();
								//사용자 정보 재조회
								findUserInfo();
							} else {
								alert("사옹자 정보 등록 실패하였습니다. 확인 후 다시 등록하시기 바랍니다.");
							}
						}, true, "POST");
					}
				}, true, "POST");
			}
		}
		
		//grid setting
		function setGrid(data){
			//이미 그리드가 그려져 있으면
			if(grid != null){
				grid.destroy();//초기화하기 위해 사용
			}
			//그리드 컬럼 정보 세팅
			var columns = [{
				header: '사용자 아이디',
				name: 'USER_ID',
				align: "center",
				width: 200
			}, {
				header: '성명',
				name: 'USER_NAME',
				align: "center",
				width: 200
			}, {
				header: '권한',
				name: 'USER_AUTH_NM',
				align: "center",
				width: 200
			}, {
				header: '전화번호',
				name: 'USER_TEL',
				align: "center",
				width: 200
			}, {
				header: '이메일',
				name: 'USER_EMAIL',
				align: "center",
				width: 200
			}, {
				header: '등록일자',
				name: 'INPUT_DATETIME',
				align: "center",
				width: 200
			}];
			
			//그리드 옵션 설정 및 그리드 생성
			grid = new tui.Grid({
				el: document.getElementById('grid'),
				columns: columns,
				scrollX: true,
				scrollY: "auto",
				bodyHeight: 420,
				contextMenu: null,
				columnOptions: {
					resizable: true //컬럼 사이즈 조정
				},
				rowHeaders: ['checkbox'] //체크박스
			});
			
			grid.resetData(data);//그리드 데이터 세팅
			tui.Grid.applyTheme('striped'); //줄무늬 스타일 적용
			
			//그리드 더블클릭 이벤트
			//1개의 행을 더블클릭할 경우 수정할수 있도록 팝업이 오픈됨.
			grid.on("dblclick", function(selected){
				var rowIdx = selected.rowKey; //선택된 행의 인덱스
				var item = grid.getRow(rowIdx);
				console.log(item);
				setModifyPop(item);
			})
		} //grid 끝
		
		//수정팝업
		function setModifyPop(item){
			//클릭한 사용자 정보 팝업창에 세팅
			$("#txtPopId").val(item.USER_ID);
			$("#txtPopPwd").val("");
			$("#cmbPopUserAuth").val(item.USER_AUTH);
			$("#txtPopName").val(item.USER_NAME);
			var userTel = item.USER_TEL;
			console.log(userTel);
			//replace문자열 치환 함수
			userTel = userTel.replace("-","").replace("-","");// - 를 빈값으로 변환함
			$("#txtPopTel").val(userTel);
			$("#txtPopMail").val(item.USER_EMAIL);
			
			$("#modalLabel").html("정보 수정");
			$("#ex1").modal({
				clickClose: false
			}); //모달 팝업창 오픈
			
			$("#btnSaveUser").hide(); //저장 버튼은 숨김
			$("#btnModifyUser").show(); //수정 버튼은 노출
			$("#txtPopId").attr("readOnly", true); //사용자 아이디는 p.k이므로 수정금지
			
		}
		
		//수정 팝업창에서 수정버튼 클릭시 입력한 정보도 데이터 업데이트
		function saveModifyUserInfo(){
			var obj = setParam();
			if(!obj){
				return;
			}
			var result = confirm("사용자 정보를 수정하시겠습니까?");
			if(result){
				console.log(obj);
				cfSave("/admin/saveModifyUserInfo.do", obj, function(data){
					if(data.success){
						alert("사용자 정보가 수정되었습니다.");
						
						//각 항목 초기화
						$(".popTxt").val("");
						//modal 팝업창 닫기
						$.modal.close();
						//사용자 정보 재조회
						findUserInfo();
					} else {
						alert("사옹자 정보 수정 실패하였습니다. 확인 후 다시 등록하시기 바랍니다.");
					}
				}, true, "POST");
			}
		}
		
		//저장 시 사용될 파라미터 정보를 세팅
		function setParam(){
			var userId = $("#txtPopId").val();
			var userPwd = $("#txtPopPwd").val();
			var userAuth = $("#cmbPopUserAuth").val();
			var userName = $("#txtPopName").val();
			var userTel = $("#txtPopTel").val();
			var userEmail = $("#txtPopMail").val();
		
		
			if(userId == null || userId == ""){
				alert("사용자 아이디를 입력하시기 바랍니다.");
				return false;
			}
			
			var obj = {
				userId: userId,
				userPwd: userPwd,
				userAuth: userAuth,
				userName: userName,
				userTel: userTel,
				userEmail: userEmail
			}
			return obj;
		}
		
		
		function _finalize() {
		}

		
		return {
			init: _init,
			finalize: _finalize
		} 
	 }
	
	 
	 
	 var userList = new UserList();
	 userList.init();
	 
 })();

 

다음으로는 앞서 여러 번 연습했던 CRUD 작업을 진행한다.

팝업창에서 사용자의 비밀번호를 입력하지 않은 경우와 입력한 경우를 구분하기 위한 로직 외에는 특별히 특이사항이 없으므로 코드 정보만 나열한다.

 

- 사용자 정보 수정 팝업에서 사용자의 비밀번호를 입력한 경우 : 비밀번호까지 업데이트 되도록 처리

- 사용자 정보 수정 팝업에서 사용자의 비밀번호를 입력하지 않은 경우 : 비밀번호는 기존 비밀번호 그대로 유지시키기 위해 업데이트 하지 않고 나머지 컬럼 정보만 업데이트하도록 처리

[ 컨트롤러 추가 ]

package kr.co.values.user.web;

import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;

import kr.co.values.user.persistence.UserListMapper;
import kr.co.values.user.service.UserListService;

@Controller
public class UserListController {
	
	@Autowired
	private UserListService userListService;

	@Autowired
	private UserListMapper userListMapper;
	
    @RequestMapping("/admin/user.do")
    public String main() {
    	
        return "userList";
    }
    
    //등록된 사용자 리스트 조회
    @RequestMapping("/admin/findUserInfo.do")
    @ResponseBody
    public List<Map<String, Object>> findUserInfo(@RequestBody Map<String, Object> param){
    	
    	List<Map<String, Object>> list = userListMapper.findUserInfo(param);
    	return list;
    }
    
    //등록된 사용자 삭제
    @RequestMapping("/admin/saveUserInfoRemove.do")
    @ResponseBody
    public Map<String, Object> saveUserInfoRemove(@RequestBody List<Map<String, Object>> param){
    	
    	userListService.saveUserInfoRemove(param);
    	Map<String, Object> result = new HashMap<String, Object>();
    	result.put("success", true);
    			
    	return result;
    }
    
 
	//신규 사용자 등록
    @RequestMapping("/admin/saveUserInfo.do")
    @ResponseBody
    public Map<String, Object> saveUserInfo(@RequestBody Map<String, Object> param){
    	
    	userListService.saveUserInfo(param);
    	
    	Map<String, Object> result = new HashMap<String, Object>();
    	result.put("success", true);
    			
    	return result;
    }
    

   //사용자 정보 수정
   @RequestMapping("/admin/saveModifyUserInfo.do")
   @ResponseBody
   public Map<String, Object> saveModifyUserInfo(@RequestBody Map<String, Object> param){
   	
   	userListService.saveModifyUserInfo(param);
   	
   	Map<String, Object> result = new HashMap<String, Object>();
   	result.put("success", true);
   			
   	return result;
   }

}

[ 서비스 추가 

package kr.co.values.user.service;

import java.util.List;
import java.util.Map;

public interface UserListService {
	//등록된 사용자 정보 삭제
	void saveUserInfoRemove(List<Map<String, Object>> list);
	
	//신규 사용자 등록 saveUserInfo
	void saveUserInfo(Map<String, Object> map);
	
	//사용자 정보 수정
	void saveModifyUserInfo(Map<String, Object> map);
}
package kr.co.values.user.service;

import java.util.List;
import java.util.Map;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;

import kr.co.values.user.persistence.UserListMapper;

@Service
public class UserListServiceImpl implements UserListService {
	
	@Autowired
	private UserListMapper userListMapper;
	
	@Autowired
	private PasswordEncoder passwordEncoder;

	@Override
	public void saveUserInfoRemove(List<Map<String, Object>> list) {
		
		//체크한 항목이 여러개일 수 있으므로
		//리스트로 전달받고 for문 돌려서 1개씩 삭제
		for(Map<String, Object> map : list) {
			userListMapper.saveUserInfoRemove(map);
		}
	}

	@Override
	public void saveUserInfo(Map<String, Object> map) {
		
		String orgPassword = (String) map.get("userPwd");
		String userId = (String) map.get("userId");
		System.out.println("orgPassword: " + orgPassword);
		String encPassword = initUserPassword(orgPassword, userId);
		map.put("userPwd", encPassword);
		userListMapper.saveUserInfo(map);
	}

	@Override
	public void saveModifyUserInfo(Map<String, Object> map) {
		
		String orgPassword = (String) map.get("userPwd");
		String userId = (String) map.get("userId");
		
		if("".equals(orgPassword)) {
		//수정된 팝업에서 비밀번호를 입력하지 않은 경우에는 업데이트 되지 않도록 공백을 보내줌
			map.put("userPwd", orgPassword);
		} else {
		//비밀번호를 입력한 경우에는 암호화된 비밀번호로 map에 재세팅해서 보내줌
			
			String encPassword = initUserPassword(orgPassword, userId);
			map.put("userPwd", encPassword);
		}
		userListMapper.saveModifyUserInfo(map);		
	}

	private String initUserPassword(String orgPassword, String userId) {
        return passwordEncoder.encode(orgPassword);//비밀번호 암호화 된것을 리턴
    }
	
}

[ 매퍼 추가 ]

package kr.co.values.user.persistence;

import java.util.List;
import java.util.Map;

public interface UserListMapper {
	//등록된 사용자 리스트 조회
	List<Map<String, Object>> findUserInfo(Map<String, Object> map);
	
	//사용자 정보 삭제
	void saveUserInfoRemove(Map<String, Object> map);
	
	//사용자 정보 등록
	void saveUserInfo(Map<String, Object> map);
	
	//사용자 정보 수정
	void saveModifyUserInfo(Map<String, Object> map);
}
<?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="kr.co.values.user.persistence.UserListMapper">

	<select id="findUserInfo" resultType="hashmap" parameterType="hashmap">
		SELECT USER_ID
			, USER_PWD
			, USER_NAME
			, USER_AUTH
			, CASE WHEN USER_AUTH = '1' THEN '일반 사용자' ELSE '관리자' END AS USER_AUTH_NM
			, CONCAT(SUBSTR(USER_TEL, 1, 3), '-', SUBSTR(USER_TEL, 4, 4), '-', SUBSTR(USER_TEL, 8, 4)) AS USER_TEL
			, USER_EMAIL
			, DATE_FORMAT(INPUT_DATETIME, '%Y-%m-%d %T') INPUT_DATETIME
		FROM MYPORTFOLIO.TBL_USER_INFO
		WHERE 1=1
		<if test="!''.equals(userId)">
			AND USER_ID LIKE CONCAT('%', #{userId}, '%')
		</if>
		<if test="!''.equals(userName)">
			AND USER_NAME LIKE CONCAT('%', #{userName}, '%')
		</if>
		<if test="!''.equals(userAuth)">
			AND USER_AUTH = #{userAuth}
		</if>
	</select>
	
	<delete id="saveUserInfoRemove" parameterType="hashmap">
		DELETE FROM MYPORTFOLIO.TBL_USER_INFO
		WHERE 1=1
		AND USER_ID = #{USER_ID}
	</delete>
	
	<insert id="saveUserInfo" parameterType="hashmap">
		INSERT INTO MYPORTFOLIO.TBL_USER_INFO (
			USER_ID
			, USER_PWD
			, USER_NAME
			, USER_TEL
			, USER_EMAIL
			, USER_AUTH
			, INPUT_DATETIME
		) VALUES (
			#{userId},
			#{userPwd},
			#{userName},
			#{userTel},
			#{userEmail},
			#{userAuth},
			NOW()
		)
	</insert>
	
	<update id="saveModifyUserInfo" parameterType="hashmap">
		UPDATE MYPORTFOLIO.TBL_USER_INFO
		SET USER_NAME = #{userName}
			, USER_TEL = #{userTel}
			, USER_EMAIL = #{userEmail}
			, USER_AUTH = #{userAuth}
			<if test="!''.equals(userPwd)">
			, USER_PWD = #{userPwd}			
			</if>
		WHERE 1=1
		AND USER_ID = #{userId}
	</update>
	
</mapper>