mycom 2022-09-02
220902 최정우 최초 커밋
@73e16e94a11ecf3e0ce80eb2a33c48fb9399199f
 
pom.xml (added)
+++ pom.xml
@@ -0,0 +1,269 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+    Maven 빌드 과정
+    0. Commend / Powershell / Terminal 창 켜기
+    1. pom.xml이 존재하는 프로젝트 경로로 이동
+    2. mvn clean (빌드를 하기전 빌드 결과 위치를 비우는 명령어)
+    3. mvn compile (Maven을 활용한 빌드 진행)
+    4. mvn package (Maven을 활용한 패키지 진행)
+-->
+<!--
+    작성자: 최정우
+    작성일: 220831
+    내용 : Maven Spring Legacy Proejct 세팅
+-->
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/maven-v4_0_0.xsd">
+
+    <modelVersion>4.0.0</modelVersion><!-- modelVersion: Maven POM의 버전 -->
+    <groupId>kr.co.takensoft</groupId><!-- groupId: 기관(소속) 식별자 -->
+    <artifactId>spring-legacy-project</artifactId><!-- artifactId: 현재 project의 식별자 -->
+    <name>project-name</name><!-- name: 현재 project의 명칭 -->
+    <packaging>war</packaging><!-- packaging: 어떤 파일 형식으로 패키징할 것인가를 정의, jar, war, exe 등이 올 수 있음 -->
+    <version>1.0.0-BUILD-SNAPSHOT</version><!-- version: 해당 artifact(컴포넌트)의 version, 뒤쪽 SNAPSHOT은 아직 개발 중임을 의미함 -->
+
+    <!-- properties: POM.xml에서 사용할 변수 -->
+    <properties>
+        <java-version>15</java-version>
+        <org.springframework.version>5.3.22</org.springframework.version>
+        <egovframework.rte.version>3.10.0</egovframework.rte.version>
+
+        <back-end-path>${project.basedir}/src/back-end</back-end-path>
+        <front-end-path>${project.basedir}/src/front-end</front-end-path>
+    </properties>
+
+    <!-- repositories: 라이브러리를 다운로드 받을 위치들을 설정 하는 곳 -->
+    <repositories>
+        <!-- repository: 라이브러리를 다운로드 받을 위치 설정, 기술되지 않을 시 기본적인 위치: https://repo1.maven.org/maven2/ -->
+        <!-- Apache재단 Maven 의존성 라이브러리 저장소 -->
+        <repository>
+            <id>mvn2s</id>
+            <url>https://repo1.maven.org/maven2/</url>
+            <releases>
+                <enabled>true</enabled>
+            </releases>
+            <snapshots>
+                <enabled>true</enabled>
+            </snapshots>
+        </repository>
+        <!-- 전자정부프레임워크 Maven 의존성 라이브러리 저장소 -->
+        <repository>
+            <id>egovframe</id>
+            <url>https://repo.maven.apache.org/maven2/</url>
+            <releases>
+                <enabled>true</enabled>
+            </releases>
+            <snapshots>
+                <enabled>false</enabled>
+            </snapshots>
+        </repository>
+    </repositories>
+
+    <!-- dependencies: 의존성 라이브러리들을 설정하는 곳 -->
+    <dependencies>
+
+        <!-- servlet 라이브러리 -->
+        <dependency>
+            <groupId>javax.servlet</groupId>
+            <artifactId>javax.servlet-api</artifactId>
+            <version>4.0.1</version>
+            <scope>provided</scope>
+        </dependency>
+
+        <!-- Spring Framwork 라이브러리 - 해당 라이브러리 다운로드 시 core, context, beans, expression, web, aop, jcl 이 같이 다운 받아짐 -->
+        <dependency>
+            <groupId>org.springframework</groupId>
+            <artifactId>spring-webmvc</artifactId>
+            <version>${org.springframework.version}</version>
+        </dependency>
+        <!-- Spring Framwork JDBC 라이브러리 - 특정 JDBC를 Bean 등록 해야 한다면 꼭 필요 함 -->
+        <dependency>
+            <groupId>org.springframework</groupId>
+            <artifactId>spring-jdbc</artifactId>
+            <version>${org.springframework.version}</version>
+        </dependency>
+
+        <!-- JSON Parsing 라이브러리 - 해당 라이브러리 다운로드 시 core, annotations 이 같이 다운 받아짐 -->
+        <dependency>
+            <groupId>com.fasterxml.jackson.core</groupId>
+            <artifactId>jackson-databind</artifactId>
+            <version>2.13.3</version>
+        </dependency>
+
+        <!-- 시스템 입출력(파일 포함) -->
+        <dependency>
+            <groupId>commons-io</groupId>
+            <artifactId>commons-io</artifactId>
+            <version>2.11.0</version>
+        </dependency>
+        <!-- 파일업로드 -->
+        <dependency>
+            <groupId>commons-fileupload</groupId>
+            <artifactId>commons-fileupload</artifactId>
+            <version>1.4</version>
+            <exclusions>
+                <exclusion>
+                    <artifactId>commons-io</artifactId>
+                    <groupId>commons-io</groupId>
+                </exclusion>
+            </exclusions>
+        </dependency>
+
+        <!-- SQL 작성 및 DBCP, JDBC 인터페이스 기능 담당 라이브러리 Mybatis -->
+        <dependency>
+            <groupId>org.mybatis</groupId>
+            <artifactId>mybatis</artifactId>
+            <version>3.5.10</version>
+        </dependency>
+        <!-- SQL 작성 및 DBCP, JDBC 인터페이스 기능 담당 라이브러리 Mybatis(SpringFramework와 인터페이스 용) - 해당 라이브러리 활용 시 의존성 라이브러리's mybatis, spring-context, spring-jdbc, spring-batch-infrastructure -->
+        <dependency>
+            <groupId>org.mybatis</groupId>
+            <artifactId>mybatis-spring</artifactId>
+            <version>2.0.7</version>
+        </dependency>
+
+
+        <!-- DB Connection Pool : HikariCP -->
+        <dependency>
+            <groupId>com.zaxxer</groupId>
+            <artifactId>HikariCP</artifactId>
+            <version>5.0.1</version>
+        </dependency>
+
+        <!-- JDBC : MariaDB -->
+        <dependency>
+            <groupId>org.mariadb.jdbc</groupId>
+            <artifactId>mariadb-java-client</artifactId>
+            <version>3.0.7</version>
+        </dependency>
+        <!-- JDBC : PostgreSQL -->
+        <dependency>
+            <groupId>org.postgresql</groupId>
+            <artifactId>postgresql</artifactId>
+            <version>42.5.0</version>
+        </dependency>
+
+
+        <!-- POI - Excel 관련 라이브러리 (2007년 이후 버전) -->
+        <dependency>
+            <groupId>org.apache.poi</groupId>
+            <artifactId>poi-ooxml</artifactId>
+            <version>5.2.2</version>
+        </dependency>
+        <!-- POI - Excel 관련 라이브러리 (2007년 이전 버전) -->
+        <dependency>
+            <groupId>org.apache.poi</groupId>
+            <artifactId>poi</artifactId>
+            <version>5.2.2</version>
+        </dependency>
+
+
+        <!-- File 바이너리 데이터의 MIME 관련 라이브러리 -->
+        <dependency>
+            <groupId>javax.activation</groupId>
+            <artifactId>activation</artifactId>
+            <version>1.1.1</version>
+        </dependency>
+
+        <!-- E-Mail 관련 라이브러리 -->
+        <dependency>
+            <groupId>javax.mail</groupId>
+            <artifactId>mail</artifactId>
+            <version>1.4.7</version>
+        </dependency>
+
+
+
+
+
+        <!-- 표준프레임워크 실행환경 (시작) -->
+        <!--<dependency>
+            <groupId>egovframework.rte</groupId>
+            <artifactId>egovframework.rte.ptl.mvc</artifactId>
+            <version>${egovframework.rte.version}</version>
+        </dependency>
+        <dependency>
+            <groupId>egovframework.rte</groupId>
+            <artifactId>egovframework.rte.psl.dataaccess</artifactId>
+            <version>${egovframework.rte.version}</version>
+        </dependency>
+        <dependency>
+            <groupId>egovframework.rte</groupId>
+            <artifactId>egovframework.rte.fdl.idgnr</artifactId>
+            <version>${egovframework.rte.version}</version>
+        </dependency>
+        <dependency>
+            <groupId>egovframework.rte</groupId>
+            <artifactId>egovframework.rte.fdl.property</artifactId>
+            <version>${egovframework.rte.version}</version>
+        </dependency>
+        <dependency>
+            <groupId>egovframework.rte</groupId>
+            <artifactId>egovframework.rte.fdl.crypto</artifactId>
+            <version>${egovframework.rte.version}</version>
+        </dependency>-->
+        <!--<dependency>
+            <groupId>org.jetbrains</groupId>
+            <artifactId>annotations</artifactId>
+            <version>RELEASE</version>
+            <scope>compile</scope>
+        </dependency>-->
+        <!-- 표준프레임워크 실행환경 (끝) -->
+
+    </dependencies>
+
+
+    <!-- build: Compile ~ Depoly에 대한 과정을 설정하는 곳 -->
+    <build>
+        <!-- finalName: 최종 packaging된 file의 이름 -->
+        <finalName>ROOT</finalName>
+        <!-- directory: 빌드 경로 (다른 곳에서 ${deploy.path} 활용하면 됨) -->
+        <directory>${project.basedir}/target</directory>
+        <!-- sourceDirectory: Java 소스 경로 -->
+        <sourceDirectory>${back-end-path}/main/java</sourceDirectory>
+        <!-- testSourceDirectory: Test용 Java 소스 경로 -->
+        <testSourceDirectory>${back-end-path}/test/java</testSourceDirectory>
+        <!-- outputDirectory: 컴파일 후 .class 파일 저장 경로 -->
+        <outputDirectory>${build.directory}/classes</outputDirectory>
+
+        <!-- resources: JAVA File 이외의 자원들을 classpath로 설정하기 위한 곳 -->
+        <resources>
+            <resource>
+                <directory>${project.basedir}/src/main/resources</directory>
+            </resource>
+        </resources>
+
+        <!-- plugins: Maven Plugin을 설정하는 곳 -->
+        <plugins>
+            <!-- maven compile plugin -->
+            <plugin>
+                <groupId>org.apache.maven.plugins</groupId>
+                <artifactId>maven-compiler-plugin</artifactId>
+                <version>3.10.1</version>
+                <configuration>
+                    <source>${java-version}</source><!-- 소스코드 Java 버전 -->
+                    <target>${java-version}</target><!-- compile시 결과물 Java 버전 -->
+                </configuration>
+            </plugin>
+            <!-- maven war package plugin -->
+            <plugin>
+                <groupId>org.apache.maven.plugins</groupId>
+                <artifactId>maven-war-plugin</artifactId>
+                <version>3.3.2</version>
+                <configuration>
+                    <!-- webResources: web 관련 자원들의 (html, js, css 등..) 경로 -->
+                    <webResources>
+                        <resource>
+                            <directory>${front-end-path}</directory>
+                        </resource>
+                    </webResources>
+                    <!-- webappDirectory: package된 후 web관련 자원들이 배포될 경로 -->
+                    <!-- <webappDirectory>${build.directory}</webappDirectory>-->
+                    <!-- web.xml 경로 -->
+                    <webXml>${project.basedir}/src/front-end/WEB-INF/web.xml</webXml>
+                </configuration>
+            </plugin>
+        </plugins>
+    </build>
+
+</project>
 
src/back-end/main/java/common/util/AsyncUtil.java (added)
+++ src/back-end/main/java/common/util/AsyncUtil.java
@@ -0,0 +1,36 @@
+package common.util;
+
+import common.util.reflection.ReflectionUtil;
+
+public class AsyncUtil implements Runnable {
+    
+	String classFilePath, packageName, className, methodName;
+	Object[] paramValues;
+	Class<?>[] paramTypes;
+	
+	public AsyncUtil (String classFilePath, String packageName, String className, String methodName, Object[] paramValues, Class<?>[] paramTypes) {
+		this.classFilePath = classFilePath;
+		this.packageName = packageName;
+		this.className = className;
+		this.methodName = methodName;
+		this.paramValues = paramValues;
+		this.paramTypes = paramTypes;
+	}
+	
+	public AsyncUtil (String packageName, String className, String methodName, Object[] paramValues, Class<?>[] paramTypes) {
+		this.packageName = packageName;
+		this.className = className;
+		this.methodName = methodName;
+		this.paramValues = paramValues;
+		this.paramTypes = paramTypes;
+	}
+	
+	@Override
+    public void run () {
+		//객체 생성
+		Object clazz = ReflectionUtil.classAndBeanLoad(classFilePath, (packageName + "." + className));
+		//메서드 실행
+		ReflectionUtil.invokeByMethodName(clazz, methodName, paramValues, paramTypes);
+    }
+
+}
 
src/back-end/main/java/common/util/AuthUtil.java (added)
+++ src/back-end/main/java/common/util/AuthUtil.java
@@ -0,0 +1,30 @@
+package common.util;
+
+import common.vo.User;
+
+import javax.servlet.http.HttpSession;
+
+public class AuthUtil {
+
+    public static final String LOGIN_USER_SESSION_KEY = "loginUser";
+
+    public static final int SESSION_MAX_TIME = 60*60*1;//1시간
+
+    public static User getLoginUser () {
+        try {
+            //현재 client의 HttpSession 조회
+            HttpSession session = CommonUtil.getHttpSession(false);
+            if(session == null || session.getAttribute(LOGIN_USER_SESSION_KEY) == null
+                || ((User) session.getAttribute(LOGIN_USER_SESSION_KEY)).getUserId() == null) {
+                return null;
+            }else {
+                return (User) session.getAttribute(LOGIN_USER_SESSION_KEY);
+            }
+        } catch(Exception e) {
+            System.out.println("AuthUtil getLoginUser Error : ");
+            e.printStackTrace();
+            return null;
+        }
+    }
+
+}
 
src/back-end/main/java/common/util/CommendUtil.java (added)
+++ src/back-end/main/java/common/util/CommendUtil.java
@@ -0,0 +1,54 @@
+package common.util;
+
+import java.io.BufferedReader;
+import java.io.InputStreamReader;
+import java.util.concurrent.TimeUnit;
+
+public class CommendUtil{
+
+    public String commend (String commendLine) throws Exception {
+        String[] commend = {"", "", commendLine};
+        if (System.getProperty("os.name").indexOf("Windows") > -1) {
+            commend[0] = "cmd.exe";
+            commend[1] = "/C";
+        } else {
+            commend[0] = "/bin/sh";
+            commend[1] = "-c";
+        }//명령어 준비 끝
+
+        CountUtil countUtil = new CountUtil();
+        Thread thread = new Thread(countUtil);
+
+        Process process = Runtime.getRuntime().exec(commend);
+        thread.start();
+
+        boolean isComplete = process.waitFor(10000, TimeUnit.SECONDS);
+        countUtil.processEnd();
+
+        StringBuilder sb = new StringBuilder();
+        BufferedReader resultBufferReader = null;
+        BufferedReader errorBufferReader = null;
+        if (isComplete == true) {
+            String msg = null;
+            resultBufferReader = new BufferedReader(new InputStreamReader(process.getInputStream(), "EUC-KR"));
+            while ((msg = resultBufferReader.readLine()) != null) {
+                if (msg.contains(System.getProperty("line.separator")) == false) {
+                    System.out.println(msg);
+                    sb.append(msg);
+                }
+            }
+            errorBufferReader = new BufferedReader(new InputStreamReader(process.getErrorStream(), "EUC-KR"));
+            int err_count = 0;
+            while ((msg = errorBufferReader.readLine()) != null) {
+                if (msg.contains(System.getProperty("line.separator")) == false) {
+                    System.out.println(msg);
+                    sb.append(msg);
+                }
+            }
+        } else {
+            System.out.println("COMMAND : " + commend[2] + " - Timeout(" + 10000 + "초)");
+        }
+
+        return sb.toString();
+    }
+}
 
