

220902 최정우 최초 커밋
@73e16e94a11ecf3e0ce80eb2a33c48fb9399199f
+++ pom.xml
... | ... | @@ -0,0 +1,269 @@ |
1 | +<?xml version="1.0" encoding="UTF-8"?> | |
2 | +<!-- | |
3 | + Maven 빌드 과정 | |
4 | + 0. Commend / Powershell / Terminal 창 켜기 | |
5 | + 1. pom.xml이 존재하는 프로젝트 경로로 이동 | |
6 | + 2. mvn clean (빌드를 하기전 빌드 결과 위치를 비우는 명령어) | |
7 | + 3. mvn compile (Maven을 활용한 빌드 진행) | |
8 | + 4. mvn package (Maven을 활용한 패키지 진행) | |
9 | +--> | |
10 | +<!-- | |
11 | + 작성자: 최정우 | |
12 | + 작성일: 220831 | |
13 | + 내용 : Maven Spring Legacy Proejct 세팅 | |
14 | +--> | |
15 | +<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" | |
16 | + xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/maven-v4_0_0.xsd"> | |
17 | + | |
18 | + <modelVersion>4.0.0</modelVersion><!-- modelVersion: Maven POM의 버전 --> | |
19 | + <groupId>kr.co.takensoft</groupId><!-- groupId: 기관(소속) 식별자 --> | |
20 | + <artifactId>spring-legacy-project</artifactId><!-- artifactId: 현재 project의 식별자 --> | |
21 | + <name>project-name</name><!-- name: 현재 project의 명칭 --> | |
22 | + <packaging>war</packaging><!-- packaging: 어떤 파일 형식으로 패키징할 것인가를 정의, jar, war, exe 등이 올 수 있음 --> | |
23 | + <version>1.0.0-BUILD-SNAPSHOT</version><!-- version: 해당 artifact(컴포넌트)의 version, 뒤쪽 SNAPSHOT은 아직 개발 중임을 의미함 --> | |
24 | + | |
25 | + <!-- properties: POM.xml에서 사용할 변수 --> | |
26 | + <properties> | |
27 | + <java-version>15</java-version> | |
28 | + <org.springframework.version>5.3.22</org.springframework.version> | |
29 | + <egovframework.rte.version>3.10.0</egovframework.rte.version> | |
30 | + | |
31 | + <back-end-path>${project.basedir}/src/back-end</back-end-path> | |
32 | + <front-end-path>${project.basedir}/src/front-end</front-end-path> | |
33 | + </properties> | |
34 | + | |
35 | + <!-- repositories: 라이브러리를 다운로드 받을 위치들을 설정 하는 곳 --> | |
36 | + <repositories> | |
37 | + <!-- repository: 라이브러리를 다운로드 받을 위치 설정, 기술되지 않을 시 기본적인 위치: https://repo1.maven.org/maven2/ --> | |
38 | + <!-- Apache재단 Maven 의존성 라이브러리 저장소 --> | |
39 | + <repository> | |
40 | + <id>mvn2s</id> | |
41 | + <url>https://repo1.maven.org/maven2/</url> | |
42 | + <releases> | |
43 | + <enabled>true</enabled> | |
44 | + </releases> | |
45 | + <snapshots> | |
46 | + <enabled>true</enabled> | |
47 | + </snapshots> | |
48 | + </repository> | |
49 | + <!-- 전자정부프레임워크 Maven 의존성 라이브러리 저장소 --> | |
50 | + <repository> | |
51 | + <id>egovframe</id> | |
52 | + <url>https://repo.maven.apache.org/maven2/</url> | |
53 | + <releases> | |
54 | + <enabled>true</enabled> | |
55 | + </releases> | |
56 | + <snapshots> | |
57 | + <enabled>false</enabled> | |
58 | + </snapshots> | |
59 | + </repository> | |
60 | + </repositories> | |
61 | + | |
62 | + <!-- dependencies: 의존성 라이브러리들을 설정하는 곳 --> | |
63 | + <dependencies> | |
64 | + | |
65 | + <!-- servlet 라이브러리 --> | |
66 | + <dependency> | |
67 | + <groupId>javax.servlet</groupId> | |
68 | + <artifactId>javax.servlet-api</artifactId> | |
69 | + <version>4.0.1</version> | |
70 | + <scope>provided</scope> | |
71 | + </dependency> | |
72 | + | |
73 | + <!-- Spring Framwork 라이브러리 - 해당 라이브러리 다운로드 시 core, context, beans, expression, web, aop, jcl 이 같이 다운 받아짐 --> | |
74 | + <dependency> | |
75 | + <groupId>org.springframework</groupId> | |
76 | + <artifactId>spring-webmvc</artifactId> | |
77 | + <version>${org.springframework.version}</version> | |
78 | + </dependency> | |
79 | + <!-- Spring Framwork JDBC 라이브러리 - 특정 JDBC를 Bean 등록 해야 한다면 꼭 필요 함 --> | |
80 | + <dependency> | |
81 | + <groupId>org.springframework</groupId> | |
82 | + <artifactId>spring-jdbc</artifactId> | |
83 | + <version>${org.springframework.version}</version> | |
84 | + </dependency> | |
85 | + | |
86 | + <!-- JSON Parsing 라이브러리 - 해당 라이브러리 다운로드 시 core, annotations 이 같이 다운 받아짐 --> | |
87 | + <dependency> | |
88 | + <groupId>com.fasterxml.jackson.core</groupId> | |
89 | + <artifactId>jackson-databind</artifactId> | |
90 | + <version>2.13.3</version> | |
91 | + </dependency> | |
92 | + | |
93 | + <!-- 시스템 입출력(파일 포함) --> | |
94 | + <dependency> | |
95 | + <groupId>commons-io</groupId> | |
96 | + <artifactId>commons-io</artifactId> | |
97 | + <version>2.11.0</version> | |
98 | + </dependency> | |
99 | + <!-- 파일업로드 --> | |
100 | + <dependency> | |
101 | + <groupId>commons-fileupload</groupId> | |
102 | + <artifactId>commons-fileupload</artifactId> | |
103 | + <version>1.4</version> | |
104 | + <exclusions> | |
105 | + <exclusion> | |
106 | + <artifactId>commons-io</artifactId> | |
107 | + <groupId>commons-io</groupId> | |
108 | + </exclusion> | |
109 | + </exclusions> | |
110 | + </dependency> | |
111 | + | |
112 | + <!-- SQL 작성 및 DBCP, JDBC 인터페이스 기능 담당 라이브러리 Mybatis --> | |
113 | + <dependency> | |
114 | + <groupId>org.mybatis</groupId> | |
115 | + <artifactId>mybatis</artifactId> | |
116 | + <version>3.5.10</version> | |
117 | + </dependency> | |
118 | + <!-- SQL 작성 및 DBCP, JDBC 인터페이스 기능 담당 라이브러리 Mybatis(SpringFramework와 인터페이스 용) - 해당 라이브러리 활용 시 의존성 라이브러리's mybatis, spring-context, spring-jdbc, spring-batch-infrastructure --> | |
119 | + <dependency> | |
120 | + <groupId>org.mybatis</groupId> | |
121 | + <artifactId>mybatis-spring</artifactId> | |
122 | + <version>2.0.7</version> | |
123 | + </dependency> | |
124 | + | |
125 | + | |
126 | + <!-- DB Connection Pool : HikariCP --> | |
127 | + <dependency> | |
128 | + <groupId>com.zaxxer</groupId> | |
129 | + <artifactId>HikariCP</artifactId> | |
130 | + <version>5.0.1</version> | |
131 | + </dependency> | |
132 | + | |
133 | + <!-- JDBC : MariaDB --> | |
134 | + <dependency> | |
135 | + <groupId>org.mariadb.jdbc</groupId> | |
136 | + <artifactId>mariadb-java-client</artifactId> | |
137 | + <version>3.0.7</version> | |
138 | + </dependency> | |
139 | + <!-- JDBC : PostgreSQL --> | |
140 | + <dependency> | |
141 | + <groupId>org.postgresql</groupId> | |
142 | + <artifactId>postgresql</artifactId> | |
143 | + <version>42.5.0</version> | |
144 | + </dependency> | |
145 | + | |
146 | + | |
147 | + <!-- POI - Excel 관련 라이브러리 (2007년 이후 버전) --> | |
148 | + <dependency> | |
149 | + <groupId>org.apache.poi</groupId> | |
150 | + <artifactId>poi-ooxml</artifactId> | |
151 | + <version>5.2.2</version> | |
152 | + </dependency> | |
153 | + <!-- POI - Excel 관련 라이브러리 (2007년 이전 버전) --> | |
154 | + <dependency> | |
155 | + <groupId>org.apache.poi</groupId> | |
156 | + <artifactId>poi</artifactId> | |
157 | + <version>5.2.2</version> | |
158 | + </dependency> | |
159 | + | |
160 | + | |
161 | + <!-- File 바이너리 데이터의 MIME 관련 라이브러리 --> | |
162 | + <dependency> | |
163 | + <groupId>javax.activation</groupId> | |
164 | + <artifactId>activation</artifactId> | |
165 | + <version>1.1.1</version> | |
166 | + </dependency> | |
167 | + | |
168 | + <!-- E-Mail 관련 라이브러리 --> | |
169 | + <dependency> | |
170 | + <groupId>javax.mail</groupId> | |
171 | + <artifactId>mail</artifactId> | |
172 | + <version>1.4.7</version> | |
173 | + </dependency> | |
174 | + | |
175 | + | |
176 | + | |
177 | + | |
178 | + | |
179 | + <!-- 표준프레임워크 실행환경 (시작) --> | |
180 | + <!--<dependency> | |
181 | + <groupId>egovframework.rte</groupId> | |
182 | + <artifactId>egovframework.rte.ptl.mvc</artifactId> | |
183 | + <version>${egovframework.rte.version}</version> | |
184 | + </dependency> | |
185 | + <dependency> | |
186 | + <groupId>egovframework.rte</groupId> | |
187 | + <artifactId>egovframework.rte.psl.dataaccess</artifactId> | |
188 | + <version>${egovframework.rte.version}</version> | |
189 | + </dependency> | |
190 | + <dependency> | |
191 | + <groupId>egovframework.rte</groupId> | |
192 | + <artifactId>egovframework.rte.fdl.idgnr</artifactId> | |
193 | + <version>${egovframework.rte.version}</version> | |
194 | + </dependency> | |
195 | + <dependency> | |
196 | + <groupId>egovframework.rte</groupId> | |
197 | + <artifactId>egovframework.rte.fdl.property</artifactId> | |
198 | + <version>${egovframework.rte.version}</version> | |
199 | + </dependency> | |
200 | + <dependency> | |
201 | + <groupId>egovframework.rte</groupId> | |
202 | + <artifactId>egovframework.rte.fdl.crypto</artifactId> | |
203 | + <version>${egovframework.rte.version}</version> | |
204 | + </dependency>--> | |
205 | + <!--<dependency> | |
206 | + <groupId>org.jetbrains</groupId> | |
207 | + <artifactId>annotations</artifactId> | |
208 | + <version>RELEASE</version> | |
209 | + <scope>compile</scope> | |
210 | + </dependency>--> | |
211 | + <!-- 표준프레임워크 실행환경 (끝) --> | |
212 | + | |
213 | + </dependencies> | |
214 | + | |
215 | + | |
216 | + <!-- build: Compile ~ Depoly에 대한 과정을 설정하는 곳 --> | |
217 | + <build> | |
218 | + <!-- finalName: 최종 packaging된 file의 이름 --> | |
219 | + <finalName>ROOT</finalName> | |
220 | + <!-- directory: 빌드 경로 (다른 곳에서 ${deploy.path} 활용하면 됨) --> | |
221 | + <directory>${project.basedir}/target</directory> | |
222 | + <!-- sourceDirectory: Java 소스 경로 --> | |
223 | + <sourceDirectory>${back-end-path}/main/java</sourceDirectory> | |
224 | + <!-- testSourceDirectory: Test용 Java 소스 경로 --> | |
225 | + <testSourceDirectory>${back-end-path}/test/java</testSourceDirectory> | |
226 | + <!-- outputDirectory: 컴파일 후 .class 파일 저장 경로 --> | |
227 | + <outputDirectory>${build.directory}/classes</outputDirectory> | |
228 | + | |
229 | + <!-- resources: JAVA File 이외의 자원들을 classpath로 설정하기 위한 곳 --> | |
230 | + <resources> | |
231 | + <resource> | |
232 | + <directory>${project.basedir}/src/main/resources</directory> | |
233 | + </resource> | |
234 | + </resources> | |
235 | + | |
236 | + <!-- plugins: Maven Plugin을 설정하는 곳 --> | |
237 | + <plugins> | |
238 | + <!-- maven compile plugin --> | |
239 | + <plugin> | |
240 | + <groupId>org.apache.maven.plugins</groupId> | |
241 | + <artifactId>maven-compiler-plugin</artifactId> | |
242 | + <version>3.10.1</version> | |
243 | + <configuration> | |
244 | + <source>${java-version}</source><!-- 소스코드 Java 버전 --> | |
245 | + <target>${java-version}</target><!-- compile시 결과물 Java 버전 --> | |
246 | + </configuration> | |
247 | + </plugin> | |
248 | + <!-- maven war package plugin --> | |
249 | + <plugin> | |
250 | + <groupId>org.apache.maven.plugins</groupId> | |
251 | + <artifactId>maven-war-plugin</artifactId> | |
252 | + <version>3.3.2</version> | |
253 | + <configuration> | |
254 | + <!-- webResources: web 관련 자원들의 (html, js, css 등..) 경로 --> | |
255 | + <webResources> | |
256 | + <resource> | |
257 | + <directory>${front-end-path}</directory> | |
258 | + </resource> | |
259 | + </webResources> | |
260 | + <!-- webappDirectory: package된 후 web관련 자원들이 배포될 경로 --> | |
261 | + <!-- <webappDirectory>${build.directory}</webappDirectory>--> | |
262 | + <!-- web.xml 경로 --> | |
263 | + <webXml>${project.basedir}/src/front-end/WEB-INF/web.xml</webXml> | |
264 | + </configuration> | |
265 | + </plugin> | |
266 | + </plugins> | |
267 | + </build> | |
268 | + | |
269 | +</project> |
+++ src/back-end/main/java/common/util/AsyncUtil.java
... | ... | @@ -0,0 +1,36 @@ |
1 | +package common.util; | |
2 | + | |
3 | +import common.util.reflection.ReflectionUtil; | |
4 | + | |
5 | +public class AsyncUtil implements Runnable { | |
6 | + | |
7 | + String classFilePath, packageName, className, methodName; | |
8 | + Object[] paramValues; | |
9 | + Class<?>[] paramTypes; | |
10 | + | |
11 | + public AsyncUtil (String classFilePath, String packageName, String className, String methodName, Object[] paramValues, Class<?>[] paramTypes) { | |
12 | + this.classFilePath = classFilePath; | |
13 | + this.packageName = packageName; | |
14 | + this.className = className; | |
15 | + this.methodName = methodName; | |
16 | + this.paramValues = paramValues; | |
17 | + this.paramTypes = paramTypes; | |
18 | + } | |
19 | + | |
20 | + public AsyncUtil (String packageName, String className, String methodName, Object[] paramValues, Class<?>[] paramTypes) { | |
21 | + this.packageName = packageName; | |
22 | + this.className = className; | |
23 | + this.methodName = methodName; | |
24 | + this.paramValues = paramValues; | |
25 | + this.paramTypes = paramTypes; | |
26 | + } | |
27 | + | |
28 | + @Override | |
29 | + public void run () { | |
30 | + //객체 생성 | |
31 | + Object clazz = ReflectionUtil.classAndBeanLoad(classFilePath, (packageName + "." + className)); | |
32 | + //메서드 실행 | |
33 | + ReflectionUtil.invokeByMethodName(clazz, methodName, paramValues, paramTypes); | |
34 | + } | |
35 | + | |
36 | +} |
+++ src/back-end/main/java/common/util/AuthUtil.java
... | ... | @@ -0,0 +1,30 @@ |
1 | +package common.util; | |
2 | + | |
3 | +import common.vo.User; | |
4 | + | |
5 | +import javax.servlet.http.HttpSession; | |
6 | + | |
7 | +public class AuthUtil { | |
8 | + | |
9 | + public static final String LOGIN_USER_SESSION_KEY = "loginUser"; | |
10 | + | |
11 | + public static final int SESSION_MAX_TIME = 60*60*1;//1시간 | |
12 | + | |
13 | + public static User getLoginUser () { | |
14 | + try { | |
15 | + //현재 client의 HttpSession 조회 | |
16 | + HttpSession session = CommonUtil.getHttpSession(false); | |
17 | + if(session == null || session.getAttribute(LOGIN_USER_SESSION_KEY) == null | |
18 | + || ((User) session.getAttribute(LOGIN_USER_SESSION_KEY)).getUserId() == null) { | |
19 | + return null; | |
20 | + }else { | |
21 | + return (User) session.getAttribute(LOGIN_USER_SESSION_KEY); | |
22 | + } | |
23 | + } catch(Exception e) { | |
24 | + System.out.println("AuthUtil getLoginUser Error : "); | |
25 | + e.printStackTrace(); | |
26 | + return null; | |
27 | + } | |
28 | + } | |
29 | + | |
30 | +} |
+++ src/back-end/main/java/common/util/CommendUtil.java
... | ... | @@ -0,0 +1,54 @@ |
1 | +package common.util; | |
2 | + | |
3 | +import java.io.BufferedReader; | |
4 | +import java.io.InputStreamReader; | |
5 | +import java.util.concurrent.TimeUnit; | |
6 | + | |
7 | +public class CommendUtil{ | |
8 | + | |
9 | + public String commend (String commendLine) throws Exception { | |
10 | + String[] commend = {"", "", commendLine}; | |
11 | + if (System.getProperty("os.name").indexOf("Windows") > -1) { | |
12 | + commend[0] = "cmd.exe"; | |
13 | + commend[1] = "/C"; | |
14 | + } else { | |
15 | + commend[0] = "/bin/sh"; | |
16 | + commend[1] = "-c"; | |
17 | + }//명령어 준비 끝 | |
18 | + | |
19 | + CountUtil countUtil = new CountUtil(); | |
20 | + Thread thread = new Thread(countUtil); | |
21 | + | |
22 | + Process process = Runtime.getRuntime().exec(commend); | |
23 | + thread.start(); | |
24 | + | |
25 | + boolean isComplete = process.waitFor(10000, TimeUnit.SECONDS); | |
26 | + countUtil.processEnd(); | |
27 | + | |
28 | + StringBuilder sb = new StringBuilder(); | |
29 | + BufferedReader resultBufferReader = null; | |
30 | + BufferedReader errorBufferReader = null; | |
31 | + if (isComplete == true) { | |
32 | + String msg = null; | |
33 | + resultBufferReader = new BufferedReader(new InputStreamReader(process.getInputStream(), "EUC-KR")); | |
34 | + while ((msg = resultBufferReader.readLine()) != null) { | |
35 | + if (msg.contains(System.getProperty("line.separator")) == false) { | |
36 | + System.out.println(msg); | |
37 | + sb.append(msg); | |
38 | + } | |
39 | + } | |
40 | + errorBufferReader = new BufferedReader(new InputStreamReader(process.getErrorStream(), "EUC-KR")); | |
41 | + int err_count = 0; | |
42 | + while ((msg = errorBufferReader.readLine()) != null) { | |
43 | + if (msg.contains(System.getProperty("line.separator")) == false) { | |
44 | + System.out.println(msg); | |
45 | + sb.append(msg); | |
46 | + } | |
47 | + } | |
48 | + } else { | |
49 | + System.out.println("COMMAND : " + commend[2] + " - Timeout(" + 10000 + "초)"); | |
50 | + } | |
51 | + | |
52 | + return sb.toString(); | |
53 | + } | |
54 | +} |
+++ src/back-end/main/java/common/util/CommonUtil.java
... | ... | @@ -0,0 +1,1250 @@ |
1 | +package common.util; | |
2 | + | |
3 | +import org.springframework.web.context.request.RequestContextHolder; | |
4 | +import org.springframework.web.context.request.ServletRequestAttributes; | |
5 | + | |
6 | +import javax.servlet.http.HttpServletRequest; | |
7 | +import javax.servlet.http.HttpSession; | |
8 | +import java.io.IOException; | |
9 | +import java.io.PrintWriter; | |
10 | +import java.io.StringWriter; | |
11 | +import java.lang.reflect.Field; | |
12 | +import java.lang.reflect.Modifier; | |
13 | +import java.net.InetAddress; | |
14 | +import java.net.InetSocketAddress; | |
15 | +import java.net.Socket; | |
16 | +import java.net.UnknownHostException; | |
17 | +import java.sql.Timestamp; | |
18 | +import java.text.SimpleDateFormat; | |
19 | +import java.time.LocalDateTime; | |
20 | +import java.util.*; | |
21 | + | |
22 | + | |
23 | +public class CommonUtil { | |
24 | + | |
25 | + /** | |
26 | + * @author 최정우 | |
27 | + * @since 2019.12.11 | |
28 | + * | |
29 | + * 데이터의 표준화 사용 유무 | |
30 | + */ | |
31 | + private static boolean IS_USE_STANDARD = true; | |
32 | + | |
33 | + public static void setIsUseStandard (boolean isUseStandard) { | |
34 | + IS_USE_STANDARD = isUseStandard; | |
35 | + } | |
36 | + | |
37 | + public static boolean getIsUseStandard () { | |
38 | + return IS_USE_STANDARD; | |
39 | + } | |
40 | + | |
41 | + /** | |
42 | + * @author 최정우 | |
43 | + * @since 2019.11.13 | |
44 | + * | |
45 | + * 빈 문자열 검사 | |
46 | + */ | |
47 | + public static boolean isNull(Object obj) { | |
48 | + return obj == null; | |
49 | + } | |
50 | + | |
51 | + | |
52 | + /** | |
53 | + * @author 최정우 | |
54 | + * @since 2019.11.13 | |
55 | + * | |
56 | + * string to int check | |
57 | + */ | |
58 | + public static boolean isInt (String text) { | |
59 | + try { | |
60 | + Integer.parseInt(text); | |
61 | + return true; | |
62 | + } catch(NumberFormatException e) { | |
63 | + return false; | |
64 | + } | |
65 | + } | |
66 | + | |
67 | + /** | |
68 | + * @author 최정우 | |
69 | + * @since 2019.11.13 | |
70 | + * | |
71 | + * string to int check | |
72 | + */ | |
73 | + public static boolean isLong (String text) { | |
74 | + try { | |
75 | + Long.parseLong(text); | |
76 | + return true; | |
77 | + } catch(NumberFormatException e) { | |
78 | + return false; | |
79 | + } | |
80 | + } | |
81 | + | |
82 | + /** | |
83 | + * @author 최정우 | |
84 | + * @since 2019.11.13 | |
85 | + * | |
86 | + * string to double check | |
87 | + */ | |
88 | + public static boolean isDouble (String text) { | |
89 | + try { | |
90 | + Double.parseDouble(text); | |
91 | + return true; | |
92 | + } catch (NumberFormatException e) { | |
93 | + return false; | |
94 | + } catch (Exception e) { | |
95 | + return false; | |
96 | + } | |
97 | + } | |
98 | + | |
99 | + /** | |
100 | + * @author 최정우 | |
101 | + * @since 2020.01.08 | |
102 | + * | |
103 | + * object to int | |
104 | + */ | |
105 | + public static int parseInt (Object obj) { | |
106 | + try { | |
107 | + return Integer.parseInt(obj.toString()); | |
108 | + } catch(Exception e) { | |
109 | + return 0; | |
110 | + } | |
111 | + } | |
112 | + | |
113 | + /** | |
114 | + * @author 최정우 | |
115 | + * @since 2020.01.08 | |
116 | + * | |
117 | + * string to int | |
118 | + */ | |
119 | + public static int parseInt (String text) { | |
120 | + try { | |
121 | + return Integer.parseInt(text); | |
122 | + } catch(NumberFormatException e) { | |
123 | + return 0; | |
124 | + } | |
125 | + } | |
126 | + | |
127 | + /** | |
128 | + * @author 최정우 | |
129 | + * @since 2020.01.08 | |
130 | + * | |
131 | + * int to double | |
132 | + */ | |
133 | + public static long parseLong (int number) { | |
134 | + try { | |
135 | + return (long) number; | |
136 | + } catch(Exception e) { | |
137 | + return 0; | |
138 | + } | |
139 | + } | |
140 | + | |
141 | + /** | |
142 | + * @author 최정우 | |
143 | + * @since 2020.01.08 | |
144 | + * | |
145 | + * object to double | |
146 | + */ | |
147 | + public static long parseLong (String text) { | |
148 | + try { | |
149 | + return Long.parseLong(text); | |
150 | + } catch(Exception e) { | |
151 | + return 0; | |
152 | + } | |
153 | + } | |
154 | + | |
155 | + /** | |
156 | + * @author 최정우 | |
157 | + * @since 2020.01.08 | |
158 | + * | |
159 | + * object to double | |
160 | + */ | |
161 | + public static long parseLong (Object obj) { | |
162 | + try { | |
163 | + if (obj instanceof Integer) { | |
164 | + return (long) obj; | |
165 | + } else { | |
166 | + return Long.parseLong(obj.toString()); | |
167 | + } | |
168 | + } catch(Exception e) { | |
169 | + return 0; | |
170 | + } | |
171 | + } | |
172 | + | |
173 | + /** | |
174 | + * @author 최정우 | |
175 | + * @since 2020.01.08 | |
176 | + * | |
177 | + * int to double | |
178 | + */ | |
179 | + public static double parseDouble (int number) { | |
180 | + try { | |
181 | + return (double) number; | |
182 | + } catch(Exception e) { | |
183 | + return 0.0; | |
184 | + } | |
185 | + } | |
186 | + | |
187 | + /** | |
188 | + * @author 최정우 | |
189 | + * @since 2020.01.08 | |
190 | + * | |
191 | + * object to double | |
192 | + */ | |
193 | + public static double parseDouble (String text) { | |
194 | + try { | |
195 | + return Double.parseDouble(text); | |
196 | + } catch(Exception e) { | |
197 | + return 0.0; | |
198 | + } | |
199 | + } | |
200 | + | |
201 | + /** | |
202 | + * @author 최정우 | |
203 | + * @since 2020.01.08 | |
204 | + * | |
205 | + * object to double | |
206 | + */ | |
207 | + public static double parseDouble (Object obj) { | |
208 | + try { | |
209 | + if (obj instanceof Integer) { | |
210 | + return (double) obj; | |
211 | + } else { | |
212 | + return Double.parseDouble(obj.toString()); | |
213 | + } | |
214 | + } catch(Exception e) { | |
215 | + return 0.0; | |
216 | + } | |
217 | + } | |
218 | + | |
219 | + /** | |
220 | + * @author 최정우 | |
221 | + * @since 2019.11.13 | |
222 | + * | |
223 | + * 문자열의 모든 공백 제거 | |
224 | + */ | |
225 | + public static String allTrim(String text) { | |
226 | + return text.replaceAll("\\p{Z}", ""); | |
227 | + } | |
228 | + | |
229 | + /** | |
230 | + * @author 최정우 | |
231 | + * @since 2019.11.13 | |
232 | + * | |
233 | + * 문자열 앞뒤 공백 제거후, 문자열 사이에 존재하는 공백을 한개의 공백으로 치환 | |
234 | + * ex) " abcd efg hijk " => "abcd efg hijk" | |
235 | + */ | |
236 | + public static String normalizeSpace(String text) { | |
237 | + return text.trim().replaceAll("\\s+", " "); | |
238 | + } | |
239 | + | |
240 | + /** | |
241 | + * @author 최정우 | |
242 | + * @since 2019.11.13 | |
243 | + * | |
244 | + * 숫자 빼고 모든 문자 제거 | |
245 | + */ | |
246 | + public static String getOnlyNumber (String text) { | |
247 | + return text.replaceAll("[^0-9]", ""); | |
248 | + } | |
249 | + | |
250 | + /** | |
251 | + * @author 최정우 | |
252 | + * @since 2019.11.13 | |
253 | + * | |
254 | + * 문자 빼고 모든 숫자 제거 | |
255 | + */ | |
256 | + public static String getOnlyText (String text) { | |
257 | + return text.replaceAll("[0-9]", ""); | |
258 | + } | |
259 | + | |
260 | + /** | |
261 | + * @author 최정우 | |
262 | + * @since 2019.11.13 | |
263 | + * | |
264 | + * 특정 문자열 개수 check | |
265 | + */ | |
266 | + public static int getWordCount (String text, String word) { | |
267 | + int size = 0; | |
268 | + int fromIndex = -1; | |
269 | + while ((fromIndex = text.indexOf(word, fromIndex + 1)) >= 0) { | |
270 | + size++; | |
271 | + } | |
272 | + return size; | |
273 | + } | |
274 | + | |
275 | + /** | |
276 | + * @author 최정우 | |
277 | + * @since 2021.12.05 | |
278 | + * | |
279 | + * 현재 서버 일시 구하기 | |
280 | + */ | |
281 | + public static Date getDateTime() { | |
282 | + LocalDateTime localDateTime = LocalDateTime.now(); | |
283 | + return Timestamp.valueOf(localDateTime); | |
284 | + } | |
285 | + | |
286 | + /** | |
287 | + * @author 최정우 | |
288 | + * @since 2019.11.13 | |
289 | + * | |
290 | + * 문자열 to Date문자열 | |
291 | + */ | |
292 | + public static boolean isDate (String text) { | |
293 | + if (StringUtil.isEmpty(text) == true || StringUtil.isEmpty(getOnlyNumber(text)) == true || getOnlyNumber(text).length() < 6) { | |
294 | + return false; | |
295 | + } | |
296 | + | |
297 | + //공백을 제외한 문자얻기, 대문자로 치환 | |
298 | + String newText = allTrim(text).toUpperCase(); | |
299 | + | |
300 | + try { | |
301 | + //문자열의 날짜 패턴 생성 | |
302 | + String pattern = createDatePattern(newText); | |
303 | + if (pattern == null) { | |
304 | + return false; | |
305 | + } | |
306 | + | |
307 | + SimpleDateFormat newPattern = new SimpleDateFormat(pattern); | |
308 | + //문자열 날짜 형태로 변환 | |
309 | + newPattern.parse(newText); | |
310 | + return true; | |
311 | + } catch (Exception e) { | |
312 | + //e.printStackTrace(); | |
313 | + return false; | |
314 | + } | |
315 | + } | |
316 | + | |
317 | + /** | |
318 | + * @author 최정우 | |
319 | + * @since 2019.11.13 | |
320 | + * | |
321 | + * 문자열 to Date문자열 | |
322 | + */ | |
323 | + public static String parseDateText (String text) { | |
324 | + if (StringUtil.isEmpty(text) == true || StringUtil.isEmpty(getOnlyNumber(text)) == true || getOnlyNumber(text).length() < 6) { | |
325 | + return null; | |
326 | + } | |
327 | + | |
328 | + //공백을 제외한 문자얻기, 대문자로 치환 | |
329 | + String newText = allTrim(text).toUpperCase(); | |
330 | + | |
331 | + //문자열의 날짜 패턴 생성 | |
332 | + String pattern = createDatePattern(newText); | |
333 | + if (pattern == null) { | |
334 | + return null; | |
335 | + } | |
336 | + | |
337 | + Date date = null; | |
338 | + String dateText = null; | |
339 | + try { | |
340 | + SimpleDateFormat newPattern = new SimpleDateFormat(pattern); | |
341 | + | |
342 | + //문자열 날짜 형태로 변환 | |
343 | + date = newPattern.parse(newText); | |
344 | + | |
345 | + //DB에 저장할 날짜 패턴 | |
346 | + SimpleDateFormat defalutPattern = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); | |
347 | + dateText = defalutPattern.format(date); | |
348 | + } catch (Exception e) { | |
349 | + //e.printStackTrace(); | |
350 | + } | |
351 | + return dateText; | |
352 | + } | |
353 | + | |
354 | + public static <T> List<T> mapToList (Map<?, T> map) { | |
355 | + List<T> items = new ArrayList<T>(); | |
356 | + | |
357 | + if (map != null) { | |
358 | + for(Map.Entry<?, T> item : map.entrySet()) { | |
359 | + items.add(item.getValue()); | |
360 | + } | |
361 | + } | |
362 | + | |
363 | + return items; | |
364 | + } | |
365 | + | |
366 | + public static Map objectToMap(Object obj) { | |
367 | + if (obj != null) { | |
368 | + try { | |
369 | + return (Map) obj; | |
370 | + } catch (Exception e) { | |
371 | + return new HashMap(); | |
372 | + } | |
373 | + } else { | |
374 | + return new HashMap(); | |
375 | + } | |
376 | + } | |
377 | + | |
378 | + | |
379 | + /* | |
380 | + * 시간 타입 | |
381 | + * PM, AM | |
382 | + */ | |
383 | + public final static List<String> TIME_TYPES = Arrays.asList(new String[] {"AM", "PM", "오전", "오후"}); | |
384 | + | |
385 | + /* | |
386 | + * 날짜 포맷 패턴's | |
387 | + */ | |
388 | + public final static List<Character> DATE_PATTERNS = Arrays.asList(new Character[] {'y', 'M', 'd', 'H', 'm', 's'}); | |
389 | + | |
390 | + /* | |
391 | + * 날짜 포맷 패턴's의 최대 문자열 수 | |
392 | + */ | |
393 | + public final static List<Integer> DATE_PATTERNS_MAX_LENGTH = Arrays.asList(new Integer[] {4, 2, 2, 2, 2, 2}); | |
394 | + | |
395 | + /** | |
396 | + * @author 최정우 | |
397 | + * @since 2019.11.13 | |
398 | + * | |
399 | + * 문자열의 날짜 패턴 생성 | |
400 | + */ | |
401 | + public static String createDatePattern (String date) { | |
402 | + | |
403 | + List<Character> DATE_PATTERNS = Arrays.asList(new Character[] {'y', 'M', 'd', 'H', 'm', 's'}); | |
404 | + | |
405 | + //시간 표기가 (0~12 -> AM, PM사용)인지 (0~23)인지 확인 후, 날짜 포맷 패턴's에 있는 시간 패턴 변경 | |
406 | + int timeTypeFindIndex = -1; | |
407 | + for (int i = 0; i < TIME_TYPES.size(); i++) { | |
408 | + //("AM", "PM", "오전", "오후" 중 1개)가 포함된 단어가 있는지 확인, Index 위치를 담기(없으면 -1) | |
409 | + if ((timeTypeFindIndex = date.indexOf(TIME_TYPES.get(i))) > -1) { | |
410 | + //문자열에 포함된 ("AM", "PM", "오전", "오후" 중 1개) 삭제 | |
411 | + date = date.replaceAll(TIME_TYPES.get(i), ""); | |
412 | + //시간 패턴 변경 [H -> h] | |
413 | + DATE_PATTERNS.set(3, 'h'); | |
414 | + break; | |
415 | + } | |
416 | + } | |
417 | + | |
418 | + //숫자를 뺀 나머지 문자열 가지고오기 ex) "2020.08.03" -> ".." | |
419 | + //숫자를 뺀 나머지 문자열 가지고오기 ex) "2020.08.03 19:20:21" -> "..::" | |
420 | + final char[] separators = getOnlyText(date).toCharArray(); | |
421 | + | |
422 | + /* | |
423 | + System.out.println(""); | |
424 | + System.out.println("@@@@@@@@@@@@@@ textToDateText @@@@@@@@@@@@@@"); | |
425 | + System.out.println("공백제거 텍스트 : " + date); | |
426 | + System.out.println("숫자제거 텍스트 : " + String.valueOf(separators)); | |
427 | + */ | |
428 | + | |
429 | + //사용할 최대 패턴 수 | |
430 | + int maxPatterSize = 0; | |
431 | + if (DATE_PATTERNS.size() <= separators.length) { | |
432 | + maxPatterSize = DATE_PATTERNS.size(); | |
433 | + } else { | |
434 | + maxPatterSize = separators.length; | |
435 | + } | |
436 | + | |
437 | + //구분자별 Index 위치's (사용할 최대 패턴 수 + 시작점:-1, 종료점:date문자열의 최종 길이) | |
438 | + List<Integer> sizeByPatterns = new ArrayList<Integer>(); | |
439 | + | |
440 | + //System.out.println(""); | |
441 | + //System.out.println("newText : " + date); | |
442 | + | |
443 | + //구분자 별 Index 위치 파악 후, 앞에 있는 문자열의 수 찾은 후, 추가 (마지막 패턴 뒤에 있는 문자열을 따로 처리해줘야함) | |
444 | + int fromIndex = -1; | |
445 | + for (int i = 0; i < maxPatterSize; i++) { | |
446 | + //구분자 | |
447 | + char separator = separators[i]; | |
448 | + | |
449 | + //'현재 찾은 위치' : 이전에 찾은 위치(찾기 시작할 위치 => fromIndex) + 1 부터 찾기 시작함 | |
450 | + int currentFromIndex = date.indexOf(separator, fromIndex + 1); | |
451 | + | |
452 | + //현재 패턴의 문자열 수 = '현재 찾은 위치' - '이전에 찾은 위치' - 1 [추가] | |
453 | + sizeByPatterns.add(currentFromIndex - fromIndex - 1); | |
454 | + //System.out.print("[" + sizeByPatterns.get(i) +"] "); | |
455 | + | |
456 | + //'현재 찾은 위치'는 '이전에 찾은 위치'가 됨 | |
457 | + fromIndex = currentFromIndex; | |
458 | + } | |
459 | + //마지막 패턴 뒤에 있는 문자열 = '문자열의 길이' - '마지막에 찾은 위치(이전에 찾은 위치)' - 1 [추가] | |
460 | + sizeByPatterns.add(date.length() - fromIndex - 1); | |
461 | + | |
462 | + | |
463 | + | |
464 | + //System.out.println(""); | |
465 | + //System.out.println("시간 타입 체킹 Index : " + timeTypeFindIndex); | |
466 | + | |
467 | + //패턴을 담을 변수 | |
468 | + StringBuilder pattern = new StringBuilder(); | |
469 | + | |
470 | + //DATE_PATTERS 순서 대로, 각 구분자 별 Index 위치 크기만큼 문자열에 패턴 삽입 + 구분자 삽입 | |
471 | + //마지막 전까지만 for문 돌림 | |
472 | + for (int i = 0, patternIndex = 0; i < sizeByPatterns.size() && patternIndex < DATE_PATTERNS.size(); i++, patternIndex++) { | |
473 | + | |
474 | + //패턴 추가 | |
475 | + int usingSize = 0; | |
476 | + for (int j = 0; j < sizeByPatterns.get(i); j++) { | |
477 | + if (j >= usingSize + DATE_PATTERNS_MAX_LENGTH.get(patternIndex)) { | |
478 | + usingSize += DATE_PATTERNS_MAX_LENGTH.get(patternIndex++); | |
479 | + | |
480 | + /*단 한개의 패턴이라도 '최대 문자열 수'를 넘어서면 -> '날짜 아님'*/ | |
481 | + if (i >= sizeByPatterns.size() || patternIndex >= DATE_PATTERNS.size()) { | |
482 | + return null; | |
483 | + } | |
484 | + } | |
485 | + | |
486 | + pattern.append(DATE_PATTERNS.get(patternIndex)); | |
487 | + } | |
488 | + | |
489 | + //날짜 구분자 추가 (마지막 구분자까지만) | |
490 | + if (i < separators.length) { | |
491 | + pattern.append(separators[i]); | |
492 | + } | |
493 | + | |
494 | + | |
495 | + } | |
496 | + | |
497 | + if (timeTypeFindIndex > -1) { | |
498 | + pattern.insert(timeTypeFindIndex, 'a'); | |
499 | + } | |
500 | + | |
501 | + return pattern.toString(); | |
502 | + } | |
503 | + | |
504 | + | |
505 | + /** | |
506 | + * @author 최정우 | |
507 | + * @since 2020.01.26 | |
508 | + * | |
509 | + * ping 체크 | |
510 | + */ | |
511 | + public static boolean pingCheck (String ip) { | |
512 | + InetAddress inetAddress; | |
513 | + try { | |
514 | + inetAddress = InetAddress.getByName(ip); | |
515 | + return inetAddress.isReachable(1000); | |
516 | + } catch (UnknownHostException e) { | |
517 | + return false; | |
518 | + } catch (IOException e) { | |
519 | + return false; | |
520 | + } catch (Exception e) { | |
521 | + return false; | |
522 | + } | |
523 | + } | |
524 | + | |
525 | + /** | |
526 | + * @author 최정우 | |
527 | + * @since 2020.01.26 | |
528 | + * | |
529 | + * 현재 client의 HttpServletRequest 조회 | |
530 | + */ | |
531 | + public static HttpServletRequest getHttpServletRequest () { | |
532 | + try { | |
533 | + ServletRequestAttributes servletRequestAttribute = (ServletRequestAttributes) RequestContextHolder.currentRequestAttributes(); | |
534 | + return servletRequestAttribute.getRequest(); | |
535 | + } catch (Exception e) { | |
536 | + return null; | |
537 | + } | |
538 | + } | |
539 | + | |
540 | + /** | |
541 | + * @author 최정우 | |
542 | + * @since 2020.01.26 | |
543 | + * | |
544 | + * 현재 client의 HttpSession 조회 | |
545 | + */ | |
546 | + public static HttpSession getHttpSession (boolean create) { | |
547 | + try { | |
548 | + HttpServletRequest request = getHttpServletRequest(); | |
549 | + if (request != null) { | |
550 | + return request.getSession(create); | |
551 | + } else { | |
552 | + return null; | |
553 | + } | |
554 | + } catch (Exception e) { | |
555 | + return null; | |
556 | + } | |
557 | + } | |
558 | + | |
559 | + /** | |
560 | + * @author 최정우 | |
561 | + * @since 2020.01.26 | |
562 | + * | |
563 | + * HttpServletRequest를 활용한 Client IP 가지고오기 | |
564 | + * Header의 X-FORWARDED-FOR 값을 통해 IP 조회, 만약 Header에 X-FORWARDED-FOR가 없으면 getRemoteAddr() 이걸로 조회 | |
565 | + */ | |
566 | + public static String getClientIp () { | |
567 | + try { | |
568 | + HttpServletRequest request = getHttpServletRequest(); | |
569 | + if (null != request.getHeader("X-FORWARDED-FOR")) { | |
570 | + return request.getHeader("X-FORWARDED-FOR"); | |
571 | + } else { | |
572 | + return request.getRemoteAddr(); | |
573 | + } | |
574 | + } catch (Exception e) { | |
575 | + return null; | |
576 | + } | |
577 | + } | |
578 | + | |
579 | + | |
580 | + | |
581 | + /** | |
582 | + * @author 최정우 | |
583 | + * @since 2020.01.26 | |
584 | + * | |
585 | + * ping 체크 (ip + port) | |
586 | + */ | |
587 | + public static boolean pingCheck(String ip, int port) { | |
588 | + Socket socket = new Socket(); | |
589 | + try { | |
590 | + socket.connect(new InetSocketAddress(ip, port), 1000); | |
591 | + boolean isConnect = socket.isConnected(); | |
592 | + socket.close(); | |
593 | + return isConnect; | |
594 | + } catch (UnknownHostException e) { | |
595 | + return false; | |
596 | + } catch (IOException e) { | |
597 | + return false; | |
598 | + } catch (Exception e) { | |
599 | + return false; | |
600 | + } | |
601 | + } | |
602 | + | |
603 | + /************************************* objectSetValue : Object to Object (start) *************************************/ | |
604 | + /** | |
605 | + * @author 최정우 | |
606 | + * @since 2020.04.22 | |
607 | + * | |
608 | + * [리플렉션 활용] VO객체(valueObject)의 변수들의 값 -> 목표 객체(targetObject)에 setting 해주는 메서드 | |
609 | + * | |
610 | + * 단, '명칭'과 '데이터 타입'이 같아야 값이 세팅됨 | |
611 | + */ | |
612 | + public static void objectSetValue (Object targetObject, Object valueObject) { | |
613 | + objectSetValue(targetObject, valueObject, null, null); | |
614 | + } | |
615 | + | |
616 | + public static void objectSetValue (Object targetObject, Object valueObject, Class<?>[] ignoreClasses) { | |
617 | + objectSetValue(targetObject, valueObject, ignoreClasses, null); | |
618 | + } | |
619 | + | |
620 | + public static void objectSetValue (Object targetObject, Object valueObject, String[] ignoreFields) { | |
621 | + objectSetValue(targetObject, valueObject, null, ignoreFields); | |
622 | + } | |
623 | + | |
624 | + /** | |
625 | + * @author 최정우 | |
626 | + * @since 2020.04.22 | |
627 | + * | |
628 | + * [리플렉션 활용] VO객체(valueObject)의 변수들의 값 -> 목표 객체(targetObject)에 setting 해주는 메서드 (+ 제거할 변수 목록) | |
629 | + * | |
630 | + * 단, '명칭'과 '데이터 타입'이 같아야 값이 세팅됨 | |
631 | + */ | |
632 | + public static void objectSetValue (Object targetObject, Object valueObject, Class<?>[] ignoreClasses, String[] ignoreFields) { | |
633 | + //빈값 체크 | |
634 | + if (valueObject == null || targetObject == null) { | |
635 | + return; | |
636 | + } | |
637 | + | |
638 | + //vo객체의 클래스 정보 얻기 | |
639 | + Class<?> valueObjectClass = valueObject.getClass(); | |
640 | + //vo객체의 클래스의 값이 null이 될 때 까지 반복 | |
641 | + while (valueObjectClass != null) { | |
642 | + | |
643 | + /* Class 필터 */ | |
644 | + boolean isIgnoreClassFind = false; | |
645 | + if (ignoreClasses != null) { | |
646 | + for (Class<?> ignoreClass : ignoreClasses) { | |
647 | + if (valueObjectClass.getName().equals(ignoreClass.getName())) { | |
648 | + //System.out.println("["+valueObjectClass.getName()+"] 제거(값 세팅 안하고 return) @@@@@@@@@@@@@@@@@@@@@"); | |
649 | + isIgnoreClassFind = true; | |
650 | + break; | |
651 | + } | |
652 | + } | |
653 | + | |
654 | + //제거할 Class를 찾았을 때 -> 다음 상위 클래스로 이동 | |
655 | + if (isIgnoreClassFind == true) { | |
656 | + //vo객체가 상속받은 상위클래스 정보 얻기 | |
657 | + valueObjectClass = valueObjectClass.getSuperclass(); | |
658 | + continue;//while문으로 이동 | |
659 | + } | |
660 | + }/* Class 필터 */ | |
661 | + | |
662 | + //vo객체의 Field목록 얻기 | |
663 | + Field[] valueObjectFields = valueObjectClass.getDeclaredFields(); | |
664 | + //Field 목록이 있을 때 -> 값 세팅하러 가기 | |
665 | + if (valueObjectFields != null && valueObjectFields.length > 0) { | |
666 | + for (int i = 0; i < valueObjectFields.length; i++) { | |
667 | + | |
668 | + /* Field 필터 */ | |
669 | + boolean isIgnoreFieldFind = false; | |
670 | + if (ignoreFields != null) { | |
671 | + for (String ignoreField : ignoreFields) { | |
672 | + if (valueObjectFields[i].getName().equals(ignoreField)) { | |
673 | + //System.out.println("["+valueObjectFields[i].getName()+"] 제거(값 세팅 안하고 return) @@@@@@@@@@@@@@@@@@@@@"); | |
674 | + isIgnoreFieldFind = true; | |
675 | + break; | |
676 | + } | |
677 | + } | |
678 | + //제거할 Field를 찾았을 때 -> 다음 Field로 이동 | |
679 | + if (isIgnoreFieldFind == true) { | |
680 | + continue;//for문으로 이동 | |
681 | + } | |
682 | + }/* Field 필터 */ | |
683 | + | |
684 | + //현재 vo객체 정보를 target객체에 값 세팅하기 | |
685 | + objectSetValueForField(targetObject, targetObject.getClass(), valueObject, valueObjectFields[i]); | |
686 | + } | |
687 | + } | |
688 | + | |
689 | + //vo객체가 상속받은 상위클래스 정보 얻기 | |
690 | + valueObjectClass = valueObjectClass.getSuperclass(); | |
691 | + } | |
692 | + } | |
693 | + | |
694 | + /** | |
695 | + * @author 최정우 | |
696 | + * @since 2020.04.22 | |
697 | + * | |
698 | + * public objectSetValue에서만 호출 가능 | |
699 | + * | |
700 | + */ | |
701 | + private static void objectSetValueForField (Object targetObject, Class<?> targetObjectSuperClass, Object valueObject, Field valueObjectField) { | |
702 | + //빈값 체크 | |
703 | + if (valueObject == null || valueObjectField == null || targetObject == null || targetObjectSuperClass == null) { | |
704 | + return; | |
705 | + } | |
706 | + | |
707 | + //Field 접근자 타입이 private라도 필드 정보에 접근가능하게 해줌 | |
708 | + valueObjectField.setAccessible(true); | |
709 | + try { | |
710 | + //vo객체의 변수필드의 명칭을 이용하여, 목표 객체의 변수필드 찾기. 만약, 못 찾으면 -> NoSuchFieldException오류 발생 -> catch로 이동 | |
711 | + Field targetObjectField = targetObjectSuperClass.getDeclaredField(valueObjectField.getName()); | |
712 | + targetObjectField.setAccessible(true);//private 변수도 접근가능하도록 settting | |
713 | + | |
714 | + //데이터 전달 객체의 필드 데이터 타입 | |
715 | + String valueObjectFieldType = valueObjectField.getType().getName(); | |
716 | + | |
717 | + //타겟 객체의 필드 데이터 타입 | |
718 | + String targetFieldType = targetObjectField.getType().getTypeName(); | |
719 | + | |
720 | + /* 목표 객체의 변수필드가 상수(final)이 아니고, 데이터 타입이 같고 때 -> 같은 클래스의 변수필드 인지 확인 */ | |
721 | + if (Modifier.isFinal(targetObjectField.getModifiers()) == false) { | |
722 | + | |
723 | + //데이터 타입이 완전 똑같을 때 | |
724 | + if (valueObjectFieldType.equals(targetFieldType)) { | |
725 | + //값 세팅 | |
726 | + targetObjectField.set(targetObject, valueObjectField.get(valueObject)); | |
727 | + } else { | |
728 | + | |
729 | + //타겟 변수가 기본형 변수 일 때 | |
730 | + if (targetObjectField.getType().isPrimitive()) { | |
731 | + String typeFullName = "java.lang." + targetFieldType; | |
732 | + if (typeFullName.toLowerCase().equals(valueObjectFieldType.toLowerCase())) { | |
733 | + //값 세팅 | |
734 | + targetObjectField.set(targetObject, valueObjectField.get(valueObject)); | |
735 | + } else { | |
736 | + throw new NoSuchFieldException(); | |
737 | + } | |
738 | + } else if (targetObjectField.getType().isInterface()) {//타겟 변수가 인터페이스 일 때 | |
739 | + //데이터 전달 객체 변수의 타입이 '타겟 변수의 인터페이스'구현체인지 확인하기 | |
740 | + boolean isImpl = false; | |
741 | + //데이터 전달 객체 변수 객체 생성 | |
742 | + Class<?> runtimeClass = ClassLoader.getSystemClassLoader().loadClass(valueObjectFieldType); | |
743 | + //데이터 전달 객체 변수의 '인터페이스' 목록 가지고오기 | |
744 | + Class<?>[] impls = runtimeClass.getInterfaces(); | |
745 | + //인터페이스가 있는지 없는지 확인 | |
746 | + for(Class<?> clz : impls) { | |
747 | + if(clz.getName().equals(targetFieldType)) { | |
748 | + isImpl = true; | |
749 | + } | |
750 | + } | |
751 | + | |
752 | + //구현체라면 | |
753 | + if (isImpl == true) { | |
754 | + //값 세팅 | |
755 | + targetObjectField.set(targetObject, valueObjectField.get(valueObject)); | |
756 | + } else { | |
757 | + throw new NoSuchFieldException(); | |
758 | + } | |
759 | + | |
760 | + } else { | |
761 | + throw new NoSuchFieldException(); | |
762 | + } | |
763 | + } | |
764 | + | |
765 | + } | |
766 | + | |
767 | + } catch (NoSuchFieldException e) {//목표 객체에서 변수를 발견 못했을 때 -> 목표 객체의 상위클래스 변수에서 찾아보기 | |
768 | + //목표 객체의 상위클래스가 존재할 때 -> 재귀 호출 | |
769 | + if (targetObjectSuperClass.getSuperclass() != null) { | |
770 | + try { | |
771 | + //목표객체의 상위클래스에서 변수 찾아서 값넣어주기 위해 재귀호출함 | |
772 | + objectSetValueForField(targetObject, targetObjectSuperClass.getSuperclass(), valueObject, valueObjectField); | |
773 | + } catch (Exception e1) { | |
774 | + e1.printStackTrace(); | |
775 | + } | |
776 | + } else { | |
777 | + return; | |
778 | + } | |
779 | + | |
780 | + } catch (Exception e) { | |
781 | + e.printStackTrace(); | |
782 | + } | |
783 | + | |
784 | + } | |
785 | + /************************************* objectSetValue : Object to Object (end) *************************************/ | |
786 | + | |
787 | + /************************************* objectSetMapValue : Map to Object (start) *************************************/ | |
788 | + /** | |
789 | + * @author 최정우 | |
790 | + * @since 2020.04.22 | |
791 | + * | |
792 | + * [리플렉션 활용] Map객체(Map<?, ?>)의 변수들의 값 -> 목표 객체(targetObject)에 setting 해주는 메서드 (+ 제거할 변수 목록) | |
793 | + * | |
794 | + * 단, '명칭'과 '데이터 타입'이 같아야 값이 세팅됨 | |
795 | + */ | |
796 | + public static void objectSetMapValue (Object targetObject, Map<?, ?> valueObject) { | |
797 | + objectSetMapValue(targetObject, valueObject, null); | |
798 | + } | |
799 | + | |
800 | + /** | |
801 | + * @author 최정우 | |
802 | + * @since 2020.04.22 | |
803 | + * | |
804 | + * [리플렉션 활용] Map객체(Map<?, ?>)의 변수들의 값 -> 목표 객체(targetObject)에 setting 해주는 메서드 (+ 제거할 변수 목록) | |
805 | + * | |
806 | + * 단, '명칭'과 '데이터 타입'이 같아야 값이 세팅됨 | |
807 | + */ | |
808 | + public static void objectSetMapValue (Object targetObject, Map<?, ?> valueObject, String[] ignoreFields) { | |
809 | + //빈값 체크 | |
810 | + if (valueObject == null || targetObject == null) { | |
811 | + return; | |
812 | + } | |
813 | + | |
814 | + for(Map.Entry<?, ?> elem : valueObject.entrySet()) { | |
815 | + String fieldName = StringUtil.toString(elem.getKey()); | |
816 | + Object fieldValue = elem.getValue(); | |
817 | + | |
818 | + if (fieldValue == null) continue; | |
819 | + | |
820 | + String fieldType = elem.getValue().getClass().getTypeName(); | |
821 | + | |
822 | + | |
823 | + /* Field 필터 */ | |
824 | + boolean isIgnoreFieldFind = false; | |
825 | + if (ignoreFields != null) { | |
826 | + for (String ignoreField : ignoreFields) { | |
827 | + if (fieldName.equals(ignoreField)) { | |
828 | + //System.out.println("["+valueObjectFields[i].getName()+"] 제거(값 세팅 안하고 return) @@@@@@@@@@@@@@@@@@@@@"); | |
829 | + isIgnoreFieldFind = true; | |
830 | + break; | |
831 | + } | |
832 | + } | |
833 | + //제거할 Field를 찾았을 때 -> 다음 Field로 이동 | |
834 | + if (isIgnoreFieldFind == true) { | |
835 | + continue;//for문으로 이동 | |
836 | + } | |
837 | + }/* Field 필터 */ | |
838 | + | |
839 | + objectSetValueForField(targetObject, targetObject.getClass(), fieldName, fieldType, fieldValue); | |
840 | + } | |
841 | + } | |
842 | + | |
843 | + /** | |
844 | + * @author 최정우 | |
845 | + * @since 2020.04.22 | |
846 | + * | |
847 | + * [리플렉션 활용] Map객체(Map<?, ?>)의 변수들의 값 -> 목표 객체(targetObject)에 setting 해주는 메서드 (+ 제거할 변수 목록) | |
848 | + * | |
849 | + * 단, '명칭'과 '데이터 타입'이 같아야 값이 세팅됨 | |
850 | + */ | |
851 | + public static void objectSetValueForField (Object targetObject, Class<?> targetObjectSuperClass, String fieldName, String fieldType, Object fieldValue) { | |
852 | + //System.out.println("targetObjectName : " + targetObject.getClass().getName() + ", targetObjectSuperClassName : " + targetObjectSuperClass.getName() + ", fieldName : " + fieldName + ", fieldType : " + fieldType); | |
853 | + | |
854 | + //빈값 체크 | |
855 | + if (StringUtil.isEmpty(fieldName) == true || StringUtil.isEmpty(fieldType) == true || fieldValue == null | |
856 | + || targetObject == null || targetObjectSuperClass == null) { | |
857 | + return; | |
858 | + } | |
859 | + | |
860 | + try { | |
861 | + //vo객체의 변수필드의 명칭을 이용하여, 목표 객체의 변수필드 찾기. 만약, 못 찾으면 -> NoSuchFieldException오류 발생 -> catch로 이동 | |
862 | + Field targetObjectField = targetObjectSuperClass.getDeclaredField(fieldName); | |
863 | + targetObjectField.setAccessible(true);//private 변수도 접근가능하도록 settting | |
864 | + //System.out.println("targetObjectFieldName : " + targetObjectField.getName() + ", targetObjectField Type Name : " + targetObjectField.getType().getTypeName() + ", " + targetObjectField.getType().getName() + ", 기본형 유무 : " + targetObjectField.getType().isPrimitive() + ", 인터페이스 유무 : " + targetObjectField.getType().isInterface()); | |
865 | + | |
866 | + //타겟 객체의 필드 데이터 타입 | |
867 | + String targetFieldType = targetObjectField.getType().getTypeName(); | |
868 | + | |
869 | + /* 목표 객체의 변수필드가 상수(final)이 아니고, 데이터 타입이 같고 때 -> 같은 클래스의 변수필드 인지 확인 */ | |
870 | + if (Modifier.isFinal(targetObjectField.getModifiers()) == false) { | |
871 | + | |
872 | + //데이터 타입이 완전 똑같을 때 | |
873 | + if (fieldType.equals(targetFieldType)) { | |
874 | + //값 세팅 | |
875 | + targetObjectField.set(targetObject, fieldValue); | |
876 | + //System.out.println("셋팅 완료"); | |
877 | + } else { | |
878 | + | |
879 | + //타겟 변수가 기본형 변수 일 때 | |
880 | + if (targetObjectField.getType().isPrimitive()) { | |
881 | + String typeFullName = "java.lang." + targetFieldType; | |
882 | + if (typeFullName.toLowerCase().equals(fieldType.toLowerCase())) { | |
883 | + //값 세팅 | |
884 | + targetObjectField.set(targetObject, fieldValue); | |
885 | + //System.out.println("셋팅 완료"); | |
886 | + } else { | |
887 | + throw new NoSuchFieldException(); | |
888 | + } | |
889 | + } else if (targetObjectField.getType().isInterface()) {//타겟 변수가 인터페이스 일 때 | |
890 | + //데이터 전달 객체 변수의 타입이 '타겟 변수의 인터페이스'구현체인지 확인하기 | |
891 | + boolean isImpl = false; | |
892 | + //데이터 전달 객체 변수 객체 생성 | |
893 | + Class<?> runtimeClass = ClassLoader.getSystemClassLoader().loadClass(fieldType); | |
894 | + //데이터 전달 객체 변수의 '인터페이스' 목록 가지고오기 | |
895 | + Class<?>[] impls = runtimeClass.getInterfaces(); | |
896 | + //인터페이스가 있는지 없는지 확인 | |
897 | + for(Class<?> clz : impls) { | |
898 | + if(clz.getName().equals(targetFieldType)) { | |
899 | + isImpl = true; | |
900 | + } | |
901 | + } | |
902 | + | |
903 | + //구현체라면 | |
904 | + if (isImpl == true) { | |
905 | + //값 세팅 | |
906 | + targetObjectField.set(targetObject, fieldValue); | |
907 | + //System.out.println("셋팅 완료"); | |
908 | + } else { | |
909 | + throw new NoSuchFieldException(); | |
910 | + } | |
911 | + } else { | |
912 | + throw new NoSuchFieldException(); | |
913 | + } | |
914 | + | |
915 | + } | |
916 | + | |
917 | + } else { | |
918 | + return; | |
919 | + } | |
920 | + | |
921 | + } catch (NoSuchFieldException e) {//목표 객체에서 변수를 발견 못했을 때 -> 목표 객체의 상위클래스 변수에서 찾아보기 | |
922 | + //목표 객체의 상위클래스가 존재할 때 -> 재귀 호출 | |
923 | + if (targetObjectSuperClass.getSuperclass() != null) { | |
924 | + try { | |
925 | + //목표객체의 상위클래스에서 변수 찾아서 값넣어주기 위해 재귀호출함 | |
926 | + objectSetValueForField(targetObject, targetObjectSuperClass.getSuperclass(), fieldName, fieldType, fieldValue); | |
927 | + } catch (Exception e1) { | |
928 | + e1.printStackTrace(); | |
929 | + } | |
930 | + } else { | |
931 | + return; | |
932 | + } | |
933 | + } catch (Exception e) { | |
934 | + e.printStackTrace(); | |
935 | + } | |
936 | + | |
937 | + System.out.println(""); | |
938 | + } | |
939 | + | |
940 | + /** | |
941 | + * @author 최정우 | |
942 | + * @since 2020.04.22 | |
943 | + * | |
944 | + * [리플렉션 활용] Map객체(Map<?, ?>)의 변수들의 값 -> 목표 객체(targetObject)에 setting 해주는 메서드 (+ 제거할 변수 목록) | |
945 | + * | |
946 | + * 단, '명칭'과 '데이터 타입'이 같아야 값이 세팅됨 | |
947 | + */ | |
948 | + public static void objectSetValueForField (Object targetObject, Class<?> targetObjectSuperClass, String fieldName, Object fieldValue) { | |
949 | + //빈값 체크 | |
950 | + if (StringUtil.isEmpty(fieldName) == true || fieldValue == null || targetObject == null || targetObjectSuperClass == null) { | |
951 | + return; | |
952 | + } | |
953 | + | |
954 | + try { | |
955 | + //vo객체의 변수필드의 명칭을 이용하여, 목표 객체의 변수필드 찾기. 만약, 못 찾으면 -> NoSuchFieldException오류 발생 -> catch로 이동 | |
956 | + Field targetObjectField = targetObjectSuperClass.getDeclaredField(fieldName); | |
957 | + targetObjectField.setAccessible(true);//private 변수도 접근가능하도록 settting | |
958 | + | |
959 | + /* 목표 객체의 변수필드가 상수(final)이 아니고, 데이터 타입이 같고 때 -> 같은 클래스의 변수필드 인지 확인 */ | |
960 | + if (Modifier.isFinal(targetObjectField.getModifiers()) == false) { | |
961 | + //값 세팅 | |
962 | + targetObjectField.set(targetObject, targetObjectField.getType().cast(fieldValue)); | |
963 | + //같은 클래스일 때 -> | |
964 | + } else { | |
965 | + return; | |
966 | + } | |
967 | + | |
968 | + } catch (NoSuchFieldException e) {//목표 객체에서 변수를 발견 못했을 때 -> 목표 객체의 상위클래스 변수에서 찾아보기 | |
969 | + //목표 객체의 상위클래스가 존재할 때 -> 재귀 호출 | |
970 | + if (targetObjectSuperClass.getSuperclass() != null) { | |
971 | + try { | |
972 | + //목표객체의 상위클래스에서 변수 찾아서 값넣어주기 위해 재귀호출함 | |
973 | + objectSetValueForField(targetObject, targetObjectSuperClass.getSuperclass(), fieldName, fieldValue); | |
974 | + } catch (Exception e1) { | |
975 | + e1.printStackTrace(); | |
976 | + } | |
977 | + } else { | |
978 | + return; | |
979 | + } | |
980 | + } catch (Exception e) { | |
981 | + e.printStackTrace(); | |
982 | + } | |
983 | + } | |
984 | + /************************************* objectSetMapValue : Map to Object (end) *************************************/ | |
985 | + | |
986 | + | |
987 | + /** | |
988 | + * @author 최정우 | |
989 | + * @since 2020.04.22 | |
990 | + * | |
991 | + * public objectSetValue에서만 호출 가능 | |
992 | + * | |
993 | + */ | |
994 | + public static void objectHTMLFilter (Object targetObject, Class<?> targetObjectClass) { | |
995 | + //빈값 체크 | |
996 | + if (targetObject == null || targetObjectClass == null) { | |
997 | + return; | |
998 | + } | |
999 | + | |
1000 | + //vo객체의 Field목록 얻기 | |
1001 | + Field[] valueObjectFields = targetObjectClass.getDeclaredFields(); | |
1002 | + | |
1003 | + Field test = null; | |
1004 | + //Field 목록이 있을 때 -> 값 세팅하러 가기 | |
1005 | + if (valueObjectFields != null && valueObjectFields.length > 0) { | |
1006 | + for (int i = 0; i < valueObjectFields.length; i++) { | |
1007 | + //현재 vo객체 정보를 target객체에 값 세팅하기 | |
1008 | + //Field 접근자 타입이 private라도 필드 정보에 접근가능하게 해줌 | |
1009 | + valueObjectFields[i].setAccessible(true); | |
1010 | + try { | |
1011 | + | |
1012 | + //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()); | |
1013 | + | |
1014 | + /* 목표 객체의 변수필드가 상수(final)이 아니고, 데이터 타입이 같고 때 -> 같은 클래스의 변수필드 인지 확인 */ | |
1015 | + if (Modifier.isFinal(valueObjectFields[i].getModifiers()) == false) { | |
1016 | + if (valueObjectFields[i].getGenericType().getTypeName().equals("java.lang.String")) { | |
1017 | + | |
1018 | + String value = StringUtil.toString(valueObjectFields[i].get(targetObject)); | |
1019 | + if (StringUtil.isEmpty(value) == false) { | |
1020 | + //같은 클래스일 때 -> 값 세팅 | |
1021 | + valueObjectFields[i].set(targetObject, StringUtil.cleanXSS(value)); | |
1022 | + } else { | |
1023 | + continue; | |
1024 | + } | |
1025 | + } else if (valueObjectFields[i].getGenericType().getTypeName().contains("List")) { | |
1026 | + List<Object> list = (List<Object>) valueObjectFields[i].get(targetObject); | |
1027 | + if (list != null) { | |
1028 | + for (int j = 0; j < list.size(); j++) { | |
1029 | + if (list.get(j) == null) { | |
1030 | + continue; | |
1031 | + } else if (list.get(j).getClass().getTypeName().indexOf(".") < 0) { | |
1032 | + continue; | |
1033 | + } else if (list.get(j).getClass().getTypeName().equals("java.lang.String")) { | |
1034 | + String value = StringUtil.toString(list.get(j)); | |
1035 | + list.set(j, StringUtil.cleanXSS(value)); | |
1036 | + } else if (list.get(j).getClass().getTypeName().contains("java.lang")) { | |
1037 | + continue; | |
1038 | + } else if (list.get(j).getClass().getTypeName().contains("List") | |
1039 | + || list.get(j).getClass().getTypeName().contains("[]") | |
1040 | + || list.get(j).getClass().getTypeName().contains("Map") | |
1041 | + || list.get(j).getClass().getTypeName().contains("Set") | |
1042 | + || list.get(j).getClass().getTypeName().contains("Collection") | |
1043 | + || list.get(j).getClass().getTypeName().contains("kr.co.sppartners")) { | |
1044 | + objectHTMLFilter(list.get(j), list.get(j).getClass()); | |
1045 | + } else { | |
1046 | + continue; | |
1047 | + } | |
1048 | + } | |
1049 | + } | |
1050 | + } else if (valueObjectFields[i].getGenericType().getTypeName().contains("[]")) { | |
1051 | + Object[] arr = (Object[]) valueObjectFields[i].get(targetObject); | |
1052 | + if (arr != null) { | |
1053 | + for (int j = 0; j < arr.length; j++) { | |
1054 | + if (arr[j] == null) { | |
1055 | + continue; | |
1056 | + } else if (arr[j].getClass().getTypeName().indexOf(".") < 0) { | |
1057 | + continue; | |
1058 | + } else if (arr[j].getClass().getTypeName().equals("java.lang.String")) { | |
1059 | + String value = StringUtil.toString(arr[j]); | |
1060 | + arr[j] = StringUtil.cleanXSS(value); | |
1061 | + } else if (arr[j].getClass().getTypeName().contains("java.lang")) { | |
1062 | + continue; | |
1063 | + } else if (arr[j].getClass().getTypeName().contains("List") | |
1064 | + || arr[j].getClass().getTypeName().contains("[]") | |
1065 | + || arr[j].getClass().getTypeName().contains("Map") | |
1066 | + || arr[j].getClass().getTypeName().contains("Set") | |
1067 | + || arr[j].getClass().getTypeName().contains("Collection") | |
1068 | + || arr[j].getClass().getTypeName().contains("kr.co.sppartners")) { | |
1069 | + objectHTMLFilter(arr[j], arr[j].getClass()); | |
1070 | + } else { | |
1071 | + continue; | |
1072 | + } | |
1073 | + } | |
1074 | + } | |
1075 | + } else if (valueObjectFields[i].getGenericType().getTypeName().contains("Map")) { | |
1076 | + if (valueObjectFields[i].getGenericType().getTypeName().contains("Map$Entry") | |
1077 | + || valueObjectFields[i].getGenericType().getTypeName().contains("Map$Node")) { | |
1078 | + Map.Entry<Object, Object> entry = (Map.Entry<Object, Object>) valueObjectFields[i].get(targetObject); | |
1079 | + if (entry != null) { | |
1080 | + if (entry.getValue() == null) { | |
1081 | + continue; | |
1082 | + } else if (entry.getValue().getClass().getTypeName().indexOf(".") < 0) { | |
1083 | + continue; | |
1084 | + } else if (entry.getValue().getClass().getTypeName().equals("java.lang.String")) { | |
1085 | + String value = StringUtil.toString(entry.getValue()); | |
1086 | + entry.setValue(StringUtil.cleanXSS(value)); | |
1087 | + } else if (entry.getValue().getClass().getTypeName().contains("java.lang")) { | |
1088 | + continue; | |
1089 | + } else if (entry.getValue().getClass().getTypeName().contains("List") | |
1090 | + || entry.getValue().getClass().getTypeName().contains("[]") | |
1091 | + || entry.getValue().getClass().getTypeName().contains("Map") | |
1092 | + || entry.getValue().getClass().getTypeName().contains("Set") | |
1093 | + || entry.getValue().getClass().getTypeName().contains("Collection") | |
1094 | + || entry.getValue().getClass().getTypeName().contains("kr.co.sppartners")) { | |
1095 | + objectHTMLFilter(entry.getValue(), entry.getValue().getClass()); | |
1096 | + } else { | |
1097 | + continue; | |
1098 | + } | |
1099 | + } | |
1100 | + } else { | |
1101 | + Map<Object, Object> map = (Map<Object, Object>) valueObjectFields[i].get(targetObject); | |
1102 | + | |
1103 | + if (map != null) { | |
1104 | + for (Object key : map.keySet()) { | |
1105 | + if (map.get(key) == null) { | |
1106 | + continue; | |
1107 | + } else if (map.get(key).getClass().getTypeName().indexOf(".") < 0) { | |
1108 | + continue; | |
1109 | + } else if (map.get(key).getClass().getTypeName().equals("java.lang.String")) { | |
1110 | + String value = StringUtil.toString(map.get(key)); | |
1111 | + map.put(key, StringUtil.cleanXSS(value)); | |
1112 | + } else if (map.get(key).getClass().getTypeName().contains("java.lang")) { | |
1113 | + continue; | |
1114 | + } else if (map.get(key).getClass().getTypeName().contains("List") | |
1115 | + || map.get(key).getClass().getTypeName().contains("[]") | |
1116 | + || map.get(key).getClass().getTypeName().contains("Map") | |
1117 | + || map.get(key).getClass().getTypeName().contains("Set") | |
1118 | + || map.get(key).getClass().getTypeName().contains("Collection") | |
1119 | + || map.get(key).getClass().getTypeName().contains("kr.co.sppartners")) { | |
1120 | + objectHTMLFilter(map.get(key), map.get(key).getClass()); | |
1121 | + } else { | |
1122 | + continue; | |
1123 | + } | |
1124 | + } | |
1125 | + } | |
1126 | + } | |
1127 | + | |
1128 | + } else if (valueObjectFields[i].getGenericType().getTypeName().contains("Set")) { | |
1129 | + Set<Object> set = (Set<Object>) valueObjectFields[i].get(targetObject); | |
1130 | + if (set != null) { | |
1131 | + for (Object obj : set) { | |
1132 | + if (obj == null) { | |
1133 | + continue; | |
1134 | + } else if (obj.getClass().getTypeName().indexOf(".") < 0) { | |
1135 | + continue; | |
1136 | + } else if (obj.getClass().getTypeName().equals("java.lang.String")) { | |
1137 | + set.remove(obj); | |
1138 | + String value = StringUtil.toString(obj); | |
1139 | + set.add(StringUtil.cleanXSS(value)); | |
1140 | + } else if (obj.getClass().getTypeName().contains("java.lang")) { | |
1141 | + continue; | |
1142 | + } else if (obj.getClass().getTypeName().contains("List") | |
1143 | + || obj.getClass().getTypeName().contains("[]") | |
1144 | + || obj.getClass().getTypeName().contains("Map") | |
1145 | + || obj.getClass().getTypeName().contains("Set") | |
1146 | + || obj.getClass().getTypeName().contains("Collection") | |
1147 | + || obj.getClass().getTypeName().contains("kr.co.sppartners")) { | |
1148 | + objectHTMLFilter(obj, obj.getClass()); | |
1149 | + } else { | |
1150 | + continue; | |
1151 | + } | |
1152 | + } | |
1153 | + } | |
1154 | + } else if (valueObjectFields[i].getGenericType().getTypeName().contains("java.util.Collection")) { | |
1155 | + Collection<Object> collection = (Collection<Object>) valueObjectFields[i].get(targetObject); | |
1156 | + if (collection != null) { | |
1157 | + for (Object obj : collection) { | |
1158 | + if (obj == null) { | |
1159 | + continue; | |
1160 | + } else if (obj.getClass().getTypeName().indexOf(".") < 0) { | |
1161 | + continue; | |
1162 | + } else if (obj.getClass().getTypeName().equals("java.lang.String")) { | |
1163 | + collection.remove(obj); | |
1164 | + String value = StringUtil.toString(obj); | |
1165 | + collection.add(StringUtil.cleanXSS(value)); | |
1166 | + } else if (obj.getClass().getTypeName().contains("java.lang")) { | |
1167 | + continue; | |
1168 | + } else if (obj.getClass().getTypeName().contains("List") | |
1169 | + || obj.getClass().getTypeName().contains("[]") | |
1170 | + || obj.getClass().getTypeName().contains("Map") | |
1171 | + || obj.getClass().getTypeName().contains("Set") | |
1172 | + || obj.getClass().getTypeName().contains("Collection") | |
1173 | + || obj.getClass().getTypeName().contains("kr.co.sppartners")) { | |
1174 | + objectHTMLFilter(obj, obj.getClass()); | |
1175 | + } else { | |
1176 | + continue; | |
1177 | + } | |
1178 | + } | |
1179 | + } | |
1180 | + } | |
1181 | + | |
1182 | + else { | |
1183 | + continue; | |
1184 | + } | |
1185 | + } else { | |
1186 | + continue; | |
1187 | + } | |
1188 | + } catch (Exception e) { | |
1189 | + e.printStackTrace(); | |
1190 | + //System.out.println("valueObjectFields[i].getGenericType().getTypeName() 에러발생 : " + valueObjectFields[i].getGenericType().getTypeName()); | |
1191 | + } | |
1192 | + } | |
1193 | + } | |
1194 | + | |
1195 | + //System.out.println("targetObjectClass.getSimpleName() : " + targetObjectClass.getSimpleName()); | |
1196 | + | |
1197 | + if (targetObjectClass.getSimpleName() != "CommonVO" && targetObjectClass.getSuperclass() != null) { | |
1198 | + try { | |
1199 | + //목표객체의 상위클래스에서 변수 찾아서 값넣어주기 위해 재귀호출함 | |
1200 | + objectHTMLFilter(targetObject, targetObjectClass.getSuperclass()); | |
1201 | + } catch (Exception e1) { | |
1202 | + e1.printStackTrace(); | |
1203 | + } | |
1204 | + } else { | |
1205 | + return; | |
1206 | + } | |
1207 | + } | |
1208 | + | |
1209 | + | |
1210 | + /** | |
1211 | + * @author 최정우 | |
1212 | + * @since 2019.12.09 | |
1213 | + * | |
1214 | + * 데이터 셋 목록 Convert LinkedHashMap<String, Object> to List<String> | |
1215 | + */ | |
1216 | + public static List<List<String>> rowDataMapToList (List<LinkedHashMap<String, Object>> rowMapData) throws Exception { | |
1217 | + List<List<String>> rowData = new ArrayList<List<String>>(); | |
1218 | + for (int i = 0; i < rowMapData.size(); i++) { | |
1219 | + List<String> row = new ArrayList<String>(); | |
1220 | + LinkedHashMap<String, Object> mapdata = rowMapData.get(i); | |
1221 | + for( String key : mapdata.keySet() ){ | |
1222 | + if (mapdata.get(key) == null) { | |
1223 | + row.add(null);//null값 대체 | |
1224 | + } else { | |
1225 | + row.add(mapdata.get(key).toString()); | |
1226 | + } | |
1227 | + } | |
1228 | + rowData.add(row); | |
1229 | + } | |
1230 | + return rowData; | |
1231 | + } | |
1232 | + | |
1233 | + public static int getRandomInt (int min, int max) { | |
1234 | + return (int) Math.round(Math.random() * (max - min));// + min; | |
1235 | + } | |
1236 | + | |
1237 | + | |
1238 | + /** | |
1239 | + * 작성일 : 210316 작성자 : 최정우 | |
1240 | + * | |
1241 | + * Exception -> String | |
1242 | + * | |
1243 | + * @param e : Exception | |
1244 | + */ | |
1245 | + public static String exceptionToString(Exception e) { | |
1246 | + StringWriter errors = new StringWriter(); | |
1247 | + e.printStackTrace(new PrintWriter(errors)); | |
1248 | + return "[Error] " + errors.toString(); | |
1249 | + } | |
1250 | +} |
+++ src/back-end/main/java/common/util/CountUtil.java
... | ... | @@ -0,0 +1,27 @@ |
1 | +package common.util; | |
2 | + | |
3 | +public class CountUtil implements Runnable { | |
4 | + | |
5 | + private boolean isProcessFinish = false; | |
6 | + private int count = 0; | |
7 | + | |
8 | + @Override | |
9 | + public void run () { | |
10 | + while (true) { | |
11 | + System.out.println("명령어 실행 중... (" + (count++) + "초)"); | |
12 | + if (isProcessFinish == true) { | |
13 | + break; | |
14 | + } | |
15 | + | |
16 | + try { | |
17 | + Thread.sleep(1000); | |
18 | + } catch (Exception e) { | |
19 | + e.printStackTrace(); | |
20 | + } | |
21 | + } | |
22 | + } | |
23 | + | |
24 | + public void processEnd () { | |
25 | + this.isProcessFinish = true; | |
26 | + } | |
27 | +} |
+++ src/back-end/main/java/common/util/CryptoUtil.java
... | ... | @@ -0,0 +1,278 @@ |
1 | +package common.util; | |
2 | + | |
3 | + | |
4 | +import javax.crypto.Cipher; | |
5 | +import javax.servlet.http.HttpSession; | |
6 | +import java.security.*; | |
7 | +import java.security.spec.PKCS8EncodedKeySpec; | |
8 | +import java.security.spec.X509EncodedKeySpec; | |
9 | +import java.util.Base64; | |
10 | + | |
11 | +/** | |
12 | + * @author 최정우 | |
13 | + * @since 2021.10.31 | |
14 | + * | |
15 | + * 암호화 관련 모듈 Class 입니다. | |
16 | + */ | |
17 | +public class CryptoUtil { | |
18 | + | |
19 | + /** | |
20 | + * @author 최정우 | |
21 | + * @since 2021.11.12 | |
22 | + * | |
23 | + * session에 RSA 암호화 Key생성 후, 공개키 반환 (무조건 새로 생성) | |
24 | + */ | |
25 | + public static PublicKey getPublicKeyInSession () { | |
26 | + try { | |
27 | + //현재 client의 HttpSession 조회 | |
28 | + HttpSession session = CommonUtil.getHttpSession(true); | |
29 | + | |
30 | + /** session이 존재하지 않을 때 **/ | |
31 | + if(session == null) { | |
32 | + return null; | |
33 | + }/** session이 존재할 때 **/ else { | |
34 | + //rsaKey 생성 | |
35 | + KeyPair keyPair = genRsaKeyPair(); | |
36 | + //session에 rsaKey 담기 | |
37 | + session.setAttribute("rsaKey", keyPair); | |
38 | + //공개키 return | |
39 | + return keyPair.getPublic(); | |
40 | + } | |
41 | + } catch(Exception e) { | |
42 | + System.out.println("AuthUtil getPublicKeyInSession Error : "); | |
43 | + e.printStackTrace(); | |
44 | + return null; | |
45 | + } | |
46 | + } | |
47 | + | |
48 | + /** | |
49 | + * @author 최정우 | |
50 | + * @since 2021.11.12 | |
51 | + * | |
52 | + * session에 담겨진 RSA 개인키 반환 (session에서 암호화 Key 무조건 삭제) | |
53 | + */ | |
54 | + public static PrivateKey getPrivateKeyInSession () { | |
55 | + try { | |
56 | + //현재 client의 HttpSession 조회 | |
57 | + HttpSession session = CommonUtil.getHttpSession(false); | |
58 | + | |
59 | + /** session이 존재하지 않을 때 **/ | |
60 | + if(session == null) { | |
61 | + return null; | |
62 | + }/** session이 존재할 때 **/ else { | |
63 | + //session에 있는 rsaKey 가지고오기 | |
64 | + KeyPair keyPair = (KeyPair) session.getAttribute("rsaKey"); | |
65 | + //session에 있는 rsaKey 삭제 | |
66 | + deleteRsaKeyInSession(); | |
67 | + //공개키 return | |
68 | + return keyPair.getPrivate(); | |
69 | + } | |
70 | + } catch(Exception e) { | |
71 | + System.out.println("AuthUtil getPrivateKeyInSession Error : "); | |
72 | + e.printStackTrace(); | |
73 | + return null; | |
74 | + } | |
75 | + } | |
76 | + | |
77 | + /* | |
78 | + * @author 최정우 | |
79 | + * @since 2021.11.12 | |
80 | + * | |
81 | + * session에 RSA암호화 Key를 반환함. | |
82 | + * | |
83 | + * @param isNewCreateRsaKey : 새로운 암호화 Key를 만들지에 대한 여부 | |
84 | + * - true : 암호화키 새로 생성 후, 생성된 암호화키 반환 (단, session이 존재할 때만 생성) | |
85 | + * - false : 새로 생성하지 않고 기존에 생성되어있는 암호화키 반환 | |
86 | + public static KeyPair getRsaKeyInSession (boolean isNewCreateRsaKey) { | |
87 | + try { | |
88 | + ServletRequestAttributes servletRequestAttribute = (ServletRequestAttributes) RequestContextHolder.currentRequestAttributes(); | |
89 | + HttpSession session = servletRequestAttribute.getRequest().getSession(false); | |
90 | + | |
91 | + *//** session이 존재하지 않을 때 **//* if(session == null) { | |
92 | + return null; | |
93 | + }*//** session이 존재할 때 **//* else { | |
94 | + *//** 새로운 암호화키 생성 (O) **//* if (isNewCreateRsaKey == true) { | |
95 | + //암호화키 생성 후, session에 담기 | |
96 | + session.setAttribute("rsaKey", genRsaKeyPair()); | |
97 | + }*//** 새로운 암호화키 생성 (X) **//* else { | |
98 | + //만약에 기존 암호화키가 없으면 새로 생성 | |
99 | + if (session.getAttribute("rsaKey") == null) { | |
100 | + session.setAttribute("rsaKey", genRsaKeyPair()); | |
101 | + } | |
102 | + } | |
103 | + //session에 담겨있는 rsaKey return | |
104 | + return (KeyPair) session.getAttribute("rsaKey"); | |
105 | + } | |
106 | + } catch(Exception e) { | |
107 | + System.out.println("AuthUtil getRsaKeyInSession Error : "); | |
108 | + e.printStackTrace(); | |
109 | + return null; | |
110 | + } | |
111 | + }*/ | |
112 | + | |
113 | + /** | |
114 | + * @author 최정우 | |
115 | + * @since 2021.11.12 | |
116 | + * | |
117 | + * session에 RSA암호화 Key를 제거 | |
118 | + */ | |
119 | + public static void deleteRsaKeyInSession () { | |
120 | + try { | |
121 | + //현재 client의 HttpSession 조회 | |
122 | + HttpSession session = CommonUtil.getHttpSession(false); | |
123 | + | |
124 | + /** session에 RSA암호화 Key가 존재할 때 **/ | |
125 | + if(session != null && session.getAttribute("rsaKey") != null) { | |
126 | + session.removeAttribute("rsaKey"); | |
127 | + } | |
128 | + } catch(Exception e) { | |
129 | + System.out.println("AuthUtil deleteRsaKeyInSession Error : "); | |
130 | + e.printStackTrace(); | |
131 | + } | |
132 | + } | |
133 | + | |
134 | + /** | |
135 | + * @author 최정우 | |
136 | + * @since 2021.11.08 | |
137 | + * | |
138 | + * RSA 암호화 키쌍(공개키, 개인키) 생성 기능 | |
139 | + */ | |
140 | + public static KeyPair genRsaKeyPair() { | |
141 | + KeyPairGenerator gen = null; | |
142 | + try { | |
143 | + gen = KeyPairGenerator.getInstance("RSA"); | |
144 | + } catch (NoSuchAlgorithmException e) { | |
145 | + e.printStackTrace(); | |
146 | + } | |
147 | + gen.initialize(1024, new SecureRandom()); | |
148 | + return gen.genKeyPair(); | |
149 | + } | |
150 | + | |
151 | + /** | |
152 | + * @author 최정우 | |
153 | + * @since 2021.11.08 | |
154 | + * | |
155 | + * RSA 공개키 -> String | |
156 | + */ | |
157 | + public static String publicKeyToString (PublicKey publicKey) { | |
158 | + return new String(byteToHex(publicKey.getEncoded())); | |
159 | + } | |
160 | + | |
161 | + /** | |
162 | + * @author 최정우 | |
163 | + * @since 2021.11.08 | |
164 | + * | |
165 | + * RSA 개인키 -> String | |
166 | + */ | |
167 | + public static String privateKeyToString (PrivateKey privateKey) { | |
168 | + return new String(byteToHex(privateKey.getEncoded())); | |
169 | + } | |
170 | + | |
171 | + /** | |
172 | + * @author 최정우 | |
173 | + * @since 2021.11.08 | |
174 | + * | |
175 | + * RSA String -> 공개키 | |
176 | + */ | |
177 | + public static PublicKey stringToPublicKey (String publicKeyStr) { | |
178 | + PublicKey publicKey = null; | |
179 | + try { | |
180 | + //문자열을 공개키로 표현하기 위한 스펙 객체 | |
181 | + X509EncodedKeySpec ukeySpec = new X509EncodedKeySpec(hexToByte(publicKeyStr)); | |
182 | + KeyFactory keyFactory = KeyFactory.getInstance("RSA"); | |
183 | + publicKey = keyFactory.generatePublic(ukeySpec); | |
184 | + } catch (Exception e) { | |
185 | + e.printStackTrace(); | |
186 | + } | |
187 | + return publicKey; | |
188 | + } | |
189 | + | |
190 | + /** | |
191 | + * @author 최정우 | |
192 | + * @since 2021.11.08 | |
193 | + * | |
194 | + * RSA String -> 개인키 | |
195 | + */ | |
196 | + public static PrivateKey stringToPrivateKey(String privateKeyStr){ | |
197 | + PrivateKey privateKey = null; | |
198 | + try{ | |
199 | + //문자열을 개인키로 표현하기 위한 스펙 객체 | |
200 | + PKCS8EncodedKeySpec rkeySpec = new PKCS8EncodedKeySpec(hexToByte(privateKeyStr)); | |
201 | + KeyFactory rkeyFactory = KeyFactory.getInstance("RSA"); | |
202 | + privateKey = rkeyFactory.generatePrivate(rkeySpec); | |
203 | + } catch (Exception e) { | |
204 | + e.printStackTrace(); | |
205 | + } | |
206 | + return privateKey; | |
207 | + } | |
208 | + | |
209 | + /** | |
210 | + * @author 최정우 | |
211 | + * @since 2021.11.08 | |
212 | + * | |
213 | + * 공개키 Key로 text를 RSA 암호화 | |
214 | + */ | |
215 | + public static String encodingByRsa (String text, PublicKey publicKey) throws Exception { | |
216 | + Cipher cipher = Cipher.getInstance("RSA"); | |
217 | + cipher.init(Cipher.ENCRYPT_MODE, publicKey); | |
218 | + | |
219 | + byte[] bytePlain = cipher.doFinal(text.getBytes()); | |
220 | + return Base64.getEncoder().encodeToString(bytePlain); | |
221 | + } | |
222 | + | |
223 | + /** | |
224 | + * @author 최정우 | |
225 | + * @since 2021.11.08 | |
226 | + * | |
227 | + * 개인키 Key로 text를 RSA 복호화 | |
228 | + */ | |
229 | + public static String decodingByRsa (String encodedText, PrivateKey privateKey) throws Exception { | |
230 | + Cipher cipher = Cipher.getInstance("RSA"); | |
231 | + byte[] byteEncrypted = Base64.getDecoder().decode(encodedText.getBytes()); | |
232 | + cipher.init(Cipher.DECRYPT_MODE, privateKey); | |
233 | + byte[] bytePlain = cipher.doFinal(byteEncrypted); | |
234 | + return new String(bytePlain, "utf-8"); | |
235 | + } | |
236 | + | |
237 | + | |
238 | + /** | |
239 | + * @author 최정우 | |
240 | + * @since 2021.10.31 | |
241 | + * | |
242 | + * SHA-256 암호화 기능 | |
243 | + */ | |
244 | + public static String encodingBySha256 (String text) throws NoSuchAlgorithmException { | |
245 | + MessageDigest md = MessageDigest.getInstance("SHA-256"); | |
246 | + md.update(text.getBytes()); | |
247 | + return byteToHex(md.digest()); | |
248 | + } | |
249 | + | |
250 | + | |
251 | + /** | |
252 | + * @author 최정우 | |
253 | + * @since 2021.10.31 | |
254 | + * | |
255 | + * 바이너리 -> 16진수 변경 | |
256 | + */ | |
257 | + public static String byteToHex(byte[] data) { | |
258 | + StringBuilder sb = new StringBuilder(); | |
259 | + for(byte b : data) { | |
260 | + sb.append(Integer.toString((b & 0xff) + 0x100, 16).substring(1)); | |
261 | + } | |
262 | + return sb.toString(); | |
263 | + } | |
264 | + | |
265 | + /** | |
266 | + * @author 최정우 | |
267 | + * @since 2021.10.31 | |
268 | + * | |
269 | + * 16진수 -> 바이너리 변경 | |
270 | + */ | |
271 | + public static byte[] hexToByte(String hex) { | |
272 | + byte[] ba = new byte[hex.length() / 2]; | |
273 | + for (int i = 0; i < ba.length; i++) { | |
274 | + ba[i] = (byte) Integer.parseInt(hex.substring(2 * i, 2 * i + 2), 16); | |
275 | + } | |
276 | + return ba; | |
277 | + } | |
278 | +} |
+++ src/back-end/main/java/common/util/EmailUtil.java
... | ... | @@ -0,0 +1,46 @@ |
1 | +package common.util; | |
2 | + | |
3 | +import javax.mail.*; | |
4 | +import javax.mail.internet.InternetAddress; | |
5 | +import javax.mail.internet.MimeMessage; | |
6 | +import java.util.Properties; | |
7 | + | |
8 | +public class EmailUtil { | |
9 | + | |
10 | + public static void naverMailSend(String receiver, String title, String content) { | |
11 | + String host = "smtp.naver.com"; // 네이버일 경우 네이버 계정, gmail경우 gmail 계정 | |
12 | + String user = "[email protected]"; // 패스워드 | |
13 | + String password = "elwlfjf!2tktn"; | |
14 | + | |
15 | + // SMTP 서버 정보를 설정한다. | |
16 | + Properties props = new Properties(); | |
17 | + props.put("mail.smtp.host", host); | |
18 | + props.put("mail.smtp.port", 587); | |
19 | + props.put("mail.smtp.auth", "true"); | |
20 | + | |
21 | + Session session = Session.getDefaultInstance(props, new javax.mail.Authenticator() { | |
22 | + protected PasswordAuthentication getPasswordAuthentication() { | |
23 | + return new PasswordAuthentication(user, password); | |
24 | + } | |
25 | + }); | |
26 | + | |
27 | + try { | |
28 | + MimeMessage message = new MimeMessage(session); | |
29 | + message.setFrom(new InternetAddress(user)); | |
30 | + message.addRecipient(Message.RecipientType.TO, new InternetAddress(receiver)); | |
31 | + | |
32 | + // 메일 제목 | |
33 | + message.setSubject(title); | |
34 | + | |
35 | + // 메일 내용 | |
36 | + message.setContent(content, "text/html; charset=UTF-8"); | |
37 | + | |
38 | + // send the message | |
39 | + Transport.send(message); | |
40 | + System.out.println("Success Message Send"); | |
41 | + } catch (MessagingException e) { | |
42 | + e.printStackTrace(); | |
43 | + } | |
44 | + } | |
45 | + | |
46 | +} |
+++ src/back-end/main/java/common/util/ExcelReadUtil.java
... | ... | @@ -0,0 +1,191 @@ |
1 | +package common.util; | |
2 | + | |
3 | +import common.vo.CommonFile; | |
4 | +import org.apache.poi.ss.usermodel.*; | |
5 | + | |
6 | +import java.io.File; | |
7 | +import java.math.BigDecimal; | |
8 | +import java.text.SimpleDateFormat; | |
9 | +import java.util.*; | |
10 | + | |
11 | +public class ExcelReadUtil { | |
12 | + /** | |
13 | + * @author 김재영 | |
14 | + * @since 2021.11.15 | |
15 | + * | |
16 | + * 일반 엑셀 Read xls, xlsx | |
17 | + * 엑셀파일 읽기 poi라이브러리 사용 | |
18 | + */ | |
19 | + public static Map<String, Object> excelFileRead(CommonFile commonFile) throws Exception { | |
20 | + Map<String, Object> dataBySheet = new LinkedHashMap<String, Object>(); | |
21 | + String fileFullPath= commonFile.getFileFullPath(); | |
22 | + String sheetTitle= "sheet0"; | |
23 | + File excelFile = new File(fileFullPath); | |
24 | + Workbook wb = WorkbookFactory.create(excelFile); | |
25 | + | |
26 | + | |
27 | + | |
28 | + for (int sheetIdx = 0; sheetIdx < wb.getNumberOfSheets(); sheetIdx++) { | |
29 | + //한개의 시트에 대한 행,열 데이터 List | |
30 | + Map<String, Object> sheetData = new LinkedHashMap<String, Object>(); | |
31 | + //rowData 담는 리스트 | |
32 | + List<LinkedHashMap<String, Object>> rowData = new ArrayList<LinkedHashMap<String, Object>>(); | |
33 | + List<List<String>> columnData = new ArrayList<List<String>>(); | |
34 | + //시트 객체 | |
35 | + Sheet sheet = wb.getSheetAt(sheetIdx); | |
36 | + | |
37 | + //데이터가 들어있는 시트의 첫 번째 행 index | |
38 | + int firstRowNum = sheet.getFirstRowNum(); | |
39 | + //데이터가 들어있는 시트의 최종 행 index | |
40 | + int lastRowNum = sheet.getLastRowNum(); | |
41 | + | |
42 | + //데이터가 들어있는 시트의 첫 번째 행의 마지막 열 index | |
43 | + //int firstCellNum = sheet.getRow(firstRowNum).getFirstCellNum(); | |
44 | + //int lastCellNum = sheet.getRow(firstRowNum).getLastCellNum(); | |
45 | + | |
46 | + //Row for문 | |
47 | + for(int rowIndex = firstRowNum+1; rowIndex <= lastRowNum; rowIndex++) { | |
48 | + //Row 객체 | |
49 | + Row row = sheet.getRow(rowIndex); | |
50 | + if(row == null) continue; | |
51 | + | |
52 | + //해당 index 행의 마지막 열 index | |
53 | + int lastCellNum = row.getLastCellNum(); | |
54 | + | |
55 | + //행에 열데이터가 1개라도 존재하는지 체크 | |
56 | + boolean isRowDataExist = false; | |
57 | + | |
58 | + //한개의 행에 대한 열 데이터 | |
59 | + LinkedHashMap<String, Object> cells = new LinkedHashMap<String, Object>(); | |
60 | + //Row의 Cell 데이터 담기 | |
61 | + for(int cellIndex = 0; cellIndex < lastCellNum; cellIndex++) { | |
62 | + Cell cell = row.getCell(cellIndex); | |
63 | + try { | |
64 | + String value = getCellValue(cell, wb); | |
65 | + if (StringUtil.isEmpty(value) == true) { | |
66 | + cells.put("cell"+cellIndex, null); | |
67 | + } else { | |
68 | + cells.put("cell"+cellIndex, value); | |
69 | + isRowDataExist = true; | |
70 | + } | |
71 | + } catch (Exception e) { | |
72 | + cells.put("cell"+cellIndex, null); | |
73 | + e.printStackTrace(); | |
74 | + } | |
75 | + } | |
76 | + | |
77 | + //행에 열데이터가 1개라도 존재하면 -> row데이터 추가 | |
78 | + if (isRowDataExist == true) { | |
79 | + //row데이터 추가 | |
80 | + rowData.add(cells); | |
81 | + } | |
82 | + | |
83 | + //raw데이터에 대한 명칭 입력 | |
84 | + //dataTable.setTitle(dataTitle); | |
85 | + }//Row for문 끝 | |
86 | + sheetData.put("rowData",rowData); | |
87 | + //시트가 2개 이상일 때, 데이터 명 == 시트명 | |
88 | + if (wb.getNumberOfSheets() > 1) { | |
89 | + sheetTitle = "sheet"+sheetIdx; | |
90 | + } | |
91 | + | |
92 | + //row데이터가 없을 때, 메세지 처리 | |
93 | +// if (dataTable.getRowData().size() == 0) { | |
94 | +// dataTable.getCheckMessage().setIsSuccess(false); | |
95 | +// dataTable.getCheckMessage().setMessage("데이터가 없습니다"); | |
96 | +// } else { | |
97 | +// dataTable.getCheckMessage().setIsSuccess(true); | |
98 | +// dataTable.getCheckMessage().setMessage("엑셀(.xls) 파일 읽기 완료"); | |
99 | +// } | |
100 | + | |
101 | + //Key(시트명) : Value(시트의 행,열 데이터) | |
102 | + dataBySheet.put(sheetTitle, sheetData); | |
103 | + } | |
104 | + //스트림 닫기 | |
105 | + if (wb != null) { | |
106 | + wb.close(); | |
107 | + } | |
108 | + | |
109 | + return dataBySheet; | |
110 | + } | |
111 | + | |
112 | + /** | |
113 | + * @author 김재영 | |
114 | + * @since 2021.11.15 | |
115 | + * | |
116 | + * 일반 엑셀 Read 관련 | |
117 | + * Excel cell value 데이터 타입 파악 후, 원본형태의 문자열로 반환 | |
118 | + */ | |
119 | + public static String getCellValue(Cell cell, Workbook wb) throws Exception { | |
120 | + if(cell != null) { | |
121 | + switch (cell.getCellType()) { | |
122 | + case FORMULA: | |
123 | + FormulaEvaluator evaluator = wb.getCreationHelper().createFormulaEvaluator(); | |
124 | + if (evaluator.evaluateFormulaCell(cell) == CellType.NUMERIC) { | |
125 | + if (DateUtil.isCellDateFormatted(cell)) { | |
126 | + return ""; | |
127 | + } else { | |
128 | + Double dou = new Double(cell.getNumericCellValue()); | |
129 | + if ((double) dou.longValue() == dou.doubleValue()) { | |
130 | + return Long.toString(dou.longValue()); | |
131 | + } else { | |
132 | + return StringUtil.toString(dou); | |
133 | + } | |
134 | + } | |
135 | + } else if (evaluator.evaluateFormulaCell(cell) == CellType.STRING) { | |
136 | + return cell.getStringCellValue(); | |
137 | + } else if (evaluator.evaluateFormulaCell(cell) == CellType.BOOLEAN) { | |
138 | + return StringUtil.toString(new Boolean(cell.getBooleanCellValue())); | |
139 | + } else { | |
140 | + return cell.getCellFormula(); | |
141 | + } | |
142 | + case NUMERIC: | |
143 | + BigDecimal big = new BigDecimal(cell.getNumericCellValue()); | |
144 | + BigDecimal fp = big.subtract(new BigDecimal(big.longValue())); | |
145 | + if(DateUtil.isCellDateFormatted(cell)) { | |
146 | + Date date = cell.getDateCellValue(); | |
147 | + return new SimpleDateFormat("yyyy-MM-dd").format(date); | |
148 | + } else if(checkDateFormat(cell)) { | |
149 | + Date date = cell.getDateCellValue(); | |
150 | + return new SimpleDateFormat("yyyy-MM-dd").format(date); | |
151 | + } else if(fp.doubleValue()==0.0d) { | |
152 | + return Long.toString(big.longValue()); | |
153 | + } else { | |
154 | + return StringUtil.toString(new Double(cell.getNumericCellValue())); | |
155 | + } | |
156 | + case STRING: | |
157 | + return cell.getStringCellValue(); | |
158 | + case BOOLEAN: | |
159 | + return StringUtil.toString(new Boolean(cell.getBooleanCellValue())); | |
160 | + case ERROR: | |
161 | + return StringUtil.toString(new Byte(cell.getErrorCellValue())); | |
162 | + case BLANK: | |
163 | + return ""; | |
164 | + default: | |
165 | + return ""; | |
166 | + } | |
167 | + } else { | |
168 | + return ""; | |
169 | + } | |
170 | + } | |
171 | + | |
172 | + /** | |
173 | + * @author 김재영 | |
174 | + * @since 2021.11.15 | |
175 | + * | |
176 | + * 일반 엑셀 Read 관련 | |
177 | + * Excel cell의 포맷 형태가 데이트관련 포맷인지 체크 | |
178 | + */ | |
179 | + public static boolean checkDateFormat(Cell cell) throws Exception{ | |
180 | + try { | |
181 | + int formatIndex = cell.getCellStyle().getDataFormat(); | |
182 | + switch(formatIndex) { | |
183 | + case 31: //excel: yyyy년 MM월 dd일 | |
184 | + return true; | |
185 | + } | |
186 | + } catch (Exception e) { | |
187 | + return false; | |
188 | + } | |
189 | + return false; | |
190 | + } | |
191 | +} |
+++ src/back-end/main/java/common/util/FileUtil.java
... | ... | @@ -0,0 +1,334 @@ |
1 | +package common.util; | |
2 | + | |
3 | +import common.vo.CheckMessage; | |
4 | +import common.vo.CommonFile; | |
5 | +import common.vo.CommonFile.FileStatus; | |
6 | +import common.vo.SystemCode.FileUploadPath; | |
7 | +import org.springframework.web.multipart.MultipartFile; | |
8 | +import org.springframework.web.multipart.MultipartHttpServletRequest; | |
9 | + | |
10 | +import javax.servlet.http.HttpServletRequest; | |
11 | +import java.io.File; | |
12 | +import java.text.DecimalFormat; | |
13 | +import java.time.LocalDate; | |
14 | +import java.util.*; | |
15 | + | |
16 | + | |
17 | +/** | |
18 | + * @author 최정우 | |
19 | + * @since 2019.11.13 | |
20 | + * | |
21 | + * File과 관련된 기능을 정의 해놓은 Util입니다. | |
22 | + * 업로드, 다운로드, 파일읽기, 파일쓰기 | |
23 | + * | |
24 | + * 파일 정보만 가지고오기 -> multipartFileToCommonFile (multipartFileCheck기능 포함) | |
25 | + * 파일 확장자 체크 -> multipartFileCheck | |
26 | + * 특정 디렉토리에 파일 생성 -> fileCreate | |
27 | + * | |
28 | + * ※주요 활용 메소드 : fileUpload -> 파일 업로드 및 업로드 정보 반환 (fileCreate기능 및 multipartFileCheck 까지 포함되어 있음) | |
29 | + */ | |
30 | +public class FileUtil { | |
31 | + | |
32 | + /** | |
33 | + * @author 최정우 | |
34 | + * @since 2019.11.13 | |
35 | + * | |
36 | + * 파일 기본 정보 (여러개 파일) | |
37 | + */ | |
38 | + public static List<CommonFile> multipartFileToCommonFile (HttpServletRequest request) throws Exception { | |
39 | + return multipartFileToCommonFile(request, null); | |
40 | + } | |
41 | + public static List<CommonFile> multipartFileToCommonFile (HttpServletRequest request, List<String> extensions) throws Exception { | |
42 | + List<CommonFile> fileuploads = new ArrayList<CommonFile>(); | |
43 | + | |
44 | + MultipartHttpServletRequest multipart = (MultipartHttpServletRequest) request; | |
45 | + Iterator<String> itr = multipart.getFileNames(); | |
46 | + | |
47 | + while (itr.hasNext()) { | |
48 | + fileuploads.add(multipartFileToCommonFile(multipart.getFile(itr.next()), extensions)); | |
49 | + } | |
50 | + | |
51 | + return fileuploads; | |
52 | + } | |
53 | + | |
54 | + /** | |
55 | + * @author 최정우 | |
56 | + * @since 2019.11.13 | |
57 | + * | |
58 | + * 파일 기본 정보 (한개 파일) | |
59 | + */ | |
60 | + public static CommonFile multipartFileToCommonFile (MultipartFile multipartFile) throws Exception { | |
61 | + return multipartFileToCommonFile(multipartFile, null); | |
62 | + } | |
63 | + public static CommonFile multipartFileToCommonFile (MultipartFile multipartFile, List<String> extensions) throws Exception { | |
64 | + CommonFile commonFile = new CommonFile(); | |
65 | + | |
66 | + commonFile.setFileOriginName(getFileNameExceptExtension(multipartFile.getOriginalFilename())); | |
67 | + commonFile.setFileExtension(getFileExtension(multipartFile.getOriginalFilename())); | |
68 | + commonFile.setFileSize(multipartFile.getSize()); | |
69 | + commonFile.setCheckMessage(multipartFileCheck(multipartFile, extensions)); | |
70 | + | |
71 | + return commonFile; | |
72 | + } | |
73 | + | |
74 | + | |
75 | + /** | |
76 | + * @author 최정우 | |
77 | + * @since 2019.11.13 | |
78 | + * | |
79 | + * 업로드 파일 체크 (여러개 파일 - extensions) | |
80 | + */ | |
81 | + public static Map<String, CheckMessage> multipartFileCheck (HttpServletRequest request, List<String> extensions) throws Exception { | |
82 | + Map<String, CheckMessage> info = new HashMap<String, CheckMessage>(); | |
83 | + | |
84 | + MultipartHttpServletRequest multipart = (MultipartHttpServletRequest) request; | |
85 | + Iterator<String> itr = multipart.getFileNames(); | |
86 | + | |
87 | + while (itr.hasNext()) { | |
88 | + MultipartFile multipartFile = multipart.getFile(itr.next()); | |
89 | + info.put(multipartFile.getName(), multipartFileCheck (multipartFile, extensions)); | |
90 | + } | |
91 | + | |
92 | + return info; | |
93 | + } | |
94 | + | |
95 | + /** | |
96 | + * @author 최정우 | |
97 | + * @since 2019.11.13 | |
98 | + * | |
99 | + * 업로드 파일 체크 (한개 파일 - extensions) | |
100 | + */ | |
101 | + public static CheckMessage multipartFileCheck (MultipartFile multipartFile, List<String> extensions) throws Exception { | |
102 | + | |
103 | + String orginFileName = multipartFile.getOriginalFilename(); | |
104 | +// System.out.println("multipartFile name : " + multipartFile.getName()); | |
105 | + //원 파일명이 없는 경우 처리(첨부가 되지 않은 input file type) | |
106 | + if (orginFileName.equals("")) { | |
107 | + return new CheckMessage(false, "파일명이 존재하지 않습니다"); | |
108 | + } | |
109 | + | |
110 | + //파일 확장자 존재 유무 | |
111 | + int index = orginFileName.lastIndexOf("."); | |
112 | + if (index == -1) { | |
113 | + return new CheckMessage(false, "파일에 확장자가 존재하지 않습니다"); | |
114 | + } | |
115 | + | |
116 | + //파일 확장자 체크 | |
117 | + String fileExt = orginFileName.substring(index + 1); | |
118 | + //파일 확장자 체크 후, 컴펌 유무 | |
119 | + boolean isConfirm = false; | |
120 | + if (extensions != null && extensions.size() > 0) {//체크할 확장자가 있으면 -> 체킹 | |
121 | + for (int i = 0; i < extensions.size(); i++) { | |
122 | + if (extensions.get(i).toUpperCase().equals(fileExt.toUpperCase())) { | |
123 | + isConfirm = true; | |
124 | + break; | |
125 | + } | |
126 | + } | |
127 | + } else {//체크할 확장자가 없으면 -> 컴펌 | |
128 | + isConfirm = true; | |
129 | + } | |
130 | + | |
131 | + if (isConfirm == false) { | |
132 | + return new CheckMessage(false, "." + fileExt + " 파일은(는) 업로드가 불가능한 확장자입니다"); | |
133 | + } | |
134 | + | |
135 | + return new CheckMessage(true, "업로드 가능한 파일 입니다"); | |
136 | + } | |
137 | + | |
138 | + /** | |
139 | + * @author 최정우 | |
140 | + * @since 2019.11.17 | |
141 | + * | |
142 | + * 업로드 파일 정보 조회 (여러개 파일) | |
143 | + */ | |
144 | + public static List<CommonFile> fileUpload (HttpServletRequest request) throws Exception { | |
145 | + return fileUpload(request, null); | |
146 | + } | |
147 | + public static List<CommonFile> fileUpload (HttpServletRequest request, List<String> extensions) throws Exception { | |
148 | + List<CommonFile> fileUploads = new ArrayList<CommonFile>(); | |
149 | + | |
150 | + MultipartHttpServletRequest multipart = (MultipartHttpServletRequest) request; | |
151 | + Iterator<String> multiFiles = multipart.getFileNames(); | |
152 | + | |
153 | + while (multiFiles.hasNext()) { | |
154 | + MultipartFile multipartFile = multipart.getFile(multiFiles.next()); | |
155 | + fileUploads.add(fileUpload(multipartFile, request, extensions)); | |
156 | + } | |
157 | + | |
158 | + return fileUploads; | |
159 | + } | |
160 | + | |
161 | + /** | |
162 | + * @author 최정우 | |
163 | + * @since 2019.11.17 | |
164 | + * | |
165 | + * 업로드 파일 정보 조회 (한개 파일) | |
166 | + */ | |
167 | + public static CommonFile fileUpload (MultipartFile multipartFile, HttpServletRequest request) throws Exception { | |
168 | + return fileUpload(multipartFile, request, null); | |
169 | + } | |
170 | + public static CommonFile fileUpload (MultipartFile multipartFile, HttpServletRequest request, List<String> extensions) throws Exception { | |
171 | + long startTime = System.currentTimeMillis();/*삭제 요망*/ | |
172 | + //파일 정보 객체 | |
173 | + CommonFile fileUpload = new CommonFile(); | |
174 | + try { | |
175 | + //프로젝트 내부 경로 | |
176 | + String relativePath = FileUploadPath.MAIN_RELATIVE_PATH.getOSFileUploadPath(); | |
177 | + //프로젝트 내부 경로 = 프로젝트 내부 경로 + /년도 | |
178 | + relativePath += File.separator + LocalDate.now().getYear(); | |
179 | + //프로젝트 내부 경로 = 프로젝트 내부 경로 + /년도 + /월 | |
180 | + relativePath += File.separator + LocalDate.now().getMonthValue(); | |
181 | + //절대 경로(프로젝트 내부 경로의 절대경로) | |
182 | + String absolutePath = request.getSession().getServletContext().getRealPath(relativePath); | |
183 | + //확장자를 제거한 원본 파일명 | |
184 | + String originName = getFileNameExceptExtension(multipartFile.getOriginalFilename()); | |
185 | + //새로 생성될 파일명 | |
186 | + String maskName = StringUtil.getCreateKey("bigdata"); | |
187 | + //원본 파일의 확장자 | |
188 | + String extension = getFileExtension(multipartFile.getOriginalFilename()); | |
189 | + //원본 파일의 파일크기(byte단위) | |
190 | + long size = multipartFile.getSize(); | |
191 | + | |
192 | + //파일 정보 셋팅 (시작) | |
193 | + fileUpload.setFileRelativePath(relativePath); | |
194 | + fileUpload.setFileAbsolutePath(absolutePath); | |
195 | + fileUpload.setFileOriginName(originName); | |
196 | + fileUpload.setFileMaskName(maskName); | |
197 | + fileUpload.setFileExtension(extension); | |
198 | + fileUpload.setFileSize(size); | |
199 | + fileUpload.setFileStatus(FileStatus.BEFORE_INSERT); | |
200 | + fileUpload.setCheckMessage(new CheckMessage(true, "파일 정보 조회 성공")); | |
201 | + //파일 정보 셋팅 (끝) | |
202 | + } catch (Exception e) { | |
203 | + fileUpload.setCheckMessage(new CheckMessage(false, "파일 정보 조회 에러", e.getMessage())); | |
204 | + } | |
205 | + | |
206 | + //실제 디렉토리에 업로드 파일 생성 | |
207 | + if (extensions != null && extensions.size() > 0) {//extensions가 존재하면 -> 파일 검사 -> 통과 시, 파일 생성 | |
208 | + //파일 확장자 검사 | |
209 | + fileUpload.setCheckMessage(multipartFileCheck(multipartFile, extensions)); | |
210 | + | |
211 | + if (fileUpload.getCheckMessage().getIsSuccess() == true) {//확장자 검사 통과 -> 성공 -> 파일 생성 | |
212 | + fileCreate(fileUpload, multipartFile); | |
213 | + long endTime = System.currentTimeMillis();/*삭제 요망*/ | |
214 | + long totalTime = endTime - startTime;/*삭제 요망*/ | |
215 | + System.out.println("업로드 경로 : " + fileUpload.getFileAbsolutePath() + ", 파일명 : " + multipartFile.getOriginalFilename() + "(" + fileUpload.getFileMaskName() + ") 파일 업로드 소요시간 : " + totalTime / 1000.0 + "초");/*삭제 요망*/ | |
216 | + } else {//확장자 검사 통과 -> 실패 | |
217 | + System.out.println(multipartFile.getOriginalFilename() + " 파일 확장자 검사 통과 실패");/*삭제 요망*/ | |
218 | + } | |
219 | + } else {//extensions가 존재하지 않으면 -> 파일 생성 | |
220 | + fileCreate(fileUpload, multipartFile); | |
221 | + long endTime = System.currentTimeMillis();/*삭제 요망*/ | |
222 | + long totalTime = endTime - startTime;/*삭제 요망*/ | |
223 | + System.out.println("업로드 경로 : " + fileUpload.getFileAbsolutePath() + ", 파일명 : " + multipartFile.getOriginalFilename() + "(" + fileUpload.getFileMaskName() + ") 파일 업로드 소요시간 : " + totalTime / 1000.0 + "초");/*삭제 요망*/ | |
224 | + } | |
225 | + | |
226 | + return fileUpload; | |
227 | + } | |
228 | + | |
229 | + /** | |
230 | + * @author 최정우 | |
231 | + * @since 2019.11.17 | |
232 | + * | |
233 | + * 실제 디렉토리에 업로드 파일 생성 | |
234 | + */ | |
235 | + public static void fileCreate (CommonFile fileupload, MultipartFile multipartFile) throws Exception { | |
236 | + try { | |
237 | + //디렉토리 만들기. | |
238 | + File dir = new File(fileupload.getFileAbsolutePath()); | |
239 | + boolean isExistDir = true; | |
240 | + if (dir.exists() == false) { | |
241 | + isExistDir = dir.mkdirs(); | |
242 | + } | |
243 | + //디렉토리가 존재할 때 | |
244 | + if (isExistDir == true) { | |
245 | + //디렉토리에 쓰기 권한이 있을 때 | |
246 | + if (dir.canWrite() == true) { | |
247 | + //디렉토리 경로에 파일 생성 | |
248 | + multipartFile.transferTo(new File(fileupload.getFileAbsolutePath(), fileupload.getFileMaskName() + "." + fileupload.getFileExtension())); | |
249 | + fileupload.setCheckMessage(new CheckMessage(true, "파일 활용 가능")); | |
250 | + } else { | |
251 | + fileupload.setCheckMessage(new CheckMessage(false, "쓰기 권한이 없습니다")); | |
252 | + } | |
253 | + } else { | |
254 | + fileupload.setCheckMessage(new CheckMessage(false, "디렉토리 생성 불가")); | |
255 | + } | |
256 | + } catch (Exception e) { | |
257 | + fileupload.setCheckMessage(new CheckMessage(false, "파일 업르드 에러", e.getMessage())); | |
258 | + } | |
259 | + } | |
260 | + | |
261 | + /** | |
262 | + * @author 최정우 | |
263 | + * @since 2019.11.17 | |
264 | + * | |
265 | + * 실제 디렉토리에 업로드 파일 생성 | |
266 | + */ | |
267 | + public static void fileRemove (String fileFullPath) throws Exception { | |
268 | + //commonFile.getFileAbsolutePath() + File.separator + commonFile.getFileMaskName() + "." + commonFile.getFileExtension() | |
269 | + File file = new File(fileFullPath); | |
270 | + if (file.exists()) { | |
271 | + file.delete(); | |
272 | + } | |
273 | + } | |
274 | + | |
275 | + /** | |
276 | + * @author 최정우 | |
277 | + * @since 2019.11.17 | |
278 | + * | |
279 | + * 파일 확장자 얻기 | |
280 | + */ | |
281 | + public static String getFileExtension (String fileName) { | |
282 | + if (StringUtil.isEmpty(fileName) == true) { | |
283 | + return null; | |
284 | + } else { | |
285 | + int index = StringUtil.lastIndexOf(fileName, "."); | |
286 | + if (index > -1) { | |
287 | + return StringUtil.lowerCase(fileName.substring(index + 1)); | |
288 | + } else { | |
289 | + return null; | |
290 | + } | |
291 | + } | |
292 | + } | |
293 | + | |
294 | + /** | |
295 | + * @author 최정우 | |
296 | + * @since 2019.11.17 | |
297 | + * | |
298 | + * 확장자를 제거한 원본 파일명 얻기 | |
299 | + */ | |
300 | + public static String getFileNameExceptExtension (String fileName) { | |
301 | + if (StringUtil.isEmpty(fileName) == true) { | |
302 | + return fileName; | |
303 | + } else { | |
304 | + int index = StringUtil.lastIndexOf(fileName, "."); | |
305 | + if (index > -1) { | |
306 | + return fileName.substring(0, index); | |
307 | + } else { | |
308 | + return fileName; | |
309 | + } | |
310 | + } | |
311 | + } | |
312 | + | |
313 | + /** | |
314 | + * @author 최정우 | |
315 | + * @since 2019.11.17 | |
316 | + * | |
317 | + * File의 용량(byte)을 각 단위에 맞게 변형 | |
318 | + */ | |
319 | + public static String convertFileSize (String bytes) { | |
320 | + String retFormat = "0"; | |
321 | + Double size = Double.parseDouble(bytes); | |
322 | + String[] s = { "bytes", "KB", "MB", "GB", "TB", "PB" }; | |
323 | + if (bytes != null && bytes.length() > 0 && !bytes.equals("0") ) { | |
324 | + int idx = (int) Math.floor(Math.log(size) / Math.log(1024)); | |
325 | + DecimalFormat df = new DecimalFormat("#,###.##"); | |
326 | + double ret = ((size / Math.pow(1024, Math.floor(idx)))); | |
327 | + retFormat = df.format(ret) + " " + s[idx]; | |
328 | + } else { | |
329 | + retFormat += " " + s[0]; | |
330 | + } | |
331 | + | |
332 | + return retFormat; | |
333 | + } | |
334 | +} |
+++ src/back-end/main/java/common/util/HTTPUtil.java
... | ... | @@ -0,0 +1,227 @@ |
1 | +package common.util; | |
2 | + | |
3 | +import java.io.*; | |
4 | +import java.net.HttpURLConnection; | |
5 | +import java.net.MalformedURLException; | |
6 | +import java.net.URL; | |
7 | +import java.net.URLEncoder; | |
8 | +import java.util.Map; | |
9 | + | |
10 | +public class HTTPUtil { | |
11 | + | |
12 | + /** | |
13 | + * @author 최정우 | |
14 | + * @throws Exception | |
15 | + * @since 2020.07.21 | |
16 | + * | |
17 | + * [GET] HTTP 통신 | |
18 | + */ | |
19 | + public synchronized String httpGetConnection (String urlText) { | |
20 | + return httpGetConnection(urlText, null, null); | |
21 | + } | |
22 | + public synchronized String httpGetConnection (String urlText, Map<String, Object> parameter) { | |
23 | + return httpGetConnection(urlText, parameter, null); | |
24 | + } | |
25 | + public synchronized String httpGetConnection (String urlText, Map<String, Object> parameter, Map<String, String> headers) { | |
26 | + StringBuffer response = new StringBuffer(); | |
27 | + | |
28 | + URL url = null; | |
29 | + try { | |
30 | + if (parameter != null && parameter.isEmpty() == false) { | |
31 | + urlText += "?" + createUrlQuery(parameter, "UTF-8"); | |
32 | + System.out.println("url@ : " + urlText); | |
33 | + } | |
34 | + //System.out.println("=====url : "+urlText); | |
35 | + url = new URL(urlText); | |
36 | + } catch (MalformedURLException e) { | |
37 | + // TODO Auto-generated catch block | |
38 | + e.printStackTrace(); | |
39 | + } | |
40 | + | |
41 | + HttpURLConnection httpCon = null; | |
42 | + try { | |
43 | + | |
44 | + /* Connection */ | |
45 | + httpCon = (HttpURLConnection) url.openConnection(); | |
46 | + httpCon.setRequestMethod("GET"); | |
47 | + 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"); | |
48 | + if (headers != null && headers.isEmpty() == false) { | |
49 | + for (String key : headers.keySet()) { | |
50 | + httpCon.setRequestProperty(key, headers.get(key)); | |
51 | + } | |
52 | + } | |
53 | + httpCon.setConnectTimeout(1000 * 60);//http통신 최대 커넥션 시간(1분) | |
54 | + httpCon.setReadTimeout(1000 * 60);//http통신 커넥션 이후, 데이터를 받아오는데 걸리는 최대 시간(1분) | |
55 | + httpCon.setDoInput(true);//받아올 데이터가 있을 때, 사용 | |
56 | + | |
57 | + //HTTP Request 결과 코드 | |
58 | + int responseCode = httpCon.getResponseCode(); | |
59 | + | |
60 | + //Response 결과 데이터 받기 | |
61 | + BufferedReader input = new BufferedReader(new InputStreamReader(httpCon.getInputStream(), "UTF-8"));//"UTF-8" | |
62 | + | |
63 | + //Response 결과 데이터를 문자열로 만들기 | |
64 | + String result = ""; | |
65 | + while ((result = input.readLine()) != null) { | |
66 | + System.out.println("result : " + result); | |
67 | + response.append(result); | |
68 | + } | |
69 | + | |
70 | + //InputStream, BufferedReader 종료 | |
71 | + input.close(); | |
72 | + | |
73 | + //HTTP Connection 종료 | |
74 | + httpCon.disconnect(); | |
75 | + | |
76 | + if (responseCode != 200) { | |
77 | + System.out.println("[HTTP " + responseCode + " 에러]" + url); | |
78 | + } | |
79 | + | |
80 | + } catch (Exception e) { | |
81 | + e.printStackTrace(); | |
82 | + } | |
83 | + //문자열로된 Response 결과 return | |
84 | + return response.toString(); | |
85 | + } | |
86 | + | |
87 | + /** | |
88 | + * @author 최정우 | |
89 | + * @throws Exception | |
90 | + * @since 2020.07.21 | |
91 | + * | |
92 | + * [POST] HTTP 통신 | |
93 | + */ | |
94 | + public synchronized String httpPostConnection (String urlText) { | |
95 | + return httpGetConnection(urlText, null, null); | |
96 | + } | |
97 | + public synchronized String httpPostConnection (String urlText, Map<String, Object> parameter) { | |
98 | + return httpGetConnection(urlText, parameter, null); | |
99 | + } | |
100 | + public synchronized String httpPostConnection (String urlText, Map<String, Object> parameter, Map<String, String> headers) { | |
101 | + StringBuffer response = new StringBuffer(); | |
102 | + | |
103 | + URL url = null; | |
104 | + try { | |
105 | + url = new URL(urlText); | |
106 | + } catch (MalformedURLException e) { | |
107 | + // TODO Auto-generated catch block | |
108 | + e.printStackTrace(); | |
109 | + } | |
110 | + | |
111 | + HttpURLConnection httpCon = null; | |
112 | + try { | |
113 | + /* Connection */ | |
114 | + httpCon = (HttpURLConnection) url.openConnection(); | |
115 | + httpCon.setRequestMethod("POST"); | |
116 | + 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"); | |
117 | + httpCon.setConnectTimeout(1000 * 60);//http통신 최대 커넥션 시간(1분) | |
118 | + httpCon.setReadTimeout(1000 * 60);//http통신 커넥션 이후, 데이터를 받아오는데 걸리는 최대 시간(1분) | |
119 | + httpCon.setDoInput(true);//받아올 데이터가 있을 때, 사용 | |
120 | + | |
121 | + | |
122 | + //보낼 파라메터 데이터가 있을 때 | |
123 | + if (parameter != null && parameter.isEmpty() == false) { | |
124 | + String dataQuery = createUrlQuery(parameter, null); | |
125 | + | |
126 | + httpCon.setRequestProperty("Content-Type", "application/x-www-form-urlencoded");//보낼 데이터의 형태 | |
127 | + httpCon.setRequestProperty("Content-Length", String.valueOf(dataQuery.length())); | |
128 | + if (headers != null && headers.isEmpty() == false) { | |
129 | + for (String key : headers.keySet()) { | |
130 | + httpCon.setRequestProperty(key, headers.get(key)); | |
131 | + } | |
132 | + } | |
133 | + httpCon.setDoOutput(true); | |
134 | + | |
135 | + DataOutputStream wr = new DataOutputStream(httpCon.getOutputStream()); | |
136 | + wr.writeBytes(dataQuery); | |
137 | + wr.flush(); | |
138 | + wr.close(); | |
139 | + } | |
140 | + | |
141 | + //HTTP Request 결과 코드 | |
142 | + int responseCode = httpCon.getResponseCode(); | |
143 | + /*if (responseCode == 200) { | |
144 | + //Response 결과 데이터 받기 | |
145 | + BufferedReader input = new BufferedReader(new InputStreamReader(httpCon.getInputStream())); | |
146 | + | |
147 | + //Response 결과 데이터를 문자열로 만들기 | |
148 | + String result = null; | |
149 | + while ((result = input.readLine()) != null) { | |
150 | + response.append(result); | |
151 | + } | |
152 | + | |
153 | + //InputStream, BufferedReader 종료 | |
154 | + input.close(); | |
155 | + | |
156 | + //HTTP Connection 종료 | |
157 | + httpCon.disconnect(); | |
158 | + } else { | |
159 | + System.out.println("[HTTP " + responseCode + " 에러]" + url); | |
160 | + }*/ | |
161 | + | |
162 | + //Response 결과 데이터 받기 | |
163 | + BufferedReader input = new BufferedReader(new InputStreamReader(httpCon.getInputStream())); | |
164 | + | |
165 | + //Response 결과 데이터를 문자열로 만들기 | |
166 | + String result = ""; | |
167 | + while ((result = input.readLine()) != null) { | |
168 | + response.append(result); | |
169 | + } | |
170 | + | |
171 | + //InputStream, BufferedReader 종료 | |
172 | + input.close(); | |
173 | + | |
174 | + //HTTP Connection 종료 | |
175 | + httpCon.disconnect(); | |
176 | + | |
177 | + if (responseCode != 200) { | |
178 | + System.out.println("[HTTP " + responseCode + " 에러]" + url); | |
179 | + } | |
180 | + | |
181 | + } catch (IOException e) { | |
182 | + // TODO Auto-generated catch block | |
183 | + e.printStackTrace(); | |
184 | + } | |
185 | + | |
186 | + //문자열로된 Response 결과 return | |
187 | + return response.toString(); | |
188 | + } | |
189 | + | |
190 | + /** | |
191 | + * @author 최정우 | |
192 | + * @throws Exception | |
193 | + * @since 2020.07.21 | |
194 | + * | |
195 | + * 파라메터 데이터를 HTTP통신을 위한 문자열로 변환시켜주는 메서드 | |
196 | + * Map -> String | |
197 | + */ | |
198 | + public String createUrlQuery (Map<String, Object> parameter, String encoding) { | |
199 | + if (parameter.isEmpty() == true) { | |
200 | + return ""; | |
201 | + } else { | |
202 | + StringBuilder query = new StringBuilder(); | |
203 | + for(Map.Entry<String,Object> param : parameter.entrySet()) { | |
204 | + try { | |
205 | + if(query.length() > 0) { | |
206 | + query.append('&'); | |
207 | + } | |
208 | + | |
209 | + if (StringUtil.isEmpty(encoding) == true) { | |
210 | + query.append(param.getKey()); | |
211 | + query.append('='); | |
212 | + query.append(param.getValue()); | |
213 | + } else { | |
214 | + query.append(URLEncoder.encode(param.getKey(), encoding)); | |
215 | + query.append('='); | |
216 | + query.append(URLEncoder.encode(String.valueOf(param.getValue()), encoding)); | |
217 | + } | |
218 | + | |
219 | + } catch (UnsupportedEncodingException e) { | |
220 | + e.printStackTrace(); | |
221 | + } | |
222 | + } | |
223 | + | |
224 | + return query.toString(); | |
225 | + } | |
226 | + } | |
227 | +} |
+++ src/back-end/main/java/common/util/JsonUtil.java
... | ... | @@ -0,0 +1,6 @@ |
1 | +package common.util; | |
2 | + | |
3 | +public class JsonUtil { | |
4 | + | |
5 | + | |
6 | +} |
+++ src/back-end/main/java/common/util/StringUtil.java
... | ... | @@ -0,0 +1,1001 @@ |
1 | +package common.util; | |
2 | + | |
3 | +import org.slf4j.Logger; | |
4 | +import org.slf4j.LoggerFactory; | |
5 | + | |
6 | +import java.io.UnsupportedEncodingException; | |
7 | +import java.sql.Timestamp; | |
8 | +import java.text.SimpleDateFormat; | |
9 | +import java.util.*; | |
10 | + | |
11 | +/** | |
12 | + * @author 최정우 | |
13 | + * @since 2019.11.13 | |
14 | + * | |
15 | + * 문자열과 관련된 기능을 정의 해놓은 Util입니다. | |
16 | + */ | |
17 | +public class StringUtil { | |
18 | + | |
19 | + private static final Logger LOGGER = LoggerFactory.getLogger(StringUtil.class); | |
20 | + | |
21 | + public static final String NULL_TEXT = "NULL"; | |
22 | + | |
23 | + public static String toString(Object obj) { | |
24 | + if (obj == null) { | |
25 | + return null; | |
26 | + } else { | |
27 | + try { | |
28 | + return obj.toString(); | |
29 | + } catch (Exception e) { | |
30 | + e.printStackTrace(); | |
31 | + return null; | |
32 | + } | |
33 | + } | |
34 | + } | |
35 | + | |
36 | + public static String toStringNotNull(Object obj) { | |
37 | + if (obj == null) { | |
38 | + return ""; | |
39 | + } else { | |
40 | + try { | |
41 | + return obj.toString(); | |
42 | + } catch (Exception e) { | |
43 | + return ""; | |
44 | + } | |
45 | + } | |
46 | + } | |
47 | + | |
48 | + /** | |
49 | + * @author 최정우 | |
50 | + * @since 2020.11.26 | |
51 | + * | |
52 | + * 객체를 문자열로 바꾼 후, 문자열 길이 반환 | |
53 | + */ | |
54 | + public static int stringLength(Object obj) { | |
55 | + if (obj == null) { | |
56 | + return 0; | |
57 | + } else { | |
58 | + try { | |
59 | + return obj.toString().length(); | |
60 | + } catch (Exception e) { | |
61 | + return 0; | |
62 | + } | |
63 | + } | |
64 | + } | |
65 | + | |
66 | + /** | |
67 | + * @author 최정우 | |
68 | + * @since 2020.11.26 | |
69 | + * | |
70 | + * 문자열이 Null or null or NULL인 경우 실제 null값 세팅 | |
71 | + */ | |
72 | + public static boolean isNullText(String text) { | |
73 | + if (isEmpty(text) == false && text.toUpperCase().equals(NULL_TEXT)) { | |
74 | + return true; | |
75 | + } else { | |
76 | + return false; | |
77 | + } | |
78 | + } | |
79 | + | |
80 | + /** | |
81 | + * @author 최정우 | |
82 | + * @since 2019.11.13 | |
83 | + * | |
84 | + * 빈 문자열 검사 | |
85 | + */ | |
86 | + public static boolean isEmpty(String text) { | |
87 | + return text == null || text.trim().length() == 0; | |
88 | + } | |
89 | + | |
90 | + /** | |
91 | + * @author 최정우 | |
92 | + * @since 2019.11.13 | |
93 | + * | |
94 | + * indexOf - 문자 검색 후, 해당 문자의 위치(index)반환 | |
95 | + */ | |
96 | + public static int indexOf(String text, String searchText) { | |
97 | + if (text == null || searchText == null) { | |
98 | + return -1; | |
99 | + } | |
100 | + return text.indexOf(searchText); | |
101 | + } | |
102 | + | |
103 | + /** | |
104 | + * @author 최정우 | |
105 | + * @since 2019.11.13 | |
106 | + * | |
107 | + * lastIndexOf - 문자 검색 후, 해당 문자의 위치(index)반환 | |
108 | + */ | |
109 | + public static int lastIndexOf(String text, String searchText) { | |
110 | + if (text == null || searchText == null) { | |
111 | + return -1; | |
112 | + } | |
113 | + return text.lastIndexOf(searchText); | |
114 | + } | |
115 | + | |
116 | + /** | |
117 | + * @author 최정우 | |
118 | + * @since 2019.11.13 | |
119 | + * | |
120 | + * substringBetween - 특정 문자열 사이에 값을 뽑아내는 메서드 | |
121 | + */ | |
122 | + public static String substringBetween(String text, String startText, String endText) { | |
123 | + if (isEmpty(text) == true || isEmpty(startText) == true || isEmpty(endText) == true) { | |
124 | + return null; | |
125 | + } | |
126 | + text = text.toLowerCase(); | |
127 | + startText = startText.toLowerCase(); | |
128 | + endText = endText.toLowerCase(); | |
129 | + | |
130 | + int start = text.indexOf(startText); | |
131 | + if (start != -1) { | |
132 | + int end = text.indexOf(endText, start + startText.length()); | |
133 | + if (end != -1) { | |
134 | + return text.substring(start + startText.length(), end); | |
135 | + } | |
136 | + } | |
137 | + return null; | |
138 | + } | |
139 | + | |
140 | + /** | |
141 | + * @author 최정우 | |
142 | + * @since 2019.11.13 | |
143 | + * | |
144 | + * 모든 공백 제거 | |
145 | + */ | |
146 | + public static String removeSpace(String text) { | |
147 | + if (isEmpty(text)) { | |
148 | + return text; | |
149 | + } | |
150 | + int length = text.length(); | |
151 | + char[] newCharList = new char[length]; | |
152 | + int count = 0; | |
153 | + for (int i = 0; i < length; i++) { | |
154 | + if (Character.isWhitespace(text.charAt(i)) == false) { | |
155 | + newCharList[count++] = text.charAt(i); | |
156 | + } | |
157 | + } | |
158 | + if (count == length) { | |
159 | + return text; | |
160 | + } | |
161 | + | |
162 | + return new String(newCharList, 0, count); | |
163 | + } | |
164 | + | |
165 | + /** | |
166 | + * @author 최정우 | |
167 | + * @since 2019.11.13 | |
168 | + * | |
169 | + * html의 특수문자를 표현하기 위해 | |
170 | + */ | |
171 | + public static String textToHtml(String text) { | |
172 | + text = text.replaceAll("<", "<"); | |
173 | + text = text.replaceAll(">", ">"); | |
174 | + text = text.replaceAll("&", "&"); | |
175 | + text = text.replaceAll(" ", " "); | |
176 | + text = text.replaceAll("'", "\'"); | |
177 | + text = text.replaceAll(""", "\""); | |
178 | + return text; | |
179 | + } | |
180 | + | |
181 | + /** | |
182 | + * @author 최정우 | |
183 | + * @since 2019.11.13 | |
184 | + * | |
185 | + * Html 코드가 들어간 문서를 표시할때 태그에 손상없이 보이기 위한 메서드 | |
186 | + */ | |
187 | + public static String htmlToText(String text) { | |
188 | + StringBuffer textBuffer = new StringBuffer(""); | |
189 | + | |
190 | + char character; | |
191 | + int length = text.length(); | |
192 | + | |
193 | + for (int i = 0; i < length; i++) { | |
194 | + character = (char) text.charAt(i); | |
195 | + | |
196 | + switch (character) { | |
197 | + case '<': | |
198 | + textBuffer.append("<"); | |
199 | + break; | |
200 | + case '>': | |
201 | + textBuffer.append(">"); | |
202 | + break; | |
203 | + case '"': | |
204 | + textBuffer.append("""); | |
205 | + break; | |
206 | + case 10: | |
207 | + textBuffer.append("<br>"); | |
208 | + break; | |
209 | + case ' ': | |
210 | + textBuffer.append(" "); | |
211 | + break; | |
212 | + //case '&' : | |
213 | + //strTxt.append("&"); | |
214 | + //break; | |
215 | + default: | |
216 | + textBuffer.append(character); | |
217 | + } | |
218 | + } | |
219 | + | |
220 | + text = textBuffer.toString(); | |
221 | + return text; | |
222 | + } | |
223 | + | |
224 | + public static String cleanXSS (String value) { | |
225 | + return value | |
226 | + .replaceAll("<", "<") | |
227 | + .replaceAll(">", ">") | |
228 | + .replaceAll("\\(", "(") | |
229 | + .replaceAll("\\)", ")") | |
230 | + .replaceAll("'", "'") | |
231 | + .replaceAll("eval\\((.*)\\)", "") | |
232 | + .replaceAll("[\\\"\\\'][\\s]*javascript:(.*)[\\\"\\\']", "\"\"") | |
233 | + .replaceAll("(?!)script", "") | |
234 | + .replaceAll("(?!)iframe", "") | |
235 | + .replaceAll("\'", "") | |
236 | + .replaceAll(";", ""); | |
237 | + } | |
238 | + | |
239 | + public static String cleanSQL (String value) { | |
240 | + return value | |
241 | + .replaceAll("(?!)SELECT", "") | |
242 | + .replaceAll("(?!)INSERT", "") | |
243 | + .replaceAll("(?!)DELETE", "") | |
244 | + .replaceAll("(?!)UPDATE", "") | |
245 | + .replaceAll("(?!)CREATE", "") | |
246 | + .replaceAll("(?!)REPLACE", "") | |
247 | + .replaceAll("(?!)DROP", "") | |
248 | + .replaceAll("(?!)LIMIT", "") | |
249 | + .replaceAll("(?!)AND", "") | |
250 | + .replaceAll("(?!)OR", "") | |
251 | + .replaceAll("(?!)IN", "") | |
252 | + .replaceAll("(?!)JOIN", "") | |
253 | + .replaceAll("(?!)IF", "") | |
254 | + .replaceAll("(?!)CASE", "") | |
255 | + .replaceAll("(?!)IS", "") | |
256 | + .replaceAll("(?!)NULL", "") | |
257 | + .replaceAll("(?!)ALL", "") | |
258 | + .replaceAll("(?!)KILL", "") | |
259 | + .replaceAll("(?!)UNION", "") | |
260 | + .replaceAll("(?!)BETWEEN", "") | |
261 | + .replaceAll("(?!)LIKE", "") | |
262 | + .replaceAll("(?!)ADD", "") | |
263 | + .replaceAll("(?!)DATABASE", "") | |
264 | + .replaceAll("(?!)ALTER", "") | |
265 | + .replaceAll("(?!)VALUE", "") | |
266 | + | |
267 | + .replaceAll("'", "") | |
268 | + .replaceAll("`", "") | |
269 | + .replaceAll("=", "") | |
270 | + .replaceAll(">", "") | |
271 | + .replaceAll("<", "") | |
272 | + .replaceAll("/", "") | |
273 | + .replaceAll("#", "") | |
274 | + .replaceAll("--", "") | |
275 | + .replaceAll(";", ""); | |
276 | + } | |
277 | + | |
278 | + /** | |
279 | + * @author 최정우 | |
280 | + * @since 2019.11.13 | |
281 | + * | |
282 | + * 문자열을 지정한 분리자에 의해 배열로 리턴하는 메서드. | |
283 | + */ | |
284 | + public static ArrayList<String> split(String text, String separator) throws NullPointerException { | |
285 | + ArrayList<String> words = new ArrayList<String>(); | |
286 | + if (isEmpty(text) == false && separator != null) { | |
287 | + int startIndex = -1; | |
288 | + int endIndex = -1; | |
289 | + while(true) { | |
290 | + startIndex++; | |
291 | + endIndex = text.indexOf(separator, startIndex); | |
292 | + if (endIndex > -1) { | |
293 | + words.add(text.substring(startIndex, endIndex)); | |
294 | + startIndex = endIndex; | |
295 | + } else { | |
296 | + words.add(text.substring(startIndex, text.length())); | |
297 | + break; | |
298 | + } | |
299 | + } | |
300 | + return words; | |
301 | + } else { | |
302 | + if (isEmpty(text) == false) { | |
303 | + words.add(text); | |
304 | + } | |
305 | + return words; | |
306 | + } | |
307 | + } | |
308 | + | |
309 | + /** | |
310 | + * @author 최정우 | |
311 | + * @since 2019.11.13 | |
312 | + * | |
313 | + * 문자열을 지정한 여러개의 분리자에 의해 배열로 리턴하는 메서드. | |
314 | + */ | |
315 | + public static ArrayList<String> split(String text, String[] separator) throws NullPointerException { | |
316 | + ArrayList<String> words = new ArrayList<String>(); | |
317 | + if (isEmpty(text) == false && separator != null && separator.length > 0) { | |
318 | + words.add(text); | |
319 | + for (int i = 0; i < separator.length; i++) { | |
320 | + ArrayList<String> subWords = new ArrayList<String>(); | |
321 | + for (int j = 0; j < words.size(); j++) { | |
322 | + subWords.addAll(split(words.get(j), separator[i])); | |
323 | + } | |
324 | + words = subWords; | |
325 | + } | |
326 | + return words; | |
327 | + } else { | |
328 | + return words; | |
329 | + } | |
330 | + } | |
331 | + | |
332 | + /** | |
333 | + * @author 최정우 | |
334 | + * @since 2019.11.13 | |
335 | + * | |
336 | + * 문자열을 지정한 분리자에 의해 지정된 길이의 배열로 리턴하는 메서드. | |
337 | + */ | |
338 | + public static ArrayList<String> split(String text, String separator, int maxLength) throws NullPointerException { | |
339 | + ArrayList<String> list = new ArrayList<String>(); | |
340 | + int startIndex = -1; | |
341 | + int endIndex = -1; | |
342 | + while(true) { | |
343 | + startIndex++; | |
344 | + endIndex = text.indexOf(separator, startIndex); | |
345 | + if (endIndex > -1) { | |
346 | + list.add(text.substring(startIndex, endIndex)); | |
347 | + startIndex = endIndex; | |
348 | + } else { | |
349 | + list.add(text.substring(startIndex, text.length())); | |
350 | + break; | |
351 | + } | |
352 | + | |
353 | + if (list.size() >= maxLength) { | |
354 | + break; | |
355 | + } | |
356 | + } | |
357 | + return list; | |
358 | + } | |
359 | + | |
360 | + /** | |
361 | + * @author 최정우 | |
362 | + * @since 2019.11.13 | |
363 | + * | |
364 | + * 소문자 변환 | |
365 | + */ | |
366 | + public static String lowerCase(String text) { | |
367 | + if (isEmpty(text) == true) { | |
368 | + return text; | |
369 | + } else { | |
370 | + return text.toLowerCase(); | |
371 | + } | |
372 | + } | |
373 | + | |
374 | + /** | |
375 | + * 대문자 변환 | |
376 | + */ | |
377 | + public static String upperCase(String text) { | |
378 | + if (isEmpty(text) == true) { | |
379 | + return text; | |
380 | + } else { | |
381 | + return text.toUpperCase(); | |
382 | + } | |
383 | + } | |
384 | + | |
385 | + /** | |
386 | + * @author 최정우 | |
387 | + * @since 2019.11.13 | |
388 | + * | |
389 | + * 현재날짜(년,월,일)를 구하는 기능 | |
390 | + */ | |
391 | + public static String getToday() { | |
392 | + String pattern = "yyyy-MM-dd"; | |
393 | + SimpleDateFormat dateFormat = new SimpleDateFormat(pattern, Locale.KOREA); | |
394 | + Timestamp timestamp = new Timestamp(System.currentTimeMillis()); | |
395 | + return dateFormat.format(timestamp.getTime()); | |
396 | + } | |
397 | + | |
398 | + /** | |
399 | + * @author 최정우 | |
400 | + * @since 2019.11.13 | |
401 | + * | |
402 | + * 현재날짜(년,월,일)를 구하는 기능 | |
403 | + */ | |
404 | + public static String getToday(String pattern) { | |
405 | + String defaultPattern = "yyyy-MM-dd"; | |
406 | + if (isEmpty(pattern) == true) { | |
407 | + pattern = defaultPattern; | |
408 | + } | |
409 | + | |
410 | + SimpleDateFormat dateFormat = null; | |
411 | + try { | |
412 | + dateFormat = new SimpleDateFormat(pattern, Locale.KOREA); | |
413 | + } catch (Exception e) { | |
414 | + dateFormat = new SimpleDateFormat(defaultPattern, Locale.KOREA); | |
415 | + } | |
416 | + Timestamp timestamp = new Timestamp(System.currentTimeMillis()); | |
417 | + return dateFormat.format(timestamp.getTime()); | |
418 | + } | |
419 | + | |
420 | + /** | |
421 | + * @author 최정우 | |
422 | + * @since 2019.11.13 | |
423 | + * | |
424 | + * 현재날짜(년,월,일)를 구하는 기능 | |
425 | + */ | |
426 | + public static String getToday(String yearSuffix, String monthSuffix, String daySuffix) { | |
427 | + String defaultPattern = "yyyy년MM월dd일"; | |
428 | + if (isEmpty(yearSuffix) == true) { | |
429 | + yearSuffix = ""; | |
430 | + } | |
431 | + if (isEmpty(monthSuffix) == true) { | |
432 | + monthSuffix = ""; | |
433 | + } | |
434 | + if (isEmpty(daySuffix) == true) { | |
435 | + daySuffix = ""; | |
436 | + } | |
437 | + | |
438 | + String pattern = "yyyy" + yearSuffix + "MM" + monthSuffix + "dd" + daySuffix; | |
439 | + | |
440 | + SimpleDateFormat dateFormat = null; | |
441 | + try { | |
442 | + dateFormat = new SimpleDateFormat(pattern, Locale.KOREA); | |
443 | + } catch (Exception e) { | |
444 | + dateFormat = new SimpleDateFormat(defaultPattern, Locale.KOREA); | |
445 | + } | |
446 | + Timestamp timestamp = new Timestamp(System.currentTimeMillis()); | |
447 | + return dateFormat.format(timestamp.getTime()); | |
448 | + } | |
449 | + | |
450 | + /** | |
451 | + * @author 최정우 | |
452 | + * @since 2019.11.13 | |
453 | + * | |
454 | + * 17자리의 현재일시를 구하는 기능 | |
455 | + */ | |
456 | + public static String getDateTime() { | |
457 | + // 문자열로 변환하기 위한 패턴 설정(년도-월-일 시:분:초:초(자정이후 초)) | |
458 | + String pattern = "yyyyMMddHHmmssSSS"; | |
459 | + SimpleDateFormat dateFormat = new SimpleDateFormat(pattern, Locale.KOREA); | |
460 | + Timestamp timestamp = new Timestamp(System.currentTimeMillis()); | |
461 | + return dateFormat.format(timestamp.getTime()); | |
462 | + } | |
463 | + | |
464 | + /** | |
465 | + * @author 최정우 | |
466 | + * @since 2019.11.13 | |
467 | + * | |
468 | + * 원하는 패턴의 현재일시 구하는 기능 | |
469 | + */ | |
470 | + public static String getDateTime(String pattern) { | |
471 | + // 문자열로 변환하기 위한 패턴 설정(년도-월-일 시:분:초:초(자정이후 초)) | |
472 | + String defaultPattern = "yyyyMMddHHmmssSSS"; | |
473 | + if (isEmpty(pattern)) { | |
474 | + pattern = defaultPattern; | |
475 | + } | |
476 | + SimpleDateFormat dateFormat = null; | |
477 | + try { | |
478 | + dateFormat = new SimpleDateFormat(pattern, Locale.KOREA); | |
479 | + } catch (Exception e) { | |
480 | + dateFormat = new SimpleDateFormat(defaultPattern, Locale.KOREA); | |
481 | + } | |
482 | + Timestamp timestamp = new Timestamp(System.currentTimeMillis()); | |
483 | + return dateFormat.format(timestamp.getTime()); | |
484 | + } | |
485 | + | |
486 | + /** | |
487 | + * @author 최정우 | |
488 | + * @since 2019.11.13 | |
489 | + * | |
490 | + * 현재 일시 - addDay => 원하는 패턴의 일시를 구하는 기능 | |
491 | + */ | |
492 | + public static String getDateTime(String pattern, int addDay) { | |
493 | + // 문자열로 변환하기 위한 패턴 설정(년도-월-일 시:분:초:초(자정이후 초)) | |
494 | + String defaultPattern = "yyyyMMddHHmmssSSS"; | |
495 | + if (pattern == null) { | |
496 | + pattern = defaultPattern; | |
497 | + } | |
498 | + SimpleDateFormat dateFormat = null; | |
499 | + try { | |
500 | + dateFormat = new SimpleDateFormat(pattern, Locale.KOREA); | |
501 | + } catch (Exception e) { | |
502 | + dateFormat = new SimpleDateFormat(defaultPattern, Locale.KOREA); | |
503 | + } | |
504 | + Calendar cal = new GregorianCalendar(); | |
505 | + cal.add(Calendar.DATE, addDay); | |
506 | + Date date = cal.getTime(); | |
507 | + return dateFormat.format(date.getTime()); | |
508 | + } | |
509 | + | |
510 | + /** | |
511 | + * @author 최정우 | |
512 | + * @since 2019.11.13 | |
513 | + * | |
514 | + * 현재 일시 - addDay => 원하는 패턴의 일시를 구하는 기능 | |
515 | + */ | |
516 | + public static String getDateTime(String pattern, int addDay, int addHour, int addMin, int addSec) { | |
517 | + // 문자열로 변환하기 위한 패턴 설정(년도-월-일 시:분:초:초(자정이후 초)) | |
518 | + String defaultPattern = "yyyyMMddHHmmssSSS"; | |
519 | + if (pattern == null) { | |
520 | + pattern = defaultPattern; | |
521 | + } | |
522 | + SimpleDateFormat dateFormat = null; | |
523 | + try { | |
524 | + dateFormat = new SimpleDateFormat(pattern, Locale.KOREA); | |
525 | + } catch (Exception e) { | |
526 | + dateFormat = new SimpleDateFormat(defaultPattern, Locale.KOREA); | |
527 | + } | |
528 | + Calendar cal = new GregorianCalendar(); | |
529 | + cal.add(Calendar.DATE, addDay); | |
530 | + cal.add(Calendar.HOUR, addHour); | |
531 | + cal.add(Calendar.MINUTE, addMin); | |
532 | + cal.add(Calendar.SECOND, addSec); | |
533 | + Date date = cal.getTime(); | |
534 | + return dateFormat.format(date.getTime()); | |
535 | + } | |
536 | + | |
537 | + /** | |
538 | + * @author 최정우 | |
539 | + * @since 2021.12.05 | |
540 | + * | |
541 | + * String -> Date | |
542 | + */ | |
543 | + public static Date stringToDate (String date, String pattern) { | |
544 | + Date result = null; | |
545 | + try { | |
546 | + SimpleDateFormat transFormat = new SimpleDateFormat(pattern); | |
547 | + result = transFormat.parse(date); | |
548 | + } catch (Exception e) { | |
549 | + e.printStackTrace(); | |
550 | + } | |
551 | + return result; | |
552 | + } | |
553 | + | |
554 | + /** | |
555 | + * @author 최정우 | |
556 | + * @since 2021.12.05 | |
557 | + * | |
558 | + * Date -> String | |
559 | + */ | |
560 | + public static String dateToString (Date date, String pattern) { | |
561 | + String result = null; | |
562 | + try { | |
563 | + SimpleDateFormat transFormat = new SimpleDateFormat(pattern); | |
564 | + result = transFormat.format(date); | |
565 | + } catch (Exception e) { | |
566 | + e.printStackTrace(); | |
567 | + } | |
568 | + return result; | |
569 | + } | |
570 | + | |
571 | + /** | |
572 | + * @author 최정우 | |
573 | + * @since 2019.11.13 | |
574 | + * | |
575 | + * 현재 일시(17자리)와, 랜덤숫자(4자리)를 이용하여 키값 생성 | |
576 | + */ | |
577 | + public static String getCreateKey (String prefix) { | |
578 | + int random = new Random().nextInt(9999); | |
579 | + String result = prefix + "_" + getDateTime() + "_" + numberToText(random, 4); | |
580 | + return result; | |
581 | + } | |
582 | + | |
583 | + /** | |
584 | + * @author 최정우 | |
585 | + * @since 2019.11.13 | |
586 | + * | |
587 | + * 현재 일시(17자리)와, 랜덤숫자(4자리)를 이용하여 키값 생성 | |
588 | + */ | |
589 | + public static String getRandomKey (int length) { | |
590 | + char[][] characters = { | |
591 | + {'!', '@', '#', '$', '%', '^', '&', '*', '-', '_', '+', '='}, | |
592 | + {'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'}, | |
593 | + {'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'}, | |
594 | + {'1', '2', '3', '4', '5', '6', '7', '8', '9', '0'} | |
595 | + }; | |
596 | + | |
597 | + String randomText = ""; | |
598 | + for (int i = 0; i < length; i++) { | |
599 | + int randomIndex1 = CommonUtil.getRandomInt(0, characters.length - 1); | |
600 | + char[] chars = characters[randomIndex1]; | |
601 | + int randomIndex2 = CommonUtil.getRandomInt(0, chars.length - 1); | |
602 | + randomText += chars[randomIndex2]; | |
603 | + } | |
604 | + | |
605 | + return randomText; | |
606 | + } | |
607 | + | |
608 | + /** | |
609 | + * @author 최정우 | |
610 | + * @since 2019.11.13 | |
611 | + * | |
612 | + * 문자열이 Date문자열(yyyy-MM-dd)로 포맷 가능한지 | |
613 | + * text: 문자열 | |
614 | + * pattern: 문자열의 날짜 패턴 | |
615 | + */ | |
616 | + public static boolean isDate(String text, String pattern) { | |
617 | + try { | |
618 | + Date date = new SimpleDateFormat(pattern).parse(text); | |
619 | + text = new SimpleDateFormat("yyyy-MM-dd").format(date); | |
620 | + return true; | |
621 | + } catch (java.text.ParseException e) { | |
622 | + // TODO Auto-generated catch block | |
623 | + return false; | |
624 | + } | |
625 | + } | |
626 | + | |
627 | + /** | |
628 | + * @author 최정우 | |
629 | + * @since 2019.11.13 | |
630 | + * | |
631 | + * 문자열을 날짜형태로 Convert | |
632 | + * text: 문자열 | |
633 | + * pattern: 문자열의 날짜 패턴 | |
634 | + * newPattern: 해당 문자열을 Converting할 날짜 패턴 | |
635 | + */ | |
636 | + public static String textToDateText (String text, String pattern, String newPattern) { | |
637 | + String defaultPattern = "yyyy-MM-dd"; | |
638 | + if (isEmpty(newPattern) == true) { | |
639 | + newPattern = defaultPattern; | |
640 | + } | |
641 | + | |
642 | + SimpleDateFormat dateFormat = new SimpleDateFormat(pattern); | |
643 | + Date date = new Date(); | |
644 | + try { | |
645 | + date = dateFormat.parse(text); | |
646 | + dateFormat.applyPattern(newPattern); | |
647 | + return dateFormat.format(date); | |
648 | + } catch (Exception e) { | |
649 | + //e.printStackTrace(); | |
650 | + return text; | |
651 | + } | |
652 | + } | |
653 | + | |
654 | + /** | |
655 | + * @author 최정우 | |
656 | + * @since 2019.11.13 | |
657 | + * | |
658 | + * 숫자 -> 문자열 -> 문자열 길이가 length보다 작을 때, length길이 만큼될 수 있도록 앞에 '0'을 붙여줌 | |
659 | + */ | |
660 | + public static String numberToText (int number, int length) { | |
661 | + String text = Integer.toString(number); | |
662 | + if (text.length() < length) { | |
663 | + int emptyLength = length - text.length(); | |
664 | + for (int i = 0; i < emptyLength; i++) { | |
665 | + text = "0" + text; | |
666 | + } | |
667 | + } | |
668 | + return text; | |
669 | + } | |
670 | + | |
671 | + /** | |
672 | + * @author 최정우 | |
673 | + * @since 2019.11.13 | |
674 | + * | |
675 | + * 문자열이 지정한 길이를 초과했을때 해당 문자열을 삭제하는 메서드 | |
676 | + * @param text 원본 문자열 배열 | |
677 | + * @param maxLength 지정길이 | |
678 | + * @return 지정길이로 자른 문자열 | |
679 | + */ | |
680 | + public static String cutString(String text, int maxLength) { | |
681 | + String result = null; | |
682 | + if (text != null) { | |
683 | + if (text.length() > maxLength) { | |
684 | + result = text.substring(0, maxLength); | |
685 | + } else | |
686 | + result = text; | |
687 | + } | |
688 | + return result; | |
689 | + } | |
690 | + | |
691 | + | |
692 | + /** | |
693 | + * @author 최정우 | |
694 | + * @since 2019.11.13 | |
695 | + * | |
696 | + * 문자열이 지정한 길이를 초과했을때 지정한길이에다가 해당 문자열을 붙여주는 메서드. | |
697 | + * @param text 원본 문자열 배열 | |
698 | + * @param addText 더할문자열 | |
699 | + * @param maxLength 지정길이 | |
700 | + * @return 지정길이로 잘라서 더할분자열 합친 문자열 | |
701 | + */ | |
702 | + public static String cutString(String text, String addText, int maxLength) { | |
703 | + String result = null; | |
704 | + if (text != null) { | |
705 | + if (text.length() > maxLength) { | |
706 | + result = text.substring(0, maxLength) + addText; | |
707 | + } else | |
708 | + result = text; | |
709 | + } | |
710 | + return result; | |
711 | + } | |
712 | + | |
713 | + | |
714 | + /** | |
715 | + * @author 최정우 | |
716 | + * @since 2019.11.13 | |
717 | + * | |
718 | + * <p>기준 문자열에 포함된 모든 대상 문자(char)를 제거한다.</p> | |
719 | + * | |
720 | + * <pre> | |
721 | + * StringUtil.remove(null, *) = null | |
722 | + * StringUtil.remove("", *) = "" | |
723 | + * StringUtil.remove("queued", 'u') = "qeed" | |
724 | + * StringUtil.remove("queued", 'z') = "queued" | |
725 | + * </pre> | |
726 | + * | |
727 | + * @param text 입력받는 기준 문자열 | |
728 | + * @param remove 입력받는 문자열에서 제거할 대상 문자열 | |
729 | + * @return 제거대상 문자열이 제거된 입력문자열. 입력문자열이 null인 경우 출력문자열은 null | |
730 | + */ | |
731 | + public static String remove(String text, char remove) { | |
732 | + if (isEmpty(text) || text.indexOf(remove) == -1) { | |
733 | + return text; | |
734 | + } | |
735 | + char[] chars = text.toCharArray(); | |
736 | + int pos = 0; | |
737 | + for (int i = 0; i < chars.length; i++) { | |
738 | + if (chars[i] != remove) { | |
739 | + chars[pos++] = chars[i]; | |
740 | + } | |
741 | + } | |
742 | + | |
743 | + return new String(chars, 0, pos); | |
744 | + } | |
745 | + | |
746 | + | |
747 | + /** | |
748 | + * @author 최정우 | |
749 | + * @since 2019.11.13 | |
750 | + * | |
751 | + * 원본 문자열의 포함된 특정 문자열을 새로운 문자열로 변환하는 메서드 | |
752 | + * @param text 원본 문자열 | |
753 | + * @param subject 원본 문자열에 포함된 특정 문자열 | |
754 | + * @param object 변환할 문자열 | |
755 | + * @return sb.toString() 새로운 문자열로 변환된 문자열 | |
756 | + */ | |
757 | + public static String replace(String text, String subject, String object) { | |
758 | + StringBuffer rtnStr = new StringBuffer(); | |
759 | + String preStr = ""; | |
760 | + String nextStr = text; | |
761 | + String srcStr = text; | |
762 | + | |
763 | + while (srcStr.indexOf(subject) >= 0) { | |
764 | + preStr = srcStr.substring(0, srcStr.indexOf(subject)); | |
765 | + nextStr = srcStr.substring(srcStr.indexOf(subject) + subject.length(), srcStr.length()); | |
766 | + srcStr = nextStr; | |
767 | + rtnStr.append(preStr).append(object); | |
768 | + } | |
769 | + rtnStr.append(nextStr); | |
770 | + return rtnStr.toString(); | |
771 | + } | |
772 | + | |
773 | + /** | |
774 | + * @author 최정우 | |
775 | + * @since 2019.11.13 | |
776 | + * | |
777 | + * 원본 문자열의 포함된 특정 문자열 첫번째 한개만 새로운 문자열로 변환하는 메서드 | |
778 | + * @param source 원본 문자열 | |
779 | + * @param subject 원본 문자열에 포함된 특정 문자열 | |
780 | + * @param object 변환할 문자열 | |
781 | + * @return sb.toString() 새로운 문자열로 변환된 문자열 / source 특정문자열이 없는 경우 원본 문자열 | |
782 | + */ | |
783 | + public static String replaceOnce(String source, String subject, String object) { | |
784 | + StringBuffer rtnStr = new StringBuffer(); | |
785 | + String preStr = ""; | |
786 | + String nextStr = source; | |
787 | + if (source.indexOf(subject) >= 0) { | |
788 | + preStr = source.substring(0, source.indexOf(subject)); | |
789 | + nextStr = source.substring(source.indexOf(subject) + subject.length(), source.length()); | |
790 | + rtnStr.append(preStr).append(object).append(nextStr); | |
791 | + return rtnStr.toString(); | |
792 | + } else { | |
793 | + return source; | |
794 | + } | |
795 | + } | |
796 | + | |
797 | + /** | |
798 | + * @author 최정우 | |
799 | + * @since 2019.11.13 | |
800 | + * | |
801 | + * <code>subject</code>에 포함된 각각의 문자를 object로 변환한다. | |
802 | + * | |
803 | + * @param source 원본 문자열 | |
804 | + * @param subject 원본 문자열에 포함된 특정 문자열 | |
805 | + * @param object 변환할 문자열 | |
806 | + * @return sb.toString() 새로운 문자열로 변환된 문자열 | |
807 | + */ | |
808 | + public static String replaceChar(String source, String subject, String object) { | |
809 | + StringBuffer rtnStr = new StringBuffer(); | |
810 | + String preStr = ""; | |
811 | + String nextStr = source; | |
812 | + String srcStr = source; | |
813 | + | |
814 | + char chA; | |
815 | + | |
816 | + for (int i = 0; i < subject.length(); i++) { | |
817 | + chA = subject.charAt(i); | |
818 | + | |
819 | + if (srcStr.indexOf(chA) >= 0) { | |
820 | + preStr = srcStr.substring(0, srcStr.indexOf(chA)); | |
821 | + nextStr = srcStr.substring(srcStr.indexOf(chA) + 1, srcStr.length()); | |
822 | + srcStr = rtnStr.append(preStr).append(object).append(nextStr).toString(); | |
823 | + } | |
824 | + } | |
825 | + | |
826 | + return srcStr; | |
827 | + } | |
828 | + | |
829 | + /** | |
830 | + * @author 최정우 | |
831 | + * @since 2019.11.13 | |
832 | + * | |
833 | + * 문자열을 다양한 문자셋(EUC-KR[KSC5601],UTF-8..)을 사용하여 인코딩하는 기능 역으로 디코딩하여 원래의 문자열을 | |
834 | + * 복원하는 기능을 제공함 String temp = new String(문자열.getBytes("바꾸기전 인코딩"),"바꿀 인코딩"); | |
835 | + * String temp = new String(문자열.getBytes("8859_1"),"KSC5601"); => UTF-8 에서 | |
836 | + * EUC-KR | |
837 | + * | |
838 | + * @param text - 문자열 | |
839 | + * @param encoding - 원래의 인코딩된 값 | |
840 | + * @param decoding - 디코딩할 문자값 | |
841 | + * @return 인(디)코딩 문자열 | |
842 | + * @see | |
843 | + */ | |
844 | + public static String textDecoding(String text, String encoding, String decoding) { | |
845 | + if (text == null) { | |
846 | + return null; | |
847 | + } | |
848 | + | |
849 | + try { | |
850 | + text = new String(text.getBytes(encoding), decoding); | |
851 | + } catch (UnsupportedEncodingException e) { | |
852 | + text = null; | |
853 | + } | |
854 | + | |
855 | + return text; | |
856 | + } | |
857 | + | |
858 | + /** | |
859 | + * @author 최정우 | |
860 | + * @since 2019.11.13 | |
861 | + * | |
862 | + * 특정 길이 만큼 문자열 뽑기 | |
863 | + */ | |
864 | + public static String fixedText (String text, int maxLength) { | |
865 | + if (text == null) text = ""; | |
866 | + | |
867 | + text = text.replaceAll("(\r\n|\r|\n|\n\r)", " "); | |
868 | + if (text.length() > maxLength) { | |
869 | + text = text.substring(0, maxLength) + "...(중략)"; | |
870 | + } else if (text.length() < maxLength) { | |
871 | + int emptySize = maxLength - text.length(); | |
872 | + if (emptySize == 1) { | |
873 | + text += " "; | |
874 | + } else { | |
875 | + int halfEmptySize = emptySize / 2; | |
876 | + for (int i = 0; i < halfEmptySize; i++) { | |
877 | + text = " " + text + " "; | |
878 | + } | |
879 | + if (0 < emptySize % 2) { | |
880 | + text += " "; | |
881 | + } | |
882 | + } | |
883 | + } | |
884 | + | |
885 | + return text; | |
886 | + } | |
887 | + | |
888 | + /** | |
889 | + * @author 최정우 | |
890 | + * @since 2021.09.28 | |
891 | + * | |
892 | + * 스네이크 표기법 => 카멜 표기법 | |
893 | + */ | |
894 | + public static String snakeToCamel (String text) { | |
895 | + String camelText = ""; | |
896 | + | |
897 | + if (text != null) { | |
898 | + text = removeSpace(text); | |
899 | + text = text.toLowerCase(); | |
900 | + | |
901 | + String[] texts = text.split("_"); | |
902 | + if (texts.length > 1) { | |
903 | + camelText += texts[0]; | |
904 | + for (int i = 1; i < texts.length; i++) { | |
905 | + if (texts[i].length() > 0) { | |
906 | + char[] chars = texts[i].toCharArray(); | |
907 | + chars[0] = Character.toUpperCase(chars[0]); | |
908 | + camelText += new String(chars); | |
909 | + } else { | |
910 | + continue; | |
911 | + } | |
912 | + } | |
913 | + } else { | |
914 | + camelText = text; | |
915 | + } | |
916 | + } | |
917 | + | |
918 | + return camelText; | |
919 | + } | |
920 | + | |
921 | + /** | |
922 | + * @author 최정우 | |
923 | + * @since 2021.09.28 | |
924 | + * | |
925 | + * 카멜 표기법 => 스네이크 표기법 | |
926 | + */ | |
927 | + public static String camelToSnake (String text, boolean isUpperCase) { | |
928 | + String snakeText = ""; | |
929 | + | |
930 | + if (text != null) { | |
931 | + text = removeSpace(text); | |
932 | + | |
933 | + String[] texts = text.split("[A-Z]"); | |
934 | + for (int i = 0; i < texts.length; i++) { | |
935 | + if (texts[i].length() > 0) { | |
936 | + snakeText += (texts[i] + "_"); | |
937 | + int currentIndex = snakeText.length() - 1 - i; | |
938 | + if (currentIndex <= text.length() - 1) { | |
939 | + //System.out.println("text.toCharArray()[currentIndex] : " + text.toCharArray()[currentIndex]); | |
940 | + snakeText += text.toCharArray()[currentIndex]; | |
941 | + } | |
942 | + } else { | |
943 | + continue; | |
944 | + } | |
945 | + } | |
946 | + | |
947 | + try { | |
948 | + snakeText = snakeText.substring(0, snakeText.length() - 1); | |
949 | + } catch (StringIndexOutOfBoundsException e) { | |
950 | + snakeText = text; | |
951 | + } | |
952 | + | |
953 | + if (isUpperCase == true) { | |
954 | + snakeText = snakeText.toUpperCase(); | |
955 | + } else { | |
956 | + snakeText = snakeText.toLowerCase(); | |
957 | + } | |
958 | + | |
959 | + } | |
960 | + | |
961 | + return snakeText; | |
962 | + } | |
963 | + | |
964 | + /** | |
965 | + * @author 최정우 | |
966 | + * @since 2021.03.24 | |
967 | + * | |
968 | + * 문자열 나누기 | |
969 | + * | |
970 | + * @param text - 문자열 | |
971 | + * @param bufferSize - 문자열을 나눌 기준 값 | |
972 | + * | |
973 | + * @throws Exception | |
974 | + */ | |
975 | + public static List<String> textSeparation (String text, int bufferSize) throws Exception { | |
976 | + List<String> result = new ArrayList<String>(); | |
977 | + | |
978 | + if (text == null) { | |
979 | + throw new Exception("문자열이 없음(null)"); | |
980 | + } | |
981 | + | |
982 | + if (bufferSize <= 0) { | |
983 | + throw new Exception("bufferSize는 0초과이어야 합니다."); | |
984 | + } | |
985 | + | |
986 | + int unitSize = text.length() / bufferSize; | |
987 | + int remainSize = text.length() % bufferSize; | |
988 | + | |
989 | + for (int i = 0; i < unitSize; i++) { | |
990 | + int startIndex = i * bufferSize; | |
991 | + int endIndex = (i + 1) * bufferSize; | |
992 | + //System.out.println(startIndex + ", " + endIndex); | |
993 | + result.add(text.substring(startIndex, endIndex)); | |
994 | + } | |
995 | + if (remainSize > 0) { | |
996 | + result.add(text.substring(unitSize * bufferSize, text.length())); | |
997 | + } | |
998 | + | |
999 | + return result; | |
1000 | + } | |
1001 | +} |
+++ src/back-end/main/java/common/util/bean/ApplicationContextProvider.java
... | ... | @@ -0,0 +1,44 @@ |
1 | +package common.util.bean; | |
2 | + | |
3 | +import org.springframework.beans.BeansException; | |
4 | +import org.springframework.context.ApplicationContext; | |
5 | +import org.springframework.context.ApplicationContextAware; | |
6 | +import org.springframework.stereotype.Component; | |
7 | + | |
8 | +/** | |
9 | + * @author 최정우 | |
10 | + * @since 2019.11.17 | |
11 | + * | |
12 | + * Spring 컨테이너(ApplicationContext)에 접근하기 위한 Class 입니다. | |
13 | + * ApplicationContextAware 구현체 | |
14 | + */ | |
15 | +public class ApplicationContextProvider implements ApplicationContextAware { | |
16 | + | |
17 | + /** | |
18 | + * 해당 어플리케이션의 인스턴스(bean)들의 정보를 담은 객체 | |
19 | + */ | |
20 | + private static ApplicationContext applicationContext; | |
21 | + | |
22 | + /** | |
23 | + * @author 최정우 | |
24 | + * @since 2019.11.17 | |
25 | + * | |
26 | + * ApplicationContextAware를 구현하기 위한 메소드 | |
27 | + * Spring 구동 시, 해당 Class가 스캔 당하면 applicationContext 객체가 생성됨 | |
28 | + */ | |
29 | + @Override | |
30 | + public void setApplicationContext(ApplicationContext ctx) throws BeansException { | |
31 | + applicationContext = ctx; | |
32 | + } | |
33 | + | |
34 | + /** | |
35 | + * @author 최정우 | |
36 | + * @since 2019.11.17 | |
37 | + * | |
38 | + * applicationContext 객체 호출 | |
39 | + */ | |
40 | + public static ApplicationContext getApplicationContext() { | |
41 | + return applicationContext; | |
42 | + } | |
43 | + | |
44 | +}(No newline at end of file) |
+++ src/back-end/main/java/common/util/bean/BeanUtil.java
... | ... | @@ -0,0 +1,44 @@ |
1 | +package common.util.bean; | |
2 | + | |
3 | +import org.springframework.beans.BeansException; | |
4 | + | |
5 | +/** | |
6 | + * ApplicationContextProvider에서 bean객체를 얻어 활용할 수 있도록 해주는 Util 입니다. | |
7 | + * | |
8 | + * @author 최정우 | |
9 | + * @since 2020.11.25 | |
10 | + */ | |
11 | +public class BeanUtil { | |
12 | + | |
13 | + /** | |
14 | + * 해당 어플리케이션에서 스프링 컨테이너가 관리하는 bean으로 등록된 객체를 이름으로 호출 | |
15 | + * | |
16 | + * @author 최정우 | |
17 | + * @since 2019.11.17 | |
18 | + */ | |
19 | + public static Object getBean(String beanName) { | |
20 | + System.out.println("BeanUtil getBean(param (String) beanName : " + beanName + ")"); | |
21 | + try { | |
22 | + return ApplicationContextProvider.getApplicationContext().getBean(beanName); | |
23 | + } catch (BeansException e) { | |
24 | + e.printStackTrace(); | |
25 | + return null; | |
26 | + } | |
27 | + } | |
28 | + | |
29 | + /** | |
30 | + * 해당 어플리케이션에서 스프링 컨테이너가 관리하는 bean으로 등록된 객체를 객체의 타입으로 호출 | |
31 | + * | |
32 | + * @author 최정우 | |
33 | + * @since 2019.11.17 | |
34 | + */ | |
35 | + public static Object getBean(Class<?> classType) { | |
36 | + System.out.println("BeanUtil getBean(param (Class<?>) classType : " + classType.getName() + ")"); | |
37 | + try { | |
38 | + return ApplicationContextProvider.getApplicationContext().getBean(classType); | |
39 | + } catch (BeansException e) { | |
40 | + e.printStackTrace(); | |
41 | + return null; | |
42 | + } | |
43 | + } | |
44 | +} |
+++ src/back-end/main/java/common/util/reflection/ParentLastURLClassLoader.java
... | ... | @@ -0,0 +1,88 @@ |
1 | +package common.util.reflection; | |
2 | + | |
3 | +import java.net.URL; | |
4 | +import java.net.URLClassLoader; | |
5 | + | |
6 | +/* | |
7 | + * 커스텀 URLClassLoder | |
8 | + * | |
9 | + * WAS(톰캣)에서 URLClassLoder로 작동시 외부 라이브러리에 있는 jar파일을 읽지 못함 | |
10 | + * 외부 라이브러리 class들을 먼저 읽기 위함 | |
11 | + */ | |
12 | +public class ParentLastURLClassLoader extends ClassLoader | |
13 | +{ | |
14 | + private ChildURLClassLoader childClassLoader; | |
15 | + | |
16 | + /** | |
17 | + * This class allows me to call findClass on a classloader | |
18 | + */ | |
19 | + private static class FindClassClassLoader extends ClassLoader | |
20 | + { | |
21 | + public FindClassClassLoader(ClassLoader parent) | |
22 | + { | |
23 | + super(parent); | |
24 | + } | |
25 | + | |
26 | + @Override | |
27 | + public Class<?> findClass(String name) throws ClassNotFoundException | |
28 | + { | |
29 | + return super.findClass(name); | |
30 | + } | |
31 | + } | |
32 | + | |
33 | + /** | |
34 | + * This class delegates (child then parent) for the findClass method for a URLClassLoader. | |
35 | + * We need this because findClass is protected in URLClassLoader | |
36 | + */ | |
37 | + private static class ChildURLClassLoader extends URLClassLoader | |
38 | + { | |
39 | + private FindClassClassLoader realParent; | |
40 | + | |
41 | + public ChildURLClassLoader( URL[] urls, FindClassClassLoader realParent ) | |
42 | + { | |
43 | + super(urls, null); | |
44 | + | |
45 | + this.realParent = realParent; | |
46 | + } | |
47 | + | |
48 | + @Override | |
49 | + public Class<?> findClass(String name) throws ClassNotFoundException | |
50 | + { | |
51 | + try | |
52 | + { | |
53 | + // first try to use the URLClassLoader findClass | |
54 | + return super.findClass(name); | |
55 | + } | |
56 | + catch( ClassNotFoundException e ) | |
57 | + { | |
58 | + // if that fails, we ask our real parent classloader to load the class (we give up) | |
59 | + return realParent.loadClass(name); | |
60 | + } | |
61 | + } | |
62 | + } | |
63 | + | |
64 | + //List<URL> classpath | |
65 | + public ParentLastURLClassLoader(URL[] urls) | |
66 | + { | |
67 | + super(Thread.currentThread().getContextClassLoader()); | |
68 | + | |
69 | + //URL[] urls = classpath.toArray(new URL[classpath.size()]); | |
70 | + | |
71 | + childClassLoader = new ChildURLClassLoader( urls, new FindClassClassLoader(this.getParent()) ); | |
72 | + } | |
73 | + | |
74 | + @Override | |
75 | + protected synchronized Class<?> loadClass(String name, boolean resolve) throws ClassNotFoundException | |
76 | + { | |
77 | + try | |
78 | + { | |
79 | + // first we try to find a class inside the child classloader | |
80 | + return childClassLoader.findClass(name); | |
81 | + } | |
82 | + catch( ClassNotFoundException e ) | |
83 | + { | |
84 | + // didn't find it, try the parent | |
85 | + return super.loadClass(name, resolve); | |
86 | + } | |
87 | + } | |
88 | +}(No newline at end of file) |
+++ src/back-end/main/java/common/util/reflection/ReflectionUtil.java
... | ... | @@ -0,0 +1,222 @@ |
1 | +package common.util.reflection; | |
2 | + | |
3 | +import common.util.StringUtil; | |
4 | +import common.util.bean.BeanUtil; | |
5 | + | |
6 | +import java.io.File; | |
7 | +import java.lang.reflect.Method; | |
8 | +import java.net.URL; | |
9 | + | |
10 | +/** | |
11 | + * @author 최정우 | |
12 | + * @since 2020.11.25 | |
13 | + * | |
14 | + * Reflection - 클래스, 인터페이스, 메소드관련 인스턴스화(로드) 및 실행 관련 Util입니다. | |
15 | + */ | |
16 | +public class ReflectionUtil { | |
17 | + | |
18 | + /******************************************** Class 단 ********************************************/ | |
19 | + /** | |
20 | + * @author 최정우 | |
21 | + * @since 2020.11.25 | |
22 | + * | |
23 | + * classLoad - 어플리케이션 내부(+Bean객체포함) OR 외부의 class 파일을 저장된 경로를 통해 class 파일 로드 후, 객체 생성 | |
24 | + * | |
25 | + * classFullName과 classFilePath를 통해 실제 클래스를 인스턴스화함. | |
26 | + * 1. Class.forName을 통해 어플리케이션 내부의 class path에 있는 class객체 생성 | |
27 | + * 2. 어플리케이션 내부에 class가 존재할 때 | |
28 | + * 2-1. 어플리케이션의 Spring 컨테이너에 해당 클래스 타입으로 생성된 Bean이 있는지 확인 | |
29 | + * => 존재할 때, Bean 객체 주입 | |
30 | + * => 존재하지 않을 때, 객체 생성 | |
31 | + * 3. 어플리케이션 내부에 class가 존재하지 않을 때 | |
32 | + * 3-1. class or jar file이 저장된 경로를 이용하여 클래스를 로드 | |
33 | + * | |
34 | + * 4. 객체 생성 실패시, Log 기록 및 다음 작업 목록으로 넘어감 | |
35 | + */ | |
36 | + public static Object classAndBeanLoad (String classFilePath, String classFullName) { | |
37 | + Object clazz = null; | |
38 | + try { | |
39 | + //Class.forName을 통해 어플리케이션 내부의 class path에 있는 class객체 생성 | |
40 | + Class<?> c = forName(classFullName); | |
41 | + if (c != null) {//어플리케이션 내부에 class가 존재할 때 | |
42 | + //플리케이션의 Spring 컨테이너에 해당 클래스 타입으로 생성된 Bean이 있는지 확인 후, Bean 객체 주입 | |
43 | + clazz = BeanUtil.getBean(c); | |
44 | + | |
45 | + if (clazz == null) {//Bean 객체 존재하지 않을 때 | |
46 | + clazz = newInstance(c); | |
47 | + } | |
48 | + } else {//어플리케이션 내부에 class가 존재하지 않을 때 | |
49 | + //class or jar file이 저장된 경로 | |
50 | + //file 경로 값이 있을 때만 클래스를 로드함 | |
51 | + if (StringUtil.isEmpty(classFilePath) == false) { | |
52 | + if (StringUtil.isEmpty(classFullName) == false) { | |
53 | + clazz = classLoad(classFilePath, classFullName); | |
54 | + } else { | |
55 | + clazz = classLoad(classFilePath); | |
56 | + } | |
57 | + } | |
58 | + } | |
59 | + } catch (Exception e) { | |
60 | + e.printStackTrace(); | |
61 | + } | |
62 | + | |
63 | + return clazz; | |
64 | + } | |
65 | + | |
66 | + /** | |
67 | + * @author 최정우 | |
68 | + * @since 2019.11.17 | |
69 | + * | |
70 | + * forName - 어플리케이션 내부의 class path에 있는 class객체 생성 | |
71 | + * | |
72 | + * classFullName = package명 + class명 | |
73 | + */ | |
74 | + public static Class<?> forName (String classFullName) { | |
75 | + try { | |
76 | + return Class.forName(classFullName); | |
77 | + } catch (Exception e) { | |
78 | + e.printStackTrace(); | |
79 | + return null; | |
80 | + } | |
81 | + } | |
82 | + | |
83 | + /** | |
84 | + * @author 최정우 | |
85 | + * @since 2019.11.17 | |
86 | + * | |
87 | + * classLoad - 어플리케이션 내부 OR 외부의 class 파일을 저장된 경로를 통해 class 파일 로드 후, 객체 생성 | |
88 | + * 주로 외부 class파일을 로드할 때 쓰임 | |
89 | + * | |
90 | + * classFilePath - 클래스파일 절대경로 | |
91 | + * classFullName = package명 + class명 | |
92 | + */ | |
93 | + public static Object classLoad (String classFilePath, String classFullName) { | |
94 | + try { | |
95 | + File file = new File(classFilePath); | |
96 | + //실제 경로상에 있는 .class파일을 통해 class를 읽어옴 | |
97 | + ParentLastURLClassLoader classLoader = new ParentLastURLClassLoader(new URL[] { file.toURI().toURL() }); | |
98 | + //읽어온 .class파일을 이용해 해당되는 패키지 내에 있는 class를 로드해 옴 | |
99 | + Class<?> c = classLoader.loadClass(classFullName); | |
100 | + //class를 new 객체 생성함 | |
101 | + return newInstance(c); | |
102 | + } catch (Exception e) { | |
103 | + e.printStackTrace(); | |
104 | + return null; | |
105 | + } | |
106 | + } | |
107 | + | |
108 | + /** | |
109 | + * @author 최정우 | |
110 | + * @since 2019.11.17 | |
111 | + * | |
112 | + * classLoad - 어플리케이션 내부 OR 외부의 class 파일을 저장된 경로를 통해 class 파일 로드 후, 객체 생성 | |
113 | + * 주로 외부 class파일을 로드할 때 쓰임 | |
114 | + * class명을 모를 때 사용 | |
115 | + * | |
116 | + * classFilePath - 클래스파일 절대경로 | |
117 | + */ | |
118 | + public static Object classLoad (String classFilePath) { | |
119 | + try { | |
120 | + File file = new File(classFilePath); | |
121 | + //실제 경로상에 있는 .class파일을 통해 class를 읽어옴 | |
122 | + ParentLastURLClassLoader classLoader = new ParentLastURLClassLoader(new URL[] { file.toURI().toURL() }); | |
123 | + //읽어온 .class파일을 이용해 해당되는 패키지 내에 있는 class를 로드해 옴 | |
124 | + Class<?> c = classLoader.getClass(); | |
125 | + //class를 new 객체 생성함 | |
126 | + return newInstance(c); | |
127 | + } catch (Exception e) { | |
128 | + e.printStackTrace(); | |
129 | + return null; | |
130 | + } | |
131 | + } | |
132 | + | |
133 | + /** | |
134 | + * @author 최정우 | |
135 | + * @since 2019.11.17 | |
136 | + * | |
137 | + * newInstance - 객체 인스턴스화(로드) | |
138 | + */ | |
139 | + public static Object newInstance(Class<?> c) { | |
140 | + try { | |
141 | + return c.newInstance(); | |
142 | + } catch (Exception e) { | |
143 | + e.printStackTrace(); | |
144 | + return null; | |
145 | + } | |
146 | + } | |
147 | + | |
148 | + /******************************************** Class 단 ********************************************/ | |
149 | + | |
150 | + | |
151 | + | |
152 | + /******************************************** Method 단 ********************************************/ | |
153 | + /** | |
154 | + * @author 최정우 | |
155 | + * @since 2019.11.17 | |
156 | + * | |
157 | + * invokeByMethodName - 메소드 이름을 통한 메소드 호출 | |
158 | + * | |
159 | + * clazz - 인스턴스화(로드)된 객체 | |
160 | + * methodName - 메소드명 | |
161 | + * paramValues - 메소드의 파라메터 값 | |
162 | + * paramTypes - 메소드의 파라메터 타입 | |
163 | + * (주의 paramValues, paramTypes 순서가 같아야함) | |
164 | + */ | |
165 | + public static Object invokeByMethodName (Object clazz, String methodName, Object[] paramValues, Class<?>[] paramTypes) { | |
166 | + try { | |
167 | + Method method = null; | |
168 | + if (paramValues != null && paramTypes != null | |
169 | + && paramValues.length > 0 && paramTypes.length > 0 | |
170 | + && paramValues.length == paramTypes.length) { | |
171 | + | |
172 | + System.out.println("clazz getPackage : " + clazz.getClass().getPackage()); | |
173 | + System.out.println("clazz name : " + clazz.getClass().getName()); | |
174 | + if (paramValues != null && paramValues.length > 0) { | |
175 | + System.out.println("clazz param value : " + paramValues[0].toString()); | |
176 | + System.out.println("clazz param type : " + paramTypes[0].getTypeName()); | |
177 | + } | |
178 | + | |
179 | + //메소드 객체 가지고오기 | |
180 | + method = clazz.getClass().getMethod(methodName, paramTypes); | |
181 | + } else { | |
182 | + //메소드 객체 가지고오기 | |
183 | + method = clazz.getClass().getMethod(methodName); | |
184 | + } | |
185 | + | |
186 | + //메소드 호출 | |
187 | + return invoke(clazz, method, paramValues); | |
188 | + | |
189 | + } catch (Exception e) { | |
190 | + e.printStackTrace(); | |
191 | + return null; | |
192 | + } | |
193 | + | |
194 | + } | |
195 | + | |
196 | + /** | |
197 | + * @author 최정우 | |
198 | + * @since 2019.11.17 | |
199 | + * | |
200 | + * invoke - 메소드 호출 | |
201 | + * | |
202 | + * clazz - 인스턴스화(로드)된 객체 | |
203 | + * method - 메소드 객체 | |
204 | + * paramValues - 메소드의 파라메터 값 | |
205 | + */ | |
206 | + public static Object invoke (Object clazz, Method method, Object[] paramValues) { | |
207 | + try { | |
208 | + if (paramValues != null && paramValues.length > 0) { | |
209 | + //메소드 호출 | |
210 | + return method.invoke(clazz, paramValues); | |
211 | + } else { | |
212 | + //메소드 호출 | |
213 | + return method.invoke(clazz); | |
214 | + } | |
215 | + } catch (Exception e) { | |
216 | + e.printStackTrace(); | |
217 | + return null; | |
218 | + } | |
219 | + | |
220 | + } | |
221 | + /******************************************** Method 단 ********************************************/ | |
222 | +} |
+++ src/back-end/main/java/common/util/socket/FileUtil.java
... | ... | @@ -0,0 +1,194 @@ |
1 | +package common.util.socket; | |
2 | + | |
3 | +//import javax.activation.MimetypesFileTypeMap; | |
4 | +import javax.imageio.ImageIO; | |
5 | +import java.awt.*; | |
6 | +import java.awt.image.BufferedImage; | |
7 | +import java.io.*; | |
8 | +import java.text.SimpleDateFormat; | |
9 | +import java.util.Base64; | |
10 | +import java.util.Date; | |
11 | + | |
12 | +/** | |
13 | + * @author 최정우 | |
14 | + * @since 2019.12.11 | |
15 | + * | |
16 | + * 파일 Util 입니다. | |
17 | + */ | |
18 | +public class FileUtil { | |
19 | + | |
20 | + //이미지 파일 resizing 여부 | |
21 | + public static boolean IMAGE_FILE_RESIZING = false; | |
22 | + | |
23 | + //resizing이 필요한 이미지 파일 크기 | |
24 | + public static int IMAGE_FILE_NEED_RESIZING_SIZE = 1024 * 1024;//1MB | |
25 | + | |
26 | + //resizing시 기본 이미지 크기 | |
27 | + public static double IMAGE_FILE_RESIZING_RATE = 0.5; | |
28 | + | |
29 | + public static byte[] fileToByte (File file) { | |
30 | + //파일 byte를 담을 공간 | |
31 | + byte[] bytes = null; | |
32 | + | |
33 | + FileInputStream fileInput = null; | |
34 | + try { | |
35 | + // 파일 읽을 줄비 | |
36 | + fileInput = new FileInputStream(file); | |
37 | + // 바이너리 공간 확보 | |
38 | + bytes = new byte[fileInput.available()]; | |
39 | + // 파일 -> byte | |
40 | + fileInput.read(bytes); | |
41 | + } catch (Exception e) { | |
42 | + e.printStackTrace(); | |
43 | + } finally { | |
44 | + if (fileInput != null) { | |
45 | + try { | |
46 | + fileInput.close(); | |
47 | + } catch (IOException e1) { | |
48 | + e1.printStackTrace(); | |
49 | + } | |
50 | + } | |
51 | + } | |
52 | + | |
53 | + return bytes; | |
54 | + } | |
55 | + | |
56 | + public static byte[] base64Encoding(byte[] buffer) { | |
57 | + return Base64.getEncoder().encode(buffer); | |
58 | + } | |
59 | + | |
60 | + public static byte[] base64Decoding(byte[] buffer) { | |
61 | + return Base64.getDecoder().decode(buffer); | |
62 | + } | |
63 | + | |
64 | + public static boolean isImageFile (File file) { | |
65 | + boolean result = false; | |
66 | + | |
67 | + try { | |
68 | + String mimeType = null;//new MimetypesFileTypeMap().getContentType(file); | |
69 | + String type = mimeType.split("/")[0]; | |
70 | + if (type.equals("image") == true) { | |
71 | + result = true; | |
72 | + } | |
73 | + } catch (Exception e) { | |
74 | + e.printStackTrace(); | |
75 | + result = false; | |
76 | + } | |
77 | + | |
78 | + return result; | |
79 | + } | |
80 | + | |
81 | + public static byte[] imageFileResizeToByte (File imageFile) { | |
82 | + //파일 byte를 담을 공간 | |
83 | + byte[] bytes = null; | |
84 | + | |
85 | + String fileName = imageFile.getName(); | |
86 | + //String filePath = imageFile.getPath(); | |
87 | + String extension = fileName.substring(fileName.lastIndexOf(".") + 1); | |
88 | + | |
89 | + //1MB보다 클 때 | |
90 | + System.out.println("file Size : " + imageFile.length()); | |
91 | + if (imageFile.length() > IMAGE_FILE_NEED_RESIZING_SIZE) { | |
92 | + BufferedImage image = null; | |
93 | + BufferedImage resizedImage = null; | |
94 | + ByteArrayOutputStream baos = null; | |
95 | + try { | |
96 | + image = ImageIO.read(imageFile); | |
97 | + if (image != null) { | |
98 | + /*이미지 파일 일 때*/ | |
99 | + int newWidth = (int) (image.getWidth() * IMAGE_FILE_RESIZING_RATE); | |
100 | + int newHeight = (int) (image.getHeight() * IMAGE_FILE_RESIZING_RATE); | |
101 | + System.out.println("resizing width : " + image.getWidth() + " ->" + newWidth); | |
102 | + System.out.println("resizing height : " + image.getHeight() + " ->" + newHeight); | |
103 | + | |
104 | + // 이미지 리사이즈 | |
105 | + // Image.SCALE_DEFAULT : 기본 이미지 스케일링 알고리즘 사용 | |
106 | + // Image.SCALE_FAST : 이미지 부드러움보다 속도 우선 | |
107 | + // Image.SCALE_REPLICATE : ReplicateScaleFilter 클래스로 구체화 된 이미지 크기 조절 알고리즘 | |
108 | + // Image.SCALE_SMOOTH : 속도보다 이미지 부드러움을 우선 | |
109 | + // Image.SCALE_AREA_AVERAGING : 평균 알고리즘 사용 | |
110 | + Image resizeImage = image.getScaledInstance(newWidth, newHeight, Image.SCALE_SMOOTH); | |
111 | + | |
112 | + int imageType = image.getType() == 0? BufferedImage.TYPE_INT_ARGB : image.getType(); | |
113 | + resizedImage = new BufferedImage(newWidth, newHeight, imageType); | |
114 | + Graphics2D g = resizedImage.createGraphics(); | |
115 | + g.drawImage(resizeImage, 0, 0, null); | |
116 | + g.dispose(); | |
117 | + | |
118 | + // resizing 파일 -> byte | |
119 | + baos = new ByteArrayOutputStream(); | |
120 | + ImageIO.write(resizedImage, extension, baos); | |
121 | + bytes = baos.toByteArray(); | |
122 | + } | |
123 | + } catch (IOException e) { | |
124 | + /*이미지 파일이 아님*/ | |
125 | + e.printStackTrace(); | |
126 | + } finally { | |
127 | + if (baos != null) { | |
128 | + try { | |
129 | + baos.close(); | |
130 | + } catch (IOException e) { | |
131 | + e.printStackTrace(); | |
132 | + } | |
133 | + } | |
134 | + } | |
135 | + } | |
136 | + | |
137 | + if (bytes == null) { | |
138 | + bytes = fileToByte(imageFile); | |
139 | + } | |
140 | + | |
141 | + return bytes; | |
142 | + } | |
143 | + | |
144 | + /** | |
145 | + * 작성일 : 210316 작성자 : 최정우 | |
146 | + * | |
147 | + * 로그파일 남기기 | |
148 | + * | |
149 | + * @param massage : 로그 | |
150 | + */ | |
151 | + public static void writeLogFile(String massage, String fileName, String filePath) { | |
152 | + BufferedWriter fw = null; | |
153 | + try { | |
154 | + // 현재 일시 | |
155 | + SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); | |
156 | + String dateTime = dateFormat.format(new Date()); | |
157 | + // 현재 일자 | |
158 | + String date = dateTime.split(" ")[0]; | |
159 | + | |
160 | + // 현재 클래스의 디렉토리 (절대경로) | |
161 | + // String currentPath = System.getProperty("user.dir"); | |
162 | + // [현재 클래스의 디렉토리 + 서브 폴더 디렉토리]의 존재 여부 | |
163 | + File dir = new File(filePath); | |
164 | + if (dir.exists() == false) { | |
165 | + dir.mkdir();// 존재하지 않을 때 폴더 생성 | |
166 | + } | |
167 | + // 로그 파일명(socket_server_log_[현재 일자].txt) | |
168 | + String newFileName = fileName + "_" + date + ".txt"; | |
169 | + | |
170 | + // 로그 파일의 절대 경로 | |
171 | + String fileFullPath = filePath + File.separator + newFileName; | |
172 | + | |
173 | + /* 로그 남기기 */ | |
174 | + // BufferedWriter 와 FileWriter를 조합하여 사용 (속도 향상) | |
175 | + fw = new BufferedWriter(new FileWriter(fileFullPath, true)); | |
176 | + // 파일안에 문자열 쓰기 | |
177 | + fw.write(("[" + dateTime + "] " + massage + "\n")); | |
178 | + fw.flush(); | |
179 | + | |
180 | + // 객체 닫기 | |
181 | + fw.close(); | |
182 | + } catch (Exception e) { | |
183 | + e.printStackTrace(); | |
184 | + } finally { | |
185 | + if (fw != null) { | |
186 | + try { | |
187 | + fw.close(); | |
188 | + } catch (IOException e) { | |
189 | + e.printStackTrace(); | |
190 | + } | |
191 | + } | |
192 | + } | |
193 | + } | |
194 | +} |
+++ src/back-end/main/java/common/util/socket/SocketManager.java
... | ... | @@ -0,0 +1,308 @@ |
1 | +package common.util.socket; | |
2 | + | |
3 | +import com.fasterxml.jackson.core.type.TypeReference; | |
4 | +import com.fasterxml.jackson.databind.DeserializationFeature; | |
5 | +import com.fasterxml.jackson.databind.ObjectMapper; | |
6 | +import com.fasterxml.jackson.databind.SerializationFeature; | |
7 | +import common.util.StringUtil; | |
8 | +import common.util.socket.message.MessageProtocol; | |
9 | +import common.util.socket.message.code.MessageCode; | |
10 | +import common.util.socket.message.vo.Message; | |
11 | + | |
12 | +import java.io.DataInputStream; | |
13 | +import java.io.DataOutputStream; | |
14 | +import java.io.InputStream; | |
15 | +import java.io.OutputStream; | |
16 | +import java.net.InetSocketAddress; | |
17 | +import java.net.Socket; | |
18 | +import java.net.SocketAddress; | |
19 | +import java.util.Arrays; | |
20 | +import java.util.List; | |
21 | + | |
22 | +public class SocketManager { | |
23 | + | |
24 | + public static final int DEFAULT_SOCKET_PORT = 2200; | |
25 | + | |
26 | + //최대 패킷 byte | |
27 | + private final int maxPacketSize = 65000; | |
28 | + //기본 Socket연결 최대 시간(밀리세컨드) | |
29 | + private final int defalutSocketTimeout = 1 * 60 * 1000;//1분 | |
30 | + //Socket 메세지 데이터 읽을 때, 최대 시간(밀리세컨드) | |
31 | + private final int defalutMessageTimeout = 10 * 1000 * 1000;//10초 | |
32 | + | |
33 | + | |
34 | + private ObjectMapper mapper = null; | |
35 | + private TypeReference<MessageProtocol> typeReferene = null; | |
36 | + { | |
37 | + /*************** [통신 처리 준비] 메세지 JSON Parsing ***************/ | |
38 | + mapper = new ObjectMapper(); | |
39 | + mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false); | |
40 | + mapper.configure(SerializationFeature.FAIL_ON_EMPTY_BEANS, false); | |
41 | + | |
42 | + typeReferene = new TypeReference<MessageProtocol>() {}; | |
43 | + } | |
44 | + | |
45 | + | |
46 | + public Message request(Socket clientSocket, Message message) throws Exception { | |
47 | + List<Message> messageList = Arrays.asList(message); | |
48 | + messageList = request(clientSocket, messageList); | |
49 | + return messageList.get(0); | |
50 | + } | |
51 | + | |
52 | + public List<Message> request(Socket clientSocket, List<Message> messageList) throws Exception { | |
53 | + if (clientSocket == null || clientSocket.isClosed() == true) { | |
54 | + throw new Exception("소켓이 없거나 닫쳤습니다."); | |
55 | + } | |
56 | + // 결과 메세지 목록 | |
57 | + List<Message> responseMessageList = null; | |
58 | + | |
59 | + InputStream input = null; | |
60 | + DataInputStream dataInput = null; | |
61 | + OutputStream output = null; | |
62 | + DataOutputStream dataOutput = null; | |
63 | + try { | |
64 | + | |
65 | + /*************** [통신 처리 준비] 클라이언트 -> 서버 ***************/ | |
66 | + // OutputStream - Client에서 Server로 메세지 발송 | |
67 | + output = clientSocket.getOutputStream(); | |
68 | + // socket의 OutputStream 정보를 OutputStream out에 넣은 뒤 | |
69 | + dataOutput = new DataOutputStream(output); | |
70 | + /*************** 요청 메세지 구성 ***************/ | |
71 | + // 통신하기 위한 메세지 규약 생성 (요청 메시지 타입 : 명령어) | |
72 | + MessageProtocol mp = new MessageProtocol(MessageCode.CommunicationType.REQUEST); | |
73 | + // Body에 데이터 전송할 데이터 담기 | |
74 | + mp.getBody().setMessageList(messageList); | |
75 | + /*************** 요청 메세지 전송 ***************/ | |
76 | + // 메세지 규약 전체를 JSON문자열로 변경 | |
77 | + String requestProtocolToJson = mapper.writeValueAsString(mp); | |
78 | + //System.out.println("requestProtocolToJson : " + requestProtocolToJson); | |
79 | + | |
80 | + System.out.println("메세지 전송 시작!"); | |
81 | + // JSON문자열을 여러개로 나눔 | |
82 | + List<String> requestProtocolToJsonList = StringUtil.textSeparation(requestProtocolToJson, maxPacketSize); | |
83 | + System.out.println("requestProtocolToJsonList.size() : " + requestProtocolToJsonList.size()); | |
84 | + | |
85 | + for (String text : requestProtocolToJsonList) { | |
86 | + // 메세지 담기 | |
87 | + dataOutput.writeUTF(text); | |
88 | + | |
89 | + // 메세지 전송 | |
90 | + //dataOutput.flush(); | |
91 | + } | |
92 | + | |
93 | + // 종료 메세지 담기 | |
94 | + dataOutput.writeUTF(MessageCode.MessageFlag.MESSAGE_END.toString()); | |
95 | + // 종료 메세지 전송 | |
96 | + dataOutput.flush(); | |
97 | + | |
98 | + System.out.println("메세지 전송 완료!"); | |
99 | + | |
100 | + /*************** [통신 처리 준비] 서버 -> 클라이언트 ***************/ | |
101 | + // InputStream - Server에서 보낸 메세지 Client로 가져옴 | |
102 | + input = clientSocket.getInputStream(); | |
103 | + // socket의 InputStream 정보를 InputStream in에 넣은 뒤 | |
104 | + dataInput = new DataInputStream(input); | |
105 | + | |
106 | + /*************** 서버 결과 메세지 확인 ***************/ | |
107 | + System.out.println("응답 대기 시작!"); | |
108 | + | |
109 | + // 클라이언트에서 온 메세지 확인 | |
110 | + String responseProtocolToJson = ""; | |
111 | + while (true) { | |
112 | + String text = dataInput.readUTF(); | |
113 | + //System.out.println((a++) + ". " + text); | |
114 | + if (text.equals(MessageCode.MessageFlag.MESSAGE_END.toString())) { | |
115 | + System.out.println("응답 완료!"); | |
116 | + break; | |
117 | + } | |
118 | + responseProtocolToJson += text; | |
119 | + } | |
120 | + //System.out.println("responseProtocolToJson : " + responseProtocolToJson); | |
121 | + | |
122 | + // 메세지 규약 전체를 JSON문자열로 변경 | |
123 | + MessageProtocol responseMP = mapper.readValue(responseProtocolToJson, typeReferene); | |
124 | + | |
125 | + // 결과 메세지 목록 | |
126 | + responseMessageList = responseMP.getBody().getMessageList(); | |
127 | + | |
128 | + for (int i = 0; i < messageList.size(); i++) { | |
129 | + messageList.set(i, responseMessageList.get(i)); | |
130 | + } | |
131 | + | |
132 | + } catch (Exception e) { | |
133 | + e.printStackTrace(); | |
134 | + } finally { | |
135 | + if (dataInput != null) | |
136 | + dataInput.close(); | |
137 | + if (input != null) | |
138 | + input.close(); | |
139 | + | |
140 | + if (dataOutput != null) | |
141 | + dataOutput.close(); | |
142 | + if (output != null) | |
143 | + output.close(); | |
144 | + | |
145 | + /*소켓 종료*/ | |
146 | + if (clientSocket != null) | |
147 | + socketClose(clientSocket); | |
148 | + } | |
149 | + | |
150 | + return responseMessageList; | |
151 | + } | |
152 | + | |
153 | + public void response(Socket clientSocket) throws Exception { | |
154 | + if (clientSocket == null || clientSocket.isClosed() == true) { | |
155 | + throw new Exception("소켓이 없거나 닫쳤습니다."); | |
156 | + } | |
157 | + | |
158 | + InputStream input = null; | |
159 | + DataInputStream dataInput = null; | |
160 | + OutputStream output = null; | |
161 | + DataOutputStream dataOutput = null; | |
162 | + try { | |
163 | + /*************** [통신 처리 준비] 클라이언트 -> 서버 ***************/ | |
164 | + // InputStream - Client에서 보낸 메세지 Server로 가져옴 | |
165 | + input = clientSocket.getInputStream(); | |
166 | + // socket의 InputStream 정보를 InputStream in에 넣은 뒤 | |
167 | + dataInput = new DataInputStream(input); | |
168 | + | |
169 | + /*************** [통신 처리 준비] 서버 -> 클라이언트 ***************/ | |
170 | + // OutputStream - Server에서 Client로 메세지 발송 | |
171 | + output = clientSocket.getOutputStream(); | |
172 | + // socket의 OutputStream 정보를 OutputStream out에 넣은 뒤 | |
173 | + dataOutput = new DataOutputStream(output); | |
174 | + | |
175 | + /*************** 클라이언트 메세지 확인 ***************/ | |
176 | + System.out.println("요청 대기 시작!"); | |
177 | + // 클라이언트에서 온 메세지 확인 | |
178 | + String requestProtocolToJson = ""; | |
179 | + while (true) { | |
180 | + String text = dataInput.readUTF(); | |
181 | + if (text.equals(MessageCode.MessageFlag.MESSAGE_END.toString())) { | |
182 | + System.out.println("요청 완료!"); | |
183 | + break; | |
184 | + } | |
185 | + requestProtocolToJson += text; | |
186 | + } | |
187 | + //System.out.println("requestProtocolToJson : " + requestProtocolToJson); | |
188 | + | |
189 | + // 메세지 규약 전체를 JSON문자열로 변경 | |
190 | + MessageProtocol requestMP = mapper.readValue(requestProtocolToJson, typeReferene); | |
191 | + // 메세지 목록 | |
192 | + List<Message> requestMessageList = requestMP.getBody().getMessageList(); | |
193 | + /*************** 클라이언트 메세지 처리 ***************/ | |
194 | + // 메세지 실행 | |
195 | + for (int i = 0; i < requestMessageList.size(); i++) { | |
196 | + try { | |
197 | + // 메세지 실행 결과 (true(=SUCCESS) or false(=FAIL)) | |
198 | + boolean result = requestMessageList.get(i).run(); | |
199 | + | |
200 | + /** run() 메소드의 동작 결과값 활용 -> '메세지 결과 세팅' (※필수) **/ | |
201 | + if (result == true) { | |
202 | + requestMessageList.get(i).setResultMessageByFlag(MessageCode.MessageFlag.SUCCESS);//result값은 자동으로 true로 정의됨 | |
203 | + } else { | |
204 | + requestMessageList.get(i).setResultMessageByFlag(MessageCode.MessageFlag.FAIL);//result값은 자동으로 false로 정의됨 | |
205 | + } | |
206 | + } catch (Exception e) { | |
207 | + /** run() 메소드의 에러 결과값 활용 -> '메세지 결과 세팅' (※필수) **/ | |
208 | + requestMessageList.get(i).setResultMessageByError(e);//result값은 자동으로 false로 정의됨 | |
209 | + } | |
210 | + } | |
211 | + | |
212 | + | |
213 | + /*************** 클라이언트에게 결과 메세지 전송 ***************/ | |
214 | + // 결과 메세지 JSON문자열로 변경 | |
215 | + String responseProtocolToJson = mapper.writeValueAsString(requestMP); | |
216 | + //System.out.println("responseProtocolToJson : " + responseProtocolToJson); | |
217 | + | |
218 | + System.out.println("결과 메세지 전송 시작!"); | |
219 | + // JSON문자열을 여러개로 나눔 | |
220 | + List<String> responseProtocolToJsonList = StringUtil.textSeparation(responseProtocolToJson, maxPacketSize); | |
221 | + System.out.println("responseProtocolToJsonList size : " + responseProtocolToJsonList.size()); | |
222 | + for (String text : responseProtocolToJsonList) { | |
223 | + //System.out.println("text : " + text); | |
224 | + // 메세지 담기 | |
225 | + dataOutput.writeUTF(text); | |
226 | + // 메세지 전송 | |
227 | + //dataOutput.flush(); | |
228 | + } | |
229 | + | |
230 | + // 종료 메세지 담기 | |
231 | + dataOutput.writeUTF(MessageCode.MessageFlag.MESSAGE_END.toString()); | |
232 | + // 종료 메세지 전송 | |
233 | + dataOutput.flush(); | |
234 | + | |
235 | + System.out.println("결과 메세지 전송 완료!"); | |
236 | + | |
237 | + } finally { | |
238 | + if (dataOutput != null) | |
239 | + dataOutput.close(); | |
240 | + if (output != null) | |
241 | + output.close(); | |
242 | + | |
243 | + if (dataInput != null) | |
244 | + dataInput.close(); | |
245 | + if (input != null) | |
246 | + input.close(); | |
247 | + } | |
248 | + } | |
249 | + | |
250 | + /** | |
251 | + * 210316 최정우 | |
252 | + * | |
253 | + * Socket 생성 | |
254 | + * | |
255 | + * @param socket : 소켓 객체 | |
256 | + * @return | |
257 | + */ | |
258 | + public Socket socketCreate(String ip, int port) { | |
259 | + SocketAddress socketAddress = null; | |
260 | + Socket socket = null; | |
261 | + try { | |
262 | + socketAddress = new InetSocketAddress(ip, port); | |
263 | + socket = new Socket(); | |
264 | + socket.setSoTimeout(defalutSocketTimeout); | |
265 | + socket.connect(socketAddress, defalutMessageTimeout); | |
266 | + } catch (Exception e) { | |
267 | + e.printStackTrace(); | |
268 | + } | |
269 | + return socket; | |
270 | + } | |
271 | + | |
272 | + /** | |
273 | + * 210316 최정우 | |
274 | + * | |
275 | + * Socket 생성 | |
276 | + */ | |
277 | + public Socket socketCreate(String ip, int port, int timeout) { | |
278 | + Socket socket = null; | |
279 | + try { | |
280 | + socket = new Socket(ip, port); | |
281 | + socket.setSoTimeout(timeout); | |
282 | + } catch (Exception e) { | |
283 | + e.printStackTrace(); | |
284 | + } | |
285 | + return socket; | |
286 | + } | |
287 | + | |
288 | + /** | |
289 | + * 210316 최정우 | |
290 | + * | |
291 | + * Socket 닫기 | |
292 | + */ | |
293 | + public boolean socketClose(Socket socket) { | |
294 | + boolean result = false; | |
295 | + try { | |
296 | + if (socket != null && socket.isClosed() == false) { | |
297 | + socket.close(); | |
298 | + } | |
299 | + result = true; | |
300 | + } catch (Exception e) { | |
301 | + e.printStackTrace(); | |
302 | + result = false; | |
303 | + } | |
304 | + | |
305 | + return result; | |
306 | + } | |
307 | + | |
308 | +} |
+++ src/back-end/main/java/common/util/socket/SocketReponseManager.java
... | ... | @@ -0,0 +1,39 @@ |
1 | +package common.util.socket; | |
2 | + | |
3 | +import common.util.CommonUtil; | |
4 | + | |
5 | +import java.net.Socket; | |
6 | +import java.net.SocketException; | |
7 | + | |
8 | +public class SocketReponseManager implements Runnable { | |
9 | + | |
10 | + private Socket clientSocket = null; | |
11 | + | |
12 | + private String userIP = null; | |
13 | + | |
14 | + public SocketReponseManager(Socket clientSocket) { | |
15 | + this.clientSocket = clientSocket; | |
16 | + this.userIP = clientSocket.getRemoteSocketAddress().toString(); | |
17 | + } | |
18 | + | |
19 | + @Override | |
20 | + public void run() { | |
21 | + SocketManager socketManager = new SocketManager(); | |
22 | + | |
23 | + try { | |
24 | + socketManager.response(clientSocket); | |
25 | + } catch (SocketException e) { | |
26 | + e.printStackTrace(); | |
27 | + /*로그 생성*/ | |
28 | + String logMessage = "[" + userIP + "] clientSocket close ??? " + CommonUtil.exceptionToString(e); | |
29 | + FileUtil.writeLogFile(logMessage, "socket_log", "./socket_log"); | |
30 | + } catch (Exception e) { | |
31 | + e.printStackTrace(); | |
32 | + /*로그 생성*/ | |
33 | + String logMessage = "[" + userIP + "] " + CommonUtil.exceptionToString(e); | |
34 | + FileUtil.writeLogFile(logMessage, "socket_log", "./socket_log"); | |
35 | + } | |
36 | + | |
37 | + } | |
38 | + | |
39 | +} |
+++ src/back-end/main/java/common/util/socket/message/Body.java
... | ... | @@ -0,0 +1,19 @@ |
1 | +package common.util.socket.message; | |
2 | + | |
3 | +import common.util.socket.message.vo.Message; | |
4 | + | |
5 | +import java.util.List; | |
6 | + | |
7 | +public class Body<T extends Message> { | |
8 | + | |
9 | + private List<T> messageList; | |
10 | + | |
11 | + public List<T> getMessageList() { | |
12 | + return messageList; | |
13 | + } | |
14 | + | |
15 | + public void setMessageList(List<T> messageList) { | |
16 | + this.messageList = messageList; | |
17 | + } | |
18 | + | |
19 | +} |
+++ src/back-end/main/java/common/util/socket/message/Header.java
... | ... | @@ -0,0 +1,24 @@ |
1 | +package common.util.socket.message; | |
2 | + | |
3 | + | |
4 | +import common.util.socket.message.code.MessageCode; | |
5 | + | |
6 | +public class Header { | |
7 | + | |
8 | + public Header() {} | |
9 | + | |
10 | + public Header(MessageCode.CommunicationType communicationType) { | |
11 | + this.communicationType = communicationType; | |
12 | + } | |
13 | + | |
14 | + private MessageCode.CommunicationType communicationType; | |
15 | + | |
16 | + public MessageCode.CommunicationType getCommunicationType() { | |
17 | + return communicationType; | |
18 | + } | |
19 | + | |
20 | + public void setCommunicationType(MessageCode.CommunicationType communicationType) { | |
21 | + this.communicationType = communicationType; | |
22 | + } | |
23 | + | |
24 | +} |
+++ src/back-end/main/java/common/util/socket/message/MessageProtocol.java
... | ... | @@ -0,0 +1,32 @@ |
1 | +package common.util.socket.message; | |
2 | + | |
3 | +import common.util.socket.message.code.MessageCode; | |
4 | + | |
5 | +public class MessageProtocol { | |
6 | + | |
7 | + public MessageProtocol() {} | |
8 | + | |
9 | + public MessageProtocol(MessageCode.CommunicationType communicationType) throws Exception { | |
10 | + this.header = new Header(communicationType); | |
11 | + this.body = new Body<>(); | |
12 | + } | |
13 | + | |
14 | + private Header header; | |
15 | + | |
16 | + private Body body; | |
17 | + | |
18 | + public Header getHeader() { | |
19 | + return header; | |
20 | + } | |
21 | + public void setHeader(Header header) { | |
22 | + this.header = header; | |
23 | + } | |
24 | + | |
25 | + public Body getBody() { | |
26 | + return body; | |
27 | + } | |
28 | + public void setBody(Body body) { | |
29 | + this.body = body; | |
30 | + } | |
31 | + | |
32 | +} |
+++ src/back-end/main/java/common/util/socket/message/code/MessageCode.java
... | ... | @@ -0,0 +1,83 @@ |
1 | +package common.util.socket.message.code; | |
2 | + | |
3 | + | |
4 | +import common.util.socket.message.vo.Message; | |
5 | +import common.util.socket.message.vo.impl.Command; | |
6 | +import common.util.socket.message.vo.impl.File; | |
7 | +import common.util.socket.message.vo.impl.Text; | |
8 | + | |
9 | +/** | |
10 | + * 210317 | |
11 | + * 최정우 | |
12 | + * | |
13 | + * Socket통신 시, 필요한 메세지 규약 저장소입니다. | |
14 | + */ | |
15 | +public class MessageCode { | |
16 | + | |
17 | + /** | |
18 | + * 210317 | |
19 | + * 최정우 | |
20 | + * | |
21 | + * 메세지 전송 타입(요청 OR 응답) | |
22 | + */ | |
23 | + public enum CommunicationType { | |
24 | + REQUEST | |
25 | + , RESPONSE; | |
26 | + } | |
27 | + | |
28 | + /** | |
29 | + * 210317 | |
30 | + * 최정우 | |
31 | + * | |
32 | + * 통신할 메세지 타입 | |
33 | + */ | |
34 | + public enum MessageType { | |
35 | + FILE(File.class)//파일 전송 | |
36 | + , TEXT(Text.class)//Text 전송 | |
37 | + , COMMEND(Command.class);//명령어 전송 | |
38 | + | |
39 | + private Class<? extends Message> clazz; | |
40 | + | |
41 | + private MessageType (Class<? extends Message> clazz) { | |
42 | + this.clazz = clazz; | |
43 | + } | |
44 | + | |
45 | + public Class<? extends Message> getClazz() { | |
46 | + return clazz; | |
47 | + } | |
48 | + } | |
49 | + | |
50 | + /** | |
51 | + * 210317 | |
52 | + * 최정우 | |
53 | + * | |
54 | + * 통신할 메세지 타입 | |
55 | + */ | |
56 | + public enum FileMessageType { | |
57 | + IMPORT//파일 가져오기 | |
58 | + , EXPORT//파일 내보내기 | |
59 | + } | |
60 | + /** | |
61 | + * 210317 | |
62 | + * 최정우 | |
63 | + * | |
64 | + * 통신을 할 때, 필요한 구분자 | |
65 | + */ | |
66 | + public enum MessageFlag { | |
67 | + MESSAGE_START | |
68 | + , MESSAGE_END | |
69 | + | |
70 | + , HEAD_START | |
71 | + , HEAD_END | |
72 | + | |
73 | + , BODY_START | |
74 | + , BODY_END | |
75 | + | |
76 | + , FILE_START | |
77 | + , FILE_END | |
78 | + | |
79 | + , SUCCESS | |
80 | + , FAIL | |
81 | + , ERROR; | |
82 | + } | |
83 | +} |
+++ src/back-end/main/java/common/util/socket/message/json/MessageDeserializer.java
... | ... | @@ -0,0 +1,72 @@ |
1 | +package common.util.socket.message.json; | |
2 | + | |
3 | +import com.fasterxml.jackson.core.JsonParser; | |
4 | +import com.fasterxml.jackson.core.JsonProcessingException; | |
5 | +import com.fasterxml.jackson.core.type.TypeReference; | |
6 | +import com.fasterxml.jackson.databind.DeserializationContext; | |
7 | +import com.fasterxml.jackson.databind.JsonNode; | |
8 | +import com.fasterxml.jackson.databind.ObjectMapper; | |
9 | +import com.fasterxml.jackson.databind.deser.std.StdDeserializer; | |
10 | +import common.util.CommonUtil; | |
11 | +import common.util.socket.message.code.MessageCode; | |
12 | +import common.util.socket.message.vo.Message; | |
13 | + | |
14 | +import java.io.IOException; | |
15 | +import java.util.HashMap; | |
16 | + | |
17 | +public class MessageDeserializer extends StdDeserializer<Message> { | |
18 | + | |
19 | + private static final long serialVersionUID = 1L; | |
20 | + | |
21 | + private final ObjectMapper mapper = new ObjectMapper(); | |
22 | + | |
23 | + private final TypeReference<HashMap<String, Object>> typeReferene = new TypeReference<HashMap<String, Object>>(){}; | |
24 | + | |
25 | + public MessageDeserializer() { | |
26 | + this(null); | |
27 | + } | |
28 | + | |
29 | + public MessageDeserializer(Class<?> vc) { | |
30 | + super(vc); | |
31 | + // TODO Auto-generated constructor stub | |
32 | + } | |
33 | + | |
34 | + @Override | |
35 | + public Message deserialize(JsonParser jsonParser, DeserializationContext arg1) throws IOException, JsonProcessingException { | |
36 | + Message result = null; | |
37 | + try { | |
38 | + //JsonParser to JsonNode | |
39 | + JsonNode node = jsonParser.getCodec().readTree(jsonParser); | |
40 | + //System.out.println("node str : " + node.toString()); | |
41 | + | |
42 | + //메세지 타입 문자열 to MessageType (String to Enum) | |
43 | + MessageCode.MessageType messageType = MessageCode.MessageType.valueOf(node.get("messageType").asText()); | |
44 | + //System.out.println("messageType : " + messageType); | |
45 | + | |
46 | + /*Message 객체 생성*/ | |
47 | + if (messageType == MessageCode.MessageType.FILE) {//MessageType이 FILE 일 때 | |
48 | + //FileMessageType 확인 | |
49 | + MessageCode.FileMessageType fileMessageType = MessageCode.FileMessageType.valueOf(node.get("fileMessageType").asText()); | |
50 | + //객체 생성시 생성자에 파라메터 값(FileMessageType) 전달 | |
51 | + result = messageType.getClazz().getDeclaredConstructor(MessageCode.FileMessageType.class).newInstance(fileMessageType); | |
52 | + } else {//MessageType이 FILE이외 다른거 일 때 | |
53 | + //객체 생성 | |
54 | + result = messageType.getClazz().newInstance(); | |
55 | + } | |
56 | + | |
57 | + //json문자열 to HashMap<String, Object> | |
58 | + HashMap<String, Object> messageMap = mapper.readValue(node.toString(), typeReferene); | |
59 | + | |
60 | + //Map(value) -> Message(value) (단, messageType은 제외) | |
61 | + String[] ignoreFields = {"messageType"}; | |
62 | + //Map(value) -> Message(value) (단, messageType은 제외) | |
63 | + CommonUtil.objectSetMapValue(result, messageMap, ignoreFields); | |
64 | + | |
65 | + System.out.println(""); | |
66 | + } catch (Exception e) { | |
67 | + e.printStackTrace(); | |
68 | + } | |
69 | + return result; | |
70 | + } | |
71 | + | |
72 | +} |
+++ src/back-end/main/java/common/util/socket/message/vo/Message.java
... | ... | @@ -0,0 +1,107 @@ |
1 | +package common.util.socket.message.vo; | |
2 | + | |
3 | + | |
4 | +import com.fasterxml.jackson.databind.annotation.JsonDeserialize; | |
5 | +import common.util.socket.message.code.MessageCode; | |
6 | +import common.util.socket.message.json.MessageDeserializer; | |
7 | + | |
8 | +/** | |
9 | + * 최정우 | |
10 | + * 210321 | |
11 | + * | |
12 | + * 최상위 통신 Message 객체 | |
13 | + */ | |
14 | +@JsonDeserialize(using = MessageDeserializer.class) | |
15 | +public abstract class Message { | |
16 | + | |
17 | + /** | |
18 | + * 전송 메세지 타입 | |
19 | + */ | |
20 | + private MessageCode.MessageType messageType; | |
21 | + | |
22 | + /** | |
23 | + * 메세지 전송 결과 | |
24 | + */ | |
25 | + private boolean result = false; | |
26 | + | |
27 | + /** | |
28 | + * 메세지 전송 결과 | |
29 | + */ | |
30 | + private String resultMessage = MessageCode.MessageFlag.FAIL.toString(); | |
31 | + | |
32 | + /** | |
33 | + * 최정우 | |
34 | + * 210321 | |
35 | + * | |
36 | + * Message동작 | |
37 | + */ | |
38 | + public abstract boolean run() throws Exception; | |
39 | + | |
40 | + //messageType - get | |
41 | + public MessageCode.MessageType getMessageType() { | |
42 | + return messageType; | |
43 | + } | |
44 | + //messageType - set | |
45 | + public void setMessageType(MessageCode.MessageType messageType) { | |
46 | + this.messageType = messageType; | |
47 | + } | |
48 | + | |
49 | + //result - get | |
50 | + public boolean getResult() { | |
51 | + return result; | |
52 | + } | |
53 | + //result - set | |
54 | + public void setResult(boolean result) { | |
55 | + this.result = result; | |
56 | + | |
57 | + //동작결과가 true -> SUCCESS | |
58 | + if (result == true) { | |
59 | + this.resultMessage = MessageCode.MessageFlag.SUCCESS.toString(); | |
60 | + } | |
61 | + //동작결과가 false -> FAIL | |
62 | + else { | |
63 | + this.resultMessage = MessageCode.MessageFlag.FAIL.toString(); | |
64 | + } | |
65 | + } | |
66 | + | |
67 | + //resultMessage - get | |
68 | + public String getResultMessage() { | |
69 | + return resultMessage; | |
70 | + } | |
71 | + //resultMessage - set | |
72 | + public void setResultMessage(String resultMessage) { | |
73 | + this.resultMessage = resultMessage; | |
74 | + } | |
75 | + | |
76 | + /********** resultMessage 별도 정의 (시작) **********/ | |
77 | + /** | |
78 | + * MessageFlag를 활용한 resultMessage 정의 | |
79 | + * @param messageFlag | |
80 | + */ | |
81 | + public void setResultMessageByFlag(MessageCode.MessageFlag messageFlag) { | |
82 | + this.resultMessage = messageFlag.toString(); | |
83 | + | |
84 | + //SUCCESS -> 동작결과 true | |
85 | + if (messageFlag == MessageCode.MessageFlag.SUCCESS) { | |
86 | + this.result = true; | |
87 | + } | |
88 | + //FAIL -> 동작결과 false | |
89 | + else if (messageFlag == MessageCode.MessageFlag.FAIL) { | |
90 | + this.result = false; | |
91 | + } | |
92 | + //SUCCESS, FAIL이외 일때 -> 뭐 없음 | |
93 | + else { | |
94 | + return; | |
95 | + } | |
96 | + } | |
97 | + /** | |
98 | + * Exception를 활용한 resultMessage 정의 | |
99 | + * @param e | |
100 | + */ | |
101 | + public void setResultMessageByError(Exception e) { | |
102 | + //에러메세지 세팅 -> result:false | |
103 | + this.resultMessage = MessageCode.MessageFlag.ERROR.toString() + " : " + e.getMessage(); | |
104 | + this.result = false; | |
105 | + } | |
106 | + /********** resultMessage 별도 정의 (종료) **********/ | |
107 | +} |
+++ src/back-end/main/java/common/util/socket/message/vo/impl/Command.java
... | ... | @@ -0,0 +1,151 @@ |
1 | +package common.util.socket.message.vo.impl; | |
2 | + | |
3 | +import common.util.socket.FileUtil; | |
4 | +import common.util.socket.message.code.MessageCode; | |
5 | +import common.util.socket.message.vo.Message; | |
6 | + | |
7 | +import java.io.BufferedReader; | |
8 | +import java.io.InputStreamReader; | |
9 | +import java.util.ArrayList; | |
10 | +import java.util.List; | |
11 | +import java.util.concurrent.TimeUnit; | |
12 | + | |
13 | +/** | |
14 | + * 210320 | |
15 | + * 최정우 | |
16 | + * | |
17 | + * 소켓통신을 통해 명령어 전송을 위한 Message객체 입니다. | |
18 | + */ | |
19 | +//public class Command implements MessageInterface { | |
20 | +public class Command extends Message { | |
21 | + | |
22 | + //명령어 최대 실행 시간(초) | |
23 | + public static int COMMAND_TIMEOUT_SECONDS = 10; | |
24 | + | |
25 | + public Command () { | |
26 | + super.setMessageType(MessageCode.MessageType.COMMEND); | |
27 | + } | |
28 | + | |
29 | + public Command (String command) { | |
30 | + super.setMessageType(MessageCode.MessageType.COMMEND); | |
31 | + | |
32 | + this.command = command; | |
33 | + } | |
34 | + | |
35 | + private String command; | |
36 | + | |
37 | + private List<String> commandResult; | |
38 | + | |
39 | + public String getCommand() { | |
40 | + return command; | |
41 | + } | |
42 | + public void setCommand(String command) { | |
43 | + this.command = command; | |
44 | + } | |
45 | + | |
46 | + public List<String> getCommandResult() { | |
47 | + return commandResult; | |
48 | + } | |
49 | + public void setCommandResult(List<String> commandResult) { | |
50 | + this.commandResult = commandResult; | |
51 | + } | |
52 | + | |
53 | + /** | |
54 | + * 210320 | |
55 | + * 최정우 | |
56 | + * | |
57 | + * 명령어 실행 | |
58 | + */ | |
59 | + @Override | |
60 | + public boolean run() throws Exception { | |
61 | + /** run() 메소드의 동작 결과 정의 (필수 변수)**/ | |
62 | + boolean result = false; | |
63 | + | |
64 | + /*************** [명령어 처리 준비] JAVA(JVM) -> OS ***************/ | |
65 | + /* | |
66 | + * 명령어 준비 | |
67 | + * | |
68 | + * Window : cmd.exe /C [명령어] (명령어 수행 완료후 cmd.exe 종료) | |
69 | + * Linux : /bin/sh -c [명렁어] (명령어 수행 완료후 shell 종료) | |
70 | + */ | |
71 | + String[] commend = {"", "", this.command}; | |
72 | + if (System.getProperty("os.name").indexOf("Windows") > -1) { | |
73 | + commend[0] = "cmd.exe"; | |
74 | + commend[1] = "/C"; | |
75 | + } else { | |
76 | + commend[0] = "/bin/sh"; | |
77 | + commend[1] = "-c"; | |
78 | + }//명령어 준비 끝 | |
79 | + | |
80 | + | |
81 | + /*************** [명령어 수행] JAVA(JVM) -> OS ***************/ | |
82 | + //Runtime객체 : 운영체제 기반의 프로그램을 실행시키거나 운영체제에 대한 정보를 제공 | |
83 | + //Process객체 : JVM 메모리에 올라와서 업무 처리를 수행할 객체 | |
84 | + Process process = Runtime.getRuntime().exec(commend); | |
85 | + | |
86 | + /*로그 생성*/ | |
87 | + String logMessage = "COMMAND : " + this.command; | |
88 | + FileUtil.writeLogFile(logMessage, "socket_log", "./socket_log"); | |
89 | + | |
90 | + /*************** 업무처리가 완료 될 때 까지 기다림 ***************/ | |
91 | + //COMMAND_TIMEOUT_SECONDS안에 업무처리가 완료 될 때 까지 기다림(+수행 처리 시간 받기) | |
92 | + //int execTime = process.waitFor(); | |
93 | + boolean isComplete = process.waitFor(COMMAND_TIMEOUT_SECONDS, TimeUnit.SECONDS); | |
94 | + System.out.println("isComplete : " + isComplete); | |
95 | + | |
96 | + /*************** [명령어 수행 결과 받을 준비 / 수행 결과 담기] OS -> JAVA(JVM) ***************/ | |
97 | + commandResult = new ArrayList<String>(); | |
98 | + | |
99 | + BufferedReader resultBufferReader = null; | |
100 | + BufferedReader errorBufferReader = null; | |
101 | + if (isComplete == true) { | |
102 | + resultBufferReader = new BufferedReader(new InputStreamReader(process.getInputStream(), "EUC-KR")); | |
103 | + String msg = null; | |
104 | + while ((msg = resultBufferReader.readLine()) != null) { | |
105 | + if (msg.contains(System.getProperty("line.separator")) == false) { | |
106 | + msg += System.getProperty("line.separator"); | |
107 | + } | |
108 | + commandResult.add(msg); | |
109 | + } | |
110 | + errorBufferReader = new BufferedReader(new InputStreamReader(process.getErrorStream(), "EUC-KR")); | |
111 | + int err_count = 0; | |
112 | + while ((msg = errorBufferReader.readLine()) != null) { | |
113 | + if (err_count++ == 0) { | |
114 | + commandResult.add("================ [Error] ================" + System.getProperty("line.separator")); | |
115 | + } | |
116 | + | |
117 | + if (msg.contains(System.getProperty("line.separator")) == false) { | |
118 | + msg += System.getProperty("line.separator"); | |
119 | + } | |
120 | + commandResult.add(msg); | |
121 | + } | |
122 | + } else { | |
123 | + commandResult.add("COMMAND : " + this.command + " - Timeout(" + COMMAND_TIMEOUT_SECONDS + "초)"); | |
124 | + } | |
125 | + | |
126 | + /*************** 클라이언트에게 명령어 수행 결과 메세지 전송 ***************/ | |
127 | + // 서버에서 클라이언트로 메세지 보내기 | |
128 | + if (isComplete && process.exitValue() == 0) { | |
129 | + //commandResult.add("[" + (execTime / 1000.0) + "초 Ok]"); | |
130 | + commandResult.add(MessageCode.MessageFlag.SUCCESS.toString()); | |
131 | + /** 결과 담기 **/ | |
132 | + result = true; | |
133 | + } else { | |
134 | + //commandResult.add("[" + (execTime / 1000.0) + "초 Error]"); | |
135 | + commandResult.add(MessageCode.MessageFlag.FAIL.toString()); | |
136 | + /** 결과 담기 **/ | |
137 | + result = false; | |
138 | + } | |
139 | + | |
140 | + if (resultBufferReader != null) resultBufferReader.close(); | |
141 | + if (errorBufferReader != null) errorBufferReader.close(); | |
142 | + if (process != null) process.destroy(); | |
143 | + | |
144 | + for (int i = 0; i < commandResult.size(); i++) { | |
145 | + System.out.println("result : " + commandResult.get(i)); | |
146 | + } | |
147 | + | |
148 | + return result; | |
149 | + } | |
150 | + | |
151 | +} |
+++ src/back-end/main/java/common/util/socket/message/vo/impl/File.java
... | ... | @@ -0,0 +1,316 @@ |
1 | +package common.util.socket.message.vo.impl; | |
2 | + | |
3 | +import common.util.StringUtil; | |
4 | +import common.util.socket.FileUtil; | |
5 | +import common.util.socket.message.code.MessageCode; | |
6 | +import common.util.socket.message.vo.Message; | |
7 | + | |
8 | +import java.io.FileInputStream; | |
9 | +import java.io.FileOutputStream; | |
10 | + | |
11 | +/** | |
12 | + * 210320 | |
13 | + * 최정우 | |
14 | + * | |
15 | + * 소켓통신을 통해 파일 전송을 위한 Message객체 입니다. | |
16 | + */ | |
17 | +//public class File implements MessageInterface { | |
18 | +public class File extends Message { | |
19 | + | |
20 | + public File (MessageCode.FileMessageType fileMessageType) { | |
21 | + super.setMessageType(MessageCode.MessageType.FILE); | |
22 | + | |
23 | + this.newFilePath = "./"; | |
24 | + | |
25 | + this.fileMessageType = fileMessageType; | |
26 | + } | |
27 | + | |
28 | + | |
29 | + public File (MessageCode.FileMessageType fileMessageType, String originFileName, String originFilePath) { | |
30 | + super.setMessageType(MessageCode.MessageType.FILE); | |
31 | + | |
32 | + this.originFileName = originFileName; | |
33 | + this.originFilePath = originFilePath; | |
34 | + this.newFileName = originFileName; | |
35 | + this.newFilePath = "./"; | |
36 | + | |
37 | + this.fileMessageType = fileMessageType; | |
38 | + } | |
39 | + | |
40 | + public File (MessageCode.FileMessageType fileMessageType, String originFileName, String originFilePath, String newFileName, String newFilePath) { | |
41 | + super.setMessageType(MessageCode.MessageType.FILE); | |
42 | + | |
43 | + this.originFileName = originFileName; | |
44 | + this.originFilePath = originFilePath; | |
45 | + this.newFileName = newFileName; | |
46 | + this.newFilePath = newFilePath; | |
47 | + | |
48 | + this.fileMessageType = fileMessageType; | |
49 | + } | |
50 | + | |
51 | + /** | |
52 | + * 원본 파일명 (확장자까지 포함) | |
53 | + */ | |
54 | + private String originFileName; | |
55 | + | |
56 | + /** | |
57 | + * 원본 파일경로 (절대경로) | |
58 | + */ | |
59 | + private String originFilePath; | |
60 | + | |
61 | + /** | |
62 | + * 원본 파일 binary | |
63 | + */ | |
64 | + private String originFileBinary; | |
65 | + | |
66 | + /** | |
67 | + * 새로운 파일명 (확장자까지 포함) | |
68 | + */ | |
69 | + private String newFileName; | |
70 | + | |
71 | + /** | |
72 | + * 새로운 파일경로 (절대경로) | |
73 | + */ | |
74 | + private String newFilePath; | |
75 | + | |
76 | + /** | |
77 | + * 파일 크기 | |
78 | + */ | |
79 | + private long fileLength; | |
80 | + | |
81 | + /** | |
82 | + * 파일 전송 타입(가지고오기, 내보내기) | |
83 | + */ | |
84 | + private MessageCode.FileMessageType fileMessageType; | |
85 | + | |
86 | + /** | |
87 | + * 이미지 파일 리사이징 완료 여부 (default:false) | |
88 | + */ | |
89 | + private boolean resizingComplete = false; | |
90 | + | |
91 | + public String getOriginFileName() { | |
92 | + return originFileName; | |
93 | + } | |
94 | + public void setOriginFileName(String originFileName) { | |
95 | + this.originFileName = originFileName; | |
96 | + } | |
97 | + | |
98 | + public String getOriginFilePath() { | |
99 | + return originFilePath; | |
100 | + } | |
101 | + public void setOriginFilePath(String originFilePath) { | |
102 | + this.originFilePath = originFilePath; | |
103 | + } | |
104 | + | |
105 | + public String getOriginFileBinary() { | |
106 | + return originFileBinary; | |
107 | + } | |
108 | + public void setOriginFileBinary(String originFileBinary) { | |
109 | + this.originFileBinary = originFileBinary; | |
110 | + } | |
111 | + | |
112 | + public String getNewFileName() { | |
113 | + return newFileName; | |
114 | + } | |
115 | + public void setNewFileName(String newFileName) { | |
116 | + this.newFileName = newFileName; | |
117 | + } | |
118 | + | |
119 | + public String getNewFilePath() { | |
120 | + return newFilePath; | |
121 | + } | |
122 | + public void setNewFilePath(String newFilePath) { | |
123 | + this.newFilePath = newFilePath; | |
124 | + } | |
125 | + | |
126 | + public long getFileLength() { | |
127 | + return fileLength; | |
128 | + } | |
129 | + public void setFileLength(long fileLength) { | |
130 | + this.fileLength = fileLength; | |
131 | + } | |
132 | + | |
133 | + public MessageCode.FileMessageType getFileMessageType() { | |
134 | + return fileMessageType; | |
135 | + } | |
136 | + | |
137 | + public void setFileMessageType(MessageCode.FileMessageType fileMessageType) { | |
138 | + this.fileMessageType = fileMessageType; | |
139 | + } | |
140 | + | |
141 | + public boolean getResizingComplete() { | |
142 | + return resizingComplete; | |
143 | + } | |
144 | + | |
145 | + | |
146 | + public void setResizingComplete(boolean resizingComplete) { | |
147 | + this.resizingComplete = resizingComplete; | |
148 | + } | |
149 | + | |
150 | + | |
151 | + /** | |
152 | + * 210320 | |
153 | + * 최정우 | |
154 | + * | |
155 | + * file정보를 활용하여 Binary로 만들기 | |
156 | + */ | |
157 | + public boolean fileToBinary() throws Exception { | |
158 | + | |
159 | + boolean result = false; | |
160 | + | |
161 | + // 원본 파일명 체크 | |
162 | + if (StringUtil.isEmpty(this.originFileName) == true) { | |
163 | + throw new Exception("파일명이 없음"); | |
164 | + } | |
165 | + // 원본 파일경로 체크 | |
166 | + if (StringUtil.isEmpty(this.originFilePath) == true) { | |
167 | + throw new Exception("파일 경로가 없음"); | |
168 | + } | |
169 | + | |
170 | + // 원본 파일 메모리에 생성 | |
171 | + System.out.println(this.originFilePath + java.io.File.separator + this.originFileName); | |
172 | + java.io.File file = new java.io.File(this.originFilePath + java.io.File.separator + this.originFileName); | |
173 | + | |
174 | + // 원본 파일 존재하는지 확인 | |
175 | + if (file.exists() == false) { | |
176 | + throw new Exception("파일이 존재하지 않음"); | |
177 | + } | |
178 | + // 원본 파일인지 아닌지 확인 | |
179 | + if (file.isFile() == false) { | |
180 | + throw new Exception("파일이 아님"); | |
181 | + } | |
182 | + | |
183 | + // 원본 파일크기 세팅 | |
184 | + this.fileLength = file.length(); | |
185 | + | |
186 | + // 새로운 파일명이 없을 때, 원본 파일명 넣기 | |
187 | + if (StringUtil.isEmpty(this.newFileName) == true) { | |
188 | + this.newFileName = this.originFileName; | |
189 | + } | |
190 | + // 새로운 파일경로가 없을 때, 소켓 서버의 디렉토리 경로 넣기 | |
191 | + if (StringUtil.isEmpty(this.newFilePath) == true) { | |
192 | + this.newFilePath = ".";//현재 디렉토리 | |
193 | + } | |
194 | + | |
195 | + FileInputStream fileInput = null; | |
196 | + try { | |
197 | + //이미지 파일에대한 유무 | |
198 | + boolean isImageFile = FileUtil.isImageFile(file); | |
199 | + | |
200 | + //파일 byte를 담을 공간 | |
201 | + byte[] bytes = null; | |
202 | + | |
203 | + //이미지 파일일 때, 축소 | |
204 | + if (FileUtil.IMAGE_FILE_RESIZING && isImageFile == true) { | |
205 | + bytes = FileUtil.imageFileResizeToByte(file); | |
206 | + } else {//이미지 파일이 아닐 때 | |
207 | + bytes = FileUtil.fileToByte(file); | |
208 | + } | |
209 | + | |
210 | + // bytes -> String | |
211 | + this.originFileBinary = new String(FileUtil.base64Encoding(bytes)); | |
212 | + /*처리 결과*/ | |
213 | + result = true; | |
214 | + } catch (Exception e) { | |
215 | + throw new Exception(e); | |
216 | + } finally { | |
217 | + if (fileInput != null) | |
218 | + fileInput.close(); | |
219 | + } | |
220 | + | |
221 | + return result; | |
222 | + } | |
223 | + | |
224 | + /** | |
225 | + * 210320 | |
226 | + * 최정우 | |
227 | + * | |
228 | + * Binary로 파일 만들기 | |
229 | + */ | |
230 | + public boolean binaryToFile() throws Exception { | |
231 | + | |
232 | + boolean result = false; | |
233 | + | |
234 | + // 생성할 파일명 체크 | |
235 | + if (StringUtil.isEmpty(this.newFileName) == true) { | |
236 | + throw new Exception("저장할 파일명이 없음"); | |
237 | + } | |
238 | + // 생성할 파일경로 체크 | |
239 | + if (StringUtil.isEmpty(this.newFilePath) == true) { | |
240 | + this.newFilePath = ".";//현재 디렉토리 | |
241 | + } | |
242 | + | |
243 | + FileOutputStream fileOutput = null; | |
244 | + try { | |
245 | + // 생성할 파일의 폴더 생성 | |
246 | + java.io.File path = new java.io.File(this.newFilePath); | |
247 | + if (path.exists() == false || path.isDirectory() == false) { | |
248 | + path.mkdir(); | |
249 | + } | |
250 | + // 파일 최종 경로 (파일 디렉토리 + 파일명) | |
251 | + String fileFullPath = this.newFilePath + java.io.File.separator + this.newFileName; | |
252 | + // 파일 읽을 줄비 | |
253 | + fileOutput = new FileOutputStream(fileFullPath); | |
254 | + // String -> byte -> 파일 | |
255 | + fileOutput.write(FileUtil.base64Decoding(this.originFileBinary.getBytes())); | |
256 | + | |
257 | + // 바이너리 비우기 | |
258 | + this.originFileBinary = null; | |
259 | + | |
260 | + /*처리 결과*/ | |
261 | + result = true; | |
262 | + } finally { | |
263 | + if (fileOutput != null) | |
264 | + fileOutput.close(); | |
265 | + } | |
266 | + | |
267 | + return result; | |
268 | + } | |
269 | + | |
270 | + /** | |
271 | + * 210320 | |
272 | + * 최정우 | |
273 | + * | |
274 | + * MessageType:FILE_IMPORT(파일 가져오기) | |
275 | + * 1. fileToBinary() 메소드를 활용하여 [파일 객체 -> Binary로 변형] | |
276 | + * (단, originFileName, originFilePath 필수) | |
277 | + * 끝 | |
278 | + * | |
279 | + * MessageType:FILE_EXPORT(파일 내보내기) | |
280 | + * 1. binaryToFile() 메소드를 활용하여 [Binary -> 파일 객체 생성] | |
281 | + * (단, newFileName, newFilePath, originFileBinary 필수) | |
282 | + * 끝 | |
283 | + */ | |
284 | + @Override | |
285 | + public boolean run() throws Exception { | |
286 | + /** run() 메소드의 동작 결과 정의 (필수 변수)**/ | |
287 | + boolean result = false; | |
288 | + | |
289 | + if (this.fileMessageType == MessageCode.FileMessageType.IMPORT) { | |
290 | + //파일 객체 -> Binary | |
291 | + result = fileToBinary(); | |
292 | + | |
293 | + /*로그 생성*/ | |
294 | + String logMessage = fileMessageType.toString() + " - "; | |
295 | + logMessage += "originFileName:" + originFilePath + "/" + originFileName; | |
296 | + logMessage += ", newFile:" + newFilePath + "/" + newFileName; | |
297 | + logMessage += ", result:" + result; | |
298 | + FileUtil.writeLogFile(logMessage, "socket_log", "./socket_log"); | |
299 | + } else if (this.fileMessageType == MessageCode.FileMessageType.EXPORT) { | |
300 | + //Binary -> 파일 객체 | |
301 | + result = binaryToFile(); | |
302 | + | |
303 | + /*로그 생성*/ | |
304 | + String logMessage = fileMessageType.toString() + " - "; | |
305 | + logMessage += "originFileName:" + originFilePath + "/" + originFileName; | |
306 | + logMessage += ", newFile:" + newFilePath + "/" + newFileName; | |
307 | + logMessage += ", result:" + result; | |
308 | + FileUtil.writeLogFile(logMessage, "socket_log", "./socket_log"); | |
309 | + } else { | |
310 | + throw new Exception("FileMessageType이 Null이거나 잘못되었습니다."); | |
311 | + } | |
312 | + | |
313 | + return result; | |
314 | + } | |
315 | + | |
316 | +} |
+++ src/back-end/main/java/common/util/socket/message/vo/impl/Text.java
... | ... | @@ -0,0 +1,55 @@ |
1 | +package common.util.socket.message.vo.impl; | |
2 | + | |
3 | +import common.util.StringUtil; | |
4 | +import common.util.socket.message.code.MessageCode; | |
5 | +import common.util.socket.message.vo.Message; | |
6 | + | |
7 | +/** | |
8 | + * 210320 | |
9 | + * 최정우 | |
10 | + * | |
11 | + * 소켓통신을 통해 문자 전송을 위한 Message객체 입니다. | |
12 | + */ | |
13 | +//public class Text implements MessageInterface { | |
14 | +public class Text extends Message { | |
15 | + | |
16 | + public Text () { | |
17 | + super.setMessageType(MessageCode.MessageType.TEXT); | |
18 | + } | |
19 | + | |
20 | + public Text (String text) { | |
21 | + super.setMessageType(MessageCode.MessageType.TEXT); | |
22 | + | |
23 | + this.text = text; | |
24 | + } | |
25 | + | |
26 | + private String text; | |
27 | + | |
28 | + public String getText() { | |
29 | + return text; | |
30 | + } | |
31 | + public void setText(String text) { | |
32 | + this.text = text; | |
33 | + } | |
34 | + | |
35 | + /** | |
36 | + * 210320 | |
37 | + * 최정우 | |
38 | + * | |
39 | + * 문자 콘솔에 찍기 | |
40 | + */ | |
41 | + @Override | |
42 | + public boolean run() throws Exception { | |
43 | + /** run() 메소드의 동작 결과 정의 (필수 변수)**/ | |
44 | + boolean result = false; | |
45 | + | |
46 | + System.out.println("text : " + text); | |
47 | + if (StringUtil.isEmpty(text) == false) { | |
48 | + result = true; | |
49 | + } else { | |
50 | + result = false; | |
51 | + } | |
52 | + | |
53 | + return result; | |
54 | + } | |
55 | +} |
+++ src/back-end/main/java/common/vo/CheckMessage.java
... | ... | @@ -0,0 +1,89 @@ |
1 | +package common.vo; | |
2 | + | |
3 | +/** | |
4 | + * @author 최정우 | |
5 | + * @since 2019.11.14 | |
6 | + * | |
7 | + * 데이터 체크, 유효성 검사 등과 같이 검사와 관련된 변수를 정의한 Class 입니다. | |
8 | + */ | |
9 | +public class CheckMessage { | |
10 | + | |
11 | + public CheckMessage() {} | |
12 | + | |
13 | + public CheckMessage(boolean isSuccess) { | |
14 | + this.isSuccess = isSuccess; | |
15 | + } | |
16 | + | |
17 | + public CheckMessage(String message) { | |
18 | + this.message = message; | |
19 | + } | |
20 | + | |
21 | + public CheckMessage(boolean isSuccess, String message) { | |
22 | + this.isSuccess = isSuccess; | |
23 | + this.message = message; | |
24 | + } | |
25 | + | |
26 | + public CheckMessage(boolean isSuccess, String message, int status) { | |
27 | + this.isSuccess = isSuccess; | |
28 | + this.message = message; | |
29 | + this.status = status; | |
30 | + } | |
31 | + | |
32 | + public CheckMessage(boolean isSuccess, String message, String error) { | |
33 | + this.isSuccess = isSuccess; | |
34 | + this.message = message; | |
35 | + this.error = error; | |
36 | + } | |
37 | + | |
38 | + /** | |
39 | + * 체크 완료(사용가능 or 성공) 여부 | |
40 | + */ | |
41 | + private boolean isSuccess; | |
42 | + | |
43 | + /** | |
44 | + * 체크한 상태의 메세지값 | |
45 | + */ | |
46 | + private String message; | |
47 | + | |
48 | + /** | |
49 | + * 에러 메세지 | |
50 | + */ | |
51 | + private String error; | |
52 | + | |
53 | + /** | |
54 | + * 체크한 상태의 상태값 -> 상황마다 다름 | |
55 | + */ | |
56 | + private int status; | |
57 | + | |
58 | + public boolean getIsSuccess() { | |
59 | + return isSuccess; | |
60 | + } | |
61 | + | |
62 | + public void setIsSuccess(boolean isSuccess) { | |
63 | + this.isSuccess = isSuccess; | |
64 | + } | |
65 | + | |
66 | + public String getMessage() { | |
67 | + return message; | |
68 | + } | |
69 | + | |
70 | + public void setMessage(String message) { | |
71 | + this.message = message; | |
72 | + } | |
73 | + | |
74 | + public String getError() { | |
75 | + return error; | |
76 | + } | |
77 | + | |
78 | + public void setError(String error) { | |
79 | + this.error = error; | |
80 | + } | |
81 | + | |
82 | + public int getStatus() { | |
83 | + return status; | |
84 | + } | |
85 | + | |
86 | + public void setStatus(int status) { | |
87 | + this.status = status; | |
88 | + } | |
89 | +} |
+++ src/back-end/main/java/common/vo/CommonFile.java
... | ... | @@ -0,0 +1,308 @@ |
1 | +package common.vo; | |
2 | + | |
3 | +import java.io.File; | |
4 | +import java.util.Arrays; | |
5 | +import java.util.List; | |
6 | + | |
7 | +/** | |
8 | + * @author 최정우 | |
9 | + * @since 2019.11.24 | |
10 | + * | |
11 | + * File 관리 Domain 입니다. | |
12 | + */ | |
13 | +public class CommonFile extends Search { | |
14 | + | |
15 | + public CommonFile() {}; | |
16 | + | |
17 | + public CommonFile(String commonFileGroupId) { | |
18 | + this.commonFileGroupId = commonFileGroupId; | |
19 | + }; | |
20 | + | |
21 | + public CommonFile(long commonFileSeq) { | |
22 | + this.commonFileSeq = commonFileSeq; | |
23 | + }; | |
24 | + | |
25 | + public CommonFile(String commonFileGroupId, long commonFileSeq) { | |
26 | + this.commonFileGroupId = commonFileGroupId; | |
27 | + this.commonFileSeq = commonFileSeq; | |
28 | + }; | |
29 | + | |
30 | + public CommonFile(FileType fileType) { | |
31 | + this.fileType = fileType; | |
32 | + }; | |
33 | + | |
34 | + public CommonFile(String commonFileGroupId, FileType fileType) { | |
35 | + this.commonFileGroupId = commonFileGroupId; | |
36 | + this.fileType = fileType; | |
37 | + }; | |
38 | + | |
39 | + /** | |
40 | + * 파일 관리 아이디 | |
41 | + */ | |
42 | + private String commonFileGroupId; | |
43 | + | |
44 | + /** | |
45 | + * 파일 SEQ | |
46 | + */ | |
47 | + private long commonFileSeq; | |
48 | + | |
49 | + /** | |
50 | + * 원본 파일명 | |
51 | + */ | |
52 | + private String fileOriginName; | |
53 | + | |
54 | + /** | |
55 | + * 마스크킹 처리된 파일명 | |
56 | + */ | |
57 | + private String fileMaskName; | |
58 | + | |
59 | + /** | |
60 | + * 파일 확장자. | |
61 | + */ | |
62 | + private String fileExtension; | |
63 | + | |
64 | + /** | |
65 | + * 파일 사이즈. | |
66 | + */ | |
67 | + private long fileSize; | |
68 | + | |
69 | + /** | |
70 | + * 파일 상대 경로 | |
71 | + */ | |
72 | + private String fileRelativePath; | |
73 | + | |
74 | + /** | |
75 | + * 파일 절대 경로 | |
76 | + */ | |
77 | + private String fileAbsolutePath; | |
78 | + | |
79 | + /** | |
80 | + * 파일 등록자 | |
81 | + */ | |
82 | + private String fileInsertUserId; | |
83 | + | |
84 | + /** | |
85 | + * 파일 등록자 이름 | |
86 | + */ | |
87 | + private String fileInsertUserName; | |
88 | + | |
89 | + /** | |
90 | + * 파일 등록일시 | |
91 | + */ | |
92 | + private String fileInsertDatetime; | |
93 | + | |
94 | + | |
95 | + | |
96 | + /** | |
97 | + * 파일 다운로드 횟수 | |
98 | + */ | |
99 | + private long fileDownloadCount; | |
100 | + | |
101 | + /** | |
102 | + * 파일 타입 | |
103 | + */ | |
104 | + private FileType fileType = FileType.ALL_FILE; | |
105 | + | |
106 | + /** | |
107 | + * 파일 상태 | |
108 | + */ | |
109 | + private FileStatus fileStatus = FileStatus.COMPLETE_INSERT; | |
110 | + | |
111 | + /** | |
112 | + * file 관련 메세지 | |
113 | + */ | |
114 | + private CheckMessage checkMessage = new CheckMessage(); | |
115 | + | |
116 | + | |
117 | + | |
118 | + public String getCommonFileGroupId() { | |
119 | + return commonFileGroupId; | |
120 | + } | |
121 | + | |
122 | + public void setCommonFileGroupId(String commonFileGroupId) { | |
123 | + this.commonFileGroupId = commonFileGroupId; | |
124 | + } | |
125 | + | |
126 | + public long getCommonFileSeq() { | |
127 | + return commonFileSeq; | |
128 | + } | |
129 | + | |
130 | + public void setCommonFileSeq(long commonFileSeq) { | |
131 | + this.commonFileSeq = commonFileSeq; | |
132 | + } | |
133 | + | |
134 | + public String getFileOriginName() { | |
135 | + return fileOriginName; | |
136 | + } | |
137 | + | |
138 | + public void setFileOriginName(String fileOriginName) { | |
139 | + this.fileOriginName = fileOriginName; | |
140 | + } | |
141 | + | |
142 | + public String getFileMaskName() { | |
143 | + return fileMaskName; | |
144 | + } | |
145 | + | |
146 | + public void setFileMaskName(String fileMaskName) { | |
147 | + this.fileMaskName = fileMaskName; | |
148 | + } | |
149 | + | |
150 | + public String getFileExtension() { | |
151 | + return fileExtension; | |
152 | + } | |
153 | + | |
154 | + public void setFileExtension(String fileExtension) { | |
155 | + this.fileExtension = fileExtension; | |
156 | + } | |
157 | + | |
158 | + public long getFileSize() { | |
159 | + return fileSize; | |
160 | + } | |
161 | + | |
162 | + public void setFileSize(long fileSize) { | |
163 | + this.fileSize = fileSize; | |
164 | + } | |
165 | + | |
166 | + public String getFileRelativePath() { | |
167 | + return fileRelativePath; | |
168 | + } | |
169 | + | |
170 | + public void setFileRelativePath(String fileRelativePath) { | |
171 | + this.fileRelativePath = fileRelativePath; | |
172 | + } | |
173 | + | |
174 | + public String getFileAbsolutePath() { | |
175 | + return fileAbsolutePath; | |
176 | + } | |
177 | + | |
178 | + public void setFileAbsolutePath(String fileAbsolutePath) { | |
179 | + this.fileAbsolutePath = fileAbsolutePath; | |
180 | + } | |
181 | + | |
182 | + public String getFileInsertUserId() { | |
183 | + return fileInsertUserId; | |
184 | + } | |
185 | + | |
186 | + public void setFileInsertUserId(String fileInsertUserId) { | |
187 | + this.fileInsertUserId = fileInsertUserId; | |
188 | + } | |
189 | + | |
190 | + public String getFileInsertUserName() { | |
191 | + return fileInsertUserName; | |
192 | + } | |
193 | + | |
194 | + public void setFileInsertUserName(String fileInsertUserName) { | |
195 | + this.fileInsertUserName = fileInsertUserName; | |
196 | + } | |
197 | + | |
198 | + public String getFileInsertDatetime() { | |
199 | + return fileInsertDatetime; | |
200 | + } | |
201 | + | |
202 | + public void setFileInsertDatetime(String fileInsertDatetime) { | |
203 | + this.fileInsertDatetime = fileInsertDatetime; | |
204 | + } | |
205 | + | |
206 | + public long getFileDownloadCount() { | |
207 | + return fileDownloadCount; | |
208 | + } | |
209 | + | |
210 | + public void setFileDownloadCount(long fileDownloadCount) { | |
211 | + this.fileDownloadCount = fileDownloadCount; | |
212 | + } | |
213 | + | |
214 | + public FileStatus getFileStatus() { | |
215 | + return fileStatus; | |
216 | + } | |
217 | + | |
218 | + public void setFileStatus(FileStatus fileStatus) { | |
219 | + this.fileStatus = fileStatus; | |
220 | + } | |
221 | + | |
222 | + public FileType getFileType() { | |
223 | + return fileType; | |
224 | + } | |
225 | + | |
226 | + public void setFileType(FileType fileType) { | |
227 | + this.fileType = fileType; | |
228 | + } | |
229 | + | |
230 | + public CheckMessage getCheckMessage() { | |
231 | + return checkMessage; | |
232 | + } | |
233 | + | |
234 | + public void setCheckMessage(CheckMessage checkMessage) { | |
235 | + this.checkMessage = checkMessage; | |
236 | + } | |
237 | + | |
238 | + | |
239 | + | |
240 | + /** | |
241 | + * @author 최정우 | |
242 | + * @since 2021.10.21 | |
243 | + * | |
244 | + * 파일 등록 및 삭제 과정에 필요한 상태 값을 정의한 상수 Class 입니다. | |
245 | + * 'DB등록 전', 'DB등록 완료', 'DB삭제 전' 순서입니다. | |
246 | + */ | |
247 | + public enum FileStatus { | |
248 | + BEFORE_INSERT("DB등록 전") | |
249 | + , COMPLETE_INSERT("DB등록 완료") | |
250 | + , BEFORE_DELETE("DB삭제 전"); | |
251 | + | |
252 | + private FileStatus (String status) { | |
253 | + this.status = status; | |
254 | + } | |
255 | + | |
256 | + /** | |
257 | + * 한글값 | |
258 | + */ | |
259 | + final private String status; | |
260 | + | |
261 | + /** | |
262 | + * 한글값 조회 | |
263 | + */ | |
264 | + public String getValue () { | |
265 | + return status; | |
266 | + } | |
267 | + } | |
268 | + | |
269 | + /** | |
270 | + * @author 최정우 | |
271 | + * @since 2019.11.13 | |
272 | + * | |
273 | + * 등록되는 파일 타입과, 해당 파일 타입의 등록가능한 확장자를 정의한 상수 Class 입니다. | |
274 | + * 첨부파일, 이미지파일, 데이터 셋 파일 순서입니다. | |
275 | + */ | |
276 | + public enum FileType { | |
277 | + 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")) | |
278 | + , IMG_FILE(Arrays.asList("bmp","jpg","gif","png","jpeg")) | |
279 | + , DATASET_FILE(Arrays.asList("xls","xlsx","csv")) | |
280 | + , DATA_FILE(Arrays.asList("xls","xlsx")); | |
281 | + | |
282 | + private FileType(List<String> extensions) { this.extensions = extensions; | |
283 | + } | |
284 | + | |
285 | + /** | |
286 | + * 확장자 목록 | |
287 | + */ | |
288 | + final private List<String> extensions; | |
289 | + | |
290 | + /** | |
291 | + * 확장자 목록 조회 | |
292 | + */ | |
293 | + public List<String> getExtensions () { | |
294 | + return extensions; | |
295 | + } | |
296 | + } | |
297 | + | |
298 | + /** | |
299 | + * @author 최정우 | |
300 | + * @since 2019.11.13 | |
301 | + * | |
302 | + * 확장자를 포함한 파일 Full 경로 (fileAbsolutePath + '/' + fileMaskName + '.' + fileExtension) | |
303 | + * | |
304 | + */ | |
305 | + public String getFileFullPath() { | |
306 | + return this.fileAbsolutePath + File.separator + this.fileMaskName + "." + this.fileExtension; | |
307 | + } | |
308 | +} |
+++ src/back-end/main/java/common/vo/CommonValueObject.java
... | ... | @@ -0,0 +1,197 @@ |
1 | +package common.vo; | |
2 | + | |
3 | +import common.util.CryptoUtil; | |
4 | + | |
5 | +import java.security.PrivateKey; | |
6 | +import java.util.ArrayList; | |
7 | +import java.util.HashMap; | |
8 | +import java.util.LinkedHashMap; | |
9 | +import java.util.List; | |
10 | + | |
11 | +/** | |
12 | + * @author 최정우 | |
13 | + * @since 2021.09.28 | |
14 | + * | |
15 | + * 공통 Value Object | |
16 | + * | |
17 | + * Object or List 데이터 활용시, 사용 (int, String, boolean... 등에는 사용할 필요 없음) | |
18 | + */ | |
19 | +public class CommonValueObject { | |
20 | + | |
21 | + public final static String DEFAULT_FILE_GROUP_NAME = "commonFileList"; | |
22 | + | |
23 | + | |
24 | + /** | |
25 | + * 검색 객체 | |
26 | + */ | |
27 | + private Search search = new Search(); | |
28 | + | |
29 | + /** | |
30 | + * object Data 객체 | |
31 | + * | |
32 | + * 활용 방법 (규칙이니까 꼭 치키세요) | |
33 | + * | |
34 | + * 1. 단일 등록(Insert) | |
35 | + * 2. 단일 수정(Update) | |
36 | + * 3. 단일 삭제(Delete) | |
37 | + * 4. 상세 조회(SelectOne) | |
38 | + * | |
39 | + * 위의 경우를 제외하고 사용하면 안됨 | |
40 | + */ | |
41 | + private LinkedHashMap<String, Object> data = new LinkedHashMap<String, Object>(); | |
42 | + | |
43 | + /** | |
44 | + * list Data 객체 | |
45 | + * | |
46 | + * 1. 다중 등록(Muliple Insert) | |
47 | + * 2. 다중 수정(Muliple Update) | |
48 | + * 3. 다중 삭제(Muliple Delete) | |
49 | + * 4. 목록 조회(SelectList) | |
50 | + */ | |
51 | + private List<LinkedHashMap<String, Object>> dataList = new ArrayList<LinkedHashMap<String, Object>>(); | |
52 | + | |
53 | + /** | |
54 | + * 암호화 대상 Key's | |
55 | + * | |
56 | + * data, dataList에 사용 | |
57 | + */ | |
58 | + private List<String> encodingTargetKeys = new ArrayList<String>(); | |
59 | + | |
60 | + | |
61 | + /** | |
62 | + * 공통 파일을 담을 객체 | |
63 | + * | |
64 | + */ | |
65 | + private HashMap<String, List<CommonFile>> commonFileGroup = new HashMap<String, List<CommonFile>>(); | |
66 | + | |
67 | + /** | |
68 | + * 메세지 | |
69 | + */ | |
70 | + private CheckMessage checkMessage = new CheckMessage(); | |
71 | + | |
72 | + public Search getSearch() { | |
73 | + return search; | |
74 | + } | |
75 | + | |
76 | + public void setSearch(Search search) { | |
77 | + this.search = search; | |
78 | + } | |
79 | + | |
80 | + public LinkedHashMap<String, Object> getData() { | |
81 | + return data; | |
82 | + } | |
83 | + | |
84 | + public void setData(LinkedHashMap<String, Object> data) { | |
85 | + this.data = data; | |
86 | + } | |
87 | + | |
88 | + public List<LinkedHashMap<String, Object>> getDataList() { | |
89 | + return dataList; | |
90 | + } | |
91 | + | |
92 | + public void setDataList(List<LinkedHashMap<String, Object>> dataList) { | |
93 | + this.dataList = dataList; | |
94 | + } | |
95 | + | |
96 | + public List<String> getEncodingTargetKeys() { | |
97 | + return encodingTargetKeys; | |
98 | + } | |
99 | + | |
100 | + public void setEncodingTargetKeys(List<String> encodingTargetKeys) { | |
101 | + this.encodingTargetKeys = encodingTargetKeys; | |
102 | + } | |
103 | + | |
104 | + public HashMap<String, List<CommonFile>> getCommonFileGroup() { | |
105 | + if (commonFileGroup.get(DEFAULT_FILE_GROUP_NAME) == null) { | |
106 | + commonFileGroup.put(DEFAULT_FILE_GROUP_NAME, new ArrayList<CommonFile>(1)); | |
107 | + } | |
108 | + return commonFileGroup; | |
109 | + } | |
110 | + | |
111 | + public void setCommonFileGroup(HashMap<String, List<CommonFile>> commonFileGroup) { | |
112 | + this.commonFileGroup = commonFileGroup; | |
113 | + } | |
114 | + | |
115 | + public CheckMessage getCheckMessage() { | |
116 | + return checkMessage; | |
117 | + } | |
118 | + | |
119 | + public void setCheckMessage(CheckMessage checkMessage) { | |
120 | + this.checkMessage = checkMessage; | |
121 | + } | |
122 | + | |
123 | + /** | |
124 | + * @author 최정우 | |
125 | + * @since 2021.11.10 | |
126 | + * | |
127 | + * RSA 암호화 디코딩 (data) | |
128 | + */ | |
129 | + public void dataDecodingByRsa () { | |
130 | + //session in RSA 개인키 (조회이후 session에서 암호화 Key 삭제) | |
131 | + PrivateKey privateKey = CryptoUtil.getPrivateKeyInSession(); | |
132 | + //데이터 복호화 (RSA 비대칭키 암호화 활용) | |
133 | + for (int i = 0; i < this.encodingTargetKeys.size(); i++) { | |
134 | + String key = this.encodingTargetKeys.get(i);//암호화 대상 Key | |
135 | + String encodingValue = (String) this.data.get(key);//암호화된 값 | |
136 | + String decodingValue = null; | |
137 | + try { | |
138 | + decodingValue = CryptoUtil.decodingByRsa(encodingValue, privateKey);//복호화된 값 | |
139 | + } catch (Exception e) { | |
140 | + decodingValue = encodingValue; | |
141 | + e.printStackTrace(); | |
142 | + } | |
143 | + //System.out.println("key: " + key + ", encodingValue: " + encodingValue + ", decodingValue: " + decodingValue); | |
144 | + this.data.put(key, decodingValue);//복호화된 값 set | |
145 | + } | |
146 | + } | |
147 | + | |
148 | + /** | |
149 | + * @author 최정우 | |
150 | + * @since 2021.11.10 | |
151 | + * | |
152 | + * RSA 암호화 디코딩 (dataList) | |
153 | + */ | |
154 | + public void dataListDecodingByRsa () { | |
155 | + //session in RSA 개인키 (조회이후 session에서 암호화 Key 삭제) | |
156 | + PrivateKey privateKey = CryptoUtil.getPrivateKeyInSession(); | |
157 | + //데이터 복호화 (RSA 비대칭키 암호화 활용) | |
158 | + for (int i = 0; i < this.dataList.size(); i++) { | |
159 | + for (int j = 0; j < this.encodingTargetKeys.size(); j++) { | |
160 | + String key = this.encodingTargetKeys.get(j);//암호화 대상 Key | |
161 | + String encodingValue = (String) this.dataList.get(i).get(key);//암호화된 값 | |
162 | + String decodingValue = null; | |
163 | + try { | |
164 | + decodingValue = CryptoUtil.decodingByRsa(encodingValue, privateKey);//복호화된 값 | |
165 | + } catch (Exception e) { | |
166 | + decodingValue = encodingValue; | |
167 | + e.printStackTrace(); | |
168 | + } | |
169 | + //System.out.println("key: " + key + ", encodingValue: " + encodingValue + ", decodingValue: " + decodingValue); | |
170 | + this.dataList.get(i).put(key, decodingValue);//복호화된 값 set | |
171 | + } | |
172 | + } | |
173 | + } | |
174 | + | |
175 | + /** | |
176 | + * @author 최정우 | |
177 | + * @since 2021.11.10 | |
178 | + * | |
179 | + * XSS 공격 방지 | |
180 | + * | |
181 | + */ | |
182 | + public void htmlFilter (Object targetObject, Class<?> targetObjectClass) { | |
183 | + | |
184 | + } | |
185 | + | |
186 | + /** | |
187 | + * @author 최정우 | |
188 | + * @since 2021.11.10 | |
189 | + * | |
190 | + * SQL Injection 공격 방지 | |
191 | + * | |
192 | + */ | |
193 | + public void sqlFilter (Object targetObject, Class<?> targetObjectClass) { | |
194 | + | |
195 | + } | |
196 | + | |
197 | +} |
+++ src/back-end/main/java/common/vo/CommonValueObject_back.java
... | ... | @@ -0,0 +1,164 @@ |
1 | +package common.vo; | |
2 | + | |
3 | +import java.util.LinkedHashMap; | |
4 | +import java.util.Map; | |
5 | + | |
6 | +/** | |
7 | + * @author 최정우 | |
8 | + * @since 2021.09.28 | |
9 | + * | |
10 | + * 공통 Value Object | |
11 | + */ | |
12 | +public class CommonValueObject_back extends LinkedHashMap<String, Object> { | |
13 | + | |
14 | + /** | |
15 | + * Search객체 생성 여부 (Defalut:true) | |
16 | + */ | |
17 | + private boolean isSearchCreate = true; | |
18 | + | |
19 | + /** | |
20 | + * Constructs an empty insertion-ordered {@code LinkedHashMap} instance | |
21 | + * with the specified initial capacity and load factor. | |
22 | + * | |
23 | + * @param initialCapacity the initial capacity | |
24 | + * @param loadFactor the load factor | |
25 | + * @throws IllegalArgumentException if the initial capacity is negative | |
26 | + * or the load factor is nonpositive | |
27 | + */ | |
28 | + public CommonValueObject_back(int initialCapacity, float loadFactor) { | |
29 | + super(initialCapacity, loadFactor); | |
30 | + init(); | |
31 | + } | |
32 | + | |
33 | + /** | |
34 | + * Constructs an empty insertion-ordered {@code LinkedHashMap} instance | |
35 | + * with the specified initial capacity and a default load factor (0.75). | |
36 | + * | |
37 | + * @param initialCapacity the initial capacity | |
38 | + * @throws IllegalArgumentException if the initial capacity is negative | |
39 | + */ | |
40 | + public CommonValueObject_back(int initialCapacity) { | |
41 | + super(initialCapacity); | |
42 | + init(); | |
43 | + } | |
44 | + | |
45 | + /** | |
46 | + * Constructs an empty insertion-ordered {@code LinkedHashMap} instance | |
47 | + * with the default initial capacity (16) and load factor (0.75). | |
48 | + */ | |
49 | + public CommonValueObject_back() { | |
50 | + super(); | |
51 | + init(); | |
52 | + } | |
53 | + | |
54 | + /** | |
55 | + * 커스텀 | |
56 | + */ | |
57 | + public CommonValueObject_back(boolean isSearchCreate) { | |
58 | + super(); | |
59 | + | |
60 | + this.isSearchCreate = isSearchCreate; | |
61 | + init(); | |
62 | + } | |
63 | + | |
64 | + /** | |
65 | + * Constructs an insertion-ordered {@code LinkedHashMap} instance with | |
66 | + * the same mappings as the specified map. The {@code LinkedHashMap} | |
67 | + * instance is created with a default load factor (0.75) and an initial | |
68 | + * capacity sufficient to hold the mappings in the specified map. | |
69 | + * | |
70 | + * @param m the map whose mappings are to be placed in this map | |
71 | + * @throws NullPointerException if the specified map is null | |
72 | + */ | |
73 | + public CommonValueObject_back(Map<String, Object> m) { | |
74 | + super(); | |
75 | + init(); | |
76 | + } | |
77 | + | |
78 | + /** | |
79 | + * Constructs an empty {@code LinkedHashMap} instance with the | |
80 | + * specified initial capacity, load factor and ordering mode. | |
81 | + * | |
82 | + * @param initialCapacity the initial capacity | |
83 | + * @param loadFactor the load factor | |
84 | + * @param accessOrder the ordering mode - {@code true} for | |
85 | + * access-order, {@code false} for insertion-order | |
86 | + * @throws IllegalArgumentException if the initial capacity is negative | |
87 | + * or the load factor is nonpositive | |
88 | + */ | |
89 | + public CommonValueObject_back(int initialCapacity, float loadFactor, boolean accessOrder) { | |
90 | + super(initialCapacity, loadFactor); | |
91 | + init(); | |
92 | + } | |
93 | + | |
94 | + | |
95 | + | |
96 | + | |
97 | + | |
98 | + /** | |
99 | + * CommonValueObject 초기화 (Search 객체 생성) | |
100 | + */ | |
101 | + public void init () { | |
102 | + if (this.isSearchCreate == true) { | |
103 | + super.put((String) "search", (Object) new Search()); | |
104 | + } else { | |
105 | + return; | |
106 | + } | |
107 | + } | |
108 | + | |
109 | + | |
110 | + | |
111 | + /** | |
112 | + * 검색 목록에 데이터 추가하기 | |
113 | + * | |
114 | + * @param column : 검색 컬럼명 | |
115 | + * @param keyword : 검색어 | |
116 | + */ | |
117 | + public void addSearchCondition (String column, String keyword) throws Exception { | |
118 | + Search search = (Search) super.get("search"); | |
119 | + search.addSearchCondition(column, keyword); | |
120 | + super.put("search", search); | |
121 | + } | |
122 | + | |
123 | + /** | |
124 | + * 검색 목록에 데이터 추가하기 | |
125 | + * | |
126 | + * @param column : 검색 컬럼명 | |
127 | + * @param keyword : 검색어 | |
128 | + * @param comparisonType : 검색어 비교 연산자 타입 ('=', 'like', 'is <not> null') | |
129 | + * @param currentSearchOperator : 현재 검색 조건 연산자 (AND, OR) | |
130 | + */ | |
131 | + public void addSearchCondition (String column, String comparisonType, String keyword, String currentSearchOperator) throws Exception { | |
132 | + ((Search) super.get("search")).addSearchCondition(column, comparisonType, keyword, currentSearchOperator); | |
133 | + } | |
134 | + | |
135 | + /** | |
136 | + * 검색 정렬 목록에 데이터 추가하기 | |
137 | + * | |
138 | + * @param column : 검색 컬럼명 | |
139 | + */ | |
140 | + public void addSearchOrder (String column) throws Exception { | |
141 | + ((Search) super.get("search")).addSearchOrder(column); | |
142 | + } | |
143 | + | |
144 | + /** | |
145 | + * 검색 목록에 데이터 추가하기 | |
146 | + * | |
147 | + * @param column : 검색 컬럼명 | |
148 | + * @param orderType : 정렬 타입('ASC', 'DESC') | |
149 | + */ | |
150 | + public void addSearchOrder (String column, String orderType) throws Exception { | |
151 | + ((Search) super.get("search")).addSearchOrder(column, orderType); | |
152 | + } | |
153 | + | |
154 | + /** | |
155 | + * 검색 객체 가지고가기 | |
156 | + */ | |
157 | + public Search getSearch() { | |
158 | + if (super.get("search") == null) { | |
159 | + return null; | |
160 | + } else { | |
161 | + return (Search) super.get("search"); | |
162 | + } | |
163 | + } | |
164 | +} |
+++ src/back-end/main/java/common/vo/Org.java
... | ... | @@ -0,0 +1,170 @@ |
1 | +package common.vo; | |
2 | + | |
3 | +import java.util.ArrayList; | |
4 | +import java.util.List; | |
5 | + | |
6 | +/** | |
7 | + * @author 최정우 | |
8 | + * @since 2021.12.06 | |
9 | + * | |
10 | + * 그룹 정보 VO입니다. | |
11 | + */ | |
12 | +public class Org { | |
13 | + | |
14 | + /** | |
15 | + * 그룹 ID | |
16 | + */ | |
17 | + private String orgId; | |
18 | + | |
19 | + /** | |
20 | + * 부모 그룹 ID | |
21 | + */ | |
22 | + private String orgParentId; | |
23 | + | |
24 | + /** | |
25 | + * 그룹명 | |
26 | + */ | |
27 | + private String orgName; | |
28 | + | |
29 | + /** | |
30 | + * 그룹 설명 | |
31 | + */ | |
32 | + private String orgComment; | |
33 | + | |
34 | + /** | |
35 | + * 그룹 Level | |
36 | + */ | |
37 | + private int orgDepth; | |
38 | + | |
39 | + /** | |
40 | + * 배치 순서 | |
41 | + */ | |
42 | + private int orgOrder; | |
43 | + | |
44 | + /** | |
45 | + * 등록자 | |
46 | + */ | |
47 | + private String orgInsertUserId; | |
48 | + | |
49 | + /** | |
50 | + * 등록일시 | |
51 | + */ | |
52 | + private String orgInsertDatetime; | |
53 | + | |
54 | + /** | |
55 | + * 수정자 | |
56 | + */ | |
57 | + private String orgUpdateUserId; | |
58 | + | |
59 | + /** | |
60 | + * 수정일시 | |
61 | + */ | |
62 | + private String orgUpdateDatetime; | |
63 | + | |
64 | + /** | |
65 | + * 사용여부 | |
66 | + */ | |
67 | + private String orgIsUse; | |
68 | + | |
69 | + /** | |
70 | + * 그룹의 권한's | |
71 | + */ | |
72 | + private List<String> orgAuthotitise = new ArrayList<String>(); | |
73 | + | |
74 | + public String getOrgId() { | |
75 | + return orgId; | |
76 | + } | |
77 | + | |
78 | + public void setOrgId(String orgId) { | |
79 | + this.orgId = orgId; | |
80 | + } | |
81 | + | |
82 | + public String getOrgParentId() { | |
83 | + return orgParentId; | |
84 | + } | |
85 | + | |
86 | + public void setOrgParentId(String orgParentId) { | |
87 | + this.orgParentId = orgParentId; | |
88 | + } | |
89 | + | |
90 | + public String getOrgName() { | |
91 | + return orgName; | |
92 | + } | |
93 | + | |
94 | + public void setOrgName(String orgName) { | |
95 | + this.orgName = orgName; | |
96 | + } | |
97 | + | |
98 | + public String getOrgComment() { | |
99 | + return orgComment; | |
100 | + } | |
101 | + | |
102 | + public void setOrgComment(String orgComment) { | |
103 | + this.orgComment = orgComment; | |
104 | + } | |
105 | + | |
106 | + public int getOrgDepth() { | |
107 | + return orgDepth; | |
108 | + } | |
109 | + | |
110 | + public void setOrgDepth(int orgDepth) { | |
111 | + this.orgDepth = orgDepth; | |
112 | + } | |
113 | + | |
114 | + public int getOrgOrder() { | |
115 | + return orgOrder; | |
116 | + } | |
117 | + | |
118 | + public void setOrgOrder(int orgOrder) { | |
119 | + this.orgOrder = orgOrder; | |
120 | + } | |
121 | + | |
122 | + public String getOrgInsertUserId() { | |
123 | + return orgInsertUserId; | |
124 | + } | |
125 | + | |
126 | + public void setOrgInsertUserId(String orgInsertUserId) { | |
127 | + this.orgInsertUserId = orgInsertUserId; | |
128 | + } | |
129 | + | |
130 | + public String getOrgInsertDatetime() { | |
131 | + return orgInsertDatetime; | |
132 | + } | |
133 | + | |
134 | + public void setOrgInsertDatetime(String orgInsertDatetime) { | |
135 | + this.orgInsertDatetime = orgInsertDatetime; | |
136 | + } | |
137 | + | |
138 | + public String getOrgUpdateUserId() { | |
139 | + return orgUpdateUserId; | |
140 | + } | |
141 | + | |
142 | + public void setOrgUpdateUserId(String orgUpdateUserId) { | |
143 | + this.orgUpdateUserId = orgUpdateUserId; | |
144 | + } | |
145 | + | |
146 | + public String getOrgUpdateDatetime() { | |
147 | + return orgUpdateDatetime; | |
148 | + } | |
149 | + | |
150 | + public void setOrgUpdateDatetime(String orgUpdateDatetime) { | |
151 | + this.orgUpdateDatetime = orgUpdateDatetime; | |
152 | + } | |
153 | + | |
154 | + public String getOrgIsUse() { | |
155 | + return orgIsUse; | |
156 | + } | |
157 | + | |
158 | + public void setOrgIsUse(String orgIsUse) { | |
159 | + this.orgIsUse = orgIsUse; | |
160 | + } | |
161 | + | |
162 | + public List<String> getOrgAuthotitise() { | |
163 | + return orgAuthotitise; | |
164 | + } | |
165 | + | |
166 | + public void setOrgAuthotitise(List<String> orgAuthotitise) { | |
167 | + this.orgAuthotitise = orgAuthotitise; | |
168 | + } | |
169 | + | |
170 | +} |
+++ src/back-end/main/java/common/vo/Search.java
... | ... | @@ -0,0 +1,315 @@ |
1 | +package common.vo; | |
2 | + | |
3 | +import common.util.AuthUtil; | |
4 | +import common.util.StringUtil; | |
5 | + | |
6 | +import java.util.ArrayList; | |
7 | +import java.util.List; | |
8 | + | |
9 | +/** | |
10 | + * @author 최정우 | |
11 | + * @since 2021.12.06 | |
12 | + * | |
13 | + * 공통 검색 VO 입니다.(상속받으세요) | |
14 | + */ | |
15 | +public class Search extends User { | |
16 | + | |
17 | + public Search () { | |
18 | + if (AuthUtil.getLoginUser() != null) { | |
19 | + User loginUser = AuthUtil.getLoginUser(); | |
20 | + super.setUserId(loginUser.getUserId()); | |
21 | + super.setLoginId(loginUser.getLoginId()); | |
22 | + super.setName(loginUser.getName()); | |
23 | + super.setEmail(loginUser.getEmail()); | |
24 | + super.setGender(loginUser.getGender()); | |
25 | + super.setBirthDate(loginUser.getBirthDate()); | |
26 | + super.setMobile(loginUser.getMobile()); | |
27 | + super.setAddress(loginUser.getAddress()); | |
28 | + super.setDetailAddress(loginUser.getDetailAddress()); | |
29 | + super.setRegistrationDatetime(loginUser.getRegistrationDatetime()); | |
30 | + super.setWithdrawDatetime(loginUser.getWithdrawDatetime()); | |
31 | + super.setIsWithdraw(loginUser.getIsWithdraw()); | |
32 | + super.setLoginFailedCount(loginUser.getLoginFailedCount()); | |
33 | + super.setIsAccountLock(loginUser.getIsAccountLock()); | |
34 | + super.setUserAuthotities(loginUser.getUserAuthotities()); | |
35 | + } | |
36 | + } | |
37 | + | |
38 | + /** | |
39 | + * 검색 목록's | |
40 | + */ | |
41 | + private List<SearchCondition> searchConditionList = new ArrayList<SearchCondition>(); | |
42 | + | |
43 | + /** | |
44 | + * 정렬 순서's | |
45 | + */ | |
46 | + private List<SearchOrder> searchOrderList = new ArrayList<SearchOrder>(); | |
47 | + | |
48 | + /** | |
49 | + * 현재 페이지 | |
50 | + */ | |
51 | + private int currentPage = 1; | |
52 | + | |
53 | + /** | |
54 | + * 한 페이지당 조회될 데이터 수 | |
55 | + */ | |
56 | + private int perPage = 10; | |
57 | + | |
58 | + /** | |
59 | + * 총 개시물 수 | |
60 | + */ | |
61 | + private int totalRows = 0; | |
62 | + | |
63 | + /** | |
64 | + * 페이징 시작할 row 넘버 | |
65 | + */ | |
66 | + private int startRowNumber = 0; | |
67 | + | |
68 | + | |
69 | + /** | |
70 | + * 페이징 사용 유무 | |
71 | + */ | |
72 | + private boolean isUsePaging = true; | |
73 | + | |
74 | + | |
75 | + public List<SearchCondition> getSearchConditionList() { | |
76 | + return searchConditionList; | |
77 | + } | |
78 | + | |
79 | + public void setSearchConditionList(List<SearchCondition> searchConditionList) { | |
80 | + this.searchConditionList = searchConditionList; | |
81 | + } | |
82 | + | |
83 | + public List<SearchOrder> getSearchOrderList() { | |
84 | + return searchOrderList; | |
85 | + } | |
86 | + | |
87 | + public void setSearchOrderList(List<SearchOrder> searchOrderList) { | |
88 | + this.searchOrderList = searchOrderList; | |
89 | + } | |
90 | + | |
91 | + public int getCurrentPage() { | |
92 | + return this.currentPage; | |
93 | + } | |
94 | + | |
95 | + public void setCurrentPage(int currentPage) { | |
96 | + this.currentPage = currentPage; | |
97 | + } | |
98 | + | |
99 | + public int getPerPage() { | |
100 | + return perPage; | |
101 | + } | |
102 | + | |
103 | + public void setPerPage(int perPage) { | |
104 | + this.perPage = perPage; | |
105 | + } | |
106 | + | |
107 | + public int getTotalRows() { | |
108 | + return totalRows; | |
109 | + } | |
110 | + | |
111 | + public void setTotalRows(int totalRows) { | |
112 | + this.totalRows = totalRows; | |
113 | + } | |
114 | + | |
115 | + public int getStartRowNumber() { | |
116 | + return (currentPage - 1) * perPage; | |
117 | + } | |
118 | + | |
119 | + public void setStartRowNumber(int startRowNumber) { | |
120 | + this.startRowNumber = startRowNumber; | |
121 | + } | |
122 | + | |
123 | + public boolean getIsUsePaging() { | |
124 | + return isUsePaging; | |
125 | + } | |
126 | + | |
127 | + public void setIsUsePaging(boolean isUsePaging) { | |
128 | + this.isUsePaging = isUsePaging; | |
129 | + } | |
130 | + | |
131 | + /** | |
132 | + * 검색 목록에 데이터 추가하기 | |
133 | + * | |
134 | + * @param column : 검색 컬럼명 | |
135 | + * @param value : 검색어 | |
136 | + */ | |
137 | + public void addSearchCondition (String column, String value) throws Exception { | |
138 | + if (StringUtil.isEmpty(column) == false) { | |
139 | + SearchCondition searchCondition = new SearchCondition(); | |
140 | + searchCondition.setColumn(column); | |
141 | + searchCondition.setValue(value); | |
142 | + | |
143 | + searchConditionList.add(searchCondition); | |
144 | + } else { | |
145 | + throw new Exception("addSearchCondition 메서드 에러 : 검색 조건의 컬럼명 값이 'null' 또는 '공백'입니다."); | |
146 | + } | |
147 | + } | |
148 | + | |
149 | + /** | |
150 | + * 검색 목록에 데이터 추가하기 | |
151 | + * | |
152 | + * @param operator : 현재 검색 조건 연산자 (AND, OR) | |
153 | + * @param column : 검색 컬럼명 | |
154 | + * @param comparisonType : 검색어 비교 연산자 타입 ('=', 'like', 'is <not> null') | |
155 | + * @param value : 검색어 | |
156 | + */ | |
157 | + public void addSearchCondition (String operator, String column, String comparisonType, String value) throws Exception { | |
158 | + if (StringUtil.isEmpty(column) == false) { | |
159 | + SearchCondition searchCondition = new SearchCondition(); | |
160 | + searchCondition.setOperator(operator); | |
161 | + searchCondition.setColumn(column); | |
162 | + searchCondition.setComparisonType(comparisonType); | |
163 | + searchCondition.setValue(value); | |
164 | + | |
165 | + searchConditionList.add(searchCondition); | |
166 | + } else { | |
167 | + throw new Exception("addSearchCondition 메서드 에러 : 검색 조건의 컬럼명 값이 'null' 또는 '공백'입니다."); | |
168 | + } | |
169 | + } | |
170 | + /** | |
171 | + * 검색 목록에 데이터 set (같은 컬럼명이 존재 할 시 -> value 대체 / 없을 시 -> 검색 목록에 추가) | |
172 | + * | |
173 | + * @param column : 검색 컬럼명 | |
174 | + */ | |
175 | + public void setSearchCondition (String column, String value) throws Exception { | |
176 | + boolean isFind = false; | |
177 | + for (int i = 0; i < searchConditionList.size(); i++) { | |
178 | + if (searchConditionList.get(i).getColumn().equals(column) == true) { | |
179 | + searchConditionList.get(i).setColumn(column); | |
180 | + searchConditionList.get(i).setValue(value); | |
181 | + isFind = true; | |
182 | + break; | |
183 | + } | |
184 | + } | |
185 | + | |
186 | + if (isFind == false) { | |
187 | + addSearchCondition(column, value); | |
188 | + } | |
189 | + } | |
190 | + /** | |
191 | + * 검색 목록에 데이터 set (같은 컬럼명이 존재 할 시 -> value 대체 / 없을 시 -> 검색 목록에 추가) | |
192 | + * | |
193 | + * @param column : 검색 컬럼명 | |
194 | + */ | |
195 | + public void setSearchCondition (String operator, String column, String comparisonType, String value) throws Exception { | |
196 | + boolean isFind = false; | |
197 | + for (int i = 0; i < searchConditionList.size(); i++) { | |
198 | + if (searchConditionList.get(i).getColumn().equals(column) == true) { | |
199 | + searchConditionList.get(i).setOperator(operator); | |
200 | + searchConditionList.get(i).setColumn(column); | |
201 | + searchConditionList.get(i).setComparisonType(comparisonType); | |
202 | + searchConditionList.get(i).setValue(value); | |
203 | + isFind = true; | |
204 | + break; | |
205 | + } | |
206 | + } | |
207 | + | |
208 | + if (isFind == false) { | |
209 | + addSearchCondition(operator, column, comparisonType, value); | |
210 | + } | |
211 | + } | |
212 | + /** | |
213 | + * 검색 목록에 데이터 삭제하기 | |
214 | + * | |
215 | + * @param column : 검색 컬럼명 | |
216 | + */ | |
217 | + public void removeSearchCondition (String column) throws Exception { | |
218 | + for (int i = 0; i < searchConditionList.size(); i++) { | |
219 | + if (searchConditionList.get(i).getColumn().equals(column) == true) { | |
220 | + searchConditionList.remove(i); | |
221 | + break; | |
222 | + } | |
223 | + } | |
224 | + } | |
225 | + | |
226 | + /** | |
227 | + * 검색 정렬 목록에 데이터 추가하기 | |
228 | + * | |
229 | + * @param column : 검색 컬럼명 | |
230 | + */ | |
231 | + public void addSearchOrder (String column) throws Exception { | |
232 | + if (StringUtil.isEmpty(column) == false) { | |
233 | + SearchOrder searchOrder = new SearchOrder(); | |
234 | + searchOrder.setColumn(column); | |
235 | + | |
236 | + searchOrderList.add(searchOrder); | |
237 | + } else { | |
238 | + throw new Exception("addSearchOrder 메서드 에러 : 정렬 조건의 컬럼명 값이 'null' 또는 '공백'입니다."); | |
239 | + } | |
240 | + } | |
241 | + | |
242 | + /** | |
243 | + * 검색 목록에 데이터 추가하기 | |
244 | + * | |
245 | + * @param column : 검색 컬럼명 | |
246 | + * @param orderType : 정렬 타입('ASC', 'DESC') | |
247 | + */ | |
248 | + public void addSearchOrder (String column, String orderType) throws Exception { | |
249 | + if (StringUtil.isEmpty(column) == false) { | |
250 | + SearchOrder searchOrder = new SearchOrder(); | |
251 | + searchOrder.setColumn(column); | |
252 | + searchOrder.setOrderType(orderType); | |
253 | + | |
254 | + searchOrderList.add(searchOrder); | |
255 | + } else { | |
256 | + throw new Exception("addSearchOrder 메서드 에러 : 정렬 조건의 컬럼명 값이 'null' 또는 '공백'입니다."); | |
257 | + } | |
258 | + } | |
259 | + /** | |
260 | + * 검색 목록에 데이터 set (같은 컬럼명이 존재 할 시 -> value 대체 / 없을 시 -> 검색 목록에 추가) | |
261 | + * | |
262 | + * @param column : 검색 컬럼명 | |
263 | + */ | |
264 | + public void setSearchOrder (String column) throws Exception { | |
265 | + boolean isFind = false; | |
266 | + for (int i = 0; i < searchOrderList.size(); i++) { | |
267 | + if (searchOrderList.get(i).getColumn().equals(column) == true) { | |
268 | + searchOrderList.get(i).setColumn(column); | |
269 | + isFind = true; | |
270 | + break; | |
271 | + } | |
272 | + } | |
273 | + | |
274 | + if (isFind == false) { | |
275 | + addSearchOrder(column); | |
276 | + } | |
277 | + } | |
278 | + /** | |
279 | + * 검색 목록에 데이터 set (같은 컬럼명이 존재 할 시 -> value 대체 / 없을 시 -> 검색 목록에 추가) | |
280 | + * | |
281 | + * @param column : 검색 컬럼명 | |
282 | + */ | |
283 | + public void setSearchOrder (String column, String orderType) throws Exception { | |
284 | + boolean isFind = false; | |
285 | + for (int i = 0; i < searchOrderList.size(); i++) { | |
286 | + if (searchOrderList.get(i).getColumn().equals(column) == true) { | |
287 | + searchOrderList.get(i).setColumn(column); | |
288 | + searchOrderList.get(i).setOrderType(orderType); | |
289 | + isFind = true; | |
290 | + break; | |
291 | + } | |
292 | + } | |
293 | + | |
294 | + if (isFind == false) { | |
295 | + addSearchOrder(column, orderType); | |
296 | + } | |
297 | + } | |
298 | + /** | |
299 | + * 검색 목록에 데이터 삭제하기 | |
300 | + * | |
301 | + * @param column : 검색 컬럼명 | |
302 | + */ | |
303 | + public void removeSearchOrder (String column) throws Exception { | |
304 | + for (int i = 0; i < searchOrderList.size(); i++) { | |
305 | + if (searchOrderList.get(i).getColumn().equals(column) == true) { | |
306 | + searchOrderList.remove(i); | |
307 | + break; | |
308 | + } | |
309 | + } | |
310 | + } | |
311 | +} | |
312 | + | |
313 | + | |
314 | + | |
315 | + |
+++ src/back-end/main/java/common/vo/SearchCondition.java
... | ... | @@ -0,0 +1,127 @@ |
1 | +package common.vo; | |
2 | + | |
3 | +import common.util.StringUtil; | |
4 | + | |
5 | +/** | |
6 | + * @author 최정우 | |
7 | + * @since 2021.12.06 | |
8 | + * | |
9 | + * 검색 조건 VO 입니다. | |
10 | + */ | |
11 | +public class SearchCondition { | |
12 | + | |
13 | + /** | |
14 | + * 현재 검색 조건 연산자 (OR, AND) (주의 - 검색 조건 앞에 붙음) | |
15 | + * | |
16 | + * Search class의 searchOperator변수보다 우선순위를 가짐 | |
17 | + * | |
18 | + * 순서: 0 | |
19 | + */ | |
20 | + private String operator = "AND"; | |
21 | + | |
22 | + /** | |
23 | + * 검색 조건 앞에 붙이는 문자 ex) 여는 괄호 '(' | |
24 | + * | |
25 | + * 순서: 1 | |
26 | + */ | |
27 | + private String prefix = ""; | |
28 | + | |
29 | + /** | |
30 | + * 검색 컬럼 | |
31 | + * | |
32 | + * 순서: 2 | |
33 | + */ | |
34 | + private String column = ""; | |
35 | + | |
36 | + /** | |
37 | + * 검색어 비교 연산자 타입 ('=', '!=', '<>', '>', '>=', '<', '<=' 'like', 'is <not> null') | |
38 | + * | |
39 | + * 순서: 3 | |
40 | + */ | |
41 | + private String comparisonType = "="; | |
42 | + | |
43 | + /** | |
44 | + * 검색값 | |
45 | + * | |
46 | + * 순서: 4 | |
47 | + */ | |
48 | + private Object value = null; | |
49 | + | |
50 | + /** | |
51 | + * 검색 조건 뒤에 붙이는 문자 ex) 닫는 괄호 ')' | |
52 | + * | |
53 | + * 순서: 5 | |
54 | + */ | |
55 | + private String suffix = ""; | |
56 | + | |
57 | + | |
58 | + public String getColumn() { | |
59 | + return column; | |
60 | + } | |
61 | + | |
62 | + public void setColumn(String column) { | |
63 | + if (StringUtil.isEmpty(column) == true) { | |
64 | + this.column = ""; | |
65 | + } else { | |
66 | + this.column = column; | |
67 | + } | |
68 | + } | |
69 | + | |
70 | + public Object getValue() { | |
71 | + return value; | |
72 | + } | |
73 | + | |
74 | + public void setValue(Object value) { | |
75 | + this.value = value; | |
76 | + } | |
77 | + | |
78 | + public String getComparisonType() { | |
79 | + return comparisonType; | |
80 | + } | |
81 | + | |
82 | + public void setComparisonType(String comparisonType) { | |
83 | + comparisonType = comparisonType.toUpperCase(); | |
84 | + if (comparisonType.equals("=") | |
85 | + || comparisonType.equals("!=") || comparisonType.equals("<>") | |
86 | + || comparisonType.equals(">") || comparisonType.equals(">=") | |
87 | + || comparisonType.equals("<") || comparisonType.equals("<=") | |
88 | + || comparisonType.equals("LIKE") || comparisonType.equals("IS") | |
89 | + || comparisonType.equals("IS NOT")) { | |
90 | + this.comparisonType = comparisonType; | |
91 | + } else { | |
92 | + //걍 냅둡시다. | |
93 | + } | |
94 | + } | |
95 | + | |
96 | + | |
97 | + public String getOperator() { | |
98 | + return operator; | |
99 | + } | |
100 | + | |
101 | + public void setOperator(String operator) { | |
102 | + this.operator = operator; | |
103 | + operator = operator.toUpperCase(); | |
104 | + if (operator.equals("AND") || operator.equals("OR")) { | |
105 | + this.operator = operator; | |
106 | + } else { | |
107 | + //걍 냅둡시다. | |
108 | + } | |
109 | + } | |
110 | + | |
111 | + public String getPrefix() { | |
112 | + return prefix; | |
113 | + } | |
114 | + | |
115 | + public void setPrefix(String prefix) { | |
116 | + this.prefix = prefix; | |
117 | + } | |
118 | + | |
119 | + public String getSuffix() { | |
120 | + return suffix; | |
121 | + } | |
122 | + | |
123 | + public void setSuffix(String suffix) { | |
124 | + this.suffix = suffix; | |
125 | + } | |
126 | + | |
127 | +}(No newline at end of file) |
+++ src/back-end/main/java/common/vo/SearchOrder.java
... | ... | @@ -0,0 +1,53 @@ |
1 | +package common.vo; | |
2 | + | |
3 | +import common.util.StringUtil; | |
4 | + | |
5 | +/** | |
6 | + * @author 최정우 | |
7 | + * @since 2021.12.06 | |
8 | + * | |
9 | + * 검색의 정렬 순서 관련 VO 입니다. | |
10 | + */ | |
11 | +public class SearchOrder { | |
12 | + | |
13 | + /** | |
14 | + * 정렬할 컬럼명 | |
15 | + */ | |
16 | + private String column = ""; | |
17 | + | |
18 | + /** | |
19 | + * 정렬 타입('ASC', 'DESC') | |
20 | + */ | |
21 | + private String orderType = "ASC"; | |
22 | + | |
23 | + public String getColumn() { | |
24 | + return column; | |
25 | + } | |
26 | + | |
27 | + public void setColumn(String column) { | |
28 | + if (StringUtil.isEmpty(column) == true) { | |
29 | + this.column = ""; | |
30 | + } else { | |
31 | + this.column = column; | |
32 | + } | |
33 | + } | |
34 | + | |
35 | + public String getOrderType() { | |
36 | + return orderType; | |
37 | + } | |
38 | + | |
39 | + public void setOrderType(String orderType) { | |
40 | + orderType = orderType.toUpperCase(); | |
41 | + if (orderType.equals("ASC") || orderType.equals("DESC")) { | |
42 | + this.orderType = orderType; | |
43 | + } else { | |
44 | + //걍 냅둡시다. | |
45 | + } | |
46 | + } | |
47 | + | |
48 | +} | |
49 | + | |
50 | + | |
51 | + | |
52 | + | |
53 | + |
+++ src/back-end/main/java/common/vo/SystemCode.java
... | ... | @@ -0,0 +1,383 @@ |
1 | +package common.vo; | |
2 | + | |
3 | +import java.util.LinkedHashMap; | |
4 | +import java.util.Map; | |
5 | + | |
6 | + | |
7 | +public class SystemCode { | |
8 | + | |
9 | + //191자 => mariaDB에서 indexing가능한 최대 크기 765Byte/한글 4Byte(utf8mb4) | |
10 | + public final static int DEFAULT_VARCHAR_SIZE = 191; | |
11 | + | |
12 | + //mariaDB에서 indexing가능한 varchar 최대 크기 765Byte | |
13 | + public final static int MAX_VARCHAR_SIZE = 765; | |
14 | + | |
15 | + //프로그램 이름 | |
16 | + public final static String PROGRAM_TITLE = "도로교통 위험분석시스템"; | |
17 | + | |
18 | + //프로그램 이름 앞에 붙는 문자열 | |
19 | + public final static String PROGRAM_TITLE_PREFIX = ""; | |
20 | + | |
21 | + /** | |
22 | + * @author 최정우 | |
23 | + * @since 2020.12.24 | |
24 | + * | |
25 | + * 시스템의 사용자 권한을 정의한 상수 Class 입니다. | |
26 | + */ | |
27 | + public enum AuthorityType { | |
28 | + ROLE_ADMIN("관리자") | |
29 | + , ROLE_USER("사용자") | |
30 | + , permitAll("API연계 수집"); | |
31 | + | |
32 | + private AuthorityType (String value) { | |
33 | + this.value = value; | |
34 | + } | |
35 | + | |
36 | + /** | |
37 | + * 한글값 | |
38 | + */ | |
39 | + final private String value; | |
40 | + | |
41 | + /** | |
42 | + * 한글값 조회 | |
43 | + */ | |
44 | + public String getValue () { | |
45 | + return value; | |
46 | + } | |
47 | + | |
48 | + /** | |
49 | + * 데이터 수집 타입 목록 조회 | |
50 | + */ | |
51 | + public static Map<AuthorityType, String> getAuthorityTypeList () { | |
52 | + Map<AuthorityType, String> info = new LinkedHashMap<AuthorityType, String>(); | |
53 | + AuthorityType[] array = AuthorityType.values(); | |
54 | + for (int i = 0; i < array.length; i++) { | |
55 | + info.put(array[i], array[i].getValue()); | |
56 | + } | |
57 | + return info; | |
58 | + } | |
59 | + } | |
60 | + | |
61 | + /** | |
62 | + * @author 최정우 | |
63 | + * @since 2020.12.24 | |
64 | + * | |
65 | + * 시스템의 사용자 권한을 정의한 상수 Class 입니다. | |
66 | + */ | |
67 | + public enum TrafficAnalysisResultType { | |
68 | + CAR_TO_CAR("차 대 차") | |
69 | + , CAR_TO_PEOPLE("차 대 사람") | |
70 | + , ROAD_CRACK("도로 크랙") | |
71 | + , ROAD_HOLE("도로 웅덩이"); | |
72 | + | |
73 | + private TrafficAnalysisResultType (String value) { | |
74 | + this.value = value; | |
75 | + } | |
76 | + | |
77 | + /** | |
78 | + * 한글값 | |
79 | + */ | |
80 | + final private String value; | |
81 | + | |
82 | + /** | |
83 | + * 한글값 조회 | |
84 | + */ | |
85 | + public String getValue () { | |
86 | + return value; | |
87 | + } | |
88 | + | |
89 | + /** | |
90 | + * 데이터 수집 타입 목록 조회 | |
91 | + */ | |
92 | + public static Map<TrafficAnalysisResultType, String> getTrafficAnalysisResultTypeList () { | |
93 | + Map<TrafficAnalysisResultType, String> info = new LinkedHashMap<TrafficAnalysisResultType, String>(); | |
94 | + TrafficAnalysisResultType[] array = TrafficAnalysisResultType.values(); | |
95 | + for (int i = 0; i < array.length; i++) { | |
96 | + info.put(array[i], array[i].getValue()); | |
97 | + } | |
98 | + return info; | |
99 | + } | |
100 | + | |
101 | + public static TrafficAnalysisResultType codeToType (String code) { | |
102 | + if (code != null && code.length() > 0) { | |
103 | + if (code.equals("0")) { | |
104 | + return ROAD_CRACK; | |
105 | + } else if (code.equals("1")) { | |
106 | + return ROAD_HOLE; | |
107 | + } else if (code.equals("2")) { | |
108 | + return CAR_TO_CAR; | |
109 | + } else if (code.equals("3")) { | |
110 | + return CAR_TO_PEOPLE; | |
111 | + } else { | |
112 | + return null; | |
113 | + } | |
114 | + } else { | |
115 | + return null; | |
116 | + } | |
117 | + } | |
118 | + } | |
119 | + | |
120 | + /** | |
121 | + * @author 최정우 | |
122 | + * @since 2020.12.24 | |
123 | + * | |
124 | + * OpenAPI의 서비스 타입을 정의한 상수 Class 입니다. | |
125 | + */ | |
126 | + public enum APIType { | |
127 | + REST | |
128 | + , RSS | |
129 | + , SOAP; | |
130 | + | |
131 | + /** | |
132 | + * 데이터 수집 타입 목록 조회 | |
133 | + */ | |
134 | + public static Map<APIType, String> getAPITypeList () { | |
135 | + Map<APIType, String> info = new LinkedHashMap<APIType, String>(); | |
136 | + APIType[] array = APIType.values(); | |
137 | + for (int i = 0; i < array.length; i++) { | |
138 | + info.put(array[i], array[i].toString()); | |
139 | + } | |
140 | + return info; | |
141 | + } | |
142 | + } | |
143 | + | |
144 | + /** | |
145 | + * @author 최정우 | |
146 | + * @since 2020.12.24 | |
147 | + * | |
148 | + * OpenAPI의 데이터 포맷 타입을 정의한 상수 Class 입니다. | |
149 | + */ | |
150 | + public enum APIDataFormatType { | |
151 | + JSON | |
152 | + , XML; | |
153 | + | |
154 | + /** | |
155 | + * 데이터 수집 타입 목록 조회 | |
156 | + */ | |
157 | + public static Map<APIDataFormatType, String> getAPIDataFormatTypeList () { | |
158 | + Map<APIDataFormatType, String> info = new LinkedHashMap<APIDataFormatType, String>(); | |
159 | + APIDataFormatType[] array = APIDataFormatType.values(); | |
160 | + for (int i = 0; i < array.length; i++) { | |
161 | + info.put(array[i], array[i].toString()); | |
162 | + } | |
163 | + return info; | |
164 | + } | |
165 | + } | |
166 | + | |
167 | + /** | |
168 | + * @author 최정우 | |
169 | + * @since 2019.11.13 | |
170 | + * | |
171 | + * 업로드 파일에 대한 저장 폴더 경로를 정의한 상수 Class | |
172 | + * MAIN-메인 저장소, TEMP-임시 저장소 | |
173 | + */ | |
174 | + public enum FileUploadPath { | |
175 | + /* 관리 시스템 파일 업로드 경로 */ | |
176 | + //상대 경로 저장소(프로젝트 내부 -> Windows, Linux 구분 없음) | |
177 | + MAIN_RELATIVE_PATH("\\resources\\common\\file\\upload\\main", "/resources/common/file/upload/main") | |
178 | + , TEMP_RELATIVE_PATH("\\resources\\common\\file\\upload\\temp", "/resources/common/file/upload/temp") | |
179 | + //절대 경로 저장소(Windows, Linux) | |
180 | + , MAIN_ABSOLUTE_PATH("C:\\bigdata\\common\\upload\\main", "/bigdata/common/upload/main") | |
181 | + , TEMP_ABSOLUTE_PATH("C:\\bigdata\\common\\upload\\temp", "/bigdata/common/upload/temp"); | |
182 | + | |
183 | + private FileUploadPath(String windowFileUploadPath, String linuxFileUploadPath) { | |
184 | + this.windowFileUploadPath = windowFileUploadPath; | |
185 | + this.linuxFileUploadPath = linuxFileUploadPath; | |
186 | + } | |
187 | + | |
188 | + final private String windowFileUploadPath; | |
189 | + | |
190 | + final private String linuxFileUploadPath; | |
191 | + | |
192 | + public String getWindowFileUploadPath() { | |
193 | + return windowFileUploadPath; | |
194 | + } | |
195 | + | |
196 | + public String getLinuxFileUploadPath() { | |
197 | + return linuxFileUploadPath; | |
198 | + } | |
199 | + | |
200 | + /** | |
201 | + * OS 타입별 파일 업로드 경로 return | |
202 | + */ | |
203 | + public String getOSFileUploadPath() { | |
204 | + if (System.getProperty("os.name").indexOf("Windows") > -1) { | |
205 | + return windowFileUploadPath; | |
206 | + } else { | |
207 | + return linuxFileUploadPath; | |
208 | + } | |
209 | + } | |
210 | + } | |
211 | + | |
212 | + | |
213 | + /** | |
214 | + * @author 최정우 | |
215 | + * @since 2019.11.13 | |
216 | + * | |
217 | + * 데이터 수집 타입을 정의한 상수 Class 입니다. | |
218 | + */ | |
219 | + public enum CollectionType { | |
220 | + FILE("파일 수집") | |
221 | + , DB("DB연계 수집") | |
222 | + , API("API연계 수집") | |
223 | + , CRAWLING("웹데이터 수집") | |
224 | + , SOCKET("소켓통신 수집"); | |
225 | + | |
226 | + private CollectionType (String value) { | |
227 | + this.value = value; | |
228 | + } | |
229 | + | |
230 | + /** | |
231 | + * 한글값 | |
232 | + */ | |
233 | + final private String value; | |
234 | + | |
235 | + /** | |
236 | + * 한글값 조회 | |
237 | + */ | |
238 | + public String getValue () { | |
239 | + return value; | |
240 | + } | |
241 | + | |
242 | + /** | |
243 | + * 데이터 수집 타입 목록 조회 | |
244 | + */ | |
245 | + public static Map<CollectionType, String> getCollectionTypeList () { | |
246 | + Map<CollectionType, String> info = new LinkedHashMap<CollectionType, String>(); | |
247 | + CollectionType[] array = CollectionType.values(); | |
248 | + for (int i = 0; i < array.length; i++) { | |
249 | + info.put(array[i], array[i].getValue()); | |
250 | + } | |
251 | + return info; | |
252 | + } | |
253 | + } | |
254 | + | |
255 | + /** | |
256 | + * @author 최정우 | |
257 | + * @since 2019.12.03 | |
258 | + * | |
259 | + * 스케줄 작업 상태 타입을 정의한 상수 Class 입니다. | |
260 | + */ | |
261 | + public enum TaskStatus { | |
262 | + START("작동 시작") | |
263 | + , COMPLETE("작동 완료") | |
264 | + , ERROR("작동 오류"); | |
265 | + | |
266 | + private TaskStatus (String message) { | |
267 | + this.message = message; | |
268 | + } | |
269 | + | |
270 | + /** | |
271 | + * 한글 메세지 | |
272 | + */ | |
273 | + final private String message; | |
274 | + | |
275 | + /** | |
276 | + * 한글 메세지 조회 | |
277 | + */ | |
278 | + public String getMessage () { | |
279 | + return message; | |
280 | + } | |
281 | + | |
282 | + /** | |
283 | + * 스케줄 상태 타입 목록 조회 | |
284 | + */ | |
285 | + public static Map<TaskStatus, String> getTaskStatusList () { | |
286 | + Map<TaskStatus, String> info = new LinkedHashMap<TaskStatus, String>(); | |
287 | + TaskStatus[] array = TaskStatus.values(); | |
288 | + for (int i = 0; i < array.length; i++) { | |
289 | + info.put(array[i], array[i].getMessage()); | |
290 | + } | |
291 | + return info; | |
292 | + } | |
293 | + } | |
294 | + | |
295 | + /** | |
296 | + * @author 최정우 | |
297 | + * @since 2019.12.03 | |
298 | + * | |
299 | + * 날짜 통계 관련 타입을 정의한 상수 Class 입니다. | |
300 | + */ | |
301 | + public enum DateStatsGroupType { | |
302 | + DATE_FLOW("시계열") | |
303 | + , DATE_CYCLE("주기별");//통계 데이터 조회 총 행 수: 31(1, 2, 3, ..., 31) | |
304 | + | |
305 | + private DateStatsGroupType (String message) { | |
306 | + this.message = message; | |
307 | + } | |
308 | + | |
309 | + /** | |
310 | + * 한글 메세지 | |
311 | + */ | |
312 | + final private String message; | |
313 | + | |
314 | + /** | |
315 | + * 한글 메세지 조회 | |
316 | + */ | |
317 | + public String getMessage () { | |
318 | + return message; | |
319 | + } | |
320 | + | |
321 | + /** | |
322 | + * 날짜 통계 관련 타입 목록 조회 | |
323 | + */ | |
324 | + public static Map<DateStatsGroupType, String> getDateStatusType () { | |
325 | + Map<DateStatsGroupType, String> info = new LinkedHashMap<DateStatsGroupType, String>(); | |
326 | + DateStatsGroupType[] array = DateStatsGroupType.values(); | |
327 | + for (int i = 0; i < array.length; i++) { | |
328 | + info.put(array[i], array[i].getMessage()); | |
329 | + } | |
330 | + return info; | |
331 | + } | |
332 | + } | |
333 | + /** | |
334 | + * @author 최정우 | |
335 | + * @since 2019.12.03 | |
336 | + * | |
337 | + * 날짜 통계 관련 타입을 정의한 상수 Class 입니다. | |
338 | + */ | |
339 | + public enum DateStatsType { | |
340 | + YEAR("년도별(시계열)")//시계열도 되고 주기도됨 (최상위 Date이기 때문) | |
341 | + | |
342 | + , DATE_FLOW_QUARTER("분기별(시계열)") | |
343 | + , DATE_FLOW_MONTH("월별(시계열)") | |
344 | + , DATE_FLOW_WEEK("주별(시계열)") | |
345 | + , DATE_FLOW_DAY("일별(시계열)") | |
346 | + | |
347 | + , DATE_CYCLE_QUARTER("분기별(주기별)")//통계 데이터 조회 총 행 수: 4(1분기, 2분기, 3분기, 4분기) | |
348 | + , DATE_CYCLE_MONTH("월별(주기별)")//통계 데이터 조회 총 행 수: 12(1월, 2월, 3월, ..., 12월) | |
349 | + , DATE_CYCLE_WEEK("요일별(주기별)")//통계 데이터 조회 총 행 수: 7(월, 화, 수, ..., 일) | |
350 | + , DATE_CYCLE_DAY("일별(주기별)")//통계 데이터 조회 총 행 수: 31(1, 2, 3, ..., 31) | |
351 | + , DATE_CYCLE_TIME("시간별(주기별)");//통계 데이터 조회 총 행 수: 31(1, 2, 3, ..., 31) | |
352 | + | |
353 | + private DateStatsType (String message) { | |
354 | + this.message = message; | |
355 | + } | |
356 | + | |
357 | + /** | |
358 | + * 한글 메세지 | |
359 | + */ | |
360 | + final private String message; | |
361 | + | |
362 | + /** | |
363 | + * 한글 메세지 조회 | |
364 | + */ | |
365 | + public String getMessage () { | |
366 | + return message; | |
367 | + } | |
368 | + | |
369 | + /** | |
370 | + * 날짜 통계 관련 타입 목록 조회 | |
371 | + */ | |
372 | + public static Map<DateStatsType, String> getDateStatusType () { | |
373 | + Map<DateStatsType, String> info = new LinkedHashMap<DateStatsType, String>(); | |
374 | + DateStatsType[] array = DateStatsType.values(); | |
375 | + for (int i = 0; i < array.length; i++) { | |
376 | + info.put(array[i], array[i].getMessage()); | |
377 | + } | |
378 | + return info; | |
379 | + } | |
380 | + } | |
381 | + | |
382 | + | |
383 | +} |
+++ src/back-end/main/java/common/vo/User.java
... | ... | @@ -0,0 +1,222 @@ |
1 | +package common.vo; | |
2 | + | |
3 | +import java.util.ArrayList; | |
4 | +import java.util.List; | |
5 | + | |
6 | +/** | |
7 | + * @author 최정우 | |
8 | + * @since 2021.12.06 | |
9 | + * | |
10 | + * 회원 정보 VO입니다. | |
11 | + */ | |
12 | +public class User extends Org { | |
13 | + | |
14 | + /** | |
15 | + * 유니크 아이디 | |
16 | + */ | |
17 | + private String userId; | |
18 | + | |
19 | + /** | |
20 | + * 로그인 아이디 | |
21 | + */ | |
22 | + private String loginId; | |
23 | + | |
24 | + /** | |
25 | + * 패스워드 | |
26 | + */ | |
27 | + private String password; | |
28 | + | |
29 | + /** | |
30 | + * 회원명 | |
31 | + */ | |
32 | + private String name; | |
33 | + | |
34 | + /** | |
35 | + * 생년월일 | |
36 | + */ | |
37 | + private String birthDate; | |
38 | + | |
39 | + /** | |
40 | + * 휴대전화 | |
41 | + */ | |
42 | + private String mobile; | |
43 | + | |
44 | + /** | |
45 | + * 이메일 | |
46 | + */ | |
47 | + private String email; | |
48 | + | |
49 | + /** | |
50 | + * 성별 | |
51 | + */ | |
52 | + private String gender; | |
53 | + | |
54 | + /** | |
55 | + * 주소 | |
56 | + */ | |
57 | + private String address; | |
58 | + | |
59 | + /** | |
60 | + * 상세주소 | |
61 | + */ | |
62 | + private String detailAddress; | |
63 | + | |
64 | + /** | |
65 | + * 회원가입일시 | |
66 | + */ | |
67 | + private String registrationDatetime; | |
68 | + | |
69 | + /** | |
70 | + * 탈퇴일시 | |
71 | + */ | |
72 | + private String withdrawDatetime; | |
73 | + | |
74 | + /** | |
75 | + * 탈퇴여부 | |
76 | + */ | |
77 | + private boolean isWithdraw; | |
78 | + | |
79 | + /** | |
80 | + * 로그인 실패 횟수 | |
81 | + */ | |
82 | + private int loginFailedCount; | |
83 | + | |
84 | + /** | |
85 | + * 로그인 잠금 여부 | |
86 | + */ | |
87 | + private boolean isAccountLock; | |
88 | + | |
89 | + | |
90 | + /** | |
91 | + * 회원의 권한's | |
92 | + */ | |
93 | + private List<String> userAuthotities = new ArrayList<String>(); | |
94 | + | |
95 | + public String getUserId() { | |
96 | + return userId; | |
97 | + } | |
98 | + | |
99 | + public void setUserId(String userId) { | |
100 | + this.userId = userId; | |
101 | + } | |
102 | + | |
103 | + public String getLoginId() { | |
104 | + return loginId; | |
105 | + } | |
106 | + | |
107 | + public void setLoginId(String loginId) { | |
108 | + this.loginId = loginId; | |
109 | + } | |
110 | + | |
111 | + public String getPassword() { | |
112 | + return password; | |
113 | + } | |
114 | + | |
115 | + public void setPassword(String password) { | |
116 | + this.password = password; | |
117 | + } | |
118 | + | |
119 | + public String getName() { | |
120 | + return name; | |
121 | + } | |
122 | + | |
123 | + public void setName(String name) { | |
124 | + this.name = name; | |
125 | + } | |
126 | + | |
127 | + public String getBirthDate() { | |
128 | + return birthDate; | |
129 | + } | |
130 | + | |
131 | + public void setBirthDate(String birthDate) { | |
132 | + this.birthDate = birthDate; | |
133 | + } | |
134 | + | |
135 | + public String getMobile() { | |
136 | + return mobile; | |
137 | + } | |
138 | + | |
139 | + public void setMobile(String mobile) { | |
140 | + this.mobile = mobile; | |
141 | + } | |
142 | + | |
143 | + public String getEmail() { | |
144 | + return email; | |
145 | + } | |
146 | + | |
147 | + public void setEmail(String email) { | |
148 | + this.email = email; | |
149 | + } | |
150 | + | |
151 | + public String getGender() { | |
152 | + return gender; | |
153 | + } | |
154 | + | |
155 | + public void setGender(String gender) { | |
156 | + this.gender = gender; | |
157 | + } | |
158 | + | |
159 | + public String getAddress() { | |
160 | + return address; | |
161 | + } | |
162 | + | |
163 | + public void setAddress(String address) { | |
164 | + this.address = address; | |
165 | + } | |
166 | + | |
167 | + public String getDetailAddress() { | |
168 | + return detailAddress; | |
169 | + } | |
170 | + | |
171 | + public void setDetailAddress(String detailAddress) { | |
172 | + this.detailAddress = detailAddress; | |
173 | + } | |
174 | + | |
175 | + public String getRegistrationDatetime() { | |
176 | + return registrationDatetime; | |
177 | + } | |
178 | + | |
179 | + public void setRegistrationDatetime(String registrationDatetime) { | |
180 | + this.registrationDatetime = registrationDatetime; | |
181 | + } | |
182 | + | |
183 | + public String getWithdrawDatetime() { | |
184 | + return withdrawDatetime; | |
185 | + } | |
186 | + | |
187 | + public void setWithdrawDatetime(String withdrawDatetime) { | |
188 | + this.withdrawDatetime = withdrawDatetime; | |
189 | + } | |
190 | + | |
191 | + public boolean getIsWithdraw() { | |
192 | + return isWithdraw; | |
193 | + } | |
194 | + | |
195 | + public void setIsWithdraw(boolean withdraw) { | |
196 | + isWithdraw = withdraw; | |
197 | + } | |
198 | + | |
199 | + public int getLoginFailedCount() { | |
200 | + return loginFailedCount; | |
201 | + } | |
202 | + | |
203 | + public void setLoginFailedCount(int loginFailedCount) { | |
204 | + this.loginFailedCount = loginFailedCount; | |
205 | + } | |
206 | + | |
207 | + public boolean getIsAccountLock() { | |
208 | + return isAccountLock; | |
209 | + } | |
210 | + | |
211 | + public void setIsAccountLock(boolean accountLock) { | |
212 | + isAccountLock = accountLock; | |
213 | + } | |
214 | + | |
215 | + public List<String> getUserAuthotities() { | |
216 | + return userAuthotities; | |
217 | + } | |
218 | + | |
219 | + public void setUserAuthotities(List<String> userAuthotities) { | |
220 | + this.userAuthotities = userAuthotities; | |
221 | + } | |
222 | +} |
+++ src/back-end/main/java/kr/co/takensoft/projectName/common/dao/CommonDAO.java
... | ... | @@ -0,0 +1,16 @@ |
1 | +package kr.co.takensoft.projectName.common.dao; | |
2 | + | |
3 | + | |
4 | +import org.apache.ibatis.annotations.Mapper; | |
5 | + | |
6 | +/** | |
7 | + * Common DAO 입니다. | |
8 | + * | |
9 | + * @author 최정우 | |
10 | + * @since 2022.09.01 | |
11 | + */ | |
12 | +//@Repository <-- Class 객체로 생성 해야 됨 | |
13 | +@Mapper | |
14 | +public interface CommonDAO { | |
15 | + | |
16 | +} |
+++ src/back-end/main/java/kr/co/takensoft/projectName/common/service/CommonService.java
... | ... | @@ -0,0 +1,11 @@ |
1 | +package kr.co.takensoft.projectName.common.service; | |
2 | + | |
3 | +/** | |
4 | + * Common 서비스 로직 Interface 입니다. | |
5 | + * | |
6 | + * @author 최정우 | |
7 | + * @since 2022.09.01 | |
8 | + */ | |
9 | +public interface CommonService { | |
10 | + | |
11 | +} |
+++ src/back-end/main/java/kr/co/takensoft/projectName/common/service/impl/CommonServiceImpl.java
... | ... | @@ -0,0 +1,25 @@ |
1 | +package kr.co.takensoft.projectName.common.service.impl; | |
2 | + | |
3 | +import com.fasterxml.jackson.databind.ObjectMapper; | |
4 | +import kr.co.takensoft.projectName.common.dao.CommonDAO; | |
5 | +import kr.co.takensoft.projectName.common.service.CommonService; | |
6 | +import org.springframework.beans.factory.annotation.Autowired; | |
7 | +import org.springframework.stereotype.Service; | |
8 | + | |
9 | +/** | |
10 | + * Common 서비스 로직 Class 객체 입니다. | |
11 | + * | |
12 | + * @author 최정우 | |
13 | + * @since 2022.09.01 | |
14 | + */ | |
15 | +@Service | |
16 | +public class CommonServiceImpl implements CommonService { | |
17 | + | |
18 | + @Autowired | |
19 | + private ObjectMapper objectMapper; | |
20 | + | |
21 | + @Autowired | |
22 | + private CommonDAO commonDAO; | |
23 | + | |
24 | + | |
25 | +} |
+++ src/back-end/main/java/kr/co/takensoft/projectName/common/web/CommonConroller.java
... | ... | @@ -0,0 +1,30 @@ |
1 | +package kr.co.takensoft.projectName.common.web; | |
2 | + | |
3 | +import com.fasterxml.jackson.databind.ObjectMapper; | |
4 | +import kr.co.takensoft.projectName.common.service.CommonService; | |
5 | +import org.springframework.beans.factory.annotation.Autowired; | |
6 | +import org.springframework.stereotype.Controller; | |
7 | +import org.springframework.web.bind.annotation.RequestMapping; | |
8 | +import org.springframework.web.servlet.ModelAndView; | |
9 | + | |
10 | +/** | |
11 | + * Common Controller 입니다. | |
12 | + * | |
13 | + * @author 최정우 | |
14 | + * @since 2022.09.01 | |
15 | + */ | |
16 | +@Controller | |
17 | +public class CommonConroller { | |
18 | + | |
19 | + @Autowired | |
20 | + private ObjectMapper objectMapper; | |
21 | + | |
22 | + @Autowired | |
23 | + private CommonService commonService; | |
24 | + | |
25 | + | |
26 | + @RequestMapping(value = "/") | |
27 | + public String main () { | |
28 | + return "redirect:/views/index.html"; | |
29 | + } | |
30 | +} |
+++ src/back-end/main/java/kr/co/takensoft/projectName/test/dao/TestDAO.java
... | ... | @@ -0,0 +1,26 @@ |
1 | +package kr.co.takensoft.projectName.test.dao; | |
2 | + | |
3 | + | |
4 | +import kr.co.takensoft.projectName.test.vo.Test; | |
5 | +import org.apache.ibatis.annotations.Mapper; | |
6 | + | |
7 | +import java.util.List; | |
8 | + | |
9 | +/** | |
10 | + * 테스트용 DAO 입니다. | |
11 | + * | |
12 | + * @author 최정우 | |
13 | + * @since 2022.09.01 | |
14 | + */ | |
15 | +//@Repository <-- Class 객체로 생성 해야 됨 | |
16 | +@Mapper | |
17 | +public interface TestDAO { | |
18 | + | |
19 | + /** | |
20 | + * 데이터 조회 테스트 | |
21 | + * | |
22 | + * @author 최정우 | |
23 | + * @since 2022.09.01 | |
24 | + */ | |
25 | + public List<Test> testDataSelectList (Test test) throws Exception; | |
26 | +} |
+++ src/back-end/main/java/kr/co/takensoft/projectName/test/service/TestService.java
... | ... | @@ -0,0 +1,19 @@ |
1 | +package kr.co.takensoft.projectName.test.service; | |
2 | + | |
3 | +import kr.co.takensoft.projectName.test.vo.Test; | |
4 | + | |
5 | +import java.util.List; | |
6 | + | |
7 | + | |
8 | +public interface TestService { | |
9 | + | |
10 | + | |
11 | + /** | |
12 | + * 데이터 조회 테스트 | |
13 | + * | |
14 | + * @author 최정우 | |
15 | + * @since 2022.09.01 | |
16 | + */ | |
17 | + public List<Test> testDataSelectList (Test test) throws Exception; | |
18 | + | |
19 | +} |
+++ src/back-end/main/java/kr/co/takensoft/projectName/test/service/impl/TestServiceImpl.java
... | ... | @@ -0,0 +1,33 @@ |
1 | +package kr.co.takensoft.projectName.test.service.impl; | |
2 | + | |
3 | +import kr.co.takensoft.projectName.test.dao.TestDAO; | |
4 | +import kr.co.takensoft.projectName.test.service.TestService; | |
5 | +import kr.co.takensoft.projectName.test.vo.Test; | |
6 | +import org.springframework.beans.factory.annotation.Autowired; | |
7 | +import org.springframework.stereotype.Service; | |
8 | + | |
9 | +import java.util.List; | |
10 | + | |
11 | +/** | |
12 | + * 테스트용 서비스 로직 Class 객체 입니다. | |
13 | + * | |
14 | + * @author 최정우 | |
15 | + * @since 2022.09.01 | |
16 | + */ | |
17 | +@Service | |
18 | +public class TestServiceImpl implements TestService { | |
19 | + | |
20 | + @Autowired | |
21 | + private TestDAO testDao; | |
22 | + | |
23 | + /** | |
24 | + * 데이터 조회 테스트 | |
25 | + * | |
26 | + * @author 최정우 | |
27 | + * @since 2022.09.01 | |
28 | + */ | |
29 | + @Override | |
30 | + public List<Test> testDataSelectList(Test test) throws Exception { | |
31 | + return testDao.testDataSelectList(test); | |
32 | + } | |
33 | +} |
+++ src/back-end/main/java/kr/co/takensoft/projectName/test/vo/Test.java
... | ... | @@ -0,0 +1,54 @@ |
1 | +package kr.co.takensoft.projectName.test.vo; | |
2 | + | |
3 | +public class Test { | |
4 | + | |
5 | + private long testId; | |
6 | + | |
7 | + private String title; | |
8 | + | |
9 | + private String content; | |
10 | + | |
11 | + private String createUserId; | |
12 | + | |
13 | + private String createDatetime; | |
14 | + | |
15 | + public long getTestId() { | |
16 | + return testId; | |
17 | + } | |
18 | + | |
19 | + public void setTestId(long testId) { | |
20 | + this.testId = testId; | |
21 | + } | |
22 | + | |
23 | + public String getContent() { | |
24 | + return content; | |
25 | + } | |
26 | + | |
27 | + public void setContent(String content) { | |
28 | + this.content = content; | |
29 | + } | |
30 | + | |
31 | + public String getCreateUserId() { | |
32 | + return createUserId; | |
33 | + } | |
34 | + | |
35 | + public void setCreateUserId(String createUserId) { | |
36 | + this.createUserId = createUserId; | |
37 | + } | |
38 | + | |
39 | + public String getCreateDatetime() { | |
40 | + return createDatetime; | |
41 | + } | |
42 | + | |
43 | + public void setCreateDatetime(String createDatetime) { | |
44 | + this.createDatetime = createDatetime; | |
45 | + } | |
46 | + | |
47 | + public String getTitle() { | |
48 | + return title; | |
49 | + } | |
50 | + | |
51 | + public void setTitle(String title) { | |
52 | + this.title = title; | |
53 | + } | |
54 | +} |
+++ src/back-end/main/java/kr/co/takensoft/projectName/test/web/TestConroller.java
... | ... | @@ -0,0 +1,106 @@ |
1 | +package kr.co.takensoft.projectName.test.web; | |
2 | + | |
3 | +import com.fasterxml.jackson.databind.ObjectMapper; | |
4 | +import kr.co.takensoft.projectName.test.service.TestService; | |
5 | +import kr.co.takensoft.projectName.test.vo.Test; | |
6 | +import org.springframework.beans.factory.annotation.Autowired; | |
7 | +import org.springframework.stereotype.Controller; | |
8 | +import org.springframework.web.bind.annotation.RequestBody; | |
9 | +import org.springframework.web.bind.annotation.RequestMapping; | |
10 | +import org.springframework.web.bind.annotation.RequestParam; | |
11 | +import org.springframework.web.multipart.MultipartFile; | |
12 | +import org.springframework.web.multipart.MultipartHttpServletRequest; | |
13 | +import org.springframework.web.servlet.ModelAndView; | |
14 | + | |
15 | +import javax.servlet.http.HttpServletRequest; | |
16 | +import java.util.HashMap; | |
17 | +import java.util.Iterator; | |
18 | + | |
19 | +/** | |
20 | + * 테스트용 Controller 입니다. | |
21 | + * | |
22 | + * @author 최정우 | |
23 | + * @since 2022.09.01 | |
24 | + */ | |
25 | +@Controller | |
26 | +public class TestConroller { | |
27 | + | |
28 | + @Autowired | |
29 | + private ObjectMapper objectMapper; | |
30 | + | |
31 | + @Autowired | |
32 | + private TestService testService; | |
33 | + | |
34 | + /** | |
35 | + * 데이터 조회 테스트 | |
36 | + * | |
37 | + * @author 최정우 | |
38 | + * @since 2022.09.01 | |
39 | + */ | |
40 | + @RequestMapping(value = "/testDataSelectList") | |
41 | + public ModelAndView testDataSelectList (@RequestParam HashMap<String, Object> param) throws Exception { | |
42 | + ModelAndView mav = new ModelAndView("jsonView"); | |
43 | + if (param != null && param.size() > 0) { | |
44 | + System.out.println("testDataSelectList param : " + objectMapper.writeValueAsString(param)); | |
45 | + } | |
46 | + Test test = new Test(); | |
47 | + mav.addObject("result", testService.testDataSelectList(test)); | |
48 | + return mav; | |
49 | + } | |
50 | + | |
51 | + /** | |
52 | + * @RequestParam HashMap<String, Object> param Test | |
53 | + * GET 방식의 URL Query 데이터 가능 | |
54 | + * POST 방식의 Body FormData 데이터 가능 | |
55 | + * | |
56 | + * @author 최정우 | |
57 | + * @since 2022.08.31 | |
58 | + */ | |
59 | + @RequestMapping(value = "/jsonTestForRequestParam") | |
60 | + public ModelAndView jsonTestForRequestParam (@RequestParam HashMap<String, Object> param) throws Exception { | |
61 | + if (param != null && param.size() > 0) { | |
62 | + System.out.println("jsonTestForRequestParam param : " + objectMapper.writeValueAsString(param)); | |
63 | + } | |
64 | + ModelAndView mav = new ModelAndView("jsonView"); | |
65 | + mav.addObject("result", param); | |
66 | + return mav; | |
67 | + } | |
68 | + | |
69 | + @RequestMapping(value = "/jsonTestForRequestBody") | |
70 | + public ModelAndView jsonTestForRequestBody (@RequestBody HashMap<String, Object> param) throws Exception { | |
71 | + if (param != null && param.size() > 0) { | |
72 | + System.out.println("jsonTestForRequestBody param : " + objectMapper.writeValueAsString(param)); | |
73 | + } | |
74 | + ModelAndView mav = new ModelAndView("jsonView"); | |
75 | + mav.addObject("result", param); | |
76 | + return mav; | |
77 | + } | |
78 | + | |
79 | + @RequestMapping(value = "/jsonTestForMultipart") | |
80 | + public ModelAndView jsonTestForMultipart (HttpServletRequest request, @RequestParam(required = false) HashMap<String, Object> param) throws Exception { | |
81 | + if (param != null && param.size() > 0) { | |
82 | + System.out.println("jsonTestForMultipart param : " + objectMapper.writeValueAsString(param)); | |
83 | + } | |
84 | + | |
85 | + try { | |
86 | + MultipartHttpServletRequest multipart = (MultipartHttpServletRequest) request; | |
87 | + Iterator<String> itr = multipart.getFileNames(); | |
88 | + | |
89 | + int index = 1; | |
90 | + while (itr.hasNext()) { | |
91 | + MultipartFile multipartFile = multipart.getFile(itr.next()); | |
92 | + System.out.println("File " + index + ". " + multipartFile.getOriginalFilename() + " (" + multipartFile.getSize() + ")"); | |
93 | + } | |
94 | + } catch (Exception e) { | |
95 | + System.out.println(""); | |
96 | + System.err.println("Mutipart Error 발생"); | |
97 | + e.printStackTrace(); | |
98 | + | |
99 | + } | |
100 | + | |
101 | + | |
102 | + ModelAndView mav = new ModelAndView("jsonView"); | |
103 | + mav.addObject("result", param); | |
104 | + return mav; | |
105 | + } | |
106 | +} |
+++ src/back-end/main/java/spring/SpringStarter.java
... | ... | @@ -0,0 +1,52 @@ |
1 | +package spring; | |
2 | + | |
3 | +import org.springframework.web.WebApplicationInitializer; | |
4 | +import org.springframework.web.context.ContextLoaderListener; | |
5 | +import org.springframework.web.context.support.AnnotationConfigWebApplicationContext; | |
6 | +import org.springframework.web.filter.CharacterEncodingFilter; | |
7 | +import org.springframework.web.servlet.DispatcherServlet; | |
8 | +import javax.servlet.FilterRegistration; | |
9 | +import javax.servlet.ServletContext; | |
10 | +import javax.servlet.ServletException; | |
11 | +import javax.servlet.ServletRegistration; | |
12 | + | |
13 | +/** | |
14 | + * SpringFramework Context 구동 Class | |
15 | + * | |
16 | + * @author 최정우 | |
17 | + * @since 2022.08.31 | |
18 | + */ | |
19 | +public class SpringStarter implements WebApplicationInitializer { | |
20 | + | |
21 | + /** | |
22 | + * SpringFramework Context 구동 시, 동작하는 이벤트 기능 (web.xml의 기능을 대체함) | |
23 | + * | |
24 | + * @author 최정우 | |
25 | + * @since 2022.08.31 | |
26 | + */ | |
27 | + @Override | |
28 | + public void onStartup(ServletContext servletContext) throws ServletException { | |
29 | + | |
30 | + AnnotationConfigWebApplicationContext rootContext = new AnnotationConfigWebApplicationContext(); | |
31 | + rootContext.register( | |
32 | + spring.config.RootContextConfig.class,//Root Context | |
33 | + spring.config.DataSourceContextConfig.class,//DataSource Context | |
34 | + spring.config.MybatisContextConfig.class//Mybatis Context | |
35 | + ); | |
36 | + servletContext.addListener(new ContextLoaderListener(rootContext)); | |
37 | + | |
38 | + // Web(Servlet) Context | |
39 | + AnnotationConfigWebApplicationContext dispatcherContext = new AnnotationConfigWebApplicationContext(); | |
40 | + dispatcherContext.register(spring.config.servlet.WebContextConfig.class); | |
41 | + | |
42 | + // Dispatcher Servlet | |
43 | + ServletRegistration.Dynamic dispatcher = servletContext.addServlet("dispatcher", new DispatcherServlet(dispatcherContext)); | |
44 | + dispatcher.setLoadOnStartup(1); | |
45 | + dispatcher.addMapping("/"); | |
46 | + | |
47 | + // Filter | |
48 | + FilterRegistration.Dynamic filter = servletContext.addFilter("encodingFilter", CharacterEncodingFilter.class); | |
49 | + filter.setInitParameter("encoding","utf-8"); | |
50 | + filter.addMappingForServletNames(null,false,"dispatcher"); | |
51 | + } | |
52 | +}(No newline at end of file) |
+++ src/back-end/main/java/spring/config/DataSourceContextConfig.java
... | ... | @@ -0,0 +1,46 @@ |
1 | +package spring.config; | |
2 | + | |
3 | +import com.zaxxer.hikari.HikariConfig; | |
4 | +import com.zaxxer.hikari.HikariDataSource; | |
5 | +import org.springframework.context.annotation.Bean; | |
6 | +import org.springframework.context.annotation.Configuration; | |
7 | + | |
8 | +/** | |
9 | + * DB Connection 자원 관련 Bean 설정 Class | |
10 | + * DBCP: HikariCP | |
11 | + * JDBC: MariaDB or PostgreSQL | |
12 | + * | |
13 | + * @author 최정우 | |
14 | + * @since 2022.09.01 | |
15 | + */ | |
16 | +@Configuration | |
17 | +public class DataSourceContextConfig { | |
18 | + | |
19 | + /** | |
20 | + * HikariCP(DBCP) Config(설정 세팅) 객체 Bean 설정 | |
21 | + * | |
22 | + * @author 최정우 | |
23 | + * @since 2022.09.01 | |
24 | + */ | |
25 | + @Bean(name = "mainHikariConfig") | |
26 | + public HikariConfig getMainHikariConfig () { | |
27 | + HikariConfig hikariConfig = new HikariConfig(); | |
28 | + hikariConfig.setDriverClassName("org.mariadb.jdbc.Driver"); | |
29 | + hikariConfig.setJdbcUrl("jdbc:mariadb://localhost:3306/test"); | |
30 | + hikariConfig.setUsername("root"); | |
31 | + hikariConfig.setPassword("1234"); | |
32 | + return hikariConfig; | |
33 | + } | |
34 | + | |
35 | + /** | |
36 | + * HikariCP(DBCP) 객체 Bean 설정 | |
37 | + * | |
38 | + * @author 최정우 | |
39 | + * @since 2022.09.01 | |
40 | + */ | |
41 | + @Bean(name = "mainHikariDataSource") | |
42 | + public HikariDataSource getMainHikariDataSource () { | |
43 | + HikariDataSource hikariDataSource = new HikariDataSource(getMainHikariConfig()); | |
44 | + return hikariDataSource; | |
45 | + } | |
46 | +} |
+++ src/back-end/main/java/spring/config/MybatisContextConfig.java
... | ... | @@ -0,0 +1,95 @@ |
1 | +package spring.config; | |
2 | + | |
3 | +import com.zaxxer.hikari.HikariDataSource; | |
4 | +import common.util.bean.BeanUtil; | |
5 | +import org.apache.ibatis.session.ExecutorType; | |
6 | +import org.apache.ibatis.session.SqlSessionFactory; | |
7 | +import org.apache.ibatis.type.TypeAliasRegistry; | |
8 | +import org.mybatis.spring.SqlSessionFactoryBean; | |
9 | +import org.mybatis.spring.SqlSessionTemplate; | |
10 | +import org.mybatis.spring.mapper.MapperScannerConfigurer; | |
11 | +import org.springframework.context.ApplicationContext; | |
12 | +import org.springframework.context.annotation.Bean; | |
13 | +import org.springframework.context.annotation.Configuration; | |
14 | + | |
15 | +/** | |
16 | + * Mybatis 관련 Bean 설정 Class | |
17 | + * | |
18 | + * @author 최정우 | |
19 | + * @since 2022.09.01 | |
20 | + */ | |
21 | +@Configuration | |
22 | +//@MapperScan(basePackages = {"kr.co.takensoft"}) <-- 이거 대신 mainMapperScannerConfigurer bean 등록 | |
23 | +public class MybatisContextConfig { | |
24 | + | |
25 | + //Mybatis 동작 설정 | |
26 | + //mybatis-config.xml 작성 대신 Class 활용 | |
27 | + private class Configuration extends org.apache.ibatis.session.Configuration { | |
28 | + private Configuration() { | |
29 | + super(); | |
30 | + super.setCacheEnabled(true);//mapper 캐시 전역 사용여부 | |
31 | + super.setLazyLoadingEnabled(false);//mybatis 지연 로딩 사용여부 | |
32 | + super.setMultipleResultSetsEnabled(true);//한개의 구문에서 여러개의 ResultSet 허용 여부 | |
33 | + super.setUseColumnLabel(true);//컬럼명 대신 컬럼라벨 사용 여부 | |
34 | + super.setUseGeneratedKeys(false);//키 자동 생성 | |
35 | + super.setDefaultExecutorType(ExecutorType.SIMPLE); | |
36 | + super.setDefaultStatementTimeout(25000); | |
37 | + super.setCallSettersOnNulls(true);//조회 조회시, null값 무조건 허용 | |
38 | + | |
39 | + //Mybatis SQL 작성시, 자주 활용하는 Class 별칭 세팅 | |
40 | + TypeAliasRegistry typeAliasRegistry = super.getTypeAliasRegistry(); | |
41 | + typeAliasRegistry.registerAlias("Test", kr.co.takensoft.projectName.test.vo.Test.class); | |
42 | + } | |
43 | + } | |
44 | + //Mybatis 동작 설정 객체 생성 | |
45 | + private Configuration configuration = new Configuration(); | |
46 | + | |
47 | + /** | |
48 | + * Main | |
49 | + * Mapper : SQL이 작성된 문서와, 작성된 SQL을 실행시킬 class(Mapper)를 매핑 시켜주기 위한 객체 Been 설정 (Main) | |
50 | + * | |
51 | + * @author 최정우 | |
52 | + * @since 2022.09.01 | |
53 | + */ | |
54 | + @Bean(name = "mainMapperScannerConfigurer") | |
55 | + public MapperScannerConfigurer getMainMapperScannerConfigurer () { | |
56 | + MapperScannerConfigurer mapperScannerConfigurer = null; | |
57 | + mapperScannerConfigurer = new MapperScannerConfigurer(); | |
58 | + mapperScannerConfigurer.setBasePackage("kr.co.takensoft"); | |
59 | + mapperScannerConfigurer.setAnnotationClass(org.apache.ibatis.annotations.Mapper.class);//Annotation을 지정해 줘야 service interface 를 Mapper라고 인식하지 않음 | |
60 | + mapperScannerConfigurer.setSqlSessionTemplateBeanName("mainSqlSessionTemplate"); | |
61 | + return mapperScannerConfigurer; | |
62 | + } | |
63 | + | |
64 | + /** | |
65 | + * Main | |
66 | + * Mybatis SqlSessionFactory Bean 설정 | |
67 | + * | |
68 | + * @author 최정우 | |
69 | + * @since 2022.09.01 | |
70 | + */ | |
71 | + @Bean(name = "mainSqlSessionFactory") | |
72 | + public SqlSessionFactory getMainSqlSessionFactory (ApplicationContext applicationContext) throws Exception { | |
73 | + SqlSessionFactoryBean sqlSessionFactoryBean = new SqlSessionFactoryBean(); | |
74 | + sqlSessionFactoryBean.setDataSource((HikariDataSource) BeanUtil.getBean("mainHikariDataSource")); | |
75 | + sqlSessionFactoryBean.setConfiguration(this.configuration); | |
76 | + sqlSessionFactoryBean.setMapperLocations(applicationContext.getResources("classpath:mybatis/main/*-SQL.xml")); | |
77 | + return sqlSessionFactoryBean.getObject(); | |
78 | + } | |
79 | + | |
80 | + /** | |
81 | + * Main | |
82 | + * Mybatis SqlSessionTemplate Bean 설정 | |
83 | + * | |
84 | + * @author 최정우 | |
85 | + * @since 2022.09.01 | |
86 | + */ | |
87 | + @Bean(name = "mainSqlSessionTemplate") | |
88 | + public SqlSessionTemplate getMainSqlSessionTemplate (ApplicationContext applicationContext) throws Exception { | |
89 | + SqlSessionTemplate sqlSessionTemplate = new SqlSessionTemplate(getMainSqlSessionFactory(applicationContext)); | |
90 | + return sqlSessionTemplate; | |
91 | + } | |
92 | + | |
93 | + | |
94 | + | |
95 | +} |
+++ src/back-end/main/java/spring/config/RootContextConfig.java
... | ... | @@ -0,0 +1,55 @@ |
1 | +package spring.config; | |
2 | + | |
3 | +import com.fasterxml.jackson.databind.ObjectMapper; | |
4 | +import com.fasterxml.jackson.databind.SerializationFeature; | |
5 | +import org.springframework.context.annotation.Bean; | |
6 | +import org.springframework.context.annotation.Configuration; | |
7 | +import common.util.bean.ApplicationContextProvider; | |
8 | + | |
9 | +import java.text.SimpleDateFormat; | |
10 | +import java.util.TimeZone; | |
11 | + | |
12 | +/** | |
13 | + * 현 프로젝트의 Global 자원 관련 Bean 설정 Class | |
14 | + * | |
15 | + * @author 최정우 | |
16 | + * @since 2022.08.31 | |
17 | + */ | |
18 | +@Configuration | |
19 | +public class RootContextConfig { | |
20 | + | |
21 | + /** | |
22 | + * Spring Application Context 객체 Bean 설정 | |
23 | + * | |
24 | + * @author 최정우 | |
25 | + * @since 2022.08.31 | |
26 | + */ | |
27 | + @Bean(name = "applicationContextProvider") | |
28 | + public ApplicationContextProvider getApplicationContextProvider () { | |
29 | + ApplicationContextProvider applicationContextProvider = new ApplicationContextProvider(); | |
30 | + return applicationContextProvider; | |
31 | + } | |
32 | + | |
33 | + /** | |
34 | + * JSON Parser 라이브러리 Class Bean 설정 | |
35 | + * | |
36 | + * @author 최정우 | |
37 | + * @since 2022.08.31 | |
38 | + */ | |
39 | + @Bean(name = "objectMapper") | |
40 | + public ObjectMapper getObjectMapper() { | |
41 | + ObjectMapper mapper = new ObjectMapper(); | |
42 | + | |
43 | + //기본 날짜 포맷 비활성화 | |
44 | + mapper.disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS); | |
45 | + | |
46 | + //새로운 날짜 포맷 세팅 | |
47 | + SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); | |
48 | + mapper.setDateFormat(dateFormat); | |
49 | + mapper.setTimeZone(TimeZone.getTimeZone("Asia/Seoul")); | |
50 | + | |
51 | + return mapper; | |
52 | + } | |
53 | + | |
54 | + | |
55 | +} |
+++ src/back-end/main/java/spring/config/servlet/WebContextConfig.java
... | ... | @@ -0,0 +1,110 @@ |
1 | +package spring.config.servlet; | |
2 | + | |
3 | +import com.fasterxml.jackson.databind.ObjectMapper; | |
4 | +import org.springframework.beans.factory.annotation.Autowired; | |
5 | +import org.springframework.context.annotation.Bean; | |
6 | +import org.springframework.context.annotation.ComponentScan; | |
7 | +import org.springframework.context.annotation.Configuration; | |
8 | +import org.springframework.web.multipart.commons.CommonsMultipartResolver; | |
9 | +import org.springframework.web.servlet.ViewResolver; | |
10 | +import org.springframework.web.servlet.config.annotation.EnableWebMvc; | |
11 | +import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry; | |
12 | +import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; | |
13 | +import org.springframework.web.servlet.view.BeanNameViewResolver; | |
14 | +import org.springframework.web.servlet.view.InternalResourceViewResolver; | |
15 | +import org.springframework.web.servlet.view.json.MappingJackson2JsonView; | |
16 | +import common.util.bean.BeanUtil; | |
17 | + | |
18 | +import javax.servlet.annotation.MultipartConfig; | |
19 | +import java.util.HashMap; | |
20 | + | |
21 | +/** | |
22 | + * Servlet 관련 설정 Class | |
23 | + * | |
24 | + * @author 최정우 | |
25 | + * @since 2022.08.31 | |
26 | + */ | |
27 | +@Configuration | |
28 | +@EnableWebMvc | |
29 | +@ComponentScan(basePackages = {"kr.co.takensoft"}) | |
30 | +public class WebContextConfig implements WebMvcConfigurer { | |
31 | + | |
32 | + | |
33 | + /** | |
34 | + * 1. 특정 URL(Path)에 대한 HTTP Request 처리를 DispatcherServlet이 담당하지 않도록 만들어 주는 설정 (html, js, css, file 등..) | |
35 | + * 2. Client가 접근하지 못하는 WEB-INF 폴더안에 위치해 있는 정적 자원에 Clien가 접근할 수 있도록 만들어 주는 설정 | |
36 | + * | |
37 | + * @author 최정우 | |
38 | + * @since 2022.08.31 | |
39 | + */ | |
40 | + @Override | |
41 | + public void addResourceHandlers(ResourceHandlerRegistry registry) { | |
42 | + registry.addResourceHandler("/resources/**").addResourceLocations("/resources/"); | |
43 | + registry.addResourceHandler("/views/**").addResourceLocations("/views/"); | |
44 | + //registry.addResourceHandler("/WEB-INF/jsp/**").addResourceLocations("/jsp/"); | |
45 | + } | |
46 | + | |
47 | + /** | |
48 | + * Custom Bean Class ViewResolver를 제공해 주기 위한 Bean (파일 다운로드, JSON 등..) | |
49 | + * | |
50 | + * @author 최정우 | |
51 | + * @since 2022.08.31 | |
52 | + * @return BeanNameViewResolver | |
53 | + */ | |
54 | + @Bean(name="beanView") | |
55 | + public BeanNameViewResolver getBeanView () { | |
56 | + BeanNameViewResolver beanView = new BeanNameViewResolver(); | |
57 | + beanView.setOrder(0); | |
58 | + return beanView; | |
59 | + } | |
60 | + | |
61 | + /** | |
62 | + * JSON ViewResolver를 제공해 주기 위한 Bean | |
63 | + * | |
64 | + * @author 최정우 | |
65 | + * @since 2022.08.31 | |
66 | + * @return MappingJackson2JsonView | |
67 | + */ | |
68 | + @Bean(name="jsonView") | |
69 | + public MappingJackson2JsonView getJsonView () { | |
70 | + ObjectMapper objectMapper = (ObjectMapper) BeanUtil.getBean("objectMapper"); | |
71 | + MappingJackson2JsonView jsonView = new MappingJackson2JsonView(objectMapper); | |
72 | + jsonView.setExtractValueFromSingleKeyModel(true); | |
73 | + return jsonView; | |
74 | + } | |
75 | + | |
76 | + /** | |
77 | + * Multipart Resolver를 제공해 주기 위한 Bean | |
78 | + * | |
79 | + * @author 최정우 | |
80 | + * @since 2022.08.31 | |
81 | + * @return MappingJackson2JsonView | |
82 | + */ | |
83 | + @Bean(name="multipartResolver") | |
84 | + public CommonsMultipartResolver getMulltipartResolver () { | |
85 | + CommonsMultipartResolver multipartResolver = new CommonsMultipartResolver(); | |
86 | + multipartResolver.setDefaultEncoding("UTF-8"); | |
87 | + //multipartResolver.setMaxUploadSize(1024 * 1024 * 1024 * 10);//10GB | |
88 | + //multipartResolver.setMaxInMemorySize(1024 * 1024 * 1024 * 10);//10GB | |
89 | + return multipartResolver; | |
90 | + } | |
91 | + | |
92 | + /** | |
93 | + * JSP ViewResolver를 제공해 주기 위한 Bean | |
94 | + * | |
95 | + * @author 최정우 | |
96 | + * @since 2022.08.31 | |
97 | + * @return InternalResourceViewResolver | |
98 | + */ | |
99 | + @Bean(name="jspView") | |
100 | + public ViewResolver getJspView() { | |
101 | + InternalResourceViewResolver jspViewResolver = new InternalResourceViewResolver(); | |
102 | + jspViewResolver.setPrefix("/WEB-INF/jsp/"); | |
103 | + jspViewResolver.setSuffix(".jsp"); | |
104 | + jspViewResolver.setOrder(1); | |
105 | + return jspViewResolver; | |
106 | + } | |
107 | + | |
108 | + | |
109 | + | |
110 | +} |
+++ src/back-end/main/resources/mybatis/main/sample-SQL.xml
... | ... | @@ -0,0 +1,35 @@ |
1 | +<?xml version="1.0" encoding="UTF-8" ?> | |
2 | +<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd"> | |
3 | + | |
4 | + | |
5 | +<!-- | |
6 | + 작성자 : 최정우 | |
7 | + 작성일 : 2022.09.01 | |
8 | + 내용 : Sample Mapper 입니다. | |
9 | + --> | |
10 | +<mapper namespace="kr.co.takensoft.projectName.test.dao.TestDAO"> | |
11 | + | |
12 | + <!-- resultMap sample | |
13 | + <resultMap id="CrawlingSiteResult" type="CrawlingSite"> | |
14 | + <result property="crawlingSiteSeq" column="crawling_site_seq"/> | |
15 | + <result property="site" column="site"/> | |
16 | + <collection property="CrawlingChannels" column="{crawlingSiteSeq = crawling_site_seq}" javaType="java.util.ArrayList" ofType="CrawlingChannel" select="getCrawlingChannelList" /> | |
17 | + </resultMap> --> | |
18 | + | |
19 | + <!-- | |
20 | + 작성자 : 최정우 | |
21 | + 작성일 : 2022.09.01 | |
22 | + 내용 : 데이터 조회 테스트 | |
23 | + --> | |
24 | + <select id="testDataSelectList" parameterType="Test" resultType="Test"> | |
25 | + SELECT | |
26 | + test_id AS testId, | |
27 | + title AS title, | |
28 | + content AS content, | |
29 | + create_user_id AS createUserId, | |
30 | + create_datetime AS createDatetime | |
31 | + FROM | |
32 | + test | |
33 | + </select> | |
34 | + | |
35 | +</mapper>(No newline at end of file) |
+++ src/front-end/WEB-INF/web.xml
... | ... | @@ -0,0 +1,10 @@ |
1 | +<?xml version="1.0" encoding="UTF-8"?> | |
2 | +<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee" | |
3 | + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" | |
4 | + xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd" | |
5 | + version="4.0"> | |
6 | + | |
7 | + <display-name>spring-legacy-project</display-name> | |
8 | + | |
9 | + | |
10 | +</web-app> |
+++ src/front-end/resources/js/test.js
... | ... | @@ -0,0 +1,3 @@ |
1 | +function test () { | |
2 | + console.log('hello world'); | |
3 | +}(No newline at end of file) |
+++ src/front-end/views/index.html
... | ... | @@ -0,0 +1,157 @@ |
1 | +<!DOCTYPE html> | |
2 | +<html lang="en"> | |
3 | +<head> | |
4 | + <meta charset="UTF-8"> | |
5 | + <title>Index</title> | |
6 | +</head> | |
7 | +<body> | |
8 | + index | |
9 | + | |
10 | + <p>jsonTestForRequestParam</p> | |
11 | + <form method="post" action="/jsonTestForRequestParam"> | |
12 | + <input type="text" name="name"> | |
13 | + <input type="text" name="age"> | |
14 | + <button type="submit">submit</button> | |
15 | + </form> | |
16 | + | |
17 | + <p>jsonTestForRequestBody 안됨</p> | |
18 | + <form method="post" action="/jsonTestForRequestBody"> | |
19 | + <input type="text" name="name"> | |
20 | + <input type="text" name="age"> | |
21 | + <button type="submit">submit</button> | |
22 | + </form> | |
23 | + | |
24 | + <p>jsonTestForMultipart 잘됨</p> | |
25 | + <form method="post" action="/jsonTestForMultipart" enctype="multipart/form-data"> | |
26 | + <input type="text" name="name"> | |
27 | + <input type="text" name="age"> | |
28 | + <input type="file" name="file" id="file"> | |
29 | + <button type="submit">submit</button> | |
30 | + <button type="button" onclick="postAjaxMultipartReqeust()">postAjaxMultipartReqeust</button> | |
31 | + </form> | |
32 | + | |
33 | + <script> | |
34 | + function testDataSelectList () { | |
35 | + fetch('/testDataSelectList', { | |
36 | + method: "GET", | |
37 | + headers: { | |
38 | + 'Content-Type': 'application/json; charset=UTF-8' | |
39 | + } | |
40 | + }).then(function (response) { | |
41 | + console.log("testDataSelectList - response:", response); | |
42 | + response.json().then(function (data) { | |
43 | + console.log("testDataSelectList - data:", data); | |
44 | + }) | |
45 | + }).catch(function (error) { | |
46 | + console.log("testDataSelectList - error", error) | |
47 | + }); | |
48 | + } | |
49 | + testDataSelectList(); | |
50 | + | |
51 | + | |
52 | + | |
53 | + function getAjaxReqeust () { | |
54 | + fetch('/jsonTestForRequestParam?method=GET&title=testTitle&age=30', { | |
55 | + method: "GET", | |
56 | + headers: { | |
57 | + //'Content-Type': 'multipart/form-data; charset=UTF-8' | |
58 | + //'Content-Type': 'application/json; charset=UTF-8' | |
59 | + 'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8' | |
60 | + } | |
61 | + }) | |
62 | + .then((response) => response.json()) | |
63 | + .then((data) => console.log("jsonTestForRequestParam - data:", data)) | |
64 | + .catch((error) => console.log("jsonTestForRequestParam - error:", error)); | |
65 | + } | |
66 | + | |
67 | + | |
68 | + | |
69 | + function postAjaxReqeust () { | |
70 | + | |
71 | + //이건 안됨 | |
72 | + /*fetch('/jsonTestForRequestParam', { | |
73 | + method: "POST", | |
74 | + headers: { | |
75 | + //'Content-Type': 'multipart/form-data; charset=UTF-8' | |
76 | + //'Content-Type': 'application/json; charset=UTF-8' | |
77 | + 'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8' | |
78 | + }, | |
79 | + body: JSON.stringify({ | |
80 | + method: "POST", | |
81 | + title: "testTitlePost", | |
82 | + age: 213, | |
83 | + }) | |
84 | + }) | |
85 | + .then((response) => response.json()) | |
86 | + .then((data) => console.log("jsonTestForRequestParam - data:", data)) | |
87 | + .catch((error) => console.log("jsonTestForRequestParam - error:", error));*/ | |
88 | + | |
89 | + //이건 잘됨 | |
90 | + fetch('/jsonTestForRequestBody', { | |
91 | + method: "POST", | |
92 | + headers: { | |
93 | + //'Content-Type': 'multipart/form-data; charset=UTF-8' | |
94 | + 'Content-Type': 'application/json; charset=UTF-8' | |
95 | + //'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8' | |
96 | + }, | |
97 | + body: JSON.stringify({ | |
98 | + method: "POST", | |
99 | + title: "testTitlePost", | |
100 | + age: 213, | |
101 | + }) | |
102 | + }) | |
103 | + .then((response) => response.json()) | |
104 | + .then((data) => console.log("jsonTestForRequestParam - data:", data)) | |
105 | + .catch((error) => console.log("jsonTestForRequestParam - error:", error)); | |
106 | + } | |
107 | + | |
108 | + function postAjaxMultipartReqeust () { | |
109 | + //이거 잘됨 | |
110 | + let formData = new FormData(); | |
111 | + formData.append('method', "POST"); | |
112 | + formData.append('title', "testTitlePost"); | |
113 | + formData.append('age', 22); | |
114 | + let fileInput = document.getElementById('file'); | |
115 | + for (let i = 0; i < fileInput.files.length; i++) { | |
116 | + formData.append('files', fileInput.files[i]); | |
117 | + } | |
118 | + //이거 잘됨 (단, progress를 활용 못함) | |
119 | + /*fetch('/jsonTestForMultipart', { | |
120 | + method: "POST", | |
121 | + headers: { | |
122 | + //'Content-Type': 'multipart/form-data' 이거 안됨. 왜 안되냐 하면, fetch api로 formData를 보낼때 헤더를 설정 하지 말아야 하고, 그 이유는 헤더에 자동으로 Content-Type:multipart/form-data; boundary=----WebKitFormBoundaryMJtHYBc9ERyjdAy8 세팅된다고 함 | |
123 | + //'Content-Type': 'application/json; charset=UTF-8' 이거 안됨(당연) | |
124 | + //'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8' 이거 안됨(당연) | |
125 | + }, | |
126 | + body: formData | |
127 | + }) | |
128 | + .then((response) => response.json()) | |
129 | + .then((data) => console.log("jsonTestForMultipart - data:", data)) | |
130 | + .catch((error) => console.log("jsonTestForMultipart - error:", error));*/ | |
131 | + | |
132 | + //이거 잘됨 (progress 활용 가능) | |
133 | + let request = new XMLHttpRequest(); | |
134 | + request.open('POST', '/jsonTestForMultipart'); | |
135 | + // upload progress event | |
136 | + request.upload.addEventListener('progress', function(e) { | |
137 | + // upload progress as percentage | |
138 | + let percent_completed = (e.loaded / e.total)*100; | |
139 | + console.log(percent_completed); | |
140 | + }); | |
141 | + // request finished event | |
142 | + request.addEventListener('load', function(e) { | |
143 | + // HTTP status message (200, 404 etc) | |
144 | + console.log('request.status : ', request.status); | |
145 | + | |
146 | + // request.response holds response from the server | |
147 | + console.log('request.response : ', request.response); | |
148 | + }); | |
149 | + // send POST request to server | |
150 | + request.send(formData); | |
151 | + } | |
152 | + | |
153 | + //getAjaxReqeust(); | |
154 | + //postAjaxReqeust(); | |
155 | + </script> | |
156 | +</body> | |
157 | +</html>(No newline at end of file) |
Add a comment
Delete comment
Once you delete this comment, you won't be able to recover it. Are you sure you want to delete this comment?