hmkim 03-24
250324 김혜민 mber 리팩토링 및 중복로그인 레디스 추가
@501ce4b23c365392658799faae109b8967850f66
build.gradle
--- build.gradle
+++ build.gradle
@@ -35,7 +35,7 @@
     implementation 'org.springframework.boot:spring-boot-starter-validation'
     implementation 'org.springframework.boot:spring-boot-starter-security'
     implementation 'org.springframework.boot:spring-boot-starter-web-services'
-//    implementation 'org.springframework.boot:spring-boot-devtools'
+    implementation 'org.springframework.boot:spring-boot-starter-data-redis'
     implementation 'org.springframework.boot:spring-boot-starter-cache'
 
     implementation ('org.egovframe.rte:org.egovframe.rte.ptl.mvc:4.2.0'){
 
build/resources/main/mybatis/mapper-ora/ums/ums-SQL.xml (deleted)
--- build/resources/main/mybatis/mapper-ora/ums/ums-SQL.xml
@@ -1,29 +0,0 @@
-<?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="com.takensoft.ums.dao.UmsDAO">
-    <insert id="save" parameterType="UmsVO">
-        INSERT INTO CUSTOMER_SMS_SEND (
-                                       USER_ID
-                                      , SCHEDULE_TYPE
-                                      , TITLE
-                                      ,MSG_CONTENT
-                                      , CALLING_NUM
-                                      ,PHONE_NUM
-                                      , RESERV_DTTM
-                                      , REG_DTTM
-        ) VALUES (
-                     #{userId},
-                     #{scheduleType},
-                     #{title},
-                     #{msgContent},
-                     #{callingNum},
-                     #{phoneNum},
-                     NULL,
-                     TO_CHAR(SYSDATE, 'YYYYMMDDHH24MISS')
-                 )
-    </insert>
-
-    <select id="findAll" resultType="UmsVO">
-        SELECT * FROM CUSTOMER_SMS_SEND
-    </select>
-</mapper>(파일 끝에 줄바꿈 문자 없음)
src/main/java/com/takensoft/cms/accesCtrl/service/Impl/SystemAccesCtrlServiceImpl.java
--- src/main/java/com/takensoft/cms/accesCtrl/service/Impl/SystemAccesCtrlServiceImpl.java
+++ src/main/java/com/takensoft/cms/accesCtrl/service/Impl/SystemAccesCtrlServiceImpl.java
@@ -3,7 +3,7 @@
 import com.takensoft.cms.accesCtrl.service.AccesCtrlService;
 import com.takensoft.cms.accesCtrl.service.SystemAccesCtrlService;
 import com.takensoft.cms.accesCtrl.vo.AccesCtrlVO;
-import com.takensoft.common.util.CommonUtils;
+import com.takensoft.common.util.HttpRequestUtil;
 import lombok.RequiredArgsConstructor;
 import org.egovframe.rte.fdl.cmmn.EgovAbstractServiceImpl;
 import org.springframework.dao.DataAccessException;
@@ -12,7 +12,6 @@
 
 import jakarta.servlet.http.HttpServletRequest;
 
-import java.net.UnknownHostException;
 import java.util.List;
 import java.util.Map;
 
@@ -35,7 +34,7 @@
 @RequiredArgsConstructor
 public class SystemAccesCtrlServiceImpl extends EgovAbstractServiceImpl implements SystemAccesCtrlService {
 
-    private final CommonUtils commonUtils;
+    private final HttpRequestUtil httpRequestUtil;
     private final AccesCtrlService accesCtrlService;
 
     /**
@@ -43,7 +42,6 @@
      * @param req : HTTP 요청 객체
      * @return boolean : 접근 여부
      * @throws DataAccessException : db 관련 예외 발생 시
-     * @throws UnknownHostException : 아이피 정보 조회 실패 시
      * @throws Exception : 그 외 예외 발생 시
      *
      * 접근 제어 조회(시스템용 - 라우터)
@@ -51,7 +49,7 @@
     @Override
     public boolean routerAccesCheck(Map params, HttpServletRequest req) {
         try {
-            String ipAdrs = commonUtils.getIp(req); // 아이피 정보
+            String ipAdrs = httpRequestUtil.getIp(req); // 아이피 정보
             String path = params.get("path").toString(); // 접근 경로
             // 공통 접근 경로인 경우
             if (isPath(path, "/cmmn/**")) {
@@ -79,8 +77,6 @@
             return matches(list, path);
         } catch (DataAccessException dae) {
             throw dae;
-        } catch (UnknownHostException ukhe) {
-            throw new RuntimeException("호스트의 IP정보를 알 수가 없습니다.", ukhe);
         } catch (Exception e) {
             throw e;
         }
src/main/java/com/takensoft/cms/accesCtrl/web/SystemAccesCtrlController.java
--- src/main/java/com/takensoft/cms/accesCtrl/web/SystemAccesCtrlController.java
+++ src/main/java/com/takensoft/cms/accesCtrl/web/SystemAccesCtrlController.java
@@ -49,7 +49,7 @@
      * 접근 제어 관련 사용자 확인
      */
     @PostMapping(value = "/accessCheck.json")
-    public ResponseEntity<?> accessCheck(@RequestBody Map params, HttpServletRequest req) throws Exception {
+    public ResponseEntity<?> accessCheck(@RequestBody Map params, HttpServletRequest req) {
         boolean result = systemAccesCtrlService.routerAccesCheck(params, req);
 
         // 응답 처리
src/main/java/com/takensoft/cms/bbs/web/BbsCnController.java
--- src/main/java/com/takensoft/cms/bbs/web/BbsCnController.java
+++ src/main/java/com/takensoft/cms/bbs/web/BbsCnController.java
@@ -64,7 +64,7 @@
      * 게시판 내용 등록
      */
     @PostMapping(path = "/saveBbsCn.file")
-    public ResponseEntity<?> saveBbsCn(@RequestPart BbsCnVO bbsCn, List<MultipartFile> multipartFileList, List<MultipartFile> multipartImgList) throws Exception {
+    public ResponseEntity<?> saveBbsCn(@RequestPart BbsCnVO bbsCn, List<MultipartFile> multipartFileList, List<MultipartFile> multipartImgList){
         // 게시판 내용 등록
         HashMap<String, Object> result = bbsCnService.saveBbsCn(bbsCn, multipartFileList, multipartImgList);
         return resUtil.successRes(result, MessageCode.COMMON_SUCCESS);
@@ -77,7 +77,7 @@
      * 게시판 내용 목록 조회
      */
     @PostMapping("/findAll.json")
-    public ResponseEntity<?> findAll(@RequestBody HashMap<String, String> params) throws Exception {
+    public ResponseEntity<?> findAll(@RequestBody HashMap<String, String> params) {
         // 게시판 내용 목록 조회
         Map<String, Object> result = bbsCnService.findAllBbsCn(params);
         return resUtil.successRes(result, MessageCode.COMMON_SUCCESS);
@@ -90,7 +90,7 @@
      * 게시판 내용 상세 조회
      */
     @PostMapping("/findByBbsCn.json")
-    public ResponseEntity<?> findByBbsCn(@RequestBody BbsCnVO bbsCnVO) throws Exception {
+    public ResponseEntity<?> findByBbsCn(@RequestBody BbsCnVO bbsCnVO) {
         // 게시판 관리 정보 조회
         BbsMngVO bbsMng = bbsMngService.findByBbsMngId(bbsCnVO.getBbsMngId());
         // 게시판 내용 상세 조회
@@ -129,7 +129,7 @@
      * 게시판 내용 수정
      */
     @PostMapping(path = "/updateBbsCn.file")
-    public ResponseEntity<?> updateBbsCn(@RequestPart HashMap<String, Object> params, @RequestPart List<HashMap<String, Object>> deleteFileList, List<MultipartFile> multipartFileList, @RequestPart List<HashMap<String, Object>> deleteImgFileList, List<MultipartFile> multipartImgList) throws Exception {
+    public ResponseEntity<?> updateBbsCn(@RequestPart HashMap<String, Object> params, @RequestPart List<HashMap<String, Object>> deleteFileList, List<MultipartFile> multipartFileList, @RequestPart List<HashMap<String, Object>> deleteImgFileList, List<MultipartFile> multipartImgList){
         // 게시판 내용 수정
         HashMap<String, Object> result = bbsCnService.updateBbsCn(params, deleteFileList, multipartFileList, deleteImgFileList, multipartImgList);
         return resUtil.successRes(result, MessageCode.COMMON_SUCCESS);
src/main/java/com/takensoft/cms/mber/Schedule/RefreshScheduler.java
--- src/main/java/com/takensoft/cms/mber/Schedule/RefreshScheduler.java
+++ src/main/java/com/takensoft/cms/mber/Schedule/RefreshScheduler.java
@@ -1,13 +1,17 @@
 package com.takensoft.cms.mber.Schedule;
 
 import com.takensoft.cms.mber.dao.RefreshTokenDAO;
+import com.takensoft.common.exception.CustomUpdateFailException;
+import org.springframework.dao.DataAccessException;
 import org.springframework.scheduling.annotation.Scheduled;
 import org.springframework.stereotype.Component;
 import org.springframework.transaction.annotation.Transactional;
-
 /**
  * @author  : takensoft
  * @since   : 2024.04.01
+ * @modification
+ *     since    |    author    | description
+ *  2024.04.01  |  takensoft   | 최초 등록
  *
  * RefreshToken 만료 기한이 된 token 제거를 위한 스케쥴러
  */
@@ -15,14 +19,11 @@
 public class RefreshScheduler {
 
     private final RefreshTokenDAO refreshTokenDAO;
-
     public RefreshScheduler(RefreshTokenDAO refreshTokenDAO) {
         this.refreshTokenDAO = refreshTokenDAO;
     }
 
     /**
-     * @author takensoft
-     * @since 2024.04.05
      * refresh token 삭제 스케쥴러
      * 매일 자정에 만료 기한이 지난 refresh token 삭제
      */
src/main/java/com/takensoft/cms/mber/dao/AdmMbrDAO.java
--- src/main/java/com/takensoft/cms/mber/dao/AdmMbrDAO.java
+++ src/main/java/com/takensoft/cms/mber/dao/AdmMbrDAO.java
@@ -9,84 +9,87 @@
 
 import java.util.HashMap;
 import java.util.List;
-
 /**
- * @author  : 박정하
- * @since   : 2024.06.21
+ * @author 박정하
+ * @since 2024.06.21
+ * @modification
+ *     since    |    author    | description
+ *  2024.06.21  |    박정하     | 최초 등록
  *
  * 회원정보 관련 Mapper
  */
 @Mapper("admMbrDAO")
 public interface AdmMbrDAO {
-    /**
-     * @author  : 박정하
-     * @since   : 2024.06.21
-     *
-     * 회원정보 목록 갯수
-     */
-    public int mbrListCnt(Pagination pagination) throws Exception;
 
     /**
-     * @author  : 박정하
-     * @since   : 2024.06.21
+     * @param pagination - 페이징 정보
+     * @return int - 회원정보 목록 갯수 결과
+     *
+     * 회원정보 목록 갯수 조회
+     */
+    public int mbrListCnt(Pagination pagination);
+
+    /**
+     * @param pagination - 페이징 정보
+     * @return List<AdmMbrDTO> - 회원정보 관련 목록 조회 결과
      *
      * 회원정보 목록 조회
      */
-    public List<AdmMbrDTO> mbrList(Pagination pagination) throws Exception;
+    public List<AdmMbrDTO> mbrList(Pagination pagination);
 
     /**
-     * @author  : 박정하
-     * @since   : 2024.06.21
+     * @param mbrId - 회원 아이디
+     * @return AdmMbrDTO - 회원정보 상세 조회 결과
      *
      * 회원정보 상세 조회
      */
-    public AdmMbrDTO mbrDetail(String mbrId) throws Exception;
+    public AdmMbrDTO mbrDetail(String mbrId);
 
     /**
-     * @author  : 박정하
-     * @since   : 2024.06.21
+     * @param admMbrDTO - 회원정보 관련 DTO
+     * @return int - 회원정보 수정 결과
      *
      * 회원정보 수정
      */
-    public int updateMbr(AdmMbrDTO admMbrDTO) throws Exception;
+    public int updateMbr(AdmMbrDTO admMbrDTO);
 
     /**
-     * @author  : 박정하
-     * @since   : 2024.06.21
+     * @param mbrId - 회원 아이디
+     * @return int - 회원정보 권한 목록 삭제 결과
      *
      * 회원정보 권한 목록 삭제 (mbrId 사용)
      */
-    public int deleteAuthorListByMbrId(String mbrId) throws Exception;
+    public int deleteAuthorListByMbrId(String mbrId);
 
     /**
-     * @author  : 박정하
-     * @since   : 2024.06.21
+     * @param mberAuthorVO - 사용자 권한 관련 VO
+     * @return int - 회원 권한 목록 삭제 결과
      *
      * 회원 권한 목록 삭제 (mbrId 사용)
      */
-    public int insertAuthor(MberAuthorVO mberAuthorVO) throws Exception;
+    public int insertAuthor(MberAuthorVO mberAuthorVO);
 
     /**
-     * @author  : 박정하
-     * @since   : 2024.06.21
+     * @param joinDTO - 회원 가입 관련 DTO
+     * @return int - 회원정보 등록 결과
      *
      * 회원정보 등록
      */
-    public int mbrInsert(JoinDTO joinDTO) throws Exception;
+    public int mbrInsert(JoinDTO joinDTO);
 
     /**
-     * @author  : 박정하
-     * @since   : 2024.07.03
+     * @param mbrVO - 회원 정보 관련 VO
+     * @return String - 로그인 아이디
      *
      * 아이디 찾기 (로그인 아이디)
      */
-    public String lgnIdSearch(MberVO mbrVO) throws Exception;
+    public String lgnIdSearch(MberVO mbrVO);
 
     /**
-     * @author  : 박정하
-     * @since   : 2024.07.03
+     * @param admMbrDTO - 회원정보 관련 DTO
+     * @return String - 회원 아이디
      *
-     * 아이디 찾기 (멤버 아이디)
+     * 아이디 찾기 (회원 아이디)
      */
-    public String mbrIdSearch(AdmMbrDTO admMbrDTO) throws Exception;
+    public String mbrIdSearch(AdmMbrDTO admMbrDTO);
 }
(파일 끝에 줄바꿈 문자 없음)
src/main/java/com/takensoft/cms/mber/dao/LgnHstryDAO.java
--- src/main/java/com/takensoft/cms/mber/dao/LgnHstryDAO.java
+++ src/main/java/com/takensoft/cms/mber/dao/LgnHstryDAO.java
@@ -8,33 +8,37 @@
 import java.util.List;
 
 /**
- * @author  : takensoft
- * @since   : 2024.04.09
+ * @author takensoft
+ * @since 2024.04.09
+ * @modification
+ *     since    |    author    | description
+ *  2024.04.09  |  takensoft   | 최초 등록
  *
  * 로그인 이력 관련 Mapper
  */
 @Mapper("lgnHstryDAO")
 public interface LgnHstryDAO {
     /**
-     * @author takensoft
-     * @since 2024.04.09
+     * @param lgnHstryVO - 로그인 이력 정보 관련 VO
+     * @return int - 로그인 이력 등록 결과
+     *
      * 로그인 이력 등록
      */
     int save(LgnHstryVO lgnHstryVO);
 
     /**
-     * @author  : 박정하
-     * @since   : 2024.05.13
+     * @param pagination - 페이징 정보
+     * @return int - 로그인 이력 등록 결과
      *
-     * 로그인 이력 목록 갯수
+     * 로그인 이력 등록
      */
-    public int selectLgnHstryListCnt(Pagination pagination) throws Exception;
+    public int selectLgnHstryListCnt(Pagination pagination);
 
     /**
-     * @author  : 박정하
-     * @since   : 2024.05.13
+     * @param pagination - 페이징 정보
+     * @return List<LgnHstryVO> - 로그인 이력 목록 조회 결과
      *
      * 로그인 이력 목록 조회
      */
-    public List<LgnHstryVO> selectLgnHstryList(Pagination pagination) throws Exception;
+    public List<LgnHstryVO> selectLgnHstryList(Pagination pagination);
 }
(파일 끝에 줄바꿈 문자 없음)
src/main/java/com/takensoft/cms/mber/dao/MberDAO.java
--- src/main/java/com/takensoft/cms/mber/dao/MberDAO.java
+++ src/main/java/com/takensoft/cms/mber/dao/MberDAO.java
@@ -8,53 +8,61 @@
 import org.egovframe.rte.psl.dataaccess.mapper.Mapper;
 
 import java.util.*;
-
 /**
- * @author  : takensoft
- * @since   : 2024.04.01
+ * @author takensoft
+ * @since 2024.04.01
+ * @modification
+ *     since    |    author    | description
+ *  2024.04.01  |  takensoft   | 최초 등록
  *
  * 회원 정보 관련 Mapper
  */
 @Mapper("mberDAO")
 public interface MberDAO {
     /**
-     * @author takensoft
-     * @since 2024.04.03
+     * @param lgnId - 로그인 아이디
+     * @return MberVO - 사용자 정보 조회 결과
+     *
      * 사용자 정보 조회 [security 용]
      */
     MberVO findByMberSecurity(String lgnId);
 
     /**
-     * @author takensoft
-     * @since 2024.04.03
+     * @param lgnId - 로그인 아이디
+     * @return boolean - 아이디 중복 여부
+     *
      * 아이디 중복 검사
      */
     boolean findByCheckLoginId(String lgnId);
 
     /**
-     * @author takensoft
-     * @since 2024.04.03
+     * @param joinDTO - 회원 가입 관련 DTO
+     * @return int - 회원가입 결과
+     *
      * 회원가입
      */
     int save(JoinDTO joinDTO);
 
     /**
-     * @author takensoft
-     * @since 2024.04.03
+     * @param mberAuthorVO - 사용자 권한 관련 VO
+     * @return int - 사용자 권한 등록 결과
+     *
      * 사용자 권한 등록
      */
     int authorSave(MberAuthorVO mberAuthorVO);
 
     /**
-     * @author takensoft
-     * @since 2024.04.15
+     * @param passwordDTO -비밀 번호 변경 관련 DTO
+     * @return int - 비밀 번호 변경 결과
+     *
      * 비밀 번호 변경
      */
     int updatePassword(PasswordDTO passwordDTO);
 
     /**
-     * @author takensoft
-     * @since 2024.04.15
+     * @param mbrId -회원 아이디
+     * @return MberVO - 사용자 정보 조회 결과
+     *
      * 사용자 정보 조회
      */
     MberVO findByMber(String mbrId);
src/main/java/com/takensoft/cms/mber/dao/RefreshTokenDAO.java
--- src/main/java/com/takensoft/cms/mber/dao/RefreshTokenDAO.java
+++ src/main/java/com/takensoft/cms/mber/dao/RefreshTokenDAO.java
@@ -6,37 +6,44 @@
 /**
  * @author  : takensoft
  * @since   : 2024.04.01
+ * @modification
+ *     since    |    author    | description
+ *  2024.04.01  |  takensoft   | 최초 등록
  *
  * RefreshToken 관련 Mapper
+ *
  */
 @Mapper("refreshTokenDAO")
 public interface RefreshTokenDAO {
 
     /**
-     * @author takensoft
-     * @since 2024.04.04
+     * @param refreshVO - RefreshToken 정보 관련 VO
+     * @return int - refresh token 등록 결과
+     *
      * refresh token 등록
      */
     int save(RefreshVO refreshVO);
 
     /**
-     * @author takensoft
-     * @since 2024.04.04
+     * @param refreshVO - RefreshToken 정보 관련 VO
+     * @return int - refresh token 삭제 결과
+     *
      * refresh token 삭제
      */
     int deleteByRefresh(RefreshVO refreshVO);
 
     /**
-     * @author takensoft
-     * @since 2024.04.04
+     * @return int - 기한 만료된 refresh token 삭제 결과
+     *
      * 기한 만료된 refresh token 삭제 [ Schedule 용 ]
      */
     int cleanExpiredRefreshTokens();
 
     /**
-     * @author takensoft
-     * @since 2024.04.17
-     * refresh token 등록 유무 확인
+     * @param refreshVO - RefreshToken 정보 관련 VO
+     * @return boolean - refresh token 등록 여부
+     *
+     * refresh token 등록 여부 확인
      */
     boolean findByCheckRefresh(RefreshVO refreshVO);
 }
src/main/java/com/takensoft/cms/mber/dto/AdmMbrDTO.java
--- src/main/java/com/takensoft/cms/mber/dto/AdmMbrDTO.java
+++ src/main/java/com/takensoft/cms/mber/dto/AdmMbrDTO.java
@@ -5,10 +5,12 @@
 
 import java.util.ArrayList;
 import java.util.List;
-
 /**
  * @author  : 박정하
  * @since   : 2024.06.21
+ * @modification
+ *     since    |    author    | description
+ *  2024.06.21  |    박정하     | 코드 리펙토링
  *
  * 회원정보 관련 DTO
  */
@@ -19,119 +21,33 @@
 @Builder
 @ToString
 public class AdmMbrDTO {
-    /**
-     * 회원 아이디
-     */
-    private String mbrId;
-    /**
-     * 로그인 아이디
-     */
-    private String lgnId;
-    /**
-     * 회원 이름
-     */
-    private String mbrNm;
-    /**
-     * 닉네임
-     */
-    private String ncnm;
-    /**
-     * 비밀번호
-     */
-    private String pswd;
-    /**
-     * 휴대폰번호
-     */
-    private String mblTelno;
-    /**
-     * 전화번호
-     */
-    private String telno;
-    /**
-     * 이메일
-     */
-    private String eml;
-    /**
-     * 우편번호
-     */
-    private String zip;
-    /**
-     * 주소
-     */
-    private String addr;
-    /**
-     * 상세주소
-     */
-    private String daddr;
-    /**
-     * 회원상태
-     * 0: 탈퇴, 1: 승인, 2: 승인대기, 3: 차단
-     */
-    private String mbrStts;
-    /**
-     * 사용여부
-     */
-    private String useYn;
-    /**
-     * 차단일
-     */
-    private String cntrlDt;
-    /**
-     * 차단사유
-     */
-    private String cntrlRsn;
-    /**
-     * 문자수신여부
-     * 0: 거부, 1: 허용
-     */
-    private String smsRcptnAgreYn;
-    /**
-     * 이메일수신여부
-     * 0: 거부, 1: 허용
-     */
-    private String emlRcptnAgreYn;
-    /**
-     * 개인정보공개여부
-     * 0: 거부, 1: 허용
-     */
-    private String prvcRlsYn;
-    /**
-     * 회원형태
-     * S: 시스템, K: 카카오, N: 네이버, G: 구글, F: 페이스북
-     */
-    private String mbrType;
-    /**
-     * 비밀번호 변경일
-     */
-    private String pswdChgDt;
-    /**
-     * 최초등록 아이디
-     */
-    private String frstRegIp;
-    /**
-     * 시스템 제공 여부 -> 시스템에서 제공되는 데이터는 사용자가 제거하지 못하도록 하기 위한 설정값
-     * 0: 시스템, 1: 사용자
-     */
-    private String sysPvsnYn;
-    /**
-     * 등록자
-     */
-    private String rgtr;
-    /**
-     * 등록일
-     */
-    private String regDt;
-    /**
-     * 수정자
-     */
-    private String mdfr;
-    /**
-     * 수정일
-     */
-    private String mdfcnDt;
-    /**
-     * 권한 정보
-     */
+
+    private String mbrId;           // 회원 아이디
+    private String lgnId;           // 로그인 아이디
+    private String mbrNm;           // 회원 이름
+    private String ncnm;            // 닉네임
+    private String pswd;            // 비밀번호
+    private String mblTelno;        // 휴대폰번호
+    private String telno;           // 전화번호
+    private String eml;             // 이메일
+    private String zip;             // 우편번호
+    private String addr;            // 주소
+    private String daddr;           // 상세주소
+    private String mbrStts;         // 회원상태 0: 탈퇴, 1: 승인, 2: 승인대기, 3: 차단
+    private String useYn;           // 사용여부
+    private String cntrlDt;         // 차단일
+    private String cntrlRsn;        // 차단사유
+    private String smsRcptnAgreYn;  // 문자수신여부  0: 거부, 1: 허용
+    private String emlRcptnAgreYn;  // 이메일수신여부 0: 거부, 1: 허용
+    private String prvcRlsYn;       // 개인정보공개여부 0: 거부, 1: 허용
+    private String mbrType;         // 회원형태 S: 시스템, K: 카카오, N: 네이버, G: 구글, F: 페이스북
+    private String pswdChgDt;       // 비밀번호 변경일
+    private String frstRegIp;       // 최초등록 아이디
+    private String sysPvsnYn;       // 시스템 제공 여부 -> 시스템에서 제공되는 데이터는 사용자가 제거하지 못하도록 하기 위한 설정값 0: 시스템, 1: 사용자
+    private String rgtr;            // 등록자
+    private String regDt;           // 등록일
+    private String mdfr;            // 수정자
+    private String mdfcnDt;         // 수정일
     @Builder.Default
-    private List<MberAuthorVO> authorList = new ArrayList<MberAuthorVO>();
+    private List<MberAuthorVO> authorList = new ArrayList<MberAuthorVO>(); // 권한 정보
 }
src/main/java/com/takensoft/cms/mber/dto/JoinDTO.java
--- src/main/java/com/takensoft/cms/mber/dto/JoinDTO.java
+++ src/main/java/com/takensoft/cms/mber/dto/JoinDTO.java
@@ -8,10 +8,12 @@
 import javax.validation.constraints.Size;
 import java.util.ArrayList;
 import java.util.List;
-
 /**
- * @author  : takensoft
- * @since   : 2024.04.01
+ * @author takensoft
+ * @since 2024.04.01
+ * @modification
+ *     since    |    author    | description
+ *  2024.04.01  |  takensoft   | 최초 등록
  *
  * 회원 가입 관련 DTO
  */
@@ -22,125 +24,39 @@
 @Builder
 @ToString
 public class JoinDTO {
-    /**
-     * 회원 아이디
-     */
-    private String mbrId;
-    /**
-     * 로그인 아이디
-     */
+
+    private String mbrId;                                   // 회원 아이디
     @NotBlank(message = "로그인 아이디는 필수 입력 값입니다.")
     @Size(min = 5, max = 50)
-    private String lgnId;
-    /**
-     * 회원 이름
-     */
+    private String lgnId;                                   // 로그인 아이디
     @NotBlank(message = "이름은 필수 입력 값입니다.")
     @Size(min = 2, max = 50)
-    private String mbrNm;
-    /**
-     * 닉네임
-     */
-    private String ncnm;
-    /**
-     * 비밀번호
-     */
+    private String mbrNm;                                   // 회원 이름
+    private String ncnm;                                    // 닉네임
     @NotBlank(message = "비밀번호는 필수 입력 값입니다.")
-    private String pswd;
-    /**
-     * 휴대폰번호
-     */
-    private String mblTelno;
-    /**
-     * 전화번호
-     */
-    private String telno;
-    /**
-     * 이메일
-     */
+    private String pswd;                                    // 비밀번호
+    private String mblTelno;                                // 휴대폰번호
+    private String telno;                                   // 전화번호
     @Email(message = "이메일 형식에 맞지 않습니다.")
-    private String eml;
-    /**
-     * 우편번호
-     */
-    private String zip;
-    /**
-     * 주소
-     */
-    private String addr;
-    /**
-     * 상세주소
-     */
-    private String daddr;
-    /**
-     * 회원상태
-     * 0: 탈퇴, 1: 승인, 2: 승인대기, 3: 차단
-     */
-    private String mbrStts;
-    /**
-     * 사용여부
-     */
-    private String useYn;
-    /**
-     * 차단일
-     */
-    private String cntrlDt;
-    /**
-     * 차단사유
-     */
-    private String cntrlRsn;
-    /**
-     * 문자수신여부
-     * 0: 거부, 1: 허용
-     */
-    private String smsRcptnAgreYn;
-    /**
-     * 이메일수신여부
-     * 0: 거부, 1: 허용
-     */
-    private String emlRcptnAgreYn;
-    /**
-     * 개인정보공개여부
-     * 0: 거부, 1: 허용
-     */
-    private String prvcRlsYn;
-    /**
-     * 회원형태
-     * S: 시스템, K: 카카오, N: 네이버, G: 구글, F: 페이스북
-     */
-    private String mbrType;
-    /**
-     * 비밀번호 변경일
-     */
-    private String pswdChgDt;
-    /**
-     * 최초등록 아이디
-     */
-    private String frstRegIp;
-    /**
-     * 시스템 제공 여부 -> 시스템에서 제공되는 데이터는 사용자가 제거하지 못하도록 하기 위한 설정값
-     * 0: 시스템, 1: 사용자
-     */
-    private String sysPvsnYn;
-    /**
-     * 등록자
-     */
-    private String rgtr;
-    /**
-     * 등록일
-     */
-    private String regDt;
-    /**
-     * 수정자
-     */
-    private String mdfr;
-    /**
-     * 수정일
-     */
-    private String mdfcnDt;
-    /**
-     * 권한 정보
-     */
+    private String eml;                                     // 이메일
+    private String zip;                                     // 우편번호
+    private String addr;                                    // 주소
+    private String daddr;                                   // 상세주소
+    private String mbrStts;                                 // 회원상태 0: 탈퇴, 1: 승인, 2: 승인대기, 3: 차단
+    private String useYn;                                   // 사용여부
+    private String cntrlDt;                                 // 차단일
+    private String cntrlRsn;                                //차단사유
+    private String smsRcptnAgreYn;                          // 문자수신여부 0: 거부, 1: 허용
+    private String emlRcptnAgreYn;                          // 이메일수신여부 0: 거부, 1: 허용
+    private String prvcRlsYn;                               // 개인정보공개여부 0: 거부, 1: 허용
+    private String mbrType;                                 // 회원형태 S: 시스템, K: 카카오, N: 네이버, G: 구글, F: 페이스북
+    private String pswdChgDt;                               // 비밀번호 변경일
+    private String frstRegIp;                               // 최초등록 아이디
+    private String sysPvsnYn;                               // 시스템 제공 여부 -> 시스템에서 제공되는 데이터는 사용자가 제거하지 못하도록 하기 위한 설정값 0: 시스템, 1: 사용자
+    private String rgtr;                                    // 등록자
+    private String regDt;                                   // 등록일
+    private String mdfr;                                    // 수정자
+    private String mdfcnDt;                                 // 수정일
     @Builder.Default
-    private List<MberAuthorVO> authorList = new ArrayList<MberAuthorVO>();
+    private List<MberAuthorVO> authorList = new ArrayList<MberAuthorVO>(); // 권한 정보
 }
src/main/java/com/takensoft/cms/mber/dto/LoginDTO.java
--- src/main/java/com/takensoft/cms/mber/dto/LoginDTO.java
+++ src/main/java/com/takensoft/cms/mber/dto/LoginDTO.java
@@ -6,10 +6,12 @@
 import lombok.NoArgsConstructor;
 
 import javax.validation.constraints.NotNull;
-
 /**
  * @author  : takensoft
  * @since   : 2024.04.01
+ * @modification
+ *     since    |    author    | description
+ *  2024.04.01  |  takensoft   | 최초 등록
  *
  * 로그인 관련 DTO
  */
@@ -18,18 +20,10 @@
 @NoArgsConstructor
 @Builder
 public class LoginDTO {
-    /**
-     * 로그인 아이디
-     */
+
     @NotNull
-    private String lgnId;
-    /**
-     * 비밀번호
-     */
+    private String lgnId;           // 로그인 아이디
     @NotNull
-    private String pswd;
-    /**
-     * refreshToken 정보
-     */
-    private String refreshToken;
+    private String pswd;            // 비밀번호
+    private String refreshToken;    // refreshToken 정보
 }
src/main/java/com/takensoft/cms/mber/dto/PasswordDTO.java
--- src/main/java/com/takensoft/cms/mber/dto/PasswordDTO.java
+++ src/main/java/com/takensoft/cms/mber/dto/PasswordDTO.java
@@ -4,12 +4,14 @@
 import lombok.*;
 
 import javax.validation.constraints.NotBlank;
-
 /**
  * @author  : takensoft
  * @since   : 2024.04.01
+ * @modification
+ *     since    |    author    | description
+ *  2024.04.01  |  takensoft   | 최초 등록
  *
- * 비밀 번호 변경
+ * 비밀 번호 변경 관련 DTO
  */
 @Setter
 @Getter
@@ -18,20 +20,10 @@
 @Builder
 @ToString
 public class PasswordDTO {
-    /**
-     * 회원 아이디
-     */
-    private String mbrId;
 
-    /**
-     * 비밀번호[현재 비밀번호]
-     */
+    private String mbrId;                                   // 회원 아이디
     @NotBlank(message = "비밀번호는 필수 입력 값입니다.")
-    private String pswd;
-
-    /**
-     * 비밀번호[변경될 비밀번호]
-     */
+    private String pswd;                                    // 비밀번호[현재 비밀번호]
     @NotBlank(message = "변경할 비밀번호는 필수 입력 값입니다.")
-    private String newPswd;
+    private String newPswd;                                 // 비밀번호[변경될 비밀번호]
 }
src/main/java/com/takensoft/cms/mber/service/AdmMbrService.java
--- src/main/java/com/takensoft/cms/mber/service/AdmMbrService.java
+++ src/main/java/com/takensoft/cms/mber/service/AdmMbrService.java
@@ -5,60 +5,70 @@
 import com.takensoft.cms.mber.vo.MberVO;
 
 import jakarta.servlet.http.HttpServletRequest;
-import java.util.HashMap;
+import org.springframework.dao.DataAccessException;
 
+import java.util.HashMap;
 /**
- * @author  : 박정하
- * @since   : 2024.06.21
+ * @author 박정하
+ * @since 2024.06.21
+ * @modification
+ *     since    |    author    | description
+ *  2024.06.21  |    박정하     | 최초 등록
  *
  * 회원정보 관련 인터페이스
  */
 public interface AdmMbrService {
     /**
-     * @author  : 박정하
-     * @since   : 2024.06.21
+     * @param params - 회원정보
+     * @return HashMap<String, Object>
+     *  - result : 회원정보
+     *  - pagination : 페이징 정보
      *
      * 회원정보 목록 조회
      */
-    public HashMap<String, Object> mbrList(HashMap<String, String> params) throws Exception;
+    public HashMap<String, Object> mbrList(HashMap<String, String> params);
 
     /**
-     * @author  : 박정하
-     * @since   : 2024.06.21
+     * @param mbrId - 회원 아이디
+     * @return AdmMbrDTO - 회원정보 상세 조회 결과
      *
      * 회원정보 상세 조회
      */
-    public AdmMbrDTO mbrDetail(String mbrId) throws Exception;
+    public AdmMbrDTO mbrDetail(String mbrId);
 
     /**
-     * @author  : 박정하
-     * @since   : 2024.06.21
+     * @param admMbrDTO -회원정보
+     * @return int - 회원정보 수정 결과
      *
      * 회원정보 수정
      */
-    public int updateMbr(AdmMbrDTO admMbrDTO) throws Exception;
+    public int updateMbr(AdmMbrDTO admMbrDTO);
 
     /**
-     * @author  : 박정하
-     * @since   : 2024.06.21
+     * @param req - HTTP 요청 객체
+     * @param joinDTO -회원정보
+     * @return HashMap<String, Object> - 회원정보 등록 결과
+     *  - mbrId : 회원 아이디
+     *  - insertResult : 회원등록정보 결과
      *
      * 회원정보 등록
      */
-    public HashMap<String, Object> mbrInsert(HttpServletRequest req, JoinDTO joinDTO) throws Exception;
+    public HashMap<String, Object> mbrInsert(HttpServletRequest req, JoinDTO joinDTO);
 
     /**
-     * @author  : 박정하
-     * @since   : 2024.07.03
+     * @param mbrVO -회원정보
+     * @return String - 로그인 아이디
      *
      * 아이디 찾기 (로그인 아이디)
      */
-    public String lgnIdSearch(MberVO mbrVO) throws Exception;
+    public String lgnIdSearch(MberVO mbrVO);
 
     /**
-     * @author  : 박정하
-     * @since   : 2024.07.03
+     * @param resetPswd -초기화비밀번호
+     * @param admMbrDTO -회원정보
+     * @return int - 회원정보 등록 결과
      *
-     * 아이디 찾기 (멤버 아이디)
+     * 아이디 찾기 (회원 아이디)
      */
-    public int mbrIdSearch(String resetPswd, AdmMbrDTO admMbrDTO) throws Exception;
+    public int mbrIdSearch(String resetPswd, AdmMbrDTO admMbrDTO);
 }
(파일 끝에 줄바꿈 문자 없음)
src/main/java/com/takensoft/cms/mber/service/Impl/AdmMbrServiceImpl.java
--- src/main/java/com/takensoft/cms/mber/service/Impl/AdmMbrServiceImpl.java
+++ src/main/java/com/takensoft/cms/mber/service/Impl/AdmMbrServiceImpl.java
@@ -10,24 +10,27 @@
 import com.takensoft.cms.mber.vo.MberVO;
 import com.takensoft.common.Pagination;
 import com.takensoft.common.idgen.service.IdgenService;
-import com.takensoft.common.util.CommonUtils;
+import com.takensoft.common.util.HttpRequestUtil;
 import com.takensoft.common.util.JWTUtil;
 import com.takensoft.common.util.Secret;
 import lombok.RequiredArgsConstructor;
 import org.egovframe.rte.fdl.cmmn.EgovAbstractServiceImpl;
+import org.springframework.dao.DataAccessException;
 import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
 import org.springframework.stereotype.Service;
 import org.springframework.transaction.annotation.Transactional;
 
 import jakarta.servlet.http.HttpServletRequest;
+
 import java.util.HashMap;
 import java.util.List;
-
 /**
- * @author  : 박정하
- * @since   : 2024.06.21
+ * @author 박정하
+ * @since 2024.06.21
+ * @modification
+ *     since    |    author    | description
+ *  2024.06.21  |    박정하     | 최초 등록
  *
- * 회원정보 관련 구현체
  * EgovAbstractServiceImpl : 전자정부 상속
  * AdmMbrService : 회원정보 인터페이스 상속
  */
@@ -36,19 +39,24 @@
 public class AdmMbrServiceImpl extends EgovAbstractServiceImpl implements AdmMbrService {
     private final JWTUtil jwtUtil;
     private final IdgenService mberIdgn;
-    private final CommonUtils commonUtils;
+    private final HttpRequestUtil httpRequestUtil;
     private final BCryptPasswordEncoder bCryptPasswordEncoder;
     private final AdmMbrDAO admMbrDAO;
     private final MberService mbrService;
 
     /**
-     * @author  : 박정하
-     * @since   : 2024.06.21
+     * @param params - 회원정보
+     * @return HashMap<String, Object>
+     *  - result : 회원정보
+     *  - pagination : 페이징 정보
+     * @throws DataAccessException - db 관련 예외 발생 시
+     * @throws Exception - 그 외 예외 발생 시
      *
      * 회원정보 목록 조회
      */
     @Override
-    public HashMap<String, Object> mbrList(HashMap<String, String> params) throws Exception {
+    public HashMap<String, Object> mbrList(HashMap<String, String> params) {
+        try {
         Pagination search = new Pagination(0, params);
         int cnt = admMbrDAO.mbrListCnt(search);
 
@@ -66,17 +74,25 @@
         result.put("list", list);
         result.put("pagination", pagination);
         return result;
+        } catch (DataAccessException dae) {
+            throw dae;
+        } catch (Exception e) {
+            throw e;
+        }
 
     }
 
     /**
-     * @author  : 박정하
-     * @since   : 2024.06.21
+     * @param mbrId - 회원 아이디
+     * @return AdmMbrDTO - 회원정보 상세 조회 결과
+     * @throws DataAccessException - db 관련 예외 발생 시
+     * @throws Exception - 그 외 예외 발생 시
      *
      * 회원정보 상세 조회
      */
     @Override
-    public AdmMbrDTO mbrDetail(String mbrId) throws Exception {
+    public AdmMbrDTO mbrDetail(String mbrId){
+        try {
         AdmMbrDTO admMbrDTO = new AdmMbrDTO();
 
         // mbrId가 있는 경우
@@ -100,19 +116,26 @@
             admMbrDTO.setSmsRcptnAgreYn("Y");
             admMbrDTO.setEmlRcptnAgreYn("Y");
         }
-
         return admMbrDTO;
+        } catch (DataAccessException dae) {
+            throw dae;
+        } catch (Exception e) {
+            throw e;
+        }
     }
 
     /**
-     * @author  : 박정하
-     * @since   : 2024.06.21
+     * @param admMbrDTO -회원정보
+     * @return int - 회원정보 수정 결과
+     * @throws DataAccessException - db 관련 예외 발생 시
+     * @throws Exception - 그 외 예외 발생 시
      *
      * 회원정보 수정
      */
     @Override
     @Transactional(rollbackFor = Exception.class)
-    public int updateMbr(AdmMbrDTO admMbrDTO) throws Exception {
+    public int updateMbr(AdmMbrDTO admMbrDTO){
+        try {
         // 비밀번호 변경
         if (admMbrDTO.getPswd() != null && !admMbrDTO.getPswd().equals("")) {
             PasswordDTO passwordDTO = new PasswordDTO();
@@ -147,89 +170,121 @@
                 }
             }
         }
-
         return result;
+        } catch (DataAccessException dae) {
+            throw dae;
+        } catch (Exception e) {
+            throw e;
+        }
     }
 
-    /**
-     * @author  : 박정하
-     * @since   : 2024.06.21
-     *
-     * 회원정보 등록
-     */
-    @Override
-    @Transactional(rollbackFor = Exception.class)
-    public HashMap<String, Object> mbrInsert(HttpServletRequest req, JoinDTO joinDTO) throws Exception {
-        // 회원 아이디 생성
-        String mbrId = mberIdgn.getNextStringId();
-        joinDTO.setMbrId(mbrId);
+        /**
+         * @param req - HTTP 요청 객체
+         * @param joinDTO -회원정보
+         * @return HashMap<String, Object> - 회원정보 등록 결과
+         *  - mbrId : 회원 아이디
+         *  - insertResult : 회원등록정보 결과
+         * @throws DataAccessException - db 관련 예외 발생 시
+         * @throws Exception - 그 외 예외 발생 시
+         *
+         * 회원정보 등록
+         */
+        @Override
+        @Transactional(rollbackFor = Exception.class)
+        public HashMap<String, Object> mbrInsert(HttpServletRequest req, JoinDTO joinDTO){
+            try {
+                // 회원 아이디 생성
+                String mbrId = mberIdgn.getNextStringId();
+                joinDTO.setMbrId(mbrId);
 
-        // 비밀번호 암호화
-        joinDTO.setPswd(bCryptPasswordEncoder.encode(joinDTO.getPswd()));
+                // 비밀번호 암호화
+                joinDTO.setPswd(bCryptPasswordEncoder.encode(joinDTO.getPswd()));
 
-        // 연락처 암호화
-        if(joinDTO.getMblTelno() != null && !joinDTO.getMblTelno().equals("")) {
-            joinDTO.setMblTelno(Secret.encrypt(joinDTO.getMblTelno()));
-        }
-        if(joinDTO.getTelno() != null && !joinDTO.getTelno().equals("")) {
-            joinDTO.setTelno(Secret.encrypt(joinDTO.getTelno()));
-        }
+                // 연락처 암호화
+                if(joinDTO.getMblTelno() != null && !joinDTO.getMblTelno().equals("")) {
+                    joinDTO.setMblTelno(Secret.encrypt(joinDTO.getMblTelno()));
+                }
+                if(joinDTO.getTelno() != null && !joinDTO.getTelno().equals("")) {
+                    joinDTO.setTelno(Secret.encrypt(joinDTO.getTelno()));
+                }
 
-        // 아이피 등록
-        String ip = commonUtils.getIp(req);
-        joinDTO.setFrstRegIp(ip);
+                // 아이피 등록
+                String ip = httpRequestUtil.getIp(req);
+                joinDTO.setFrstRegIp(ip);
 
-        // 작성자 등록
-        String writer = jwtUtil.getWriter();
-        if(writer != null && !writer.equals("")) {
-            joinDTO.setRgtr(writer);
-        }
+                // 작성자 등록
+                String writer = jwtUtil.getWriter();
+                if(writer != null && !writer.equals("")) {
+                    joinDTO.setRgtr(writer);
+                }
 
-        // 회원정보 등록
-        int insertResult = admMbrDAO.mbrInsert(joinDTO);
+                // 회원정보 등록
+                int insertResult = admMbrDAO.mbrInsert(joinDTO);
 
-        // 권한 등록
-        if(joinDTO.getAuthorList().size() > 0) {
-            for(MberAuthorVO mberAuthorVO : joinDTO.getAuthorList()) {
-                mberAuthorVO.setMbrId(joinDTO.getMbrId());
-                mberAuthorVO.setRgtr(writer);
-                insertResult += admMbrDAO.insertAuthor(mberAuthorVO);
+                // 권한 등록
+                if(joinDTO.getAuthorList().size() > 0) {
+                    for(MberAuthorVO mberAuthorVO : joinDTO.getAuthorList()) {
+                        mberAuthorVO.setMbrId(joinDTO.getMbrId());
+                        mberAuthorVO.setRgtr(writer);
+                        insertResult += admMbrDAO.insertAuthor(mberAuthorVO);
+                    }
+                }
+
+                HashMap<String, Object> result = new HashMap<>();
+                result.put("mbrId", mbrId);
+                result.put("insertResult", insertResult);
+                return result;
+            } catch (DataAccessException dae) {
+                throw dae;
+            } catch (Exception e) {
+                throw e;
             }
         }
 
-        HashMap<String, Object> result = new HashMap<>();
-        result.put("mbrId", mbrId);
-        result.put("insertResult", insertResult);
-        return result;
-    }
-
     /**
-     * @author  : 박정하
-     * @since   : 2024.07.03
+     * @param mbrVO -회원정보
+     * @return String - 로그인 아이디
+     * @throws DataAccessException - db 관련 예외 발생 시
+     * @throws Exception - 그 외 예외 발생 시
      *
      * 아이디 찾기 (로그인 아이디)
      */
-    public String lgnIdSearch(MberVO mbrVO) throws Exception {
-        return admMbrDAO.lgnIdSearch(mbrVO);
+    public String lgnIdSearch(MberVO mbrVO){
+        try {
+            return admMbrDAO.lgnIdSearch(mbrVO);
+        } catch (DataAccessException dae) {
+            throw dae;
+        } catch (Exception e) {
+            throw e;
+        }
     }
 
     /**
-     * @author  : 박정하
-     * @since   : 2024.07.03
+     * @param resetPswd -초기화비밀번호
+     * @param admMbrDTO -회원정보
+     * @return int - 회원정보 등록 결과
+     * @throws DataAccessException - db 관련 예외 발생 시
+     * @throws Exception - 그 외 예외 발생 시
      *
-     * 아이디 찾기 (멤버 아이디)
+     * 아이디 찾기 (회원 아이디)
      */
-    public int mbrIdSearch(String resetPswd, AdmMbrDTO admMbrDTO) throws Exception {
-        String mbrId = admMbrDAO.mbrIdSearch(admMbrDTO);
+    public int mbrIdSearch(String resetPswd, AdmMbrDTO admMbrDTO){
+        try {
+            String mbrId = admMbrDAO.mbrIdSearch(admMbrDTO);
 
-        PasswordDTO passwordDTO = new PasswordDTO();
-        passwordDTO.setMbrId(mbrId);
-        passwordDTO.setPswd(admMbrDTO.getPswd());
-        passwordDTO.setNewPswd(resetPswd);
+            PasswordDTO passwordDTO = new PasswordDTO();
+            passwordDTO.setMbrId(mbrId);
+            passwordDTO.setPswd(admMbrDTO.getPswd());
+            passwordDTO.setNewPswd(resetPswd);
 
-        // 비밀번호 변경
-        int result = mbrService.updatePassword(passwordDTO);
+            // 비밀번호 변경
+            int result = mbrService.updatePassword(passwordDTO);
 
-        return result;
+            return result;
+        } catch (DataAccessException dae) {
+            throw dae;
+        } catch (Exception e) {
+            throw e;
+        }
     }
 }
(파일 끝에 줄바꿈 문자 없음)
src/main/java/com/takensoft/cms/mber/service/Impl/LgnHstryServiceImpl.java
--- src/main/java/com/takensoft/cms/mber/service/Impl/LgnHstryServiceImpl.java
+++ src/main/java/com/takensoft/cms/mber/service/Impl/LgnHstryServiceImpl.java
@@ -13,18 +13,22 @@
 import org.egovframe.rte.fdl.cmmn.EgovAbstractServiceImpl;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
+import org.springframework.dao.DataAccessException;
 import org.springframework.stereotype.Service;
 
 import java.util.HashMap;
 import java.util.List;
-
 /**
- * @author  : takensoft
- * @since   : 2024.04.09
+ * @author takensoft
+ * @since 2024.04.09
+ * @modification
+ *     since    |    author    | description
+ *  2024.04.09  |  takensoft   | 최초 등록
  *
  * 로그인 이력 정보 관련 구현체
  * EgovAbstractServiceImpl : 전자정부 상속
  * LgnHstryService : 로그인 이력 정보 인터페이스 상속
+ *
  */
 @Service("lgnHstryService")
 @RequiredArgsConstructor
@@ -33,34 +37,56 @@
     private final CodeManageService codeManageService;
 
     /**
-     * @author takensoft
-     * @since 2024.04.09
+     * @param lgnHstryVO - 로그인 이력 정보
+     * @return int - 로그인 이력 결과
+     * @throws DataAccessException - db 관련 예외 발생 시
+     * @throws Exception - 그 외 예외 발생 시
+     *
      * 로그인 이력 등록
      */
     @Override
-    public int LgnHstrySave(LgnHstryVO lgnHstryVO) throws Exception {
-        return lgnHstryDAO.save(lgnHstryVO);
+    public int LgnHstrySave(LgnHstryVO lgnHstryVO){
+        try {
+        int result = lgnHstryDAO.save(lgnHstryVO);
+
+        return result;
+        } catch (DataAccessException dae) {
+            throw dae;
+        } catch (Exception e) {
+            throw e;
+        }
     }
 
     /**
-     * @author  : 박정하
-     * @since   : 2024.05.13
+     * @param params -회원정보
+     * @return HashMap<String, Object>
+     *  - list : 로그인 이력 목록
+     *  - pagination : 페이징 정보
+     *  - codeList : 공통 코드 조회(로그인이력)
+     * @throws DataAccessException - db 관련 예외 발생 시
+     * @throws Exception - 그 외 예외 발생 시
      *
      * 로그인 이력 목록 조회
      */
     @Override
-    public HashMap<String, Object> lgnHstryList(HashMap<String, String> params) throws Exception {
-        Pagination search = new Pagination(0, params);
-        int cnt = lgnHstryDAO.selectLgnHstryListCnt(search);
+    public HashMap<String, Object> lgnHstryList(HashMap<String, String> params){
+        try {
+            Pagination search = new Pagination(0, params);
+            int cnt = lgnHstryDAO.selectLgnHstryListCnt(search);
 
-        Pagination pagination = new Pagination(cnt, params);
-        List<LgnHstryVO> list = lgnHstryDAO.selectLgnHstryList(pagination);
-        List<CodeManageVO> codeList = codeManageService.findByChildCdCache("lgnHstry"); // 검색 조건
+            Pagination pagination = new Pagination(cnt, params);
+            List<LgnHstryVO> list = lgnHstryDAO.selectLgnHstryList(pagination);
+            List<CodeManageVO> codeList = codeManageService.findByChildCdCache("lgnHstry"); // 검색 조건
 
-        HashMap<String, Object> result = new HashMap<>();
-        result.put("list", list);
-        result.put("pagination", pagination);
-        result.put("codeList", codeList);
-        return result;
+            HashMap<String, Object> result = new HashMap<>();
+            result.put("list", list);
+            result.put("pagination", pagination);
+            result.put("codeList", codeList);
+            return result;
+        } catch (DataAccessException dae) {
+            throw dae;
+        } catch (Exception e) {
+            throw e;
+        }
     }
 }
(파일 끝에 줄바꿈 문자 없음)
src/main/java/com/takensoft/cms/mber/service/Impl/MberServiceImpl.java
--- src/main/java/com/takensoft/cms/mber/service/Impl/MberServiceImpl.java
+++ src/main/java/com/takensoft/cms/mber/service/Impl/MberServiceImpl.java
@@ -7,11 +7,12 @@
 import com.takensoft.cms.mber.vo.MberAuthorVO;
 import com.takensoft.cms.mber.vo.MberVO;
 import com.takensoft.common.idgen.service.IdgenService;
-import com.takensoft.common.util.CommonUtils;
+import com.takensoft.common.util.HttpRequestUtil;
 import com.takensoft.common.util.JWTUtil;
 import com.takensoft.common.util.Secret;
 import lombok.RequiredArgsConstructor;
 import org.egovframe.rte.fdl.cmmn.EgovAbstractServiceImpl;
+import org.springframework.dao.DataAccessException;
 import org.springframework.security.core.userdetails.UserDetails;
 import org.springframework.security.core.userdetails.UserDetailsService;
 import org.springframework.security.core.userdetails.UsernameNotFoundException;
@@ -20,11 +21,14 @@
 import org.springframework.transaction.annotation.Transactional;
 
 import jakarta.servlet.http.HttpServletRequest;
-import java.util.HashMap;
 
+import java.util.HashMap;
 /**
- * @author  : takensoft
- * @since   : 2024.04.01
+ * @author takensoft
+ * @since 2024.04.01
+ * @modification
+ *     since    |    author    | description
+ *  2024.04.01  |  takensoft   | 최초 등록
  *
  * 회원 정보 관련 구현체
  * EgovAbstractServiceImpl : 전자정부 상속
@@ -38,112 +42,146 @@
     private final IdgenService mberIdgn;
     private final BCryptPasswordEncoder bCryptPasswordEncoder;
     private final JWTUtil jwtUtil;
-    private final CommonUtils commonUtils;
+    private final HttpRequestUtil httpRequestUtil;
 
     /**
-     * @author takensoft
-     * @since 2024.04.03
+     * @param username -회원이름
+     * @return UserDetails - Spring Security에서 사용자의 정보를 담는 인터페이스
+     * @throws UsernameNotFoundException - 가입하지 않은 계정으로 로그인 시도 시
+     * @throws Exception - 그 외 예외 발생 시
      *
      * security 상속 시 Override 하는 메소드
      */
     @Override
     @Transactional(readOnly = true)
-    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
-        return mberDAO.findByMberSecurity(username);
-    }
+    public UserDetails loadUserByUsername(String username){
+        try {
+             UserDetails userDetails = mberDAO.findByMberSecurity(username);
 
+             return userDetails;
+        } catch (UsernameNotFoundException Unfe) {
+            throw Unfe;
+        } catch (Exception e) {
+            throw e;
+        }
+    }
     /**
-     * @author takensoft
-     * @since 2024.04.03
+     * @param lgnId - 로그인 아이디
+     * @return boolean - 아이디 아이디 중복 여부
      *
      * 아이디 중복 검사
      */
     @Override
-    public boolean findByCheckLoginId(String lgnId) throws Exception {
+    public boolean findByCheckLoginId(String lgnId) {
         return mberDAO.findByCheckLoginId(lgnId);
     }
 
     /**
-     * @author takensoft
-     * @since 2024.04.03
+     * @param req - HTTP 요청 객체
+     * @param joinDTO -회원정보
+     * @return HashMap<String, Object> - 회원정보 등록 결과
+     *  - mbrId : 회원 아이디
+     *  - result : 회원등록정보 결과
+     * @throws DataAccessException - db 관련 예외 발생 시
+     * @throws Exception - 그 외 예외 발생 시
+     *
      * 회원가입
      */
     @Override
     @Transactional(rollbackFor = Exception.class)
-    public HashMap<String, Object> userJoin(HttpServletRequest req,  JoinDTO joinDTO) throws Exception {
-        // 회원 아이디 생성
-        String mbrId = mberIdgn.getNextStringId();
-        joinDTO.setMbrId(mbrId);
+    public HashMap<String, Object> userJoin(HttpServletRequest req,  JoinDTO joinDTO){
+        try {
+            // 회원 아이디 생성
+            String mbrId = mberIdgn.getNextStringId();
+            joinDTO.setMbrId(mbrId);
 
-        // 비밀번호 암호화
-        joinDTO.setPswd(bCryptPasswordEncoder.encode(joinDTO.getPswd()));
+            // 비밀번호 암호화
+            joinDTO.setPswd(bCryptPasswordEncoder.encode(joinDTO.getPswd()));
 
-        // 연락처 암호화
-        if(joinDTO.getMblTelno() != null && !joinDTO.getMblTelno().equals("")) {
-            joinDTO.setMblTelno(Secret.encrypt(joinDTO.getMblTelno()));
-        }
-        if(joinDTO.getTelno() != null && !joinDTO.getTelno().equals("")) {
-            joinDTO.setTelno(Secret.encrypt(joinDTO.getTelno()));
-        }
-
-        // 아이피 조회 및 등록
-        joinDTO.setFrstRegIp(commonUtils.getIp(req));
-        
-        // 작성자 조회 및 등록
-        if(jwtUtil.getWriter() != null && !jwtUtil.getWriter().equals("")) {
-            joinDTO.setRgtr(jwtUtil.getWriter());
-        }
-
-        // 회원정보 등록
-        HashMap<String, Object> result = new HashMap<>();
-        int saveResult = mberDAO.save(joinDTO);
-        result.put("mbrId", mbrId);
-
-        // 권한 등록
-        int authorResult = 0;
-        if(joinDTO.getAuthorList().size() > 0) {
-            for(MberAuthorVO vo : joinDTO.getAuthorList()) {
-                vo.setMbrId(joinDTO.getMbrId());
-                // 작성자 조회 및 등록
-                if(jwtUtil.getWriter() != null && !jwtUtil.getWriter().equals("")) {
-                    vo.setRgtr(jwtUtil.getWriter());
-                }
-                authorResult += mberDAO.authorSave(vo);
+            // 연락처 암호화
+            if(joinDTO.getMblTelno() != null && !joinDTO.getMblTelno().equals("")) {
+                joinDTO.setMblTelno(Secret.encrypt(joinDTO.getMblTelno()));
             }
-        }
-        result.put("result", saveResult + authorResult);
+            if(joinDTO.getTelno() != null && !joinDTO.getTelno().equals("")) {
+                joinDTO.setTelno(Secret.encrypt(joinDTO.getTelno()));
+            }
 
-        return result;
+            // 아이피 조회 및 등록
+            joinDTO.setFrstRegIp(httpRequestUtil.getIp(req));
+
+            // 작성자 조회 및 등록
+            if(jwtUtil.getWriter() != null && !jwtUtil.getWriter().equals("")) {
+                joinDTO.setRgtr(jwtUtil.getWriter());
+            }
+
+            // 회원정보 등록
+            HashMap<String, Object> result = new HashMap<>();
+            int saveResult = mberDAO.save(joinDTO);
+            result.put("mbrId", mbrId);
+
+            // 권한 등록
+            int authorResult = 0;
+            if(joinDTO.getAuthorList().size() > 0) {
+                for(MberAuthorVO vo : joinDTO.getAuthorList()) {
+                    vo.setMbrId(joinDTO.getMbrId());
+                    // 작성자 조회 및 등록
+                    if(jwtUtil.getWriter() != null && !jwtUtil.getWriter().equals("")) {
+                        vo.setRgtr(jwtUtil.getWriter());
+                    }
+                    authorResult += mberDAO.authorSave(vo);
+                }
+            }
+            result.put("result", saveResult + authorResult);
+
+            return result;
+        } catch (DataAccessException dae) {
+            throw dae;
+        } catch (Exception e) {
+            throw e;
+        }
     }
 
     /**
-     * @author takensoft
-     * @since 2024.04.15
+     * @param passwordDTO - 비밀번호
+     * @return boolean - 비밀번호 사용 가능 여부
+     * @throws DataAccessException - db 관련 예외 발생 시
+     * @throws Exception - 그 외 예외 발생 시
+     *
      * 비밀번호 비교
      */
     @Override
-    public boolean passwordCheck(PasswordDTO passwordDTO) throws Exception {
-        // 회원 정보 호출
-        MberVO mbr = mberDAO.findByMber(jwtUtil.getWriter());
-        // 비밀번호 비교 후 성공 시 비밀번호 수정 후 true 반환
-        if(bCryptPasswordEncoder.matches(passwordDTO.getPswd(), mbr.getPassword())) {
-            passwordDTO.setNewPswd(bCryptPasswordEncoder.encode(passwordDTO.getNewPswd()));
-            passwordDTO.setMbrId(mbr.getMbrId());
-            mberDAO.updatePassword(passwordDTO);
-            return true;
-            // 기존 비밀번호와 입력한 비밀번호가 서로 다를 경우 false 반환
-        } else {
-            return false;
+    public boolean passwordCheck(PasswordDTO passwordDTO){
+        try {
+            // 회원 정보 호출
+            MberVO mbr = mberDAO.findByMber(jwtUtil.getWriter());
+            // 비밀번호 비교 후 성공 시 비밀번호 수정 후 true 반환
+            if(bCryptPasswordEncoder.matches(passwordDTO.getPswd(), mbr.getPassword())) {
+                passwordDTO.setNewPswd(bCryptPasswordEncoder.encode(passwordDTO.getNewPswd()));
+                passwordDTO.setMbrId(mbr.getMbrId());
+                mberDAO.updatePassword(passwordDTO);
+                return true;
+                // 기존 비밀번호와 입력한 비밀번호가 서로 다를 경우 false 반환
+            } else {
+                return false;
+            }
+        } catch (DataAccessException dae) {
+            throw dae;
+        } catch (Exception e) {
+            throw e;
         }
     }
-
     /**
-     * @author 박정하
-     * @since 2024.04.23
+     * @param params
+     *  - 회원 아이디
+     * @return MberVO - 회원 정보
+     * @throws DataAccessException - db 관련 예외 발생 시
+     * @throws Exception - 그 외 예외 발생 시
+     *
      * 회원정보 상세 조회
      */
     @Override
-    public MberVO findByMbr(HashMap<String, Object> params) throws Exception {
+    public MberVO findByMbr(HashMap<String, Object> params){
+        try {
         String mbrId = params.get("mbrId").toString();
         MberVO mberVO = mberDAO.findByMber(mbrId);
         // 휴대폰번호 복호화
@@ -155,15 +193,21 @@
             mberVO.setTelno(Secret.decrypt(mberVO.getTelno().toString()));
         }
         return mberVO;
+        } catch (DataAccessException dae) {
+            throw dae;
+        } catch (Exception e) {
+            throw e;
+        }
     }
 
     /**
-     * @author takensoft
-     * @since 2024.04.24
+     * @param passwordDTO - 비밀번호
+     * @return int - 비밀번호 수정 결과
+     *
      * 비밀번호 수정
      */
     @Override
-    public int updatePassword(PasswordDTO passwordDTO) throws Exception {
+    public int updatePassword(PasswordDTO passwordDTO) {
         passwordDTO.setNewPswd(bCryptPasswordEncoder.encode(passwordDTO.getNewPswd()));
         return mberDAO.updatePassword(passwordDTO);
     }
src/main/java/com/takensoft/cms/mber/service/Impl/RefreshTokenServiceImpl.java
--- src/main/java/com/takensoft/cms/mber/service/Impl/RefreshTokenServiceImpl.java
+++ src/main/java/com/takensoft/cms/mber/service/Impl/RefreshTokenServiceImpl.java
@@ -1,12 +1,12 @@
 package com.takensoft.cms.mber.service.Impl;
 
-import com.fasterxml.jackson.datatype.jsr310.ser.YearSerializer;
 import com.takensoft.cms.mber.dao.RefreshTokenDAO;
 import com.takensoft.cms.mber.service.RefreshTokenService;
 import com.takensoft.cms.mber.vo.MberAuthorVO;
 import com.takensoft.cms.mber.vo.MberVO;
 import com.takensoft.cms.mber.vo.RefreshVO;
-import com.takensoft.common.util.CommonUtils;
+import com.takensoft.common.config.RedisConfig;
+import com.takensoft.common.util.HttpRequestUtil;
 import com.takensoft.common.util.JWTUtil;
 import io.jsonwebtoken.ExpiredJwtException;
 import lombok.RequiredArgsConstructor;
@@ -14,20 +14,26 @@
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import org.springframework.beans.factory.annotation.Value;
+import org.springframework.dao.DataAccessException;
+import org.springframework.data.redis.core.RedisTemplate;
 import org.springframework.stereotype.Service;
 import org.springframework.transaction.annotation.Transactional;
 
 import jakarta.servlet.http.Cookie;
 import jakarta.servlet.http.HttpServletRequest;
 import jakarta.servlet.http.HttpServletResponse;
+
 import java.util.Date;
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
 
 /**
- * @author  : takensoft
- * @since   : 2024.04.01
+ * @author takensoft
+ * @since 2024.04.01
+ * @modification
+ *     since    |    author    | description
+ *  2024.04.01  |  takensoft   | 최초 등록
  *
  * RefreshToken 정보 관련 구현체
  * EgovAbstractServiceImpl : 전자정부 상속
@@ -40,7 +46,9 @@
     private static final Logger LOGGER = LoggerFactory.getLogger(RefreshTokenServiceImpl.class);
     private final RefreshTokenDAO refreshTokenDAO;
     private final JWTUtil jwtUtil;
-    private final CommonUtils commonUtils;
+    private final HttpRequestUtil httpRequestUtil;
+    private final RedisConfig redisConfig;
+    private final RedisTemplate<String, String> redisTemplate;
 
     @Value("${jwt.accessTime}")
     private long JWT_ACCESSTIME; // access 토큰 유지 시간
@@ -50,8 +58,11 @@
     private int COOKIE_TIME; // 쿠키 유지 시간
 
     /**
-     * @author takensoft
-     * @since 2024.04.04
+     * @param req - HTTP 요청 객체
+     * @return Map<String, Object>
+     *  - result : refresh token 검증 결과
+     *  - refreshToken : refresh token
+     *
      * refresh token 검증
      */
     private Map<String, Object> refreshTokenCheck(HttpServletRequest req) {
@@ -86,112 +97,185 @@
     }
 
     /**
-     * @author takensoft
-     * @since 2024.04.04
+     * @param req - HTTP 요청 객체
+     * @param res - HTTP 응답 객체
+     * @param refresh - RefreshToken 정보
+     * @param expiredMs - 토큰 만료 시간 (밀리초)
+     * @return int - refresh token 등록결과
+     * @throws DataAccessException - db 관련 예외 발생 시
+     * @throws Exception - 그 외 예외 발생 시
+     *
      * refresh token 등록
      */
     @Override
-    public int saveRefreshToken(HttpServletRequest req, HttpServletResponse res, RefreshVO refresh, long expiredMs) throws Exception {
-        // 만료 시간
-        refresh.setExpryDt(new Date(System.currentTimeMillis() + expiredMs));
-        // 사용중인 아이피
-        refresh.setUseIp(commonUtils.getIp(req));
-        return refreshTokenDAO.save(refresh);
+    public int saveRefreshToken(HttpServletRequest req, HttpServletResponse res, RefreshVO refresh, long expiredMs){
+        try {
+            // 만료 시간
+            refresh.setExpryDt(new Date(System.currentTimeMillis() + expiredMs));
+            // 사용중인 아이피
+            refresh.setUseIp(httpRequestUtil.getIp(req));
+
+            int result = refreshTokenDAO.save(refresh);
+
+            return result;
+        } catch (DataAccessException dae) {
+            throw dae;
+        } catch (Exception e) {
+            throw e;
+        }
     }
 
     /**
-     * @author takensoft
-     * @since 2024.04.04
+     * @param req - HTTP 요청 객체
+     * @param res - HTTP 응답 객체
+     * @return int - refresh token 삭제 결과
+     * @throws DataAccessException - db 관련 예외 발생 시
+     * @throws Exception - 그 외 예외 발생 시
+     *
      * refresh token 삭제 프로세스 (로그아웃)
      */
     @Override
-    public int deleteByRefresh(HttpServletRequest req, HttpServletResponse res) throws Exception {
-        // refresh token 검증
-        int result = (int) refreshTokenCheck(req).get("result");
-        if(result == 0) return result;
+    public int deleteByRefresh(HttpServletRequest req, HttpServletResponse res) {
+        try {
+            // refresh token 검증
+            int result = (int) refreshTokenCheck(req).get("result");
+            if(result == 0) return result;
 
-        //Refresh 토큰 Cookie 값 0
-//        res.addCookie(jwtUtil.createCookie("refresh",null, 0));
+            //Refresh 토큰 Cookie 값 0
+            //res.addCookie(jwtUtil.createCookie("refresh",null, 0));
 
-        RefreshVO refreshVO = new RefreshVO();
-        refreshVO.setMbrId(jwtUtil.getMbrId(refreshTokenCheck(req).get("refreshToken").toString()));
+            RefreshVO refreshVO = new RefreshVO();
+            refreshVO.setMbrId(jwtUtil.getMbrId(refreshTokenCheck(req).get("refreshToken").toString()));
 
-        return delete(req, refreshVO);
+            //중복로그인 비허용시 삭제
+            if (!redisConfig.isAllowMultipleLogin()) {
+                redisTemplate.delete("jwt:" + refreshVO.getMbrId()); // 기존 JWT 삭제
+            }
+            return delete(req, refreshVO);
+        } catch (DataAccessException dae) {
+            throw dae;
+        } catch (Exception e) {
+            throw e;
+        }
     }
-
     /**
-     * @author takensoft
-     * @since 2024.04.04
+     * @param req - HTTP 요청 객체
+     * @param res - HTTP 응답 객체
+     * @return int - 토큰 재발급 결과
+     * @throws DataAccessException - db 관련 예외 발생 시
+     * @throws Exception - 그 외 예외 발생 시
+     *
      * 토큰 재발급
      */
     @Override
     @Transactional(rollbackFor = Exception.class)
-    public int tokenReissueProc(HttpServletRequest req, HttpServletResponse res) throws Exception {
-        // refresh token 검증
-        int result = (int) refreshTokenCheck(req).get("result");
-        if(result == 0) return result;
+    public int tokenReissueProc(HttpServletRequest req, HttpServletResponse res){
+        try {
+            // refresh token 검증
+            int result = (int) refreshTokenCheck(req).get("result");
+            if(result == 0) return result;
 
-        String refreshToken = refreshTokenCheck(req).get("refreshToken").toString();
+            String refreshToken = refreshTokenCheck(req).get("refreshToken").toString();
 
-        Date expired = jwtUtil.getExpired(refreshToken);
+            String userId = jwtUtil.getMbrId(refreshToken);
 
-        // 만료시간과 현재 시간의 차이 계산
-        long timeDffrnc = (expired.getTime() - new Date().getTime()) / (1000 * 60 * 60);
+            // 중복 로그인 비허용 체크 (DB에 저장된 리프레시 토큰과 비교)
+            if (!redisConfig.isAllowMultipleLogin()) {
+                String storedRefreshToken = redisTemplate.opsForValue().get("jwt:" + userId);
 
-        MberVO mber = new MberVO();
-        List<MberAuthorVO> roles = jwtUtil.getRoles(refreshToken);
-        mber.setLgnId(jwtUtil.getLgnId(refreshToken));
-        mber.setMbrId(jwtUtil.getMbrId(refreshToken));
-        mber.setMbrNm(jwtUtil.getMbrNm(refreshToken));
-        mber.setAuthorList(roles);
-        // 신규 AccessToken 발행
-        String newAccessToken = jwtUtil.createJwt("Authorization", mber.getMbrId(), mber.getLgnId(), mber.getMbrNm(), (List) mber.getAuthorities(), JWT_ACCESSTIME);
+                if (storedRefreshToken == null || !storedRefreshToken.equals(refreshToken)) {
+                    // 다른 기기에서 로그인되었으므로 자동 로그인 차단
+                    return HttpServletResponse.SC_UNAUTHORIZED;
+                }
+            }
 
-        // 남은 시간이 3시간 미만으로 남았을 경우 RefreshToken 재발급
-        if(timeDffrnc < 3) {
-            RefreshVO refresh = new RefreshVO();
-            refresh.setMbrId(mber.getMbrId());
+            Date expired = jwtUtil.getExpired(refreshToken);
 
-            // 기존 RefreshToken 삭제
-            result += delete(req, refresh);
+            // 만료시간과 현재 시간의 차이 계산
+            long timeDffrnc = (expired.getTime() - new Date().getTime()) / (1000 * 60 * 60);
 
-            // 신규 RefreshToken 발행
-            String newRefreshToken = jwtUtil.createJwt("refresh", mber.getMbrId(), mber.getLgnId(), mber.getMbrNm(), (List) mber.getAuthorities(), JWT_REFRESHTIME);
-            refresh.setToken(newRefreshToken);
-            result += saveRefreshToken(req, res,refresh, JWT_REFRESHTIME);
+            MberVO mber = new MberVO();
+            List<MberAuthorVO> roles = jwtUtil.getRoles(refreshToken);
+            mber.setLgnId(jwtUtil.getLgnId(refreshToken));
+            mber.setMbrId(jwtUtil.getMbrId(refreshToken));
+            mber.setMbrNm(jwtUtil.getMbrNm(refreshToken));
+            mber.setAuthorList(roles);
+            // 신규 AccessToken 발행
+            String newAccessToken = jwtUtil.createJwt("Authorization", mber.getMbrId(), mber.getLgnId(), mber.getMbrNm(), (List) mber.getAuthorities(), JWT_ACCESSTIME);
 
-            // 응답설정 RefreshToken
-//            res.setHeader("refresh", newRefreshToken);
-            // 쿠키 방식
-            res.addCookie(jwtUtil.createCookie("refresh",newRefreshToken, COOKIE_TIME));
+            // 남은 시간이 3시간 미만으로 남았을 경우 RefreshToken 재발급
+            if(timeDffrnc < 3) {
+                RefreshVO refresh = new RefreshVO();
+                refresh.setMbrId(mber.getMbrId());
+
+                // 기존 RefreshToken 삭제
+                result += delete(req, refresh);
+
+                // 신규 RefreshToken 발행
+                String newRefreshToken = jwtUtil.createJwt("refresh", mber.getMbrId(), mber.getLgnId(), mber.getMbrNm(), (List) mber.getAuthorities(), JWT_REFRESHTIME);
+                refresh.setToken(newRefreshToken);
+                result += saveRefreshToken(req, res,refresh, JWT_REFRESHTIME);
+
+                // 응답설정 RefreshToken
+    //            res.setHeader("refresh", newRefreshToken);
+                // 쿠키 방식
+                res.addCookie(jwtUtil.createCookie("refresh",newRefreshToken, COOKIE_TIME));
+            }
+            // 응답설정 AccessToken
+            res.setHeader("Authorization", newAccessToken);
+
+            return result;
+        } catch (DataAccessException dae) {
+            throw dae;
+        } catch (Exception e) {
+            throw e;
         }
-        // 응답설정 AccessToken
-        res.setHeader("Authorization", newAccessToken);
-
-        return result;
     }
-
     /**
-     * @author takensoft
-     * @since 2024.04.04
+     * @param req - HTTP 요청 객체
+     * @param refreshVO - RefreshToken 정보
+     * @return int - 토큰 삭제 결과
+     * @throws DataAccessException - db 관련 예외 발생 시
+     * @throws Exception - 그 외 예외 발생 시
+     *
      * 토큰 삭제
      */
     @Override
-    public int delete(HttpServletRequest req, RefreshVO refreshVO) throws Exception {
-        refreshVO.setUseIp(commonUtils.getIp(req));
-        return refreshTokenDAO.deleteByRefresh(refreshVO);
-    }
+    public int delete(HttpServletRequest req, RefreshVO refreshVO) {
+        try {
+            refreshVO.setUseIp(httpRequestUtil.getIp(req));
+            //중복로그인 비허용시 삭제
+            if (!redisConfig.isAllowMultipleLogin()) {
+                redisTemplate.delete("jwt:" + refreshVO.getMbrId()); // 기존 JWT 삭제
+            }
+            return refreshTokenDAO.deleteByRefresh(refreshVO);
 
+        } catch (DataAccessException dae) {
+            throw dae;
+        } catch (Exception e) {
+            throw e;
+        }
+    }
     /**
-     * @author takensoft
-     * @since 2024.04.17
-     * refresh token 등록 유무 확인
+     * @param req - HTTP 요청 객체
+     * @param refreshVO - RefreshToken 정보
+     * @return boolean - refresh token 등록 여부
+     * @throws DataAccessException - db 관련 예외 발생 시
+     * @throws Exception - 그 외 예외 발생 시
+     *
+     * refresh token 등록 여부 확인
      */
     @Override
-    public boolean findByCheckRefresh(HttpServletRequest req, RefreshVO refreshVO) throws Exception {
-        // 사용중인 아이피
-        refreshVO.setUseIp(commonUtils.getIp(req));
-        return refreshTokenDAO.findByCheckRefresh(refreshVO);
+    public boolean findByCheckRefresh(HttpServletRequest req, RefreshVO refreshVO)  {
+        try {
+            // 사용중인 아이피
+            refreshVO.setUseIp(httpRequestUtil.getIp(req));
+            return refreshTokenDAO.findByCheckRefresh(refreshVO);
+        } catch (DataAccessException dae) {
+            throw dae;
+        } catch (Exception e) {
+            throw e;
+        }
     }
 
 }
src/main/java/com/takensoft/cms/mber/service/LgnHstryService.java
--- src/main/java/com/takensoft/cms/mber/service/LgnHstryService.java
+++ src/main/java/com/takensoft/cms/mber/service/LgnHstryService.java
@@ -1,28 +1,36 @@
 package com.takensoft.cms.mber.service;
 
 import com.takensoft.cms.mber.vo.LgnHstryVO;
+import org.springframework.dao.DataAccessException;
 
 import java.util.HashMap;
-
 /**
- * @author  : takensoft
- * @since   : 2024.04.09
+ * @author 박정하
+ * @since 2024.04.09
+ * @modification
+ *     since    |    author    | description
+ *  2024.04.09  |    박정하     | 최초 등록
  *
- * 로그인 이력 정보 관련 인터페이스
+ * 로그인 이력 관련 인터페이스
  */
 public interface LgnHstryService {
-    /**
-     * @author takensoft
-     * @since 2024.04.09
-     * 로그인 이력 등록
-     */
-    public int LgnHstrySave(LgnHstryVO lgnHstryVO) throws Exception;
 
     /**
-     * @author  : 박정하
-     * @since   : 2024.05.13
+     * @param lgnHstryVO - 로그인 이력 정보
+     * @return int - 로그인 이력 결과
+     *
+     * 로그인 이력 등록
+     */
+    public int LgnHstrySave(LgnHstryVO lgnHstryVO);
+
+    /**
+     * @param params -회원정보
+     * @return HashMap<String, Object>
+     *  - list : 로그인 이력 목록
+     *  - pagination : 페이징 정보
+     *  - codeList : 공통 코드 조회(로그인이력)
      *
      * 로그인 이력 목록 조회
      */
-    public HashMap<String, Object> lgnHstryList(HashMap<String, String> params) throws Exception;
+    public HashMap<String, Object> lgnHstryList(HashMap<String, String> params);
 }
(파일 끝에 줄바꿈 문자 없음)
src/main/java/com/takensoft/cms/mber/service/MberService.java
--- src/main/java/com/takensoft/cms/mber/service/MberService.java
+++ src/main/java/com/takensoft/cms/mber/service/MberService.java
@@ -5,48 +5,61 @@
 import com.takensoft.cms.mber.vo.MberVO;
 
 import jakarta.servlet.http.HttpServletRequest;
-import java.util.*;
+import org.springframework.dao.DataAccessException;
 
+import java.util.*;
 /**
- * @author  : takensoft
- * @since   : 2024.04.01
+ * @author takensoft
+ * @since 2024.04.01
+ * @modification
+ *     since    |    author    | description
+ *  2024.04.01  |  takensoft   | 최초 등록
  *
  * 회원 정보 관련 인터페이스
  */
 public interface MberService {
+
     /**
-     * @author takensoft
-     * @since 2024.04.03
+     * @param lgnId - 로그인 아이디
+     * @return boolean - 아이디 아이디 중복 여부
      *
      * 아이디 중복 검사
      */
-    public boolean findByCheckLoginId(String lgnId) throws  Exception;
+    public boolean findByCheckLoginId(String lgnId);
 
     /**
-     * @author takensoft
-     * @since 2024.04.03
+     * @param req - HTTP 요청 객체
+     * @param joinDTO -회원정보
+     * @return HashMap<String, Object> - 회원정보 등록 결과
+     *  - mbrId : 회원 아이디
+     *  - result : 회원등록정보 결과
+     *
      * 회원가입
      */
-    public HashMap<String, Object> userJoin(HttpServletRequest req, JoinDTO joinDTO) throws Exception;
+    public HashMap<String, Object> userJoin(HttpServletRequest req, JoinDTO joinDTO);
 
     /**
-     * @author takensoft
-     * @since 2024.04.15
+     * @param passwordDTO - 비밀번호
+     * @return boolean - 비밀번호 사용 가능 여부
+     *
      * 비밀번호 비교
      */
-    public boolean passwordCheck(PasswordDTO passwordDTO) throws Exception;
+    public boolean passwordCheck(PasswordDTO passwordDTO);
 
     /**
-     * @author 박정하
-     * @since 2024.04.23
+     * @param params
+     *  - 회원 아이디
+     * @return MberVO - 회원 정보
+     *
      * 회원정보 상세 조회
      */
-    public MberVO findByMbr(HashMap<String, Object> params) throws Exception;
+    public MberVO findByMbr(HashMap<String, Object> params);
 
     /**
-     * @author takensoft
-     * @since 2024.04.24
+     * @param passwordDTO - 비밀번호
+     * @return int - 비밀번호 수정 결과
+     *
      * 비밀번호 수정
      */
-    public int updatePassword(PasswordDTO passwordDTO) throws Exception;
+    public int updatePassword(PasswordDTO passwordDTO);
 }
(파일 끝에 줄바꿈 문자 없음)
src/main/java/com/takensoft/cms/mber/service/RefreshTokenService.java
--- src/main/java/com/takensoft/cms/mber/service/RefreshTokenService.java
+++ src/main/java/com/takensoft/cms/mber/service/RefreshTokenService.java
@@ -4,47 +4,63 @@
 
 import jakarta.servlet.http.HttpServletRequest;
 import jakarta.servlet.http.HttpServletResponse;
+import org.springframework.dao.DataAccessException;
 
 /**
- * @author  : takensoft
- * @since   : 2024.04.01
+ * @author takensoft
+ * @since 2024.04.01
+ * @modification
+ *     since    |    author    | description
+ *  2024.04.01  |  takensoft   | 최초 등록
  *
  * RefreshToken 정보 관련 인터페이스
  */
 public interface RefreshTokenService {
 
     /**
-     * @author takensoft
-     * @since 2024.04.04
+     * @param req - HTTP 요청 객체
+     * @param res - HTTP 응답 객체
+     * @param refresh - RefreshToken 정보
+     * @param expiredMs - 토큰 만료 시간 (밀리초)
+     * @return int - refresh token 등록결과
+     *
      * refresh token 등록
      */
-    public int saveRefreshToken(HttpServletRequest req, HttpServletResponse res, RefreshVO refresh, long expiredMs) throws Exception;
+    public int saveRefreshToken(HttpServletRequest req, HttpServletResponse res, RefreshVO refresh, long expiredMs);
 
     /**
-     * @author takensoft
-     * @since 2024.04.04
-     * refresh token 삭제 프로세스
+     * @param req - HTTP 요청 객체
+     * @param res - HTTP 응답 객체
+     * @return int - refresh token 삭제 결과
+     *
+     * refresh token 삭제 프로세스 (로그아웃)
      */
-    public int deleteByRefresh(HttpServletRequest req, HttpServletResponse res) throws Exception;
+    public int deleteByRefresh(HttpServletRequest req, HttpServletResponse res);
 
     /**
-     * @author takensoft
-     * @since 2024.04.04
+     * @param req - HTTP 요청 객체
+     * @param res - HTTP 응답 객체
+     * @return int - 토큰 재발급 결과
+     *
      * 토큰 재발급
      */
-    public int tokenReissueProc(HttpServletRequest req, HttpServletResponse res) throws Exception;
+    public int tokenReissueProc(HttpServletRequest req, HttpServletResponse res);
 
     /**
-     * @author takensoft
-     * @since 2024.04.04
+     * @param req - HTTP 요청 객체
+     * @param refreshVO - RefreshToken 정보
+     * @return int - 토큰 삭제 결과
+     *
      * 토큰 삭제
      */
-    public int delete(HttpServletRequest req, RefreshVO refreshVO) throws Exception;
+    public int delete(HttpServletRequest req, RefreshVO refreshVO);
 
     /**
-     * @author takensoft
-     * @since 2024.04.17
-     * refresh token 등록 유무 확인
+     * @param req - HTTP 요청 객체
+     * @param refreshVO - RefreshToken 정보
+     * @return boolean - refresh token 등록 여부
+     *
+     * refresh token 등록 여부 확인
      */
-    public boolean findByCheckRefresh(HttpServletRequest req, RefreshVO refreshVO) throws Exception;
+    public boolean findByCheckRefresh(HttpServletRequest req, RefreshVO refreshVO);
 }
src/main/java/com/takensoft/cms/mber/vo/LgnHstryVO.java
--- src/main/java/com/takensoft/cms/mber/vo/LgnHstryVO.java
+++ src/main/java/com/takensoft/cms/mber/vo/LgnHstryVO.java
@@ -1,10 +1,12 @@
 package com.takensoft.cms.mber.vo;
 
 import lombok.*;
-
 /**
  * @author  : takensoft
  * @since   : 2024.04.01
+ * @modification
+ *     since    |    author    | description
+ *  2024.04.01  |  takensoft   | 최초 등록
  *
  * 로그인 이력 정보 관련 VO
  */
@@ -16,32 +18,11 @@
 @NoArgsConstructor
 public class LgnHstryVO {
 
-    /**
-     * 로그인 아이디
-     */
-    private String lgnId;
-    /**
-     * 로그인 유형
-     */
-    private String lgnType;
-    /**
-     * 접속일
-     */
-    private String cntnDt;
-    /**
-     * 접속 아이피
-     */
-    private String cntnIp;
-    /**
-     * 접속 운영체제
-     */
-    private String cntnOperSys;
-    /**
-     * 디바이스명
-     */
-    private String deviceNm;
-    /**
-     * 브라우저명
-     */
-    private String brwsrNm;
+    private String lgnId;       // 로그인 아이디
+    private String lgnType;     // 로그인 유형
+    private String cntnDt;      // 접속일
+    private String cntnIp;      // 접속 아이피
+    private String cntnOperSys; // 접속 운영체제
+    private String deviceNm;    // 디바이스명
+    private String brwsrNm;     // 브라우저명
 }
src/main/java/com/takensoft/cms/mber/vo/MberAuthorVO.java
--- src/main/java/com/takensoft/cms/mber/vo/MberAuthorVO.java
+++ src/main/java/com/takensoft/cms/mber/vo/MberAuthorVO.java
@@ -3,10 +3,13 @@
 import lombok.*;
 
 /**
- * @author  : takensoft
- * @since   : 2024.04.01
+ * @author takensoft
+ * @since 2025.01.22
+ * @modification
+ *     since    |    author    | description
+ *  2025.01.22  |  takensoft   | 최초 등록
  *
- * 회원 권한 정보 관련 VO
+ * 사용자 권한 관련 VO
  */
 @Getter
 @Setter
@@ -15,24 +18,19 @@
 @AllArgsConstructor
 @NoArgsConstructor
 public class MberAuthorVO {
-    /**
-     * 회원 아이디
-     */
-    private String mbrId;
-    /**
-     * 권한명
-     */
-    private String authrtNm;
-    /**
-     * 권한 코드
-     */
-    private String authrtCd;
-    /**
-     * 등록자
-     */
-    private String rgtr;
-    /**
-     * 등록일
-     */
-    private String regDt;
+
+    private String mbrId;       // 회원 아이디
+    private String authrtNm;    // 권한명
+    private String authrtCd;    // 권한 코드
+    private String rgtr;        // 등록자
+    private String regDt;       // 등록일
+    public MberAuthorVO(String authrtCd) {
+        this.authrtCd = authrtCd;
+    } // 생성자
+
+    public MberAuthorVO(String mbrId, String authrtCd, String rgtr) {
+        this.mbrId = mbrId;
+        this.authrtCd = authrtCd;
+        this.rgtr = rgtr;
+    }
 }
(파일 끝에 줄바꿈 문자 없음)
src/main/java/com/takensoft/cms/mber/vo/MberVO.java
--- src/main/java/com/takensoft/cms/mber/vo/MberVO.java
+++ src/main/java/com/takensoft/cms/mber/vo/MberVO.java
@@ -14,15 +14,18 @@
 import java.util.Collection;
 import java.util.List;
 import java.util.stream.Collectors;
-
 /**
  * @author  : takensoft
  * @since   : 2024.04.01
+ * @modification
+ *     since    |    author    | description
+ *  2024.04.01  |  takensoft   | 최초 등록
  *
  * 회원 정보 관련 VO
  * UserDetails : security 사용을 위해 상속
  * Serializable : 직렬화를 위해 상속
  */
+
 @Setter
 @Getter
 @NoArgsConstructor
@@ -31,121 +34,34 @@
 
     private static final long serialVersionUID = 1L;
 
-    /**
-     * 회원 아이디
-     */
-    private String mbrId;
-    /**
-     * 로그인 아이디
-     */
-    private String lgnId;
-    /**
-     * 회원 이름
-     */
-    private String mbrNm;
-    /**
-     * 닉네임
-     */
-    private String ncnm;
-    /**
-     * 비밀번호
-     */
-    private String pswd;
-    /**
-     * 휴대폰번호
-     */
-    private String mblTelno;
-    /**
-     * 전화번호
-     */
-    private String telno;
-    /**
-     * 이메일
-     */
-    private String eml;
-    /**
-     * 우편번호
-     */
-    private String zip;
-    /**
-     * 주소
-     */
-    private String addr;
-    /**
-     * 상세주소
-     */
-    private String daddr;
-    /**
-     * 회원상태
-     * 0: 탈퇴, 1: 승인, 2: 승인대기, 3: 차단
-     */
-    private String mbrStts;
-    /**
-     * 사용여부
-     */
-    private boolean useYn;
-    /**
-     * 차단일
-     */
-    private String cntrlDt;
-    /**
-     * 차단사유
-     */
-    private String cntrlRsn;
-    /**
-     * 문자수신여부
-     * 0: 거부, 1: 허용
-     */
-    private String smsRcptnAgreYn;
-    /**
-     * 이메일수신여부
-     * 0: 거부, 1: 허용
-     */
-    private String emlRcptnAgreYn;
-    /**
-     * 개인정보공개여부
-     * 0: 거부, 1: 허용
-     */
-    private String prvcRlsYn;
-    /**
-     * 회원형태
-     * S: 시스템, K: 카카오, N: 네이버, G: 구글, F: 페이스북
-     */
-    private String mbrType;
-    /**
-     * 비밀번호 변경일
-     */
-    private String pswdChgDt;
-    /**
-     * 최초등록 아이디
-     */
-    private String frstRegIp;
-    /**
-     * 시스템 제공 여부 -> 시스템에서 제공되는 데이터는 사용자가 제거하지 못하도록 하기 위한 설정값
-     * 0: 시스템, 1: 사용자
-     */
-    private String sysPvsnYn;
-    /**
-     * 등록자
-     */
-    private String rgtr;
-    /**
-     * 등록일
-     */
-    private String regDt;
-    /**
-     * 수정자
-     */
-    private String mdfr;
-    /**
-     * 수정일
-     */
-    private String mdfcnDt;
-    /**
-     * 권한 정보
-     */
+    private String mbrId;           // 회원 아이디
+    private String lgnId;           // 로그인 아이디
+    private String mbrNm;           // 회원 이름
+    private String ncnm;            // 닉네임
+    private String pswd;            // 비밀번호
+    private String mblTelno;        // 휴대폰번호
+    private String telno;           // 전화번호
+    private String eml;             // 이메일
+    private String zip;             // 우편번호
+    private String addr;            // 주소
+    private String daddr;           // 상세주소
+    private String mbrStts;         // 회원상태 0: 탈퇴, 1: 승인, 2: 승인대기, 3: 차단
+    private boolean useYn;          // 사용여부
+    private String cntrlDt;         // 차단일
+    private String cntrlRsn;        // 차단사유
+    private String smsRcptnAgreYn;  // 문자수신여부 0: 거부, 1: 허용
+    private String emlRcptnAgreYn;  // 이메일수신여부 0: 거부, 1: 허용
+    private String prvcRlsYn;       // 개인정보공개여부 0: 거부, 1: 허용
+    private String mbrType;         // 회원형태 S: 시스템, K: 카카오, N: 네이버, G: 구글, F: 페이스북
+    private String pswdChgDt;       // 비밀번호 변경일
+    private String frstRegIp;       // 최초등록 아이디
+    private String sysPvsnYn;       // 시스템 제공 여부 -> 시스템에서 제공되는 데이터는 사용자가 제거하지 못하도록 하기 위한 설정값 0: 시스템, 1: 사용자
+    private String rgtr;            // 등록자
+    private String regDt;           // 등록일
+    private String mdfr;            // 수정자
+    private String mdfcnDt;         // 수정일
     @JsonIgnore
-    private List<MberAuthorVO> authorList = new ArrayList<MberAuthorVO>();
+    private List<MberAuthorVO> authorList = new ArrayList<MberAuthorVO>();  // 권한 정보
 
     @Override
     public Collection<? extends GrantedAuthority> getAuthorities() {
@@ -187,4 +103,22 @@
     public boolean isEnabled() {
         return this.useYn;
     }
+
+    // JWT 필터용 생성자
+    public MberVO(String mbrId, String lgnId, List<MberAuthorVO> authorList) {
+        this.mbrId = mbrId;
+        this.lgnId = lgnId;
+        this.authorList = authorList;
+    }
+    // 토큰 재발행용
+    public MberVO(String mbrId, String lgnId, String mbrNm, List<MberAuthorVO> authorList) {
+        this.mbrId = mbrId;
+        this.lgnId = lgnId;
+        this.mbrNm = mbrNm;
+        this.authorList = authorList;
+    }
+
+
+
+
 }
src/main/java/com/takensoft/cms/mber/vo/RefreshVO.java
--- src/main/java/com/takensoft/cms/mber/vo/RefreshVO.java
+++ src/main/java/com/takensoft/cms/mber/vo/RefreshVO.java
@@ -6,10 +6,12 @@
 import lombok.Setter;
 
 import java.util.Date;
-
 /**
  * @author  : takensoft
  * @since   : 2024.04.01
+ * @modification
+ *     since    |    author    | description
+ *  2024.04.01  |  takensoft   | 최초 등록
  *
  * RefreshToken 정보 관련 VO
  */
@@ -18,20 +20,9 @@
 @NoArgsConstructor
 @AllArgsConstructor
 public class RefreshVO {
-    /**
-     * 회원 아이디
-     */
-    private String mbrId;
-    /**
-     * 토큰
-     */
-    private String token;
-    /**
-     * 만료기간 expry_dt expryYmd
-     */
-    private Date expryDt;
-    /**
-     * 사용중인 아이피
-     */
-    private String useIp;
+
+    private String mbrId; // 회원 아이디
+    private String token; // 토큰
+    private Date expryDt; // 만료기간
+    private String useIp; // 사용중인 아이피
 }
src/main/java/com/takensoft/cms/mber/web/AdmMbrController.java
--- src/main/java/com/takensoft/cms/mber/web/AdmMbrController.java
+++ src/main/java/com/takensoft/cms/mber/web/AdmMbrController.java
@@ -11,6 +11,7 @@
 import com.takensoft.common.util.ResponseData;
 import com.takensoft.common.util.ResponseUtil;
 import lombok.RequiredArgsConstructor;
+import org.springframework.dao.DataAccessException;
 import org.springframework.http.HttpHeaders;
 import org.springframework.http.HttpStatus;
 import org.springframework.http.MediaType;
@@ -41,17 +42,15 @@
     private final AdmMbrService admMbrService;
     private final MberService mbrService;
     private final ResponseUtil resUtil;
+
     /**
-     * @author 박정하
-     * @since 2024.06.21
-     * @param params
-     * @return
-     * @throws Exception
+     * @param params - 회원정보
+     * @return ResponseEntity - 회원정보 목록 조회 응답 결과
      *
      * 회원정보 목록 조회
      */
     @PostMapping(value = "/listProc.json")
-    public ResponseEntity<?> listProc(@RequestBody HashMap<String, String> params) throws Exception {
+    public ResponseEntity<?> listProc(@RequestBody HashMap<String, String> params){
         HashMap<String, Object> result = admMbrService.mbrList(params);
 
         // 응답 처리
@@ -59,16 +58,14 @@
     }
 
     /**
-     * @author 박정하
-     * @since 2024.06.21
-     * @param resetPswd, admMbrDTO
-     * @return
-     * @throws Exception
+     * @param resetPswd - 초기화비밀번호
+     * @param admMbrDTO - 회원정보
+     * @return ResponseEntity - 회원정보 비밀번호 초기화 응답 결과
      *
      * 회원정보 비밀번호 초기화
-    */
+     */
     @PostMapping(value = "/pswdResetProc.json")
-    public ResponseEntity<?> pswdResetProc(@Value("${password.reset}") String resetPswd, @RequestBody AdmMbrDTO admMbrDTO) throws  Exception {
+    public ResponseEntity<?> pswdResetProc(@Value("${password.reset}") String resetPswd, @RequestBody AdmMbrDTO admMbrDTO){
         PasswordDTO passwordDTO = new PasswordDTO();
         passwordDTO.setMbrId(admMbrDTO.getMbrId());
         passwordDTO.setPswd(admMbrDTO.getPswd());
@@ -86,16 +83,13 @@
     }
 
     /**
-     * @author 박정하
-     * @since 2024.06.21
-     * @param admMbrDTO
-     * @return
-     * @throws Exception
+     * @param admMbrDTO - 회원정보
+     * @return ResponseEntity - 회회원정보 상세 조회 응답 결과
      *
      * 회원정보 상세 조회
      */
     @PostMapping(value = "/detailProc.json")
-    public ResponseEntity<?> detailProc(@RequestBody AdmMbrDTO admMbrDTO) throws Exception {
+    public ResponseEntity<?> detailProc(@RequestBody AdmMbrDTO admMbrDTO){
         // 상세 조회
         AdmMbrDTO result = admMbrService.mbrDetail(admMbrDTO.getMbrId());
 
@@ -104,16 +98,13 @@
     }
 
     /**
-     * @author 박정하
-     * @since 2024.06.21
-     * @param admMbrDTO
-     * @return
-     * @throws Exception
+     * @param admMbrDTO - 회원정보
+     * @return ResponseEntity - 회원정보 수정 응답 결과
      *
      * 회원정보 수정
      */
     @PostMapping(value = "/updateProc.json")
-    public ResponseEntity<?> updateProc(@RequestBody AdmMbrDTO admMbrDTO) throws Exception {
+    public ResponseEntity<?> updateProc(@RequestBody AdmMbrDTO admMbrDTO) {
         int result = admMbrService.updateMbr(admMbrDTO);
 
         // 응답 처리
@@ -125,16 +116,13 @@
     }
 
     /**
-     * @author 박정하
-     * @since 2024.06.21
-     * @param admMbrDTO
-     * @return
-     * @throws Exception
+     * @param admMbrDTO - 회원정보
+     * @return ResponseEntity - 회원정보 삭제 응답 결과
      *
      * 회원정보 삭제
      */
     @PostMapping(value = "/deleteProc.json")
-    public ResponseEntity<?> deleteProc(@RequestBody AdmMbrDTO admMbrDTO) throws Exception {
+    public ResponseEntity<?> deleteProc(@RequestBody AdmMbrDTO admMbrDTO){
         admMbrDTO.setUseYn("N"); // 회원정보 삭제
         int result = admMbrService.updateMbr(admMbrDTO);
 
@@ -145,22 +133,16 @@
             return resUtil.errorRes(MessageCode.COMMON_DELETE_FAIL);
         }
     }
-    
+
     /**
-     * @author 박정하
-     * @since 2024.06.21
-     * @param req, joinDTO
-     * @return
-     * @throws Exception
+     * @param req - HTTP 요청 객체
+     * @param joinDTO - 회원정보
+     * @return ResponseEntity - 회원정보 등록 응답 결과
      *
      * 회원정보 등록
      */
     @PostMapping(value = "/joinProc.json")
-    public ResponseEntity<?> joinProc(HttpServletRequest req, @RequestBody @Valid JoinDTO joinDTO) throws Exception {
-        // 응답 처리
-        HttpHeaders headers = new HttpHeaders();
-        headers.setContentType(new MediaType("application", "json", Charset.forName("UTF-8")));
-        ResponseData responseData = new ResponseData();
+    public ResponseEntity<?> joinProc(HttpServletRequest req, @RequestBody @Valid JoinDTO joinDTO){
 
         // 아이디 중복 검사
         boolean isExistence = mbrService.findByCheckLoginId(joinDTO.getLgnId());
@@ -178,18 +160,14 @@
             return resUtil.errorRes(MessageCode.COMMON_UNKNOWN_ERROR);
         }
     }
-
     /**
-     * @author 박정하
-     * @since 2024.07.03
-     * @param mbrVO
-     * @return
-     * @throws Exception
+     * @param mbrVO - 회원정보
+     * @return ResponseEntity - 아이디 찾기 응답 결과
      *
      * 아이디 찾기
      */
     @PostMapping(value = "/searchIdProc.json")
-    public ResponseEntity<?> searchIdProc(@RequestBody MberVO mbrVO) throws Exception {
+    public ResponseEntity<?> searchIdProc(@RequestBody MberVO mbrVO) {
         String result = admMbrService.lgnIdSearch(mbrVO);
 
         // 응답 처리
@@ -202,19 +180,15 @@
             return resUtil.errorRes(MessageCode.LOGIN_USER_NOT_FOUND);
         }
     }
-
-
     /**
-     * @author 박정하
-     * @since 2024.07.03
-     * @param admMbrDTO
-     * @return
-     * @throws Exception
+     * @param resetPswd -초기화비밀번호
+     * @param admMbrDTO -회원정보
+     * @return ResponseEntity - 비밀번호 초기화 응답 결과
      *
      * 비밀번호 초기화
      */
     @PostMapping(value = "/resetPswdProc.json")
-    public ResponseEntity<?> resetPswdProc(@Value("${password.reset}") String resetPswd, @RequestBody AdmMbrDTO admMbrDTO) throws Exception {
+    public ResponseEntity<?> resetPswdProc(@Value("${password.reset}") String resetPswd, @RequestBody AdmMbrDTO admMbrDTO){
         int result = admMbrService.mbrIdSearch(resetPswd, admMbrDTO);
 
         // 응답 처리
src/main/java/com/takensoft/cms/mber/web/LgnHstryController.java
--- src/main/java/com/takensoft/cms/mber/web/LgnHstryController.java
+++ src/main/java/com/takensoft/cms/mber/web/LgnHstryController.java
@@ -33,16 +33,13 @@
     private final ResponseUtil resUtil;
 
     /**
-     * @author 박정하
-     * @since 2024.05.13
-     * @param params
-     * @return
-     * @throws Exception
+     * @param params - 회원정보
+     * @return ResponseEntity - 로그인 이력 목록 조회 응답 결과
      *
      * 로그인 이력 목록 조회
      */
     @PostMapping("/listProc.json")
-    public ResponseEntity<?> listProc(@RequestBody HashMap<String, String> params) throws Exception {
+    public ResponseEntity<?> listProc(@RequestBody HashMap<String, String> params){
         HashMap<String, Object> result = lgnHstryService.lgnHstryList(params);
 
         // 응답 처리
src/main/java/com/takensoft/cms/mber/web/MberController.java
--- src/main/java/com/takensoft/cms/mber/web/MberController.java
+++ src/main/java/com/takensoft/cms/mber/web/MberController.java
@@ -38,34 +38,27 @@
     private final ResponseUtil resUtil;
 
     /**
-     * @author takensoft
-     * @since 2024.04.16
-     * @param
-     * @return
-     * @throws Exception
+     * @param params - 부서 아이디
+     * @return ResponseEntity - 회원정보 상세 조회 응답 결과
      *
      * 회원정보 상세 조회
      */
     @PostMapping(value = "/findByMbr.json")
-    public ResponseEntity<?> findByMbr(@RequestBody HashMap<String, Object> params) throws Exception {
+    public ResponseEntity<?> findByMbr(@RequestBody HashMap<String, Object> params){
         // 상세 조회
         MberVO result = mberService.findByMbr(params);
 
         // 응답 처리
         return resUtil.successRes(result, MessageCode.COMMON_SUCCESS);
     }
-
     /**
-     * @author takensoft
-     * @since 2024.04.15
-     * @param passwordDTO
-     * @return
-     * @throws Exception
+     * @param passwordDTO - 비밀번호
+     * @return ResponseEntity - 비밀번호 변경 결과
      *
      * 비밀번호 변경
      */
     @PostMapping(value = "/updatePassword.json")
-    public ResponseEntity<?> joinProc(@RequestBody @Valid PasswordDTO passwordDTO) throws  Exception {
+    public ResponseEntity<?> joinProc(@RequestBody @Valid PasswordDTO passwordDTO){
         // 비밀 번호 비교
         boolean isExistence = mberService.passwordCheck(passwordDTO);
 
src/main/java/com/takensoft/cms/mber/web/RefreshTokenController.java
--- src/main/java/com/takensoft/cms/mber/web/RefreshTokenController.java
+++ src/main/java/com/takensoft/cms/mber/web/RefreshTokenController.java
@@ -36,19 +36,15 @@
     private final RefreshTokenService refreshTokenService;
 
     /**
-     * @author takensoft
-     * @since 2024.04.04
-     * @return
-     * @throws Exception
+     * @param req - HTTP 요청 객체
+     * @param res - HTTP 응답 객체
+     * @return ResponseEntity - 로그아웃 응답 결과
+     *
      * 로그아웃
      */
     @PostMapping(value = "/mbr/logout.json")
-    public ResponseEntity<?> logout(HttpServletRequest req, HttpServletResponse res) throws Exception {
+    public ResponseEntity<?> logout(HttpServletRequest req, HttpServletResponse res){
         int result = refreshTokenService.deleteByRefresh(req, res);
-        // 응답 처리
-        HttpHeaders headers = new HttpHeaders();
-        headers.setContentType(new MediaType("application", "json", Charset.forName("UTF-8")));
-        ResponseData responseData = new ResponseData();
         if(result > 0) {
             Cookie cookie = new Cookie("refresh", null);
             cookie.setMaxAge(0); // 생명주기
@@ -63,14 +59,14 @@
     }
 
     /**
-     * @author takensoft
-     * @since 2024.04.04
-     * @return
-     * @throws Exception
+     * @param req - HTTP 요청 객체
+     * @param res - HTTP 응답 객체
+     * @return ResponseEntity - 토큰 재발급 응답 결과
+     *
      * 토큰 재발급
      */
     @PostMapping("/refresh/tokenReissue.json")
-    public ResponseEntity<?> tokenReissue(HttpServletRequest req, HttpServletResponse res) throws Exception {
+    public ResponseEntity<?> tokenReissue(HttpServletRequest req, HttpServletResponse res) {
         int result = refreshTokenService.tokenReissueProc(req, res);
 
         // 응답 처리
src/main/java/com/takensoft/cms/popup/service/Impl/PopupServiceImpl.java
--- src/main/java/com/takensoft/cms/popup/service/Impl/PopupServiceImpl.java
+++ src/main/java/com/takensoft/cms/popup/service/Impl/PopupServiceImpl.java
@@ -21,8 +21,6 @@
 import org.springframework.transaction.annotation.Transactional;
 import org.springframework.web.multipart.MultipartFile;
 
-import java.io.IOException;
-import java.net.UnknownHostException;
 import java.util.*;
 
 /**
src/main/java/com/takensoft/cms/popup/web/PopupController.java
--- src/main/java/com/takensoft/cms/popup/web/PopupController.java
+++ src/main/java/com/takensoft/cms/popup/web/PopupController.java
@@ -16,8 +16,6 @@
 import org.springframework.web.bind.annotation.*;
 import org.springframework.web.multipart.MultipartFile;
 
-import java.net.UnknownHostException;
-import java.nio.charset.Charset;
 import java.util.*;
 
 /**
src/main/java/com/takensoft/cms/prvcInqHstry/service/Impl/PrvcInqHstryServiceImpl.java
--- src/main/java/com/takensoft/cms/prvcInqHstry/service/Impl/PrvcInqHstryServiceImpl.java
+++ src/main/java/com/takensoft/cms/prvcInqHstry/service/Impl/PrvcInqHstryServiceImpl.java
@@ -2,14 +2,12 @@
 
 import com.takensoft.cms.codeManage.service.CodeManageService;
 import com.takensoft.cms.codeManage.vo.CodeManageVO;
-import com.takensoft.cms.popup.vo.PopupVO;
 import com.takensoft.cms.prvcInqHstry.dao.PrvcInqHstryDAO;
 import com.takensoft.cms.prvcInqHstry.service.PrvcInqHstryService;
 import com.takensoft.cms.prvcInqHstry.vo.PrvcInqHstryVO;
 import com.takensoft.common.Pagination;
 import com.takensoft.common.exception.CustomInsertFailException;
-import com.takensoft.common.exception.CustomNotFoundException;
-import com.takensoft.common.util.CommonUtils;
+import com.takensoft.common.util.HttpRequestUtil;
 import com.takensoft.common.util.JWTUtil;
 import lombok.RequiredArgsConstructor;
 import org.egovframe.rte.fdl.cmmn.EgovAbstractServiceImpl;
@@ -40,7 +38,7 @@
 public class PrvcInqHstryServiceImpl extends EgovAbstractServiceImpl implements PrvcInqHstryService {
 
     private final JWTUtil jwtUtil;
-    private final CommonUtils commonUtils;
+    private final HttpRequestUtil httpRequestUtil;
     private final PrvcInqHstryDAO prvcInqHstryDAO;
     private final CodeManageService codeManageService;
 
@@ -51,7 +49,6 @@
      * @throws CustomInsertFailException - 등록 실패 예외 발생 시
      * @throws DataAccessException - 데이터베이스 접근 예외 발생 시
      * @throws NullPointerException - Null 값이 발생할 경우
-     * @throws UnknownHostException - 호스트의 IP정보를 알 수 없는 경우
      * @throws Exception - 그 외 예외 발생 시
      *
      * 개인정보 조회 이력 등록
@@ -59,7 +56,7 @@
     public int prvcInqHstryInsert(HttpServletRequest request, PrvcInqHstryVO prvcInqHstryVO) {
         try {
             // 조회 아이피 삽입
-            String ipAdd = commonUtils.getIp(request);
+            String ipAdd = httpRequestUtil.getIp(request);
             prvcInqHstryVO.setInqIp(ipAdd);
 
             // 조회자 삽입
@@ -74,8 +71,6 @@
             throw dae;
         } catch (NullPointerException ne) {
             throw ne;
-        } catch (UnknownHostException ukhe) {
-            throw new RuntimeException("호스트의 IP정보를 알 수가 없습니다.", ukhe);
         } catch (Exception e) {
             throw e;
         }
src/main/java/com/takensoft/common/config/CommonConfig.java
--- src/main/java/com/takensoft/common/config/CommonConfig.java
+++ src/main/java/com/takensoft/common/config/CommonConfig.java
@@ -12,10 +12,23 @@
 import org.springframework.context.annotation.Configuration;
 import org.springframework.util.AntPathMatcher;
 import org.springframework.web.servlet.view.json.MappingJackson2JsonView;
-
+/**
+ * @author takensoft
+ * @since 2025.01.22
+ * @modification
+ *     since    |    author    | description
+ *  2025.01.22  |  takensoft   | 최초 등록
+ *
+ * 기본 설정을 위한 Config
+ */
 @Configuration
 public class CommonConfig {
 
+    /**
+     * @return MappingJackson2JsonView - JSON 응답을 위한 뷰 객체
+     *
+     * JSON 응답을 반환할 때 사용하는 Jackson ObjectMapper를 설정하여, 모델에서 값을 추출하는 방식으로 JSON 응답을 생성
+     */
     @Bean(name="jsonView")
     public MappingJackson2JsonView getJsonView () {
         ObjectMapper objectMapper = getObjectMapper();
@@ -23,7 +36,12 @@
         jsonView.setExtractValueFromSingleKeyModel(true);
         return jsonView;
     }
-
+    /**
+     * @return ObjectMapper - JSON 직렬화 및 역직렬화를 위한 객체
+     *
+     * Java Time API를 위한 모듈을 등록하고, 날짜 포맷을 설정하는 등 ObjectMapper를 커스터마이즈하여 JSON 변환
+     *
+     */
     @Bean(name = "objectMapper")
     public ObjectMapper getObjectMapper() {
         ObjectMapper mapper = new ObjectMapper();
@@ -39,17 +57,29 @@
 
         return mapper;
     }
-
+    /**
+     * @return AntPathMatcher - 경로 패턴 매칭을 위한 객체
+     *
+     * 경로 패턴을 매칭하여 URL 경로를 처리하는 데 사용되는 객체를 반환
+     */
     @Bean
     public AntPathMatcher antPathMatcher() {
         return new AntPathMatcher();
     }
-
+    /**
+     * @return DefaultTraceHandler - 추적 처리를 위한 기본 핸들러
+     *
+     * 추적 요청을 처리하는 기본 핸들러를 반환
+     */
     @Bean
     public DefaultTraceHandler defaultTraceHandler() {
         return new DefaultTraceHandler();
     }
-
+    /**
+     * @return DefaultTraceHandleManager - 추적 핸들러 관리 서비스 객체
+     *
+     * 여러 추적 핸들러와 경로 매칭 설정을 관리하는 서비스를 제공
+     */
     @Bean
     public DefaultTraceHandleManager traceHandlerService() {
         DefaultTraceHandleManager defaultTraceHandleManager = new DefaultTraceHandleManager();
@@ -58,7 +88,11 @@
         defaultTraceHandleManager.setHandlers(new TraceHandler[]{defaultTraceHandler()});
         return defaultTraceHandleManager;
     }
-
+    /**
+     * @return LeaveaTrace - 추적 기능을 위한 LeaveaTrace 객체
+     *
+     * 추적 핸들러 서비스를 설정하여 추적 기능을 활성화
+     */
     @Bean
     public LeaveaTrace leaveaTrace() {
         LeaveaTrace leaveaTrace = new LeaveaTrace();
@@ -66,4 +100,6 @@
         return leaveaTrace;
     }
 
+
+
 }
src/main/java/com/takensoft/common/config/CorsMvcConfig.java
--- src/main/java/com/takensoft/common/config/CorsMvcConfig.java
+++ src/main/java/com/takensoft/common/config/CorsMvcConfig.java
@@ -1,22 +1,58 @@
 package com.takensoft.common.config;
 
 import org.springframework.beans.factory.annotation.Value;
+import org.springframework.context.annotation.Bean;
 import org.springframework.context.annotation.Configuration;
+import org.springframework.web.servlet.LocaleResolver;
 import org.springframework.web.servlet.config.annotation.CorsRegistry;
 import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
+import org.springframework.web.servlet.i18n.AcceptHeaderLocaleResolver;
 
+import java.util.Locale;
+
+/**
+ * @author  : takensoft
+ * @since   : 2025.01.22
+ * @modification
+ *     since    |    author    | description
+ *  2025.01.22  |  takensoft   | 최초 등록
+ *
+ * WebMvcConfigurer - pring MVC에서 제공하는 인터페이스 ( Spring의 기본 설정을 커스터마이징하는 데 사용 )
+ *
+ * CORS(Cross-Origin Resource Sharing) 설정을 위한 Config
+ */
 @Configuration
 public class CorsMvcConfig implements WebMvcConfigurer {
 
     private static String FRONT_URL; // 프론트 경로
+    /**
+     * @param value - 프론트 경로 (application.yml에서 값을 읽어 옴)
+     *
+     * 프론트엔드 URL을 설정
+     */
     @Value("${front.url}")
     public void setFrontUrl(String value) {
         FRONT_URL = value;
     }
-
+    /**
+     * @param corsRegistry - CORS 매핑을 관리하는 객체
+     *
+     * CORS 매핑 설정을 추가
+     */
     @Override
     public void addCorsMappings(CorsRegistry corsRegistry) {
         corsRegistry.addMapping("/**")
                 .allowedOrigins(FRONT_URL);
     }
+    /**
+     * @return LocaleResolver 객체 (기본 로케일을 한국으로 설정)
+     *
+     * 다국어 지원을 위한 LocaleResolver
+     */
+    @Bean
+    public LocaleResolver localeResolver() {
+        AcceptHeaderLocaleResolver resolver = new AcceptHeaderLocaleResolver();
+        resolver.setDefaultLocale(Locale.KOREA);
+        return resolver;
+    }
 }
(파일 끝에 줄바꿈 문자 없음)
 
src/main/java/com/takensoft/common/config/RedisConfig.java (added)
+++ src/main/java/com/takensoft/common/config/RedisConfig.java
@@ -0,0 +1,65 @@
+package com.takensoft.common.config;
+
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.data.redis.connection.RedisConnectionFactory;
+import org.springframework.data.redis.connection.lettuce.LettuceConnectionFactory;
+import org.springframework.data.redis.core.RedisTemplate;
+import org.springframework.data.redis.serializer.StringRedisSerializer;
+
+/**
+ * @author takensoft
+ * @since 2025.03.12
+ * @modification
+ *     since    |    author    | description
+ *  2025.03.12  |  takensoft   | 최초 등록
+ *
+ * redis 설정을 위한 Config
+ */
+
+@Configuration
+public class RedisConfig {
+
+    @Value("${redis.host}")
+    private String redisHost;
+    @Value("${redis.port}")
+    private int redisPort;
+
+    @Value("${config.allow-multiple-logins}") // 기본값 false (중복 로그인 비허용)
+    private boolean allowMultipleLogin;
+
+    @Bean
+    @ConditionalOnProperty(name = "config.allow-multiple-logins", havingValue = "false", matchIfMissing = true) //redis 사용 안 할 경우 빈 등록x
+    public RedisConnectionFactory redisConnectionFactory() {
+        return new LettuceConnectionFactory(redisHost, redisPort);
+    }
+    @Bean
+    @ConditionalOnProperty(name = "config.allow-multiple-logins", havingValue = "false", matchIfMissing = true) //redis 사용 안 할 경우 빈 등록x
+    public RedisTemplate<String, String> redisTemplate(RedisConnectionFactory redisConnectionFactory) {
+        RedisTemplate<String, String> redisTemp = new RedisTemplate<>();
+        redisTemp.setConnectionFactory(redisConnectionFactory);
+        redisTemp.setKeySerializer(new StringRedisSerializer());
+        redisTemp.setValueSerializer(new StringRedisSerializer());
+        return redisTemp;
+    }
+
+    /**
+     * @return allowMultipleLogin - 중복로그인 허용/비허용 반환
+     *
+     * 중복 로그인 허용 여부를 반환하는 메서드
+     */
+    public boolean isAllowMultipleLogin() {
+        return allowMultipleLogin;
+    }
+    /**
+     * @return allowMultipleLogin - 중복로그인 허용/비허용 반환
+     *
+     * 관리자가 설정을 변경할 수 있도록 Setter 추가
+     */
+    public void setAllowMultipleLogin(boolean allowMultipleLogin) {
+        this.allowMultipleLogin = allowMultipleLogin;
+    }
+
+}
src/main/java/com/takensoft/common/config/SecurityConfig.java
--- src/main/java/com/takensoft/common/config/SecurityConfig.java
+++ src/main/java/com/takensoft/common/config/SecurityConfig.java
@@ -6,13 +6,14 @@
 import com.takensoft.common.filter.AccesFilter;
 import com.takensoft.common.filter.JWTFilter;
 import com.takensoft.common.filter.LoginFilter;
-import com.takensoft.common.util.CommonUtils;
+import com.takensoft.common.util.HttpRequestUtil;
 import com.takensoft.common.exception.CustomAccessDenieHandler;
 import com.takensoft.common.exception.CustomAuthenticationEntryPoint;
 import com.takensoft.common.util.JWTUtil;
 import org.springframework.beans.factory.annotation.Value;
 import org.springframework.context.annotation.Bean;
 import org.springframework.context.annotation.Configuration;
+import org.springframework.data.redis.core.RedisTemplate;
 import org.springframework.security.authentication.AuthenticationManager;
 import org.springframework.security.config.annotation.authentication.configuration.AuthenticationConfiguration;
 import org.springframework.security.config.annotation.web.builders.HttpSecurity;
@@ -29,9 +30,12 @@
 
 /**
  * @author takensoft
- * @since 2024.04.01
- * 
- * 스프링 시큐리티 설정
+ * @since 2025.01.22
+ * @modification
+ *     since    |    author    | description
+ *  2025.01.22  |  takensoft   | 최초 등록
+ *
+ * Spring Security 설정을 위한 Config
  */
 @Configuration
 @EnableWebSecurity
@@ -45,17 +49,33 @@
     private final AccesCtrlService accesCtrlService;
     private final CustomAuthenticationEntryPoint authenticationEntryPoint;
     private final CustomAccessDenieHandler accessDenieHandler;
-    private final CommonUtils commonUtils;
+    private final HttpRequestUtil httpRequestUtil;
     private final CommonConfig commonConfig;
+    private final RedisConfig redisConfig;
 
     private static String FRONT_URL;    // 프론트 접근 허용 URL
     private static long JWT_ACCESSTIME; // access 토큰 유지 시간
     private static long JWT_REFRESHTIME; // refresh 토큰 유지 시간
     private static int COOKIE_TIME; // 쿠키 유지 시간
 
-    public SecurityConfig(AuthenticationConfiguration authenticationConfiguration, JWTUtil jwtUtil, RefreshTokenService refreshTokenService, AccesCtrlService accesCtrlService, CommonConfig commonConfig,
-                          LgnHstryService lgnHstryService, CustomAuthenticationEntryPoint authenticationEntryPoint, CustomAccessDenieHandler accessDenieHandler, CommonUtils commonUtils,
-                          @Value("${front.url}")String fUrl,@Value("${jwt.accessTime}")long aTime, @Value("${jwt.refreshTime}")long rTime, @Value("${cookie.time}")int ctime) {
+    private final RedisTemplate<String, String> redisTemplate;
+
+    /**
+     * @param fUrl - 프론트엔드 URL (application.yml에서 값을 읽어 옴)
+     * @param aTime - JWT 접근 토큰 유효 시간 (application.yml에서 값을 읽어 옴)
+     * @param rTime - JWT 리프레시 토큰 유효 시간 (application.yml에서 값을 읽어 옴)
+     * @param ctime - 쿠키 유효 시간 (application.yml에서 값을 읽어 옴)
+     * @param authenticationConfiguration - 인증 구성 객체
+     * @param authenticationEntryPoint - 인증 실패 시 처리 엔트리 포인트
+     * @param accessDenieHandler - 접근 거부 처리 핸들러
+     * @param jwtUtil - JWT 유틸리티 객체
+     * @param redisTemplate
+     *
+     * SecurityConfig 생성자
+     */
+    public SecurityConfig(AuthenticationConfiguration authenticationConfiguration, JWTUtil jwtUtil, RefreshTokenService refreshTokenService, AccesCtrlService accesCtrlService, CommonConfig commonConfig, RedisConfig redisConfig,
+                          LgnHstryService lgnHstryService, CustomAuthenticationEntryPoint authenticationEntryPoint, CustomAccessDenieHandler accessDenieHandler, HttpRequestUtil httpRequestUtil,
+                          @Value("${front.url}")String fUrl, @Value("${jwt.accessTime}")long aTime, @Value("${jwt.refreshTime}")long rTime, @Value("${cookie.time}")int ctime, RedisTemplate<String, String> redisTemplate) {
 
         this.authenticationConfiguration = authenticationConfiguration;
         this.refreshTokenService = refreshTokenService;
@@ -64,27 +84,46 @@
         this.authenticationEntryPoint = authenticationEntryPoint;
         this.accessDenieHandler = accessDenieHandler;
         this.jwtUtil = jwtUtil;
-        this.commonUtils = commonUtils;
+        this.httpRequestUtil = httpRequestUtil;
         this.commonConfig = commonConfig;
+        this.redisConfig = redisConfig;
 
         this.FRONT_URL = fUrl;
         this.JWT_ACCESSTIME = aTime;
         this.JWT_REFRESHTIME = rTime;
         this.COOKIE_TIME = ctime;
+        this.redisTemplate = redisTemplate;
     }
 
-    // AuthenticationManager Bean 등록
+    /**
+     * @param configuration - 인증 구성 객체
+     * @return AuthenticationManager 객체
+     * @throws Exception - 인증 관리자 초기화 실패 시
+     *
+     * AuthenticationManager Bean 등록
+     */
     @Bean
     public AuthenticationManager authenticationManager(AuthenticationConfiguration configuration) throws Exception {
         return configuration.getAuthenticationManager();
     }
 
-    // 해시 암호화
+    /**
+     * @return BCryptPasswordEncoder 객체
+     *
+     * 비밀번호 해시 암호화를 위한 Bean 등록
+     */
     @Bean
     public BCryptPasswordEncoder bCryptPasswordEncoder() {
         return new BCryptPasswordEncoder();
     }
 
+    /**
+     * @param http - HTTP 보안 설정 객체
+     * @return SecurityFilterChain 객체
+     * @throws Exception - 보안 필터 체인 초기화 실패 시
+     *
+     * Spring Security 필터 체인 설정
+     */
     @Bean
     public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
         http.cors((cors) -> cors
@@ -124,11 +163,17 @@
 //                .anyRequest().permitAll() // 모든 사용자 접근 가능
         );
 
+        // 로그인 방식에 따라 필터 적용 (JWT vs 세션)
+       /* if ("SESSION".equals(authConfig.getLoginType())) {
+            http.addFilterBefore(sessionAuthFilter, LoginFilter.class); // 세션 인증 필터 추가
+        } else {
+            http.addFilterBefore(new JWTFilter(jwtUtil, commonConfig, redisConfig, redisTemplate), LoginFilter.class); // JWT 인증 필터 추가
+        }*/
 
-        http.addFilterBefore(new JWTFilter(jwtUtil, commonConfig), LoginFilter.class); // 토큰 검증 필터
-        http.addFilterBefore(new AccesFilter(accesCtrlService, commonUtils, commonConfig), JWTFilter.class); // 아이피 검증
-        http.addFilterAt(new LoginFilter(authenticationManager(authenticationConfiguration), jwtUtil, refreshTokenService, lgnHstryService, commonUtils,
-                        commonConfig, JWT_ACCESSTIME, JWT_REFRESHTIME, COOKIE_TIME), UsernamePasswordAuthenticationFilter.class); // 로그인 필터
+        http.addFilterBefore(new JWTFilter(jwtUtil, commonConfig, redisConfig, redisTemplate), LoginFilter.class); // 토큰 검증 필터
+        http.addFilterBefore(new AccesFilter(accesCtrlService, httpRequestUtil, commonConfig), JWTFilter.class); // 아이피 검증
+        http.addFilterAt(new LoginFilter(authenticationManager(authenticationConfiguration), jwtUtil, refreshTokenService, lgnHstryService, httpRequestUtil,
+                        commonConfig,redisConfig, JWT_ACCESSTIME, JWT_REFRESHTIME, COOKIE_TIME, redisTemplate), UsernamePasswordAuthenticationFilter.class); // 로그인 필터
 
         return http.build();
     }
 
src/main/java/com/takensoft/common/config/UmsDataSourceConfig.java (deleted)
--- src/main/java/com/takensoft/common/config/UmsDataSourceConfig.java
@@ -1,56 +0,0 @@
-package com.takensoft.common.config;
-
-
-import org.apache.ibatis.session.SqlSessionFactory;
-import org.mybatis.spring.SqlSessionFactoryBean;
-import org.mybatis.spring.SqlSessionTemplate;
-import org.mybatis.spring.annotation.MapperScan;
-import org.springframework.beans.factory.annotation.Qualifier;
-import org.springframework.boot.context.properties.ConfigurationProperties;
-import org.springframework.boot.jdbc.DataSourceBuilder;
-import org.springframework.context.ApplicationContext;
-import org.springframework.context.annotation.Bean;
-import org.springframework.context.annotation.Configuration;
-import org.springframework.web.context.WebApplicationContext;
-
-import javax.sql.DataSource;
-
-@Configuration
-@MapperScan(basePackages="com.takensoft.ums.dao", sqlSessionFactoryRef = "umsSqlSessionFactory")
-public class UmsDataSourceConfig {
-    @Bean(name = "umsDataSource")
-    @ConfigurationProperties(prefix="spring.ums.datasource")
-    public DataSource umsDataSource() {
-        return DataSourceBuilder.create().build();
-    }
-
-    @Bean(name = "umsSqlSessionFactory")
-    public SqlSessionFactory umsSqlSessionFactory(@Qualifier("umsDataSource") DataSource umsDataSource,
-                                                  ApplicationContext applicationContext) throws Exception {
-        SqlSessionFactoryBean sqlSessionFactoryBean = new SqlSessionFactoryBean();
-        sqlSessionFactoryBean.setDataSource(umsDataSource);
-        sqlSessionFactoryBean.setTypeAliasesPackage("com.takensoft.ums.vo");
-        sqlSessionFactoryBean.setMapperLocations(applicationContext.getResources("classpath:mybatis/mapper-ora/**/*-SQL.xml"));
-
-        // MyBatis Configuration 설정 추가
-        org.apache.ibatis.session.Configuration myBatisConfig = new org.apache.ibatis.session.Configuration();
-        myBatisConfig.setCacheEnabled(true);
-        myBatisConfig.setLazyLoadingEnabled(false);
-        myBatisConfig.setMultipleResultSetsEnabled(true);
-        myBatisConfig.setUseColumnLabel(true);
-        myBatisConfig.setUseGeneratedKeys(false);
-        myBatisConfig.setDefaultExecutorType(org.apache.ibatis.session.ExecutorType.SIMPLE);
-        myBatisConfig.setDefaultStatementTimeout(25000);
-        myBatisConfig.setCallSettersOnNulls(true);
-        myBatisConfig.setMapUnderscoreToCamelCase(true);
-
-        sqlSessionFactoryBean.setConfiguration(myBatisConfig);
-
-        return sqlSessionFactoryBean.getObject();
-    }
-
-    @Bean(name = "umsSessionTemplate")
-    public SqlSessionTemplate umsSqlSessionTemplate(@Qualifier("umsSqlSessionFactory") SqlSessionFactory umsSqlSessionFactory) {
-        return new SqlSessionTemplate(umsSqlSessionFactory);
-    }
-}
src/main/java/com/takensoft/common/config/WebConfig.java
--- src/main/java/com/takensoft/common/config/WebConfig.java
+++ src/main/java/com/takensoft/common/config/WebConfig.java
@@ -6,14 +6,31 @@
 import org.springframework.web.filter.ForwardedHeaderFilter;
 
 import jakarta.servlet.Filter;
-
+/**
+ * @author  : takensoft
+ * @since   : 2025.01.22
+ * @modification
+ *     since    |    author    | description
+ *  2025.01.22  |  takensoft   | 최초 등록
+ *
+ * Web 관련 설정을 위한 COnfig
+ */
 @Configuration
 public class WebConfig {
+    /**
+     * @return ForwardedHeaderFilter
+     *
+     * ForwardedHeaderFilter를 사용하여 HTTP 요청의 헤더 정보(특히 Forwarded 및 X-Forwarded-* 헤더)를 적절히 처리할 수 있도록 필터를 추가
+     */
     @Bean
     public Filter forwardedHeaderFilter() {
         return new ForwardedHeaderFilter();
     }
-
+    /**
+     * @return @return CommonsRequestLoggingFilter
+     *
+     * CommonsRequestLoggingFilter를 사용하여 HTTP 요청 로깅을 설정
+     */
     @Bean
     public CommonsRequestLoggingFilter requestLoggingFilter() {
         CommonsRequestLoggingFilter loggingFilter = new CommonsRequestLoggingFilter();
src/main/java/com/takensoft/common/exception/FilterExceptionHandler.java
--- src/main/java/com/takensoft/common/exception/FilterExceptionHandler.java
+++ src/main/java/com/takensoft/common/exception/FilterExceptionHandler.java
@@ -75,7 +75,7 @@
     private static void errorRes(HttpServletResponse res, MessageCode messageCode) throws IOException {
         /*
          * Accept-Language가 header에 있으면 해당 언어에 맞게 호출 [ ko: 한국어, en: 영어 ]
-         * header에 Accept-Language가 없다면 한국어를 기본으로함.
+         * header에 Accept-Language가 없다면 한국어를 기본으로함
          * 다국어 메시지 적용
          */
         String message = messageSource.getMessage(messageCode.getMessageKey(), null, LocaleContextHolder.getLocale());
src/main/java/com/takensoft/common/file/web/FileController.java
--- src/main/java/com/takensoft/common/file/web/FileController.java
+++ src/main/java/com/takensoft/common/file/web/FileController.java
@@ -72,7 +72,7 @@
     }
 
     @PostMapping("/postImageUpload.file")
-    public Map<String, Object> handleFileUpload(@RequestPart("upload") MultipartFile file) throws Exception {
+    public Map<String, Object> handleFileUpload(@RequestPart("upload") MultipartFile file){
         Map<String, Object> response = new HashMap<>();
 
         String uploadPath = fileService.editorUploadImg(file);
src/main/java/com/takensoft/common/filter/AccesFilter.java
--- src/main/java/com/takensoft/common/filter/AccesFilter.java
+++ src/main/java/com/takensoft/common/filter/AccesFilter.java
@@ -1,10 +1,9 @@
 package com.takensoft.common.filter;
 
 import com.takensoft.cms.accesCtrl.service.AccesCtrlService;
-import com.takensoft.cms.accesCtrl.service.SystemAccesCtrlService;
 import com.takensoft.cms.accesCtrl.vo.AccesCtrlVO;
 import com.takensoft.common.config.CommonConfig;
-import com.takensoft.common.util.CommonUtils;
+import com.takensoft.common.util.HttpRequestUtil;
 import com.takensoft.common.util.ErrorResponse;
 import org.springframework.http.HttpStatus;
 import org.springframework.http.MediaType;
@@ -25,15 +24,15 @@
  *
  * Access(아이피) 검증 필터
  */
-public class AccesFilter extends OncePerRequestFilter {
+public class  AccesFilter extends OncePerRequestFilter {
 
     private final AccesCtrlService accesCtrlService;
-    private final CommonUtils commonUtils;
+    private final HttpRequestUtil httpRequestUtil;
     private final CommonConfig commonConfig;
 
-    public AccesFilter(AccesCtrlService accesCtrlService, CommonUtils commonUtils, CommonConfig commonConfig) {
+    public AccesFilter(AccesCtrlService accesCtrlService, HttpRequestUtil httpRequestUtil, CommonConfig commonConfig) {
         this.accesCtrlService = accesCtrlService;
-        this.commonUtils = commonUtils;
+        this.httpRequestUtil = httpRequestUtil;
         this.commonConfig = commonConfig;
     }
 
@@ -41,7 +40,7 @@
     protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
         try {
             // 아이피 정보
-            String ipAdrs = commonUtils.getIp(request);
+            String ipAdrs = httpRequestUtil.getIp(request);
             // 접근 제어 정보 조회
             List<AccesCtrlVO> accesCtrlList = accesCtrlService.findAllAccesCtrlSecurity(ipAdrs);
 
src/main/java/com/takensoft/common/filter/JWTFilter.java
--- src/main/java/com/takensoft/common/filter/JWTFilter.java
+++ src/main/java/com/takensoft/common/filter/JWTFilter.java
@@ -1,13 +1,14 @@
 package com.takensoft.common.filter;
 
-import com.fasterxml.jackson.databind.ObjectMapper;
 import com.takensoft.cms.mber.vo.MberAuthorVO;
 import com.takensoft.cms.mber.vo.MberVO;
 import com.takensoft.common.config.CommonConfig;
+import com.takensoft.common.config.RedisConfig;
 import com.takensoft.common.util.ErrorResponse;
 import com.takensoft.common.util.JWTUtil;
 import io.jsonwebtoken.ExpiredJwtException;
 import io.jsonwebtoken.JwtException;
+import org.springframework.data.redis.core.RedisTemplate;
 import org.springframework.http.HttpStatus;
 import org.springframework.http.MediaType;
 import org.springframework.security.authentication.InsufficientAuthenticationException;
@@ -23,48 +24,93 @@
 import java.io.IOException;
 import java.time.LocalDateTime;
 import java.util.List;
-
 /**
  * @author takensoft
  * @since 2024.04.01
+ * @modification
+ *     since    |    author    | description
+ *  2024.04.01  |  takensoft   | 최초 등록
  *
- * JWT - Access 토큰 검증 필터
+ * OncePerRequestFilter - 한 번의 요청마다 단 한 번만 필터링 작업을 수행하는 필터를 제공하는 클래스
+ *
+ * JWT 토큰 검증 Filter
  */
 public class JWTFilter extends OncePerRequestFilter {
 
     private final JWTUtil jwtUtil;
     private final CommonConfig commonConfig;
-    public JWTFilter(JWTUtil jwtUtil, CommonConfig commonConfig) {
+    private final RedisConfig redisConfig;
+    private final RedisTemplate<String, String> redisTemplate;
+    /**
+     * @param jwtUtil JWT 유틸리티 클래스의 인스턴스
+     *
+     * JWTFilter 생성자
+     */
+    public JWTFilter(JWTUtil jwtUtil, CommonConfig commonConfig, RedisConfig redisConfig, RedisTemplate<String, String> redisTemplate) {
         this.jwtUtil = jwtUtil;
         this.commonConfig = commonConfig;
+        this.redisConfig = redisConfig;
+        this.redisTemplate = redisTemplate;
     }
-
+    /**
+     * @param request HttpServletRequest 객체
+     * @param response HttpServletResponse 객체
+     * @param filterChain 필터 체인을 통해 다음 필터로 요청을 전달
+     * @throws ServletException 필터 처리 중 발생한 서블릿 예외
+     * @throws IOException 필터 처리 중 발생한 IO 예외
+     *
+     * JWT 토큰 검증
+     */
     @Override
     protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
-        // 헤더에서 access에 대한 토큰을 꺼냄
-        String accessToken = request.getHeader("Authorization");
-        // 토큰이 없다면 다음 필터로 넘김
-        if(accessToken == null) {
-            filterChain.doFilter(request, response);
-            return;
-        }
         try {
+            // 헤더에서 access에 대한 토큰을 꺼냄
+            String accessToken = request.getHeader("Authorization");
+            // 토큰이 없다면 다음 필터로 넘김
+            if(accessToken == null) {
+                filterChain.doFilter(request, response);
+                return;
+            }
+
             // 토큰 만료 여부 검증
             if(jwtUtil.isExpired(accessToken)) {
                 throw new JwtException("Token expired");
             }
             // 토큰에서 페이로드 확인[ 발급시 명시 ]
-            String category = jwtUtil.getCategory(accessToken);
-            if(!category.equals("Authorization")) {
-                throw new JwtException("Wrong Token");
-            }
-            // 토큰에서 사용자 정보 추출
-            MberVO mber = new MberVO();
-            List<MberAuthorVO> roles = jwtUtil.getRoles(accessToken);
-            mber.setLgnId(jwtUtil.getLgnId(accessToken));
-            mber.setMbrId(jwtUtil.getMbrId(accessToken));
-            mber.setAuthorList(roles);
+            String category = (String) jwtUtil.getClaim(accessToken, "category");
 
+
+            MberVO mber = new MberVO(
+                    (String) jwtUtil.getClaim(accessToken, "mbrId")
+                    , (String) jwtUtil.getClaim(accessToken, "lgnId")
+                    , (List<MberAuthorVO>) jwtUtil.getClaim(accessToken, "roles")
+            );
+
+            // 중복 로그인 비허용 설정이면 Redis에서 최신 JWT 가져와 비교
+            String userId = jwtUtil.getMbrId(accessToken);
+            if (!redisConfig.isAllowMultipleLogin()) {
+                String storedToken = redisTemplate.opsForValue().get("jwt:" + userId);
+                if (storedToken == null) {
+                    System.out.println("Redis에 저장된 JWT 없음 (첫 로그인)");
+                } else if (!storedToken.equals(accessToken)) {
+                    System.out.println("JWT 불일치: Redis=" + storedToken + " / 클라이언트=" + accessToken);
+
+                    response.setContentType(MediaType.APPLICATION_JSON_VALUE);
+                    response.setStatus(HttpStatus.UNAUTHORIZED.value());
+
+                    ErrorResponse errorResponse = new ErrorResponse();
+                    errorResponse.setMessage("다른 기기에서 로그인되었습니다.");
+                    errorResponse.setPath(request.getRequestURI());
+                    errorResponse.setError(HttpStatus.UNAUTHORIZED.getReasonPhrase());
+                    errorResponse.setStatus(HttpStatus.UNAUTHORIZED.value());
+                    errorResponse.setTimestamp(LocalDateTime.now());
+                    // 응답 헤더 설정 및 json 응답 전송
+                    response.setContentType(MediaType.APPLICATION_JSON_VALUE);
+                    response.setStatus(HttpStatus.UNAUTHORIZED.value());
+                    response.getOutputStream().write(commonConfig.getObjectMapper().writeValueAsBytes(errorResponse));
+                    return;
+                }
+            }
             // 시큐리티 컨텍스트에 사용자 정보 설정
             Authentication authToken = new UsernamePasswordAuthenticationToken(mber, null, mber.getAuthorities());
             SecurityContextHolder.getContext().setAuthentication(authToken);
src/main/java/com/takensoft/common/filter/LoginFilter.java
--- src/main/java/com/takensoft/common/filter/LoginFilter.java
+++ src/main/java/com/takensoft/common/filter/LoginFilter.java
@@ -8,13 +8,14 @@
 import com.takensoft.cms.mber.vo.MberVO;
 import com.takensoft.cms.mber.vo.RefreshVO;
 import com.takensoft.common.config.CommonConfig;
-import com.takensoft.common.util.CommonUtils;
-import com.takensoft.common.util.ErrorResponse;
+import com.takensoft.common.config.RedisConfig;
+import com.takensoft.common.exception.FilterExceptionHandler;
+import com.takensoft.common.util.HttpRequestUtil;
 import com.takensoft.common.util.JWTUtil;
 import lombok.SneakyThrows;
 import org.springframework.beans.factory.annotation.Value;
+import org.springframework.data.redis.core.RedisTemplate;
 import org.springframework.http.HttpStatus;
-import org.springframework.http.MediaType;
 import org.springframework.security.authentication.AuthenticationManager;
 import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
 import org.springframework.security.core.Authentication;
@@ -27,14 +28,19 @@
 import jakarta.servlet.http.HttpServletRequest;
 import jakarta.servlet.http.HttpServletResponse;
 import java.io.IOException;
-import java.time.LocalDateTime;
 import java.util.List;
+import java.util.concurrent.TimeUnit;
 
 /**
  * @author takensoft
  * @since 2024.04.01
+ * @modification
+ *     since    |    author    | description
+ *  2024.04.01  |  takensoft   | 최초 등록
  *
- * 로그인 필터
+ * UsernamePasswordAuthenticationFilter - Spring Security에서 사용자 로그인 요청을 처리하는 필터 클래스
+ *
+ * 사용자 로그인 요청을 처리하는 Filter
  */
 public class LoginFilter extends UsernamePasswordAuthenticationFilter {
 
@@ -42,34 +48,50 @@
     private final JWTUtil jwtUtil;
     private final RefreshTokenService refreshTokenService;
     private final LgnHstryService lgnHstryService;
-    private final CommonUtils commonUtils;
+    private final HttpRequestUtil httpRequestUtil;
     private final CommonConfig commonConfig;
+    private final RedisConfig redisConfig;
 
     private static long JWT_ACCESSTIME; // access 토큰 유지 시간
     private static long JWT_REFRESHTIME; // refresh 토큰 유지 시간
     private static int COOKIE_TIME; // 쿠키 유지 시간
 
-    public LoginFilter(AuthenticationManager authenticationManager, JWTUtil jwtUtil, RefreshTokenService refreshTokenService, LgnHstryService lgnHstryService, CommonUtils commonUtils,
-                       CommonConfig commonConfig, @Value("${jwt.accessTime}")long aTime, @Value("${jwt.refreshTime}")long rTime, @Value("${cookie.time}")int ctime) {
+    private final RedisTemplate<String, String> redisTemplate;
+    /**
+     * @param aTime - 액세스 토큰의 유효 시간 (application.yml에서 값을 읽어 옴)
+     * @param rTime - 리프레시 토큰의 유효 시간 (application.yml에서 값을 읽어 옴)
+     * @param ctime - 쿠키의 유효 시간 (application.yml에서 값을 읽어 옴)
+     * @param authenticationManager - 인증 관리자
+     * @param jwtUtil - JWT 유틸리티
+     *
+     * LoginFilter 생성자
+     */
+    public LoginFilter(AuthenticationManager authenticationManager, JWTUtil jwtUtil, RefreshTokenService refreshTokenService, LgnHstryService lgnHstryService, HttpRequestUtil httpRequestUtil,
+                       CommonConfig commonConfig, RedisConfig redisConfig, @Value("${jwt.accessTime}")long aTime, @Value("${jwt.refreshTime}")long rTime, @Value("${cookie.time}")int ctime, RedisTemplate<String, String> redisTemplate) {
         this.authenticationManager = authenticationManager;
         this.jwtUtil = jwtUtil;
         this.refreshTokenService = refreshTokenService;
         this.lgnHstryService = lgnHstryService;
-        this.commonUtils = commonUtils;
+        this.httpRequestUtil = httpRequestUtil;
         this.commonConfig = commonConfig;
-
+        this.redisConfig = redisConfig;
 
         this.JWT_ACCESSTIME = aTime;
         this.JWT_REFRESHTIME = rTime;
         this.COOKIE_TIME = ctime;
+        this.redisTemplate = redisTemplate;
+
 
         this.setRequiresAuthenticationRequestMatcher(new AntPathRequestMatcher("/mbr/loginProc.json","POST"));
     }
 
     /**
-     * @author takensoft
-     * @since 2024.04.03
-     * 로그인 검증
+     * @param req - HTTP 요청 객체
+     * @param res - HTTP 응답 객체
+     * @return 인증 정보
+     * @throws AuthenticationException - 인증 예외
+     *
+     * 로그인 요청을 처리 ( 사용자가 입력한 로그인 정보로 인증 시도 )
      */
     @SneakyThrows
     @Override
@@ -88,9 +110,14 @@
     }
 
     /**
-     * @author takensoft
-     * @since 2024.04.03
-     * 로그인 성공시 실행하는 메서드 -> JWT 발급
+     * @param req - HTTP 요청 객체
+     * @param res - HTTP 응답 객체
+     * @param chain - 필터 체인
+     * @param authentication - 인증된 사용자 정보
+     * @throws IOException - IO 예외
+     * @throws ServletException - 서블릿 예외
+     *
+     * 로그인 인증 성공 시
      */
     @SneakyThrows
     @Override
@@ -105,10 +132,10 @@
         } else {
             lgnHstryVO.setLgnType("1");
         }
-        lgnHstryVO.setCntnIp(commonUtils.getIp(req));
-        lgnHstryVO.setCntnOperSys(commonUtils.getOS(commonUtils.getUserAgent(req)));
-        lgnHstryVO.setDeviceNm(commonUtils.getDevice(commonUtils.getUserAgent(req)));
-        lgnHstryVO.setBrwsrNm(commonUtils.getBrowser(commonUtils.getUserAgent(req)));
+        lgnHstryVO.setCntnIp(httpRequestUtil.getIp(req));
+        lgnHstryVO.setCntnOperSys(httpRequestUtil.getOS(httpRequestUtil.getUserAgent(req)));
+        lgnHstryVO.setDeviceNm(httpRequestUtil.getDevice(httpRequestUtil.getUserAgent(req)));
+        lgnHstryVO.setBrwsrNm(httpRequestUtil.getBrowser(httpRequestUtil.getUserAgent(req)));
         lgnHstryService.LgnHstrySave(lgnHstryVO);
 
         // 토큰 생성(access, refresh)
@@ -127,6 +154,12 @@
         refresh.setToken(refreshToken);
         refreshTokenService.saveRefreshToken(req, res, refresh, JWT_REFRESHTIME);
 
+        // Redis에 AccessToken 저장 (중복 로그인 비허용 설정일 때)
+        if (!redisConfig.isAllowMultipleLogin()) {
+            redisTemplate.delete("jwt:" + mber.getMbrId()); // 기존 JWT 삭제
+            redisTemplate.opsForValue().set("jwt:" + mber.getMbrId(), accessToken, JWT_ACCESSTIME, TimeUnit.MILLISECONDS);
+        }
+
         // 응답설정
         res.setHeader("Authorization", accessToken);
 //        res.setHeader("refresh", refreshToken);
@@ -136,28 +169,16 @@
     }
 
     /**
-     * @author takensoft
-     * @since 2024.04.04
-     * 로그인 실패시 실행하는 메소드
+     * @param req - HTTP 요청 객체
+     * @param res - HTTP 응답 객체
+     * @param failed - 인증 예외
+     * @throws IOException - IO 예외
+     * @throws ServletException - 서블릿 예외
+     *
+     * 로그인 인증 실패 시
      */
     @Override
     protected void unsuccessfulAuthentication(HttpServletRequest req, HttpServletResponse res, AuthenticationException failed) throws IOException, ServletException {
-
-        ErrorResponse errorResponse = new ErrorResponse();
-        // 에러 내용
-        errorResponse.setMessage("아이디 혹은 비밀번호를 잘못 입력하셨습니다.");
-        errorResponse.setPath(req.getRequestURI());
-        errorResponse.setError(HttpStatus.UNAUTHORIZED.getReasonPhrase());
-        errorResponse.setStatus(HttpStatus.UNAUTHORIZED.value());
-        errorResponse.setTimestamp(LocalDateTime.now());
-
-        // 문자 인코딩
-        req.setCharacterEncoding("UTF-8");
-        res.setCharacterEncoding("UTF-8");
-
-        // 응답설정
-        res.setContentType(MediaType.APPLICATION_JSON_VALUE);
-        res.setStatus(HttpStatus.UNAUTHORIZED.value());
-        res.getOutputStream().write(commonConfig.getObjectMapper().writeValueAsBytes(errorResponse));
+        FilterExceptionHandler.loginError(res, failed);
     }
 }
 
src/main/java/com/takensoft/common/filter/SessionAuthFilter.java (added)
+++ src/main/java/com/takensoft/common/filter/SessionAuthFilter.java
@@ -0,0 +1,67 @@
+package com.takensoft.common.filter;
+
+import com.takensoft.common.util.JWTUtil;
+import jakarta.servlet.FilterChain;
+import jakarta.servlet.ServletException;
+import jakarta.servlet.http.HttpServletRequest;
+import jakarta.servlet.http.HttpServletResponse;
+import org.springframework.web.filter.OncePerRequestFilter;
+
+import java.io.IOException;
+
+/**
+ * @author takensoft
+ * @since 2024.03.20
+ * @modification
+ *     since    |    author    | description
+ *  2024.03.20  |  takensoft   | 최초 등록
+ *
+ * OncePerRequestFilter - 한 번의 요청마다 단 한 번만 필터링 작업을 수행하는 필터를 제공하는 클래스
+ *
+ * 세션 검증 Filter
+ */
+public class SessionAuthFilter extends OncePerRequestFilter {
+
+    private final JWTUtil jwtUtil;
+
+    public SessionAuthFilter(JWTUtil jwtUtil) {
+        this.jwtUtil = jwtUtil;
+    }
+
+    @Override
+    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)
+            throws ServletException, IOException {
+/*
+        // 현재 로그인 방식 확인
+        if (!"SESSION".equals(authConfig.getLoginType())) {
+            filterChain.doFilter(request, response);
+            return;
+        }
+
+        HttpSession session = request.getSession(false);
+        if (session == null || session.getAttribute("JWT_TOKEN") == null) {
+            response.sendError(HttpServletResponse.SC_UNAUTHORIZED, "Unauthorized");
+            return;
+        }
+
+        String accessToken = (String) session.getAttribute("JWT_TOKEN");
+
+        // JWT 검증
+        if (jwtUtil.isExpired(accessToken)) {
+            response.sendError(HttpServletResponse.SC_UNAUTHORIZED, "Token expired");
+            return;
+        }
+        MberVO mber = new MberVO();
+        List<MberAuthorVO> roles = jwtUtil.getRoles(accessToken);
+        mber.setLgnId(jwtUtil.getLgnId(accessToken));
+        mber.setMbrId(jwtUtil.getMbrId(accessToken));
+        mber.setAuthorList(roles);
+
+        // 사용자 정보 추출 후 SecurityContext에 저장
+        UsernamePasswordAuthenticationToken authentication =
+                new UsernamePasswordAuthenticationToken(mber, null, mber.getAuthorities());
+        SecurityContextHolder.getContext().setAuthentication(authentication);
+
+        filterChain.doFilter(request, response);*/
+    }
+}(파일 끝에 줄바꿈 문자 없음)
src/main/java/com/takensoft/common/idgen/dao/IdgenMapper.java
--- src/main/java/com/takensoft/common/idgen/dao/IdgenMapper.java
+++ src/main/java/com/takensoft/common/idgen/dao/IdgenMapper.java
@@ -4,25 +4,30 @@
 import org.egovframe.rte.psl.dataaccess.mapper.Mapper;
 
 /**
- * @author  :takensoft
- * @since   : 2024.04.01
+ * @author takensoft
+ * @since 2025.01.22
+ * @modification
+ *     since    |    author    | description
+ *  2025.01.22  |  takensoft   | 최초 등록
  *
- * Idgen 관련 Mapper
+ * 고유 아이디 관련 DAO
  */
 @Mapper
 public interface IdgenMapper {
 
     /**
-     * 테이블명으로 시퀀스 조회
-     * @author takensoft
-     * @since 2024.04.01
+     * @param tblNm - 테이블명
+     * @return IdgenVO - 테이블에 해당하는 마지막 아이디 정보
+     *
+     * 특정 테이블에 대해 마지막으로 사용된 아이디 값을 조회
      */
     IdgenVO selectNextId(String tblNm);
 
     /**
-     * 시퀀스 등록 및 수정
-     * @author takensoft
-     * @since 2024.04.01
+     * @param idgenVO - 아이디 정보 객체
+     * @return int - 삽입 또는 업데이트된 행의 수
+     *
+     * 새로운 아이디 값을 테이블에 삽입하거나 기존의 아이디 값을 업데이트
      */
     void upsertSeqNmg(IdgenVO idgenVO);
 
src/main/java/com/takensoft/common/idgen/service/IdgenService.java
--- src/main/java/com/takensoft/common/idgen/service/IdgenService.java
+++ src/main/java/com/takensoft/common/idgen/service/IdgenService.java
@@ -8,7 +8,15 @@
 import org.apache.commons.logging.Log;
 import org.apache.commons.logging.LogFactory;
 import org.springframework.beans.factory.annotation.Autowired;
-
+/**
+ * @author takensoft
+ * @since 2025.01.22
+ * @modification
+ *     since    |    author    | description
+ *  2025.01.22  |  takensoft   | 최초 등록
+ *
+ * 고유 아이디 관련 서비스
+ */
 @Setter
 @Getter
 public class IdgenService {
@@ -21,7 +29,12 @@
 
     @Autowired
     private IdgenMapper idgenMapper;
-
+    /**
+     * @return 생성된 고유 아이디 값
+     *
+     * 지정된 테이블에 대한 다음 고유 ID를 생성하여 반환
+     * 새로 생성되는 경우 아이디 값은 1부터 시작하며, 기존 값은 1씩 증가하여 업데이트
+     */
     public String getNextStringId() {
         IdgenVO idgenVO = idgenMapper.selectNextId(tblNm);		// 다음 아이디값 조회
         boolean firstFlag = false;		// 신규 생성인지 확인
src/main/java/com/takensoft/common/idgen/vo/IdgenVO.java
--- src/main/java/com/takensoft/common/idgen/vo/IdgenVO.java
+++ src/main/java/com/takensoft/common/idgen/vo/IdgenVO.java
@@ -6,13 +6,22 @@
 
 import java.io.Serializable;
 
-@SuppressWarnings("serial")
+/**
+ * @author takensoft
+ * @since 2025.01.22
+ * @modification
+ *     since    |    author    | description
+ *  2025.01.22  |  takensoft   | 최초 등록
+ *
+ * Serializable - 객체를 직렬화할 수 있게 해주는 인터페이스
+ *
+ * 고유 아이디 관련 VO
+ */
 @NoArgsConstructor
 @Getter
 @Setter
 public class IdgenVO implements Serializable {
-    // 테이블 이름
-    private String tblNm;
-    // 다음 아이디
-    private int aftrId;
+
+    private String tblNm; // 테이블명
+    private int aftrId;     // ID값
 }
 
src/main/java/com/takensoft/common/util/CommonUtils.java (deleted)
--- src/main/java/com/takensoft/common/util/CommonUtils.java
@@ -1,107 +0,0 @@
-package com.takensoft.common.util;
-
-import org.springframework.stereotype.Component;
-
-import jakarta.servlet.http.HttpServletRequest;
-import java.net.InetAddress;
-import java.net.UnknownHostException;
-
-@Component
-public class CommonUtils {
-
-    // 사용자 아이피 주소
-    public String getIp(HttpServletRequest req) throws UnknownHostException {
-        String ip = req.getHeader("X-Forwarded-For");
-
-        if(ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
-            ip = req.getHeader("Proxy-Client-IP");
-        }
-        if(ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
-            ip = req.getHeader("WL-Proxy-Client-IP");
-        }
-        if(ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
-            ip = req.getHeader("HTTP_CLIENT_IP");
-        }
-        if(ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
-            ip = req.getHeader("HTTP_X_FORWARDED_FOR");
-        }
-        if(ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
-            ip = req.getHeader("X-Real-IP");
-        }
-        if(ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
-            ip = req.getHeader("X-RealIP");
-        }
-        if(ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
-            ip = req.getHeader("REMOTE_ADDR");
-        }
-        if(ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
-            ip = req.getRemoteAddr();
-        }
-
-        if(ip.equals("0:0:0:0:0:0:0:1") || ip.equals("127.0.0.1") || ip.equals("::1")) {
-            InetAddress adr = InetAddress.getLocalHost();
-            ip = adr.getHostAddress();
-//            ip = adr.getHostName() + "/" + adr.getHostAddress();
-        } else if (ip.startsWith("::ffff:")) {
-            ip = ip.substring(7); // ::ffff:를 제거하고 IPv4 주소만 추출
-        }
-
-        return ip;
-    }
-
-    // HTTP 요청에서 User-Agent 해더 추출
-    public static String getUserAgent(HttpServletRequest req) {
-        return req.getHeader("User-Agent");
-    }
-
-    // 운영체제 정보 추출
-    public static String getOS(String userAgent) {
-        String os = "Unknown";
-
-        // userAgent 문자열에서 운영체제 정보 추출
-        if(userAgent != null && !userAgent.isEmpty()) {
-            if(userAgent.toLowerCase().contains("windows")) {
-                os = "Windows";
-            } else if(userAgent.toLowerCase().contains("mac")) {
-                os = "Mac";
-            } else if(userAgent.toLowerCase().contains("linux")) {
-                os = "Linux";
-            }
-        }
-        return os;
-    }
-
-    // 디바이스 정보 추출
-    public static String getDevice(String userAgent) {
-        String device = "Unknown";
-        // userAgent 문자열에서 디바이스 정보 추출
-        if(userAgent != null && !userAgent.isEmpty()) {
-            if(userAgent.toLowerCase().contains("mobile")) {
-                device = "Mobile";
-            } else {
-                device = "Desktop";
-            }
-        }
-        return device;
-    }
-
-    // 브라우저 정보 추출
-    public static String getBrowser(String userAgent) {
-        String browser = "Unknown";
-        // userAgent 문자열에서 브라우저저 정보추출
-        if(userAgent != null && !userAgent.isEmpty()) {
-            if(userAgent.toLowerCase().contains("msie")) {
-                browser = "Internet Explorer";
-            } else if(userAgent.toLowerCase().contains("firefox")) {
-                browser = "Firefox";
-            } else if(userAgent.toLowerCase().contains("chrome")) {
-                browser = "Chrome";
-            } else if(userAgent.toLowerCase().contains("safari")) {
-                browser = "Safari";
-            } else if(userAgent.toLowerCase().contains("edge")) {
-                browser = "Edge";
-            }
-        }
-        return browser;
-    }
-}
src/main/java/com/takensoft/common/util/FileUtil.java
--- src/main/java/com/takensoft/common/util/FileUtil.java
+++ src/main/java/com/takensoft/common/util/FileUtil.java
@@ -2,8 +2,6 @@
 
 import org.springframework.stereotype.Component;
 
-import java.net.InetAddress;
-import java.net.UnknownHostException;
 
 /**
  * @author 하석형
 
src/main/java/com/takensoft/common/util/HttpRequestUtil.java (added)
+++ src/main/java/com/takensoft/common/util/HttpRequestUtil.java
@@ -0,0 +1,148 @@
+package com.takensoft.common.util;
+
+import org.springframework.dao.DataAccessException;
+import org.springframework.stereotype.Component;
+
+import jakarta.servlet.http.HttpServletRequest;
+import java.net.InetAddress;
+import java.net.UnknownHostException;
+/**
+ * @author  : takensoft
+ * @since   : 2025.01.22
+ * @modification
+ *     since    |    author    | description
+ *  2025.01.22  |  takensoft   | 최초 등록
+ *
+ * HTTP 요청 관련 유틸리티
+ */
+@Component
+public class HttpRequestUtil {
+
+    /**
+     * @param req - HTTP 요청 객체
+     * @return 클라이언트 IP 주소 (String)
+     * @throws UnknownHostException - 로컬 IP 주소를 확인할 수 없는 경우
+     *
+     * HTTP 요청에서 클라이언트의 IP 주소를 반환
+     */
+    public String getIp(HttpServletRequest req){
+        try {
+            String ip = req.getHeader("X-Forwarded-For");
+
+            if(ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
+                ip = req.getHeader("Proxy-Client-IP");
+            }
+            if(ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
+                ip = req.getHeader("WL-Proxy-Client-IP");
+            }
+            if(ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
+                ip = req.getHeader("HTTP_CLIENT_IP");
+            }
+            if(ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
+                ip = req.getHeader("HTTP_X_FORWARDED_FOR");
+            }
+            if(ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
+                ip = req.getHeader("X-Real-IP");
+            }
+            if(ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
+                ip = req.getHeader("X-RealIP");
+            }
+            if(ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
+                ip = req.getHeader("REMOTE_ADDR");
+            }
+            if(ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
+                ip = req.getRemoteAddr();
+            }
+
+            if(ip.equals("0:0:0:0:0:0:0:1") || ip.equals("127.0.0.1") || ip.equals("::1")) {
+                InetAddress adr = InetAddress.getLocalHost();
+                ip = adr.getHostAddress();
+    //            ip = adr.getHostName() + "/" + adr.getHostAddress();
+            } else if (ip.startsWith("::ffff:")) {
+                ip = ip.substring(7); // ::ffff:를 제거하고 IPv4 주소만 추출
+            }
+            return ip;
+
+        } catch (UnknownHostException Uhe) {
+            throw new RuntimeException("호스트 IP의 정보를 알 수가 없습니다.", Uhe);
+        } catch (Exception e) {
+            throw e;
+        }
+    }
+
+    /**
+     * @param req - HTTP 요청 객체
+     * @return User-Agent (String)
+     *
+     * HTTP 요청에서 User-Agent 헤더 값을 추출
+     */
+    public static String getUserAgent(HttpServletRequest req) {
+        return req.getHeader("User-Agent");
+    }
+
+    /**
+     * @param userAgent - User-Agent
+     * @return 운영체제 이름 (String)
+     *
+     * User-Agent에서 운영체제 정보를 추출
+     */
+    public static String getOS(String userAgent) {
+        String os = "Unknown";
+
+        // userAgent 문자열에서 운영체제 정보 추출
+        if(userAgent != null && !userAgent.isEmpty()) {
+            if(userAgent.toLowerCase().contains("windows")) {
+                os = "Windows";
+            } else if(userAgent.toLowerCase().contains("mac")) {
+                os = "Mac";
+            } else if(userAgent.toLowerCase().contains("linux")) {
+                os = "Linux";
+            }
+        }
+        return os;
+    }
+
+    /**
+     * @param userAgent - User-Agent
+     * @return 디바이스 이름 (String)
+     *
+     * User-Agent에서 디바이스 정보를 추출
+     */
+    public static String getDevice(String userAgent) {
+        String device = "Unknown";
+        // userAgent 문자열에서 디바이스 정보 추출
+        if(userAgent != null && !userAgent.isEmpty()) {
+            if(userAgent.toLowerCase().contains("mobile")) {
+                device = "Mobile";
+            } else {
+                device = "Desktop";
+            }
+        }
+        return device;
+    }
+
+    /**
+     * @param userAgent - User-Agent
+     * @return 브라우저 이름 (String)
+     *
+     * User-Agent에서 브라우저 정보를 추출
+     */
+    public static String getBrowser(String userAgent) {
+        String browser = "Unknown";
+        // userAgent 문자열에서 브라우저저 정보추출
+        if(userAgent != null && !userAgent.isEmpty()) {
+            if(userAgent.toLowerCase().contains("msie")) {
+                browser = "Internet Explorer";
+            } else if(userAgent.toLowerCase().contains("firefox")) {
+                browser = "Firefox";
+            } else if(userAgent.toLowerCase().contains("chrome")) {
+                browser = "Chrome";
+            } else if(userAgent.toLowerCase().contains("safari")) {
+                browser = "Safari";
+            } else if(userAgent.toLowerCase().contains("edge")) {
+                browser = "Edge";
+            }
+        }
+        return browser;
+    }
+}
src/main/java/com/takensoft/common/util/JWTUtil.java
--- src/main/java/com/takensoft/common/util/JWTUtil.java
+++ src/main/java/com/takensoft/common/util/JWTUtil.java
@@ -16,18 +16,40 @@
 import jakarta.servlet.http.Cookie;
 import java.nio.charset.StandardCharsets;
 import java.util.*;
-
+/**
+ * @author  : takensoft
+ * @since   : 2025.01.22
+ * @modification
+ *     since    |    author    | description
+ *  2025.01.22  |  takensoft   | 최초 등록
+ *
+ * JWT 토큰 생성 및 검증, 쿠키 생성 등의 유틸리티
+ */
 @Component
 public class JWTUtil {
 
     private static SecretKey JWT_SECRET_KEY;
 
-
+    /**
+     * @param secret - JWT 서명을 위한 키 (application.yml에서 값을 읽어 옴)
+     *
+     * 기본 생성자
+     */
     public JWTUtil(@Value("${jwt.secret}")String secret) {
         this.JWT_SECRET_KEY = new SecretKeySpec(secret.getBytes(StandardCharsets.UTF_8), Jwts.SIG.HS256.key().build().getAlgorithm());
     }
 
-    // 토큰 생성
+    /**
+     * @param category  토큰의 카테고리 정보 (Authorization, refresh)
+     * @param mbrId 사용자 ID
+     * @param lgnId 로그인 ID
+     * @param mbrNm 사용자 이름
+     * @param roles  사용자 권한 목록
+     * @param expiredMs 토큰 만료 시간 (밀리초)
+     * @return 생성된 JWT 토큰 (String)
+     *
+     * JWT 토큰 생성
+     */
     public String createJwt(String category, String mbrId, String lgnId, String mbrNm, List<String> roles, long expiredMs) {
         return Jwts.builder()
                 .claim("category", category)
@@ -41,7 +63,14 @@
                 .compact();
     }
 
-    // 쿠키 생성
+    /**
+     * @param key 쿠키 키 값
+     * @param value 쿠키 값
+     * @param time 쿠키의 생명주기 (초 단위)
+     * @return 생성된 Cookie 객체
+     *
+     * 쿠키 생성
+     */
     public Cookie createCookie(String key, String value, int time) {
         // 쿠키 생성
         Cookie cookie = new Cookie(key, value);
@@ -108,4 +137,53 @@
         return mbrId;
     }
 
+
+
+
+    /**
+     * @param tkn JWT 토큰 문자열
+     * @param knd 조회할 데이터의 종류 (예: ctgry, userId, loginId 등)
+     * @return 조회된 클레임 데이터 (종류에 따라 String, Date, List 등으로 반환)
+     * @throws IllegalArgumentException 유효하지 않은 knd 값일 경우 예외 발생
+     *
+     * 클레임 조회
+     */
+    public Object getClaim(String tkn, String knd) {
+        Claims claims = Jwts.parser()
+                .verifyWith(JWT_SECRET_KEY)
+                .build()
+                .parseSignedClaims(tkn)
+                .getPayload();
+        switch (knd) {
+            case "category":
+                return claims.get("category", String.class);
+            case "mbrId":
+                return claims.get("mbrId", String.class);
+            case "lgnId":
+                return claims.get("lgnId", String.class);
+            case "mbrNm":
+                return claims.get("mbrNm", String.class);
+            case "roles":
+                // roles 클레임에서 사용자 권한 정보를 파싱
+                List<Map<String, Object>> roles = claims.get("roles", List.class);
+                List<MberAuthorVO> authorList = new ArrayList<>();
+                if(roles != null && !roles.isEmpty()) {
+                    for(Map<String, Object> role : roles) {
+                        MberAuthorVO userAuthor = new MberAuthorVO(role.get("authority").toString());
+                        authorList.add(userAuthor);
+                    }
+                }
+                return authorList;
+            case "isExpired":
+                // 토큰 만료 여부 반환
+                return claims.getExpiration().before(new Date());
+            case "expired":
+                // 토큰 만료 시간 반환
+                return claims.getExpiration();
+            default:
+                // 유효하지 않는 knd 처리
+                throw new IllegalArgumentException("Invalid knd : " + knd);
+        }
+    }
+
 }
src/main/java/com/takensoft/common/util/ResponseData.java
--- src/main/java/com/takensoft/common/util/ResponseData.java
+++ src/main/java/com/takensoft/common/util/ResponseData.java
@@ -8,16 +8,16 @@
 import java.time.LocalDateTime;
 
 /**
- * @author takensoft
- * @since 2024.04.03
- * 응답 데이터
+ * @author  : takensoft
+ * @since   : 2025.01.22
+ * @modification
+ *     since    |    author    | description
+ *  2025.01.22  |  takensoft   | 최초 등록
+ *
+ * 응답 데이터 객체
  */
 @Data
 public class ResponseData {
-
-    /*private HttpStatus status;
-    private String message;
-    private Object data;*/
 
     private int status;                 // 상태 코드
     private HttpStatus statusText;      // 상태 메시지
@@ -28,9 +28,6 @@
     private LocalDateTime resTime;      // 응답 시간
 
     public ResponseData() {
-        /*this.status = HttpStatus.BAD_REQUEST;
-        this.data = null;
-        this.message = null;*/
         this.status = 0;
         this.statusText = null;
         this.message = null;
src/main/java/com/takensoft/common/util/Secret.java
--- src/main/java/com/takensoft/common/util/Secret.java
+++ src/main/java/com/takensoft/common/util/Secret.java
@@ -10,27 +10,37 @@
 import java.util.Base64.Decoder;
 
 /**
- * @author takensoft
- * @since 2024.04.03
- * 암복호화
+ * @author  : takensoft
+ * @since   : 2025.01.22
+ * @modification
+ *     since    |    author    | description
+ *  2025.01.22  |  takensoft   | 최초 등록
+ *
+ * 암호화 및 복호화 작업을 수행하는 유틸리티
  */
 @Component
 public class Secret {
 
-    private static final Charset UTF_8 = StandardCharsets.UTF_8;
+    private static final Charset UTF_8 = StandardCharsets.UTF_8; // UTF-8 문자셋
 
-    private static String SECRET_KEY;
+    private static String SECRET_KEY; // 암호화 키
 
-    private static String VECTOR_KEY;
-
+    private static String VECTOR_KEY; // 복호화 키
+    /**
+     * @param secret - 암호화 키 (application.yml에서 값을 읽어 옴)
+     * @param vector - 복호화 키 (application.yml에서 값을 읽어 옴)
+     *
+     * 기본 생성자
+     */
     public Secret(@Value("${crypto.secret}")String secret, @Value("${crypto.vector}")String vector) {
         this.SECRET_KEY = secret;
         this.VECTOR_KEY = vector;
     }
 
     /**
-     * @author takensoft
-     * @since 2024.04.03
+     * @param data - 암호화할 데이터
+     * @return 암호화된 데이터 (Base64로 인코딩된 문자열)
+     *
      * 암호화
      */
     public static String encrypt(String data) {
@@ -41,8 +51,9 @@
     }
 
     /**
-     * @author takensoft
-     * @since 2024.04.03
+     * @param encryptedData - 복호화할 암호화된 데이터 (Base64로 인코딩된 문자열)
+     * @return 복호화된 원본 데이터
+     *
      * 복호화
      */
     public static String decrypt(String encryptedData) {
 
src/main/java/com/takensoft/ums/dao/UmsDAO.java (deleted)
--- src/main/java/com/takensoft/ums/dao/UmsDAO.java
@@ -1,24 +0,0 @@
-package com.takensoft.ums.dao;
-
-import com.takensoft.ums.vo.UmsVO;
-import org.egovframe.rte.psl.dataaccess.mapper.Mapper;
-
-import java.util.HashMap;
-import java.util.List;
-
-/**
- * @author  : 방선주
- * @since   : 2024.06.25
- *
- * 문자서비스 Mapper
- */
-@Mapper
-public interface UmsDAO {
-    /**
-     * 문자 메시지 목록 조회
-     */
-    public int save(UmsVO umsVO) throws Exception;
-
-    public List<UmsVO> findAll() throws Exception;
-}
-
 
src/main/java/com/takensoft/ums/service/Impl/UmsServiceImpl.java (deleted)
--- src/main/java/com/takensoft/ums/service/Impl/UmsServiceImpl.java
@@ -1,59 +0,0 @@
-package com.takensoft.ums.service.Impl;
-
-import com.takensoft.cms.mber.dto.AdmMbrDTO;
-import com.takensoft.cms.mber.service.AdmMbrService;
-import com.takensoft.cms.mber.vo.MberVO;
-import com.takensoft.ums.dao.UmsDAO;
-import com.takensoft.ums.service.UmsService;
-import com.takensoft.ums.vo.UmsVO;
-import lombok.RequiredArgsConstructor;
-import org.egovframe.rte.fdl.cmmn.EgovAbstractServiceImpl;
-import org.springframework.stereotype.Service;
-import org.springframework.transaction.annotation.Transactional;
-
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-
-/**
- * @author  : 방선주
- * @since   : 2024.06.25
- *
- * UmsServiceImpl - 문자 메시지 전송을 위한 서비스 구현체
- */
-
-@Service("umsService")
-@RequiredArgsConstructor
-public class UmsServiceImpl extends EgovAbstractServiceImpl implements UmsService {
-
-    private final UmsDAO umsDAO;
-    private final AdmMbrService admMbrService;
-
-    @Override
-    @Transactional
-    public Map<String, Object> save() throws Exception {
-        Map<String, Object> result = new HashMap<>();
-
-        // 슈퍼관리자 정보 찾아 가져오기
-        String mbrId = "MBR_000000000000001";
-        AdmMbrDTO admMbrDTO = admMbrService.mbrDetail(mbrId);
-        UmsVO umsVO = new UmsVO();
-        umsVO.setUserId("mono_customer"); // 계정 전달 필요
-        umsVO.setScheduleType("0"); // 즉시 전달 1: 예약
-        umsVO.setTitle("온라인 상담 신규 접수"); // 제목 (null 가능)
-        umsVO.setMsgContent("신규 온라인 상담 신청 건이 등록 되었습니다. "); // 내용
-        umsVO.setCallingNum("054-639-6161"); // 회신번호
-        umsVO.setPhoneNum(admMbrDTO.getMblTelno()); // 슈퍼 관리자 전화번호 가져오기
-
-        result.put("status", umsDAO.save(umsVO));
-        return result;
-    }
-
-    @Override
-    public Map<String, Object> findAll() throws Exception {
-        Map<String, Object> result = new HashMap<>();
-        List<UmsVO> list = umsDAO.findAll();
-        result.put("list", list);
-        return result;
-    }
-}
 
src/main/java/com/takensoft/ums/service/UmsService.java (deleted)
--- src/main/java/com/takensoft/ums/service/UmsService.java
@@ -1,16 +0,0 @@
-package com.takensoft.ums.service;
-
-import java.util.Map;
-
-/**
- * @author  : 방선주
- * @since   : 2024.06.25
- *
- * UmsService - 문자 메시지 전송을 위한 서비스
- */
-
-public interface UmsService {
-    public Map<String, Object> save() throws Exception;
-
-    public Map<String, Object> findAll() throws Exception;
-}(파일 끝에 줄바꿈 문자 없음)
 
src/main/java/com/takensoft/ums/vo/UmsVO.java (deleted)
--- src/main/java/com/takensoft/ums/vo/UmsVO.java
@@ -1,87 +0,0 @@
-package com.takensoft.ums.vo;
-
-import lombok.AllArgsConstructor;
-import lombok.Getter;
-import lombok.Setter;
-
-/**
- * @author  : 방선주
- * @since   : 2024.06.25
- *
- * 게시판 관리 관련 VO
- */
-@Setter
-@Getter
-@AllArgsConstructor
-public class UmsVO {
-    /**
-     * 문자 메시지 아이디
-     */
-    private String id;
-    /**
-     * ums 로그인 아이디
-     */
-    private String userId;
-    /**
-     * 스케쥴 타입구분(0:즉시, 1:예약)
-     */
-    private String scheduleType;
-    /**
-     * 제목
-     */
-    private String title;
-    /**
-     * 메시지 내용
-     */
-    private String msgContent;
-    /**
-     * 회신번호
-     */
-    private String callingNum;
-    /**
-     * 수신자
-     */
-    private String tgtNm;
-    /**
-     * 수신번호
-     */
-    private String phoneNum;
-    /**
-     * 상태코드 (0: 미전송, 1: 전송, 2:에러)
-     */
-    private String stateCd;
-    /**
-     * STATE_CD 값이 ‘2’일 경우 상세 에러메시지
-     */
-    private String resultMsg;
-    /**
-     * 카카오 알림톡 전송 시 템플릿코드 입력(SMS일
-     * 경우 NULL)
-     */
-    private String templateCd;
-    /**
-     * 푸시전송여부 ‘Y’일경우 푸시로 전송
-     */
-    private String pushSendYn;
-    /**
-     * 푸시전송 시 식별자 아이디(앱아이디)
-     */
-    private String pushId;
-    /**
-     * 카카오알림톡 재전송 후 실패 시 문자전송.
-     */
-    private String pushResendTpCd;
-    /**
-     * 예약전송일시
-     */
-    private String reservDttm;
-    /**
-     * DB입력시간
-     */
-    private String regDttm;
-
-
-    public UmsVO() {
-
-    }
-}
 
src/main/java/com/takensoft/ums/web/UmsController.java (deleted)
--- src/main/java/com/takensoft/ums/web/UmsController.java
@@ -1,48 +0,0 @@
-package com.takensoft.ums.web;
-
-import com.takensoft.common.message.MessageCode;
-import com.takensoft.common.util.ResponseData;
-import com.takensoft.common.util.ResponseUtil;
-import com.takensoft.ums.service.UmsService;
-import lombok.RequiredArgsConstructor;
-import lombok.extern.slf4j.Slf4j;
-import org.springframework.http.HttpHeaders;
-import org.springframework.http.HttpStatus;
-import org.springframework.http.MediaType;
-import org.springframework.http.ResponseEntity;
-import org.springframework.web.bind.annotation.PostMapping;
-import org.springframework.web.bind.annotation.RequestMapping;
-import org.springframework.web.bind.annotation.RestController;
-
-import java.nio.charset.Charset;
-import java.util.HashMap;
-import java.util.Map;
-/**
- * @author 방선주
- * @since 2024.06.25
- * @modification
- *     since    |    author    | description
- *  2024.06.25  |    방선주     | 최초 등록
- *
- * UmsController - 문자 메시지 전송을 위한 컨트롤러
- */
-@RestController
-@RequiredArgsConstructor
-@Slf4j
-@RequestMapping(value="/ums")
-public class UmsController {
-
-    private final ResponseUtil resUtil;
-    private final UmsService umsService;
-
-    // 문자 메시지 테이블 확인
-    @PostMapping(value="/saveUmsInfo.json")
-    public ResponseEntity<?> saveUmsInfo() throws Exception {
-        // 목록 조회
-//        Map<String, Object> result = umsService.findAll();
-        Map<String, Object> result = umsService.save();
-
-        // 응답처리
-        return resUtil.successRes(result, MessageCode.COMMON_SUCCESS);
-    }
-}(파일 끝에 줄바꿈 문자 없음)
src/main/resources/application.yml
--- src/main/resources/application.yml
+++ src/main/resources/application.yml
@@ -21,13 +21,12 @@
       password: tts96314728!@
 
   # 오라클 설정
-#  ums:
-#    datasource:
-#      driver-class-name: oracle.jdbc.OracleDriver
-#      jdbc-url: jdbc:oracle:thin:@localhost:1521:xe
-#      username: c##test1
-#      password: 1234
-
+  #  ums:
+  #    datasource:
+  #      driver-class-name: oracle.jdbc.OracleDriver
+  #      jdbc-url: jdbc:oracle:thin:@localhost:1521:xe
+  #      username: c##test1
+  #      password: 1234
   sql:
     init:
       platform: postgres
@@ -86,4 +85,14 @@
 
 file:
   file-upload-path: /fileUpload/
-  edit-file-upload-path: /editFileUpload/
(파일 끝에 줄바꿈 문자 없음)
+  edit-file-upload-path: /editFileUpload/
+
+redis:
+  host: localhost
+  port: 6379
+
+config:
+  allow-multiple-logins: true
+
+auth:
+  login-type: JWT
(파일 끝에 줄바꿈 문자 없음)
 
src/main/resources/mybatis/mapper-ora/ums/ums-SQL.xml (deleted)
--- src/main/resources/mybatis/mapper-ora/ums/ums-SQL.xml
@@ -1,29 +0,0 @@
-<?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="com.takensoft.ums.dao.UmsDAO">
-    <insert id="save" parameterType="UmsVO">
-        INSERT INTO CUSTOMER_SMS_SEND (
-                                       USER_ID
-                                      , SCHEDULE_TYPE
-                                      , TITLE
-                                      ,MSG_CONTENT
-                                      , CALLING_NUM
-                                      ,PHONE_NUM
-                                      , RESERV_DTTM
-                                      , REG_DTTM
-        ) VALUES (
-                     #{userId},
-                     #{scheduleType},
-                     #{title},
-                     #{msgContent},
-                     #{callingNum},
-                     #{phoneNum},
-                     NULL,
-                     TO_CHAR(SYSDATE, 'YYYYMMDDHH24MISS')
-                 )
-    </insert>
-
-    <select id="findAll" resultType="UmsVO">
-        SELECT * FROM CUSTOMER_SMS_SEND
-    </select>
-</mapper>(파일 끝에 줄바꿈 문자 없음)
Add a comment
List