src/back-end/main/java/common/util/CommonUtil.java (added)
+++ src/back-end/main/java/common/util/CommonUtil.java
@@ -0,0 +1,1250 @@
+package common.util;
+
+import org.springframework.web.context.request.RequestContextHolder;
+import org.springframework.web.context.request.ServletRequestAttributes;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpSession;
+import java.io.IOException;
+import java.io.PrintWriter;
+import java.io.StringWriter;
+import java.lang.reflect.Field;
+import java.lang.reflect.Modifier;
+import java.net.InetAddress;
+import java.net.InetSocketAddress;
+import java.net.Socket;
+import java.net.UnknownHostException;
+import java.sql.Timestamp;
+import java.text.SimpleDateFormat;
+import java.time.LocalDateTime;
+import java.util.*;
+
+
+public class CommonUtil {
+
+	/**
+     * @author 최정우
+     * @since 2019.12.11
+     * 
+     * 데이터의 표준화 사용 유무 
+     */
+	private static boolean IS_USE_STANDARD = true;
+	
+	public static void setIsUseStandard (boolean isUseStandard) {
+		IS_USE_STANDARD = isUseStandard;
+	}
+	
+	public static boolean getIsUseStandard () {
+		return IS_USE_STANDARD;
+	}
+	
+	/**
+     * @author 최정우
+     * @since 2019.11.13
+     * 
+     * 빈 문자열 검사
+     */
+    public static boolean isNull(Object obj) {
+        return obj == null;
+    }
+    
+
+    /**
+     * @author 최정우
+     * @since 2019.11.13
+     * 
+     * string to int check
+     */
+    public static boolean isInt (String text) {
+		try {
+			Integer.parseInt(text);
+			return true;
+		} catch(NumberFormatException e) {
+			return false;
+		}
+	}
+    
+    /**
+     * @author 최정우
+     * @since 2019.11.13
+     * 
+     * string to int check
+     */
+    public static boolean isLong (String text) {
+		try {
+			Long.parseLong(text);
+			return true;
+		} catch(NumberFormatException e) {
+			return false;
+		}
+	}
+	
+    /**
+     * @author 최정우
+     * @since 2019.11.13
+     * 
+     * string to double check
+     */
+	public static boolean isDouble (String text) {
+		try {
+			Double.parseDouble(text);
+			return true;
+		} catch (NumberFormatException e) {
+			return false;
+		} catch (Exception e) {
+			return false;
+		}
+	}
+	
+	/**
+     * @author 최정우
+     * @since 2020.01.08
+     * 
+     * object to int
+     */
+	public static int parseInt (Object obj) {
+		try {
+			return Integer.parseInt(obj.toString());
+		} catch(Exception e) {
+			return 0;
+		}
+	}
+	
+	/**
+     * @author 최정우
+     * @since 2020.01.08
+     * 
+     * string to int
+     */
+	public static int parseInt (String text) {
+		try {
+			return Integer.parseInt(text);
+		} catch(NumberFormatException e) {
+			return 0;
+		}
+	}
+	
+	/**
+     * @author 최정우
+     * @since 2020.01.08
+     * 
+     * int to double 
+     */
+	public static long parseLong (int number) {
+		try {
+			return (long) number;
+		} catch(Exception e) {
+			return 0;
+		}
+	}
+	
+	/**
+     * @author 최정우
+     * @since 2020.01.08
+     * 
+     * object to double 
+     */
+	public static long parseLong (String text) {
+		try {
+			return Long.parseLong(text);
+		} catch(Exception e) {
+			return 0;
+		}
+	}
+
+	/**
+     * @author 최정우
+     * @since 2020.01.08
+     * 
+     * object to double 
+     */
+	public static long parseLong (Object obj) {
+		try {
+			if (obj instanceof Integer) {
+				return (long) obj;
+			} else {
+				return Long.parseLong(obj.toString());
+			}
+		} catch(Exception e) {
+			return 0;
+		}
+	}
+	
+	/**
+     * @author 최정우
+     * @since 2020.01.08
+     * 
+     * int to double 
+     */
+	public static double parseDouble (int number) {
+		try {
+			return (double) number;
+		} catch(Exception e) {
+			return 0.0;
+		}
+	}
+	
+	/**
+     * @author 최정우
+     * @since 2020.01.08
+     * 
+     * object to double 
+     */
+	public static double parseDouble (String text) {
+		try {
+			return Double.parseDouble(text);
+		} catch(Exception e) {
+			return 0.0;
+		}
+	}
+
+	/**
+     * @author 최정우
+     * @since 2020.01.08
+     * 
+     * object to double 
+     */
+	public static double parseDouble (Object obj) {
+		try {
+			if (obj instanceof Integer) {
+				return (double) obj;
+			} else {
+				return Double.parseDouble(obj.toString());
+			}
+		} catch(Exception e) {
+			return 0.0;
+		}
+	}
+	
+	/**
+     * @author 최정우
+     * @since 2019.11.13
+     * 
+     * 문자열의 모든 공백 제거
+     */
+	public static String allTrim(String text) {
+		return text.replaceAll("\\p{Z}", "");
+	}
+	
+	/**
+     * @author 최정우
+     * @since 2019.11.13
+     * 
+     * 문자열 앞뒤 공백 제거후, 문자열 사이에 존재하는 공백을 한개의 공백으로 치환
+     * ex) " abcd     efg    hijk   " => "abcd efg hijk" 
+     */
+	public static String normalizeSpace(String text) {
+		return text.trim().replaceAll("\\s+", " ");
+	}
+	
+	/**
+     * @author 최정우
+     * @since 2019.11.13
+     * 
+     * 숫자 빼고 모든 문자 제거
+     */
+	public static String getOnlyNumber (String text) {
+		return text.replaceAll("[^0-9]", "");
+	}
+	
+	/**
+     * @author 최정우
+     * @since 2019.11.13
+     * 
+     * 문자 빼고 모든 숫자 제거
+     */
+	public static String getOnlyText (String text) {
+		return text.replaceAll("[0-9]", "");
+	}
+	
+	/**
+     * @author 최정우
+     * @since 2019.11.13
+     * 
+     * 특정 문자열 개수 check
+     */
+	public static int getWordCount (String text, String word) {
+		int size = 0;
+		int fromIndex = -1;
+		while ((fromIndex = text.indexOf(word, fromIndex + 1)) >= 0) {
+			size++;
+		}
+		return size;
+	}
+
+	/**
+	 * @author 최정우
+	 * @since 2021.12.05
+	 * 
+	 * 현재 서버 일시 구하기
+	 */
+	public static Date getDateTime() {
+		LocalDateTime localDateTime = LocalDateTime.now();
+		return Timestamp.valueOf(localDateTime);
+	}
+	
+	/**
+     * @author 최정우
+     * @since 2019.11.13
+     * 
+     * 문자열 to Date문자열
+     */
+	public static boolean isDate (String text) {
+		if (StringUtil.isEmpty(text) == true || StringUtil.isEmpty(getOnlyNumber(text)) == true || getOnlyNumber(text).length() < 6) {
+			return false;
+		}
+		
+		//공백을 제외한 문자얻기, 대문자로 치환
+		String newText = allTrim(text).toUpperCase();
+		
+		try {
+			//문자열의 날짜 패턴 생성
+			String pattern = createDatePattern(newText);
+			if (pattern == null) {
+				return false;
+			}
+		
+			SimpleDateFormat newPattern = new SimpleDateFormat(pattern);
+			//문자열 날짜 형태로 변환
+			newPattern.parse(newText);
+			return true;
+		} catch (Exception e) {
+			//e.printStackTrace();
+			return false;
+		}
+	}
+	
+	/**
+     * @author 최정우
+     * @since 2019.11.13
+     * 
+     * 문자열 to Date문자열
+     */
+	public static String parseDateText (String text) {
+		if (StringUtil.isEmpty(text) == true || StringUtil.isEmpty(getOnlyNumber(text)) == true || getOnlyNumber(text).length() < 6) {
+			return null;
+		}
+		
+		//공백을 제외한 문자얻기, 대문자로 치환
+		String newText = allTrim(text).toUpperCase();
+		
+		//문자열의 날짜 패턴 생성 
+		String pattern = createDatePattern(newText);
+		if (pattern == null) {
+			return null;
+		}
+
+		Date date = null;
+		String dateText = null;
+		try {
+			SimpleDateFormat newPattern = new SimpleDateFormat(pattern);
+			
+			//문자열 날짜 형태로 변환
+			date = newPattern.parse(newText);
+			
+			//DB에 저장할 날짜 패턴
+			SimpleDateFormat defalutPattern = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
+			dateText = defalutPattern.format(date);
+		} catch (Exception e) {
+			//e.printStackTrace();
+		}
+		return dateText;
+	}
+	
+	public static <T> List<T> mapToList (Map<?, T> map) {
+		List<T> items = new ArrayList<T>();
+		
+		if (map != null) {
+			for(Map.Entry<?, T> item : map.entrySet()) {
+				items.add(item.getValue());
+	        }
+		}
+		
+		return items;
+	}
+	
+	public static Map objectToMap(Object obj) {
+		if (obj != null) {
+			try {
+				return (Map) obj;
+			} catch (Exception e) {
+				return new HashMap();
+			}
+		} else {
+			return new HashMap();
+		}
+	}
+	
+	
+	/*
+	 * 시간 타입
+	 * PM, AM
+	 */
+	public final static List<String> TIME_TYPES = Arrays.asList(new String[] {"AM", "PM", "오전", "오후"});
+	
+	/*
+	 * 날짜 포맷 패턴's
+	 */
+	public final static List<Character> DATE_PATTERNS = Arrays.asList(new Character[] {'y', 'M', 'd', 'H', 'm', 's'});
+	
+	/*
+	 * 날짜 포맷 패턴's의 최대 문자열 수
+	 */
+	public final static List<Integer> DATE_PATTERNS_MAX_LENGTH = Arrays.asList(new Integer[] {4, 2, 2, 2, 2, 2});
+	
+	/**
+     * @author 최정우
+     * @since 2019.11.13
+     * 
+     * 문자열의 날짜 패턴 생성
+     */
+	public static String createDatePattern (String date) {
+		
+		List<Character> DATE_PATTERNS = Arrays.asList(new Character[] {'y', 'M', 'd', 'H', 'm', 's'});
+		
+		//시간 표기가 (0~12 -> AM, PM사용)인지 (0~23)인지 확인 후, 날짜 포맷 패턴's에 있는 시간 패턴 변경
+		int timeTypeFindIndex = -1;
+		for (int i = 0; i < TIME_TYPES.size(); i++) {
+			//("AM", "PM", "오전", "오후" 중 1개)가 포함된 단어가 있는지 확인, Index 위치를 담기(없으면 -1)
+			if ((timeTypeFindIndex = date.indexOf(TIME_TYPES.get(i))) > -1) {
+				//문자열에 포함된 ("AM", "PM", "오전", "오후" 중 1개) 삭제
+				date = date.replaceAll(TIME_TYPES.get(i), "");
+				//시간 패턴 변경 [H -> h]
+				DATE_PATTERNS.set(3, 'h');
+				break;
+			}
+		}
+		
+		//숫자를 뺀 나머지 문자열 가지고오기 ex) "2020.08.03" -> ".."
+		//숫자를 뺀 나머지 문자열 가지고오기 ex) "2020.08.03 19:20:21" -> "..::"
+		final char[] separators = getOnlyText(date).toCharArray();
+		
+		/*
+		System.out.println("");
+		System.out.println("@@@@@@@@@@@@@@ textToDateText @@@@@@@@@@@@@@");
+		System.out.println("공백제거 텍스트 : " + date);
+		System.out.println("숫자제거 텍스트 : " + String.valueOf(separators));
+		*/
+		
+		//사용할 최대 패턴 수
+		int maxPatterSize = 0;
+		if (DATE_PATTERNS.size() <= separators.length) {
+			maxPatterSize = DATE_PATTERNS.size();
+		} else {
+			maxPatterSize = separators.length;
+		}
+		
+		//구분자별 Index 위치's (사용할 최대 패턴 수 + 시작점:-1, 종료점:date문자열의 최종 길이)
+		List<Integer> sizeByPatterns = new ArrayList<Integer>();
+		
+		//System.out.println("");
+		//System.out.println("newText : " + date);
+		
+		//구분자 별 Index 위치 파악 후, 앞에 있는 문자열의 수 찾은 후, 추가 (마지막 패턴 뒤에 있는 문자열을 따로 처리해줘야함)
+		int fromIndex = -1;
+		for (int i = 0; i < maxPatterSize; i++) {
+			//구분자
+			char separator = separators[i];
+			
+			//'현재 찾은 위치' : 이전에 찾은 위치(찾기 시작할 위치 => fromIndex) + 1 부터 찾기 시작함
+			int currentFromIndex = date.indexOf(separator, fromIndex + 1);
+			
+			//현재 패턴의 문자열 수 = '현재 찾은 위치' - '이전에 찾은 위치' - 1 [추가]
+			sizeByPatterns.add(currentFromIndex - fromIndex - 1);
+			//System.out.print("[" + sizeByPatterns.get(i) +"] ");
+			
+			//'현재 찾은 위치'는 '이전에 찾은 위치'가 됨
+			fromIndex = currentFromIndex;
+		}
+		//마지막 패턴 뒤에 있는 문자열 = '문자열의 길이' - '마지막에 찾은 위치(이전에 찾은 위치)' - 1 [추가]
+		sizeByPatterns.add(date.length() - fromIndex - 1);
+		
+		
+		
+		//System.out.println("");
+		//System.out.println("시간 타입 체킹 Index : " + timeTypeFindIndex);
+		
+		//패턴을 담을 변수
+		StringBuilder pattern = new StringBuilder();
+		
+		//DATE_PATTERS 순서 대로, 각 구분자 별 Index 위치 크기만큼 문자열에 패턴 삽입 + 구분자 삽입
+		//마지막 전까지만 for문 돌림
+		for (int i = 0, patternIndex = 0; i < sizeByPatterns.size() && patternIndex < DATE_PATTERNS.size(); i++, patternIndex++) {
+			
+			//패턴 추가
+			int usingSize = 0;
+			for (int j = 0; j < sizeByPatterns.get(i); j++) {
+				if (j >= usingSize + DATE_PATTERNS_MAX_LENGTH.get(patternIndex)) {
+					usingSize += DATE_PATTERNS_MAX_LENGTH.get(patternIndex++);
+					
+					/*단 한개의 패턴이라도 '최대 문자열 수'를 넘어서면 -> '날짜 아님'*/
+					if (i >= sizeByPatterns.size() || patternIndex >= DATE_PATTERNS.size()) {
+						return null;
+					}
+				}
+				
+				pattern.append(DATE_PATTERNS.get(patternIndex));
+			}
+			
+			//날짜 구분자 추가 (마지막 구분자까지만) 
+			if (i < separators.length) {
+				pattern.append(separators[i]);
+			}
+			
+			
+		}
+		
+		if (timeTypeFindIndex > -1) {
+			pattern.insert(timeTypeFindIndex, 'a');
+		}
+		
+		return pattern.toString();
+	}
+	
+	
+	/**
+     * @author 최정우
+     * @since 2020.01.26
+     * 
+     * ping 체크
+     */
+	public static boolean pingCheck (String ip) {
+		InetAddress inetAddress;
+		try {
+			inetAddress = InetAddress.getByName(ip);
+			return inetAddress.isReachable(1000);
+		} catch (UnknownHostException e) {
+			return false;
+		} catch (IOException e) {
+			return false;
+		} catch (Exception e) {
+			return false;
+		}
+	}
+
+	/**
+	 * @author 최정우
+	 * @since 2020.01.26
+	 *
+	 * 현재 client의 HttpServletRequest 조회
+	 */
+	public static HttpServletRequest getHttpServletRequest () {
+		try {
+			ServletRequestAttributes servletRequestAttribute = (ServletRequestAttributes) RequestContextHolder.currentRequestAttributes();
+			return servletRequestAttribute.getRequest();
+		} catch (Exception e) {
+			return null;
+		}
+	}
+
+	/**
+	 * @author 최정우
+	 * @since 2020.01.26
+	 *
+	 * 현재 client의 HttpSession 조회
+	 */
+	public static HttpSession getHttpSession (boolean create) {
+		try {
+			HttpServletRequest request = getHttpServletRequest();
+			if (request != null) {
+				return request.getSession(create);
+			} else {
+				return null;
+			}
+		} catch (Exception e) {
+			return null;
+		}
+	}
+
+	/**
+	 * @author 최정우
+	 * @since 2020.01.26
+	 *
+	 * HttpServletRequest를 활용한 Client IP 가지고오기
+	 * Header의 X-FORWARDED-FOR 값을 통해 IP 조회, 만약 Header에 X-FORWARDED-FOR가 없으면 getRemoteAddr() 이걸로 조회
+	 */
+	public static String getClientIp () {
+		try {
+			HttpServletRequest request = getHttpServletRequest();
+			if (null != request.getHeader("X-FORWARDED-FOR")) {
+				return request.getHeader("X-FORWARDED-FOR");
+			} else {
+				return request.getRemoteAddr();
+			}
+		} catch (Exception e) {
+			return null;
+		}
+	}
+
+
+	
+	/**
+     * @author 최정우
+     * @since 2020.01.26
+     * 
+     * ping 체크 (ip + port)
+     */
+	public static boolean pingCheck(String ip, int port) {
+		Socket socket = new Socket();
+		try {
+			socket.connect(new InetSocketAddress(ip, port), 1000);
+			boolean isConnect = socket.isConnected();
+			socket.close();
+			return isConnect;
+		} catch (UnknownHostException e) {
+			return false;
+		} catch (IOException e) {
+			return false;
+		} catch (Exception e) {
+			return false;
+		}
+	}
+
+	/************************************* objectSetValue : Object to Object (start) *************************************/
+	/**
+	 * @author 최정우
+	 * @since 2020.04.22
+	 *
+	 * [리플렉션 활용] VO객체(valueObject)의 변수들의 값 -> 목표 객체(targetObject)에 setting 해주는 메서드
+	 *
+	 * 단, '명칭'과 '데이터 타입'이 같아야 값이 세팅됨
+	 */
+	public static void objectSetValue (Object targetObject, Object valueObject) {
+		objectSetValue(targetObject, valueObject, null, null);
+	}
+
+	public static void objectSetValue (Object targetObject, Object valueObject, Class<?>[] ignoreClasses) {
+		objectSetValue(targetObject, valueObject, ignoreClasses, null);
+	}
+
+	public static void objectSetValue (Object targetObject, Object valueObject, String[] ignoreFields) {
+		objectSetValue(targetObject, valueObject, null, ignoreFields);
+	}
+
+	/**
+	 * @author 최정우
+	 * @since 2020.04.22
+	 *
+	 * [리플렉션 활용] VO객체(valueObject)의 변수들의 값 -> 목표 객체(targetObject)에 setting 해주는 메서드 (+ 제거할 변수 목록)
+	 *
+	 * 단, '명칭'과 '데이터 타입'이 같아야 값이 세팅됨
+	 */
+	public static void objectSetValue (Object targetObject, Object valueObject, Class<?>[] ignoreClasses, String[] ignoreFields) {
+		//빈값 체크
+		if (valueObject == null || targetObject == null) {
+			return;
+		}
+
+		//vo객체의 클래스 정보 얻기
+		Class<?> valueObjectClass = valueObject.getClass();
+		//vo객체의 클래스의 값이 null이 될 때 까지 반복
+		while (valueObjectClass != null) {
+
+			/* Class 필터 */
+			boolean isIgnoreClassFind = false;
+			if (ignoreClasses != null) {
+				for (Class<?> ignoreClass : ignoreClasses) {
+					if (valueObjectClass.getName().equals(ignoreClass.getName())) {
+						//System.out.println("["+valueObjectClass.getName()+"] 제거(값 세팅 안하고 return) @@@@@@@@@@@@@@@@@@@@@");
+						isIgnoreClassFind = true;
+						break;
+					}
+				}
+
+				//제거할 Class를 찾았을 때 -> 다음 상위 클래스로 이동
+				if (isIgnoreClassFind == true) {
+					//vo객체가 상속받은 상위클래스 정보 얻기
+					valueObjectClass = valueObjectClass.getSuperclass();
+					continue;//while문으로 이동
+				}
+			}/* Class 필터 */
+
+			//vo객체의 Field목록 얻기
+			Field[] valueObjectFields = valueObjectClass.getDeclaredFields();
+			//Field 목록이 있을 때 -> 값 세팅하러 가기
+			if (valueObjectFields != null && valueObjectFields.length > 0) {
+				for (int i = 0; i < valueObjectFields.length; i++) {
+
+					/* Field 필터 */
+					boolean isIgnoreFieldFind = false;
+					if (ignoreFields != null) {
+						for (String ignoreField : ignoreFields) {
+							if (valueObjectFields[i].getName().equals(ignoreField)) {
+								//System.out.println("["+valueObjectFields[i].getName()+"] 제거(값 세팅 안하고 return) @@@@@@@@@@@@@@@@@@@@@");
+								isIgnoreFieldFind = true;
+								break;
+							}
+						}
+						//제거할 Field를 찾았을 때 -> 다음 Field로 이동
+						if (isIgnoreFieldFind == true) {
+							continue;//for문으로 이동
+						}
+					}/* Field 필터 */
+
+					//현재 vo객체 정보를 target객체에 값 세팅하기
+					objectSetValueForField(targetObject, targetObject.getClass(), valueObject, valueObjectFields[i]);
+				}
+			}
+
+			//vo객체가 상속받은 상위클래스 정보 얻기
+			valueObjectClass = valueObjectClass.getSuperclass();
+		}
+	}
+
+	/**
+	 * @author 최정우
+	 * @since 2020.04.22
+	 *
+	 * public objectSetValue에서만 호출 가능
+	 *
+	 */
+	private static void objectSetValueForField (Object targetObject, Class<?> targetObjectSuperClass, Object valueObject, Field valueObjectField) {
+		//빈값 체크
+		if (valueObject == null || valueObjectField == null || targetObject == null || targetObjectSuperClass == null) {
+			return;
+		}
+
+		//Field 접근자 타입이 private라도 필드 정보에 접근가능하게 해줌
+		valueObjectField.setAccessible(true);
+		try {
+			//vo객체의 변수필드의 명칭을 이용하여, 목표 객체의 변수필드 찾기. 만약, 못 찾으면 -> NoSuchFieldException오류 발생 -> catch로 이동
+			Field targetObjectField = targetObjectSuperClass.getDeclaredField(valueObjectField.getName());
+			targetObjectField.setAccessible(true);//private 변수도 접근가능하도록 settting
+
+			//데이터 전달 객체의 필드 데이터 타입
+			String valueObjectFieldType = valueObjectField.getType().getName();
+
+			//타겟 객체의 필드 데이터 타입
+			String targetFieldType = targetObjectField.getType().getTypeName();
+
+			/* 목표 객체의 변수필드가 상수(final)이 아니고, 데이터 타입이 같고 때 -> 같은 클래스의 변수필드 인지 확인 */
+			if (Modifier.isFinal(targetObjectField.getModifiers()) == false) {
+
+				//데이터 타입이 완전 똑같을 때
+				if (valueObjectFieldType.equals(targetFieldType)) {
+					//값 세팅
+					targetObjectField.set(targetObject, valueObjectField.get(valueObject));
+				} else {
+
+					//타겟 변수가 기본형 변수 일 때
+					if (targetObjectField.getType().isPrimitive()) {
+						String typeFullName = "java.lang." + targetFieldType;
+						if (typeFullName.toLowerCase().equals(valueObjectFieldType.toLowerCase())) {
+							//값 세팅
+							targetObjectField.set(targetObject, valueObjectField.get(valueObject));
+						} else {
+							throw new NoSuchFieldException();
+						}
+					} else if (targetObjectField.getType().isInterface()) {//타겟 변수가 인터페이스 일 때
+						//데이터 전달 객체 변수의 타입이 '타겟 변수의 인터페이스'구현체인지 확인하기
+						boolean isImpl = false;
+						//데이터 전달 객체 변수 객체 생성
+						Class<?> runtimeClass = ClassLoader.getSystemClassLoader().loadClass(valueObjectFieldType);
+						//데이터 전달 객체 변수의 '인터페이스' 목록 가지고오기
+						Class<?>[] impls = runtimeClass.getInterfaces();
+						//인터페이스가 있는지 없는지 확인
+						for(Class<?> clz : impls) {
+							if(clz.getName().equals(targetFieldType)) {
+								isImpl = true;
+							}
+						}
+
+						//구현체라면
+						if (isImpl == true) {
+							//값 세팅
+							targetObjectField.set(targetObject, valueObjectField.get(valueObject));
+						} else {
+							throw new NoSuchFieldException();
+						}
+
+					} else {
+						throw new NoSuchFieldException();
+					}
+				}
+
+			}
+
+		} catch (NoSuchFieldException e) {//목표 객체에서 변수를 발견 못했을 때 -> 목표 객체의 상위클래스 변수에서 찾아보기
+			//목표 객체의 상위클래스가 존재할 때 -> 재귀 호출
+			if (targetObjectSuperClass.getSuperclass() != null) {
+				try {
+					//목표객체의 상위클래스에서 변수 찾아서 값넣어주기 위해 재귀호출함
+					objectSetValueForField(targetObject, targetObjectSuperClass.getSuperclass(), valueObject, valueObjectField);
+				} catch (Exception e1) {
+					e1.printStackTrace();
+				}
+			} else {
+				return;
+			}
+
+		} catch (Exception e) {
+			e.printStackTrace();
+		}
+
+	}
+	/************************************* objectSetValue : Object to Object (end) *************************************/
+
+	/************************************* objectSetMapValue : Map to Object (start) *************************************/
+	/**
+	 * @author 최정우
+	 * @since 2020.04.22
+	 *
+	 * [리플렉션 활용] Map객체(Map<?, ?>)의 변수들의 값 -> 목표 객체(targetObject)에 setting 해주는 메서드 (+ 제거할 변수 목록)
+	 *
+	 * 단, '명칭'과 '데이터 타입'이 같아야 값이 세팅됨
+	 */
+	public static void objectSetMapValue (Object targetObject, Map<?, ?> valueObject) {
+		objectSetMapValue(targetObject, valueObject, null);
+	}
+
+	/**
+	 * @author 최정우
+	 * @since 2020.04.22
+	 *
+	 * [리플렉션 활용] Map객체(Map<?, ?>)의 변수들의 값 -> 목표 객체(targetObject)에 setting 해주는 메서드 (+ 제거할 변수 목록)
+	 *
+	 * 단, '명칭'과 '데이터 타입'이 같아야 값이 세팅됨
+	 */
+	public static void objectSetMapValue (Object targetObject, Map<?, ?> valueObject, String[] ignoreFields) {
+		//빈값 체크
+		if (valueObject == null || targetObject == null) {
+			return;
+		}
+
+		for(Map.Entry<?, ?> elem : valueObject.entrySet()) {
+			String fieldName = StringUtil.toString(elem.getKey());
+			Object fieldValue = elem.getValue();
+
+			if (fieldValue == null) continue;
+
+			String fieldType = elem.getValue().getClass().getTypeName();
+
+
+			/* Field 필터 */
+			boolean isIgnoreFieldFind = false;
+			if (ignoreFields != null) {
+				for (String ignoreField : ignoreFields) {
+					if (fieldName.equals(ignoreField)) {
+						//System.out.println("["+valueObjectFields[i].getName()+"] 제거(값 세팅 안하고 return) @@@@@@@@@@@@@@@@@@@@@");
+						isIgnoreFieldFind = true;
+						break;
+					}
+				}
+				//제거할 Field를 찾았을 때 -> 다음 Field로 이동
+				if (isIgnoreFieldFind == true) {
+					continue;//for문으로 이동
+				}
+			}/* Field 필터 */
+
+			objectSetValueForField(targetObject, targetObject.getClass(), fieldName, fieldType, fieldValue);
+		}
+	}
+
+	/**
+	 * @author 최정우
+	 * @since 2020.04.22
+	 *
+	 * [리플렉션 활용] Map객체(Map<?, ?>)의 변수들의 값 -> 목표 객체(targetObject)에 setting 해주는 메서드 (+ 제거할 변수 목록)
+	 *
+	 * 단, '명칭'과 '데이터 타입'이 같아야 값이 세팅됨
+	 */
+	public static void objectSetValueForField (Object targetObject, Class<?> targetObjectSuperClass, String fieldName, String fieldType, Object fieldValue) {
+		//System.out.println("targetObjectName : " + targetObject.getClass().getName() + ", targetObjectSuperClassName : " + targetObjectSuperClass.getName() + ", fieldName : " + fieldName + ", fieldType : " + fieldType);
+
+		//빈값 체크
+		if (StringUtil.isEmpty(fieldName) == true || StringUtil.isEmpty(fieldType) == true || fieldValue == null
+				|| targetObject == null || targetObjectSuperClass == null) {
+			return;
+		}
+
+		try {
+			//vo객체의 변수필드의 명칭을 이용하여, 목표 객체의 변수필드 찾기. 만약, 못 찾으면 -> NoSuchFieldException오류 발생 -> catch로 이동
+			Field targetObjectField = targetObjectSuperClass.getDeclaredField(fieldName);
+			targetObjectField.setAccessible(true);//private 변수도 접근가능하도록 settting
+			//System.out.println("targetObjectFieldName : " + targetObjectField.getName() + ", targetObjectField Type Name : " + targetObjectField.getType().getTypeName() + ", " + targetObjectField.getType().getName() + ", 기본형 유무 : " + targetObjectField.getType().isPrimitive() + ", 인터페이스 유무 : " + targetObjectField.getType().isInterface());
+
+			//타겟 객체의 필드 데이터 타입
+			String targetFieldType = targetObjectField.getType().getTypeName();
+
+			/* 목표 객체의 변수필드가 상수(final)이 아니고, 데이터 타입이 같고 때 -> 같은 클래스의 변수필드 인지 확인 */
+			if (Modifier.isFinal(targetObjectField.getModifiers()) == false) {
+
+				//데이터 타입이 완전 똑같을 때
+				if (fieldType.equals(targetFieldType)) {
+					//값 세팅
+					targetObjectField.set(targetObject, fieldValue);
+					//System.out.println("셋팅 완료");
+				} else {
+
+					//타겟 변수가 기본형 변수 일 때
+					if (targetObjectField.getType().isPrimitive()) {
+						String typeFullName = "java.lang." + targetFieldType;
+						if (typeFullName.toLowerCase().equals(fieldType.toLowerCase())) {
+							//값 세팅
+							targetObjectField.set(targetObject, fieldValue);
+							//System.out.println("셋팅 완료");
+						} else {
+							throw new NoSuchFieldException();
+						}
+					} else if (targetObjectField.getType().isInterface()) {//타겟 변수가 인터페이스 일 때
+						//데이터 전달 객체 변수의 타입이 '타겟 변수의 인터페이스'구현체인지 확인하기
+						boolean isImpl = false;
+						//데이터 전달 객체 변수 객체 생성
+						Class<?> runtimeClass = ClassLoader.getSystemClassLoader().loadClass(fieldType);
+						//데이터 전달 객체 변수의 '인터페이스' 목록 가지고오기
+						Class<?>[] impls = runtimeClass.getInterfaces();
+						//인터페이스가 있는지 없는지 확인
+						for(Class<?> clz : impls) {
+							if(clz.getName().equals(targetFieldType)) {
+								isImpl = true;
+							}
+						}
+
+						//구현체라면
+						if (isImpl == true) {
+							//값 세팅
+							targetObjectField.set(targetObject, fieldValue);
+							//System.out.println("셋팅 완료");
+						} else {
+							throw new NoSuchFieldException();
+						}
+					} else {
+						throw new NoSuchFieldException();
+					}
+
+				}
+
+			} else {
+				return;
+			}
+
+		} catch (NoSuchFieldException e) {//목표 객체에서 변수를 발견 못했을 때 -> 목표 객체의 상위클래스 변수에서 찾아보기
+			//목표 객체의 상위클래스가 존재할 때 -> 재귀 호출
+			if (targetObjectSuperClass.getSuperclass() != null) {
+				try {
+					//목표객체의 상위클래스에서 변수 찾아서 값넣어주기 위해 재귀호출함
+					objectSetValueForField(targetObject, targetObjectSuperClass.getSuperclass(), fieldName, fieldType, fieldValue);
+				} catch (Exception e1) {
+					e1.printStackTrace();
+				}
+			} else {
+				return;
+			}
+		} catch (Exception e) {
+			e.printStackTrace();
+		}
+
+		System.out.println("");
+	}
+
+	/**
+	 * @author 최정우
+	 * @since 2020.04.22
+	 *
+	 * [리플렉션 활용] Map객체(Map<?, ?>)의 변수들의 값 -> 목표 객체(targetObject)에 setting 해주는 메서드 (+ 제거할 변수 목록)
+	 *
+	 * 단, '명칭'과 '데이터 타입'이 같아야 값이 세팅됨
+	 */
+	public static void objectSetValueForField (Object targetObject, Class<?> targetObjectSuperClass, String fieldName, Object fieldValue) {
+		//빈값 체크
+		if (StringUtil.isEmpty(fieldName) == true || fieldValue == null || targetObject == null || targetObjectSuperClass == null) {
+			return;
+		}
+
+		try {
+			//vo객체의 변수필드의 명칭을 이용하여, 목표 객체의 변수필드 찾기. 만약, 못 찾으면 -> NoSuchFieldException오류 발생 -> catch로 이동
+			Field targetObjectField = targetObjectSuperClass.getDeclaredField(fieldName);
+			targetObjectField.setAccessible(true);//private 변수도 접근가능하도록 settting
+
+			/* 목표 객체의 변수필드가 상수(final)이 아니고, 데이터 타입이 같고 때 -> 같은 클래스의 변수필드 인지 확인 */
+			if (Modifier.isFinal(targetObjectField.getModifiers()) == false) {
+				//값 세팅
+				targetObjectField.set(targetObject, targetObjectField.getType().cast(fieldValue));
+				//같은 클래스일 때 ->
+			} else {
+				return;
+			}
+
+		} catch (NoSuchFieldException e) {//목표 객체에서 변수를 발견 못했을 때 -> 목표 객체의 상위클래스 변수에서 찾아보기
+			//목표 객체의 상위클래스가 존재할 때 -> 재귀 호출
+			if (targetObjectSuperClass.getSuperclass() != null) {
+				try {
+					//목표객체의 상위클래스에서 변수 찾아서 값넣어주기 위해 재귀호출함
+					objectSetValueForField(targetObject, targetObjectSuperClass.getSuperclass(), fieldName, fieldValue);
+				} catch (Exception e1) {
+					e1.printStackTrace();
+				}
+			} else {
+				return;
+			}
+		} catch (Exception e) {
+			e.printStackTrace();
+		}
+	}
+	/************************************* objectSetMapValue : Map to Object (end) *************************************/
+	
+	
+	/**
+	 * @author 최정우
+	 * @since 2020.04.22
+	 * 
+	 * public objectSetValue에서만 호출 가능
+	 * 
+	 */
+	public static void objectHTMLFilter (Object targetObject, Class<?> targetObjectClass) {
+		//빈값 체크
+		if (targetObject == null || targetObjectClass == null) {
+			return;
+		}
+		
+		//vo객체의 Field목록 얻기
+		Field[] valueObjectFields = targetObjectClass.getDeclaredFields();
+		
+		Field test = null;
+		//Field 목록이 있을 때 -> 값 세팅하러 가기
+		if (valueObjectFields != null && valueObjectFields.length > 0) {
+			for (int i = 0; i < valueObjectFields.length; i++) {
+				//현재 vo객체 정보를 target객체에 값 세팅하기 
+				//Field 접근자 타입이 private라도 필드 정보에 접근가능하게 해줌
+				valueObjectFields[i].setAccessible(true);
+				try {
+					
+					//System.out.println("valueObjectFields["+i+"].getType().getName() : " + valueObjectFields[i].getType().getName() + ", name : " + valueObjectFields[i].getName() + ", value : " + valueObjectFields[i].get(targetObject) + ", getGenericType().getTypeName() : " + valueObjectFields[i].getGenericType().getTypeName());
+					
+					/* 목표 객체의 변수필드가 상수(final)이 아니고, 데이터 타입이 같고 때 -> 같은 클래스의 변수필드 인지 확인 */
+					if (Modifier.isFinal(valueObjectFields[i].getModifiers()) == false) {
+						if (valueObjectFields[i].getGenericType().getTypeName().equals("java.lang.String")) {
+							
+							String value = StringUtil.toString(valueObjectFields[i].get(targetObject));
+							if (StringUtil.isEmpty(value) == false) {
+								//같은 클래스일 때 -> 값 세팅
+								valueObjectFields[i].set(targetObject, StringUtil.cleanXSS(value));
+							} else {
+								continue;
+							}
+						} else if (valueObjectFields[i].getGenericType().getTypeName().contains("List")) {
+							List<Object> list = (List<Object>) valueObjectFields[i].get(targetObject);
+							if (list != null) {
+								for (int j = 0; j < list.size(); j++) {
+									if (list.get(j) == null) {
+										continue;
+									} else if (list.get(j).getClass().getTypeName().indexOf(".") < 0) {
+										continue;
+									} else if (list.get(j).getClass().getTypeName().equals("java.lang.String")) {
+										String value = StringUtil.toString(list.get(j));
+										list.set(j, StringUtil.cleanXSS(value));
+									} else if (list.get(j).getClass().getTypeName().contains("java.lang")) {
+										continue;
+									} else if (list.get(j).getClass().getTypeName().contains("List")
+											|| list.get(j).getClass().getTypeName().contains("[]")
+											|| list.get(j).getClass().getTypeName().contains("Map")
+											|| list.get(j).getClass().getTypeName().contains("Set")
+											|| list.get(j).getClass().getTypeName().contains("Collection")
+											|| list.get(j).getClass().getTypeName().contains("kr.co.sppartners")) {
+										objectHTMLFilter(list.get(j), list.get(j).getClass());
+									} else {
+										continue;
+									}
+								}
+							}
+						} else if (valueObjectFields[i].getGenericType().getTypeName().contains("[]")) {
+							Object[] arr = (Object[]) valueObjectFields[i].get(targetObject);
+							if (arr != null) {
+								for (int j = 0; j < arr.length; j++) {
+									if (arr[j] == null) {
+										continue;
+									} else if (arr[j].getClass().getTypeName().indexOf(".") < 0) {
+										continue;
+									} else if (arr[j].getClass().getTypeName().equals("java.lang.String")) {
+										String value = StringUtil.toString(arr[j]);
+										arr[j] = StringUtil.cleanXSS(value);
+									} else if (arr[j].getClass().getTypeName().contains("java.lang")) {
+										continue;
+									} else if (arr[j].getClass().getTypeName().contains("List")
+											|| arr[j].getClass().getTypeName().contains("[]")
+											|| arr[j].getClass().getTypeName().contains("Map")
+											|| arr[j].getClass().getTypeName().contains("Set")
+											|| arr[j].getClass().getTypeName().contains("Collection")
+											|| arr[j].getClass().getTypeName().contains("kr.co.sppartners")) {
+										objectHTMLFilter(arr[j], arr[j].getClass());
+									} else {
+										continue;
+									}
+								}
+							}
+						} else if (valueObjectFields[i].getGenericType().getTypeName().contains("Map")) {
+							if (valueObjectFields[i].getGenericType().getTypeName().contains("Map$Entry")
+								|| valueObjectFields[i].getGenericType().getTypeName().contains("Map$Node")) {
+								Map.Entry<Object, Object> entry = (Map.Entry<Object, Object>) valueObjectFields[i].get(targetObject);
+								if (entry != null) {
+									if (entry.getValue() == null) {
+										continue;
+									} else if (entry.getValue().getClass().getTypeName().indexOf(".") < 0) {
+										continue;
+									} else if (entry.getValue().getClass().getTypeName().equals("java.lang.String")) {
+										String value = StringUtil.toString(entry.getValue());
+										entry.setValue(StringUtil.cleanXSS(value));
+									} else if (entry.getValue().getClass().getTypeName().contains("java.lang")) {
+										continue;
+									} else if (entry.getValue().getClass().getTypeName().contains("List")
+											|| entry.getValue().getClass().getTypeName().contains("[]")
+											|| entry.getValue().getClass().getTypeName().contains("Map")
+											|| entry.getValue().getClass().getTypeName().contains("Set")
+											|| entry.getValue().getClass().getTypeName().contains("Collection")
+											|| entry.getValue().getClass().getTypeName().contains("kr.co.sppartners")) {
+										objectHTMLFilter(entry.getValue(), entry.getValue().getClass());
+									} else {
+										continue;
+									}
+								}
+							} else {
+								Map<Object, Object> map = (Map<Object, Object>) valueObjectFields[i].get(targetObject);
+								
+								if (map != null) {
+									for (Object key : map.keySet()) {
+										if (map.get(key) == null) {
+											continue;
+										} else if (map.get(key).getClass().getTypeName().indexOf(".") < 0) {
+											continue;
+										} else if (map.get(key).getClass().getTypeName().equals("java.lang.String")) {
+											String value = StringUtil.toString(map.get(key));
+											map.put(key, StringUtil.cleanXSS(value));
+										} else if (map.get(key).getClass().getTypeName().contains("java.lang")) {
+											continue;
+										} else if (map.get(key).getClass().getTypeName().contains("List")
+												|| map.get(key).getClass().getTypeName().contains("[]")
+												|| map.get(key).getClass().getTypeName().contains("Map")
+												|| map.get(key).getClass().getTypeName().contains("Set")
+												|| map.get(key).getClass().getTypeName().contains("Collection")
+												|| map.get(key).getClass().getTypeName().contains("kr.co.sppartners")) {
+											objectHTMLFilter(map.get(key), map.get(key).getClass());
+										} else {
+											continue;
+										}
+									}
+								}
+							}
+							
+						} else if (valueObjectFields[i].getGenericType().getTypeName().contains("Set")) {
+							Set<Object> set = (Set<Object>) valueObjectFields[i].get(targetObject);
+							if (set != null) {
+								for (Object obj : set) {
+									if (obj == null) {
+										continue;
+									} else if (obj.getClass().getTypeName().indexOf(".") < 0) {
+										continue;
+									} else if (obj.getClass().getTypeName().equals("java.lang.String")) {
+										set.remove(obj);
+										String value = StringUtil.toString(obj);
+										set.add(StringUtil.cleanXSS(value));
+									} else if (obj.getClass().getTypeName().contains("java.lang")) {
+										continue;
+									} else if (obj.getClass().getTypeName().contains("List")
+											|| obj.getClass().getTypeName().contains("[]")
+											|| obj.getClass().getTypeName().contains("Map")
+											|| obj.getClass().getTypeName().contains("Set")
+											|| obj.getClass().getTypeName().contains("Collection")
+											|| obj.getClass().getTypeName().contains("kr.co.sppartners")) {
+										objectHTMLFilter(obj, obj.getClass());
+									} else {
+										continue;
+									}
+								}
+							}
+						} else if (valueObjectFields[i].getGenericType().getTypeName().contains("java.util.Collection")) {
+							Collection<Object> collection = (Collection<Object>) valueObjectFields[i].get(targetObject);
+							if (collection != null) {
+								for (Object obj : collection) {
+									if (obj == null) {
+										continue;
+									} else if (obj.getClass().getTypeName().indexOf(".") < 0) {
+										continue;
+									} else if (obj.getClass().getTypeName().equals("java.lang.String")) {
+										collection.remove(obj);
+										String value = StringUtil.toString(obj);
+										collection.add(StringUtil.cleanXSS(value));
+									} else if (obj.getClass().getTypeName().contains("java.lang")) {
+										continue;
+									} else if (obj.getClass().getTypeName().contains("List")
+											|| obj.getClass().getTypeName().contains("[]")
+											|| obj.getClass().getTypeName().contains("Map")
+											|| obj.getClass().getTypeName().contains("Set")
+											|| obj.getClass().getTypeName().contains("Collection")
+											|| obj.getClass().getTypeName().contains("kr.co.sppartners")) {
+										objectHTMLFilter(obj, obj.getClass());
+									} else {
+										continue;
+									}
+								}
+							}
+						}
+						
+						else {
+							continue;
+						}
+					} else {
+						continue;
+					}
+				}  catch (Exception e) {
+					e.printStackTrace();
+					//System.out.println("valueObjectFields[i].getGenericType().getTypeName() 에러발생 : " + valueObjectFields[i].getGenericType().getTypeName());
+				}
+			}
+		}
+		
+		//System.out.println("targetObjectClass.getSimpleName() : " + targetObjectClass.getSimpleName());
+		
+		if (targetObjectClass.getSimpleName() != "CommonVO" && targetObjectClass.getSuperclass() != null) {
+			try {
+				//목표객체의 상위클래스에서 변수 찾아서 값넣어주기 위해 재귀호출함 
+				objectHTMLFilter(targetObject, targetObjectClass.getSuperclass());
+			} catch (Exception e1) {
+				e1.printStackTrace();
+			} 
+		} else {
+			return;
+		}
+	}
+
+
+	/**
+	 * @author 최정우
+	 * @since 2019.12.09
+	 * 
+	 * 데이터 셋 목록 Convert LinkedHashMap<String, Object> to List<String>
+	 */
+	public static List<List<String>> rowDataMapToList (List<LinkedHashMap<String, Object>> rowMapData) throws Exception {
+		List<List<String>> rowData = new ArrayList<List<String>>();
+		for (int i = 0; i < rowMapData.size(); i++) {
+			List<String> row = new ArrayList<String>();
+			LinkedHashMap<String, Object> mapdata = rowMapData.get(i);
+	        for( String key : mapdata.keySet() ){
+	        	if (mapdata.get(key) == null) {
+	        		row.add(null);//null값 대체
+	        	} else {
+	        		row.add(mapdata.get(key).toString());
+	        	}
+	        }
+	        rowData.add(row);
+		}
+		return rowData;
+	}
+
+	public static int getRandomInt (int min, int max) {
+		return (int) Math.round(Math.random() * (max - min));// + min;
+	}
+
+
+	/**
+	 * 작성일 : 210316 작성자 : 최정우
+	 *
+	 * Exception -> String
+	 *
+	 * @param e : Exception
+	 */
+	public static String exceptionToString(Exception e) {
+		StringWriter errors = new StringWriter();
+		e.printStackTrace(new PrintWriter(errors));
+		return "[Error] " + errors.toString();
+	}
+}
 
src/back-end/main/java/common/util/CountUtil.java (added)
+++ src/back-end/main/java/common/util/CountUtil.java
@@ -0,0 +1,27 @@
+package common.util;
+
+public class CountUtil implements Runnable {
+
+    private boolean isProcessFinish = false;
+    private int count = 0;
+
+    @Override
+    public void run () {
+        while (true) {
+            System.out.println("명령어 실행 중... (" + (count++) + "초)");
+            if (isProcessFinish == true) {
+                break;
+            }
+
+            try {
+                Thread.sleep(1000);
+            } catch (Exception e) {
+                e.printStackTrace();
+            }
+        }
+    }
+
+    public void processEnd () {
+        this.isProcessFinish = true;
+    }
+}
 
src/back-end/main/java/common/util/CryptoUtil.java (added)
+++ src/back-end/main/java/common/util/CryptoUtil.java
@@ -0,0 +1,278 @@
+package common.util;
+
+
+import javax.crypto.Cipher;
+import javax.servlet.http.HttpSession;
+import java.security.*;
+import java.security.spec.PKCS8EncodedKeySpec;
+import java.security.spec.X509EncodedKeySpec;
+import java.util.Base64;
+
+/**
+ * @author 최정우
+ * @since 2021.10.31
+ *
+ * 암호화 관련 모듈 Class 입니다.
+ */
+public class CryptoUtil {
+
+    /**
+     * @author 최정우
+     * @since 2021.11.12
+     *
+     * session에 RSA 암호화 Key생성 후, 공개키 반환 (무조건 새로 생성)
+     */
+    public static PublicKey getPublicKeyInSession () {
+        try {
+            //현재 client의 HttpSession 조회
+            HttpSession session = CommonUtil.getHttpSession(true);
+
+            /** session이 존재하지 않을 때 **/
+            if(session == null) {
+                return null;
+            }/** session이 존재할 때 **/ else {
+                //rsaKey 생성
+                KeyPair keyPair = genRsaKeyPair();
+                //session에 rsaKey 담기
+                session.setAttribute("rsaKey", keyPair);
+                //공개키 return
+                return keyPair.getPublic();
+            }
+        } catch(Exception e) {
+            System.out.println("AuthUtil getPublicKeyInSession Error : ");
+            e.printStackTrace();
+            return null;
+        }
+    }
+
+    /**
+     * @author 최정우
+     * @since 2021.11.12
+     *
+     * session에 담겨진 RSA 개인키 반환 (session에서 암호화 Key 무조건 삭제)
+     */
+    public static PrivateKey getPrivateKeyInSession () {
+        try {
+            //현재 client의 HttpSession 조회
+            HttpSession session = CommonUtil.getHttpSession(false);
+
+            /** session이 존재하지 않을 때 **/
+            if(session == null) {
+                return null;
+            }/** session이 존재할 때 **/ else {
+                //session에 있는 rsaKey 가지고오기
+                KeyPair keyPair = (KeyPair) session.getAttribute("rsaKey");
+                //session에 있는 rsaKey 삭제
+                deleteRsaKeyInSession();
+                //공개키 return
+                return keyPair.getPrivate();
+            }
+        } catch(Exception e) {
+            System.out.println("AuthUtil getPrivateKeyInSession Error : ");
+            e.printStackTrace();
+            return null;
+        }
+    }
+
+    /*
+     * @author 최정우
+     * @since 2021.11.12
+     *
+     * session에 RSA암호화 Key를 반환함.
+     *
+     * @param isNewCreateRsaKey : 새로운 암호화 Key를 만들지에 대한 여부
+     *  - true : 암호화키 새로 생성 후, 생성된 암호화키 반환 (단, session이 존재할 때만 생성)
+     *  - false : 새로 생성하지 않고 기존에 생성되어있는 암호화키 반환
+    public static KeyPair getRsaKeyInSession (boolean isNewCreateRsaKey) {
+        try {
+            ServletRequestAttributes servletRequestAttribute = (ServletRequestAttributes) RequestContextHolder.currentRequestAttributes();
+            HttpSession session = servletRequestAttribute.getRequest().getSession(false);
+
+            *//** session이 존재하지 않을 때 **//* if(session == null) {
+                return null;
+            }*//** session이 존재할 때 **//* else {
+                *//** 새로운 암호화키 생성 (O) **//* if (isNewCreateRsaKey == true) {
+                    //암호화키 생성 후, session에 담기
+                    session.setAttribute("rsaKey", genRsaKeyPair());
+                }*//** 새로운 암호화키 생성 (X) **//* else {
+                    //만약에 기존 암호화키가 없으면 새로 생성
+                    if (session.getAttribute("rsaKey") == null) {
+                        session.setAttribute("rsaKey", genRsaKeyPair());
+                    }
+                }
+                //session에 담겨있는 rsaKey return
+                return (KeyPair) session.getAttribute("rsaKey");
+            }
+        } catch(Exception e) {
+            System.out.println("AuthUtil getRsaKeyInSession Error : ");
+            e.printStackTrace();
+            return null;
+        }
+    }*/
+
+    /**
+     * @author 최정우
+     * @since 2021.11.12
+     *
+     * session에 RSA암호화 Key를 제거
+     */
+    public static void deleteRsaKeyInSession () {
+        try {
+            //현재 client의 HttpSession 조회
+            HttpSession session = CommonUtil.getHttpSession(false);
+
+            /** session에 RSA암호화 Key가 존재할 때 **/
+            if(session != null && session.getAttribute("rsaKey") != null) {
+                session.removeAttribute("rsaKey");
+            }
+        } catch(Exception e) {
+            System.out.println("AuthUtil deleteRsaKeyInSession Error : ");
+            e.printStackTrace();
+        }
+    }
+
+    /**
+     * @author 최정우
+     * @since 2021.11.08
+     *
+     * RSA 암호화 키쌍(공개키, 개인키) 생성 기능
+     */
+    public static KeyPair genRsaKeyPair() {
+        KeyPairGenerator gen = null;
+        try {
+            gen = KeyPairGenerator.getInstance("RSA");
+        } catch (NoSuchAlgorithmException e) {
+            e.printStackTrace();
+        }
+        gen.initialize(1024, new SecureRandom());
+        return gen.genKeyPair();
+    }
+
+    /**
+     * @author 최정우
+     * @since 2021.11.08
+     *
+     * RSA 공개키 -> String
+     */
+    public static String publicKeyToString (PublicKey publicKey) {
+        return new String(byteToHex(publicKey.getEncoded()));
+    }
+
+    /**
+     * @author 최정우
+     * @since 2021.11.08
+     *
+     * RSA 개인키 -> String
+     */
+    public static String privateKeyToString (PrivateKey privateKey) {
+        return new String(byteToHex(privateKey.getEncoded()));
+    }
+
+    /**
+     * @author 최정우
+     * @since 2021.11.08
+     *
+     * RSA String -> 공개키
+     */
+    public static PublicKey stringToPublicKey (String publicKeyStr) {
+        PublicKey publicKey = null;
+        try {
+            //문자열을 공개키로 표현하기 위한 스펙 객체
+            X509EncodedKeySpec ukeySpec = new X509EncodedKeySpec(hexToByte(publicKeyStr));
+            KeyFactory keyFactory = KeyFactory.getInstance("RSA");
+            publicKey = keyFactory.generatePublic(ukeySpec);
+        } catch (Exception e) {
+            e.printStackTrace();
+        }
+        return publicKey;
+    }
+
+    /**
+     * @author 최정우
+     * @since 2021.11.08
+     *
+     * RSA String -> 개인키
+     */
+    public static PrivateKey stringToPrivateKey(String privateKeyStr){
+        PrivateKey privateKey = null;
+        try{
+            //문자열을 개인키로 표현하기 위한 스펙 객체
+            PKCS8EncodedKeySpec rkeySpec = new PKCS8EncodedKeySpec(hexToByte(privateKeyStr));
+            KeyFactory rkeyFactory = KeyFactory.getInstance("RSA");
+            privateKey = rkeyFactory.generatePrivate(rkeySpec);
+        } catch (Exception e) {
+            e.printStackTrace();
+        }
+        return privateKey;
+    }
+
+    /**
+     * @author 최정우
+     * @since 2021.11.08
+     *
+     * 공개키 Key로 text를 RSA 암호화
+     */
+    public static String encodingByRsa (String text, PublicKey publicKey) throws Exception {
+        Cipher cipher = Cipher.getInstance("RSA");
+        cipher.init(Cipher.ENCRYPT_MODE, publicKey);
+
+        byte[] bytePlain = cipher.doFinal(text.getBytes());
+        return Base64.getEncoder().encodeToString(bytePlain);
+    }
+
+    /**
+     * @author 최정우
+     * @since 2021.11.08
+     *
+     * 개인키 Key로 text를 RSA 복호화
+     */
+    public static String decodingByRsa (String encodedText, PrivateKey privateKey) throws Exception {
+        Cipher cipher = Cipher.getInstance("RSA");
+        byte[] byteEncrypted = Base64.getDecoder().decode(encodedText.getBytes());
+        cipher.init(Cipher.DECRYPT_MODE, privateKey);
+        byte[] bytePlain = cipher.doFinal(byteEncrypted);
+        return new String(bytePlain, "utf-8");
+    }
+
+
+    /**
+     * @author 최정우
+     * @since 2021.10.31
+     *
+     * SHA-256 암호화 기능
+     */
+    public static String encodingBySha256 (String text) throws NoSuchAlgorithmException {
+        MessageDigest md = MessageDigest.getInstance("SHA-256");
+        md.update(text.getBytes());
+        return byteToHex(md.digest());
+    }
+
+
+    /**
+     * @author 최정우
+     * @since 2021.10.31
+     *
+     * 바이너리 -> 16진수 변경
+     */
+    public static String byteToHex(byte[] data) {
+        StringBuilder sb = new StringBuilder();
+        for(byte b : data) {
+            sb.append(Integer.toString((b & 0xff) + 0x100, 16).substring(1));
+        }
+        return sb.toString();
+    }
+
+    /**
+     * @author 최정우
+     * @since 2021.10.31
+     *
+     * 16진수 -> 바이너리 변경
+     */
+    public static byte[] hexToByte(String hex) {
+        byte[] ba = new byte[hex.length() / 2];
+        for (int i = 0; i < ba.length; i++) {
+            ba[i] = (byte) Integer.parseInt(hex.substring(2 * i, 2 * i + 2), 16);
+        }
+        return ba;
+    }
+}
 
src/back-end/main/java/common/util/EmailUtil.java (added)
+++ src/back-end/main/java/common/util/EmailUtil.java
@@ -0,0 +1,46 @@
+package common.util;
+
+import javax.mail.*;
+import javax.mail.internet.InternetAddress;
+import javax.mail.internet.MimeMessage;
+import java.util.Properties;
+
+public class EmailUtil {
+
+    public static void naverMailSend(String receiver, String title, String content) {
+        String host = "smtp.naver.com"; // 네이버일 경우 네이버 계정, gmail경우 gmail 계정
+        String user = "[email protected]"; // 패스워드
+        String password = "elwlfjf!2tktn";
+
+        // SMTP 서버 정보를 설정한다.
+        Properties props = new Properties();
+        props.put("mail.smtp.host", host);
+        props.put("mail.smtp.port", 587);
+        props.put("mail.smtp.auth", "true");
+
+        Session session = Session.getDefaultInstance(props, new javax.mail.Authenticator() {
+            protected PasswordAuthentication getPasswordAuthentication() {
+                return new PasswordAuthentication(user, password);
+            }
+        });
+
+        try {
+            MimeMessage message = new MimeMessage(session);
+            message.setFrom(new InternetAddress(user));
+            message.addRecipient(Message.RecipientType.TO, new InternetAddress(receiver));
+
+            // 메일 제목
+            message.setSubject(title);
+
+            // 메일 내용
+            message.setContent(content, "text/html; charset=UTF-8");
+
+            // send the message
+            Transport.send(message);
+            System.out.println("Success Message Send");
+        } catch (MessagingException e) {
+            e.printStackTrace();
+        }
+    }
+
+}
 
src/back-end/main/java/common/util/ExcelReadUtil.java (added)
+++ src/back-end/main/java/common/util/ExcelReadUtil.java
@@ -0,0 +1,191 @@
+package common.util;
+
+import common.vo.CommonFile;
+import org.apache.poi.ss.usermodel.*;
+
+import java.io.File;
+import java.math.BigDecimal;
+import java.text.SimpleDateFormat;
+import java.util.*;
+
+public class ExcelReadUtil {
+    /**
+     * @author 김재영
+     * @since 2021.11.15
+     *
+     * 일반 엑셀 Read xls, xlsx
+     * 엑셀파일 읽기 poi라이브러리 사용
+     */
+    public static Map<String, Object> excelFileRead(CommonFile commonFile) throws Exception {
+        Map<String, Object> dataBySheet = new LinkedHashMap<String, Object>();
+        String fileFullPath= commonFile.getFileFullPath();
+        String sheetTitle= "sheet0";
+        File excelFile = new File(fileFullPath);
+        Workbook wb = WorkbookFactory.create(excelFile);
+
+
+
+        for (int sheetIdx = 0; sheetIdx < wb.getNumberOfSheets(); sheetIdx++) {
+            //한개의 시트에 대한 행,열 데이터 List
+            Map<String, Object> sheetData = new LinkedHashMap<String, Object>();
+            //rowData 담는 리스트
+            List<LinkedHashMap<String, Object>> rowData = new ArrayList<LinkedHashMap<String, Object>>();
+            List<List<String>> columnData = new ArrayList<List<String>>();
+            //시트 객체
+            Sheet sheet = wb.getSheetAt(sheetIdx);
+
+            //데이터가 들어있는 시트의 첫 번째 행 index
+            int firstRowNum = sheet.getFirstRowNum();
+            //데이터가 들어있는 시트의 최종 행 index
+            int lastRowNum = sheet.getLastRowNum();
+
+            //데이터가 들어있는 시트의 첫 번째 행의 마지막 열 index
+            //int firstCellNum = sheet.getRow(firstRowNum).getFirstCellNum();
+            //int lastCellNum = sheet.getRow(firstRowNum).getLastCellNum();
+
+            //Row for문
+            for(int rowIndex = firstRowNum+1; rowIndex <= lastRowNum; rowIndex++) {
+                //Row 객체
+                Row row = sheet.getRow(rowIndex);
+                if(row == null) continue;
+
+                //해당 index 행의 마지막 열 index
+                int lastCellNum = row.getLastCellNum();
+
+                //행에 열데이터가 1개라도 존재하는지 체크
+                boolean isRowDataExist = false;
+
+                //한개의 행에 대한 열 데이터
+                LinkedHashMap<String, Object> cells = new LinkedHashMap<String, Object>();
+                //Row의 Cell 데이터 담기
+                for(int cellIndex = 0; cellIndex < lastCellNum; cellIndex++) {
+                    Cell cell = row.getCell(cellIndex);
+                    try {
+                        String value = getCellValue(cell, wb);
+                        if (StringUtil.isEmpty(value) == true) {
+                            cells.put("cell"+cellIndex, null);
+                        } else {
+                            cells.put("cell"+cellIndex, value);
+                            isRowDataExist = true;
+                        }
+                    } catch (Exception e) {
+                        cells.put("cell"+cellIndex, null);
+                        e.printStackTrace();
+                    }
+                }
+
+                //행에 열데이터가 1개라도 존재하면 -> row데이터 추가
+                if (isRowDataExist == true) {
+                    //row데이터 추가
+                    rowData.add(cells);
+                }
+
+                //raw데이터에 대한 명칭 입력
+                //dataTable.setTitle(dataTitle);
+            }//Row for문 끝
+            sheetData.put("rowData",rowData);
+            //시트가 2개 이상일 때, 데이터 명 == 시트명
+            if (wb.getNumberOfSheets() > 1) {
+                sheetTitle = "sheet"+sheetIdx;
+            }
+
+            //row데이터가 없을 때, 메세지 처리
+//            if (dataTable.getRowData().size() == 0) {
+//                dataTable.getCheckMessage().setIsSuccess(false);
+//                dataTable.getCheckMessage().setMessage("데이터가 없습니다");
+//            } else {
+//                dataTable.getCheckMessage().setIsSuccess(true);
+//                dataTable.getCheckMessage().setMessage("엑셀(.xls) 파일 읽기 완료");
+//            }
+
+            //Key(시트명) : Value(시트의 행,열 데이터)
+            dataBySheet.put(sheetTitle, sheetData);
+        }
+        //스트림 닫기
+        if (wb != null) {
+            wb.close();
+        }
+
+        return dataBySheet;
+    }
+
+    /**
+     * @author 김재영
+     * @since 2021.11.15
+     *
+     * 일반 엑셀 Read 관련
+     * Excel cell value 데이터 타입 파악 후, 원본형태의 문자열로 반환
+     */
+    public static String getCellValue(Cell cell, Workbook wb) throws Exception {
+        if(cell != null) {
+            switch (cell.getCellType()) {
+                case FORMULA:
+                    FormulaEvaluator evaluator = wb.getCreationHelper().createFormulaEvaluator();
+                    if (evaluator.evaluateFormulaCell(cell) == CellType.NUMERIC) {
+                        if (DateUtil.isCellDateFormatted(cell)) {
+                            return "";
+                        } else {
+                            Double dou = new Double(cell.getNumericCellValue());
+                            if ((double) dou.longValue() == dou.doubleValue()) {
+                                return Long.toString(dou.longValue());
+                            } else {
+                                return StringUtil.toString(dou);
+                            }
+                        }
+                    } else if (evaluator.evaluateFormulaCell(cell) == CellType.STRING) {
+                        return cell.getStringCellValue();
+                    } else if (evaluator.evaluateFormulaCell(cell) == CellType.BOOLEAN) {
+                        return StringUtil.toString(new Boolean(cell.getBooleanCellValue()));
+                    } else {
+                        return cell.getCellFormula();
+                    }
+                case NUMERIC:
+                    BigDecimal big = new BigDecimal(cell.getNumericCellValue());
+                    BigDecimal fp = big.subtract(new BigDecimal(big.longValue()));
+                    if(DateUtil.isCellDateFormatted(cell)) {
+                        Date date = cell.getDateCellValue();
+                        return new SimpleDateFormat("yyyy-MM-dd").format(date);
+                    } else if(checkDateFormat(cell)) {
+                        Date date = cell.getDateCellValue();
+                        return new SimpleDateFormat("yyyy-MM-dd").format(date);
+                    } else if(fp.doubleValue()==0.0d) {
+                        return Long.toString(big.longValue());
+                    } else {
+                        return StringUtil.toString(new Double(cell.getNumericCellValue()));
+                    }
+                case STRING:
+                    return cell.getStringCellValue();
+                case BOOLEAN:
+                    return StringUtil.toString(new Boolean(cell.getBooleanCellValue()));
+                case ERROR:
+                    return StringUtil.toString(new Byte(cell.getErrorCellValue()));
+                case BLANK:
+                    return "";
+                default:
+                    return "";
+            }
+        } else {
+            return "";
+        }
+    }
+
+    /**
+     * @author 김재영
+     * @since 2021.11.15
+     *
+     * 일반 엑셀 Read 관련
+     * Excel cell의 포맷 형태가 데이트관련 포맷인지 체크
+     */
+    public static boolean checkDateFormat(Cell cell) throws Exception{
+        try {
+            int formatIndex = cell.getCellStyle().getDataFormat();
+            switch(formatIndex) {
+                case 31: //excel: yyyy년 MM월 dd일
+                    return true;
+            }
+        } catch (Exception e) {
+            return false;
+        }
+        return false;
+    }
+}
 
src/back-end/main/java/common/util/FileUtil.java (added)
+++ src/back-end/main/java/common/util/FileUtil.java
@@ -0,0 +1,334 @@
+package common.util;
+
+import common.vo.CheckMessage;
+import common.vo.CommonFile;
+import common.vo.CommonFile.FileStatus;
+import common.vo.SystemCode.FileUploadPath;
+import org.springframework.web.multipart.MultipartFile;
+import org.springframework.web.multipart.MultipartHttpServletRequest;
+
+import javax.servlet.http.HttpServletRequest;
+import java.io.File;
+import java.text.DecimalFormat;
+import java.time.LocalDate;
+import java.util.*;
+
+
+/**
+ * @author 최정우
+ * @since 2019.11.13
+ *
+ * File과 관련된 기능을 정의 해놓은 Util입니다.
+ * 업로드, 다운로드, 파일읽기, 파일쓰기
+ *
+ * 파일 정보만 가지고오기 -> multipartFileToCommonFile (multipartFileCheck기능 포함)
+ * 파일 확장자 체크 -> multipartFileCheck
+ * 특정 디렉토리에 파일 생성 -> fileCreate
+ *
+ * ※주요 활용 메소드 : fileUpload -> 파일 업로드 및 업로드 정보 반환  (fileCreate기능 및 multipartFileCheck 까지 포함되어 있음)
+ */
+public class FileUtil {
+
+	/**
+	 * @author 최정우
+	 * @since 2019.11.13
+	 *
+     * 파일 기본 정보 (여러개 파일)
+     */
+    public static List<CommonFile> multipartFileToCommonFile (HttpServletRequest request) throws Exception {
+    	return multipartFileToCommonFile(request, null);
+    }
+    public static List<CommonFile> multipartFileToCommonFile (HttpServletRequest request, List<String> extensions) throws Exception {
+    	List<CommonFile> fileuploads = new ArrayList<CommonFile>();
+
+    	MultipartHttpServletRequest multipart = (MultipartHttpServletRequest) request;
+    	Iterator<String> itr = multipart.getFileNames();
+
+		while (itr.hasNext()) {
+			fileuploads.add(multipartFileToCommonFile(multipart.getFile(itr.next()), extensions));
+		}
+
+		return fileuploads;
+    }
+
+    /**
+	 * @author 최정우
+	 * @since 2019.11.13
+	 *
+	 * 파일 기본 정보 (한개 파일)
+	 */
+	public static CommonFile multipartFileToCommonFile (MultipartFile multipartFile) throws Exception {
+		return multipartFileToCommonFile(multipartFile, null);
+	}
+    public static CommonFile multipartFileToCommonFile (MultipartFile multipartFile, List<String> extensions) throws Exception {
+    	CommonFile commonFile = new CommonFile();
+
+    	commonFile.setFileOriginName(getFileNameExceptExtension(multipartFile.getOriginalFilename()));
+    	commonFile.setFileExtension(getFileExtension(multipartFile.getOriginalFilename()));
+    	commonFile.setFileSize(multipartFile.getSize());
+    	commonFile.setCheckMessage(multipartFileCheck(multipartFile, extensions));
+
+    	return commonFile;
+    }
+
+
+	/**
+	 * @author 최정우
+	 * @since 2019.11.13
+	 *
+     * 업로드 파일 체크 (여러개 파일 - extensions)
+     */
+    public static Map<String, CheckMessage> multipartFileCheck (HttpServletRequest request, List<String> extensions) throws Exception {
+    	Map<String, CheckMessage> info = new HashMap<String, CheckMessage>();
+
+    	MultipartHttpServletRequest multipart = (MultipartHttpServletRequest) request;
+    	Iterator<String> itr = multipart.getFileNames();
+
+		while (itr.hasNext()) {
+			MultipartFile multipartFile = multipart.getFile(itr.next());
+			info.put(multipartFile.getName(), multipartFileCheck (multipartFile, extensions));
+		}
+
+		return info;
+    }
+
+    /**
+     * @author 최정우
+	 * @since 2019.11.13
+	 *
+     * 업로드 파일 체크  (한개 파일 - extensions)
+     */
+    public static CheckMessage multipartFileCheck (MultipartFile multipartFile, List<String> extensions) throws Exception {
+
+    	String orginFileName = multipartFile.getOriginalFilename();
+//	    System.out.println("multipartFile name : " + multipartFile.getName());
+	    //원 파일명이 없는 경우 처리(첨부가 되지 않은 input file type)
+	    if (orginFileName.equals("")) {
+	    	return new CheckMessage(false, "파일명이 존재하지 않습니다");
+	    }
+
+	    //파일 확장자 존재 유무
+	    int index = orginFileName.lastIndexOf(".");
+	    if (index == -1) {
+	    	return new CheckMessage(false, "파일에 확장자가 존재하지 않습니다");
+	    }
+
+	    //파일 확장자 체크
+	    String fileExt = orginFileName.substring(index + 1);
+	    //파일 확장자 체크 후, 컴펌 유무
+	    boolean isConfirm = false;
+	    if (extensions != null && extensions.size() > 0) {//체크할 확장자가 있으면 -> 체킹
+	    	for (int i = 0; i < extensions.size(); i++) {
+		    	if (extensions.get(i).toUpperCase().equals(fileExt.toUpperCase())) {
+		    		isConfirm = true;
+		    		break;
+		    	}
+		    }
+	    } else {//체크할 확장자가 없으면 -> 컴펌
+	    	isConfirm = true;
+	    }
+
+	    if (isConfirm == false) {
+	    	return new CheckMessage(false, "." + fileExt + " 파일은(는) 업로드가 불가능한 확장자입니다");
+	    }
+
+	    return new CheckMessage(true, "업로드 가능한 파일 입니다");
+    }
+
+    /**
+     * @author 최정우
+	 * @since 2019.11.17
+	 *
+     * 업로드 파일 정보 조회 (여러개 파일)
+     */
+    public static List<CommonFile> fileUpload (HttpServletRequest request) throws Exception {
+    	return fileUpload(request, null);
+	}
+	public static List<CommonFile> fileUpload (HttpServletRequest request, List<String> extensions) throws Exception {
+		List<CommonFile> fileUploads = new ArrayList<CommonFile>();
+
+		MultipartHttpServletRequest multipart = (MultipartHttpServletRequest) request;
+		Iterator<String> multiFiles = multipart.getFileNames();
+
+		while (multiFiles.hasNext()) {
+			MultipartFile multipartFile = multipart.getFile(multiFiles.next());
+			fileUploads.add(fileUpload(multipartFile, request, extensions));
+		}
+
+		return fileUploads;
+	}
+
+	/**
+	 * @author 최정우
+	 * @since 2019.11.17
+	 *
+     * 업로드 파일 정보 조회 (한개 파일)
+     */
+	public static CommonFile fileUpload (MultipartFile multipartFile, HttpServletRequest request) throws Exception {
+		return fileUpload(multipartFile, request, null);
+	}
+	public static CommonFile fileUpload (MultipartFile multipartFile, HttpServletRequest request, List<String> extensions) throws Exception {
+		long startTime = System.currentTimeMillis();/*삭제 요망*/
+		//파일 정보 객체
+		CommonFile fileUpload = new CommonFile();
+		try {
+			//프로젝트 내부 경로
+			String relativePath = FileUploadPath.MAIN_RELATIVE_PATH.getOSFileUploadPath();
+			//프로젝트 내부 경로 = 프로젝트 내부 경로 + /년도
+			relativePath += File.separator + LocalDate.now().getYear();
+			//프로젝트 내부 경로 = 프로젝트 내부 경로 + /년도 + /월
+			relativePath += File.separator + LocalDate.now().getMonthValue();
+			//절대 경로(프로젝트 내부 경로의 절대경로)
+			String absolutePath = request.getSession().getServletContext().getRealPath(relativePath);
+			//확장자를 제거한 원본 파일명
+			String originName = getFileNameExceptExtension(multipartFile.getOriginalFilename());
+			//새로 생성될 파일명
+			String maskName = StringUtil.getCreateKey("bigdata");
+			//원본 파일의 확장자
+			String extension = getFileExtension(multipartFile.getOriginalFilename());
+			//원본 파일의 파일크기(byte단위)
+			long size = multipartFile.getSize();
+
+			//파일 정보 셋팅 (시작)
+			fileUpload.setFileRelativePath(relativePath);
+			fileUpload.setFileAbsolutePath(absolutePath);
+			fileUpload.setFileOriginName(originName);
+			fileUpload.setFileMaskName(maskName);
+			fileUpload.setFileExtension(extension);
+			fileUpload.setFileSize(size);
+			fileUpload.setFileStatus(FileStatus.BEFORE_INSERT);
+			fileUpload.setCheckMessage(new CheckMessage(true, "파일 정보 조회 성공"));
+			//파일 정보 셋팅 (끝)
+		} catch (Exception e) {
+			fileUpload.setCheckMessage(new CheckMessage(false, "파일 정보 조회 에러", e.getMessage()));
+		}
+
+		//실제 디렉토리에 업로드 파일 생성
+		if (extensions != null && extensions.size() > 0) {//extensions가 존재하면 -> 파일 검사 -> 통과 시, 파일 생성
+			//파일 확장자 검사
+			fileUpload.setCheckMessage(multipartFileCheck(multipartFile, extensions));
+
+			if (fileUpload.getCheckMessage().getIsSuccess() == true) {//확장자 검사 통과 -> 성공 -> 파일 생성
+				fileCreate(fileUpload, multipartFile);
+				long endTime = System.currentTimeMillis();/*삭제 요망*/
+				long totalTime = endTime - startTime;/*삭제 요망*/
+				System.out.println("업로드 경로 : " + fileUpload.getFileAbsolutePath() + ", 파일명 : " + multipartFile.getOriginalFilename() + "(" + fileUpload.getFileMaskName() + ") 파일 업로드 소요시간 : " + totalTime / 1000.0 + "초");/*삭제 요망*/
+			} else {//확장자 검사 통과 -> 실패
+				System.out.println(multipartFile.getOriginalFilename() + " 파일 확장자 검사 통과 실패");/*삭제 요망*/
+			}
+		} else {//extensions가 존재하지 않으면 -> 파일 생성
+			fileCreate(fileUpload, multipartFile);
+			long endTime = System.currentTimeMillis();/*삭제 요망*/
+			long totalTime = endTime - startTime;/*삭제 요망*/
+			System.out.println("업로드 경로 : " + fileUpload.getFileAbsolutePath() + ", 파일명 : " + multipartFile.getOriginalFilename() + "(" + fileUpload.getFileMaskName() + ") 파일 업로드 소요시간 : " + totalTime / 1000.0 + "초");/*삭제 요망*/
+		}
+
+		return fileUpload;
+	}
+
+	/**
+	 * @author 최정우
+	 * @since 2019.11.17
+	 *
+     * 실제 디렉토리에 업로드 파일 생성
+     */
+	public static void fileCreate (CommonFile fileupload, MultipartFile multipartFile) throws Exception  {
+		try {
+			//디렉토리 만들기.
+			File dir = new File(fileupload.getFileAbsolutePath());
+			boolean isExistDir = true;
+			if (dir.exists() == false) {
+				isExistDir = dir.mkdirs();
+			}
+			//디렉토리가 존재할 때
+			if (isExistDir == true) {
+				//디렉토리에 쓰기 권한이 있을 때
+				if (dir.canWrite() == true) {
+					//디렉토리 경로에 파일 생성
+				    multipartFile.transferTo(new File(fileupload.getFileAbsolutePath(), fileupload.getFileMaskName() + "." + fileupload.getFileExtension()));
+				    fileupload.setCheckMessage(new CheckMessage(true, "파일 활용 가능"));
+				} else {
+					fileupload.setCheckMessage(new CheckMessage(false, "쓰기 권한이 없습니다"));
+				}
+			} else {
+				fileupload.setCheckMessage(new CheckMessage(false, "디렉토리 생성 불가"));
+			}
+		} catch (Exception e) {
+			fileupload.setCheckMessage(new CheckMessage(false, "파일 업르드 에러", e.getMessage()));
+		}
+	}
+
+	/**
+	 * @author 최정우
+	 * @since 2019.11.17
+	 *
+     * 실제 디렉토리에 업로드 파일 생성
+     */
+	public static void fileRemove (String fileFullPath) throws Exception {
+		//commonFile.getFileAbsolutePath() + File.separator + commonFile.getFileMaskName() + "." + commonFile.getFileExtension()
+		File file = new File(fileFullPath);
+		if (file.exists()) {
+			file.delete();
+		}
+	}
+
+	/**
+	 * @author 최정우
+	 * @since 2019.11.17
+	 *
+     * 파일 확장자 얻기
+     */
+	public static String getFileExtension (String fileName) {
+		if (StringUtil.isEmpty(fileName) == true) {
+			return null;
+		} else {
+			int index = StringUtil.lastIndexOf(fileName, ".");
+			if (index > -1) {
+				return StringUtil.lowerCase(fileName.substring(index + 1));
+			} else {
+				return null;
+			}
+		}
+	}
+
+	/**
+	 * @author 최정우
+	 * @since 2019.11.17
+	 *
+     * 확장자를 제거한 원본 파일명 얻기
+     */
+	public static String getFileNameExceptExtension (String fileName) {
+		if (StringUtil.isEmpty(fileName) == true) {
+			return fileName;
+		} else {
+			int index = StringUtil.lastIndexOf(fileName, ".");
+			if (index > -1) {
+				return fileName.substring(0, index);
+			} else {
+				return fileName;
+			}
+		}
+	}
+
+	/**
+	 * @author 최정우
+	 * @since 2019.11.17
+	 *
+     * File의 용량(byte)을 각 단위에 맞게 변형
+     */
+    public static String convertFileSize (String bytes) {
+        String retFormat = "0";
+        Double size = Double.parseDouble(bytes);
+        String[] s = { "bytes", "KB", "MB", "GB", "TB", "PB" };
+        if (bytes != null && bytes.length() > 0 && !bytes.equals("0") ) {
+              int idx = (int) Math.floor(Math.log(size) / Math.log(1024));
+              DecimalFormat df = new DecimalFormat("#,###.##");
+              double ret = ((size / Math.pow(1024, Math.floor(idx))));
+              retFormat = df.format(ret) + " " + s[idx];
+         } else {
+              retFormat += " " + s[0];
+         }
+
+         return retFormat;
+    }
+}
 
src/back-end/main/java/common/util/HTTPUtil.java (added)
+++ src/back-end/main/java/common/util/HTTPUtil.java
@@ -0,0 +1,227 @@
+package common.util;
+
+import java.io.*;
+import java.net.HttpURLConnection;
+import java.net.MalformedURLException;
+import java.net.URL;
+import java.net.URLEncoder;
+import java.util.Map;
+
+public class HTTPUtil {
+
+	/**
+	 * @author 최정우
+	 * @throws Exception 
+	 * @since 2020.07.21
+	 * 
+	 * [GET] HTTP 통신
+	 */
+	public synchronized String httpGetConnection (String urlText) {
+		return httpGetConnection(urlText, null, null);
+	}
+	public synchronized String httpGetConnection (String urlText, Map<String, Object> parameter) {
+		return httpGetConnection(urlText, parameter, null);
+	}
+	public synchronized String httpGetConnection (String urlText, Map<String, Object> parameter, Map<String, String> headers) {
+		StringBuffer response = new StringBuffer();
+		
+		URL url = null;
+		try {
+			if (parameter != null && parameter.isEmpty() == false) {
+				urlText += "?" + createUrlQuery(parameter, "UTF-8"); 
+				System.out.println("url@ : " + urlText);
+			}
+			//System.out.println("=====url : "+urlText);
+			url = new URL(urlText);
+		} catch (MalformedURLException e) {
+			// TODO Auto-generated catch block
+			e.printStackTrace();
+		}
+
+		HttpURLConnection httpCon = null;
+		try {
+
+			/* Connection */
+			httpCon = (HttpURLConnection) url.openConnection();
+			httpCon.setRequestMethod("GET");
+			httpCon.setRequestProperty("User-Agent", "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/41.0.2272.101 Safari/537.36");
+			if (headers != null && headers.isEmpty() == false) {
+				for (String key : headers.keySet()) {
+					httpCon.setRequestProperty(key, headers.get(key));
+				}
+			}
+			httpCon.setConnectTimeout(1000 * 60);//http통신 최대 커넥션 시간(1분)
+			httpCon.setReadTimeout(1000 * 60);//http통신 커넥션 이후, 데이터를 받아오는데 걸리는 최대 시간(1분)
+			httpCon.setDoInput(true);//받아올 데이터가 있을 때, 사용
+			
+			//HTTP Request 결과 코드
+			int responseCode = httpCon.getResponseCode();
+
+			//Response 결과 데이터 받기
+			BufferedReader input = new BufferedReader(new InputStreamReader(httpCon.getInputStream(), "UTF-8"));//"UTF-8"
+
+			//Response 결과 데이터를 문자열로 만들기
+			String result = "";
+			while ((result = input.readLine()) != null) {
+				System.out.println("result : " + result);
+				response.append(result);
+			}
+
+			//InputStream, BufferedReader 종료
+			input.close();
+
+			//HTTP Connection 종료
+			httpCon.disconnect();
+
+			if (responseCode != 200) {
+				System.out.println("[HTTP " + responseCode + " 에러]" + url);
+			}
+			
+		} catch (Exception e) {
+			e.printStackTrace();
+		}
+		//문자열로된 Response 결과 return
+		return response.toString();
+	}
+	
+	/**
+	 * @author 최정우
+	 * @throws Exception 
+	 * @since 2020.07.21
+	 * 
+	 * [POST] HTTP 통신
+	 */
+	public synchronized String httpPostConnection (String urlText) {
+		return httpGetConnection(urlText, null, null);
+	}
+	public synchronized String httpPostConnection (String urlText, Map<String, Object> parameter) {
+		return httpGetConnection(urlText, parameter, null);
+	}
+	public synchronized String httpPostConnection (String urlText, Map<String, Object> parameter, Map<String, String> headers) {
+		StringBuffer response = new StringBuffer();
+		
+		URL url = null;
+		try {
+			url = new URL(urlText);
+		} catch (MalformedURLException e) {
+			// TODO Auto-generated catch block
+			e.printStackTrace();
+		}
+
+		HttpURLConnection httpCon = null;
+		try {
+			/* Connection */
+			httpCon = (HttpURLConnection) url.openConnection();
+			httpCon.setRequestMethod("POST");
+			httpCon.setRequestProperty("User-Agent", "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/41.0.2272.101 Safari/537.36");
+			httpCon.setConnectTimeout(1000 * 60);//http통신 최대 커넥션 시간(1분)
+			httpCon.setReadTimeout(1000 * 60);//http통신 커넥션 이후, 데이터를 받아오는데 걸리는 최대 시간(1분)
+			httpCon.setDoInput(true);//받아올 데이터가 있을 때, 사용
+
+			
+			//보낼 파라메터 데이터가 있을 때
+			if (parameter != null && parameter.isEmpty() == false) {
+				String dataQuery = createUrlQuery(parameter, null);
+				
+				httpCon.setRequestProperty("Content-Type", "application/x-www-form-urlencoded");//보낼 데이터의 형태
+				httpCon.setRequestProperty("Content-Length", String.valueOf(dataQuery.length()));
+				if (headers != null && headers.isEmpty() == false) {
+					for (String key : headers.keySet()) {
+						httpCon.setRequestProperty(key, headers.get(key));
+					}
+				}
+				httpCon.setDoOutput(true);
+				
+				DataOutputStream wr = new DataOutputStream(httpCon.getOutputStream());
+				wr.writeBytes(dataQuery);
+				wr.flush();
+				wr.close();
+			}
+			
+			//HTTP Request 결과 코드
+			int responseCode = httpCon.getResponseCode();
+			/*if (responseCode == 200) {
+				//Response 결과 데이터 받기
+				BufferedReader input = new BufferedReader(new InputStreamReader(httpCon.getInputStream()));
+				
+				//Response 결과 데이터를 문자열로 만들기
+				String result = null;
+				while ((result = input.readLine()) != null) {
+					response.append(result);
+				}
+				
+				//InputStream, BufferedReader 종료
+				input.close();
+				
+				//HTTP Connection 종료
+				httpCon.disconnect();
+			} else {
+				System.out.println("[HTTP " + responseCode + " 에러]" + url);
+			}*/
+
+			//Response 결과 데이터 받기
+			BufferedReader input = new BufferedReader(new InputStreamReader(httpCon.getInputStream()));
+
+			//Response 결과 데이터를 문자열로 만들기
+			String result = "";
+			while ((result = input.readLine()) != null) {
+				response.append(result);
+			}
+
+			//InputStream, BufferedReader 종료
+			input.close();
+
+			//HTTP Connection 종료
+			httpCon.disconnect();
+
+			if (responseCode != 200) {
+				System.out.println("[HTTP " + responseCode + " 에러]" + url);
+			}
+			
+		} catch (IOException e) {
+			// TODO Auto-generated catch block
+			e.printStackTrace();
+		}
+		
+		//문자열로된 Response 결과 return
+		return response.toString();
+	}
+	
+	/**
+	 * @author 최정우
+	 * @throws Exception 
+	 * @since 2020.07.21
+	 * 
+	 * 파라메터 데이터를 HTTP통신을 위한 문자열로 변환시켜주는 메서드
+	 * Map -> String
+	 */
+	public String createUrlQuery (Map<String, Object> parameter, String encoding) {
+		if (parameter.isEmpty() == true) {
+			return "";
+		} else {
+			StringBuilder query = new StringBuilder();
+		    for(Map.Entry<String,Object> param : parameter.entrySet()) {
+		        try {
+		        	if(query.length() > 0) {
+		        		query.append('&');
+		        	}
+		        	
+		        	if (StringUtil.isEmpty(encoding) == true) {
+		        		query.append(param.getKey());
+			        	query.append('=');
+			        	query.append(param.getValue());
+		        	} else {
+		        		query.append(URLEncoder.encode(param.getKey(), encoding));
+			        	query.append('=');
+			        	query.append(URLEncoder.encode(String.valueOf(param.getValue()), encoding));
+		        	}
+		        	
+				} catch (UnsupportedEncodingException e) {
+					e.printStackTrace();
+				}
+		    }
+		    
+		    return query.toString();
+		}
+	}
+}
 
src/back-end/main/java/common/util/JsonUtil.java (added)
+++ src/back-end/main/java/common/util/JsonUtil.java
@@ -0,0 +1,6 @@
+package common.util;
+
+public class JsonUtil {
+
+
+}
 
src/back-end/main/java/common/util/StringUtil.java (added)
+++ src/back-end/main/java/common/util/StringUtil.java
@@ -0,0 +1,1001 @@
+package common.util;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.io.UnsupportedEncodingException;
+import java.sql.Timestamp;
+import java.text.SimpleDateFormat;
+import java.util.*;
+
+/**
+ * @author 최정우
+ * @since 2019.11.13
+ * 
+ * 문자열과 관련된 기능을 정의 해놓은 Util입니다.
+ */
+public class StringUtil {
+
+	private static final Logger LOGGER = LoggerFactory.getLogger(StringUtil.class);
+	
+	public static final String NULL_TEXT = "NULL";
+	
+	public static String toString(Object obj) {
+		if (obj == null) {
+			return null;
+		} else {
+			try {
+				return obj.toString();
+			} catch (Exception e) {
+				e.printStackTrace();
+				return null;
+			}
+		}
+	}
+	
+	public static String toStringNotNull(Object obj) {
+		if (obj == null) {
+			return "";
+		} else {
+			try {
+				return obj.toString();
+			} catch (Exception e) {
+				return "";
+			}
+		}
+	}
+	
+	/**
+     * @author 최정우
+     * @since 2020.11.26
+     * 
+     * 객체를 문자열로 바꾼 후, 문자열 길이 반환
+     */
+	public static int stringLength(Object obj) {
+		if (obj == null) {
+			return 0;
+		} else {
+			try {
+				return obj.toString().length();
+			} catch (Exception e) {
+				return 0;
+			}
+		}
+	}
+	
+	/**
+     * @author 최정우
+     * @since 2020.11.26
+     * 
+     * 문자열이 Null or null or NULL인 경우 실제 null값 세팅 
+     */
+	public static boolean isNullText(String text) {
+		if (isEmpty(text) == false && text.toUpperCase().equals(NULL_TEXT)) {
+			return true;
+		} else {
+			return false;
+		}
+	}
+	
+    /**
+     * @author 최정우
+     * @since 2019.11.13
+     * 
+     * 빈 문자열 검사
+     */
+    public static boolean isEmpty(String text) {
+        return text == null || text.trim().length() == 0;
+    }
+    
+    /**
+     * @author 최정우
+     * @since 2019.11.13
+     * 
+     * indexOf - 문자 검색 후, 해당 문자의 위치(index)반환
+     */
+    public static int indexOf(String text, String searchText) {
+        if (text == null || searchText == null) {
+            return -1;
+        }
+        return text.indexOf(searchText);
+    }
+    
+    /**
+     * @author 최정우
+     * @since 2019.11.13
+     * 
+     * lastIndexOf - 문자 검색 후, 해당 문자의 위치(index)반환
+     */
+    public static int lastIndexOf(String text, String searchText) {
+    	if (text == null || searchText == null) {
+            return -1;
+        }
+        return text.lastIndexOf(searchText);
+    }
+    
+    /**
+     * @author 최정우
+     * @since 2019.11.13
+     * 
+     * substringBetween - 특정 문자열 사이에 값을 뽑아내는 메서드
+     */
+    public static String substringBetween(String text, String startText, String endText) {
+		if (isEmpty(text) == true || isEmpty(startText) == true || isEmpty(endText) == true) {
+			return null;
+		}
+		text = text.toLowerCase();
+		startText = startText.toLowerCase();
+		endText = endText.toLowerCase();
+		
+		int start = text.indexOf(startText);
+		if (start != -1) {
+			int end = text.indexOf(endText, start + startText.length());
+			if (end != -1) {
+				return text.substring(start + startText.length(), end);
+			}
+		}
+		return null;
+	}
+
+    /**
+     * @author 최정우
+     * @since 2019.11.13
+     * 
+     * 모든 공백 제거
+     */
+    public static String removeSpace(String text) {
+        if (isEmpty(text)) {
+            return text;
+        }
+        int length = text.length();
+        char[] newCharList = new char[length];
+        int count = 0;
+        for (int i = 0; i < length; i++) {
+            if (Character.isWhitespace(text.charAt(i)) == false) {
+            	newCharList[count++] = text.charAt(i);
+            }
+        }
+        if (count == length) {
+            return text;
+        }
+
+        return new String(newCharList, 0, count);
+    }
+    
+    /**
+     * @author 최정우
+     * @since 2019.11.13
+     * 
+     * html의 특수문자를 표현하기 위해
+     */
+    public static String textToHtml(String text) {
+    	text = text.replaceAll("&lt;", "<");
+    	text = text.replaceAll("&gt;", ">");
+    	text = text.replaceAll("&amp;", "&");
+    	text = text.replaceAll("&nbsp;", " ");
+    	text = text.replaceAll("&apos;", "\'");
+    	text = text.replaceAll("&quot;", "\"");
+		return  text;
+	}
+
+    /**
+     * @author 최정우
+     * @since 2019.11.13
+     * 
+     * Html 코드가 들어간 문서를 표시할때 태그에 손상없이 보이기 위한 메서드
+     */
+	public static String htmlToText(String text) {
+		StringBuffer textBuffer = new StringBuffer("");
+
+		char character;
+		int length = text.length();
+
+		for (int i = 0; i < length; i++) {
+			character = (char) text.charAt(i);
+
+			switch (character) {
+				case '<':
+					textBuffer.append("&lt;");
+					break;
+				case '>':
+					textBuffer.append("&gt;");
+					break;
+				case '"':
+					textBuffer.append("&quot;");
+					break;
+				case 10:
+					textBuffer.append("<br>");
+					break;
+				case ' ':
+					textBuffer.append("&nbsp;");
+					break;
+				//case '&' :
+				//strTxt.append("&amp;");
+				//break;
+				default:
+					textBuffer.append(character);
+			}
+		}
+
+		text = textBuffer.toString();
+		return text;
+	}
+	
+	public static String cleanXSS (String value) {
+		return value
+				.replaceAll("<", "&lt;")
+				.replaceAll(">", "&gt;")
+				.replaceAll("\\(", "&#40;")
+				.replaceAll("\\)", "&#41;")
+				.replaceAll("'", "&#39;")
+				.replaceAll("eval\\((.*)\\)", "")
+				.replaceAll("[\\\"\\\'][\\s]*javascript:(.*)[\\\"\\\']", "\"\"")
+				.replaceAll("(?!)script", "")
+				.replaceAll("(?!)iframe", "")
+				.replaceAll("\'", "")
+				.replaceAll(";", "");
+	}
+
+	public static String cleanSQL (String value) {
+		return value
+				.replaceAll("(?!)SELECT", "")
+				.replaceAll("(?!)INSERT", "")
+				.replaceAll("(?!)DELETE", "")
+				.replaceAll("(?!)UPDATE", "")
+				.replaceAll("(?!)CREATE", "")
+				.replaceAll("(?!)REPLACE", "")
+				.replaceAll("(?!)DROP", "")
+				.replaceAll("(?!)LIMIT", "")
+				.replaceAll("(?!)AND", "")
+				.replaceAll("(?!)OR", "")
+				.replaceAll("(?!)IN", "")
+				.replaceAll("(?!)JOIN", "")
+				.replaceAll("(?!)IF", "")
+				.replaceAll("(?!)CASE", "")
+				.replaceAll("(?!)IS", "")
+				.replaceAll("(?!)NULL", "")
+				.replaceAll("(?!)ALL", "")
+				.replaceAll("(?!)KILL", "")
+				.replaceAll("(?!)UNION", "")
+				.replaceAll("(?!)BETWEEN", "")
+				.replaceAll("(?!)LIKE", "")
+				.replaceAll("(?!)ADD", "")
+				.replaceAll("(?!)DATABASE", "")
+				.replaceAll("(?!)ALTER", "")
+				.replaceAll("(?!)VALUE", "")
+
+				.replaceAll("'", "")
+				.replaceAll("`", "")
+				.replaceAll("=", "")
+				.replaceAll(">", "")
+				.replaceAll("<", "")
+				.replaceAll("/", "")
+				.replaceAll("#", "")
+				.replaceAll("--", "")
+				.replaceAll(";", "");
+	}
+
+    /**
+     * @author 최정우
+     * @since 2019.11.13
+     * 
+     * 문자열을 지정한 분리자에 의해 배열로 리턴하는 메서드.
+     */
+	public static ArrayList<String> split(String text, String separator) throws NullPointerException {
+		ArrayList<String> words = new ArrayList<String>();
+		if (isEmpty(text) == false && separator != null) {
+			int startIndex = -1;
+	    	int endIndex = -1;
+	        while(true) {
+	        	startIndex++;
+	        	endIndex = text.indexOf(separator, startIndex);
+	        	if (endIndex > -1) {
+	        		words.add(text.substring(startIndex, endIndex));
+	        		startIndex = endIndex;
+	        	} else {
+	        		words.add(text.substring(startIndex, text.length()));
+	        		break;
+	        	}
+	        }
+	        return words;
+		} else {
+			if (isEmpty(text) == false) {
+				words.add(text);
+			}
+	        return words;
+		}
+    }
+	
+	/**
+     * @author 최정우
+     * @since 2019.11.13
+     * 
+     * 문자열을 지정한 여러개의 분리자에 의해 배열로 리턴하는 메서드.
+     */
+	public static ArrayList<String> split(String text, String[] separator) throws NullPointerException {
+		ArrayList<String> words = new ArrayList<String>();
+		if (isEmpty(text) == false && separator != null && separator.length > 0) {
+			words.add(text);
+			for (int i = 0; i < separator.length; i++) {
+				ArrayList<String> subWords = new ArrayList<String>();
+				for (int j = 0; j < words.size(); j++) {
+					subWords.addAll(split(words.get(j), separator[i]));
+				}
+				words = subWords;
+			}
+			return words;
+		} else {
+			return words;
+		}
+    }
+    
+    /**
+     * @author 최정우
+     * @since 2019.11.13
+     * 
+     * 문자열을 지정한 분리자에 의해 지정된 길이의 배열로 리턴하는 메서드.
+     */
+    public static ArrayList<String> split(String text, String separator, int maxLength) throws NullPointerException {
+    	ArrayList<String> list = new ArrayList<String>(); 
+    	int startIndex = -1;
+    	int endIndex = -1;
+        while(true) {
+        	startIndex++;
+        	endIndex = text.indexOf(separator, startIndex);
+        	if (endIndex > -1) {
+        		list.add(text.substring(startIndex, endIndex));
+        		startIndex = endIndex;
+        	} else {
+        		list.add(text.substring(startIndex, text.length()));
+        		break;
+        	}
+        	
+        	if (list.size() >= maxLength) {
+        		break;
+        	}
+        }
+        return list;
+    }
+
+    /**
+     * @author 최정우
+     * @since 2019.11.13
+     * 
+     * 소문자 변환
+     */
+    public static String lowerCase(String text) {
+        if (isEmpty(text) == true) {
+            return text;
+        } else {
+        	return text.toLowerCase();
+        }
+    }
+
+    /**
+     * 대문자 변환
+     */
+    public static String upperCase(String text) {
+    	if (isEmpty(text) == true) {
+            return text;
+        } else {
+        	return text.toUpperCase();
+        }
+    }
+
+    /**
+     * @author 최정우
+     * @since 2019.11.13
+     * 
+     * 현재날짜(년,월,일)를 구하는 기능
+     */
+    public static String getToday() {
+		String pattern = "yyyy-MM-dd";
+		SimpleDateFormat dateFormat = new SimpleDateFormat(pattern, Locale.KOREA);
+		Timestamp timestamp = new Timestamp(System.currentTimeMillis());
+		return dateFormat.format(timestamp.getTime());
+    }
+    
+    /**
+     * @author 최정우
+     * @since 2019.11.13
+     * 
+     * 현재날짜(년,월,일)를 구하는 기능
+     */
+    public static String getToday(String pattern) {
+    	String defaultPattern = "yyyy-MM-dd";
+    	if (isEmpty(pattern) == true) {
+    		pattern = defaultPattern;
+    	}
+    	
+    	SimpleDateFormat dateFormat = null;
+		try {
+			dateFormat = new SimpleDateFormat(pattern, Locale.KOREA);
+		} catch (Exception e) {
+			dateFormat = new SimpleDateFormat(defaultPattern, Locale.KOREA);
+		}
+		Timestamp timestamp = new Timestamp(System.currentTimeMillis());
+		return dateFormat.format(timestamp.getTime());
+    }
+    
+    /**
+     * @author 최정우
+     * @since 2019.11.13
+     * 
+     * 현재날짜(년,월,일)를 구하는 기능
+     */
+    public static String getToday(String yearSuffix, String monthSuffix, String daySuffix) {
+    	String defaultPattern = "yyyy년MM월dd일";
+    	if (isEmpty(yearSuffix) == true) {
+    		yearSuffix = "";
+    	}
+    	if (isEmpty(monthSuffix) == true) {
+    		monthSuffix = "";
+    	}
+    	if (isEmpty(daySuffix) == true) {
+    		daySuffix = "";
+    	}
+    	
+    	String pattern = "yyyy" + yearSuffix + "MM" + monthSuffix + "dd" + daySuffix;
+    	
+    	SimpleDateFormat dateFormat = null;
+		try {
+			dateFormat = new SimpleDateFormat(pattern, Locale.KOREA);
+		} catch (Exception e) {
+			dateFormat = new SimpleDateFormat(defaultPattern, Locale.KOREA);
+		}
+		Timestamp timestamp = new Timestamp(System.currentTimeMillis());
+		return dateFormat.format(timestamp.getTime());
+    }
+    
+    /**
+     * @author 최정우
+     * @since 2019.11.13
+     * 
+     * 17자리의 현재일시를 구하는 기능
+     */
+    public static String getDateTime() {
+		// 문자열로 변환하기 위한 패턴 설정(년도-월-일 시:분:초:초(자정이후 초))
+		String pattern = "yyyyMMddHHmmssSSS";
+		SimpleDateFormat dateFormat = new SimpleDateFormat(pattern, Locale.KOREA);
+		Timestamp timestamp = new Timestamp(System.currentTimeMillis());
+		return dateFormat.format(timestamp.getTime());
+    }
+    
+    /**
+     * @author 최정우
+     * @since 2019.11.13
+     * 
+     * 원하는 패턴의 현재일시 구하는 기능
+     */
+    public static String getDateTime(String pattern) {
+    	// 문자열로 변환하기 위한 패턴 설정(년도-월-일 시:분:초:초(자정이후 초))
+    	String defaultPattern = "yyyyMMddHHmmssSSS";
+    	if (isEmpty(pattern)) {
+    		pattern = defaultPattern;
+    	}
+		SimpleDateFormat dateFormat = null;
+		try {
+			dateFormat = new SimpleDateFormat(pattern, Locale.KOREA);
+		} catch (Exception e) {
+			dateFormat = new SimpleDateFormat(defaultPattern, Locale.KOREA);
+		}
+		Timestamp timestamp = new Timestamp(System.currentTimeMillis());
+		return dateFormat.format(timestamp.getTime());
+    }
+    
+    /**
+     * @author 최정우
+     * @since 2019.11.13
+     * 
+     * 현재 일시 - addDay => 원하는 패턴의 일시를 구하는 기능 
+     */
+    public static String getDateTime(String pattern, int addDay) {
+    	// 문자열로 변환하기 위한 패턴 설정(년도-월-일 시:분:초:초(자정이후 초))
+    	String defaultPattern = "yyyyMMddHHmmssSSS";	
+    	if (pattern == null) {
+    		pattern = defaultPattern;
+    	}
+		SimpleDateFormat dateFormat = null;
+		try {
+			dateFormat = new SimpleDateFormat(pattern, Locale.KOREA);
+		} catch (Exception e) {
+			dateFormat = new SimpleDateFormat(defaultPattern, Locale.KOREA);
+		}
+		Calendar cal = new GregorianCalendar();
+		cal.add(Calendar.DATE, addDay);
+		Date date = cal.getTime();
+		return dateFormat.format(date.getTime());
+    }
+    
+    /**
+     * @author 최정우
+     * @since 2019.11.13
+     * 
+     * 현재 일시 - addDay => 원하는 패턴의 일시를 구하는 기능 
+     */
+    public static String getDateTime(String pattern, int addDay, int addHour, int addMin, int addSec) {
+    	// 문자열로 변환하기 위한 패턴 설정(년도-월-일 시:분:초:초(자정이후 초))
+    	String defaultPattern = "yyyyMMddHHmmssSSS";	
+    	if (pattern == null) {
+    		pattern = defaultPattern;
+    	}
+		SimpleDateFormat dateFormat = null;
+		try {
+			dateFormat = new SimpleDateFormat(pattern, Locale.KOREA);
+		} catch (Exception e) {
+			dateFormat = new SimpleDateFormat(defaultPattern, Locale.KOREA);
+		}
+		Calendar cal = new GregorianCalendar();
+		cal.add(Calendar.DATE, addDay);
+		cal.add(Calendar.HOUR, addHour);
+		cal.add(Calendar.MINUTE, addMin);
+		cal.add(Calendar.SECOND, addSec);
+		Date date = cal.getTime();
+		return dateFormat.format(date.getTime());
+    }
+
+	/**
+	 * @author 최정우
+	 * @since 2021.12.05
+	 *
+	 * String -> Date
+	 */
+	public static Date stringToDate (String date, String pattern) {
+		Date result = null;
+		try {
+			SimpleDateFormat transFormat = new SimpleDateFormat(pattern);
+			result = transFormat.parse(date);
+		} catch (Exception e) {
+			e.printStackTrace();
+		}
+		return result;
+	}
+
+	/**
+	 * @author 최정우
+	 * @since 2021.12.05
+	 *
+	 * Date -> String
+	 */
+	public static String dateToString (Date date, String pattern) {
+		String result = null;
+		try {
+			SimpleDateFormat transFormat = new SimpleDateFormat(pattern);
+			result = transFormat.format(date);
+		} catch (Exception e) {
+			e.printStackTrace();
+		}
+		return result;
+	}
+    
+    /**
+     * @author 최정우
+     * @since 2019.11.13
+     * 
+     * 현재 일시(17자리)와, 랜덤숫자(4자리)를 이용하여 키값 생성
+     */
+    public static String getCreateKey (String prefix) {
+		int random = new Random().nextInt(9999);
+		String result = prefix + "_" + getDateTime() + "_" + numberToText(random, 4);
+		return result;
+    }
+
+	/**
+	 * @author 최정우
+	 * @since 2019.11.13
+	 *
+	 * 현재 일시(17자리)와, 랜덤숫자(4자리)를 이용하여 키값 생성
+	 */
+	public static String getRandomKey (int length) {
+		char[][] characters = {
+			{'!', '@', '#', '$', '%', '^', '&', '*', '-', '_', '+', '='},
+			{'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'Z', 'Y', 'Z'},
+			{'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'z', 'y', 'z'},
+			{'1', '2', '3', '4', '5', '6', '7', '8', '9', '0'}
+		};
+
+		String randomText = "";
+		for (int i = 0; i < length; i++) {
+			int randomIndex1 = CommonUtil.getRandomInt(0, characters.length - 1);
+			char[] chars = characters[randomIndex1];
+			int randomIndex2 = CommonUtil.getRandomInt(0, chars.length - 1);
+			randomText += chars[randomIndex2];
+		}
+
+		return randomText;
+	}
+    
+    /**
+     * @author 최정우
+     * @since 2019.11.13
+     * 
+     * 문자열이 Date문자열(yyyy-MM-dd)로 포맷 가능한지
+     * text: 문자열
+     * pattern: 문자열의 날짜 패턴
+     */
+    public static boolean isDate(String text, String pattern) {
+    	try {
+    		Date date = new SimpleDateFormat(pattern).parse(text);
+    		text = new SimpleDateFormat("yyyy-MM-dd").format(date);
+        	return true;
+    	} catch (java.text.ParseException e) {
+			// TODO Auto-generated catch block
+			return false;
+		}
+    }
+    
+    /**
+     * @author 최정우
+     * @since 2019.11.13
+     * 
+     * 문자열을 날짜형태로 Convert
+     * text: 문자열
+     * pattern: 문자열의 날짜 패턴
+     * newPattern: 해당 문자열을 Converting할 날짜 패턴 
+     */
+    public static String textToDateText (String text, String pattern, String newPattern) {
+		String defaultPattern = "yyyy-MM-dd";
+		if (isEmpty(newPattern) == true) {
+			newPattern = defaultPattern;
+    	}
+		
+		SimpleDateFormat dateFormat = new SimpleDateFormat(pattern);
+		Date date = new Date();
+		try {
+			date = dateFormat.parse(text);
+			dateFormat.applyPattern(newPattern);
+			return dateFormat.format(date);
+        } catch (Exception e) {
+            //e.printStackTrace();
+            return text;
+        }
+	}
+    
+    /**
+     * @author 최정우
+     * @since 2019.11.13
+     * 
+     * 숫자 -> 문자열 -> 문자열 길이가 length보다 작을 때, length길이 만큼될 수 있도록 앞에 '0'을 붙여줌
+     */
+    public static String numberToText (int number, int length) {
+    	String text = Integer.toString(number);
+    	if (text.length() < length) {
+            int emptyLength = length - text.length();
+            for (int i = 0; i < emptyLength; i++) {
+            	text = "0" + text;
+            }
+        }
+        return text;
+    }
+
+    /**
+     * @author 최정우
+     * @since 2019.11.13
+     * 
+     * 문자열이 지정한 길이를 초과했을때 해당 문자열을 삭제하는 메서드
+     * @param text 원본 문자열 배열
+     * @param maxLength 지정길이
+     * @return 지정길이로 자른 문자열
+     */
+    public static String cutString(String text, int maxLength) {
+        String result = null;
+        if (text != null) {
+            if (text.length() > maxLength) {
+                result = text.substring(0, maxLength);
+            } else
+                result = text;
+        }
+        return result;
+    }
+	
+
+    /**
+     * @author 최정우
+     * @since 2019.11.13
+     * 
+     * 문자열이 지정한 길이를 초과했을때 지정한길이에다가 해당 문자열을 붙여주는 메서드.
+     * @param text 원본 문자열 배열
+     * @param addText 더할문자열
+     * @param maxLength 지정길이
+     * @return 지정길이로 잘라서 더할분자열 합친 문자열
+     */
+    public static String cutString(String text, String addText, int maxLength) {
+        String result = null;
+        if (text != null) {
+            if (text.length() > maxLength) {
+            	result = text.substring(0, maxLength) + addText;
+            } else
+            	result = text;
+        }
+        return result;
+    }
+
+    
+    /**
+     * @author 최정우
+     * @since 2019.11.13
+     * 
+     * <p>기준 문자열에 포함된 모든 대상 문자(char)를 제거한다.</p>
+     *
+     * <pre>
+     * StringUtil.remove(null, *)       = null
+     * StringUtil.remove("", *)         = ""
+     * StringUtil.remove("queued", 'u') = "qeed"
+     * StringUtil.remove("queued", 'z') = "queued"
+     * </pre>
+     *
+     * @param text  입력받는 기준 문자열
+     * @param remove  입력받는 문자열에서 제거할 대상 문자열
+     * @return 제거대상 문자열이 제거된 입력문자열. 입력문자열이 null인 경우 출력문자열은 null
+     */
+    public static String remove(String text, char remove) {
+        if (isEmpty(text) || text.indexOf(remove) == -1) {
+            return text;
+        }
+        char[] chars = text.toCharArray();
+        int pos = 0;
+        for (int i = 0; i < chars.length; i++) {
+            if (chars[i] != remove) {
+                chars[pos++] = chars[i];
+            }
+        }
+        
+        return new String(chars, 0, pos);
+    }
+
+
+    /**
+     * @author 최정우
+     * @since 2019.11.13
+     * 
+     * 원본 문자열의 포함된 특정 문자열을 새로운 문자열로 변환하는 메서드
+     * @param text 원본 문자열
+     * @param subject 원본 문자열에 포함된 특정 문자열
+     * @param object 변환할 문자열
+     * @return sb.toString() 새로운 문자열로 변환된 문자열
+     */
+    public static String replace(String text, String subject, String object) {
+        StringBuffer rtnStr = new StringBuffer();
+        String preStr = "";
+        String nextStr = text;
+        String srcStr  = text;
+
+        while (srcStr.indexOf(subject) >= 0) {
+            preStr = srcStr.substring(0, srcStr.indexOf(subject));
+            nextStr = srcStr.substring(srcStr.indexOf(subject) + subject.length(), srcStr.length());
+            srcStr = nextStr;
+            rtnStr.append(preStr).append(object);
+        }
+        rtnStr.append(nextStr);
+        return rtnStr.toString();
+    }
+
+    /**
+     * @author 최정우
+     * @since 2019.11.13
+     * 
+     * 원본 문자열의 포함된 특정 문자열 첫번째 한개만 새로운 문자열로 변환하는 메서드
+     * @param source 원본 문자열
+     * @param subject 원본 문자열에 포함된 특정 문자열
+     * @param object 변환할 문자열
+     * @return sb.toString() 새로운 문자열로 변환된 문자열 / source 특정문자열이 없는 경우 원본 문자열
+     */
+    public static String replaceOnce(String source, String subject, String object) {
+        StringBuffer rtnStr = new StringBuffer();
+        String preStr = "";
+        String nextStr = source;
+        if (source.indexOf(subject) >= 0) {
+            preStr = source.substring(0, source.indexOf(subject));
+            nextStr = source.substring(source.indexOf(subject) + subject.length(), source.length());
+            rtnStr.append(preStr).append(object).append(nextStr);
+            return rtnStr.toString();
+        } else {
+            return source;
+        }
+    }
+
+    /**
+     * @author 최정우
+     * @since 2019.11.13
+     * 
+     * <code>subject</code>에 포함된 각각의 문자를 object로 변환한다.
+     *
+     * @param source 원본 문자열
+     * @param subject 원본 문자열에 포함된 특정 문자열
+     * @param object 변환할 문자열
+     * @return sb.toString() 새로운 문자열로 변환된 문자열
+     */
+    public static String replaceChar(String source, String subject, String object) {
+        StringBuffer rtnStr = new StringBuffer();
+        String preStr = "";
+        String nextStr = source;
+        String srcStr  = source;
+
+        char chA;
+
+        for (int i = 0; i < subject.length(); i++) {
+            chA = subject.charAt(i);
+
+            if (srcStr.indexOf(chA) >= 0) {
+                preStr = srcStr.substring(0, srcStr.indexOf(chA));
+                nextStr = srcStr.substring(srcStr.indexOf(chA) + 1, srcStr.length());
+                srcStr = rtnStr.append(preStr).append(object).append(nextStr).toString();
+            }
+        }
+
+        return srcStr;
+    }
+
+    /**
+     * @author 최정우
+     * @since 2019.11.13
+     * 
+     * 문자열을 다양한 문자셋(EUC-KR[KSC5601],UTF-8..)을 사용하여 인코딩하는 기능 역으로 디코딩하여 원래의 문자열을
+     * 복원하는 기능을 제공함 String temp = new String(문자열.getBytes("바꾸기전 인코딩"),"바꿀 인코딩");
+     * String temp = new String(문자열.getBytes("8859_1"),"KSC5601"); => UTF-8 에서
+     * EUC-KR
+     *
+     * @param text - 문자열
+     * @param encoding - 원래의 인코딩된 값
+     * @param decoding - 디코딩할 문자값
+     * @return 인(디)코딩 문자열
+     * @see
+     */
+    public static String textDecoding(String text, String encoding, String decoding) {
+		if (text == null) {
+			return null;
+		}
+	
+		try {
+			text = new String(text.getBytes(encoding), decoding);
+		} catch (UnsupportedEncodingException e) {
+			text = null;
+		}
+	
+		return text;
+    }
+    
+    /**
+     * @author 최정우
+     * @since 2019.11.13
+     * 
+     * 특정 길이 만큼 문자열 뽑기 
+     */
+    public static String fixedText (String text, int maxLength) {
+		if (text == null) text = "";
+		
+		text = text.replaceAll("(\r\n|\r|\n|\n\r)", " ");
+		if (text.length() > maxLength) {
+			text = text.substring(0, maxLength) + "...(중략)";
+		} else if (text.length() < maxLength) {
+			int emptySize = maxLength - text.length();
+			if (emptySize == 1) {
+				text += " ";
+			} else {
+				int halfEmptySize = emptySize / 2;
+				for (int i = 0; i < halfEmptySize; i++) {
+					text = " " + text + " ";
+				}
+				if (0 < emptySize % 2) {
+					text += " ";
+				}
+			}
+		}
+		
+		return text;
+	}
+    
+    /**
+     * @author 최정우
+     * @since 2021.09.28
+     * 
+     * 스네이크 표기법 => 카멜 표기법 
+     */
+    public static String snakeToCamel (String text) {
+    	String camelText = "";
+    	
+    	if (text != null) {
+    		text = removeSpace(text);
+    		text = text.toLowerCase();
+    		
+    		String[] texts = text.split("_");
+    		if (texts.length > 1) {
+    			camelText += texts[0];
+    			for (int i = 1; i < texts.length; i++) {
+    				if (texts[i].length() > 0) {
+    					char[] chars = texts[i].toCharArray();
+        				chars[0] = Character.toUpperCase(chars[0]);
+        				camelText += new String(chars);
+    				} else {
+    					continue;
+    				}
+    			}
+    		} else {
+    			camelText = text;
+    		}
+    	}
+    	
+    	return camelText;
+    }
+    
+    /**
+     * @author 최정우
+     * @since 2021.09.28
+     * 
+     * 카멜 표기법 => 스네이크 표기법
+     */
+    public static String camelToSnake (String text, boolean isUpperCase) {
+    	String snakeText = "";
+    	
+    	if (text != null) {
+    		text = removeSpace(text);
+    		
+    		String[] texts = text.split("[A-Z]");
+			for (int i = 0; i < texts.length; i++) {
+				if (texts[i].length() > 0) {
+					snakeText += (texts[i] + "_");
+					int currentIndex = snakeText.length() - 1 - i;
+					if (currentIndex <= text.length() - 1) {
+						//System.out.println("text.toCharArray()[currentIndex] : " + text.toCharArray()[currentIndex]);
+						snakeText += text.toCharArray()[currentIndex];
+					}
+				} else {
+					continue;
+				}
+			}
+
+			try {
+				snakeText = snakeText.substring(0, snakeText.length() - 1);
+			} catch (StringIndexOutOfBoundsException e) {
+				snakeText = text;
+			}
+    		
+    		if (isUpperCase == true) {
+    			snakeText = snakeText.toUpperCase();
+    		} else {
+    			snakeText = snakeText.toLowerCase();
+    		}
+    		
+    	}
+    	
+    	return snakeText;
+    }
+
+	/**
+	 * @author 최정우
+	 * @since 2021.03.24
+	 *
+	 * 문자열 나누기
+	 *
+	 * @param text - 문자열
+	 * @param bufferSize - 문자열을 나눌 기준 값
+	 *
+	 * @throws Exception
+	 */
+	public static List<String> textSeparation (String text, int bufferSize) throws Exception {
+		List<String> result = new ArrayList<String>();
+
+		if (text == null) {
+			throw new Exception("문자열이 없음(null)");
+		}
+
+		if (bufferSize <= 0) {
+			throw new Exception("bufferSize는 0초과이어야 합니다.");
+		}
+
+		int unitSize = text.length() / bufferSize;
+		int remainSize = text.length() % bufferSize;
+
+		for (int i = 0; i < unitSize; i++) {
+			int startIndex = i * bufferSize;
+			int endIndex = (i + 1) * bufferSize;
+			//System.out.println(startIndex + ", " + endIndex);
+			result.add(text.substring(startIndex, endIndex));
+		}
+		if (remainSize > 0) {
+			result.add(text.substring(unitSize * bufferSize, text.length()));
+		}
+
+		return result;
+	}
+}
 
src/back-end/main/java/common/util/bean/ApplicationContextProvider.java (added)
+++ src/back-end/main/java/common/util/bean/ApplicationContextProvider.java
@@ -0,0 +1,44 @@
+package common.util.bean;
+
+import org.springframework.beans.BeansException;
+import org.springframework.context.ApplicationContext;
+import org.springframework.context.ApplicationContextAware;
+import org.springframework.stereotype.Component;
+
+/**
+ * @author 최정우
+ * @since 2019.11.17
+ * 
+ * Spring 컨테이너(ApplicationContext)에 접근하기 위한 Class 입니다.
+ * ApplicationContextAware 구현체
+ */
+public class ApplicationContextProvider implements ApplicationContextAware {
+    
+	/**
+	 * 해당 어플리케이션의 인스턴스(bean)들의 정보를 담은 객체 
+	 */
+    private static ApplicationContext applicationContext;
+    
+    /**
+     * @author 최정우
+     * @since 2019.11.17
+     * 
+     * ApplicationContextAware를 구현하기 위한 메소드
+     * Spring 구동 시, 해당 Class가 스캔 당하면 applicationContext 객체가 생성됨
+     */
+    @Override
+    public void setApplicationContext(ApplicationContext ctx) throws BeansException {
+        applicationContext = ctx;
+    }
+    
+    /**
+     * @author 최정우
+     * @since 2019.11.17
+     * 
+     * applicationContext 객체 호출
+     */
+    public static ApplicationContext getApplicationContext() {
+        return applicationContext;
+    }
+ 
+}(No newline at end of file)
 
src/back-end/main/java/common/util/bean/BeanUtil.java (added)
+++ src/back-end/main/java/common/util/bean/BeanUtil.java
@@ -0,0 +1,44 @@
+package common.util.bean;
+
+import org.springframework.beans.BeansException;
+
+/**
+ * ApplicationContextProvider에서 bean객체를 얻어 활용할 수 있도록 해주는 Util 입니다.
+ *
+ * @author 최정우
+ * @since 2020.11.25
+ */
+public class BeanUtil {
+
+	/**
+	 * 해당 어플리케이션에서 스프링 컨테이너가 관리하는 bean으로 등록된 객체를 이름으로 호출
+	 *
+	 * @author 최정우
+	 * @since 2019.11.17
+	 */
+	public static Object getBean(String beanName) {
+		System.out.println("BeanUtil getBean(param (String) beanName : " + beanName + ")");
+		try {
+			return ApplicationContextProvider.getApplicationContext().getBean(beanName);
+		} catch (BeansException e) {
+			e.printStackTrace();
+			return null;
+		}
+	}
+
+	/**
+	 * 해당 어플리케이션에서 스프링 컨테이너가 관리하는 bean으로 등록된 객체를 객체의 타입으로 호출
+	 *
+	 * @author 최정우
+	 * @since 2019.11.17
+	 */
+	public static Object getBean(Class<?> classType) {
+		System.out.println("BeanUtil getBean(param (Class<?>) classType : " + classType.getName() + ")");
+		try {
+			return ApplicationContextProvider.getApplicationContext().getBean(classType);
+		} catch (BeansException e) {
+			e.printStackTrace();
+			return null;
+		}
+	}
+}
 
src/back-end/main/java/common/util/reflection/ParentLastURLClassLoader.java (added)
+++ src/back-end/main/java/common/util/reflection/ParentLastURLClassLoader.java
@@ -0,0 +1,88 @@
+package common.util.reflection;
+
+import java.net.URL;
+import java.net.URLClassLoader;
+
+/*
+ * 커스텀 URLClassLoder
+ * 
+ * WAS(톰캣)에서 URLClassLoder로 작동시 외부 라이브러리에 있는 jar파일을 읽지 못함
+ * 외부 라이브러리 class들을 먼저 읽기 위함
+ */
+public class ParentLastURLClassLoader extends ClassLoader 
+{
+    private ChildURLClassLoader childClassLoader;
+
+    /**
+     * This class allows me to call findClass on a classloader
+     */
+    private static class FindClassClassLoader extends ClassLoader
+    {
+        public FindClassClassLoader(ClassLoader parent)
+        {
+            super(parent);
+        }
+
+        @Override
+        public Class<?> findClass(String name) throws ClassNotFoundException
+        {
+            return super.findClass(name);
+        }
+    }
+
+    /**
+     * This class delegates (child then parent) for the findClass method for a URLClassLoader.
+     * We need this because findClass is protected in URLClassLoader
+     */
+    private static class ChildURLClassLoader extends URLClassLoader
+    {
+        private FindClassClassLoader realParent;
+
+        public ChildURLClassLoader( URL[] urls, FindClassClassLoader realParent )
+        {
+            super(urls, null);
+
+            this.realParent = realParent;
+        }
+
+        @Override
+        public Class<?> findClass(String name) throws ClassNotFoundException
+        {
+            try
+            {
+                // first try to use the URLClassLoader findClass
+                return super.findClass(name);
+            }
+            catch( ClassNotFoundException e )
+            {
+                // if that fails, we ask our real parent classloader to load the class (we give up)
+                return realParent.loadClass(name);
+            }
+        }
+    }
+
+    //List<URL> classpath
+    public ParentLastURLClassLoader(URL[] urls)
+    {
+        super(Thread.currentThread().getContextClassLoader());
+
+        //URL[] urls = classpath.toArray(new URL[classpath.size()]);
+
+        childClassLoader = new ChildURLClassLoader( urls, new FindClassClassLoader(this.getParent()) );
+    }
+
+    @Override
+    protected synchronized Class<?> loadClass(String name, boolean resolve) throws ClassNotFoundException
+    {
+        try
+        {
+            // first we try to find a class inside the child classloader
+            return childClassLoader.findClass(name);
+        }
+        catch( ClassNotFoundException e )
+        {
+            // didn't find it, try the parent
+            return super.loadClass(name, resolve);
+        }
+    }
+}(No newline at end of file)
 
src/back-end/main/java/common/util/reflection/ReflectionUtil.java (added)
+++ src/back-end/main/java/common/util/reflection/ReflectionUtil.java
@@ -0,0 +1,222 @@
+package common.util.reflection;
+
+import common.util.StringUtil;
+import common.util.bean.BeanUtil;
+
+import java.io.File;
+import java.lang.reflect.Method;
+import java.net.URL;
+
+/**
+ * @author 최정우
+ * @since 2020.11.25
+ * 
+ * Reflection - 클래스, 인터페이스, 메소드관련 인스턴스화(로드) 및 실행 관련 Util입니다.
+ */
+public class ReflectionUtil {
+	
+	/******************************************** Class 단 ********************************************/
+	/**
+     * @author 최정우
+	 * @since 2020.11.25 
+     *
+     * classLoad - 어플리케이션 내부(+Bean객체포함) OR 외부의 class 파일을 저장된 경로를 통해  class 파일 로드 후, 객체 생성
+     * 
+	 * classFullName과 classFilePath를 통해 실제 클래스를 인스턴스화함.
+	 * 1. Class.forName을 통해 어플리케이션 내부의 class path에 있는 class객체 생성
+	 * 2. 어플리케이션 내부에 class가 존재할 때
+	 * 		2-1. 어플리케이션의 Spring 컨테이너에 해당 클래스 타입으로 생성된 Bean이 있는지 확인
+	 * 			=> 존재할 때, Bean 객체 주입
+	 * 			=> 존재하지 않을 때, 객체 생성
+	 * 3. 어플리케이션 내부에 class가 존재하지 않을 때
+	 * 		3-1. class or jar file이 저장된 경로를 이용하여 클래스를 로드 
+	 * 
+	 * 4. 객체 생성 실패시, Log 기록 및 다음 작업 목록으로 넘어감
+	 */
+    public static Object classAndBeanLoad (String classFilePath, String classFullName) {
+    	Object clazz = null;
+    	try {
+    		//Class.forName을 통해 어플리케이션 내부의 class path에 있는 class객체 생성
+			Class<?> c = forName(classFullName);
+			if (c != null) {//어플리케이션 내부에 class가 존재할 때
+				//플리케이션의 Spring 컨테이너에 해당 클래스 타입으로 생성된 Bean이 있는지 확인 후, Bean 객체 주입
+				clazz = BeanUtil.getBean(c);
+				
+				if (clazz == null) {//Bean 객체 존재하지 않을 때
+					clazz = newInstance(c);
+				}
+			} else {//어플리케이션 내부에 class가 존재하지 않을 때
+				//class or jar file이 저장된 경로
+				//file 경로 값이 있을 때만 클래스를 로드함
+				if (StringUtil.isEmpty(classFilePath) == false) {
+					if (StringUtil.isEmpty(classFullName) == false) {
+						clazz = classLoad(classFilePath, classFullName);
+					} else {
+						clazz = classLoad(classFilePath);
+					}
+				}
+			}
+    	} catch (Exception e) {
+    		e.printStackTrace();
+    	}
+    	
+    	return clazz;
+    }
+	
+	/**
+     * @author 최정우
+	 * @since 2019.11.17
+     * 
+     * forName - 어플리케이션 내부의 class path에 있는 class객체 생성
+     * 
+     * classFullName = package명 + class명
+     */
+    public static Class<?> forName (String classFullName) {
+    	try {
+    		return Class.forName(classFullName);
+    	} catch (Exception e) {
+    		e.printStackTrace();
+    		return null;
+    	} 
+    }
+    
+    /**
+     * @author 최정우
+	 * @since 2019.11.17 
+     *
+     * classLoad - 어플리케이션 내부 OR 외부의 class 파일을 저장된 경로를 통해  class 파일 로드 후, 객체 생성
+     * 주로 외부 class파일을 로드할 때 쓰임
+     * 
+     * classFilePath - 클래스파일 절대경로
+     * classFullName = package명 + class명
+     */
+    public static Object classLoad (String classFilePath, String classFullName) {
+    	try {
+    		File file = new File(classFilePath);
+    		//실제 경로상에 있는 .class파일을 통해 class를 읽어옴
+    		ParentLastURLClassLoader classLoader = new ParentLastURLClassLoader(new URL[] { file.toURI().toURL() });
+    		//읽어온 .class파일을 이용해 해당되는  패키지 내에 있는 class를 로드해 옴
+    		Class<?> c = classLoader.loadClass(classFullName);
+    		//class를 new 객체 생성함
+    		return newInstance(c);
+    	} catch (Exception e) {
+    		e.printStackTrace();
+    		return null;
+    	}
+    }
+    
+    /**
+     * @author 최정우
+	 * @since 2019.11.17
+     * 
+     * classLoad - 어플리케이션 내부 OR 외부의 class 파일을 저장된 경로를 통해  class 파일 로드 후, 객체 생성
+     * 주로 외부 class파일을 로드할 때 쓰임
+     * class명을 모를 때 사용
+     * 
+     * classFilePath - 클래스파일 절대경로
+     */
+    public static Object classLoad (String classFilePath) {
+    	try {
+    		File file = new File(classFilePath);
+    		//실제 경로상에 있는 .class파일을 통해 class를 읽어옴
+    		ParentLastURLClassLoader classLoader = new ParentLastURLClassLoader(new URL[] { file.toURI().toURL() });
+    		//읽어온 .class파일을 이용해 해당되는  패키지 내에 있는 class를 로드해 옴
+    		Class<?> c = classLoader.getClass();
+    		//class를 new 객체 생성함
+    		return newInstance(c);
+    	} catch (Exception e) {
+    		e.printStackTrace();
+    		return null;
+    	}
+    }
+    
+    /**
+     * @author 최정우
+	 * @since 2019.11.17
+     * 
+     * newInstance - 객체 인스턴스화(로드)
+     */
+    public static Object newInstance(Class<?> c) {
+    	try {
+			return c.newInstance();
+		} catch (Exception e) {
+			e.printStackTrace();
+			return null;
+		}
+    }
+    
+    /******************************************** Class 단 ********************************************/
+    
+    
+    
+    /******************************************** Method 단 ********************************************/
+    /**
+     * @author 최정우
+	 * @since 2019.11.17
+     * 
+     * invokeByMethodName - 메소드 이름을 통한 메소드 호출
+     * 
+     * clazz - 인스턴스화(로드)된 객체
+     * methodName - 메소드명
+     * paramValues - 메소드의 파라메터 값
+     * paramTypes - 메소드의 파라메터 타입
+     * (주의 paramValues, paramTypes 순서가 같아야함)
+     */
+    public static Object invokeByMethodName (Object clazz, String methodName, Object[] paramValues, Class<?>[] paramTypes) {
+    	try {
+    		Method method = null;
+        	if (paramValues != null && paramTypes != null 
+        		&& paramValues.length > 0 && paramTypes.length > 0
+        		&& paramValues.length == paramTypes.length) {
+        		
+        		System.out.println("clazz getPackage : " + clazz.getClass().getPackage());
+        		System.out.println("clazz name : " + clazz.getClass().getName());
+        		if (paramValues != null && paramValues.length > 0) {
+        			System.out.println("clazz param value : " + paramValues[0].toString());
+            		System.out.println("clazz param type : " + paramTypes[0].getTypeName());
+        		}
+        		
+        		//메소드 객체 가지고오기
+        		method = clazz.getClass().getMethod(methodName, paramTypes);
+        	} else {
+        		//메소드 객체 가지고오기
+        		method = clazz.getClass().getMethod(methodName);
+        	}
+        	
+        	//메소드 호출
+    		return invoke(clazz, method, paramValues);
+        	
+		} catch (Exception e) {
+			e.printStackTrace();
+			return null;
+		}
+    	
+    }
+    
+    /**
+     * @author 최정우
+	 * @since 2019.11.17
+     * 
+     * invoke - 메소드 호출
+     * 
+     * clazz - 인스턴스화(로드)된 객체
+     * method - 메소드 객체
+     * paramValues - 메소드의 파라메터 값
+     */
+    public static Object invoke (Object clazz, Method method, Object[] paramValues) {
+    	try {
+        	if (paramValues != null && paramValues.length > 0) {
+        		//메소드 호출
+        		return method.invoke(clazz, paramValues);
+        	} else {
+        		//메소드 호출
+        		return method.invoke(clazz);
+        	}
+		} catch (Exception e) {
+			e.printStackTrace();
+			return null;
+		}
+    	
+    }
+    /******************************************** Method 단 ********************************************/
+}
 
src/back-end/main/java/common/util/socket/FileUtil.java (added)
+++ src/back-end/main/java/common/util/socket/FileUtil.java
@@ -0,0 +1,194 @@
+package common.util.socket;
+
+//import javax.activation.MimetypesFileTypeMap;
+import javax.imageio.ImageIO;
+import java.awt.*;
+import java.awt.image.BufferedImage;
+import java.io.*;
+import java.text.SimpleDateFormat;
+import java.util.Base64;
+import java.util.Date;
+
+/**
+ * @author 최정우
+ * @since 2019.12.11
+ * 
+ * 파일 Util 입니다. 
+ */
+public class FileUtil {
+
+	//이미지 파일 resizing 여부
+	public static boolean IMAGE_FILE_RESIZING = false;
+	
+	//resizing이 필요한 이미지 파일 크기
+	public static int IMAGE_FILE_NEED_RESIZING_SIZE = 1024 * 1024;//1MB
+	
+	//resizing시 기본 이미지 크기
+	public static double IMAGE_FILE_RESIZING_RATE = 0.5;
+	
+	public static byte[] fileToByte (File file) {
+		//파일 byte를 담을 공간
+		byte[] bytes = null;
+		
+		FileInputStream fileInput = null;
+		try {
+			// 파일 읽을 줄비
+			fileInput = new FileInputStream(file);
+			// 바이너리 공간 확보
+			bytes = new byte[fileInput.available()];
+			// 파일 -> byte
+			fileInput.read(bytes);
+		} catch (Exception e) {
+			e.printStackTrace();
+		} finally {
+			if (fileInput != null) {
+				try {
+					fileInput.close();
+				} catch (IOException e1) {
+					e1.printStackTrace();
+				}
+			}
+		}
+		
+		return bytes;
+	}
+	
+	public static byte[] base64Encoding(byte[] buffer) {
+	    return Base64.getEncoder().encode(buffer);
+	}
+	
+	public static byte[] base64Decoding(byte[] buffer) {
+	    return Base64.getDecoder().decode(buffer);
+	}
+	
+	public static boolean isImageFile (File file) {
+		boolean result = false;
+		
+		try {
+			String mimeType = null;//new MimetypesFileTypeMap().getContentType(file);
+			String type = mimeType.split("/")[0];
+			if (type.equals("image") == true) {
+				result = true;
+			}
+		} catch (Exception e) {
+			e.printStackTrace();
+			result = false;
+		}
+		
+		return result;
+	}
+	
+	public static byte[] imageFileResizeToByte (File imageFile) {
+		//파일 byte를 담을 공간
+		byte[] bytes = null;
+		
+		String fileName = imageFile.getName();
+		//String filePath = imageFile.getPath();
+		String extension = fileName.substring(fileName.lastIndexOf(".") + 1);
+		
+		//1MB보다 클 때
+		System.out.println("file Size : " + imageFile.length());
+		if (imageFile.length() > IMAGE_FILE_NEED_RESIZING_SIZE) {
+			BufferedImage image = null;
+			BufferedImage resizedImage = null;
+			ByteArrayOutputStream baos = null;
+			try {
+				image = ImageIO.read(imageFile);
+				if (image != null) {
+					/*이미지 파일 일 때*/
+					int newWidth = (int) (image.getWidth() * IMAGE_FILE_RESIZING_RATE);
+					int newHeight = (int) (image.getHeight() * IMAGE_FILE_RESIZING_RATE);
+					System.out.println("resizing width : " + image.getWidth() + " ->" + newWidth);
+					System.out.println("resizing height : " + image.getHeight() + " ->" + newHeight);
+					
+					// 이미지 리사이즈
+		            // Image.SCALE_DEFAULT : 기본 이미지 스케일링 알고리즘 사용
+		            // Image.SCALE_FAST    : 이미지 부드러움보다 속도 우선
+		            // Image.SCALE_REPLICATE : ReplicateScaleFilter 클래스로 구체화 된 이미지 크기 조절 알고리즘
+		            // Image.SCALE_SMOOTH  : 속도보다 이미지 부드러움을 우선
+		            // Image.SCALE_AREA_AVERAGING  : 평균 알고리즘 사용
+					Image resizeImage = image.getScaledInstance(newWidth, newHeight, Image.SCALE_SMOOTH);
+					
+					int imageType = image.getType() == 0? BufferedImage.TYPE_INT_ARGB : image.getType();
+					resizedImage = new BufferedImage(newWidth, newHeight, imageType);
+			        Graphics2D g = resizedImage.createGraphics();
+			        g.drawImage(resizeImage, 0, 0, null);
+			        g.dispose();
+			        
+			        // resizing 파일 -> byte
+			        baos = new ByteArrayOutputStream();
+			        ImageIO.write(resizedImage, extension, baos);
+			        bytes = baos.toByteArray();
+				}
+			} catch (IOException e) {
+				/*이미지 파일이 아님*/
+				e.printStackTrace();
+			} finally {
+				if (baos != null) {
+					try {
+						baos.close();
+					} catch (IOException e) {
+						e.printStackTrace();
+					}
+				}
+			}
+		}
+		
+		if (bytes == null) {
+			bytes = fileToByte(imageFile);
+		}
+		
+		return bytes;
+	}
+	
+	/**
+	 * 작성일 : 210316 작성자 : 최정우
+	 * 
+	 * 로그파일 남기기
+	 * 
+	 * @param massage : 로그
+	 */
+	public static void writeLogFile(String massage, String fileName, String filePath) {
+		BufferedWriter fw = null;
+		try {
+			// 현재 일시
+			SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
+			String dateTime = dateFormat.format(new Date());
+			// 현재 일자
+			String date = dateTime.split(" ")[0];
+
+			// 현재 클래스의 디렉토리 (절대경로)
+			// String currentPath = System.getProperty("user.dir");
+			// [현재 클래스의 디렉토리 + 서브 폴더 디렉토리]의 존재 여부
+			File dir = new File(filePath);
+			if (dir.exists() == false) {
+				dir.mkdir();// 존재하지 않을 때 폴더 생성
+			}
+			// 로그 파일명(socket_server_log_[현재 일자].txt)
+			String newFileName = fileName + "_" + date + ".txt";
+
+			// 로그 파일의 절대 경로
+			String fileFullPath = filePath + File.separator + newFileName;
+
+			/* 로그 남기기 */
+			// BufferedWriter 와 FileWriter를 조합하여 사용 (속도 향상)
+			fw = new BufferedWriter(new FileWriter(fileFullPath, true));
+			// 파일안에 문자열 쓰기
+			fw.write(("[" + dateTime + "] " + massage + "\n"));
+			fw.flush();
+
+			// 객체 닫기
+			fw.close();
+		} catch (Exception e) {
+			e.printStackTrace();
+		} finally {
+			if (fw != null) {
+				try {
+					fw.close();
+				} catch (IOException e) {
+					e.printStackTrace();
+				}
+			}
+		}
+	}
+}
 
src/back-end/main/java/common/util/socket/SocketManager.java (added)
+++ src/back-end/main/java/common/util/socket/SocketManager.java
@@ -0,0 +1,308 @@
+package common.util.socket;
+
+import com.fasterxml.jackson.core.type.TypeReference;
+import com.fasterxml.jackson.databind.DeserializationFeature;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.fasterxml.jackson.databind.SerializationFeature;
+import common.util.StringUtil;
+import common.util.socket.message.MessageProtocol;
+import common.util.socket.message.code.MessageCode;
+import common.util.socket.message.vo.Message;
+
+import java.io.DataInputStream;
+import java.io.DataOutputStream;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.net.InetSocketAddress;
+import java.net.Socket;
+import java.net.SocketAddress;
+import java.util.Arrays;
+import java.util.List;
+
+public class SocketManager {
+	
+	public static final int DEFAULT_SOCKET_PORT = 2200;
+	
+	//최대 패킷 byte
+	private final int maxPacketSize = 65000;
+	//기본 Socket연결 최대 시간(밀리세컨드)
+	private final int defalutSocketTimeout = 1 * 60 * 1000;//1분
+	//Socket 메세지 데이터 읽을 때, 최대 시간(밀리세컨드)
+	private final int defalutMessageTimeout = 10 * 1000 * 1000;//10초
+	
+	
+	private ObjectMapper mapper = null;
+	private TypeReference<MessageProtocol> typeReferene = null;
+	{
+		/*************** [통신 처리 준비] 메세지 JSON Parsing ***************/
+		mapper = new ObjectMapper();
+		mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
+		mapper.configure(SerializationFeature.FAIL_ON_EMPTY_BEANS, false);
+		
+		typeReferene = new TypeReference<MessageProtocol>() {};
+	}
+	
+
+	public Message request(Socket clientSocket, Message message) throws Exception {
+		List<Message> messageList = Arrays.asList(message);
+		messageList = request(clientSocket, messageList);
+		return messageList.get(0);
+	}
+
+	public List<Message> request(Socket clientSocket, List<Message> messageList) throws Exception {
+		if (clientSocket == null || clientSocket.isClosed() == true) {
+			throw new Exception("소켓이 없거나 닫쳤습니다.");
+		}
+		// 결과 메세지 목록
+		List<Message> responseMessageList = null;
+		
+		InputStream input = null;
+		DataInputStream dataInput = null;
+		OutputStream output = null;
+		DataOutputStream dataOutput = null;
+		try {
+			
+			/*************** [통신 처리 준비] 클라이언트 -> 서버 ***************/
+			// OutputStream - Client에서 Server로 메세지 발송
+			output = clientSocket.getOutputStream();
+			// socket의 OutputStream 정보를 OutputStream out에 넣은 뒤
+			dataOutput = new DataOutputStream(output);
+			/*************** 요청 메세지 구성 ***************/
+			// 통신하기 위한 메세지 규약 생성 (요청 메시지 타입 : 명령어)
+			MessageProtocol mp = new MessageProtocol(MessageCode.CommunicationType.REQUEST);
+			// Body에 데이터 전송할 데이터 담기
+			mp.getBody().setMessageList(messageList);
+			/*************** 요청 메세지 전송 ***************/
+			// 메세지 규약 전체를 JSON문자열로 변경
+			String requestProtocolToJson = mapper.writeValueAsString(mp);
+			//System.out.println("requestProtocolToJson : " + requestProtocolToJson);
+			
+			System.out.println("메세지 전송 시작!");
+			// JSON문자열을 여러개로 나눔
+			List<String> requestProtocolToJsonList = StringUtil.textSeparation(requestProtocolToJson, maxPacketSize);
+			System.out.println("requestProtocolToJsonList.size() : " + requestProtocolToJsonList.size());
+			
+			for (String text : requestProtocolToJsonList) {
+				// 메세지 담기
+				dataOutput.writeUTF(text);
+				
+				// 메세지 전송
+				//dataOutput.flush();
+			}
+			
+			// 종료 메세지 담기
+			dataOutput.writeUTF(MessageCode.MessageFlag.MESSAGE_END.toString());
+			// 종료 메세지 전송
+			dataOutput.flush();
+			
+			System.out.println("메세지 전송 완료!");
+			
+			/*************** [통신 처리 준비] 서버 -> 클라이언트 ***************/
+			// InputStream - Server에서 보낸 메세지 Client로 가져옴
+			input = clientSocket.getInputStream();
+			// socket의 InputStream 정보를 InputStream in에 넣은 뒤
+			dataInput = new DataInputStream(input);
+			
+			/*************** 서버 결과 메세지 확인 ***************/
+			System.out.println("응답 대기 시작!");
+			
+			// 클라이언트에서 온 메세지 확인
+			String responseProtocolToJson = "";
+			while (true) {
+				String text = dataInput.readUTF();
+				//System.out.println((a++) + ". " + text);
+				if (text.equals(MessageCode.MessageFlag.MESSAGE_END.toString())) {
+					System.out.println("응답 완료!");
+					break;
+				}
+				responseProtocolToJson += text;
+			}
+			//System.out.println("responseProtocolToJson : " + responseProtocolToJson);
+			
+			// 메세지 규약 전체를 JSON문자열로 변경
+			MessageProtocol responseMP = mapper.readValue(responseProtocolToJson, typeReferene);
+			
+			// 결과 메세지 목록
+			responseMessageList = responseMP.getBody().getMessageList();
+			
+			for (int i = 0; i < messageList.size(); i++) {
+				messageList.set(i, responseMessageList.get(i));
+			}
+			
+		} catch (Exception e) {
+			e.printStackTrace();
+		} finally {
+			if (dataInput != null)
+				dataInput.close();
+			if (input != null)
+				input.close();
+
+			if (dataOutput != null)
+				dataOutput.close();
+			if (output != null)
+				output.close();
+			
+			/*소켓 종료*/
+			if (clientSocket != null)
+				socketClose(clientSocket);
+		}
+		
+		return responseMessageList;
+	}
+
+	public void response(Socket clientSocket) throws Exception {
+		if (clientSocket == null || clientSocket.isClosed() == true) {
+			throw new Exception("소켓이 없거나 닫쳤습니다.");
+		}
+
+		InputStream input = null;
+		DataInputStream dataInput = null;
+		OutputStream output = null;
+		DataOutputStream dataOutput = null;
+		try {
+			/*************** [통신 처리 준비] 클라이언트 -> 서버 ***************/
+			// InputStream - Client에서 보낸 메세지 Server로 가져옴
+			input = clientSocket.getInputStream();
+			// socket의 InputStream 정보를 InputStream in에 넣은 뒤
+			dataInput = new DataInputStream(input);
+			
+			/*************** [통신 처리 준비] 서버 -> 클라이언트 ***************/
+			// OutputStream - Server에서 Client로 메세지 발송
+			output = clientSocket.getOutputStream();
+			// socket의 OutputStream 정보를 OutputStream out에 넣은 뒤
+			dataOutput = new DataOutputStream(output);
+			
+			/*************** 클라이언트 메세지 확인 ***************/
+			System.out.println("요청 대기 시작!");
+			// 클라이언트에서 온 메세지 확인
+			String requestProtocolToJson = "";
+			while (true) {
+				String text = dataInput.readUTF();
+				if (text.equals(MessageCode.MessageFlag.MESSAGE_END.toString())) {
+					System.out.println("요청 완료!");
+					break;
+				}
+				requestProtocolToJson += text;
+			}
+			//System.out.println("requestProtocolToJson : " + requestProtocolToJson);
+			
+			// 메세지 규약 전체를 JSON문자열로 변경
+			MessageProtocol requestMP = mapper.readValue(requestProtocolToJson, typeReferene);
+			// 메세지 목록
+			List<Message> requestMessageList = requestMP.getBody().getMessageList();
+			/*************** 클라이언트 메세지 처리 ***************/
+			// 메세지 실행
+			for (int i = 0; i < requestMessageList.size(); i++) {
+				try {
+					// 메세지 실행 결과 (true(=SUCCESS) or false(=FAIL))
+					boolean result = requestMessageList.get(i).run();
+					
+					/** run() 메소드의 동작 결과값 활용 -> '메세지 결과 세팅' (※필수) **/
+					if (result == true) {
+						requestMessageList.get(i).setResultMessageByFlag(MessageCode.MessageFlag.SUCCESS);//result값은 자동으로 true로 정의됨
+					} else {
+						requestMessageList.get(i).setResultMessageByFlag(MessageCode.MessageFlag.FAIL);//result값은 자동으로 false로 정의됨
+					}
+				} catch (Exception e) {
+					/** run() 메소드의 에러 결과값 활용 -> '메세지 결과 세팅' (※필수) **/
+					requestMessageList.get(i).setResultMessageByError(e);//result값은 자동으로 false로 정의됨
+				}
+			}
+			
+			
+			/*************** 클라이언트에게 결과 메세지 전송 ***************/
+			// 결과 메세지 JSON문자열로 변경
+			String responseProtocolToJson = mapper.writeValueAsString(requestMP);
+			//System.out.println("responseProtocolToJson : " + responseProtocolToJson);
+			
+			System.out.println("결과 메세지 전송 시작!");
+			// JSON문자열을 여러개로 나눔
+			List<String> responseProtocolToJsonList = StringUtil.textSeparation(responseProtocolToJson, maxPacketSize);
+			System.out.println("responseProtocolToJsonList size : " + responseProtocolToJsonList.size());
+			for (String text : responseProtocolToJsonList) {
+				//System.out.println("text : " + text);
+				// 메세지 담기
+				dataOutput.writeUTF(text);
+				// 메세지 전송
+				//dataOutput.flush();
+			}
+			
+			// 종료 메세지 담기
+			dataOutput.writeUTF(MessageCode.MessageFlag.MESSAGE_END.toString());
+			// 종료 메세지 전송
+			dataOutput.flush();
+			
+			System.out.println("결과 메세지 전송 완료!");
+			
+		} finally {
+			if (dataOutput != null)
+				dataOutput.close();
+			if (output != null)
+				output.close();
+
+			if (dataInput != null)
+				dataInput.close();
+			if (input != null)
+				input.close();
+		}
+	}
+
+	/**
+	 * 210316 최정우
+	 * 
+	 * Socket 생성
+	 * 
+	 * @param socket : 소켓 객체
+	 * @return
+	 */
+	public Socket socketCreate(String ip, int port) {
+		SocketAddress socketAddress = null;
+		Socket socket = null;
+		try {
+			socketAddress = new InetSocketAddress(ip, port);
+			socket = new Socket();
+			socket.setSoTimeout(defalutSocketTimeout);
+			socket.connect(socketAddress, defalutMessageTimeout);
+		} catch (Exception e) {
+			e.printStackTrace();
+		}
+		return socket;
+	}
+	
+	/**
+	 * 210316 최정우
+	 * 
+	 * Socket 생성
+	 */
+	public Socket socketCreate(String ip, int port, int timeout) {
+		Socket socket = null;
+		try {
+			socket = new Socket(ip, port);
+			socket.setSoTimeout(timeout);
+		} catch (Exception e) {
+			e.printStackTrace();
+		}
+		return socket;
+	}
+
+	/**
+	 * 210316 최정우
+	 * 
+	 * Socket 닫기
+	 */
+	public boolean socketClose(Socket socket) {
+		boolean result = false;
+		try {
+			if (socket != null && socket.isClosed() == false) {
+				socket.close();
+			}
+			result = true;
+		} catch (Exception e) {
+			e.printStackTrace();
+			result = false;
+		}
+
+		return result;
+	}
+
+}
 
src/back-end/main/java/common/util/socket/SocketReponseManager.java (added)
+++ src/back-end/main/java/common/util/socket/SocketReponseManager.java
@@ -0,0 +1,39 @@
+package common.util.socket;
+
+import common.util.CommonUtil;
+
+import java.net.Socket;
+import java.net.SocketException;
+
+public class SocketReponseManager implements Runnable {
+	
+	private Socket clientSocket = null;
+	
+	private String userIP = null;
+	
+	public SocketReponseManager(Socket clientSocket) {
+		this.clientSocket = clientSocket;
+		this.userIP = clientSocket.getRemoteSocketAddress().toString();
+	}
+	
+	@Override
+	public void run() {
+		SocketManager socketManager = new SocketManager();
+		
+		try {
+			socketManager.response(clientSocket);
+		} catch (SocketException e) {
+			e.printStackTrace();
+			/*로그 생성*/
+			String logMessage = "[" + userIP + "] clientSocket close ??? " + CommonUtil.exceptionToString(e);
+			FileUtil.writeLogFile(logMessage, "socket_log", "./socket_log");
+		} catch (Exception e) {
+			e.printStackTrace();
+			/*로그 생성*/
+			String logMessage = "[" + userIP + "] " + CommonUtil.exceptionToString(e);
+			FileUtil.writeLogFile(logMessage, "socket_log", "./socket_log");
+		}
+		
+	}
+
+}
 
src/back-end/main/java/common/util/socket/message/Body.java (added)
+++ src/back-end/main/java/common/util/socket/message/Body.java
@@ -0,0 +1,19 @@
+package common.util.socket.message;
+
+import common.util.socket.message.vo.Message;
+
+import java.util.List;
+
+public class Body<T extends Message> {
+	
+	private List<T> messageList;
+
+	public List<T> getMessageList() {
+		return messageList;
+	}
+
+	public void setMessageList(List<T> messageList) {
+		this.messageList = messageList;
+	}
+
+}
 
src/back-end/main/java/common/util/socket/message/Header.java (added)
+++ src/back-end/main/java/common/util/socket/message/Header.java
@@ -0,0 +1,24 @@
+package common.util.socket.message;
+
+
+import common.util.socket.message.code.MessageCode;
+
+public class Header {
+	
+	public Header() {}
+	
+	public Header(MessageCode.CommunicationType communicationType) {
+		this.communicationType = communicationType;
+	}
+	
+	private MessageCode.CommunicationType communicationType;
+	
+	public MessageCode.CommunicationType getCommunicationType() {
+		return communicationType;
+	}
+
+	public void setCommunicationType(MessageCode.CommunicationType communicationType) {
+		this.communicationType = communicationType;
+	}
+	
+}
 
src/back-end/main/java/common/util/socket/message/MessageProtocol.java (added)
+++ src/back-end/main/java/common/util/socket/message/MessageProtocol.java
@@ -0,0 +1,32 @@
+package common.util.socket.message;
+
+import common.util.socket.message.code.MessageCode;
+
+public class MessageProtocol {
+
+	public MessageProtocol() {}
+	
+	public MessageProtocol(MessageCode.CommunicationType communicationType) throws Exception {
+		this.header = new Header(communicationType);
+		this.body = new Body<>();
+	}
+	
+	private Header header;
+	
+	private Body body;
+
+	public Header getHeader() {
+		return header;
+	}
+	public void setHeader(Header header) {
+		this.header = header;
+	}
+	
+	public Body getBody() {
+		return body;
+	}
+	public void setBody(Body body) {
+		this.body = body;
+	}
+	
+}
 
src/back-end/main/java/common/util/socket/message/code/MessageCode.java (added)
+++ src/back-end/main/java/common/util/socket/message/code/MessageCode.java
@@ -0,0 +1,83 @@
+package common.util.socket.message.code;
+
+
+import common.util.socket.message.vo.Message;
+import common.util.socket.message.vo.impl.Command;
+import common.util.socket.message.vo.impl.File;
+import common.util.socket.message.vo.impl.Text;
+
+/**
+ * 210317
+ * 최정우
+ * 
+ * Socket통신 시, 필요한 메세지 규약 저장소입니다.
+ */
+public class MessageCode {
+
+	/**
+	 * 210317
+	 * 최정우
+	 * 
+	 * 메세지 전송 타입(요청 OR 응답)
+	 */
+	public enum CommunicationType {
+		REQUEST
+		, RESPONSE;
+	}
+	
+	/**
+	 * 210317
+	 * 최정우
+	 * 
+	 * 통신할 메세지 타입
+	 */
+	public enum MessageType {
+		FILE(File.class)//파일 전송
+		, TEXT(Text.class)//Text 전송
+		, COMMEND(Command.class);//명령어 전송
+		
+		private Class<? extends Message> clazz;
+		
+		private MessageType (Class<? extends Message> clazz) {
+	        this.clazz = clazz;
+	    }
+
+		public Class<? extends Message> getClazz() {
+			return clazz;
+		}
+	}
+	
+	/**
+	 * 210317
+	 * 최정우
+	 * 
+	 * 통신할 메세지 타입
+	 */
+	public enum FileMessageType {
+		IMPORT//파일 가져오기
+		, EXPORT//파일 내보내기
+	}
+	/**
+	 * 210317
+	 * 최정우
+	 * 
+	 * 통신을 할 때, 필요한 구분자  
+	 */
+	public enum MessageFlag {
+		MESSAGE_START
+		, MESSAGE_END
+		
+		, HEAD_START
+		, HEAD_END
+		
+		, BODY_START
+		, BODY_END
+		
+		, FILE_START
+		, FILE_END
+		
+		, SUCCESS
+		, FAIL
+		, ERROR;
+	}
+}
 
src/back-end/main/java/common/util/socket/message/json/MessageDeserializer.java (added)
+++ src/back-end/main/java/common/util/socket/message/json/MessageDeserializer.java
@@ -0,0 +1,72 @@
+package common.util.socket.message.json;
+
+import com.fasterxml.jackson.core.JsonParser;
+import com.fasterxml.jackson.core.JsonProcessingException;
+import com.fasterxml.jackson.core.type.TypeReference;
+import com.fasterxml.jackson.databind.DeserializationContext;
+import com.fasterxml.jackson.databind.JsonNode;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.fasterxml.jackson.databind.deser.std.StdDeserializer;
+import common.util.CommonUtil;
+import common.util.socket.message.code.MessageCode;
+import common.util.socket.message.vo.Message;
+
+import java.io.IOException;
+import java.util.HashMap;
+
+public class MessageDeserializer extends StdDeserializer<Message> {
+
+	private static final long serialVersionUID = 1L;
+	
+	private final ObjectMapper mapper = new ObjectMapper();
+	
+	private final TypeReference<HashMap<String, Object>> typeReferene = new TypeReference<HashMap<String, Object>>(){};
+
+	public MessageDeserializer() {
+		this(null);
+	}
+
+	public MessageDeserializer(Class<?> vc) {
+		super(vc);
+		// TODO Auto-generated constructor stub
+	}
+
+	@Override
+	public Message deserialize(JsonParser jsonParser, DeserializationContext arg1) throws IOException, JsonProcessingException {
+		Message result = null;
+		try {
+			//JsonParser to JsonNode
+			JsonNode node = jsonParser.getCodec().readTree(jsonParser);
+			//System.out.println("node str : " + node.toString());
+			
+			//메세지 타입 문자열 to MessageType (String to Enum)
+			MessageCode.MessageType messageType = MessageCode.MessageType.valueOf(node.get("messageType").asText());
+			//System.out.println("messageType : " + messageType);
+			
+			/*Message 객체 생성*/
+			if (messageType == MessageCode.MessageType.FILE) {//MessageType이 FILE 일 때
+				//FileMessageType 확인
+				MessageCode.FileMessageType fileMessageType = MessageCode.FileMessageType.valueOf(node.get("fileMessageType").asText());
+				//객체 생성시 생성자에 파라메터 값(FileMessageType) 전달
+				result = messageType.getClazz().getDeclaredConstructor(MessageCode.FileMessageType.class).newInstance(fileMessageType);
+			} else {//MessageType이 FILE이외 다른거 일 때
+				//객체 생성
+				result = messageType.getClazz().newInstance();
+			}
+			
+			//json문자열 to HashMap<String, Object>
+			HashMap<String, Object> messageMap = mapper.readValue(node.toString(), typeReferene);
+			
+			//Map(value) -> Message(value) (단, messageType은 제외)
+			String[] ignoreFields = {"messageType"};
+			//Map(value) -> Message(value) (단, messageType은 제외)
+			CommonUtil.objectSetMapValue(result, messageMap, ignoreFields);
+			
+			System.out.println("");
+		} catch (Exception e) {
+			e.printStackTrace();
+		}
+		return result;
+	}
+
+}
 
src/back-end/main/java/common/util/socket/message/vo/Message.java (added)
+++ src/back-end/main/java/common/util/socket/message/vo/Message.java
@@ -0,0 +1,107 @@
+package common.util.socket.message.vo;
+
+
+import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
+import common.util.socket.message.code.MessageCode;
+import common.util.socket.message.json.MessageDeserializer;
+
+/**
+ * 최정우
+ * 210321
+ * 
+ * 최상위 통신 Message 객체
+ */
+@JsonDeserialize(using = MessageDeserializer.class)
+public abstract class Message {
+	
+	/**
+	 * 전송 메세지 타입
+	 */
+	private MessageCode.MessageType messageType;
+	
+	/**
+	 * 메세지 전송 결과
+	 */
+	private boolean result = false;
+	
+	/**
+	 * 메세지 전송 결과
+	 */
+	private String resultMessage = MessageCode.MessageFlag.FAIL.toString();
+	
+	/**
+	 * 최정우
+	 * 210321
+	 * 
+	 * Message동작
+	 */
+	public abstract boolean run() throws Exception;
+	
+	//messageType - get
+	public MessageCode.MessageType getMessageType() {
+		return messageType;
+	}
+	//messageType - set
+	public void setMessageType(MessageCode.MessageType messageType) {
+		this.messageType = messageType;
+	}
+	
+	//result - get
+	public boolean getResult() {
+		return result;
+	}
+	//result - set
+	public void setResult(boolean result) {
+		this.result = result;
+		
+		//동작결과가 true -> SUCCESS
+		if (result == true) {
+			this.resultMessage = MessageCode.MessageFlag.SUCCESS.toString();
+		}
+		//동작결과가 false -> FAIL
+		else {
+			this.resultMessage = MessageCode.MessageFlag.FAIL.toString();
+		}
+	}
+
+	//resultMessage - get
+	public String getResultMessage() {
+		return resultMessage;
+	}
+	//resultMessage - set
+	public void setResultMessage(String resultMessage) {
+		this.resultMessage = resultMessage;
+	}
+	
+	/********** resultMessage 별도 정의 (시작) **********/
+	/**
+	 * MessageFlag를 활용한 resultMessage 정의 
+	 * @param messageFlag
+	 */
+	public void setResultMessageByFlag(MessageCode.MessageFlag messageFlag) {
+		this.resultMessage = messageFlag.toString();
+		
+		//SUCCESS -> 동작결과 true
+		if (messageFlag == MessageCode.MessageFlag.SUCCESS) {
+			this.result = true;
+		}
+		//FAIL -> 동작결과 false
+		else if (messageFlag == MessageCode.MessageFlag.FAIL) {
+			this.result = false;
+		}
+		//SUCCESS, FAIL이외 일때 -> 뭐 없음
+		else {
+			return;
+		}
+	}
+	/**
+	 * Exception를 활용한 resultMessage 정의 
+	 * @param e
+	 */
+	public void setResultMessageByError(Exception e) {
+		//에러메세지 세팅 -> result:false
+		this.resultMessage = MessageCode.MessageFlag.ERROR.toString() + " : " + e.getMessage();
+		this.result = false;
+	}
+	/********** resultMessage 별도 정의 (종료) **********/
+}
 
src/back-end/main/java/common/util/socket/message/vo/impl/Command.java (added)
+++ src/back-end/main/java/common/util/socket/message/vo/impl/Command.java
@@ -0,0 +1,151 @@
+package common.util.socket.message.vo.impl;
+
+import common.util.socket.FileUtil;
+import common.util.socket.message.code.MessageCode;
+import common.util.socket.message.vo.Message;
+
+import java.io.BufferedReader;
+import java.io.InputStreamReader;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.concurrent.TimeUnit;
+
+/**
+ * 210320
+ * 최정우
+ * 
+ * 소켓통신을 통해 명령어 전송을 위한 Message객체 입니다.
+ */
+//public class Command implements MessageInterface {
+public class Command extends Message {
+	
+	//명령어 최대 실행 시간(초)
+	public static int COMMAND_TIMEOUT_SECONDS = 10;
+	
+	public Command () {
+		super.setMessageType(MessageCode.MessageType.COMMEND);
+	}
+	
+	public Command (String command) {
+		super.setMessageType(MessageCode.MessageType.COMMEND);
+		
+		this.command = command;
+	}
+	
+	private String command;
+	
+	private List<String> commandResult;
+
+	public String getCommand() {
+		return command;
+	}
+	public void setCommand(String command) {
+		this.command = command;
+	}
+
+	public List<String> getCommandResult() {
+		return commandResult;
+	}
+	public void setCommandResult(List<String> commandResult) {
+		this.commandResult = commandResult;
+	}
+
+	/**
+	 * 210320
+	 * 최정우
+	 * 
+	 * 명령어 실행
+	 */
+	@Override
+	public boolean run() throws Exception {
+		/** run() 메소드의 동작 결과 정의 (필수 변수)**/
+		boolean result = false;
+		
+		/*************** [명령어 처리 준비] JAVA(JVM) -> OS ***************/
+        /*
+         * 명령어 준비
+         * 
+         * Window : cmd.exe /C [명령어] (명령어 수행 완료후 cmd.exe 종료)
+         * Linux : /bin/sh -c [명렁어] (명령어 수행 완료후 shell 종료)
+         */
+        String[] commend = {"", "", this.command};
+        if (System.getProperty("os.name").indexOf("Windows") > -1) {
+        	commend[0] = "cmd.exe";
+        	commend[1] = "/C"; 
+        } else {
+        	commend[0] = "/bin/sh";
+        	commend[1] = "-c";
+        }//명령어 준비 끝
+        
+        
+        /*************** [명령어 수행] JAVA(JVM) -> OS ***************/
+        //Runtime객체 : 운영체제 기반의 프로그램을 실행시키거나 운영체제에 대한 정보를 제공
+        //Process객체 : JVM 메모리에 올라와서 업무 처리를 수행할 객체 
+        Process process = Runtime.getRuntime().exec(commend);
+        
+        /*로그 생성*/
+		String logMessage = "COMMAND : " + this.command;
+		FileUtil.writeLogFile(logMessage, "socket_log", "./socket_log");
+        
+        /*************** 업무처리가 완료 될 때 까지 기다림 ***************/
+        //COMMAND_TIMEOUT_SECONDS안에 업무처리가 완료 될 때 까지 기다림(+수행 처리 시간 받기)
+		//int execTime = process.waitFor();
+        boolean isComplete = process.waitFor(COMMAND_TIMEOUT_SECONDS, TimeUnit.SECONDS);
+        System.out.println("isComplete : " + isComplete);
+        
+        /*************** [명령어 수행 결과 받을 준비 / 수행 결과 담기] OS -> JAVA(JVM) ***************/
+        commandResult = new ArrayList<String>();
+        
+        BufferedReader resultBufferReader = null;
+        BufferedReader errorBufferReader = null;
+        if (isComplete == true) {
+        	 resultBufferReader = new BufferedReader(new InputStreamReader(process.getInputStream(), "EUC-KR"));
+             String msg = null;
+             while ((msg = resultBufferReader.readLine()) != null) {
+             	if (msg.contains(System.getProperty("line.separator")) == false) {
+             		msg += System.getProperty("line.separator");
+             	}
+             	commandResult.add(msg);
+             }
+             errorBufferReader = new BufferedReader(new InputStreamReader(process.getErrorStream(), "EUC-KR"));
+             int err_count = 0;
+             while ((msg = errorBufferReader.readLine()) != null) {
+             	if (err_count++ == 0) {
+             		commandResult.add("================ [Error] ================" + System.getProperty("line.separator"));
+             	}
+             	
+             	if (msg.contains(System.getProperty("line.separator")) == false) {
+             		msg += System.getProperty("line.separator");
+             	}
+             	commandResult.add(msg);
+             }
+        } else {
+        	commandResult.add("COMMAND : " + this.command + " - Timeout(" + COMMAND_TIMEOUT_SECONDS + "초)");
+        }
+        
+		/*************** 클라이언트에게 명령어 수행 결과 메세지 전송 ***************/
+        // 서버에서 클라이언트로 메세지 보내기
+        if (isComplete && process.exitValue() == 0) {
+        	//commandResult.add("[" + (execTime / 1000.0) + "초 Ok]");
+        	commandResult.add(MessageCode.MessageFlag.SUCCESS.toString());
+        	/** 결과 담기 **/
+        	result = true;
+        } else {
+        	//commandResult.add("[" + (execTime / 1000.0) + "초 Error]");
+        	commandResult.add(MessageCode.MessageFlag.FAIL.toString());
+        	/** 결과 담기 **/
+        	result = false;
+        }
+        
+		if (resultBufferReader != null) resultBufferReader.close();
+		if (errorBufferReader != null) errorBufferReader.close();
+		if (process != null) process.destroy();
+		
+		for (int i = 0; i < commandResult.size(); i++) {
+			System.out.println("result : " + commandResult.get(i));
+		}
+		
+		return result;
+	}
+
+}
 
src/back-end/main/java/common/util/socket/message/vo/impl/File.java (added)
+++ src/back-end/main/java/common/util/socket/message/vo/impl/File.java
@@ -0,0 +1,316 @@
+package common.util.socket.message.vo.impl;
+
+import common.util.StringUtil;
+import common.util.socket.FileUtil;
+import common.util.socket.message.code.MessageCode;
+import common.util.socket.message.vo.Message;
+
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+
+/**
+ * 210320
+ * 최정우
+ * 
+ * 소켓통신을 통해 파일 전송을 위한 Message객체 입니다.
+ */
+//public class File implements MessageInterface {
+public class File extends Message {
+	
+	public File (MessageCode.FileMessageType fileMessageType) {
+		super.setMessageType(MessageCode.MessageType.FILE);
+		
+		this.newFilePath = "./";
+		
+		this.fileMessageType = fileMessageType;
+	}
+	
+	
+	public File (MessageCode.FileMessageType fileMessageType, String originFileName, String originFilePath) {
+		super.setMessageType(MessageCode.MessageType.FILE);
+		
+		this.originFileName = originFileName;
+		this.originFilePath = originFilePath;
+		this.newFileName = originFileName;
+		this.newFilePath = "./";
+		
+		this.fileMessageType = fileMessageType;
+	}
+	
+	public File (MessageCode.FileMessageType fileMessageType, String originFileName, String originFilePath, String newFileName, String newFilePath) {
+		super.setMessageType(MessageCode.MessageType.FILE);
+		
+		this.originFileName = originFileName;
+		this.originFilePath = originFilePath;
+		this.newFileName = newFileName;
+		this.newFilePath = newFilePath;
+		
+		this.fileMessageType = fileMessageType;
+	}
+	
+	/**
+	 * 원본 파일명 (확장자까지 포함)
+	 */
+	private String originFileName;
+	
+	/**
+	 * 원본 파일경로 (절대경로)
+	 */	
+	private String originFilePath;
+	
+	/**
+	 * 원본 파일 binary
+	 */	
+	private String originFileBinary;
+	
+	/**
+	 * 새로운 파일명 (확장자까지 포함)
+	 */	
+	private String newFileName;
+	
+	/**
+	 * 새로운 파일경로 (절대경로)
+	 */	
+	private String newFilePath;
+	
+	/**
+	 * 파일 크기
+	 */
+	private long fileLength;
+	
+	/**
+	 * 파일 전송 타입(가지고오기, 내보내기)
+	 */
+	private MessageCode.FileMessageType fileMessageType;
+	
+	/**
+	 * 이미지 파일 리사이징 완료 여부 (default:false)
+	 */
+	private boolean resizingComplete = false;
+
+	public String getOriginFileName() {
+		return originFileName;
+	}
+	public void setOriginFileName(String originFileName) {
+		this.originFileName = originFileName;
+	}
+
+	public String getOriginFilePath() {
+		return originFilePath;
+	}
+	public void setOriginFilePath(String originFilePath) {
+		this.originFilePath = originFilePath;
+	}
+
+	public String getOriginFileBinary() {
+		return originFileBinary;
+	}
+	public void setOriginFileBinary(String originFileBinary) {
+		this.originFileBinary = originFileBinary;
+	}
+
+	public String getNewFileName() {
+		return newFileName;
+	}
+	public void setNewFileName(String newFileName) {
+		this.newFileName = newFileName;
+	}
+
+	public String getNewFilePath() {
+		return newFilePath;
+	}
+	public void setNewFilePath(String newFilePath) {
+		this.newFilePath = newFilePath;
+	}
+
+	public long getFileLength() {
+		return fileLength;
+	}
+	public void setFileLength(long fileLength) {
+		this.fileLength = fileLength;
+	}
+
+	public MessageCode.FileMessageType getFileMessageType() {
+		return fileMessageType;
+	}
+
+	public void setFileMessageType(MessageCode.FileMessageType fileMessageType) {
+		this.fileMessageType = fileMessageType;
+	}
+
+	public boolean getResizingComplete() {
+		return resizingComplete;
+	}
+
+
+	public void setResizingComplete(boolean resizingComplete) {
+		this.resizingComplete = resizingComplete;
+	}
+
+
+	/**
+	 * 210320
+	 * 최정우
+	 * 
+	 * file정보를 활용하여 Binary로 만들기
+	 */
+	public boolean fileToBinary() throws Exception {
+		
+		boolean result = false;
+		
+		// 원본 파일명 체크
+		if (StringUtil.isEmpty(this.originFileName) == true) {
+			throw new Exception("파일명이 없음");
+		}
+		// 원본 파일경로 체크
+		if (StringUtil.isEmpty(this.originFilePath) == true) {
+			throw new Exception("파일 경로가 없음");
+		}
+
+		// 원본 파일 메모리에 생성
+		System.out.println(this.originFilePath + java.io.File.separator + this.originFileName);
+		java.io.File file = new java.io.File(this.originFilePath + java.io.File.separator + this.originFileName);
+		
+		// 원본 파일 존재하는지 확인
+		if (file.exists() == false) {
+			throw new Exception("파일이 존재하지 않음");
+		}
+		// 원본 파일인지 아닌지 확인
+		if (file.isFile() == false) {
+			throw new Exception("파일이 아님");
+		}
+		
+		// 원본 파일크기 세팅
+		this.fileLength = file.length();
+
+		// 새로운 파일명이 없을 때, 원본 파일명 넣기
+		if (StringUtil.isEmpty(this.newFileName) == true) {
+			this.newFileName = this.originFileName;
+		}
+		// 새로운 파일경로가 없을 때, 소켓 서버의 디렉토리 경로 넣기
+		if (StringUtil.isEmpty(this.newFilePath) == true) {
+			this.newFilePath = ".";//현재 디렉토리
+		}
+		
+		FileInputStream fileInput = null;
+		try {
+			//이미지 파일에대한 유무
+			boolean isImageFile = FileUtil.isImageFile(file);
+			
+			//파일 byte를 담을 공간
+			byte[] bytes = null;
+			
+			//이미지 파일일 때, 축소
+			if (FileUtil.IMAGE_FILE_RESIZING && isImageFile == true) {
+				bytes = FileUtil.imageFileResizeToByte(file);
+			} else {//이미지 파일이 아닐 때
+				bytes = FileUtil.fileToByte(file);
+			}
+			
+			// bytes -> String
+			this.originFileBinary = new String(FileUtil.base64Encoding(bytes)); 
+			/*처리 결과*/
+			result = true;
+		} catch (Exception e) {
+			throw new Exception(e);
+		} finally {
+			if (fileInput != null)
+				fileInput.close();
+		}
+		
+		return result;
+	}
+	
+	/**
+	 * 210320
+	 * 최정우
+	 * 
+	 * Binary로 파일 만들기
+	 */
+	public boolean binaryToFile() throws Exception {
+		
+		boolean result = false;
+		
+		// 생성할 파일명 체크
+		if (StringUtil.isEmpty(this.newFileName) == true) {
+			throw new Exception("저장할 파일명이 없음");
+		}
+		// 생성할 파일경로 체크
+		if (StringUtil.isEmpty(this.newFilePath) == true) {
+			this.newFilePath = ".";//현재 디렉토리
+		}
+		
+		FileOutputStream fileOutput = null;
+		try {
+			// 생성할 파일의 폴더 생성
+			java.io.File path = new java.io.File(this.newFilePath); 
+			if (path.exists() == false || path.isDirectory() == false) {
+				path.mkdir();
+			}
+			// 파일 최종 경로 (파일 디렉토리 + 파일명)
+			String fileFullPath = this.newFilePath + java.io.File.separator + this.newFileName;
+			// 파일 읽을 줄비
+			fileOutput = new FileOutputStream(fileFullPath);
+			// String -> byte -> 파일
+			fileOutput.write(FileUtil.base64Decoding(this.originFileBinary.getBytes()));
+			
+			// 바이너리 비우기
+			this.originFileBinary = null;
+			
+			/*처리 결과*/
+			result = true;
+		} finally {
+			if (fileOutput != null)
+				fileOutput.close();
+		}
+		
+		return result;
+	}
+	
+	/**
+	 * 210320
+	 * 최정우
+	 * 
+	 * MessageType:FILE_IMPORT(파일 가져오기)
+	 *  1. fileToBinary() 메소드를 활용하여 [파일 객체 -> Binary로 변형]
+	 *  (단, originFileName, originFilePath 필수) 
+	 *  끝
+	 * 
+	 * MessageType:FILE_EXPORT(파일 내보내기)
+	 *  1. binaryToFile() 메소드를 활용하여 [Binary -> 파일 객체 생성]
+	 *  (단, newFileName, newFilePath, originFileBinary 필수)
+	 *  끝
+	 */
+	@Override
+	public boolean run() throws Exception {
+		/** run() 메소드의 동작 결과 정의 (필수 변수)**/
+		boolean result = false;
+		
+		if (this.fileMessageType == MessageCode.FileMessageType.IMPORT) {
+			//파일 객체 -> Binary
+			result = fileToBinary();
+			
+			/*로그 생성*/
+			String logMessage = fileMessageType.toString() + " - ";
+			logMessage += "originFileName:" + originFilePath + "/" + originFileName;
+			logMessage += ", newFile:" + newFilePath + "/" + newFileName;
+			logMessage += ", result:" + result;
+			FileUtil.writeLogFile(logMessage, "socket_log", "./socket_log");
+		} else if (this.fileMessageType == MessageCode.FileMessageType.EXPORT) {
+			//Binary -> 파일 객체
+			result = binaryToFile();
+			
+			/*로그 생성*/
+			String logMessage = fileMessageType.toString() + " - ";
+			logMessage += "originFileName:" + originFilePath + "/" + originFileName;
+			logMessage += ", newFile:" + newFilePath + "/" + newFileName;
+			logMessage += ", result:" + result;
+			FileUtil.writeLogFile(logMessage, "socket_log", "./socket_log");
+		} else {
+			throw new Exception("FileMessageType이 Null이거나 잘못되었습니다.");
+		}
+		
+		return result;
+	}
+	
+}
 
src/back-end/main/java/common/util/socket/message/vo/impl/Text.java (added)
+++ src/back-end/main/java/common/util/socket/message/vo/impl/Text.java
@@ -0,0 +1,55 @@
+package common.util.socket.message.vo.impl;
+
+import common.util.StringUtil;
+import common.util.socket.message.code.MessageCode;
+import common.util.socket.message.vo.Message;
+
+/**
+ * 210320
+ * 최정우
+ * 
+ * 소켓통신을 통해 문자 전송을 위한 Message객체 입니다.
+ */
+//public class Text implements MessageInterface {
+public class Text extends Message {
+	
+	public Text () {
+		super.setMessageType(MessageCode.MessageType.TEXT);
+	}
+	
+	public Text (String text) {
+		super.setMessageType(MessageCode.MessageType.TEXT);
+		
+		this.text = text;
+	}
+	
+	private String text;
+
+	public String getText() {
+		return text;
+	}
+	public void setText(String text) {
+		this.text = text;
+	}
+
+	/**
+	 * 210320
+	 * 최정우
+	 * 
+	 * 문자 콘솔에 찍기
+	 */
+	@Override
+	public boolean run() throws Exception {
+		/** run() 메소드의 동작 결과 정의 (필수 변수)**/
+		boolean result = false;
+		
+		System.out.println("text : " + text);
+		if (StringUtil.isEmpty(text) == false) {
+			result = true;
+		} else {
+			result = false;
+		}
+		
+		return result;
+	}
+}
 
src/back-end/main/java/common/vo/CheckMessage.java (added)
+++ src/back-end/main/java/common/vo/CheckMessage.java
@@ -0,0 +1,89 @@
+package common.vo;
+
+/**
+ * @author 최정우
+ * @since 2019.11.14
+ *
+ * 데이터 체크, 유효성 검사 등과 같이 검사와 관련된 변수를 정의한 Class 입니다.
+ */
+public class CheckMessage {
+
+	public CheckMessage() {}
+
+	public CheckMessage(boolean isSuccess) {
+		this.isSuccess = isSuccess;
+	}
+
+	public CheckMessage(String message) {
+		this.message = message;
+	}
+
+	public CheckMessage(boolean isSuccess, String message) {
+		this.isSuccess = isSuccess;
+		this.message = message;
+	}
+
+	public CheckMessage(boolean isSuccess, String message, int status) {
+		this.isSuccess = isSuccess;
+		this.message = message;
+		this.status = status;
+	}
+
+	public CheckMessage(boolean isSuccess, String message, String error) {
+		this.isSuccess = isSuccess;
+		this.message = message;
+		this.error = error;
+	}
+
+	/**
+	 * 체크 완료(사용가능 or 성공) 여부
+	 */
+	private boolean isSuccess;
+
+	/**
+	 * 체크한 상태의 메세지값
+	 */
+	private String message;
+
+	/**
+	 * 에러 메세지
+	 */
+	private String error;
+
+	/**
+	 * 체크한 상태의 상태값 -> 상황마다 다름
+	 */
+	private int status;
+
+	public boolean getIsSuccess() {
+		return isSuccess;
+	}
+
+	public void setIsSuccess(boolean isSuccess) {
+		this.isSuccess = isSuccess;
+	}
+
+	public String getMessage() {
+		return message;
+	}
+
+	public void setMessage(String message) {
+		this.message = message;
+	}
+
+	public String getError() {
+		return error;
+	}
+
+	public void setError(String error) {
+		this.error = error;
+	}
+
+	public int getStatus() {
+		return status;
+	}
+
+	public void setStatus(int status) {
+		this.status = status;
+	}
+}
 
src/back-end/main/java/common/vo/CommonFile.java (added)
+++ src/back-end/main/java/common/vo/CommonFile.java
@@ -0,0 +1,308 @@
+package common.vo;
+
+import java.io.File;
+import java.util.Arrays;
+import java.util.List;
+
+/**
+ * @author 최정우
+ * @since 2019.11.24
+ *
+ * File 관리 Domain 입니다.
+ */
+public class CommonFile extends Search {
+
+	public CommonFile() {};
+
+	public CommonFile(String commonFileGroupId) {
+		this.commonFileGroupId = commonFileGroupId;
+	};
+
+	public CommonFile(long commonFileSeq) {
+		this.commonFileSeq = commonFileSeq;
+	};
+
+	public CommonFile(String commonFileGroupId, long commonFileSeq) {
+		this.commonFileGroupId = commonFileGroupId;
+		this.commonFileSeq = commonFileSeq;
+	};
+
+	public CommonFile(FileType fileType) {
+		this.fileType = fileType;
+	};
+
+	public CommonFile(String commonFileGroupId, FileType fileType) {
+		this.commonFileGroupId = commonFileGroupId;
+		this.fileType = fileType;
+	};
+
+	/**
+	 * 파일 관리 아이디
+	 */
+	private String commonFileGroupId;
+
+	/**
+	 * 파일 SEQ
+	 */
+	private long commonFileSeq;
+
+	/**
+	 * 원본 파일명
+	 */
+	private String fileOriginName;
+
+	/**
+	 * 마스크킹 처리된 파일명
+	 */
+	private String fileMaskName;
+
+	/**
+	 * 파일 확장자.
+	 */
+	private String fileExtension;
+
+	/**
+	 * 파일 사이즈.
+	 */
+	private long fileSize;
+
+	/**
+	 * 파일 상대 경로
+	 */
+	private String fileRelativePath;
+
+	/**
+	 * 파일 절대 경로
+	 */
+	private String fileAbsolutePath;
+
+	/**
+	 * 파일 등록자
+	 */
+	private String fileInsertUserId;
+
+	/**
+	 * 파일 등록자 이름
+	 */
+	private String fileInsertUserName;
+
+	/**
+	 * 파일 등록일시
+	 */
+	private String fileInsertDatetime;
+
+
+
+	/**
+	 * 파일 다운로드 횟수
+	 */
+	private long fileDownloadCount;
+
+	/**
+	 * 파일 타입
+	 */
+	private FileType fileType = FileType.ALL_FILE;
+
+	/**
+	 * 파일 상태
+	 */
+	private FileStatus fileStatus = FileStatus.COMPLETE_INSERT;
+
+	/**
+	 * file 관련 메세지
+	 */
+	private CheckMessage checkMessage = new CheckMessage();
+
+
+
+	public String getCommonFileGroupId() {
+		return commonFileGroupId;
+	}
+
+	public void setCommonFileGroupId(String commonFileGroupId) {
+		this.commonFileGroupId = commonFileGroupId;
+	}
+
+	public long getCommonFileSeq() {
+		return commonFileSeq;
+	}
+
+	public void setCommonFileSeq(long commonFileSeq) {
+		this.commonFileSeq = commonFileSeq;
+	}
+
+	public String getFileOriginName() {
+		return fileOriginName;
+	}
+
+	public void setFileOriginName(String fileOriginName) {
+		this.fileOriginName = fileOriginName;
+	}
+
+	public String getFileMaskName() {
+		return fileMaskName;
+	}
+
+	public void setFileMaskName(String fileMaskName) {
+		this.fileMaskName = fileMaskName;
+	}
+
+	public String getFileExtension() {
+		return fileExtension;
+	}
+
+	public void setFileExtension(String fileExtension) {
+		this.fileExtension = fileExtension;
+	}
+
+	public long getFileSize() {
+		return fileSize;
+	}
+
+	public void setFileSize(long fileSize) {
+		this.fileSize = fileSize;
+	}
+
+	public String getFileRelativePath() {
+		return fileRelativePath;
+	}
+
+	public void setFileRelativePath(String fileRelativePath) {
+		this.fileRelativePath = fileRelativePath;
+	}
+
+	public String getFileAbsolutePath() {
+		return fileAbsolutePath;
+	}
+
+	public void setFileAbsolutePath(String fileAbsolutePath) {
+		this.fileAbsolutePath = fileAbsolutePath;
+	}
+
+	public String getFileInsertUserId() {
+		return fileInsertUserId;
+	}
+
+	public void setFileInsertUserId(String fileInsertUserId) {
+		this.fileInsertUserId = fileInsertUserId;
+	}
+
+	public String getFileInsertUserName() {
+		return fileInsertUserName;
+	}
+
+	public void setFileInsertUserName(String fileInsertUserName) {
+		this.fileInsertUserName = fileInsertUserName;
+	}
+
+	public String getFileInsertDatetime() {
+		return fileInsertDatetime;
+	}
+
+	public void setFileInsertDatetime(String fileInsertDatetime) {
+		this.fileInsertDatetime = fileInsertDatetime;
+	}
+
+	public long getFileDownloadCount() {
+		return fileDownloadCount;
+	}
+
+	public void setFileDownloadCount(long fileDownloadCount) {
+		this.fileDownloadCount = fileDownloadCount;
+	}
+
+	public FileStatus getFileStatus() {
+		return fileStatus;
+	}
+
+	public void setFileStatus(FileStatus fileStatus) {
+		this.fileStatus = fileStatus;
+	}
+
+	public FileType getFileType() {
+		return fileType;
+	}
+
+	public void setFileType(FileType fileType) {
+		this.fileType = fileType;
+	}
+
+	public CheckMessage getCheckMessage() {
+		return checkMessage;
+	}
+
+	public void setCheckMessage(CheckMessage checkMessage) {
+		this.checkMessage = checkMessage;
+	}
+
+
+
+	/**
+	 * @author 최정우
+	 * @since 2021.10.21
+	 *
+	 * 파일 등록 및 삭제 과정에 필요한 상태 값을 정의한 상수 Class 입니다.
+	 * 'DB등록 전', 'DB등록 완료', 'DB삭제 전' 순서입니다.
+	 */
+	public enum FileStatus {
+		BEFORE_INSERT("DB등록 전")
+		, COMPLETE_INSERT("DB등록 완료")
+		, BEFORE_DELETE("DB삭제 전");
+
+		private FileStatus (String status) {
+			this.status = status;
+		}
+
+		/**
+		 * 한글값
+		 */
+		final private String status;
+
+		/**
+		 * 한글값 조회
+		 */
+		public String getValue () {
+			return status;
+		}
+	}
+
+	/**
+	 * @author 최정우
+	 * @since 2019.11.13
+	 *
+	 * 등록되는 파일 타입과, 해당 파일 타입의 등록가능한 확장자를 정의한 상수 Class 입니다.
+	 * 첨부파일, 이미지파일, 데이터 셋 파일 순서입니다.
+	 */
+	public enum FileType {
+		ALL_FILE(Arrays.asList("bmp","jpg","gif","png","jpeg","bmp","wma","avi","wav","mp3","mp4","mpeg","wmv","asf","pdf","ppt","pptx","docx","xls","xlsx","csv","hwp","txt","doc","zip", "json", "xml"))
+		, IMG_FILE(Arrays.asList("bmp","jpg","gif","png","jpeg"))
+		, DATASET_FILE(Arrays.asList("xls","xlsx","csv"))
+		, DATA_FILE(Arrays.asList("xls","xlsx"));
+
+		private FileType(List<String> extensions) { this.extensions = extensions;
+		}
+
+		/**
+		 * 확장자 목록
+		 */
+		final private List<String> extensions;
+
+		/**
+		 * 확장자 목록 조회
+		 */
+		public List<String> getExtensions () {
+			return extensions;
+		}
+	}
+
+	/**
+	 * @author 최정우
+	 * @since 2019.11.13
+	 *
+	 * 확장자를 포함한 파일 Full 경로 (fileAbsolutePath + '/' + fileMaskName + '.' + fileExtension)
+	 *
+	 */
+	public String getFileFullPath() {
+		return this.fileAbsolutePath + File.separator + this.fileMaskName + "." + this.fileExtension;
+	}
+}
 
src/back-end/main/java/common/vo/CommonValueObject.java (added)
+++ src/back-end/main/java/common/vo/CommonValueObject.java
@@ -0,0 +1,197 @@
+package common.vo;
+
+import common.util.CryptoUtil;
+
+import java.security.PrivateKey;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.LinkedHashMap;
+import java.util.List;
+
+/**
+ * @author 최정우
+ * @since 2021.09.28
+ *
+ * 공통 Value Object
+ *
+ * Object or List 데이터 활용시, 사용 (int, String, boolean... 등에는 사용할 필요 없음)
+ */
+public class CommonValueObject {
+
+	public final static String DEFAULT_FILE_GROUP_NAME = "commonFileList";
+
+
+	/**
+	 * 검색 객체
+	 */
+	private Search search = new Search();
+
+	/**
+	 * object Data 객체
+	 *
+	 * 활용 방법 (규칙이니까 꼭 치키세요)
+	 *
+	 * 1. 단일 등록(Insert)
+	 * 2. 단일 수정(Update)
+	 * 3. 단일 삭제(Delete)
+	 * 4. 상세 조회(SelectOne)
+	 *
+	 * 위의 경우를 제외하고 사용하면 안됨
+	 */
+	private LinkedHashMap<String, Object> data = new LinkedHashMap<String, Object>();
+
+	/**
+	 * list Data 객체
+	 *
+	 * 1. 다중 등록(Muliple Insert)
+	 * 2. 다중 수정(Muliple Update)
+	 * 3. 다중 삭제(Muliple Delete)
+	 * 4. 목록 조회(SelectList)
+	 */
+	private List<LinkedHashMap<String, Object>> dataList = new ArrayList<LinkedHashMap<String, Object>>();
+
+	/**
+	 * 암호화 대상 Key's
+	 *
+	 * data, dataList에 사용
+	 */
+	private List<String> encodingTargetKeys = new ArrayList<String>();
+
+
+	/**
+	 * 공통 파일을 담을 객체
+	 *
+	 */
+	private HashMap<String, List<CommonFile>> commonFileGroup = new HashMap<String, List<CommonFile>>();
+
+	/**
+	 * 메세지
+	 */
+	private CheckMessage checkMessage = new CheckMessage();
+
+	public Search getSearch() {
+		return search;
+	}
+
+	public void setSearch(Search search) {
+		this.search = search;
+	}
+
+	public LinkedHashMap<String, Object> getData() {
+		return data;
+	}
+
+	public void setData(LinkedHashMap<String, Object> data) {
+		this.data = data;
+	}
+
+	public List<LinkedHashMap<String, Object>> getDataList() {
+		return dataList;
+	}
+
+	public void setDataList(List<LinkedHashMap<String, Object>> dataList) {
+		this.dataList = dataList;
+	}
+
+	public List<String> getEncodingTargetKeys() {
+		return encodingTargetKeys;
+	}
+
+	public void setEncodingTargetKeys(List<String> encodingTargetKeys) {
+		this.encodingTargetKeys = encodingTargetKeys;
+	}
+
+	public HashMap<String, List<CommonFile>> getCommonFileGroup() {
+		if (commonFileGroup.get(DEFAULT_FILE_GROUP_NAME) == null) {
+			commonFileGroup.put(DEFAULT_FILE_GROUP_NAME, new ArrayList<CommonFile>(1));
+		}
+		return commonFileGroup;
+	}
+
+	public void setCommonFileGroup(HashMap<String, List<CommonFile>> commonFileGroup) {
+		this.commonFileGroup = commonFileGroup;
+	}
+
+	public CheckMessage getCheckMessage() {
+		return checkMessage;
+	}
+
+	public void setCheckMessage(CheckMessage checkMessage) {
+		this.checkMessage = checkMessage;
+	}
+
+	/**
+	 * @author 최정우
+	 * @since 2021.11.10
+	 *
+	 * RSA 암호화 디코딩 (data)
+	 */
+	public void dataDecodingByRsa () {
+		//session in RSA 개인키 (조회이후 session에서 암호화 Key 삭제)
+		PrivateKey privateKey = CryptoUtil.getPrivateKeyInSession();
+		//데이터 복호화 (RSA 비대칭키 암호화 활용)
+		for (int i = 0; i < this.encodingTargetKeys.size(); i++) {
+			String key = this.encodingTargetKeys.get(i);//암호화 대상 Key
+			String encodingValue = (String) this.data.get(key);//암호화된 값
+			String decodingValue = null;
+			try {
+				decodingValue = CryptoUtil.decodingByRsa(encodingValue, privateKey);//복호화된 값
+			} catch (Exception e) {
+				decodingValue = encodingValue;
+				e.printStackTrace();
+			}
+			//System.out.println("key: " + key + ", encodingValue: " + encodingValue + ", decodingValue: " + decodingValue);
+			this.data.put(key, decodingValue);//복호화된 값 set
+		}
+	}
+
+	/**
+	 * @author 최정우
+	 * @since 2021.11.10
+	 *
+	 * RSA 암호화 디코딩 (dataList)
+	 */
+	public void dataListDecodingByRsa () {
+		//session in RSA 개인키 (조회이후 session에서 암호화 Key 삭제)
+		PrivateKey privateKey = CryptoUtil.getPrivateKeyInSession();
+		//데이터 복호화 (RSA 비대칭키 암호화 활용)
+		for (int i = 0; i < this.dataList.size(); i++) {
+			for (int j = 0; j < this.encodingTargetKeys.size(); j++) {
+				String key = this.encodingTargetKeys.get(j);//암호화 대상 Key
+				String encodingValue = (String) this.dataList.get(i).get(key);//암호화된 값
+				String decodingValue = null;
+				try {
+					decodingValue = CryptoUtil.decodingByRsa(encodingValue, privateKey);//복호화된 값
+				} catch (Exception e) {
+					decodingValue = encodingValue;
+					e.printStackTrace();
+				}
+				//System.out.println("key: " + key + ", encodingValue: " + encodingValue + ", decodingValue: " + decodingValue);
+				this.dataList.get(i).put(key, decodingValue);//복호화된 값 set
+			}
+		}
+	}
+
+	/**
+	 * @author 최정우
+	 * @since 2021.11.10
+	 *
+	 * XSS 공격 방지
+	 *
+	 */
+	public void htmlFilter (Object targetObject, Class<?> targetObjectClass) {
+
+	}
+
+	/**
+	 * @author 최정우
+	 * @since 2021.11.10
+	 *
+	 * SQL Injection 공격 방지
+	 *
+	 */
+	public void sqlFilter (Object targetObject, Class<?> targetObjectClass) {
+
+	}
+
+}
 
src/back-end/main/java/common/vo/CommonValueObject_back.java (added)
+++ src/back-end/main/java/common/vo/CommonValueObject_back.java
@@ -0,0 +1,164 @@
+package common.vo;
+
+import java.util.LinkedHashMap;
+import java.util.Map;
+
+/**
+ * @author 최정우
+ * @since 2021.09.28
+ * 
+ * 공통 Value Object
+ */
+public class CommonValueObject_back extends LinkedHashMap<String, Object> {
+
+	/**
+	 * Search객체 생성 여부 (Defalut:true)
+	 */
+	private boolean isSearchCreate = true;
+	
+	/**
+     * Constructs an empty insertion-ordered {@code LinkedHashMap} instance
+     * with the specified initial capacity and load factor.
+     *
+     * @param  initialCapacity the initial capacity
+     * @param  loadFactor      the load factor
+     * @throws IllegalArgumentException if the initial capacity is negative
+     *         or the load factor is nonpositive
+     */
+    public CommonValueObject_back(int initialCapacity, float loadFactor) {
+        super(initialCapacity, loadFactor);
+        init();
+    }
+
+    /**
+     * Constructs an empty insertion-ordered {@code LinkedHashMap} instance
+     * with the specified initial capacity and a default load factor (0.75).
+     *
+     * @param  initialCapacity the initial capacity
+     * @throws IllegalArgumentException if the initial capacity is negative
+     */
+    public CommonValueObject_back(int initialCapacity) {
+        super(initialCapacity);
+        init();
+    }
+
+    /**
+     * Constructs an empty insertion-ordered {@code LinkedHashMap} instance
+     * with the default initial capacity (16) and load factor (0.75).
+     */
+    public CommonValueObject_back() {
+        super();
+        init();
+    }
+    
+    /**
+     * 커스텀
+     */
+    public CommonValueObject_back(boolean isSearchCreate) {
+        super();
+        
+        this.isSearchCreate = isSearchCreate;
+        init();
+    }
+
+    /**
+     * Constructs an insertion-ordered {@code LinkedHashMap} instance with
+     * the same mappings as the specified map.  The {@code LinkedHashMap}
+     * instance is created with a default load factor (0.75) and an initial
+     * capacity sufficient to hold the mappings in the specified map.
+     *
+     * @param  m the map whose mappings are to be placed in this map
+     * @throws NullPointerException if the specified map is null
+     */
+    public CommonValueObject_back(Map<String, Object> m) {
+        super();
+        init();
+    }
+    
+    /**
+     * Constructs an empty {@code LinkedHashMap} instance with the
+     * specified initial capacity, load factor and ordering mode.
+     *
+     * @param  initialCapacity the initial capacity
+     * @param  loadFactor      the load factor
+     * @param  accessOrder     the ordering mode - {@code true} for
+     *         access-order, {@code false} for insertion-order
+     * @throws IllegalArgumentException if the initial capacity is negative
+     *         or the load factor is nonpositive
+     */
+    public CommonValueObject_back(int initialCapacity, float loadFactor, boolean accessOrder) {
+        super(initialCapacity, loadFactor);
+        init();
+    }
+    
+    
+    
+    
+    
+    /** 
+	 * CommonValueObject 초기화 (Search 객체 생성)
+	 */
+    public void init () {
+    	if (this.isSearchCreate == true) {
+        	super.put((String) "search", (Object) new Search());
+    	} else {
+    		return;
+    	}
+    }
+    
+    
+    
+    /** 
+	 * 검색 목록에 데이터 추가하기
+	 * 
+	 * @param column : 검색 컬럼명
+	 * @param keyword : 검색어
+	 */
+	public void addSearchCondition (String column, String keyword) throws Exception {
+		Search search = (Search) super.get("search");
+		search.addSearchCondition(column, keyword);
+		super.put("search", search);
+	}
+	
+	/** 
+	 * 검색 목록에 데이터 추가하기
+	 * 
+	 * @param column : 검색 컬럼명
+	 * @param keyword : 검색어
+	 * @param comparisonType : 검색어 비교 연산자 타입 ('=', 'like', 'is <not> null')
+	 * @param currentSearchOperator : 현재 검색 조건 연산자 (AND, OR)
+	 */
+	public void addSearchCondition (String column, String comparisonType, String keyword, String currentSearchOperator) throws Exception {
+		((Search) super.get("search")).addSearchCondition(column, comparisonType, keyword, currentSearchOperator);
+	}
+	
+	/** 
+	 * 검색 정렬 목록에 데이터 추가하기
+	 * 
+	 * @param column : 검색 컬럼명
+	 */
+	public void addSearchOrder (String column) throws Exception {
+		((Search) super.get("search")).addSearchOrder(column);
+	}
+	
+	/** 
+	 * 검색 목록에 데이터 추가하기
+	 * 
+	 * @param column : 검색 컬럼명
+	 * @param orderType : 정렬 타입('ASC', 'DESC')
+	 */
+	public void addSearchOrder (String column, String orderType) throws Exception {
+		((Search) super.get("search")).addSearchOrder(column, orderType);
+	}
+	
+	/** 
+	 * 검색 객체 가지고가기
+	 */
+	public Search getSearch() {
+		if (super.get("search") == null) {
+			return null;
+		} else {
+			return (Search) super.get("search");
+		}
+	}
+}
 
src/back-end/main/java/common/vo/Org.java (added)
+++ src/back-end/main/java/common/vo/Org.java
@@ -0,0 +1,170 @@
+package common.vo;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * @author 최정우
+ * @since 2021.12.06
+ *
+ * 그룹 정보 VO입니다.
+ */
+public class Org {
+
+	/**
+	 * 그룹 ID
+	 */
+	private String orgId;
+
+	/**
+	 * 부모 그룹 ID
+	 */
+	private String orgParentId;
+
+	/**
+	 * 그룹명
+	 */
+	private String orgName;
+
+	/**
+	 * 그룹 설명
+	 */
+	private String orgComment;
+
+	/**
+	 * 그룹 Level
+	 */
+	private int orgDepth;
+
+	/**
+	 * 배치 순서
+	 */
+	private int orgOrder;
+
+	/**
+	 * 등록자
+	 */
+	private String orgInsertUserId;
+
+	/**
+	 * 등록일시
+	 */
+	private String orgInsertDatetime;
+
+	/**
+	 * 수정자
+	 */
+	private String orgUpdateUserId;
+
+	/**
+	 * 수정일시
+	 */
+	private String orgUpdateDatetime;
+
+	/**
+	 * 사용여부
+	 */
+	private String orgIsUse;
+
+	/**
+	 * 그룹의 권한's
+	 */
+	private List<String> orgAuthotitise = new ArrayList<String>();
+
+	public String getOrgId() {
+		return orgId;
+	}
+
+	public void setOrgId(String orgId) {
+		this.orgId = orgId;
+	}
+
+	public String getOrgParentId() {
+		return orgParentId;
+	}
+
+	public void setOrgParentId(String orgParentId) {
+		this.orgParentId = orgParentId;
+	}
+
+	public String getOrgName() {
+		return orgName;
+	}
+
+	public void setOrgName(String orgName) {
+		this.orgName = orgName;
+	}
+
+	public String getOrgComment() {
+		return orgComment;
+	}
+
+	public void setOrgComment(String orgComment) {
+		this.orgComment = orgComment;
+	}
+
+	public int getOrgDepth() {
+		return orgDepth;
+	}
+
+	public void setOrgDepth(int orgDepth) {
+		this.orgDepth = orgDepth;
+	}
+
+	public int getOrgOrder() {
+		return orgOrder;
+	}
+
+	public void setOrgOrder(int orgOrder) {
+		this.orgOrder = orgOrder;
+	}
+
+	public String getOrgInsertUserId() {
+		return orgInsertUserId;
+	}
+
+	public void setOrgInsertUserId(String orgInsertUserId) {
+		this.orgInsertUserId = orgInsertUserId;
+	}
+
+	public String getOrgInsertDatetime() {
+		return orgInsertDatetime;
+	}
+
+	public void setOrgInsertDatetime(String orgInsertDatetime) {
+		this.orgInsertDatetime = orgInsertDatetime;
+	}
+
+	public String getOrgUpdateUserId() {
+		return orgUpdateUserId;
+	}
+
+	public void setOrgUpdateUserId(String orgUpdateUserId) {
+		this.orgUpdateUserId = orgUpdateUserId;
+	}
+
+	public String getOrgUpdateDatetime() {
+		return orgUpdateDatetime;
+	}
+
+	public void setOrgUpdateDatetime(String orgUpdateDatetime) {
+		this.orgUpdateDatetime = orgUpdateDatetime;
+	}
+
+	public String getOrgIsUse() {
+		return orgIsUse;
+	}
+
+	public void setOrgIsUse(String orgIsUse) {
+		this.orgIsUse = orgIsUse;
+	}
+
+	public List<String> getOrgAuthotitise() {
+		return orgAuthotitise;
+	}
+
+	public void setOrgAuthotitise(List<String> orgAuthotitise) {
+		this.orgAuthotitise = orgAuthotitise;
+	}
+
+}
 
src/back-end/main/java/common/vo/Search.java (added)
+++ src/back-end/main/java/common/vo/Search.java
@@ -0,0 +1,315 @@
+package common.vo;
+
+import common.util.AuthUtil;
+import common.util.StringUtil;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * @author 최정우
+ * @since 2021.12.06
+ *
+ * 공통 검색 VO 입니다.(상속받으세요)
+ */
+public class Search extends User {
+
+	public Search () {
+		if (AuthUtil.getLoginUser() != null) {
+			User loginUser = AuthUtil.getLoginUser();
+			super.setUserId(loginUser.getUserId());
+			super.setLoginId(loginUser.getLoginId());
+			super.setName(loginUser.getName());
+			super.setEmail(loginUser.getEmail());
+			super.setGender(loginUser.getGender());
+			super.setBirthDate(loginUser.getBirthDate());
+			super.setMobile(loginUser.getMobile());
+			super.setAddress(loginUser.getAddress());
+			super.setDetailAddress(loginUser.getDetailAddress());
+			super.setRegistrationDatetime(loginUser.getRegistrationDatetime());
+			super.setWithdrawDatetime(loginUser.getWithdrawDatetime());
+			super.setIsWithdraw(loginUser.getIsWithdraw());
+			super.setLoginFailedCount(loginUser.getLoginFailedCount());
+			super.setIsAccountLock(loginUser.getIsAccountLock());
+			super.setUserAuthotities(loginUser.getUserAuthotities());
+		}
+	}
+
+	/**
+	 * 검색 목록's
+	 */
+	private List<SearchCondition> searchConditionList = new ArrayList<SearchCondition>();
+
+	/**
+	 * 정렬 순서's
+	 */
+	private List<SearchOrder> searchOrderList = new ArrayList<SearchOrder>();
+
+	/**
+	 * 현재 페이지
+	 */
+	private int currentPage = 1;
+
+	/**
+	 * 한 페이지당 조회될 데이터 수
+	 */
+	private int perPage = 10;
+
+	/**
+	 * 총 개시물 수
+	 */
+	private int totalRows = 0;
+
+	/**
+	 * 페이징 시작할 row 넘버
+	 */
+	private int startRowNumber = 0;
+
+
+	/**
+	 * 페이징 사용 유무
+	 */
+	private boolean isUsePaging = true;
+
+
+	public List<SearchCondition> getSearchConditionList() {
+		return searchConditionList;
+	}
+
+	public void setSearchConditionList(List<SearchCondition> searchConditionList) {
+		this.searchConditionList = searchConditionList;
+	}
+
+	public List<SearchOrder> getSearchOrderList() {
+		return searchOrderList;
+	}
+
+	public void setSearchOrderList(List<SearchOrder> searchOrderList) {
+		this.searchOrderList = searchOrderList;
+	}
+
+	public int getCurrentPage() {
+		return this.currentPage;
+	}
+
+	public void setCurrentPage(int currentPage) {
+		this.currentPage = currentPage;
+	}
+
+	public int getPerPage() {
+		return perPage;
+	}
+
+	public void setPerPage(int perPage) {
+		this.perPage = perPage;
+	}
+
+	public int getTotalRows() {
+		return totalRows;
+	}
+
+	public void setTotalRows(int totalRows) {
+		this.totalRows = totalRows;
+	}
+
+	public int getStartRowNumber() {
+		return (currentPage - 1) * perPage;
+	}
+
+	public void setStartRowNumber(int startRowNumber) {
+		this.startRowNumber = startRowNumber;
+	}
+
+	public boolean getIsUsePaging() {
+		return isUsePaging;
+	}
+
+	public void setIsUsePaging(boolean isUsePaging) {
+		this.isUsePaging = isUsePaging;
+	}
+
+	/**
+	 * 검색 목록에 데이터 추가하기
+	 *
+	 * @param column : 검색 컬럼명
+	 * @param value : 검색어
+	 */
+	public void addSearchCondition (String column, String value) throws Exception {
+		if (StringUtil.isEmpty(column) == false) {
+			SearchCondition searchCondition = new SearchCondition();
+			searchCondition.setColumn(column);
+			searchCondition.setValue(value);
+
+			searchConditionList.add(searchCondition);
+		} else {
+			throw new Exception("addSearchCondition 메서드 에러 : 검색 조건의 컬럼명 값이 'null' 또는 '공백'입니다.");
+		}
+	}
+
+	/**
+	 * 검색 목록에 데이터 추가하기
+	 *
+	 * @param operator : 현재 검색 조건 연산자 (AND, OR)
+	 * @param column : 검색 컬럼명
+	 * @param comparisonType : 검색어 비교 연산자 타입 ('=', 'like', 'is <not> null')
+	 * @param value : 검색어
+	 */
+	public void addSearchCondition (String operator, String column, String comparisonType, String value) throws Exception {
+		if (StringUtil.isEmpty(column) == false) {
+			SearchCondition searchCondition = new SearchCondition();
+			searchCondition.setOperator(operator);
+			searchCondition.setColumn(column);
+			searchCondition.setComparisonType(comparisonType);
+			searchCondition.setValue(value);
+
+			searchConditionList.add(searchCondition);
+		} else {
+			throw new Exception("addSearchCondition 메서드 에러 : 검색 조건의 컬럼명 값이 'null' 또는 '공백'입니다.");
+		}
+	}
+	/**
+	 * 검색 목록에 데이터 set (같은 컬럼명이 존재 할 시 -> value 대체 / 없을 시 -> 검색 목록에 추가)
+	 *
+	 * @param column : 검색 컬럼명
+	 */
+	public void setSearchCondition (String column, String value) throws Exception {
+		boolean isFind = false;
+		for (int i = 0; i < searchConditionList.size(); i++) {
+			if (searchConditionList.get(i).getColumn().equals(column) == true) {
+				searchConditionList.get(i).setColumn(column);
+				searchConditionList.get(i).setValue(value);
+				isFind = true;
+				break;
+			}
+		}
+
+		if (isFind == false) {
+			addSearchCondition(column, value);
+		}
+	}
+	/**
+	 * 검색 목록에 데이터 set (같은 컬럼명이 존재 할 시 -> value 대체 / 없을 시 -> 검색 목록에 추가)
+	 *
+	 * @param column : 검색 컬럼명
+	 */
+	public void setSearchCondition (String operator, String column, String comparisonType, String value) throws Exception {
+		boolean isFind = false;
+		for (int i = 0; i < searchConditionList.size(); i++) {
+			if (searchConditionList.get(i).getColumn().equals(column) == true) {
+				searchConditionList.get(i).setOperator(operator);
+				searchConditionList.get(i).setColumn(column);
+				searchConditionList.get(i).setComparisonType(comparisonType);
+				searchConditionList.get(i).setValue(value);
+				isFind = true;
+				break;
+			}
+		}
+
+		if (isFind == false) {
+			addSearchCondition(operator, column, comparisonType, value);
+		}
+	}
+	/**
+	 * 검색 목록에 데이터 삭제하기
+	 *
+	 * @param column : 검색 컬럼명
+	 */
+	public void removeSearchCondition (String column) throws Exception {
+		for (int i = 0; i < searchConditionList.size(); i++) {
+			if (searchConditionList.get(i).getColumn().equals(column) == true) {
+				searchConditionList.remove(i);
+				break;
+			}
+		}
+	}
+
+	/**
+	 * 검색 정렬 목록에 데이터 추가하기
+	 *
+	 * @param column : 검색 컬럼명
+	 */
+	public void addSearchOrder (String column) throws Exception {
+		if (StringUtil.isEmpty(column) == false) {
+			SearchOrder searchOrder = new SearchOrder();
+			searchOrder.setColumn(column);
+
+			searchOrderList.add(searchOrder);
+		} else {
+			throw new Exception("addSearchOrder 메서드 에러 : 정렬 조건의 컬럼명 값이 'null' 또는 '공백'입니다.");
+		}
+	}
+
+	/**
+	 * 검색 목록에 데이터 추가하기
+	 *
+	 * @param column : 검색 컬럼명
+	 * @param orderType : 정렬 타입('ASC', 'DESC')
+	 */
+	public void addSearchOrder (String column, String orderType) throws Exception {
+		if (StringUtil.isEmpty(column) == false) {
+			SearchOrder searchOrder = new SearchOrder();
+			searchOrder.setColumn(column);
+			searchOrder.setOrderType(orderType);
+
+			searchOrderList.add(searchOrder);
+		} else {
+			throw new Exception("addSearchOrder 메서드 에러 : 정렬 조건의 컬럼명 값이 'null' 또는 '공백'입니다.");
+		}
+	}
+	/**
+	 * 검색 목록에 데이터 set (같은 컬럼명이 존재 할 시 -> value 대체 / 없을 시 -> 검색 목록에 추가)
+	 *
+	 * @param column : 검색 컬럼명
+	 */
+	public void setSearchOrder (String column) throws Exception {
+		boolean isFind = false;
+		for (int i = 0; i < searchOrderList.size(); i++) {
+			if (searchOrderList.get(i).getColumn().equals(column) == true) {
+				searchOrderList.get(i).setColumn(column);
+				isFind = true;
+				break;
+			}
+		}
+
+		if (isFind == false) {
+			addSearchOrder(column);
+		}
+	}
+	/**
+	 * 검색 목록에 데이터 set (같은 컬럼명이 존재 할 시 -> value 대체 / 없을 시 -> 검색 목록에 추가)
+	 *
+	 * @param column : 검색 컬럼명
+	 */
+	public void setSearchOrder (String column, String orderType) throws Exception {
+		boolean isFind = false;
+		for (int i = 0; i < searchOrderList.size(); i++) {
+			if (searchOrderList.get(i).getColumn().equals(column) == true) {
+				searchOrderList.get(i).setColumn(column);
+				searchOrderList.get(i).setOrderType(orderType);
+				isFind = true;
+				break;
+			}
+		}
+
+		if (isFind == false) {
+			addSearchOrder(column, orderType);
+		}
+	}
+	/**
+	 * 검색 목록에 데이터 삭제하기
+	 *
+	 * @param column : 검색 컬럼명
+	 */
+	public void removeSearchOrder (String column) throws Exception {
+		for (int i = 0; i < searchOrderList.size(); i++) {
+			if (searchOrderList.get(i).getColumn().equals(column) == true) {
+				searchOrderList.remove(i);
+				break;
+			}
+		}
+	}
+}
+
+
+
+
 
src/back-end/main/java/common/vo/SearchCondition.java (added)
+++ src/back-end/main/java/common/vo/SearchCondition.java
@@ -0,0 +1,127 @@
+package common.vo;
+
+import common.util.StringUtil;
+
+/**
+ * @author 최정우
+ * @since 2021.12.06
+ *
+ * 검색 조건 VO 입니다.
+ */
+public class SearchCondition {
+
+	/**
+	 * 현재 검색 조건 연산자 (OR, AND) (주의 - 검색 조건 앞에 붙음)
+	 *
+	 * Search class의 searchOperator변수보다 우선순위를 가짐
+	 *
+	 * 순서: 0
+	 */
+	private String operator = "AND";
+
+	/**
+	 * 검색 조건 앞에 붙이는 문자 ex) 여는 괄호 '('
+	 *
+	 * 순서: 1
+	 */
+	private String prefix = "";
+
+	/**
+	 * 검색 컬럼
+	 *
+	 * 순서: 2
+	 */
+	private String column = "";
+
+	/**
+	 * 검색어 비교 연산자 타입 ('=', '!=', '<>', '>', '>=', '<', '<=' 'like', 'is <not> null')
+	 *
+	 * 순서: 3
+	 */
+	private String comparisonType = "=";
+
+	/**
+	 * 검색값
+	 *
+	 * 순서: 4
+	 */
+	private Object value = null;
+
+	/**
+	 * 검색 조건 뒤에 붙이는 문자 ex) 닫는 괄호 ')'
+	 *
+	 * 순서: 5
+	 */
+	private String suffix = "";
+
+
+	public String getColumn() {
+		return column;
+	}
+
+	public void setColumn(String column) {
+		if (StringUtil.isEmpty(column) == true) {
+			this.column = "";
+		} else {
+			this.column = column;
+		}
+	}
+
+	public Object getValue() {
+		return value;
+	}
+
+	public void setValue(Object value) {
+		this.value = value;
+	}
+
+	public String getComparisonType() {
+		return comparisonType;
+	}
+
+	public void setComparisonType(String comparisonType) {
+		comparisonType = comparisonType.toUpperCase();
+		if (comparisonType.equals("=")
+			|| comparisonType.equals("!=") || comparisonType.equals("<>")
+			|| comparisonType.equals(">") || comparisonType.equals(">=")
+			|| comparisonType.equals("<") || comparisonType.equals("<=")
+			|| comparisonType.equals("LIKE") || comparisonType.equals("IS")
+			|| comparisonType.equals("IS NOT")) {
+			this.comparisonType = comparisonType;
+		} else {
+			//걍 냅둡시다.
+		}
+	}
+
+
+	public String getOperator() {
+		return operator;
+	}
+
+	public void setOperator(String operator) {
+		this.operator = operator;
+		operator = operator.toUpperCase();
+		if (operator.equals("AND") || operator.equals("OR")) {
+			this.operator = operator;
+		} else {
+			//걍 냅둡시다.
+		}
+	}
+
+	public String getPrefix() {
+		return prefix;
+	}
+
+	public void setPrefix(String prefix) {
+		this.prefix = prefix;
+	}
+
+	public String getSuffix() {
+		return suffix;
+	}
+
+	public void setSuffix(String suffix) {
+		this.suffix = suffix;
+	}
+
+}(No newline at end of file)
 
src/back-end/main/java/common/vo/SearchOrder.java (added)
+++ src/back-end/main/java/common/vo/SearchOrder.java
@@ -0,0 +1,53 @@
+package common.vo;
+
+import common.util.StringUtil;
+
+/**
+ * @author 최정우
+ * @since 2021.12.06
+ * 
+ * 검색의 정렬 순서 관련 VO 입니다.
+ */
+public class SearchOrder {
+
+	/**
+	 * 정렬할 컬럼명
+	 */
+	private String column = "";
+	
+	/**
+	 * 정렬 타입('ASC', 'DESC')
+	 */
+	private String orderType = "ASC";
+
+	public String getColumn() {
+		return column;
+	}
+
+	public void setColumn(String column) {
+		if (StringUtil.isEmpty(column) == true) {
+			this.column = "";
+		} else {
+			this.column = column;
+		}
+	}
+
+	public String getOrderType() {
+		return orderType;
+	}
+
+	public void setOrderType(String orderType) {
+		orderType = orderType.toUpperCase();
+		if (orderType.equals("ASC") || orderType.equals("DESC")) {
+			this.orderType = orderType;
+		} else {
+			//걍 냅둡시다.
+		}
+	}
+	
+}
+
+
+
+
+
 
src/back-end/main/java/common/vo/SystemCode.java (added)
+++ src/back-end/main/java/common/vo/SystemCode.java
@@ -0,0 +1,383 @@
+package common.vo;
+
+import java.util.LinkedHashMap;
+import java.util.Map;
+
+
+public class SystemCode {
+
+	//191자 => mariaDB에서 indexing가능한 최대 크기 765Byte/한글 4Byte(utf8mb4)
+	public final static int DEFAULT_VARCHAR_SIZE = 191;
+
+	//mariaDB에서 indexing가능한 varchar 최대 크기 765Byte
+	public final static int MAX_VARCHAR_SIZE = 765;
+
+	//프로그램 이름
+	public final static String PROGRAM_TITLE = "도로교통 위험분석시스템";
+
+	//프로그램 이름 앞에 붙는 문자열
+	public final static String PROGRAM_TITLE_PREFIX = "";
+
+	/**
+	 * @author 최정우
+	 * @since 2020.12.24
+	 *
+	 * 시스템의 사용자 권한을 정의한 상수 Class 입니다.
+	 */
+	public enum AuthorityType {
+		ROLE_ADMIN("관리자")
+		, ROLE_USER("사용자")
+		, permitAll("API연계 수집");
+
+		private AuthorityType (String value) {
+			this.value = value;
+		}
+
+		/**
+		 * 한글값
+		 */
+		final private String value;
+
+		/**
+		 * 한글값 조회
+		 */
+		public String getValue () {
+			return value;
+		}
+
+		/**
+		 * 데이터 수집 타입 목록 조회
+		 */
+		public static Map<AuthorityType, String> getAuthorityTypeList () {
+			Map<AuthorityType, String> info = new LinkedHashMap<AuthorityType, String>();
+			AuthorityType[] array = AuthorityType.values();
+			for (int i = 0; i < array.length; i++) {
+				info.put(array[i], array[i].getValue());
+			}
+			return info;
+		}
+	}
+
+	/**
+	 * @author 최정우
+	 * @since 2020.12.24
+	 *
+	 * 시스템의 사용자 권한을 정의한 상수 Class 입니다.
+	 */
+	public enum TrafficAnalysisResultType {
+		CAR_TO_CAR("차 대 차")
+		, CAR_TO_PEOPLE("차 대 사람")
+		, ROAD_CRACK("도로 크랙")
+		, ROAD_HOLE("도로 웅덩이");
+
+		private TrafficAnalysisResultType (String value) {
+			this.value = value;
+		}
+
+		/**
+		 * 한글값
+		 */
+		final private String value;
+
+		/**
+		 * 한글값 조회
+		 */
+		public String getValue () {
+			return value;
+		}
+
+		/**
+		 * 데이터 수집 타입 목록 조회
+		 */
+		public static Map<TrafficAnalysisResultType, String> getTrafficAnalysisResultTypeList () {
+			Map<TrafficAnalysisResultType, String> info = new LinkedHashMap<TrafficAnalysisResultType, String>();
+			TrafficAnalysisResultType[] array = TrafficAnalysisResultType.values();
+			for (int i = 0; i < array.length; i++) {
+				info.put(array[i], array[i].getValue());
+			}
+			return info;
+		}
+
+		public static TrafficAnalysisResultType codeToType (String code) {
+			if (code != null && code.length() > 0) {
+				if (code.equals("0")) {
+					return ROAD_CRACK;
+				} else if (code.equals("1")) {
+					return ROAD_HOLE;
+				} else if (code.equals("2")) {
+					return CAR_TO_CAR;
+				} else if (code.equals("3")) {
+					return CAR_TO_PEOPLE;
+				} else {
+					return null;
+				}
+			} else {
+				return null;
+			}
+		}
+	}
+
+	/**
+	 * @author 최정우
+	 * @since 2020.12.24
+	 *
+	 * OpenAPI의 서비스 타입을 정의한 상수 Class 입니다.
+	 */
+	public enum APIType {
+		REST
+		, RSS
+		, SOAP;
+
+		/**
+		 * 데이터 수집 타입 목록 조회
+		 */
+		public static Map<APIType, String> getAPITypeList () {
+	    	Map<APIType, String> info = new LinkedHashMap<APIType, String>();
+	    	APIType[] array = APIType.values();
+	    	for (int i = 0; i < array.length; i++) {
+	    		info.put(array[i], array[i].toString());
+	    	}
+	    	return info;
+		}
+	}
+
+	/**
+	 * @author 최정우
+	 * @since 2020.12.24
+	 *
+	 * OpenAPI의 데이터 포맷 타입을 정의한 상수 Class 입니다.
+	 */
+	public enum APIDataFormatType {
+		JSON
+		, XML;
+
+		/**
+		 * 데이터 수집 타입 목록 조회
+		 */
+		public static Map<APIDataFormatType, String> getAPIDataFormatTypeList () {
+	    	Map<APIDataFormatType, String> info = new LinkedHashMap<APIDataFormatType, String>();
+	    	APIDataFormatType[] array = APIDataFormatType.values();
+	    	for (int i = 0; i < array.length; i++) {
+	    		info.put(array[i], array[i].toString());
+	    	}
+	    	return info;
+		}
+	}
+
+	/**
+	 * @author 최정우
+	 * @since 2019.11.13
+	 *
+	 * 업로드 파일에 대한 저장 폴더 경로를 정의한 상수 Class
+	 * MAIN-메인 저장소, TEMP-임시 저장소
+	 */
+	public enum FileUploadPath {
+		/* 관리 시스템 파일 업로드 경로 */
+		//상대 경로 저장소(프로젝트 내부 -> Windows, Linux 구분 없음)
+		MAIN_RELATIVE_PATH("\\resources\\common\\file\\upload\\main", "/resources/common/file/upload/main")
+		, TEMP_RELATIVE_PATH("\\resources\\common\\file\\upload\\temp", "/resources/common/file/upload/temp")
+		//절대 경로 저장소(Windows, Linux)
+		, MAIN_ABSOLUTE_PATH("C:\\bigdata\\common\\upload\\main", "/bigdata/common/upload/main")
+		, TEMP_ABSOLUTE_PATH("C:\\bigdata\\common\\upload\\temp", "/bigdata/common/upload/temp");
+
+		private FileUploadPath(String windowFileUploadPath, String linuxFileUploadPath) {
+			this.windowFileUploadPath = windowFileUploadPath;
+			this.linuxFileUploadPath = linuxFileUploadPath;
+		}
+
+		final private String windowFileUploadPath;
+
+		final private String linuxFileUploadPath;
+
+		public String getWindowFileUploadPath() {
+			return windowFileUploadPath;
+		}
+
+		public String getLinuxFileUploadPath() {
+			return linuxFileUploadPath;
+		}
+
+		/**
+		 * OS 타입별 파일 업로드 경로 return
+		 */
+		public String getOSFileUploadPath() {
+			if (System.getProperty("os.name").indexOf("Windows") > -1) {
+	        	return windowFileUploadPath;
+	        } else {
+	        	return linuxFileUploadPath;
+	        }
+		}
+	}
+
+
+	/**
+	 * @author 최정우
+	 * @since 2019.11.13
+	 *
+	 * 데이터 수집 타입을 정의한 상수 Class 입니다.
+	 */
+	public enum CollectionType {
+		FILE("파일 수집")
+		, DB("DB연계 수집")
+		, API("API연계 수집")
+		, CRAWLING("웹데이터 수집")
+		, SOCKET("소켓통신 수집");
+
+		private CollectionType (String value) {
+			this.value = value;
+		}
+
+		/**
+		 * 한글값
+		 */
+		final private String value;
+
+		/**
+		 * 한글값 조회
+		 */
+		public String getValue () {
+			return value;
+		}
+
+		/**
+		 * 데이터 수집 타입 목록 조회
+		 */
+		public static Map<CollectionType, String> getCollectionTypeList () {
+	    	Map<CollectionType, String> info = new LinkedHashMap<CollectionType, String>();
+	    	CollectionType[] array = CollectionType.values();
+	    	for (int i = 0; i < array.length; i++) {
+	    		info.put(array[i], array[i].getValue());
+	    	}
+	    	return info;
+		}
+	}
+
+	/**
+	 * @author 최정우
+	 * @since 2019.12.03
+	 *
+	 * 스케줄 작업 상태 타입을 정의한 상수 Class 입니다.
+	 */
+	public enum TaskStatus {
+		START("작동 시작")
+		, COMPLETE("작동 완료")
+		, ERROR("작동 오류");
+
+		private TaskStatus (String message) {
+			this.message = message;
+		}
+
+		/**
+		 * 한글 메세지
+		 */
+		final private String message;
+
+		/**
+		 * 한글 메세지 조회
+		 */
+		public String getMessage () {
+			return message;
+		}
+
+		/**
+		 * 스케줄 상태 타입 목록 조회
+		 */
+		public static Map<TaskStatus, String> getTaskStatusList () {
+	    	Map<TaskStatus, String> info = new LinkedHashMap<TaskStatus, String>();
+	    	TaskStatus[] array = TaskStatus.values();
+	    	for (int i = 0; i < array.length; i++) {
+	    		info.put(array[i], array[i].getMessage());
+	    	}
+	    	return info;
+		}
+	}
+
+	/**
+	 * @author 최정우
+	 * @since 2019.12.03
+	 *
+	 * 날짜 통계 관련 타입을 정의한 상수 Class 입니다.
+	 */
+	public enum DateStatsGroupType {
+		DATE_FLOW("시계열")
+		, DATE_CYCLE("주기별");//통계 데이터 조회 총 행 수: 31(1, 2, 3, ..., 31)
+
+		private DateStatsGroupType (String message) {
+			this.message = message;
+		}
+
+		/**
+		 * 한글 메세지
+		 */
+		final private String message;
+
+		/**
+		 * 한글 메세지 조회
+		 */
+		public String getMessage () {
+			return message;
+		}
+
+		/**
+		 * 날짜 통계 관련 타입 목록 조회
+		 */
+		public static Map<DateStatsGroupType, String> getDateStatusType () {
+			Map<DateStatsGroupType, String> info = new LinkedHashMap<DateStatsGroupType, String>();
+			DateStatsGroupType[] array = DateStatsGroupType.values();
+			for (int i = 0; i < array.length; i++) {
+				info.put(array[i], array[i].getMessage());
+			}
+			return info;
+		}
+	}
+	/**
+	 * @author 최정우
+	 * @since 2019.12.03
+	 *
+	 * 날짜 통계 관련 타입을 정의한 상수 Class 입니다.
+	 */
+	public enum DateStatsType {
+		YEAR("년도별(시계열)")//시계열도 되고 주기도됨 (최상위 Date이기 때문)
+
+		, DATE_FLOW_QUARTER("분기별(시계열)")
+		, DATE_FLOW_MONTH("월별(시계열)")
+		, DATE_FLOW_WEEK("주별(시계열)")
+		, DATE_FLOW_DAY("일별(시계열)")
+
+		, DATE_CYCLE_QUARTER("분기별(주기별)")//통계 데이터 조회 총 행 수: 4(1분기, 2분기, 3분기, 4분기)
+		, DATE_CYCLE_MONTH("월별(주기별)")//통계 데이터 조회 총 행 수: 12(1월, 2월, 3월, ..., 12월)
+		, DATE_CYCLE_WEEK("요일별(주기별)")//통계 데이터 조회 총 행 수: 7(월, 화, 수, ..., 일)
+		, DATE_CYCLE_DAY("일별(주기별)")//통계 데이터 조회 총 행 수: 31(1, 2, 3, ..., 31)
+		, DATE_CYCLE_TIME("시간별(주기별)");//통계 데이터 조회 총 행 수: 31(1, 2, 3, ..., 31)
+
+		private DateStatsType (String message) {
+			this.message = message;
+		}
+
+		/**
+		 * 한글 메세지
+		 */
+		final private String message;
+
+		/**
+		 * 한글 메세지 조회
+		 */
+		public String getMessage () {
+			return message;
+		}
+
+		/**
+		 * 날짜 통계 관련 타입 목록 조회
+		 */
+		public static Map<DateStatsType, String> getDateStatusType () {
+			Map<DateStatsType, String> info = new LinkedHashMap<DateStatsType, String>();
+			DateStatsType[] array = DateStatsType.values();
+			for (int i = 0; i < array.length; i++) {
+				info.put(array[i], array[i].getMessage());
+			}
+			return info;
+		}
+	}
+
+
+}
 
src/back-end/main/java/common/vo/User.java (added)
+++ src/back-end/main/java/common/vo/User.java
@@ -0,0 +1,222 @@
+package common.vo;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * @author 최정우
+ * @since 2021.12.06
+ *
+ * 회원 정보 VO입니다.
+ */
+public class User extends Org {
+
+	/**
+	 * 유니크 아이디
+	 */
+	private String userId;
+
+	/**
+	 * 로그인 아이디
+	 */
+	private String loginId;
+
+	/**
+	 * 패스워드
+	 */
+	private String password;
+
+	/**
+	 * 회원명
+	 */
+	private String name;
+
+	/**
+	 * 생년월일
+	 */
+	private String birthDate;
+
+	/**
+	 * 휴대전화
+	 */
+	private String mobile;
+
+	/**
+	 * 이메일
+	 */
+	private String email;
+
+	/**
+	 * 성별
+	 */
+	private String gender;
+
+	/**
+	 * 주소
+	 */
+	private String address;
+
+	/**
+	 * 상세주소
+	 */
+	private String detailAddress;
+
+	/**
+	 * 회원가입일시
+	 */
+	private String registrationDatetime;
+
+	/**
+	 * 탈퇴일시
+	 */
+	private String withdrawDatetime;
+
+	/**
+	 * 탈퇴여부
+	 */
+	private boolean isWithdraw;
+
+	/**
+	 * 로그인 실패 횟수
+	 */
+	private int loginFailedCount;
+
+	/**
+	 * 로그인 잠금 여부
+	 */
+	private boolean isAccountLock;
+
+
+	/**
+	 * 회원의 권한's
+	 */
+	private List<String> userAuthotities = new ArrayList<String>();
+
+	public String getUserId() {
+		return userId;
+	}
+
+	public void setUserId(String userId) {
+		this.userId = userId;
+	}
+
+	public String getLoginId() {
+		return loginId;
+	}
+
+	public void setLoginId(String loginId) {
+		this.loginId = loginId;
+	}
+
+	public String getPassword() {
+		return password;
+	}
+
+	public void setPassword(String password) {
+		this.password = password;
+	}
+
+	public String getName() {
+		return name;
+	}
+
+	public void setName(String name) {
+		this.name = name;
+	}
+
+	public String getBirthDate() {
+		return birthDate;
+	}
+
+	public void setBirthDate(String birthDate) {
+		this.birthDate = birthDate;
+	}
+
+	public String getMobile() {
+		return mobile;
+	}
+
+	public void setMobile(String mobile) {
+		this.mobile = mobile;
+	}
+
+	public String getEmail() {
+		return email;
+	}
+
+	public void setEmail(String email) {
+		this.email = email;
+	}
+
+	public String getGender() {
+		return gender;
+	}
+
+	public void setGender(String gender) {
+		this.gender = gender;
+	}
+
+	public String getAddress() {
+		return address;
+	}
+
+	public void setAddress(String address) {
+		this.address = address;
+	}
+
+	public String getDetailAddress() {
+		return detailAddress;
+	}
+
+	public void setDetailAddress(String detailAddress) {
+		this.detailAddress = detailAddress;
+	}
+
+	public String getRegistrationDatetime() {
+		return registrationDatetime;
+	}
+
+	public void setRegistrationDatetime(String registrationDatetime) {
+		this.registrationDatetime = registrationDatetime;
+	}
+
+	public String getWithdrawDatetime() {
+		return withdrawDatetime;
+	}
+
+	public void setWithdrawDatetime(String withdrawDatetime) {
+		this.withdrawDatetime = withdrawDatetime;
+	}
+
+	public boolean getIsWithdraw() {
+		return isWithdraw;
+	}
+
+	public void setIsWithdraw(boolean withdraw) {
+		isWithdraw = withdraw;
+	}
+
+	public int getLoginFailedCount() {
+		return loginFailedCount;
+	}
+
+	public void setLoginFailedCount(int loginFailedCount) {
+		this.loginFailedCount = loginFailedCount;
+	}
+
+	public boolean getIsAccountLock() {
+		return isAccountLock;
+	}
+
+	public void setIsAccountLock(boolean accountLock) {
+		isAccountLock = accountLock;
+	}
+
+	public List<String> getUserAuthotities() {
+		return userAuthotities;
+	}
+
+	public void setUserAuthotities(List<String> userAuthotities) {
+		this.userAuthotities = userAuthotities;
+	}
+}
 
src/back-end/main/java/kr/co/takensoft/projectName/common/dao/CommonDAO.java (added)
+++ src/back-end/main/java/kr/co/takensoft/projectName/common/dao/CommonDAO.java
@@ -0,0 +1,16 @@
+package kr.co.takensoft.projectName.common.dao;
+
+
+import org.apache.ibatis.annotations.Mapper;
+
+/**
+ * Common DAO 입니다.
+ *
+ * @author 최정우
+ * @since 2022.09.01
+ */
+//@Repository <-- Class 객체로 생성 해야 됨
+@Mapper
+public interface CommonDAO {
+
+}
 
src/back-end/main/java/kr/co/takensoft/projectName/common/service/CommonService.java (added)
+++ src/back-end/main/java/kr/co/takensoft/projectName/common/service/CommonService.java
@@ -0,0 +1,11 @@
+package kr.co.takensoft.projectName.common.service;
+
+/**
+ * Common 서비스 로직 Interface 입니다.
+ *
+ * @author 최정우
+ * @since 2022.09.01
+ */
+public interface CommonService {
+
+}
 
src/back-end/main/java/kr/co/takensoft/projectName/common/service/impl/CommonServiceImpl.java (added)
+++ src/back-end/main/java/kr/co/takensoft/projectName/common/service/impl/CommonServiceImpl.java
@@ -0,0 +1,25 @@
+package kr.co.takensoft.projectName.common.service.impl;
+
+import com.fasterxml.jackson.databind.ObjectMapper;
+import kr.co.takensoft.projectName.common.dao.CommonDAO;
+import kr.co.takensoft.projectName.common.service.CommonService;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+
+/**
+ * Common 서비스 로직 Class 객체 입니다.
+ *
+ * @author 최정우
+ * @since 2022.09.01
+ */
+@Service
+public class CommonServiceImpl implements CommonService {
+
+    @Autowired
+    private ObjectMapper objectMapper;
+
+    @Autowired
+    private CommonDAO commonDAO;
+
+
+}
 
src/back-end/main/java/kr/co/takensoft/projectName/common/web/CommonConroller.java (added)
+++ src/back-end/main/java/kr/co/takensoft/projectName/common/web/CommonConroller.java
@@ -0,0 +1,30 @@
+package kr.co.takensoft.projectName.common.web;
+
+import com.fasterxml.jackson.databind.ObjectMapper;
+import kr.co.takensoft.projectName.common.service.CommonService;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Controller;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.servlet.ModelAndView;
+
+/**
+ * Common Controller 입니다.
+ *
+ * @author 최정우
+ * @since 2022.09.01
+ */
+@Controller
+public class CommonConroller {
+
+    @Autowired
+    private ObjectMapper objectMapper;
+
+    @Autowired
+    private CommonService commonService;
+
+
+    @RequestMapping(value = "/")
+    public String main () {
+        return "redirect:/views/index.html";
+    }
+}
 
src/back-end/main/java/kr/co/takensoft/projectName/test/dao/TestDAO.java (added)
+++ src/back-end/main/java/kr/co/takensoft/projectName/test/dao/TestDAO.java
@@ -0,0 +1,26 @@
+package kr.co.takensoft.projectName.test.dao;
+
+
+import kr.co.takensoft.projectName.test.vo.Test;
+import org.apache.ibatis.annotations.Mapper;
+
+import java.util.List;
+
+/**
+ * 테스트용 DAO 입니다.
+ *
+ * @author 최정우
+ * @since 2022.09.01
+ */
+//@Repository <-- Class 객체로 생성 해야 됨
+@Mapper
+public interface TestDAO {
+
+    /**
+     * 데이터 조회 테스트
+     *
+     * @author 최정우
+     * @since 2022.09.01
+     */
+    public List<Test> testDataSelectList (Test test) throws Exception;
+}
 
src/back-end/main/java/kr/co/takensoft/projectName/test/service/TestService.java (added)
+++ src/back-end/main/java/kr/co/takensoft/projectName/test/service/TestService.java
@@ -0,0 +1,19 @@
+package kr.co.takensoft.projectName.test.service;
+
+import kr.co.takensoft.projectName.test.vo.Test;
+
+import java.util.List;
+
+
+public interface TestService {
+
+
+    /**
+     * 데이터 조회 테스트
+     *
+     * @author 최정우
+     * @since 2022.09.01
+     */
+    public List<Test> testDataSelectList (Test test) throws Exception;
+
+}
 
src/back-end/main/java/kr/co/takensoft/projectName/test/service/impl/TestServiceImpl.java (added)
+++ src/back-end/main/java/kr/co/takensoft/projectName/test/service/impl/TestServiceImpl.java
@@ -0,0 +1,33 @@
+package kr.co.takensoft.projectName.test.service.impl;
+
+import kr.co.takensoft.projectName.test.dao.TestDAO;
+import kr.co.takensoft.projectName.test.service.TestService;
+import kr.co.takensoft.projectName.test.vo.Test;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+
+import java.util.List;
+
+/**
+ * 테스트용 서비스 로직 Class 객체 입니다.
+ *
+ * @author 최정우
+ * @since 2022.09.01
+ */
+@Service
+public class TestServiceImpl implements TestService {
+
+    @Autowired
+    private TestDAO testDao;
+
+    /**
+     * 데이터 조회 테스트
+     *
+     * @author 최정우
+     * @since 2022.09.01
+     */
+    @Override
+    public List<Test> testDataSelectList(Test test) throws Exception {
+        return testDao.testDataSelectList(test);
+    }
+}
 
src/back-end/main/java/kr/co/takensoft/projectName/test/vo/Test.java (added)
+++ src/back-end/main/java/kr/co/takensoft/projectName/test/vo/Test.java
@@ -0,0 +1,54 @@
+package kr.co.takensoft.projectName.test.vo;
+
+public class Test {
+
+    private long testId;
+
+    private String title;
+
+    private String content;
+
+    private String createUserId;
+
+    private String createDatetime;
+
+    public long getTestId() {
+        return testId;
+    }
+
+    public void setTestId(long testId) {
+        this.testId = testId;
+    }
+
+    public String getContent() {
+        return content;
+    }
+
+    public void setContent(String content) {
+        this.content = content;
+    }
+
+    public String getCreateUserId() {
+        return createUserId;
+    }
+
+    public void setCreateUserId(String createUserId) {
+        this.createUserId = createUserId;
+    }
+
+    public String getCreateDatetime() {
+        return createDatetime;
+    }
+
+    public void setCreateDatetime(String createDatetime) {
+        this.createDatetime = createDatetime;
+    }
+
+    public String getTitle() {
+        return title;
+    }
+
+    public void setTitle(String title) {
+        this.title = title;
+    }
+}
 
src/back-end/main/java/kr/co/takensoft/projectName/test/web/TestConroller.java (added)
+++ src/back-end/main/java/kr/co/takensoft/projectName/test/web/TestConroller.java
@@ -0,0 +1,106 @@
+package kr.co.takensoft.projectName.test.web;
+
+import com.fasterxml.jackson.databind.ObjectMapper;
+import kr.co.takensoft.projectName.test.service.TestService;
+import kr.co.takensoft.projectName.test.vo.Test;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Controller;
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RequestParam;
+import org.springframework.web.multipart.MultipartFile;
+import org.springframework.web.multipart.MultipartHttpServletRequest;
+import org.springframework.web.servlet.ModelAndView;
+
+import javax.servlet.http.HttpServletRequest;
+import java.util.HashMap;
+import java.util.Iterator;
+
+/**
+ * 테스트용 Controller 입니다.
+ *
+ * @author 최정우
+ * @since 2022.09.01
+ */
+@Controller
+public class TestConroller {
+
+    @Autowired
+    private ObjectMapper objectMapper;
+
+    @Autowired
+    private TestService testService;
+
+    /**
+     * 데이터 조회 테스트
+     *
+     * @author 최정우
+     * @since 2022.09.01
+     */
+    @RequestMapping(value = "/testDataSelectList")
+    public ModelAndView testDataSelectList (@RequestParam HashMap<String, Object> param) throws Exception {
+        ModelAndView mav = new ModelAndView("jsonView");
+        if (param != null && param.size() > 0) {
+            System.out.println("testDataSelectList param : " + objectMapper.writeValueAsString(param));
+        }
+        Test test = new Test();
+        mav.addObject("result", testService.testDataSelectList(test));
+        return mav;
+    }
+
+    /**
+     * @RequestParam HashMap<String, Object> param Test
+     * GET 방식의 URL Query 데이터 가능
+     * POST 방식의 Body FormData 데이터 가능
+     *
+     * @author 최정우
+     * @since 2022.08.31
+     */
+    @RequestMapping(value = "/jsonTestForRequestParam")
+    public ModelAndView jsonTestForRequestParam (@RequestParam HashMap<String, Object> param) throws Exception {
+        if (param != null && param.size() > 0) {
+            System.out.println("jsonTestForRequestParam param : " + objectMapper.writeValueAsString(param));
+        }
+        ModelAndView mav = new ModelAndView("jsonView");
+        mav.addObject("result", param);
+        return mav;
+    }
+
+    @RequestMapping(value = "/jsonTestForRequestBody")
+    public ModelAndView jsonTestForRequestBody (@RequestBody HashMap<String, Object> param) throws Exception {
+        if (param != null && param.size() > 0) {
+            System.out.println("jsonTestForRequestBody param : " + objectMapper.writeValueAsString(param));
+        }
+        ModelAndView mav = new ModelAndView("jsonView");
+        mav.addObject("result", param);
+        return mav;
+    }
+
+    @RequestMapping(value = "/jsonTestForMultipart")
+    public ModelAndView jsonTestForMultipart (HttpServletRequest request, @RequestParam(required = false) HashMap<String, Object> param) throws Exception {
+        if (param != null && param.size() > 0) {
+            System.out.println("jsonTestForMultipart param : " + objectMapper.writeValueAsString(param));
+        }
+
+        try {
+            MultipartHttpServletRequest multipart = (MultipartHttpServletRequest) request;
+            Iterator<String> itr = multipart.getFileNames();
+
+            int index = 1;
+            while (itr.hasNext()) {
+                MultipartFile multipartFile = multipart.getFile(itr.next());
+                System.out.println("File " + index + ". " + multipartFile.getOriginalFilename() + " (" + multipartFile.getSize() + ")");
+            }
+        } catch (Exception e) {
+            System.out.println("");
+            System.err.println("Mutipart Error 발생");
+            e.printStackTrace();
+
+        }
+
+
+        ModelAndView mav = new ModelAndView("jsonView");
+        mav.addObject("result", param);
+        return mav;
+    }
+}
 
src/back-end/main/java/spring/SpringStarter.java (added)
+++ src/back-end/main/java/spring/SpringStarter.java
@@ -0,0 +1,52 @@
+package spring;
+
+import org.springframework.web.WebApplicationInitializer;
+import org.springframework.web.context.ContextLoaderListener;
+import org.springframework.web.context.support.AnnotationConfigWebApplicationContext;
+import org.springframework.web.filter.CharacterEncodingFilter;
+import org.springframework.web.servlet.DispatcherServlet;
+import javax.servlet.FilterRegistration;
+import javax.servlet.ServletContext;
+import javax.servlet.ServletException;
+import javax.servlet.ServletRegistration;
+
+/**
+ * SpringFramework Context 구동 Class
+ *
+ * @author 최정우
+ * @since 2022.08.31
+ */
+public class SpringStarter implements WebApplicationInitializer {
+
+    /**
+     * SpringFramework Context 구동 시, 동작하는 이벤트 기능 (web.xml의 기능을 대체함)
+     *
+     * @author 최정우
+     * @since 2022.08.31
+     */
+    @Override
+    public void onStartup(ServletContext servletContext) throws ServletException {
+
+        AnnotationConfigWebApplicationContext rootContext = new AnnotationConfigWebApplicationContext();
+        rootContext.register(
+            spring.config.RootContextConfig.class,//Root Context
+            spring.config.DataSourceContextConfig.class,//DataSource Context
+            spring.config.MybatisContextConfig.class//Mybatis Context
+        );
+        servletContext.addListener(new ContextLoaderListener(rootContext));
+
+        // Web(Servlet) Context
+        AnnotationConfigWebApplicationContext dispatcherContext = new AnnotationConfigWebApplicationContext();
+        dispatcherContext.register(spring.config.servlet.WebContextConfig.class);
+
+        // Dispatcher Servlet
+        ServletRegistration.Dynamic dispatcher = servletContext.addServlet("dispatcher", new DispatcherServlet(dispatcherContext));
+        dispatcher.setLoadOnStartup(1);
+        dispatcher.addMapping("/");
+
+        // Filter
+        FilterRegistration.Dynamic filter = servletContext.addFilter("encodingFilter", CharacterEncodingFilter.class);
+        filter.setInitParameter("encoding","utf-8");
+        filter.addMappingForServletNames(null,false,"dispatcher");
+    }
+}(No newline at end of file)
 
src/back-end/main/java/spring/config/DataSourceContextConfig.java (added)
+++ src/back-end/main/java/spring/config/DataSourceContextConfig.java
@@ -0,0 +1,46 @@
+package spring.config;
+
+import com.zaxxer.hikari.HikariConfig;
+import com.zaxxer.hikari.HikariDataSource;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+
+/**
+ * DB Connection 자원 관련 Bean 설정 Class
+ * DBCP: HikariCP
+ * JDBC: MariaDB or PostgreSQL
+ *
+ * @author 최정우
+ * @since 2022.09.01
+ */
+@Configuration
+public class DataSourceContextConfig {
+
+    /**
+     * HikariCP(DBCP) Config(설정 세팅) 객체 Bean 설정
+     *
+     * @author 최정우
+     * @since 2022.09.01
+     */
+    @Bean(name = "mainHikariConfig")
+    public HikariConfig getMainHikariConfig () {
+        HikariConfig hikariConfig = new HikariConfig();
+        hikariConfig.setDriverClassName("org.mariadb.jdbc.Driver");
+        hikariConfig.setJdbcUrl("jdbc:mariadb://localhost:3306/test");
+        hikariConfig.setUsername("root");
+        hikariConfig.setPassword("1234");
+        return hikariConfig;
+    }
+
+    /**
+     * HikariCP(DBCP) 객체 Bean 설정
+     *
+     * @author 최정우
+     * @since 2022.09.01
+     */
+    @Bean(name = "mainHikariDataSource")
+    public HikariDataSource getMainHikariDataSource () {
+        HikariDataSource hikariDataSource = new HikariDataSource(getMainHikariConfig());
+        return hikariDataSource;
+    }
+}
 
src/back-end/main/java/spring/config/MybatisContextConfig.java (added)
+++ src/back-end/main/java/spring/config/MybatisContextConfig.java
@@ -0,0 +1,95 @@
+package spring.config;
+
+import com.zaxxer.hikari.HikariDataSource;
+import common.util.bean.BeanUtil;
+import org.apache.ibatis.session.ExecutorType;
+import org.apache.ibatis.session.SqlSessionFactory;
+import org.apache.ibatis.type.TypeAliasRegistry;
+import org.mybatis.spring.SqlSessionFactoryBean;
+import org.mybatis.spring.SqlSessionTemplate;
+import org.mybatis.spring.mapper.MapperScannerConfigurer;
+import org.springframework.context.ApplicationContext;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+
+/**
+ * Mybatis 관련 Bean 설정 Class
+ *
+ * @author 최정우
+ * @since 2022.09.01
+ */
+@Configuration
+//@MapperScan(basePackages = {"kr.co.takensoft"}) <-- 이거 대신 mainMapperScannerConfigurer bean 등록
+public class MybatisContextConfig {
+
+    //Mybatis 동작 설정
+    //mybatis-config.xml 작성 대신 Class 활용
+    private class Configuration extends org.apache.ibatis.session.Configuration {
+        private Configuration() {
+            super();
+            super.setCacheEnabled(true);//mapper 캐시 전역 사용여부
+            super.setLazyLoadingEnabled(false);//mybatis 지연 로딩 사용여부
+            super.setMultipleResultSetsEnabled(true);//한개의 구문에서 여러개의 ResultSet 허용 여부
+            super.setUseColumnLabel(true);//컬럼명 대신 컬럼라벨 사용 여부
+            super.setUseGeneratedKeys(false);//키 자동 생성
+            super.setDefaultExecutorType(ExecutorType.SIMPLE);
+            super.setDefaultStatementTimeout(25000);
+            super.setCallSettersOnNulls(true);//조회 조회시, null값 무조건 허용
+
+            //Mybatis SQL 작성시, 자주 활용하는 Class 별칭 세팅
+            TypeAliasRegistry typeAliasRegistry = super.getTypeAliasRegistry();
+            typeAliasRegistry.registerAlias("Test", kr.co.takensoft.projectName.test.vo.Test.class);
+        }
+    }
+    //Mybatis 동작 설정 객체 생성
+    private Configuration configuration = new Configuration();
+
+    /**
+     * Main
+     * Mapper : SQL이 작성된 문서와, 작성된 SQL을 실행시킬 class(Mapper)를 매핑 시켜주기 위한 객체 Been 설정 (Main)
+     *
+     * @author 최정우
+     * @since 2022.09.01
+     */
+    @Bean(name = "mainMapperScannerConfigurer")
+    public MapperScannerConfigurer getMainMapperScannerConfigurer () {
+        MapperScannerConfigurer mapperScannerConfigurer = null;
+        mapperScannerConfigurer = new MapperScannerConfigurer();
+        mapperScannerConfigurer.setBasePackage("kr.co.takensoft");
+        mapperScannerConfigurer.setAnnotationClass(org.apache.ibatis.annotations.Mapper.class);//Annotation을 지정해 줘야 service interface 를 Mapper라고 인식하지 않음 
+        mapperScannerConfigurer.setSqlSessionTemplateBeanName("mainSqlSessionTemplate");
+        return mapperScannerConfigurer;
+    }
+
+    /**
+     * Main
+     * Mybatis SqlSessionFactory Bean 설정
+     *
+     * @author 최정우
+     * @since 2022.09.01
+     */
+    @Bean(name = "mainSqlSessionFactory")
+    public SqlSessionFactory getMainSqlSessionFactory (ApplicationContext applicationContext) throws Exception {
+        SqlSessionFactoryBean sqlSessionFactoryBean = new SqlSessionFactoryBean();
+        sqlSessionFactoryBean.setDataSource((HikariDataSource) BeanUtil.getBean("mainHikariDataSource"));
+        sqlSessionFactoryBean.setConfiguration(this.configuration);
+        sqlSessionFactoryBean.setMapperLocations(applicationContext.getResources("classpath:mybatis/main/*-SQL.xml"));
+        return sqlSessionFactoryBean.getObject();
+    }
+
+    /**
+     * Main
+     * Mybatis SqlSessionTemplate Bean 설정
+     *
+     * @author 최정우
+     * @since 2022.09.01
+     */
+    @Bean(name = "mainSqlSessionTemplate")
+    public SqlSessionTemplate getMainSqlSessionTemplate (ApplicationContext applicationContext) throws Exception {
+        SqlSessionTemplate sqlSessionTemplate = new SqlSessionTemplate(getMainSqlSessionFactory(applicationContext));
+        return sqlSessionTemplate;
+    }
+
+
+
+}
 
src/back-end/main/java/spring/config/RootContextConfig.java (added)
+++ src/back-end/main/java/spring/config/RootContextConfig.java
@@ -0,0 +1,55 @@
+package spring.config;
+
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.fasterxml.jackson.databind.SerializationFeature;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import common.util.bean.ApplicationContextProvider;
+
+import java.text.SimpleDateFormat;
+import java.util.TimeZone;
+
+/**
+ * 현 프로젝트의 Global 자원 관련 Bean 설정 Class
+ *
+ * @author 최정우
+ * @since 2022.08.31
+ */
+@Configuration
+public class RootContextConfig {
+
+    /**
+     * Spring Application Context 객체 Bean 설정
+     *
+     * @author 최정우
+     * @since 2022.08.31
+     */
+    @Bean(name = "applicationContextProvider")
+    public ApplicationContextProvider getApplicationContextProvider () {
+        ApplicationContextProvider applicationContextProvider = new ApplicationContextProvider();
+        return applicationContextProvider;
+    }
+
+    /**
+     * JSON Parser 라이브러리 Class Bean 설정
+     *
+     * @author 최정우
+     * @since 2022.08.31
+     */
+    @Bean(name = "objectMapper")
+    public ObjectMapper getObjectMapper() {
+        ObjectMapper mapper = new ObjectMapper();
+
+        //기본 날짜 포맷 비활성화
+        mapper.disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS);
+
+        //새로운 날짜 포맷 세팅
+        SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
+        mapper.setDateFormat(dateFormat);
+        mapper.setTimeZone(TimeZone.getTimeZone("Asia/Seoul"));
+
+        return mapper;
+    }
+
+
+}
 
src/back-end/main/java/spring/config/servlet/WebContextConfig.java (added)
+++ src/back-end/main/java/spring/config/servlet/WebContextConfig.java
@@ -0,0 +1,110 @@
+package spring.config.servlet;
+
+import com.fasterxml.jackson.databind.ObjectMapper;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.ComponentScan;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.web.multipart.commons.CommonsMultipartResolver;
+import org.springframework.web.servlet.ViewResolver;
+import org.springframework.web.servlet.config.annotation.EnableWebMvc;
+import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
+import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
+import org.springframework.web.servlet.view.BeanNameViewResolver;
+import org.springframework.web.servlet.view.InternalResourceViewResolver;
+import org.springframework.web.servlet.view.json.MappingJackson2JsonView;
+import common.util.bean.BeanUtil;
+
+import javax.servlet.annotation.MultipartConfig;
+import java.util.HashMap;
+
+/**
+ * Servlet 관련 설정 Class
+ *
+ * @author 최정우
+ * @since 2022.08.31
+ */
+@Configuration
+@EnableWebMvc
+@ComponentScan(basePackages = {"kr.co.takensoft"})
+public class WebContextConfig implements WebMvcConfigurer {
+
+
+    /**
+     * 1. 특정 URL(Path)에 대한 HTTP Request 처리를 DispatcherServlet이 담당하지 않도록 만들어 주는 설정 (html, js, css, file 등..)
+     * 2. Client가 접근하지 못하는 WEB-INF 폴더안에 위치해 있는 정적 자원에 Clien가 접근할 수 있도록 만들어 주는 설정
+     *
+     * @author 최정우
+     * @since 2022.08.31
+     */
+    @Override
+    public void addResourceHandlers(ResourceHandlerRegistry registry) {
+        registry.addResourceHandler("/resources/**").addResourceLocations("/resources/");
+        registry.addResourceHandler("/views/**").addResourceLocations("/views/");
+        //registry.addResourceHandler("/WEB-INF/jsp/**").addResourceLocations("/jsp/");
+    }
+
+    /**
+     * Custom Bean Class ViewResolver를 제공해 주기 위한 Bean (파일 다운로드, JSON 등..)
+     *
+     * @author 최정우
+     * @since 2022.08.31
+     * @return BeanNameViewResolver
+     */
+    @Bean(name="beanView")
+    public BeanNameViewResolver getBeanView () {
+        BeanNameViewResolver beanView = new BeanNameViewResolver();
+        beanView.setOrder(0);
+        return beanView;
+    }
+
+    /**
+     * JSON ViewResolver를 제공해 주기 위한 Bean
+     *
+     * @author 최정우
+     * @since 2022.08.31
+     * @return MappingJackson2JsonView
+     */
+    @Bean(name="jsonView")
+    public MappingJackson2JsonView getJsonView () {
+        ObjectMapper objectMapper = (ObjectMapper) BeanUtil.getBean("objectMapper");
+        MappingJackson2JsonView jsonView = new MappingJackson2JsonView(objectMapper);
+        jsonView.setExtractValueFromSingleKeyModel(true);
+        return jsonView;
+    }
+
+    /**
+     * Multipart Resolver를 제공해 주기 위한 Bean
+     *
+     * @author 최정우
+     * @since 2022.08.31
+     * @return MappingJackson2JsonView
+     */
+    @Bean(name="multipartResolver")
+    public CommonsMultipartResolver getMulltipartResolver  () {
+        CommonsMultipartResolver multipartResolver  = new CommonsMultipartResolver();
+        multipartResolver.setDefaultEncoding("UTF-8");
+        //multipartResolver.setMaxUploadSize(1024 * 1024 * 1024 * 10);//10GB
+        //multipartResolver.setMaxInMemorySize(1024 * 1024 * 1024 * 10);//10GB
+        return multipartResolver;
+    }
+
+    /**
+     * JSP ViewResolver를 제공해 주기 위한 Bean
+     *
+     * @author 최정우
+     * @since 2022.08.31
+     * @return InternalResourceViewResolver
+     */
+    @Bean(name="jspView")
+    public ViewResolver getJspView() {
+        InternalResourceViewResolver jspViewResolver = new InternalResourceViewResolver();
+        jspViewResolver.setPrefix("/WEB-INF/jsp/");
+        jspViewResolver.setSuffix(".jsp");
+        jspViewResolver.setOrder(1);
+        return jspViewResolver;
+    }
+
+
+
+}
 
src/back-end/main/resources/mybatis/main/sample-SQL.xml (added)
+++ src/back-end/main/resources/mybatis/main/sample-SQL.xml
@@ -0,0 +1,35 @@
+<?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">
+
+
+<!--
+	작성자 : 최정우
+	작성일 : 2022.09.01
+	내용 : Sample Mapper 입니다.
+ -->
+<mapper namespace="kr.co.takensoft.projectName.test.dao.TestDAO">
+
+    <!-- resultMap sample
+    <resultMap id="CrawlingSiteResult" type="CrawlingSite">
+        <result property="crawlingSiteSeq" column="crawling_site_seq"/>
+        <result property="site" column="site"/>
+        <collection property="CrawlingChannels" column="{crawlingSiteSeq = crawling_site_seq}" javaType="java.util.ArrayList" ofType="CrawlingChannel" select="getCrawlingChannelList" />
+    </resultMap> -->
+
+    <!--
+        작성자 : 최정우
+        작성일 : 2022.09.01
+        내용 : 데이터 조회 테스트
+     -->
+    <select id="testDataSelectList" parameterType="Test" resultType="Test">
+        SELECT
+            test_id AS testId,
+            title AS title,
+            content AS content,
+            create_user_id AS createUserId,
+            create_datetime AS createDatetime
+        FROM
+            test
+    </select>
+
+</mapper>(No newline at end of file)
 
src/front-end/WEB-INF/web.xml (added)
+++ src/front-end/WEB-INF/web.xml
@@ -0,0 +1,10 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
+         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
+         version="4.0">
+
+    <display-name>spring-legacy-project</display-name>
+
+
+</web-app>
 
src/front-end/resources/js/test.js (added)
+++ src/front-end/resources/js/test.js
@@ -0,0 +1,3 @@
+function test () {
+    console.log('hello world');
+}(No newline at end of file)
 
src/front-end/views/index.html (added)
+++ src/front-end/views/index.html
@@ -0,0 +1,157 @@
+<!DOCTYPE html>
+<html lang="en">
+<head>
+    <meta charset="UTF-8">
+    <title>Index</title>
+</head>
+<body>
+    index
+
+    <p>jsonTestForRequestParam</p>
+    <form method="post" action="/jsonTestForRequestParam">
+        <input type="text" name="name">
+        <input type="text" name="age">
+        <button type="submit">submit</button>
+    </form>
+
+    <p>jsonTestForRequestBody 안됨</p>
+    <form method="post" action="/jsonTestForRequestBody">
+        <input type="text" name="name">
+        <input type="text" name="age">
+        <button type="submit">submit</button>
+    </form>
+
+    <p>jsonTestForMultipart 잘됨</p>
+    <form method="post" action="/jsonTestForMultipart" enctype="multipart/form-data">
+        <input type="text" name="name">
+        <input type="text" name="age">
+        <input type="file" name="file" id="file">
+        <button type="submit">submit</button>
+        <button type="button" onclick="postAjaxMultipartReqeust()">postAjaxMultipartReqeust</button>
+    </form>
+
+    <script>
+        function testDataSelectList () {
+            fetch('/testDataSelectList', {
+                method: "GET",
+                headers: {
+                    'Content-Type': 'application/json; charset=UTF-8'
+                }
+            }).then(function (response) {
+                console.log("testDataSelectList - response:", response);
+                response.json().then(function (data) {
+                    console.log("testDataSelectList - data:", data);
+                })
+            }).catch(function (error) {
+                console.log("testDataSelectList - error", error)
+            });
+        }
+        testDataSelectList();
+
+
+
+        function getAjaxReqeust () {
+            fetch('/jsonTestForRequestParam?method=GET&title=testTitle&age=30', {
+                method: "GET",
+                headers: {
+                    //'Content-Type': 'multipart/form-data; charset=UTF-8'
+                    //'Content-Type': 'application/json; charset=UTF-8'
+                    'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8'
+                }
+            })
+            .then((response) => response.json())
+            .then((data) => console.log("jsonTestForRequestParam - data:", data))
+            .catch((error) => console.log("jsonTestForRequestParam - error:", error));
+        }
+
+
+
+        function postAjaxReqeust () {
+
+            //이건 안됨
+            /*fetch('/jsonTestForRequestParam', {
+                method: "POST",
+                headers: {
+                    //'Content-Type': 'multipart/form-data; charset=UTF-8'
+                    //'Content-Type': 'application/json; charset=UTF-8'
+                    'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8'
+                },
+                body: JSON.stringify({
+                    method: "POST",
+                    title: "testTitlePost",
+                    age: 213,
+                })
+            })
+            .then((response) => response.json())
+            .then((data) => console.log("jsonTestForRequestParam - data:", data))
+            .catch((error) => console.log("jsonTestForRequestParam - error:", error));*/
+
+            //이건 잘됨
+            fetch('/jsonTestForRequestBody', {
+                method: "POST",
+                headers: {
+                    //'Content-Type': 'multipart/form-data; charset=UTF-8'
+                    'Content-Type': 'application/json; charset=UTF-8'
+                    //'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8'
+                },
+                body: JSON.stringify({
+                    method: "POST",
+                    title: "testTitlePost",
+                    age: 213,
+                })
+            })
+            .then((response) => response.json())
+            .then((data) => console.log("jsonTestForRequestParam - data:", data))
+            .catch((error) => console.log("jsonTestForRequestParam - error:", error));
+        }
+
+        function postAjaxMultipartReqeust () {
+            //이거 잘됨
+            let formData = new FormData();
+            formData.append('method', "POST");
+            formData.append('title', "testTitlePost");
+            formData.append('age', 22);
+            let fileInput = document.getElementById('file');
+            for (let i = 0; i < fileInput.files.length; i++) {
+                formData.append('files', fileInput.files[i]);
+            }
+            //이거 잘됨 (단, progress를 활용 못함)
+            /*fetch('/jsonTestForMultipart', {
+                method: "POST",
+                headers: {
+                    //'Content-Type': 'multipart/form-data' 이거 안됨. 왜 안되냐 하면, fetch api로 formData를 보낼때 헤더를 설정 하지 말아야 하고, 그 이유는 헤더에 자동으로 Content-Type:multipart/form-data; boundary=----WebKitFormBoundaryMJtHYBc9ERyjdAy8 세팅된다고 함
+                    //'Content-Type': 'application/json; charset=UTF-8' 이거 안됨(당연)
+                    //'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8' 이거 안됨(당연)
+                },
+                body: formData
+            })
+            .then((response) => response.json())
+            .then((data) => console.log("jsonTestForMultipart - data:", data))
+            .catch((error) => console.log("jsonTestForMultipart - error:", error));*/
+
+            //이거 잘됨 (progress 활용 가능)
+            let request = new XMLHttpRequest();
+            request.open('POST', '/jsonTestForMultipart');
+            // upload progress event
+            request.upload.addEventListener('progress', function(e) {
+                // upload progress as percentage
+                let percent_completed = (e.loaded / e.total)*100;
+                console.log(percent_completed);
+            });
+            // request finished event
+            request.addEventListener('load', function(e) {
+                // HTTP status message (200, 404 etc)
+                console.log('request.status : ', request.status);
+
+                // request.response holds response from the server
+                console.log('request.response : ', request.response);
+            });
+            // send POST request to server
+            request.send(formData);
+        }
+
+        //getAjaxReqeust();
+        //postAjaxReqeust();
+    </script>
+</body>
+</html>(No newline at end of file)
Add a comment
List