
--- build.gradle
+++ build.gradle
... | ... | @@ -40,7 +40,9 @@ |
40 | 40 |
implementation group: 'com.googlecode.json-simple', name: 'json-simple', version: '1.1.1' |
41 | 41 |
// https://mvnrepository.com/artifact/org.json/json |
42 | 42 |
implementation group: 'org.json', name: 'json', version: '20231013' |
43 |
- |
|
43 |
+ // https://mvnrepository.com/artifact/org.springframework.security/spring-security-crypto |
|
44 |
+ implementation group: 'org.springframework.security', name: 'spring-security-crypto', version: '6.2.1' |
|
45 |
+ // https://mvnrepository.com/artifact/javax.servlet/javax.servlet-api |
|
44 | 46 |
//compileOnly group: 'javax.servlet', name: 'javax.servlet-api', version: '3.0.1' |
45 | 47 |
implementation 'org.bgee.log4jdbc-log4j2:log4jdbc-log4j2-jdbc4.1:1.16' |
46 | 48 |
// https://mvnrepository.com/artifact/com.fasterxml.jackson.datatype/jackson-datatype-jsr310 |
+++ build/resources/main/spring/mapper/mybatis-config.xml
... | ... | @@ -0,0 +1,23 @@ |
1 | +<?xml version="1.0" encoding="UTF-8"?> | |
2 | +<!DOCTYPE configuration PUBLIC "-//mybatis.org//DTD Config 3.0/EN" | |
3 | + "http://mybatis.org/dtd/mybatis-3-config.dtd"> | |
4 | +<configuration> | |
5 | + <settings> | |
6 | + <setting name="cacheEnabled" value="true"/> <!-- mapper 캐시 전역 사용여부 --> | |
7 | + <setting name="lazyLoadingEnabled" value="false"/> <!-- mybatis 지연 로딩 사용여부 --> | |
8 | + <setting name="multipleResultSetsEnabled" value="true"/> <!-- 한개의 구문에서 여러개의 ResultSet 허용 여부 --> | |
9 | + <setting name="useColumnLabel" value="true"/> <!-- 컬럼명 대신 컬럼라벨 사용 여부 --> | |
10 | + <setting name="useGeneratedKeys" value="false"/> <!-- 키자동생성 --> | |
11 | + <setting name="defaultExecutorType" value="SIMPLE"/> | |
12 | + <setting name="defaultStatementTimeout" value="25000"/> | |
13 | + <setting name="callSettersOnNulls" value="true"/> | |
14 | + </settings> | |
15 | + | |
16 | + <typeAliases> | |
17 | + <!-- 회원정보 객체 --> | |
18 | + <typeAlias type="com.ajin.ajinerp.user.member.vo.Member" alias="Member"/> | |
19 | + <!-- 로그인로그 객체 --> | |
20 | + <typeAlias type="com.ajin.ajinerp.user.member.vo.LoginLogVO" alias="LoginLogVO"/> | |
21 | + </typeAliases> | |
22 | + | |
23 | +</configuration>(파일 끝에 줄바꿈 문자 없음) |
+++ build/resources/main/spring/mapper/user/login-SQL.xml
... | ... | @@ -0,0 +1,41 @@ |
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 | +<mapper namespace="com.ajin.ajinerp.user.member.dao.LoginDAO"> | |
6 | + <!-- 로그인 매퍼 --> | |
7 | + <resultMap id="loginLog" type="LoginLogVO"> | |
8 | + <result property="userid" column="USERID" /> | |
9 | + <result property="usernm" column="USERNM" /> | |
10 | + <result property="contgu" column="CONTGU" /> | |
11 | + <result property="errxxx" column="ERRXXX" /> | |
12 | + <result property="ipaddr" column="IPADDR" /> | |
13 | + <result property="tmlreg" column="TMLREG" /> | |
14 | + <result property="macadd" column="MACADD" /> | |
15 | + <result property="sysdat" column="SYSDAT" /> | |
16 | + <result property="systim" column="SYSTIM" /> | |
17 | + </resultMap> | |
18 | + | |
19 | + <!-- 2.로그인 로그 --> | |
20 | + <insert id="insertLoginLog" parameterType="LoginLogVO"> | |
21 | + INSERT INTO USLOGXXT | |
22 | + ( | |
23 | + USERID, | |
24 | + USERNM, | |
25 | + CONTGU, | |
26 | + ERRXXX, | |
27 | + IPADDR, | |
28 | + TMLREG, | |
29 | + SYSDAT, | |
30 | + SYSTIM) | |
31 | + VALUES | |
32 | + (#{userid}, | |
33 | + #{usernm}, | |
34 | + #{contgu}, | |
35 | + #{errxxx}, | |
36 | + #{ipaddr}, | |
37 | + #{tmlreg}, | |
38 | + TO_CHAR(SYSDATE, 'YYYYMMDD'), -- 현재 날짜를 YYYYMMDD 포맷으로 변환 | |
39 | + TO_CHAR(SYSDATE, 'HH24MISS')) -- 현재 시간을 HH24MISS 포맷으로 변환 | |
40 | + </insert> | |
41 | +</mapper>(파일 끝에 줄바꿈 문자 없음) |
+++ build/resources/main/spring/mapper/user/member-SQL.xml
... | ... | @@ -0,0 +1,97 @@ |
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 | +<mapper namespace="com.ajin.ajinerp.user.member.dao.MemberDAO"> | |
6 | + | |
7 | + <!-- 사용자 매퍼 --> | |
8 | + <resultMap id="memberResult" type="Member"> | |
9 | + <result property="userid" column="USERID" /> | |
10 | + <result property="usernm" column="USERNM" /> | |
11 | + <result property="oldwrd" column="OLDWRD" /> | |
12 | + <result property="newwrd" column="NEWWRD" /> | |
13 | + <result property="pw_ymd" column="PW_YMD" /> | |
14 | + <result property="prjcod" column="PRJCOD" /> | |
15 | + <result property="compcd" column="COMPCD" /> | |
16 | + <result property="buscod" column="BUSCOD" /> | |
17 | + <result property="kangub" column="KANGUB" /> | |
18 | + <result property="saygub" column="SAYGUB" /> | |
19 | + <result property="iduptx" column="IDUPTX" /> | |
20 | + <result property="dtmupt" column="DTMUPT" /> | |
21 | + <result property="tmlupt" column="TMLUPT" /> | |
22 | + <result property="imagex" column="IMAGEX" /> | |
23 | + </resultMap> | |
24 | + | |
25 | + <!-- 1.아이디로 이름 조회--> | |
26 | + <select id="getNameById" parameterType="String" resultMap="memberResult"> | |
27 | + SELECT NVL(USERID, '') AS USERID | |
28 | + , NVL(USERNM, '') AS USERNM | |
29 | + FROM US01001T | |
30 | + WHERE USERID = #{userid} | |
31 | + AND SAYGUB = 'Y' | |
32 | + </select> | |
33 | + | |
34 | + <!-- 2. 아이디로 회원 조회 COUNT--> | |
35 | + <select id="getCountById" parameterType="String" resultType="int"> | |
36 | + SELECT COUNT(*) | |
37 | + FROM US01001T | |
38 | + WHERE USERID = #{userid} | |
39 | + AND SAYGUB = 'Y' | |
40 | + </select> | |
41 | + | |
42 | + <!-- 2.아이디로 이미지 조회 --> | |
43 | + <select id="getImageById" parameterType="String" resultMap="memberResult"> | |
44 | + SELECT IMAGEX | |
45 | + FROM US01003T | |
46 | + WHERE USERID = #{userid} | |
47 | + </select> | |
48 | + | |
49 | + <!-- 3.사용자 이미지 변경--> | |
50 | + <update id="updateUserImage" parameterType="String"> | |
51 | + UPDATE US01003T | |
52 | + SET IMAGEX = #{imagex} | |
53 | + WHERE USERID = #{userid} | |
54 | + </update> | |
55 | + | |
56 | + <!-- 4.사용자 마지막 비밀번호 변경 날짜 조회 --> | |
57 | + <select id="checkPasswordExpiry" parameterType="String" resultType="int"> | |
58 | + SELECT COUNT(*) FROM US01001T WHERE USERID = #{userid} AND MONTHS_BETWEEN(SYSDATE, TO_DATE(PW_YMD, 'YYYYMMDD')) >= 2 | |
59 | + </select> | |
60 | + | |
61 | + <!-- 5.사용자 비밀번호 변경 --> | |
62 | + <update id="updatePassword" parameterType="Member"> | |
63 | + UPDATE US01001T | |
64 | + SET OLDWRD = #{oldwrd} | |
65 | + , NEWWRD = #{newwrd} | |
66 | + , IDUPTX = #{userid} | |
67 | + , DTMUPT = SYSDATE | |
68 | + , TMLUPT = #{tmlupt} | |
69 | + WHERE USERID = #{userid} | |
70 | + </update> | |
71 | + | |
72 | + <!-- 6.아이디 비밀번호로 회원 조회 --> | |
73 | + <select id="getMember" parameterType="Member" resultMap="memberResult"> | |
74 | + SELECT NVL(USERID, '') AS USERID | |
75 | + , NVL(USERNM, '') AS USERNM | |
76 | + , NVL(OLDWRD, '') AS OLDWRD | |
77 | + , NVL(NEWWRD, '') AS NEWWRD | |
78 | + , NVL(PW_YMD, '') AS PW_YMD | |
79 | + , NVL(PRJCOD, '') AS PRJCOD | |
80 | + , NVL(COMPCD, '') AS COMPCD | |
81 | + , NVL(KANGUB, '') AS KANGUB | |
82 | + , NVL(SAYGUB, '') AS SAYGUB | |
83 | + FROM US01001T | |
84 | + WHERE USERID = #{userid} | |
85 | + AND NEWWRD = #{newwrd} | |
86 | + AND SAYGUB = 'Y' | |
87 | + </select> | |
88 | + | |
89 | + <!-- 7.아이디 비밀번호로 회원 조회 COUNT --> | |
90 | + <select id="getMemberCount" parameterType="Member" resultType="int"> | |
91 | + SELECT COUNT(*) | |
92 | + FROM US01001T | |
93 | + WHERE USERID = #{userid} | |
94 | + AND NEWWRD = #{newwrd} | |
95 | + AND SAYGUB = 'Y' | |
96 | + </select> | |
97 | +</mapper>(파일 끝에 줄바꿈 문자 없음) |
+++ src/main/java/com/ajin/ajinerp/common/util/AsyncUtil.java
... | ... | @@ -0,0 +1,35 @@ |
1 | +package com.ajin.ajinerp.common.util; | |
2 | +import com.ajin.ajinerp.common.util.reflection.ReflectionUtil; | |
3 | + | |
4 | +public class AsyncUtil implements Runnable { | |
5 | + | |
6 | + String classFilePath, packageName, className, methodName; | |
7 | + Object[] paramValues; | |
8 | + Class<?>[] paramTypes; | |
9 | + | |
10 | + public AsyncUtil(String classFilePath, String packageName, String className, String methodName, Object[] paramValues, Class<?>[] paramTypes) { | |
11 | + this.classFilePath = classFilePath; | |
12 | + this.packageName = packageName; | |
13 | + this.className = className; | |
14 | + this.methodName = methodName; | |
15 | + this.paramValues = paramValues; | |
16 | + this.paramTypes = paramTypes; | |
17 | + } | |
18 | + | |
19 | + public AsyncUtil(String packageName, String className, String methodName, Object[] paramValues, Class<?>[] paramTypes) { | |
20 | + this.packageName = packageName; | |
21 | + this.className = className; | |
22 | + this.methodName = methodName; | |
23 | + this.paramValues = paramValues; | |
24 | + this.paramTypes = paramTypes; | |
25 | + } | |
26 | + | |
27 | + @Override | |
28 | + public void run () { | |
29 | + //객체 생성 | |
30 | + Object clazz = ReflectionUtil.classAndBeanLoad(classFilePath, (packageName + "." + className)); | |
31 | + //메서드 실행 | |
32 | + ReflectionUtil.invokeByMethodName(clazz, methodName, paramValues, paramTypes); | |
33 | + } | |
34 | + | |
35 | +} |
+++ src/main/java/com/ajin/ajinerp/common/util/AuthUtil.java
... | ... | @@ -0,0 +1,99 @@ |
1 | +package com.ajin.ajinerp.common.util; | |
2 | + | |
3 | +import org.slf4j.Logger; | |
4 | +import org.slf4j.LoggerFactory; | |
5 | + | |
6 | +import jakarta.servlet.http.HttpSession; | |
7 | + | |
8 | +import java.util.HashMap; | |
9 | + | |
10 | +public class AuthUtil { | |
11 | + | |
12 | + private static final Logger LOGGER = LoggerFactory.getLogger(AuthUtil.class); | |
13 | + | |
14 | + //Session에 등록된 Login User ID Key | |
15 | + public static final String LOGIN_USER_SESSION = "loginUsers"; | |
16 | + | |
17 | + //중복 로그인가능 여부 | |
18 | + public static final boolean IS_POSSIBLE_DUPLICATION_LOGIN = false; | |
19 | + | |
20 | + //Session Max 시간(초) | |
21 | + public static final int SESSION_MAX_TIME = 60*60*6;//6시간 | |
22 | + | |
23 | + public static HashMap<String, Object> getLoginUser () { | |
24 | + try { | |
25 | + //현재 client의 HttpSession 조회 | |
26 | + HttpSession session = CommonUtil.getHttpSession(false); | |
27 | + if(session == null || session.getAttribute(LOGIN_USER_SESSION) == null || ((HashMap<String, Object>) session.getAttribute(LOGIN_USER_SESSION)).get("user_id") == null) { | |
28 | + return null; | |
29 | + }else { | |
30 | + return (HashMap<String, Object>) session.getAttribute(LOGIN_USER_SESSION); | |
31 | + } | |
32 | + } catch(NullPointerException e) { | |
33 | + LOGGER.error(e.toString()); | |
34 | + // System.out.println("AuthUtil getLoginUser Error : "); | |
35 | + // e.printStackTrace(); | |
36 | + return null; | |
37 | + } | |
38 | + } | |
39 | + | |
40 | + public static String getLoginUserId () { | |
41 | + HashMap<String, Object> user = getLoginUser(); | |
42 | + if (user != null) { | |
43 | + return (String) user.get("user_id"); | |
44 | + } else { | |
45 | + return null; | |
46 | + } | |
47 | + } | |
48 | + public static HashMap<String, Object> getKey () { | |
49 | + try { | |
50 | + //현재 client의 HttpSession 조회 | |
51 | + HttpSession session = CommonUtil.getHttpSession(true); | |
52 | + if(session == null || session.getAttribute("key") == null || ((HashMap<String, Object>) session.getAttribute("key")).get("salt") == null) { | |
53 | + return null; | |
54 | + }else { | |
55 | + return ((HashMap<String, Object>) session.getAttribute("key")); | |
56 | + } | |
57 | + } catch(NullPointerException e) { | |
58 | + LOGGER.error(e.toString()); | |
59 | + return null; | |
60 | + } | |
61 | + } | |
62 | + | |
63 | + public static String getKeySaltKey () { | |
64 | + HashMap<String, Object> key = getKey(); | |
65 | + if (key != null ) { | |
66 | + if(key.get("salt") != null) { | |
67 | + return key.get("salt").toString(); | |
68 | + }else { | |
69 | + return null; | |
70 | + } | |
71 | + } else { | |
72 | + return null; | |
73 | + } | |
74 | + } | |
75 | + public static String getKeyIvtKey () { | |
76 | + HashMap<String, Object> key = getKey(); | |
77 | + if (key != null ) { | |
78 | + if(key != null) { | |
79 | + return key.get("iv").toString(); | |
80 | + }else { | |
81 | + return null; | |
82 | + } | |
83 | + } else { | |
84 | + return null; | |
85 | + } | |
86 | + } | |
87 | + public static String getKeyENC_KEY () { | |
88 | + HashMap<String, Object> key = getKey(); | |
89 | + if (key != null ) { | |
90 | + if(key.get("ENC_KEY") != null) { | |
91 | + return key.get("ENC_KEY").toString(); | |
92 | + }else{ | |
93 | + return null; | |
94 | + } | |
95 | + } else { | |
96 | + return null; | |
97 | + } | |
98 | + } | |
99 | +} |
+++ src/main/java/com/ajin/ajinerp/common/util/CommonUtil.java
... | ... | @@ -0,0 +1,801 @@ |
1 | +package com.ajin.ajinerp.common.util; | |
2 | + | |
3 | + | |
4 | + | |
5 | +import java.io.IOException; | |
6 | +import java.lang.reflect.Field; | |
7 | +import java.lang.reflect.Modifier; | |
8 | +import java.math.BigDecimal; | |
9 | +import java.net.InetAddress; | |
10 | +import java.net.InetSocketAddress; | |
11 | +import java.net.Socket; | |
12 | +import java.net.UnknownHostException; | |
13 | +import java.text.SimpleDateFormat; | |
14 | +import java.util.ArrayList; | |
15 | +import java.util.Arrays; | |
16 | +import java.util.Collection; | |
17 | +import java.util.Date; | |
18 | +import java.util.HashMap; | |
19 | +import java.util.LinkedHashMap; | |
20 | +import java.util.List; | |
21 | +import java.util.Map; | |
22 | +import java.util.Set; | |
23 | +import java.util.UUID; | |
24 | + | |
25 | +import jakarta.servlet.http.HttpServletRequest; | |
26 | +import jakarta.servlet.http.HttpSession; | |
27 | + | |
28 | +import org.json.XML; | |
29 | +import org.json.simple.JSONArray; | |
30 | +import org.json.simple.JSONObject; | |
31 | +import org.springframework.web.context.request.RequestContextHolder; | |
32 | +import org.springframework.web.context.request.ServletRequestAttributes; | |
33 | + | |
34 | +import com.fasterxml.jackson.core.JsonParseException; | |
35 | +import com.fasterxml.jackson.core.type.TypeReference; | |
36 | +import com.fasterxml.jackson.databind.JsonMappingException; | |
37 | +import com.fasterxml.jackson.databind.ObjectMapper; | |
38 | +import com.fasterxml.jackson.databind.SerializationFeature; | |
39 | + | |
40 | +public class CommonUtil { | |
41 | + | |
42 | + /** | |
43 | + * @author 최정우 | |
44 | + * @since 2019.12.11 | |
45 | + * | |
46 | + * 데이터의 표준화 사용 유무 | |
47 | + */ | |
48 | + private static boolean IS_USE_STANDARD = true; | |
49 | + | |
50 | + public static void setIsUseStandard (boolean isUseStandard) { | |
51 | + IS_USE_STANDARD = isUseStandard; | |
52 | + } | |
53 | + | |
54 | + public static boolean getIsUseStandard () { | |
55 | + return IS_USE_STANDARD; | |
56 | + } | |
57 | + | |
58 | + /** | |
59 | + * @author 최정우 | |
60 | + * @since 2019.11.13 | |
61 | + * | |
62 | + * 빈 문자열 검사 | |
63 | + */ | |
64 | + public static boolean isNull(Object obj) { | |
65 | + return obj == null; | |
66 | + } | |
67 | + | |
68 | + | |
69 | + /** | |
70 | + * @author 최정우 | |
71 | + * @since 2019.11.13 | |
72 | + * | |
73 | + * string to int check | |
74 | + */ | |
75 | + public static boolean isInt (String text) { | |
76 | + try { | |
77 | + Integer.parseInt(text); | |
78 | + return true; | |
79 | + } catch(NumberFormatException e) { | |
80 | + return false; | |
81 | + } | |
82 | + } | |
83 | + | |
84 | + /** | |
85 | + * @author 최정우 | |
86 | + * @since 2019.11.13 | |
87 | + * | |
88 | + * string to int check | |
89 | + */ | |
90 | + public static boolean isLong (String text) { | |
91 | + try { | |
92 | + Long.parseLong(text); | |
93 | + return true; | |
94 | + } catch(NumberFormatException e) { | |
95 | + return false; | |
96 | + } | |
97 | + } | |
98 | + | |
99 | + /** | |
100 | + * @author 최정우 | |
101 | + * @since 2019.11.13 | |
102 | + * | |
103 | + * string to double check | |
104 | + */ | |
105 | + public static boolean isDouble (String text) { | |
106 | + try { | |
107 | + Double.parseDouble(text); | |
108 | + return true; | |
109 | + } catch (NumberFormatException e) { | |
110 | + return false; | |
111 | + } catch (Exception e) { | |
112 | + return false; | |
113 | + } | |
114 | + } | |
115 | + | |
116 | + /** | |
117 | + * @author 최정우 | |
118 | + * @since 2020.01.08 | |
119 | + * | |
120 | + * object to int | |
121 | + */ | |
122 | + public static int parseInt (Object obj) { | |
123 | + try { | |
124 | + return Integer.parseInt(obj.toString()); | |
125 | + } catch(Exception e) { | |
126 | + return 0; | |
127 | + } | |
128 | + } | |
129 | + | |
130 | + /** | |
131 | + * @author 최정우 | |
132 | + * @since 2020.01.08 | |
133 | + * | |
134 | + * string to int | |
135 | + */ | |
136 | + public static int parseInt (String text) { | |
137 | + try { | |
138 | + return Integer.parseInt(text); | |
139 | + } catch(NumberFormatException e) { | |
140 | + return 0; | |
141 | + } | |
142 | + } | |
143 | + | |
144 | + /** | |
145 | + * @author 최정우 | |
146 | + * @since 2020.01.08 | |
147 | + * | |
148 | + * int to double | |
149 | + */ | |
150 | + public static long parseLong (int number) { | |
151 | + try { | |
152 | + return (long) number; | |
153 | + } catch(Exception e) { | |
154 | + return 0; | |
155 | + } | |
156 | + } | |
157 | + | |
158 | + /** | |
159 | + * @author 최정우 | |
160 | + * @since 2020.01.08 | |
161 | + * | |
162 | + * object to double | |
163 | + */ | |
164 | + public static long parseLong (String text) { | |
165 | + try { | |
166 | + return Long.parseLong(text); | |
167 | + } catch(Exception e) { | |
168 | + return 0; | |
169 | + } | |
170 | + } | |
171 | + | |
172 | + /** | |
173 | + * @author 최정우 | |
174 | + * @since 2020.01.08 | |
175 | + * | |
176 | + * object to double | |
177 | + */ | |
178 | + public static long parseLong (Object obj) { | |
179 | + try { | |
180 | + if (obj instanceof Integer) { | |
181 | + return (long) obj; | |
182 | + } else { | |
183 | + return Long.parseLong(obj.toString()); | |
184 | + } | |
185 | + } catch(Exception e) { | |
186 | + return 0; | |
187 | + } | |
188 | + } | |
189 | + | |
190 | + /** | |
191 | + * @author 최정우 | |
192 | + * @since 2020.01.08 | |
193 | + * | |
194 | + * int to double | |
195 | + */ | |
196 | + public static double parseDouble (int number) { | |
197 | + try { | |
198 | + return (double) number; | |
199 | + } catch(Exception e) { | |
200 | + return 0.0; | |
201 | + } | |
202 | + } | |
203 | + | |
204 | + /** | |
205 | + * @author 최정우 | |
206 | + * @since 2020.01.08 | |
207 | + * | |
208 | + * object to double | |
209 | + */ | |
210 | + public static double parseDouble (String text) { | |
211 | + try { | |
212 | + return Double.parseDouble(text); | |
213 | + } catch(Exception e) { | |
214 | + return 0.0; | |
215 | + } | |
216 | + } | |
217 | + | |
218 | + /** | |
219 | + * @author 최정우 | |
220 | + * @since 2020.01.08 | |
221 | + * | |
222 | + * object to double | |
223 | + */ | |
224 | + public static double parseDouble (Object obj) { | |
225 | + try { | |
226 | + if (obj instanceof Integer) { | |
227 | + return (double) obj; | |
228 | + } else { | |
229 | + return Double.parseDouble(obj.toString()); | |
230 | + } | |
231 | + } catch(Exception e) { | |
232 | + return 0.0; | |
233 | + } | |
234 | + } | |
235 | + | |
236 | + /** | |
237 | + * @author 최정우 | |
238 | + * @since 2019.11.13 | |
239 | + * | |
240 | + * 문자열의 모든 공백 제거 | |
241 | + */ | |
242 | + public static String allTrim(String text) { | |
243 | + return text.replaceAll("\\p{Z}", ""); | |
244 | + } | |
245 | + | |
246 | + /** | |
247 | + * @author 최정우 | |
248 | + * @since 2019.11.13 | |
249 | + * | |
250 | + * 문자열 앞뒤 공백 제거후, 문자열 사이에 존재하는 공백을 한개의 공백으로 치환 | |
251 | + * ex) " abcd efg hijk " => "abcd efg hijk" | |
252 | + */ | |
253 | + public static String normalizeSpace(String text) { | |
254 | + return text.trim().replaceAll("\\s+", " "); | |
255 | + } | |
256 | + | |
257 | + /** | |
258 | + * @author 최정우 | |
259 | + * @since 2019.11.13 | |
260 | + * | |
261 | + * 숫자 빼고 모든 문자 제거 | |
262 | + */ | |
263 | + public static String getOnlyNumber (String text) { | |
264 | + return text.replaceAll("[^0-9]", ""); | |
265 | + } | |
266 | + | |
267 | + /** | |
268 | + * @author 최정우 | |
269 | + * @since 2019.11.13 | |
270 | + * | |
271 | + * 문자 빼고 모든 숫자 제거 | |
272 | + */ | |
273 | + public static String getOnlyText (String text) { | |
274 | + return text.replaceAll("[0-9]", ""); | |
275 | + } | |
276 | + | |
277 | + /** | |
278 | + * @author 최정우 | |
279 | + * @since 2019.11.13 | |
280 | + * | |
281 | + * 특정 문자열 개수 check | |
282 | + */ | |
283 | + public static int getWordCount (String text, String word) { | |
284 | + int size = 0; | |
285 | + int fromIndex = -1; | |
286 | + while ((fromIndex = text.indexOf(word, fromIndex + 1)) >= 0) { | |
287 | + size++; | |
288 | + } | |
289 | + return size; | |
290 | + } | |
291 | + | |
292 | + /** | |
293 | + * @author 최정우 | |
294 | + * @since 2019.11.13 | |
295 | + * | |
296 | + * 문자열 to Date문자열 | |
297 | + */ | |
298 | + public static boolean isDate (String text) { | |
299 | + if (StringUtil.isEmpty(text) == true || StringUtil.isEmpty(getOnlyNumber(text)) == true || getOnlyNumber(text).length() < 6) { | |
300 | + return false; | |
301 | + } | |
302 | + | |
303 | + //공백을 제외한 문자얻기, 대문자로 치환 | |
304 | + String newText = allTrim(text).toUpperCase(); | |
305 | + | |
306 | + try { | |
307 | + //문자열의 날짜 패턴 생성 | |
308 | + String pattern = createDatePattern(newText); | |
309 | + if (pattern == null) { | |
310 | + return false; | |
311 | + } | |
312 | + | |
313 | + SimpleDateFormat newPattern = new SimpleDateFormat(pattern); | |
314 | + //문자열 날짜 형태로 변환 | |
315 | + newPattern.parse(newText); | |
316 | + return true; | |
317 | + } catch (Exception e) { | |
318 | + //e.printStackTrace(); | |
319 | + return false; | |
320 | + } | |
321 | + } | |
322 | + | |
323 | + /** | |
324 | + * @author 최정우 | |
325 | + * @since 2019.11.13 | |
326 | + * | |
327 | + * 문자열 to Date문자열 | |
328 | + */ | |
329 | + public static String parseDateText (String text) { | |
330 | + if (StringUtil.isEmpty(text) == true || StringUtil.isEmpty(getOnlyNumber(text)) == true || getOnlyNumber(text).length() < 6) { | |
331 | + return null; | |
332 | + } | |
333 | + | |
334 | + //공백을 제외한 문자얻기, 대문자로 치환 | |
335 | + String newText = allTrim(text).toUpperCase(); | |
336 | + | |
337 | + //문자열의 날짜 패턴 생성 | |
338 | + String pattern = createDatePattern(newText); | |
339 | + if (pattern == null) { | |
340 | + return null; | |
341 | + } | |
342 | + | |
343 | + Date date = null; | |
344 | + String dateText = null; | |
345 | + try { | |
346 | + SimpleDateFormat newPattern = new SimpleDateFormat(pattern); | |
347 | + | |
348 | + //문자열 날짜 형태로 변환 | |
349 | + date = newPattern.parse(newText); | |
350 | + | |
351 | + //DB에 저장할 날짜 패턴 | |
352 | + SimpleDateFormat defalutPattern = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); | |
353 | + dateText = defalutPattern.format(date); | |
354 | + } catch (Exception e) { | |
355 | + //e.printStackTrace(); | |
356 | + } | |
357 | + return dateText; | |
358 | + } | |
359 | + | |
360 | + public static <T> List<T> mapToList (Map<?, T> map) { | |
361 | + List<T> items = new ArrayList<T>(); | |
362 | + | |
363 | + if (map != null) { | |
364 | + for(Map.Entry<?, T> item : map.entrySet()) { | |
365 | + items.add(item.getValue()); | |
366 | + } | |
367 | + } | |
368 | + | |
369 | + return items; | |
370 | + } | |
371 | + | |
372 | + public static Map objectToMap(Object obj) { | |
373 | + if (obj != null) { | |
374 | + try { | |
375 | + return (Map) obj; | |
376 | + } catch (Exception e) { | |
377 | + return new HashMap(); | |
378 | + } | |
379 | + } else { | |
380 | + return new HashMap(); | |
381 | + } | |
382 | + } | |
383 | + | |
384 | + | |
385 | + /* | |
386 | + * 시간 타입 | |
387 | + * PM, AM | |
388 | + */ | |
389 | + public final static List<String> TIME_TYPES = Arrays.asList(new String[] {"AM", "PM", "오전", "오후"}); | |
390 | + | |
391 | + /* | |
392 | + * 날짜 포맷 패턴's | |
393 | + */ | |
394 | + public final static List<Character> DATE_PATTERNS = Arrays.asList(new Character[] {'y', 'M', 'd', 'H', 'm', 's'}); | |
395 | + | |
396 | + /* | |
397 | + * 날짜 포맷 패턴's의 최대 문자열 수 | |
398 | + */ | |
399 | + public final static List<Integer> DATE_PATTERNS_MAX_LENGTH = Arrays.asList(new Integer[] {4, 2, 2, 2, 2, 2}); | |
400 | + | |
401 | + /** | |
402 | + * @author 최정우 | |
403 | + * @since 2019.11.13 | |
404 | + * | |
405 | + * 문자열의 날짜 패턴 생성 | |
406 | + */ | |
407 | + public static String createDatePattern (String date) { | |
408 | + | |
409 | + List<Character> DATE_PATTERNS = Arrays.asList(new Character[] {'y', 'M', 'd', 'H', 'm', 's'}); | |
410 | + | |
411 | + //시간 표기가 (0~12 -> AM, PM사용)인지 (0~23)인지 확인 후, 날짜 포맷 패턴's에 있는 시간 패턴 변경 | |
412 | + int timeTypeFindIndex = -1; | |
413 | + for (int i = 0; i < TIME_TYPES.size(); i++) { | |
414 | + //("AM", "PM", "오전", "오후" 중 1개)가 포함된 단어가 있는지 확인, Index 위치를 담기(없으면 -1) | |
415 | + if ((timeTypeFindIndex = date.indexOf(TIME_TYPES.get(i))) > -1) { | |
416 | + //문자열에 포함된 ("AM", "PM", "오전", "오후" 중 1개) 삭제 | |
417 | + date = date.replaceAll(TIME_TYPES.get(i), ""); | |
418 | + //시간 패턴 변경 [H -> h] | |
419 | + DATE_PATTERNS.set(3, 'h'); | |
420 | + break; | |
421 | + } | |
422 | + } | |
423 | + | |
424 | + //숫자를 뺀 나머지 문자열 가지고오기 ex) "2020.08.03" -> ".." | |
425 | + //숫자를 뺀 나머지 문자열 가지고오기 ex) "2020.08.03 19:20:21" -> "..::" | |
426 | + final char[] separators = getOnlyText(date).toCharArray(); | |
427 | + | |
428 | + | |
429 | + | |
430 | + //사용할 최대 패턴 수 | |
431 | + int maxPatterSize = 0; | |
432 | + if (DATE_PATTERNS.size() <= separators.length) { | |
433 | + maxPatterSize = DATE_PATTERNS.size(); | |
434 | + } else { | |
435 | + maxPatterSize = separators.length; | |
436 | + } | |
437 | + | |
438 | + //구분자별 Index 위치's (사용할 최대 패턴 수 + 시작점:-1, 종료점:date문자열의 최종 길이) | |
439 | + List<Integer> sizeByPatterns = new ArrayList<Integer>(); | |
440 | + | |
441 | + | |
442 | + //구분자 별 Index 위치 파악 후, 앞에 있는 문자열의 수 찾은 후, 추가 (마지막 패턴 뒤에 있는 문자열을 따로 처리해줘야함) | |
443 | + int fromIndex = -1; | |
444 | + for (int i = 0; i < maxPatterSize; i++) { | |
445 | + //구분자 | |
446 | + char separator = separators[i]; | |
447 | + | |
448 | + //'현재 찾은 위치' : 이전에 찾은 위치(찾기 시작할 위치 => fromIndex) + 1 부터 찾기 시작함 | |
449 | + int currentFromIndex = date.indexOf(separator, fromIndex + 1); | |
450 | + | |
451 | + //현재 패턴의 문자열 수 = '현재 찾은 위치' - '이전에 찾은 위치' - 1 [추가] | |
452 | + sizeByPatterns.add(currentFromIndex - fromIndex - 1); | |
453 | + | |
454 | + //'현재 찾은 위치'는 '이전에 찾은 위치'가 됨 | |
455 | + fromIndex = currentFromIndex; | |
456 | + } | |
457 | + //마지막 패턴 뒤에 있는 문자열 = '문자열의 길이' - '마지막에 찾은 위치(이전에 찾은 위치)' - 1 [추가] | |
458 | + sizeByPatterns.add(date.length() - fromIndex - 1); | |
459 | + | |
460 | + | |
461 | + //패턴을 담을 변수 | |
462 | + StringBuilder pattern = new StringBuilder(); | |
463 | + | |
464 | + //DATE_PATTERS 순서 대로, 각 구분자 별 Index 위치 크기만큼 문자열에 패턴 삽입 + 구분자 삽입 | |
465 | + //마지막 전까지만 for문 돌림 | |
466 | + for (int i = 0, patternIndex = 0; i < sizeByPatterns.size() && patternIndex < DATE_PATTERNS.size(); i++, patternIndex++) { | |
467 | + | |
468 | + //패턴 추가 | |
469 | + int usingSize = 0; | |
470 | + for (int j = 0; j < sizeByPatterns.get(i); j++) { | |
471 | + if (j >= usingSize + DATE_PATTERNS_MAX_LENGTH.get(patternIndex)) { | |
472 | + usingSize += DATE_PATTERNS_MAX_LENGTH.get(patternIndex++); | |
473 | + | |
474 | + /*단 한개의 패턴이라도 '최대 문자열 수'를 넘어서면 -> '날짜 아님'*/ | |
475 | + if (i >= sizeByPatterns.size() || patternIndex >= DATE_PATTERNS.size()) { | |
476 | + return null; | |
477 | + } | |
478 | + } | |
479 | + | |
480 | + pattern.append(DATE_PATTERNS.get(patternIndex)); | |
481 | + } | |
482 | + | |
483 | + //날짜 구분자 추가 (마지막 구분자까지만) | |
484 | + if (i < separators.length) { | |
485 | + pattern.append(separators[i]); | |
486 | + } | |
487 | + | |
488 | + | |
489 | + } | |
490 | + | |
491 | + if (timeTypeFindIndex > -1) { | |
492 | + pattern.insert(timeTypeFindIndex, 'a'); | |
493 | + } | |
494 | + | |
495 | + if(!(pattern.toString().equals("-") || pattern.toString().equals("/") || pattern.toString().equals("."))){ | |
496 | + pattern = null; | |
497 | + } | |
498 | + | |
499 | + return pattern.toString(); | |
500 | + } | |
501 | + | |
502 | + | |
503 | + /** | |
504 | + * @author 최정우 | |
505 | + * @since 2020.01.26 | |
506 | + * | |
507 | + * ping 체크 | |
508 | + */ | |
509 | + public static boolean pingCheck (String ip) { | |
510 | + InetAddress inetAddress; | |
511 | + try { | |
512 | + inetAddress = InetAddress.getByName(ip); | |
513 | + return inetAddress.isReachable(1000); | |
514 | + } catch (UnknownHostException e) { | |
515 | + return false; | |
516 | + } catch (IOException e) { | |
517 | + return false; | |
518 | + } catch (Exception e) { | |
519 | + return false; | |
520 | + } | |
521 | + } | |
522 | + | |
523 | + /** | |
524 | + * @author 김성원 | |
525 | + * @since 2024.01.04 | |
526 | + * | |
527 | + * 접속 체크 (ip + port) | |
528 | + */ | |
529 | + public static boolean linkCheck(String ip, int port) { | |
530 | + Socket socket = new Socket(); | |
531 | + try { | |
532 | + socket.connect(new InetSocketAddress(ip, port), 1000); | |
533 | + boolean isConnect = socket.isConnected(); | |
534 | + socket.close(); | |
535 | + return isConnect; | |
536 | + } catch (UnknownHostException e) { | |
537 | + return false; | |
538 | + } catch (IOException e) { | |
539 | + return false; | |
540 | + } catch (Exception e) { | |
541 | + return false; | |
542 | + } | |
543 | + } | |
544 | + | |
545 | + | |
546 | + /** | |
547 | + * @author 최정우 | |
548 | + * @since 2019.12.09 | |
549 | + * | |
550 | + * 데이터 셋 목록 Convert LinkedHashMap<String, Object> to List<String> | |
551 | + */ | |
552 | + public static List<List<Object>> rowDataMapToList (List<LinkedHashMap<String, Object>> rowMapData) throws Exception { | |
553 | + List<List<Object>> rowData = new ArrayList<List<Object>>(); | |
554 | + for (int i = 0; i < rowMapData.size(); i++) { | |
555 | + List<Object> row = new ArrayList<Object>(); | |
556 | + LinkedHashMap<String, Object> mapdata = rowMapData.get(i); | |
557 | + | |
558 | + for( String key : mapdata.keySet() ){ | |
559 | + if (mapdata.get(key) == null) { | |
560 | + row.add("");//null값 대체 | |
561 | + } else { | |
562 | + row.add(mapdata.get(key).toString()); | |
563 | + } | |
564 | + } | |
565 | + rowData.add(row); | |
566 | + } | |
567 | + return rowData; | |
568 | + } | |
569 | + | |
570 | + /** | |
571 | + * @author 최정우 | |
572 | + * @since 2019.12.09 | |
573 | + * | |
574 | + * 데이터 셋 목록 Convert LinkedHashMap<String, Object> to List<String> | |
575 | + */ | |
576 | + public static List<List<Object>> rowDataMapToListOnject (List<LinkedHashMap<String, Object>> rowMapData) throws Exception { | |
577 | + List<List<Object>> rowData = new ArrayList<List<Object>>(); | |
578 | + for (int i = 0; i < rowMapData.size(); i++) { | |
579 | + List<Object> row = new ArrayList<Object>(); | |
580 | + LinkedHashMap<String, Object> mapdata = rowMapData.get(i); | |
581 | + for( String key : mapdata.keySet() ){ | |
582 | + if (mapdata.get(key) == null) { | |
583 | + row.add(null);//null값 대체 | |
584 | + } else { | |
585 | + row.add(mapdata.get(key)); | |
586 | + } | |
587 | + } | |
588 | + rowData.add(row); | |
589 | + } | |
590 | + return rowData; | |
591 | + } | |
592 | + | |
593 | + /** | |
594 | + * @author 최정우 | |
595 | + * @since 2020.01.26 | |
596 | + * | |
597 | + * 현재 client의 HttpServletRequest 조회 | |
598 | + */ | |
599 | + public static HttpServletRequest getHttpServletRequest () { | |
600 | + try { | |
601 | + ServletRequestAttributes servletRequestAttribute = (ServletRequestAttributes) RequestContextHolder.currentRequestAttributes(); | |
602 | + return servletRequestAttribute.getRequest(); | |
603 | + } catch (NullPointerException e) { | |
604 | + return null; | |
605 | + } | |
606 | + } | |
607 | + | |
608 | + | |
609 | + /** | |
610 | + * @author 최정우 | |
611 | + * @since 2020.01.26 | |
612 | + * | |
613 | + * 현재 client의 HttpSession 조회 | |
614 | + */ | |
615 | + public static HttpSession getHttpSession (boolean create) { | |
616 | + try { | |
617 | + HttpServletRequest request = getHttpServletRequest(); | |
618 | + if (request != null) { | |
619 | + return request.getSession(create); | |
620 | + } else { | |
621 | + return null; | |
622 | + } | |
623 | + } catch (NullPointerException e) { | |
624 | + return null; | |
625 | + } | |
626 | + } | |
627 | + | |
628 | + /** | |
629 | + * @author 김성원 | |
630 | + * @since 2024.01.10 | |
631 | + * | |
632 | + * 사용자 세션 정보 조회 | |
633 | + */ | |
634 | + public static HashMap<String, Object> getHttpSessionMember () { | |
635 | + try { | |
636 | + HttpServletRequest request = getHttpServletRequest(); | |
637 | + if(request.getSession().getAttribute(AuthUtil.LOGIN_USER_SESSION) != null) { | |
638 | + return (HashMap<String, Object>)request.getSession().getAttribute(AuthUtil.LOGIN_USER_SESSION); | |
639 | + }else { | |
640 | + return null; | |
641 | + } | |
642 | + } catch (NullPointerException e) { | |
643 | + return null; | |
644 | + } | |
645 | + } | |
646 | + | |
647 | + /** | |
648 | + * @author 최정우 | |
649 | + * @since 2020.01.26 | |
650 | + * | |
651 | + * HttpServletRequest를 활용한 Client IP 가지고오기 | |
652 | + * Header의 X-FORWARDED-FOR 값을 통해 IP 조회, 만약 Header에 X-FORWARDED-FOR가 없으면 getRemoteAddr() 이걸로 조회 | |
653 | + */ | |
654 | + public static String getClientIp () { | |
655 | + try { | |
656 | + HttpServletRequest request = getHttpServletRequest(); | |
657 | + if (null != request.getHeader("X-FORWARDED-FOR")) { | |
658 | + return request.getHeader("X-FORWARDED-FOR"); | |
659 | + } else { | |
660 | + return request.getRemoteAddr(); | |
661 | + } | |
662 | + } catch (NullPointerException e) { | |
663 | + return null; | |
664 | + } | |
665 | + } | |
666 | + | |
667 | + | |
668 | + | |
669 | + /** | |
670 | + * @author 최정우 | |
671 | + * @since 2019.12.09 | |
672 | + * | |
673 | + * JSONObject to Map<String, Object> | |
674 | + */ | |
675 | + public static Map<String, Object> jsonObjectToMap( JSONObject jsonObj ) { | |
676 | + Map<String, Object> map = null; | |
677 | + try { | |
678 | + map = new ObjectMapper().readValue(jsonObj.toJSONString(), Map.class) ; | |
679 | + | |
680 | + } catch (JsonParseException e) { | |
681 | + e.printStackTrace(); | |
682 | + } catch (JsonMappingException e) { | |
683 | + e.printStackTrace(); | |
684 | + } catch (IOException e) { | |
685 | + e.printStackTrace(); | |
686 | + } | |
687 | + return map; | |
688 | + } | |
689 | + | |
690 | + /** | |
691 | + * @author 최정우 | |
692 | + * @since 2019.12.09 | |
693 | + * | |
694 | + * JSONObject to List<Map<String, Object>> | |
695 | + */ | |
696 | + public static List<Map<String, Object>> jsonArrayToMap( JSONArray jsonObj ) { | |
697 | + List<Map<String, Object>> map = null; | |
698 | + try { | |
699 | + map = new ObjectMapper().readValue(jsonObj.toJSONString(), new TypeReference<List<Map<String, Object>>>(){}) ; | |
700 | + | |
701 | + } catch (JsonParseException e) { | |
702 | + e.printStackTrace(); | |
703 | + } catch (JsonMappingException e) { | |
704 | + e.printStackTrace(); | |
705 | + } catch (IOException e) { | |
706 | + e.printStackTrace(); | |
707 | + } | |
708 | + return map; | |
709 | + } | |
710 | + | |
711 | + /** | |
712 | + * @author 최정우 | |
713 | + * @since 2019.12.09 | |
714 | + * | |
715 | + * xmlStr to JsonStr | |
716 | + */ | |
717 | + public static String xmlStrToJsonStr(String xmlStr) throws Exception { | |
718 | + org.json.JSONObject jObject = XML.toJSONObject(xmlStr); | |
719 | + ObjectMapper mapper = new ObjectMapper(); | |
720 | + mapper.enable(SerializationFeature.INDENT_OUTPUT); | |
721 | + Object json = mapper.readValue(jObject.toString(), Object.class); | |
722 | + String output = mapper.writeValueAsString(json); | |
723 | + return output; | |
724 | + } | |
725 | + | |
726 | + | |
727 | + | |
728 | + /** | |
729 | + * @author 김성원 | |
730 | + * @since 2024.01.10 | |
731 | + * | |
732 | + * 데이터베이스 난수생성 | |
733 | + */ | |
734 | + public static String getRandKey(String prifix) { | |
735 | + SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMddHHmmssSSS"); | |
736 | + long timeInMillis =System.currentTimeMillis(); | |
737 | + Date timeInDate = new Date(timeInMillis); | |
738 | + return prifix+"_"+sdf.format(timeInDate)+UUID.randomUUID().toString().substring(0,5); | |
739 | + } | |
740 | + | |
741 | + /** | |
742 | + * @author 김성원 | |
743 | + * @since 2024.01.10 | |
744 | + * | |
745 | + * 로그인된 사용자 ID 조회 | |
746 | + */ | |
747 | + public static String getLoginUserId() { | |
748 | + String resultId = ""; | |
749 | + HashMap<String, Object> LoginUserInfo = new HashMap<>(); | |
750 | + HttpServletRequest request = CommonUtil.getHttpServletRequest(); | |
751 | + HttpSession session = request.getSession(false); | |
752 | + | |
753 | + if(session != null && session.getAttribute(AuthUtil.LOGIN_USER_SESSION) != null) { | |
754 | + LoginUserInfo = (HashMap<String, Object>)session.getAttribute(AuthUtil.LOGIN_USER_SESSION); | |
755 | + resultId = LoginUserInfo.get("user_id").toString(); | |
756 | + } | |
757 | + | |
758 | + return resultId; | |
759 | + } | |
760 | + | |
761 | + /** | |
762 | + * @author 김성원 | |
763 | + * @since 2024.01.10 | |
764 | + * | |
765 | + * 로그인된 사용자 ID 조회 | |
766 | + */ | |
767 | + public static String getLoginUserDeptCode() { | |
768 | + String resultId = ""; | |
769 | + HashMap<String, Object> LoginUserInfo = new HashMap<>(); | |
770 | + HttpServletRequest request = CommonUtil.getHttpServletRequest(); | |
771 | + HttpSession session = request.getSession(false); | |
772 | + | |
773 | + if(session != null && session.getAttribute(AuthUtil.LOGIN_USER_SESSION) != null) { | |
774 | + LoginUserInfo = (HashMap<String, Object>)session.getAttribute(AuthUtil.LOGIN_USER_SESSION); | |
775 | + resultId = LoginUserInfo.get("dept_code").toString(); | |
776 | + } | |
777 | + | |
778 | + return resultId; | |
779 | + } | |
780 | + | |
781 | + /** | |
782 | + * @author 김성원 | |
783 | + * @since 2024.01.10 | |
784 | + * | |
785 | + * 로그인된 사용자 권한 조회 | |
786 | + */ | |
787 | + public static List<String> getLoginUserAuth() { | |
788 | + List<String> authList = new ArrayList<>(); | |
789 | + HashMap<String, Object> LoginUserInfo = new HashMap<>(); | |
790 | + HttpServletRequest request = CommonUtil.getHttpServletRequest(); | |
791 | + HttpSession session = request.getSession(false); | |
792 | + if(session != null && session.getAttribute(AuthUtil.LOGIN_USER_SESSION) != null) { | |
793 | + LoginUserInfo = (HashMap<String, Object>)session.getAttribute(AuthUtil.LOGIN_USER_SESSION); | |
794 | + authList = (List<String>)LoginUserInfo.get("user_auth"); | |
795 | + } | |
796 | + return authList; | |
797 | + } | |
798 | + | |
799 | + | |
800 | + | |
801 | +} |
+++ src/main/java/com/ajin/ajinerp/common/util/CryptoUtil.java
... | ... | @@ -0,0 +1,221 @@ |
1 | +package com.ajin.ajinerp.common.util; | |
2 | + | |
3 | + | |
4 | +import java.nio.ByteBuffer; | |
5 | +import java.nio.charset.StandardCharsets; | |
6 | +import java.util.Base64; | |
7 | +import java.util.Base64.Decoder; | |
8 | +import java.util.Base64.Encoder; | |
9 | +import java.util.HashMap; | |
10 | +import java.util.Map; | |
11 | + | |
12 | +import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; | |
13 | +import org.springframework.security.crypto.encrypt.AesBytesEncryptor; | |
14 | +import org.springframework.security.crypto.factory.PasswordEncoderFactories; | |
15 | +import org.springframework.security.crypto.password.DelegatingPasswordEncoder; | |
16 | +import org.springframework.security.crypto.password.PasswordEncoder; | |
17 | + | |
18 | +/** | |
19 | + * @author 김성원 | |
20 | + * @since 2024.01.02 | |
21 | + * | |
22 | + * 암호화 관련 클래스 | |
23 | + */ | |
24 | +public class CryptoUtil { | |
25 | + | |
26 | + | |
27 | + private final static String encoderKey = "bcrypt"; | |
28 | + private final static String secret = "takenbmsc!@#"; | |
29 | + private final static String salt = "70726574657374"; | |
30 | + | |
31 | + /** | |
32 | + * @author 김성원 | |
33 | + * @since 2024.01.09 | |
34 | + * | |
35 | + * 기본 단방향 엔코드 생성 | |
36 | + */ | |
37 | + public static PasswordEncoder createDelegatingPasswordEncoder() { | |
38 | + Map<String, PasswordEncoder> encoders = new HashMap<>(); | |
39 | + encoders.put(encoderKey, new BCryptPasswordEncoder()); | |
40 | + return new DelegatingPasswordEncoder(encoderKey, encoders); | |
41 | + } | |
42 | + | |
43 | + /** | |
44 | + * @author 김성원 | |
45 | + * @since 2024.01.09 | |
46 | + * | |
47 | + * 커스텀 key기반의 단방향 엔코드 생성 | |
48 | + */ | |
49 | + public static PasswordEncoder createDelegatingPasswordEncoder(String key) { | |
50 | + Map<String, PasswordEncoder> encoders = new HashMap<>(); | |
51 | + encoders.put(key, new BCryptPasswordEncoder()); | |
52 | + return new DelegatingPasswordEncoder(key, encoders); | |
53 | + } | |
54 | + | |
55 | + | |
56 | + /** | |
57 | + * @author 김성원 | |
58 | + * @since 2024.01.09 | |
59 | + * | |
60 | + * 기본 단방향 암호화 | |
61 | + */ | |
62 | + public static String PasswordEncoder(String data) { | |
63 | + | |
64 | + PasswordEncoder passwordEncoder = PasswordEncoderFactories.createDelegatingPasswordEncoder(); | |
65 | + Encoder encoder = Base64.getEncoder(); | |
66 | + return encoder.encodeToString(passwordEncoder.encode(data).getBytes(StandardCharsets.UTF_8)) ; | |
67 | + } | |
68 | + | |
69 | + /** | |
70 | + * @author 김성원 | |
71 | + * @since 2024.01.09 | |
72 | + * | |
73 | + * 커스텀 key기반의 단방향 암호화 | |
74 | + */ | |
75 | + public static String PasswordEncoder(String key , String data) { | |
76 | + | |
77 | + if(StringUtil.isEmpty(data)) { | |
78 | + return data; | |
79 | + } | |
80 | + | |
81 | + PasswordEncoder passwordEncoder = createDelegatingPasswordEncoder(key); | |
82 | + | |
83 | + return passwordEncoder.encode(data); | |
84 | + } | |
85 | + | |
86 | + | |
87 | + | |
88 | + /** | |
89 | + * @author 김성원 | |
90 | + * @since 2024.01.09 | |
91 | + * | |
92 | + * 단방향 암호화 비교구문 | |
93 | + */ | |
94 | + public static boolean passwordMatch(String data, String checkData) { | |
95 | + | |
96 | + PasswordEncoder passwordEncoder = PasswordEncoderFactories.createDelegatingPasswordEncoder(); | |
97 | + Decoder decoder = Base64.getDecoder(); | |
98 | + return passwordEncoder.matches(data,new String(decoder.decode(checkData), StandardCharsets.UTF_8) ); | |
99 | + | |
100 | + } | |
101 | + | |
102 | + | |
103 | + /** | |
104 | + * @author 김성원 | |
105 | + * @since 2024.01.09 | |
106 | + * | |
107 | + * 기본 key, salt 기반의 양방향 암호화 객체 생성 | |
108 | + */ | |
109 | + public static AesBytesEncryptor aesBytesEncryptor() { | |
110 | + return new AesBytesEncryptor("232323", salt); | |
111 | + } | |
112 | + | |
113 | + /** | |
114 | + * @author 김성원 | |
115 | + * @since 2024.01.09 | |
116 | + * | |
117 | + * 커스텀 key, salt 기반의 양방향 암호화 객체 생성 | |
118 | + */ | |
119 | + public static AesBytesEncryptor aesBytesEncryptor(String key, String salt) { | |
120 | + return new AesBytesEncryptor(key, salt); | |
121 | + | |
122 | + } | |
123 | + | |
124 | + /** | |
125 | + * @author 김성원 | |
126 | + * @since 2024.01.09 | |
127 | + * | |
128 | + * 기본 key, salt 기반의 양방향 암호화 | |
129 | + */ | |
130 | + public static String encryptData(String data) { | |
131 | + if(StringUtil.isEmpty(data)) { | |
132 | + return data; | |
133 | + } | |
134 | + AesBytesEncryptor bytesEncryptor = aesBytesEncryptor(); | |
135 | + byte[] encrypt = bytesEncryptor.encrypt(data.getBytes(StandardCharsets.UTF_8)); | |
136 | + Encoder encoder = Base64.getEncoder(); | |
137 | + return encoder.encodeToString(encrypt); | |
138 | + } | |
139 | + | |
140 | + /** | |
141 | + * @author 김성원 | |
142 | + * @since 2024.01.09 | |
143 | + * | |
144 | + * 커스텀 key, salt 기반의 양방향 암호화 | |
145 | + */ | |
146 | + public static String encryptData(String key, String salt, String data) { | |
147 | + if(StringUtil.isEmpty(data)) { | |
148 | + return data; | |
149 | + } | |
150 | + AesBytesEncryptor bytesEncryptor = aesBytesEncryptor(key, salt); | |
151 | + byte[] encrypt = bytesEncryptor.encrypt(data.getBytes(StandardCharsets.UTF_8)); | |
152 | + Encoder encoder = Base64.getEncoder(); | |
153 | + return encoder.encodeToString(encrypt); | |
154 | + } | |
155 | + | |
156 | + | |
157 | + | |
158 | + /** | |
159 | + * @author 김성원 | |
160 | + * @since 2024.01.09 | |
161 | + * | |
162 | + * 기본 key, salt 기반의 양방향 복호화 | |
163 | + */ | |
164 | + public static String decryptData(String data) { | |
165 | + if(StringUtil.isEmpty(data)) { | |
166 | + return data; | |
167 | + } | |
168 | + AesBytesEncryptor bytesEncryptor = aesBytesEncryptor(); | |
169 | + Decoder decoder = Base64.getDecoder(); | |
170 | + byte[] decrypt = bytesEncryptor.decrypt(decoder.decode(data)); | |
171 | + return new String(decrypt, StandardCharsets.UTF_8); | |
172 | + } | |
173 | + | |
174 | + /** | |
175 | + * @author 김성원 | |
176 | + * @since 2024.01.09 | |
177 | + * | |
178 | + * 커스텀 key, salt 기반의 양방향 복호화 | |
179 | + */ | |
180 | + public static String decryptData(String key, String salt, String data) { | |
181 | + if(StringUtil.isEmpty(data)) { | |
182 | + return data; | |
183 | + } | |
184 | + AesBytesEncryptor bytesEncryptor = aesBytesEncryptor(key, salt); | |
185 | + Decoder decoder = Base64.getDecoder(); | |
186 | + byte[] decrypt = bytesEncryptor.decrypt(decoder.decode(data)); | |
187 | + return new String(decrypt, StandardCharsets.UTF_8); | |
188 | + } | |
189 | + | |
190 | + | |
191 | + /** | |
192 | + * @author 김성원 | |
193 | + * @since 2024.01.09 | |
194 | + * | |
195 | + * * 바이트 스트링 변환 | |
196 | + */ | |
197 | + public static String byteArrayToString(byte[] bytes) { | |
198 | + StringBuilder sb = new StringBuilder(); | |
199 | + for (byte abyte :bytes){ | |
200 | + sb.append(abyte); | |
201 | + sb.append(" "); | |
202 | + } | |
203 | + return sb.toString(); | |
204 | + } | |
205 | + | |
206 | + /** | |
207 | + * @author 김성원 | |
208 | + * @since 2024.01.09 | |
209 | + * | |
210 | + * 스트링 바이트 변환 | |
211 | + */ | |
212 | + public static byte[] stringToByteArray(String byteString) { | |
213 | + String[] split = byteString.split("\\s"); | |
214 | + ByteBuffer buffer = ByteBuffer.allocate(split.length); | |
215 | + for (String s : split) { | |
216 | + buffer.put((byte) Integer.parseInt(s)); | |
217 | + } | |
218 | + return buffer.array(); | |
219 | + } | |
220 | + | |
221 | +} |
+++ src/main/java/com/ajin/ajinerp/common/util/PaginationSupport.java
... | ... | @@ -0,0 +1,32 @@ |
1 | +package com.ajin.ajinerp.common.util; | |
2 | + | |
3 | +/** | |
4 | + * 페이징 지원 객체 입니다. | |
5 | + * | |
6 | + * @author 서영석 | |
7 | + * @since 2023.10.24 | |
8 | + */ | |
9 | +public class PaginationSupport { | |
10 | + | |
11 | + //한 페이지당 보여질 데이터 개수 (Default) | |
12 | + private final static int PER_PAGE = 10; | |
13 | + | |
14 | + /** | |
15 | + * @author 서영석 | |
16 | + * @since 2023.10.24 | |
17 | + * 내용 : PostgreSQL 데이터 | |
18 | + */ | |
19 | + public static int pagingRowIndexForPostgreSql (int currentPage) { | |
20 | + return pagingRowIndexForPostgreSql(currentPage, PER_PAGE); | |
21 | + } | |
22 | + /** | |
23 | + * @author 서영석 | |
24 | + * @since 2023.10.24 | |
25 | + * 내용 : PostgreSQL 데이터 | |
26 | + */ | |
27 | + public static int pagingRowIndexForPostgreSql (int currentPage, int perPage) { | |
28 | + int startIndex = 0; | |
29 | + startIndex = (currentPage - 1) * perPage; | |
30 | + return startIndex; | |
31 | + } | |
32 | +} |
+++ src/main/java/com/ajin/ajinerp/common/util/SesssionEventListener.java
... | ... | @@ -0,0 +1,292 @@ |
1 | +package com.ajin.ajinerp.common.util; | |
2 | + | |
3 | +import org.slf4j.Logger; | |
4 | +import org.slf4j.LoggerFactory; | |
5 | + | |
6 | +import jakarta.servlet.annotation.WebListener; | |
7 | +import jakarta.servlet.http.HttpSession; | |
8 | +import jakarta.servlet.http.HttpSessionEvent; | |
9 | +import jakarta.servlet.http.HttpSessionListener; | |
10 | +import java.security.NoSuchAlgorithmException; | |
11 | +import java.security.SecureRandom; | |
12 | +import java.util.*; | |
13 | +import java.util.concurrent.ConcurrentHashMap; | |
14 | + | |
15 | +/** | |
16 | + * @author 서영석 | |
17 | + * @since 2023.05.31 | |
18 | + * | |
19 | + * Custom session 저장소를 만들어 놓고 | |
20 | + * Tomcat이 관리하는 session 생성 또는 소멸시, 발생하는 이벤트를 활용하여 (HttpSessionListener를 통해 이벤트를 받을 수 있음) | |
21 | + * Custom session 저장소에 추가, 삭제를 통해 | |
22 | + * session을 적절히 controll 하기위한 목적을 가진 Class 입니다. | |
23 | + */ | |
24 | +@WebListener | |
25 | +public class SesssionEventListener implements HttpSessionListener { | |
26 | + | |
27 | + private static final Logger LOGGER = LoggerFactory.getLogger(SesssionEventListener.class); | |
28 | + | |
29 | + //싱글턴패턴 사용을 위한 클래스변수 | |
30 | + public static SesssionEventListener sesssionEventListener = null; | |
31 | + | |
32 | + //싱글턴패턴으로 객체 생성 후 리턴. | |
33 | + public static synchronized SesssionEventListener getInstance() { | |
34 | + if(sesssionEventListener == null) { | |
35 | + sesssionEventListener = new SesssionEventListener(); | |
36 | + } | |
37 | + return sesssionEventListener; | |
38 | + } | |
39 | + | |
40 | + /** | |
41 | + * Custom session 저장소 (tomcat이 관리하고있는 실제 session저장소는 아님) 목록 | |
42 | + * ConcurrentHashMap을 사용하는 이유 : | |
43 | + * HashMap은 Thread Safe 하지 않기 때문에 싱글턴 패턴에서 해당 session 저장소를 사용하기 위해서는 Thread Safe 한 ConcurrentHashMap를 사용 | |
44 | + * HashTable도 Thread Safe 하지만, 읽기 쓰기 둘다 한개의 Thread만 접근 가능함 | |
45 | + * ConcurrentHashMap은 쓰기에서한 한개의 Tread만 접근 가능하도록 해놓음 (읽기는 여러개의 쓰레드에서 동시 접근 가능) | |
46 | + */ | |
47 | + private static final Map<String, HttpSession> sessions = new ConcurrentHashMap<>(); | |
48 | + | |
49 | + /** | |
50 | + * @author 서영석 | |
51 | + * @since 2023.05.31 | |
52 | + * | |
53 | + * @param userId : 사용자(회원) ID | |
54 | + * | |
55 | + * userId와 동일한 로그인 session을 가진 session ID 목록 조회 | |
56 | + */ | |
57 | + public synchronized static List<String> duplicationLoginSessionIdSelectListByUserId (String userId) { | |
58 | + List<String> result = new ArrayList<>(); | |
59 | + try { | |
60 | + //Custom session 저장소에서 session ID는 다르지만 userId가 같은게 존재하는지 확인 | |
61 | + for (String key : sessions.keySet()) { | |
62 | + HttpSession session = sessions.get(key); | |
63 | + if (session == null || session.getAttribute(AuthUtil.LOGIN_USER_SESSION) == null) { | |
64 | + //세션이 존재하고, 로그인 정보가 없으면 continue; | |
65 | + continue; | |
66 | + } else { | |
67 | + //로그인 정보가 있으면 -> 중복 확인 | |
68 | + HashMap<String, Object> loginUser = (HashMap<String, Object>) session.getAttribute(AuthUtil.LOGIN_USER_SESSION); | |
69 | + String loginUserId = (String) loginUser.get("user_id"); | |
70 | + | |
71 | + /** 사용자(회원) ID와 동일한 로그인 정보 일 시 -> add **/ | |
72 | + if (userId.equals(loginUserId) == true) { | |
73 | + result.add(session.getId()); | |
74 | + } else { | |
75 | + //동일한 로그인 정보가 아니면 -> continue; | |
76 | + continue; | |
77 | + } | |
78 | + } | |
79 | + } | |
80 | + } catch (NullPointerException e) { | |
81 | + LOGGER.error(e.toString()); | |
82 | + } | |
83 | + | |
84 | + return result; | |
85 | + } | |
86 | + | |
87 | + | |
88 | + /** | |
89 | + * @author 서영석 | |
90 | + * @since 2023.05.31 | |
91 | + * | |
92 | + * 현재 client의 정보와 중복된 로그인 session ID 목록 조회 | |
93 | + * | |
94 | + * 현재 User의 세션과 Custom session 저장소에 저장된 session 중 | |
95 | + * session ID는 다르지만 userId가 같은 session List return | |
96 | + */ | |
97 | + public synchronized static List<String> duplicationLoginSessionIdSelectList () { | |
98 | + List<String> result = new ArrayList<>(); | |
99 | + | |
100 | + try { | |
101 | + //현재 사용자의 session | |
102 | + HttpSession currentUserSession = CommonUtil.getHttpSession(false); | |
103 | + //현재 사용자의 session이 존재하고, 로그인 정보가 있을 때 | |
104 | + if (currentUserSession != null && currentUserSession.getAttribute(AuthUtil.LOGIN_USER_SESSION) == null) { | |
105 | + //현재 사용자의 로그인 정보 | |
106 | + HashMap<String, Object> currentLoginUser = (HashMap<String, Object>) currentUserSession.getAttribute(AuthUtil.LOGIN_USER_SESSION); | |
107 | + String currentLoginUserId = (String) currentLoginUser.get("user_id"); | |
108 | + | |
109 | + //Custom session 저장소에서 session ID는 다르지만 userId가 같은게 존재하는지 확인 | |
110 | + for (String key : sessions.keySet()) { | |
111 | + HttpSession session = sessions.get(key); | |
112 | + if (session == null || session.getAttribute(AuthUtil.LOGIN_USER_SESSION) == null) { | |
113 | + //세션이 존재하고, 로그인 정보가 없으면 continue; | |
114 | + continue; | |
115 | + } else if (currentUserSession.getId().equals(session.getId()) == true) { | |
116 | + //동일한 세션 ID이면 continue; | |
117 | + continue; | |
118 | + } else { | |
119 | + //로그인 정보가 있으면 -> 중복 확인 | |
120 | + HashMap<String, Object> duplicationLoginUser = (HashMap<String, Object>) session.getAttribute(AuthUtil.LOGIN_USER_SESSION); | |
121 | + String duplicationLoginUserId = (String) duplicationLoginUser.get("user_id"); | |
122 | + | |
123 | + /** 동일한 로그인 정보 일 시 -> add **/ | |
124 | + if (currentLoginUserId.equals(duplicationLoginUserId) == true) { | |
125 | + result.add(session.getId()); | |
126 | + } else { | |
127 | + //동일한 로그인 정보가 아니면 -> continue; | |
128 | + continue; | |
129 | + } | |
130 | + } | |
131 | + } | |
132 | + } | |
133 | + } catch (NullPointerException e) { | |
134 | + LOGGER.error(e.toString()); | |
135 | + } | |
136 | + | |
137 | + return result; | |
138 | + } | |
139 | + | |
140 | + /** | |
141 | + * @author 서영석 | |
142 | + * @since 2023.05.31 | |
143 | + * | |
144 | + * @param userId : 사용자(회원) ID | |
145 | + * | |
146 | + * userId와 동일한 로그인 session을 가진 session ID 목록 삭제 | |
147 | + */ | |
148 | + public static int duplicationLoginSessionDeleteByUserId (String userId) { | |
149 | + int result = 0; | |
150 | + try { | |
151 | + List<String> sessionIds = duplicationLoginSessionIdSelectListByUserId(userId); | |
152 | + for (int i = 0; i < sessionIds.size(); i++) { | |
153 | + //Custom session 저장소에서 session 무효화 시키기 | |
154 | + sessions.get(sessionIds.get(i)).invalidate(); | |
155 | + //Custom session 저장소에서 session 삭제 | |
156 | + sessions.remove(sessionIds.get(i)); | |
157 | + } | |
158 | + } catch (NullPointerException e) { | |
159 | + LOGGER.error(e.toString()); | |
160 | + } | |
161 | + return result; | |
162 | + } | |
163 | + | |
164 | + /** | |
165 | + * @author 서영석 | |
166 | + * @since 2023.05.31 | |
167 | + * | |
168 | + * 현재 client의 정보와 중복된 로그인 session 전부 무효화 시키기 (완전 삭제는 못시킴) | |
169 | + */ | |
170 | + public static int duplicationLoginSessionDeleteAll () { | |
171 | + int result = 0; | |
172 | + try { | |
173 | + List<String> sessionIds = duplicationLoginSessionIdSelectList(); | |
174 | + for (int i = 0; i < sessionIds.size(); i++) { | |
175 | + //Custom session 저장소에서 session 무효화 시키기 | |
176 | + sessions.get(sessionIds.get(i)).invalidate(); | |
177 | + //Custom session 저장소에서 session 삭제 | |
178 | + sessions.remove(sessionIds.get(i)); | |
179 | + } | |
180 | + } catch (NullPointerException e) { | |
181 | + LOGGER.error(e.toString()); | |
182 | + } | |
183 | + return result; | |
184 | + } | |
185 | + | |
186 | + //난수생성 | |
187 | + public static String generateRandomHex(int length) { | |
188 | + SecureRandom random = new SecureRandom(); | |
189 | + byte[] randomBytes = new byte[length / 2]; // 16진수 문자열의 길이에 맞게 바이트 배열 크기를 조절 | |
190 | + | |
191 | + random.nextBytes(randomBytes); | |
192 | + | |
193 | + // 바이트 배열을 16진수 문자열로 변환 | |
194 | + StringBuilder hexStringBuilder = new StringBuilder(); | |
195 | + for (byte b : randomBytes) { | |
196 | + hexStringBuilder.append(String.format("%02x", b)); | |
197 | + } | |
198 | + | |
199 | + return hexStringBuilder.toString(); | |
200 | + } | |
201 | + | |
202 | + /** | |
203 | + * HttpSessionListener Interface로 부터 상속 받은 메소드 | |
204 | + * | |
205 | + * tomcat에서 session이 생성되었을 때(session timeout), 발생하는 이벤트 | |
206 | + * @param target : session 이벤트(생성) 객체 | |
207 | + * | |
208 | + * session 생성 이벤트가 발생하면 Custom session 저장소(sessions)에 해당 session ID 값을 Key로 잡고 저장 | |
209 | + * (※ Default로 session에 현재 Client의 IP를 넣어줌) | |
210 | + */ | |
211 | + @Override | |
212 | + public void sessionCreated(HttpSessionEvent target) { | |
213 | + //System.out.println("sessionCreated - 현재 세션 개수 : " + sessions.size() + "개"); | |
214 | + int i = 1; | |
215 | + for (String key : sessions.keySet()) { | |
216 | + HttpSession hs = sessions.get(key); | |
217 | + //System.out.println("sessionCreated - 세션 목록 " + (i++) + ". " + hs.getId()); | |
218 | + } | |
219 | +// System.out.println("sessionCreated - 이제 추가될 session id : " + target.getSession().getId()); | |
220 | + //System.out.println(""); | |
221 | + //System.out.println(""); | |
222 | + | |
223 | + // session에 key(salt) 값 넣기 시작 | |
224 | + HashMap<String, Object> key = new HashMap<String, Object>(); | |
225 | + | |
226 | + // "SHA1PRNG"은 알고리즘 이름 | |
227 | +// SecureRandom random = null; | |
228 | +// try { | |
229 | +// random = SecureRandom.getInstance("SHA1PRNG"); | |
230 | +// } catch (NoSuchAlgorithmException e) { | |
231 | +// e.printStackTrace(); | |
232 | +// } | |
233 | +// SecureRandom random = new SecureRandom(); | |
234 | +// | |
235 | +// byte[] saltBytes = new byte[24]; | |
236 | +// byte[] encKeyBytes = new byte[24]; | |
237 | +// byte[] ivBytes = new byte[24]; | |
238 | +// random.nextBytes(saltBytes); | |
239 | +// random.nextBytes(encKeyBytes); | |
240 | +// random.nextBytes(ivBytes); | |
241 | + //SALT 생성 | |
242 | +// String salt = Base64.getEncoder().encodeToString(saltBytes); | |
243 | +// String ENC_KEY = Base64.getEncoder().encodeToString(encKeyBytes); | |
244 | +// String iv = Base64.getEncoder().encodeToString(ivBytes); | |
245 | + String salt = generateRandomHex(32); | |
246 | + String ENC_KEY = generateRandomHex(32); | |
247 | + String iv = generateRandomHex(32); | |
248 | + key.put("salt",salt); | |
249 | + key.put("ENC_KEY",ENC_KEY); | |
250 | + key.put("iv",iv); | |
251 | + | |
252 | + target.getSession().setAttribute("key", key); | |
253 | + | |
254 | +// System.out.println("key : "+key); | |
255 | + //종료 | |
256 | + | |
257 | + | |
258 | + //현재 Client의 IP set | |
259 | + target.getSession().setAttribute("ip", CommonUtil.getClientIp()); | |
260 | +// target.getSession().setAttribute("key",); | |
261 | +// System.out.println("target test1: "+target); | |
262 | +// System.out.println("target.getSession() test1: "+target.getSession()); | |
263 | +// System.out.println("sessions test1: "+sessions); | |
264 | +// System.out.println("sessions test2: "+sessions.get(target.getSession().getId())); | |
265 | +// System.out.println("CommonUtil.getClientIp() test: "+CommonUtil.getClientIp()); | |
266 | +// System.out.println("target.getSession() test: "+target.getSession()); | |
267 | + | |
268 | + //세션 저장소에 set | |
269 | + sessions.put(target.getSession().getId(), target.getSession()); | |
270 | + } | |
271 | + | |
272 | + /** | |
273 | + * HttpSessionListener Interface로 부터 상속 받은 메소드 | |
274 | + * | |
275 | + * tomcat에서 session이 소멸되었을 때, 발생하는 이벤트 | |
276 | + * @param target : session 이벤트(소멸) 객체 | |
277 | + * | |
278 | + * session 제거 이벤트가 발생하면 Custom session 저장소(sessions)에 해당 session ID 값을 가지고 있는 session 무효화 및 제거 | |
279 | + */ | |
280 | + @Override | |
281 | + public void sessionDestroyed(HttpSessionEvent target) { | |
282 | + //소멸된 세션 Custom session 저장소에서 가지고 오기 | |
283 | + if (sessions.get(target.getSession().getId()) != null) { | |
284 | + //소멸된 세션 무효화 시키기 (가능한지 모르겠지만, 일단 작성해봄) | |
285 | + sessions.get(target.getSession().getId()).invalidate(); | |
286 | + //Custom session 저장소에서 해당 session 삭제 | |
287 | + sessions.remove(target.getSession().getId()); | |
288 | + } else { | |
289 | + return; | |
290 | + } | |
291 | + } | |
292 | +}(파일 끝에 줄바꿈 문자 없음) |
+++ src/main/java/com/ajin/ajinerp/common/util/StringUtil.java
... | ... | @@ -0,0 +1,712 @@ |
1 | +package com.ajin.ajinerp.common.util; | |
2 | + | |
3 | + | |
4 | +import java.io.UnsupportedEncodingException; | |
5 | +import java.sql.Timestamp; | |
6 | +import java.text.SimpleDateFormat; | |
7 | +import java.util.ArrayList; | |
8 | +import java.util.Calendar; | |
9 | +import java.util.Date; | |
10 | +import java.util.GregorianCalendar; | |
11 | +import java.util.Locale; | |
12 | +import java.util.Random; | |
13 | + | |
14 | +import org.slf4j.Logger; | |
15 | +import org.slf4j.LoggerFactory; | |
16 | +import org.springframework.boot.web.servlet.server.Encoding.Type; | |
17 | + | |
18 | + | |
19 | +/** | |
20 | + * @author 최정우 | |
21 | + * @since 2019.11.13 | |
22 | + * | |
23 | + * 문자열과 관련된 기능을 정의 해놓은 Util입니다. | |
24 | + */ | |
25 | +public class StringUtil { | |
26 | + | |
27 | + private static final Logger LOGGER = LoggerFactory.getLogger(StringUtil.class); | |
28 | + | |
29 | + public static final String NULL_TEXT = "NULL"; | |
30 | + | |
31 | + public static String toString(Object obj) { | |
32 | + if (obj == null) { | |
33 | + return null; | |
34 | + } else { | |
35 | + try { | |
36 | + return obj.toString(); | |
37 | + } catch (Exception e) { | |
38 | + return null; | |
39 | + } | |
40 | + } | |
41 | + } | |
42 | + | |
43 | + public static String toStringNotNull(Object obj) { | |
44 | + if (obj == null) { | |
45 | + return ""; | |
46 | + } else { | |
47 | + try { | |
48 | + return obj.toString(); | |
49 | + } catch (Exception e) { | |
50 | + return ""; | |
51 | + } | |
52 | + } | |
53 | + } | |
54 | + | |
55 | + /** | |
56 | + * @author 최정우 | |
57 | + * @since 2020.11.26 | |
58 | + * | |
59 | + * 객체를 문자열로 바꾼 후, 문자열 길이 반환 | |
60 | + */ | |
61 | + public static int stringLength(Object obj) { | |
62 | + if (obj == null) { | |
63 | + return 0; | |
64 | + } else { | |
65 | + try { | |
66 | + return obj.toString().length(); | |
67 | + } catch (Exception e) { | |
68 | + return 0; | |
69 | + } | |
70 | + } | |
71 | + } | |
72 | + | |
73 | + /** | |
74 | + * @author 최정우 | |
75 | + * @since 2020.11.26 | |
76 | + * | |
77 | + * 문자열이 Null or null or NULL인 경우 실제 null값 세팅 | |
78 | + */ | |
79 | + public static boolean isNullText(String text) { | |
80 | + if (isEmpty(text) == false && text.toUpperCase().equals(NULL_TEXT)) { | |
81 | + return true; | |
82 | + } else { | |
83 | + return false; | |
84 | + } | |
85 | + } | |
86 | + | |
87 | + /** | |
88 | + * @author 최정우 | |
89 | + * @since 2019.11.13 | |
90 | + * | |
91 | + * 빈 문자열 검사 | |
92 | + */ | |
93 | + public static boolean isEmpty(String text) { | |
94 | + return text == null || text.trim().length() == 0; | |
95 | + } | |
96 | + | |
97 | + /** | |
98 | + * @author 최정우 | |
99 | + * @since 2019.11.13 | |
100 | + * | |
101 | + * indexOf - 문자 검색 후, 해당 문자의 위치(index)반환 | |
102 | + */ | |
103 | + public static int indexOf(String text, String searchText) { | |
104 | + if (text == null || searchText == null) { | |
105 | + return -1; | |
106 | + } | |
107 | + return text.indexOf(searchText); | |
108 | + } | |
109 | + | |
110 | + /** | |
111 | + * @author 최정우 | |
112 | + * @since 2019.11.13 | |
113 | + * | |
114 | + * lastIndexOf - 문자 검색 후, 해당 문자의 위치(index)반환 | |
115 | + */ | |
116 | + public static int lastIndexOf(String text, String searchText) { | |
117 | + if (text == null || searchText == null) { | |
118 | + return -1; | |
119 | + } | |
120 | + return text.lastIndexOf(searchText); | |
121 | + } | |
122 | + | |
123 | + /** | |
124 | + * @author 최정우 | |
125 | + * @since 2019.11.13 | |
126 | + * | |
127 | + * substringBetween - 특정 문자열 사이에 값을 뽑아내는 메서드 | |
128 | + */ | |
129 | + public static String substringBetween(String text, String startText, String endText) { | |
130 | + if (isEmpty(text) == true || isEmpty(startText) == true || isEmpty(endText) == true) { | |
131 | + return null; | |
132 | + } | |
133 | + text = text.toLowerCase(); | |
134 | + startText = startText.toLowerCase(); | |
135 | + endText = endText.toLowerCase(); | |
136 | + | |
137 | + int start = text.indexOf(startText); | |
138 | + if (start != -1) { | |
139 | + int end = text.indexOf(endText, start + startText.length()); | |
140 | + if (end != -1) { | |
141 | + return text.substring(start + startText.length(), end); | |
142 | + } | |
143 | + } | |
144 | + return null; | |
145 | + } | |
146 | + | |
147 | + /** | |
148 | + * @author 최정우 | |
149 | + * @since 2019.11.13 | |
150 | + * | |
151 | + * 모든 공백 제거 | |
152 | + */ | |
153 | + public static String removeSpace(String text) { | |
154 | + if (isEmpty(text)) { | |
155 | + return text; | |
156 | + } | |
157 | + int length = text.length(); | |
158 | + char[] newCharList = new char[length]; | |
159 | + int count = 0; | |
160 | + for (int i = 0; i < length; i++) { | |
161 | + if (Character.isWhitespace(text.charAt(i)) == false) { | |
162 | + newCharList[count++] = text.charAt(i); | |
163 | + } | |
164 | + } | |
165 | + if (count == length) { | |
166 | + return text; | |
167 | + } | |
168 | + | |
169 | + return new String(newCharList, 0, count); | |
170 | + } | |
171 | + | |
172 | + | |
173 | + | |
174 | + /** | |
175 | + * @author 최정우 | |
176 | + * @since 2019.11.13 | |
177 | + * | |
178 | + * 소문자 변환 | |
179 | + */ | |
180 | + public static String lowerCase(String text) { | |
181 | + if (isEmpty(text) == true) { | |
182 | + return text; | |
183 | + } else { | |
184 | + return text.toLowerCase(); | |
185 | + } | |
186 | + } | |
187 | + | |
188 | + /** | |
189 | + * 대문자 변환 | |
190 | + */ | |
191 | + public static String upperCase(String text) { | |
192 | + if (isEmpty(text) == true) { | |
193 | + return text; | |
194 | + } else { | |
195 | + return text.toUpperCase(); | |
196 | + } | |
197 | + } | |
198 | + | |
199 | + /** | |
200 | + * @author 최정우 | |
201 | + * @since 2019.11.13 | |
202 | + * | |
203 | + * 현재날짜(년,월,일)를 구하는 기능 | |
204 | + */ | |
205 | + public static String getToday() { | |
206 | + String pattern = "yyyy-MM-dd"; | |
207 | + SimpleDateFormat dateFormat = new SimpleDateFormat(pattern, Locale.KOREA); | |
208 | + Timestamp timestamp = new Timestamp(System.currentTimeMillis()); | |
209 | + return dateFormat.format(timestamp.getTime()); | |
210 | + } | |
211 | + | |
212 | + /** | |
213 | + * @author 최정우 | |
214 | + * @since 2019.11.13 | |
215 | + * | |
216 | + * 현재날짜(년,월,일)를 구하는 기능 | |
217 | + */ | |
218 | + public static String getToday(String pattern) { | |
219 | + String defaultPattern = "yyyy-MM-dd"; | |
220 | + if (isEmpty(pattern) == true) { | |
221 | + pattern = defaultPattern; | |
222 | + } | |
223 | + | |
224 | + SimpleDateFormat dateFormat = null; | |
225 | + try { | |
226 | + dateFormat = new SimpleDateFormat(pattern, Locale.KOREA); | |
227 | + } catch (Exception e) { | |
228 | + dateFormat = new SimpleDateFormat(defaultPattern, Locale.KOREA); | |
229 | + } | |
230 | + Timestamp timestamp = new Timestamp(System.currentTimeMillis()); | |
231 | + return dateFormat.format(timestamp.getTime()); | |
232 | + } | |
233 | + | |
234 | + | |
235 | + /** | |
236 | + * @author 김성원 | |
237 | + * @since 2019.11.13 | |
238 | + * | |
239 | + * 현재날짜(년,월,일)에 특정 날짜 + - | |
240 | + */ | |
241 | + public static String getTodayaddDate(String pattern, String type, int date) { | |
242 | + String defaultPattern = "yyyy-MM-dd"; | |
243 | + if (isEmpty(pattern) == true) { | |
244 | + pattern = defaultPattern; | |
245 | + } | |
246 | + | |
247 | + SimpleDateFormat dateFormat = null; | |
248 | + try { | |
249 | + dateFormat = new SimpleDateFormat(pattern, Locale.KOREA); | |
250 | + } catch (Exception e) { | |
251 | + dateFormat = new SimpleDateFormat(defaultPattern, Locale.KOREA); | |
252 | + } | |
253 | + | |
254 | + Timestamp timestamp = new Timestamp(System.currentTimeMillis()); | |
255 | + Calendar cal = Calendar.getInstance(); | |
256 | + if(type.equals("year")) { | |
257 | + cal.add(Calendar.YEAR, date); | |
258 | + }else if(type.equals("month")) { | |
259 | + cal.add(Calendar.MONTH, date); | |
260 | + }else if(type.equals("day")) { | |
261 | + cal.add(Calendar.DATE, date); | |
262 | + } | |
263 | + | |
264 | + return dateFormat.format(cal.getTime()); | |
265 | + } | |
266 | + | |
267 | + /** | |
268 | + * @author 최정우 | |
269 | + * @since 2019.11.13 | |
270 | + * | |
271 | + * 현재날짜(년,월,일)를 구하는 기능 | |
272 | + */ | |
273 | + public static String getToday(String yearSuffix, String monthSuffix, String daySuffix) { | |
274 | + String defaultPattern = "yyyy년MM월dd일"; | |
275 | + if (isEmpty(yearSuffix) == true) { | |
276 | + yearSuffix = ""; | |
277 | + } | |
278 | + if (isEmpty(monthSuffix) == true) { | |
279 | + monthSuffix = ""; | |
280 | + } | |
281 | + if (isEmpty(daySuffix) == true) { | |
282 | + daySuffix = ""; | |
283 | + } | |
284 | + | |
285 | + String pattern = "yyyy" + yearSuffix + "MM" + monthSuffix + "dd" + daySuffix; | |
286 | + | |
287 | + SimpleDateFormat dateFormat = null; | |
288 | + try { | |
289 | + dateFormat = new SimpleDateFormat(pattern, Locale.KOREA); | |
290 | + } catch (Exception e) { | |
291 | + dateFormat = new SimpleDateFormat(defaultPattern, Locale.KOREA); | |
292 | + } | |
293 | + Timestamp timestamp = new Timestamp(System.currentTimeMillis()); | |
294 | + return dateFormat.format(timestamp.getTime()); | |
295 | + } | |
296 | + | |
297 | + /** | |
298 | + * @author 최정우 | |
299 | + * @since 2019.11.13 | |
300 | + * | |
301 | + * 17자리의 현재일시를 구하는 기능 | |
302 | + */ | |
303 | + public static String getDateTime() { | |
304 | + // 문자열로 변환하기 위한 패턴 설정(년도-월-일 시:분:초:초(자정이후 초)) | |
305 | + String pattern = "yyyyMMddHHmmssSSS"; | |
306 | + SimpleDateFormat dateFormat = new SimpleDateFormat(pattern, Locale.KOREA); | |
307 | + Timestamp timestamp = new Timestamp(System.currentTimeMillis()); | |
308 | + return dateFormat.format(timestamp.getTime()); | |
309 | + } | |
310 | + | |
311 | + /** | |
312 | + * @author 최정우 | |
313 | + * @since 2019.11.13 | |
314 | + * | |
315 | + * 원하는 패턴의 현재일시 구하는 기능 | |
316 | + */ | |
317 | + public static String getDateTime(String pattern) { | |
318 | + // 문자열로 변환하기 위한 패턴 설정(년도-월-일 시:분:초:초(자정이후 초)) | |
319 | + String defaultPattern = "yyyyMMddHHmmssSSS"; | |
320 | + if (isEmpty(pattern)) { | |
321 | + pattern = defaultPattern; | |
322 | + } | |
323 | + SimpleDateFormat dateFormat = null; | |
324 | + try { | |
325 | + dateFormat = new SimpleDateFormat(pattern, Locale.KOREA); | |
326 | + } catch (Exception e) { | |
327 | + dateFormat = new SimpleDateFormat(defaultPattern, Locale.KOREA); | |
328 | + } | |
329 | + Timestamp timestamp = new Timestamp(System.currentTimeMillis()); | |
330 | + return dateFormat.format(timestamp.getTime()); | |
331 | + } | |
332 | + | |
333 | + /** | |
334 | + * @author 최정우 | |
335 | + * @since 2019.11.13 | |
336 | + * | |
337 | + * 현재 일시 - addDay => 원하는 패턴의 일시를 구하는 기능 | |
338 | + */ | |
339 | + public static String getDateTime(String pattern, int addDay) { | |
340 | + // 문자열로 변환하기 위한 패턴 설정(년도-월-일 시:분:초:초(자정이후 초)) | |
341 | + String defaultPattern = "yyyyMMddHHmmssSSS"; | |
342 | + if (pattern == null) { | |
343 | + pattern = defaultPattern; | |
344 | + } | |
345 | + SimpleDateFormat dateFormat = null; | |
346 | + try { | |
347 | + dateFormat = new SimpleDateFormat(pattern, Locale.KOREA); | |
348 | + } catch (Exception e) { | |
349 | + dateFormat = new SimpleDateFormat(defaultPattern, Locale.KOREA); | |
350 | + } | |
351 | + Calendar cal = new GregorianCalendar(); | |
352 | + cal.add(Calendar.DATE, addDay); | |
353 | + Date date = cal.getTime(); | |
354 | + return dateFormat.format(date.getTime()); | |
355 | + } | |
356 | + | |
357 | + /** | |
358 | + * @author 최정우 | |
359 | + * @since 2019.11.13 | |
360 | + * | |
361 | + * 현재 일시 - addDay => 원하는 패턴의 일시를 구하는 기능 | |
362 | + */ | |
363 | + public static String getDateTime(String pattern, int addDay, int addHour, int addMin, int addSec) { | |
364 | + // 문자열로 변환하기 위한 패턴 설정(년도-월-일 시:분:초:초(자정이후 초)) | |
365 | + String defaultPattern = "yyyyMMddHHmmssSSS"; | |
366 | + if (pattern == null) { | |
367 | + pattern = defaultPattern; | |
368 | + } | |
369 | + SimpleDateFormat dateFormat = null; | |
370 | + try { | |
371 | + dateFormat = new SimpleDateFormat(pattern, Locale.KOREA); | |
372 | + } catch (Exception e) { | |
373 | + dateFormat = new SimpleDateFormat(defaultPattern, Locale.KOREA); | |
374 | + } | |
375 | + Calendar cal = new GregorianCalendar(); | |
376 | + cal.add(Calendar.DATE, addDay); | |
377 | + cal.add(Calendar.HOUR, addHour); | |
378 | + cal.add(Calendar.MINUTE, addMin); | |
379 | + cal.add(Calendar.SECOND, addSec); | |
380 | + Date date = cal.getTime(); | |
381 | + return dateFormat.format(date.getTime()); | |
382 | + } | |
383 | + | |
384 | + /** | |
385 | + * @author 최정우 | |
386 | + * @since 2019.11.13 | |
387 | + * | |
388 | + * 현재 일시(17자리)와, 랜덤숫자(4자리)를 이용하여 키값 생성 | |
389 | + */ | |
390 | + public static String getCreateKey (String prefix) { | |
391 | + int random = new Random().nextInt(9999); | |
392 | + String result = prefix + "_" + getDateTime() + "_" + numberToText(random, 4); | |
393 | + return result; | |
394 | + } | |
395 | + | |
396 | + /** | |
397 | + * @author 최정우 | |
398 | + * @since 2019.11.13 | |
399 | + * | |
400 | + * 문자열이 Date문자열(yyyy-MM-dd)로 포맷 가능한지 | |
401 | + * text: 문자열 | |
402 | + * pattern: 문자열의 날짜 패턴 | |
403 | + */ | |
404 | + public static boolean isDate(String text, String pattern) { | |
405 | + try { | |
406 | + Date date = new SimpleDateFormat(pattern).parse(text); | |
407 | + text = new SimpleDateFormat("yyyy-MM-dd").format(date); | |
408 | + return true; | |
409 | + } catch (java.text.ParseException e) { | |
410 | + // TODO Auto-generated catch block | |
411 | + return false; | |
412 | + } | |
413 | + } | |
414 | + | |
415 | + /** | |
416 | + * @author 최정우 | |
417 | + * @since 2019.11.13 | |
418 | + * | |
419 | + * 문자열을 날짜형태로 Convert | |
420 | + * text: 문자열 | |
421 | + * pattern: 문자열의 날짜 패턴 | |
422 | + * newPattern: 해당 문자열을 Converting할 날짜 패턴 | |
423 | + */ | |
424 | + public static String textToDateText (String text, String pattern, String newPattern) { | |
425 | + String defaultPattern = "yyyy-MM-dd"; | |
426 | + if (isEmpty(newPattern) == true) { | |
427 | + newPattern = defaultPattern; | |
428 | + } | |
429 | + | |
430 | + SimpleDateFormat dateFormat = new SimpleDateFormat(pattern); | |
431 | + Date date = new Date(); | |
432 | + try { | |
433 | + date = dateFormat.parse(text); | |
434 | + dateFormat.applyPattern(newPattern); | |
435 | + return dateFormat.format(date); | |
436 | + } catch (Exception e) { | |
437 | + //e.printStackTrace(); | |
438 | + return text; | |
439 | + } | |
440 | + } | |
441 | + | |
442 | + /** | |
443 | + * @author 최정우 | |
444 | + * @since 2019.11.13 | |
445 | + * | |
446 | + * 숫자 -> 문자열 -> 문자열 길이가 length보다 작을 때, length길이 만큼될 수 있도록 앞에 '0'을 붙여줌 | |
447 | + */ | |
448 | + public static String numberToText (int number, int length) { | |
449 | + String text = Integer.toString(number); | |
450 | + if (text.length() < length) { | |
451 | + int emptyLength = length - text.length(); | |
452 | + for (int i = 0; i < emptyLength; i++) { | |
453 | + text = "0" + text; | |
454 | + } | |
455 | + } | |
456 | + return text; | |
457 | + } | |
458 | + | |
459 | + /** | |
460 | + * @author 최정우 | |
461 | + * @since 2019.11.13 | |
462 | + * | |
463 | + * 문자열이 지정한 길이를 초과했을때 해당 문자열을 삭제하는 메서드 | |
464 | + * @param text 원본 문자열 배열 | |
465 | + * @param maxLength 지정길이 | |
466 | + * @return 지정길이로 자른 문자열 | |
467 | + */ | |
468 | + public static String cutString(String text, int maxLength) { | |
469 | + String result = null; | |
470 | + if (text != null) { | |
471 | + if (text.length() > maxLength) { | |
472 | + result = text.substring(0, maxLength); | |
473 | + } else | |
474 | + result = text; | |
475 | + } | |
476 | + return result; | |
477 | + } | |
478 | + | |
479 | + | |
480 | + /** | |
481 | + * @author 최정우 | |
482 | + * @since 2019.11.13 | |
483 | + * | |
484 | + * 문자열이 지정한 길이를 초과했을때 지정한길이에다가 해당 문자열을 붙여주는 메서드. | |
485 | + * @param text 원본 문자열 배열 | |
486 | + * @param addText 더할문자열 | |
487 | + * @param maxLength 지정길이 | |
488 | + * @return 지정길이로 잘라서 더할분자열 합친 문자열 | |
489 | + */ | |
490 | + public static String cutString(String text, String addText, int maxLength) { | |
491 | + String result = null; | |
492 | + if (text != null) { | |
493 | + if (text.length() > maxLength) { | |
494 | + result = text.substring(0, maxLength) + addText; | |
495 | + } else | |
496 | + result = text; | |
497 | + } | |
498 | + return result; | |
499 | + } | |
500 | + | |
501 | + | |
502 | + /** | |
503 | + * @author 최정우 | |
504 | + * @since 2019.11.13 | |
505 | + * | |
506 | + * <p>기준 문자열에 포함된 모든 대상 문자(char)를 제거한다.</p> | |
507 | + * | |
508 | + * <pre> | |
509 | + * StringUtil.remove(null, *) = null | |
510 | + * StringUtil.remove("", *) = "" | |
511 | + * StringUtil.remove("queued", 'u') = "qeed" | |
512 | + * StringUtil.remove("queued", 'z') = "queued" | |
513 | + * </pre> | |
514 | + * | |
515 | + * @param str 입력받는 기준 문자열 | |
516 | + * @param remove 입력받는 문자열에서 제거할 대상 문자열 | |
517 | + * @return 제거대상 문자열이 제거된 입력문자열. 입력문자열이 null인 경우 출력문자열은 null | |
518 | + */ | |
519 | + public static String remove(String text, char remove) { | |
520 | + if (isEmpty(text) || text.indexOf(remove) == -1) { | |
521 | + return text; | |
522 | + } | |
523 | + char[] chars = text.toCharArray(); | |
524 | + int pos = 0; | |
525 | + for (int i = 0; i < chars.length; i++) { | |
526 | + if (chars[i] != remove) { | |
527 | + chars[pos++] = chars[i]; | |
528 | + } | |
529 | + } | |
530 | + | |
531 | + return new String(chars, 0, pos); | |
532 | + } | |
533 | + | |
534 | + | |
535 | + /** | |
536 | + * @author 최정우 | |
537 | + * @since 2019.11.13 | |
538 | + * | |
539 | + * 원본 문자열의 포함된 특정 문자열을 새로운 문자열로 변환하는 메서드 | |
540 | + * @param source 원본 문자열 | |
541 | + * @param subject 원본 문자열에 포함된 특정 문자열 | |
542 | + * @param object 변환할 문자열 | |
543 | + * @return sb.toString() 새로운 문자열로 변환된 문자열 | |
544 | + */ | |
545 | + public static String replace(String text, String subject, String object) { | |
546 | + StringBuffer rtnStr = new StringBuffer(); | |
547 | + String preStr = ""; | |
548 | + String nextStr = text; | |
549 | + String srcStr = text; | |
550 | + | |
551 | + while (srcStr.indexOf(subject) >= 0) { | |
552 | + preStr = srcStr.substring(0, srcStr.indexOf(subject)); | |
553 | + nextStr = srcStr.substring(srcStr.indexOf(subject) + subject.length(), srcStr.length()); | |
554 | + srcStr = nextStr; | |
555 | + rtnStr.append(preStr).append(object); | |
556 | + } | |
557 | + rtnStr.append(nextStr); | |
558 | + return rtnStr.toString(); | |
559 | + } | |
560 | + | |
561 | + /** | |
562 | + * @author 최정우 | |
563 | + * @since 2019.11.13 | |
564 | + * | |
565 | + * 원본 문자열의 포함된 특정 문자열 첫번째 한개만 새로운 문자열로 변환하는 메서드 | |
566 | + * @param source 원본 문자열 | |
567 | + * @param subject 원본 문자열에 포함된 특정 문자열 | |
568 | + * @param object 변환할 문자열 | |
569 | + * @return sb.toString() 새로운 문자열로 변환된 문자열 / source 특정문자열이 없는 경우 원본 문자열 | |
570 | + */ | |
571 | + public static String replaceOnce(String source, String subject, String object) { | |
572 | + StringBuffer rtnStr = new StringBuffer(); | |
573 | + String preStr = ""; | |
574 | + String nextStr = source; | |
575 | + if (source.indexOf(subject) >= 0) { | |
576 | + preStr = source.substring(0, source.indexOf(subject)); | |
577 | + nextStr = source.substring(source.indexOf(subject) + subject.length(), source.length()); | |
578 | + rtnStr.append(preStr).append(object).append(nextStr); | |
579 | + return rtnStr.toString(); | |
580 | + } else { | |
581 | + return source; | |
582 | + } | |
583 | + } | |
584 | + | |
585 | + /** | |
586 | + * @author 최정우 | |
587 | + * @since 2019.11.13 | |
588 | + * | |
589 | + * <code>subject</code>에 포함된 각각의 문자를 object로 변환한다. | |
590 | + * | |
591 | + * @param source 원본 문자열 | |
592 | + * @param subject 원본 문자열에 포함된 특정 문자열 | |
593 | + * @param object 변환할 문자열 | |
594 | + * @return sb.toString() 새로운 문자열로 변환된 문자열 | |
595 | + */ | |
596 | + public static String replaceChar(String source, String subject, String object) { | |
597 | + StringBuffer rtnStr = new StringBuffer(); | |
598 | + String preStr = ""; | |
599 | + String nextStr = source; | |
600 | + String srcStr = source; | |
601 | + | |
602 | + char chA; | |
603 | + | |
604 | + for (int i = 0; i < subject.length(); i++) { | |
605 | + chA = subject.charAt(i); | |
606 | + | |
607 | + if (srcStr.indexOf(chA) >= 0) { | |
608 | + preStr = srcStr.substring(0, srcStr.indexOf(chA)); | |
609 | + nextStr = srcStr.substring(srcStr.indexOf(chA) + 1, srcStr.length()); | |
610 | + srcStr = rtnStr.append(preStr).append(object).append(nextStr).toString(); | |
611 | + } | |
612 | + } | |
613 | + | |
614 | + return srcStr; | |
615 | + } | |
616 | + | |
617 | + /** | |
618 | + * @author 최정우 | |
619 | + * @since 2019.11.13 | |
620 | + * | |
621 | + * 문자열을 다양한 문자셋(EUC-KR[KSC5601],UTF-8..)을 사용하여 인코딩하는 기능 역으로 디코딩하여 원래의 문자열을 | |
622 | + * 복원하는 기능을 제공함 String temp = new String(문자열.getBytes("바꾸기전 인코딩"),"바꿀 인코딩"); | |
623 | + * String temp = new String(문자열.getBytes("8859_1"),"KSC5601"); => UTF-8 에서 | |
624 | + * EUC-KR | |
625 | + * | |
626 | + * @param text - 문자열 | |
627 | + * @param encoding - 원래의 인코딩된 값 | |
628 | + * @param decoding - 디코딩할 문자값 | |
629 | + * @return 인(디)코딩 문자열 | |
630 | + * @exception MyException | |
631 | + * @see | |
632 | + */ | |
633 | + public static String textDecoding(String text, String encoding, String decoding) { | |
634 | + if (text == null) { | |
635 | + return null; | |
636 | + } | |
637 | + | |
638 | + try { | |
639 | + text = new String(text.getBytes(encoding), decoding); | |
640 | + } catch (UnsupportedEncodingException e) { | |
641 | + text = null; | |
642 | + } | |
643 | + | |
644 | + return text; | |
645 | + } | |
646 | + | |
647 | + | |
648 | + /** | |
649 | + * @author 최정우 | |
650 | + * @since 2020.11.26 | |
651 | + * | |
652 | + * 문자열 특정 포맷팅으로 변환 ##-#### | |
653 | + */ | |
654 | + public static String formatConvert(String data, String format) { | |
655 | + | |
656 | + StringBuilder bf = new StringBuilder(); | |
657 | + | |
658 | + if(StringUtil.isEmpty(format) || StringUtil.isEmpty(data)) { | |
659 | + bf.append(data); | |
660 | + }else { | |
661 | + int num = data.length()-1; | |
662 | + for(int i = format.length()-1 ; i >= 0 ; i--) { | |
663 | + if(format.charAt(i) == '#') { | |
664 | + bf.insert(0, data.charAt(num--)); | |
665 | + }else { | |
666 | + bf.insert(0,format.charAt(i)); | |
667 | + } | |
668 | + } | |
669 | + } | |
670 | + | |
671 | + return bf.toString(); | |
672 | + } | |
673 | + | |
674 | + /** | |
675 | + * @author 김성원 | |
676 | + * @since 2022.07.06 | |
677 | + * | |
678 | + * 날짜형식 문자열 특정 포맷팅으로 변환 ##-#### | |
679 | + */ | |
680 | + public static String dateConvert(String date) { | |
681 | + | |
682 | + StringBuilder bf = new StringBuilder(); | |
683 | + | |
684 | + boolean dateForm = true; | |
685 | + | |
686 | + if(!date.contains("-") && date.length() > 4) { | |
687 | + dateForm = false; | |
688 | + } | |
689 | + | |
690 | + if(!StringUtil.isEmpty(date)) { | |
691 | + | |
692 | + String dateStr = date.replaceAll("[^0-9]", ""); | |
693 | + // 년도 처리 | |
694 | + if(dateStr.length() < 5) { | |
695 | + bf.append(date.substring(0,4)); | |
696 | + }else { | |
697 | + if(dateForm == true) { | |
698 | + bf.append(StringUtil.formatConvert(dateStr.substring(0,6),"####-##")); | |
699 | + }else { | |
700 | + bf.append(StringUtil.formatConvert(dateStr.substring(0,6),"####-##")); | |
701 | + //bf.append(dateStr.substring(0,4)); | |
702 | + //bf.append("년 "); | |
703 | + } | |
704 | + } | |
705 | + } | |
706 | + | |
707 | + return bf.toString(); | |
708 | + } | |
709 | + | |
710 | + | |
711 | + | |
712 | +} |
+++ src/main/java/com/ajin/ajinerp/common/util/bean/ApplicationContextProvider.java
... | ... | @@ -0,0 +1,44 @@ |
1 | +package com.ajin.ajinerp.common.util.bean; | |
2 | +import org.springframework.beans.BeansException; | |
3 | +import org.springframework.context.ApplicationContext; | |
4 | +import org.springframework.context.ApplicationContextAware; | |
5 | +import org.springframework.stereotype.Component; | |
6 | + | |
7 | +/** | |
8 | + * @author 최정우 | |
9 | + * @since 2019.11.17 | |
10 | + * | |
11 | + * Spring 컨테이너(ApplicationContext)에 접근하기 위한 Class 입니다. | |
12 | + * ApplicationContextAware 구현체 | |
13 | + */ | |
14 | +@Component | |
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 | +}(파일 끝에 줄바꿈 문자 없음) |
+++ src/main/java/com/ajin/ajinerp/common/util/bean/BeanUtil.java
... | ... | @@ -0,0 +1,42 @@ |
1 | +package com.ajin.ajinerp.common.util.bean; | |
2 | + | |
3 | +import org.springframework.beans.BeansException; | |
4 | + | |
5 | +/** | |
6 | + * @author 최정우 | |
7 | + * @since 2020.11.25 | |
8 | + * | |
9 | + * ApplicationContextProvider에서 bean객체를 얻어 활용할 수 있도록 해주는 Util 입니다. | |
10 | + */ | |
11 | +public class BeanUtil { | |
12 | + | |
13 | + /** | |
14 | + * @author 최정우 | |
15 | + * @since 2019.11.17 | |
16 | + * | |
17 | + * 해당 어플리케이션에서 스프링 컨테이너가 관리하는 bean으로 등록된 객체를 이름으로 호출 | |
18 | + */ | |
19 | + public static Object getBean(String beanName) { | |
20 | + try { | |
21 | + return ApplicationContextProvider.getApplicationContext().getBean(beanName); | |
22 | + } catch (BeansException e) { | |
23 | + e.printStackTrace(); | |
24 | + return null; | |
25 | + } | |
26 | + } | |
27 | + | |
28 | + /** | |
29 | + * @author 최정우 | |
30 | + * @since 2019.11.17 | |
31 | + * | |
32 | + * 해당 어플리케이션에서 스프링 컨테이너가 관리하는 bean으로 등록된 객체를 객체의 타입으로 호출 | |
33 | + */ | |
34 | + public static Object getBean(Class<?> classType) { | |
35 | + try { | |
36 | + return ApplicationContextProvider.getApplicationContext().getBean(classType); | |
37 | + } catch (BeansException e) { | |
38 | + e.printStackTrace(); | |
39 | + return null; | |
40 | + } | |
41 | + } | |
42 | +} |
+++ src/main/java/com/ajin/ajinerp/common/util/reflection/ParentLastURLClassLoader.java
... | ... | @@ -0,0 +1,88 @@ |
1 | +package com.ajin.ajinerp.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 | +}(파일 끝에 줄바꿈 문자 없음) |
+++ src/main/java/com/ajin/ajinerp/common/util/reflection/ReflectionUtil.java
... | ... | @@ -0,0 +1,223 @@ |
1 | +package com.ajin.ajinerp.common.util.reflection; | |
2 | + | |
3 | + | |
4 | +import com.ajin.ajinerp.common.util.StringUtil; | |
5 | +import com.ajin.ajinerp.common.util.bean.BeanUtil; | |
6 | + | |
7 | +import java.io.File; | |
8 | +import java.lang.reflect.Method; | |
9 | +import java.net.URL; | |
10 | + | |
11 | +/** | |
12 | + * @author 최정우 | |
13 | + * @since 2020.11.25 | |
14 | + * | |
15 | + * Reflection - 클래스, 인터페이스, 메소드관련 인스턴스화(로드) 및 실행 관련 Util입니다. | |
16 | + */ | |
17 | +public class ReflectionUtil { | |
18 | + | |
19 | + /******************************************** Class 단 ********************************************/ | |
20 | + /** | |
21 | + * @author 최정우 | |
22 | + * @since 2020.11.25 | |
23 | + * | |
24 | + * classLoad - 어플리케이션 내부(+Bean객체포함) OR 외부의 class 파일을 저장된 경로를 통해 class 파일 로드 후, 객체 생성 | |
25 | + * | |
26 | + * classFullName과 classFilePath를 통해 실제 클래스를 인스턴스화함. | |
27 | + * 1. Class.forName을 통해 어플리케이션 내부의 class path에 있는 class객체 생성 | |
28 | + * 2. 어플리케이션 내부에 class가 존재할 때 | |
29 | + * 2-1. 어플리케이션의 Spring 컨테이너에 해당 클래스 타입으로 생성된 Bean이 있는지 확인 | |
30 | + * => 존재할 때, Bean 객체 주입 | |
31 | + * => 존재하지 않을 때, 객체 생성 | |
32 | + * 3. 어플리케이션 내부에 class가 존재하지 않을 때 | |
33 | + * 3-1. class or jar file이 저장된 경로를 이용하여 클래스를 로드 | |
34 | + * | |
35 | + * 4. 객체 생성 실패시, Log 기록 및 다음 작업 목록으로 넘어감 | |
36 | + */ | |
37 | + public static Object classAndBeanLoad (String classFilePath, String classFullName) { | |
38 | + Object clazz = null; | |
39 | + try { | |
40 | + //Class.forName을 통해 어플리케이션 내부의 class path에 있는 class객체 생성 | |
41 | + Class<?> c = forName(classFullName); | |
42 | + if (c != null) {//어플리케이션 내부에 class가 존재할 때 | |
43 | + //플리케이션의 Spring 컨테이너에 해당 클래스 타입으로 생성된 Bean이 있는지 확인 후, Bean 객체 주입 | |
44 | + clazz = BeanUtil.getBean(c); | |
45 | + | |
46 | + if (clazz == null) {//Bean 객체 존재하지 않을 때 | |
47 | + clazz = newInstance(c); | |
48 | + } | |
49 | + } else {//어플리케이션 내부에 class가 존재하지 않을 때 | |
50 | + //class or jar file이 저장된 경로 | |
51 | + //file 경로 값이 있을 때만 클래스를 로드함 | |
52 | + if (StringUtil.isEmpty(classFilePath) == false) { | |
53 | + if (StringUtil.isEmpty(classFullName) == false) { | |
54 | + clazz = classLoad(classFilePath, classFullName); | |
55 | + } else { | |
56 | + clazz = classLoad(classFilePath); | |
57 | + } | |
58 | + } | |
59 | + } | |
60 | + } catch (Exception e) { | |
61 | + e.printStackTrace(); | |
62 | + } | |
63 | + | |
64 | + return clazz; | |
65 | + } | |
66 | + | |
67 | + /** | |
68 | + * @author 최정우 | |
69 | + * @since 2019.11.17 | |
70 | + * | |
71 | + * forName - 어플리케이션 내부의 class path에 있는 class객체 생성 | |
72 | + * | |
73 | + * classFullName = package명 + class명 | |
74 | + */ | |
75 | + public static Class<?> forName (String classFullName) { | |
76 | + try { | |
77 | + return Class.forName(classFullName); | |
78 | + } catch (Exception e) { | |
79 | + e.printStackTrace(); | |
80 | + return null; | |
81 | + } | |
82 | + } | |
83 | + | |
84 | + /** | |
85 | + * @author 최정우 | |
86 | + * @since 2019.11.17 | |
87 | + * | |
88 | + * classLoad - 어플리케이션 내부 OR 외부의 class 파일을 저장된 경로를 통해 class 파일 로드 후, 객체 생성 | |
89 | + * 주로 외부 class파일을 로드할 때 쓰임 | |
90 | + * | |
91 | + * classFilePath - 클래스파일 절대경로 | |
92 | + * classFullName = package명 + class명 | |
93 | + */ | |
94 | + public static Object classLoad (String classFilePath, String classFullName) { | |
95 | + try { | |
96 | + File file = new File(classFilePath); | |
97 | + //실제 경로상에 있는 .class파일을 통해 class를 읽어옴 | |
98 | + ParentLastURLClassLoader classLoader = new ParentLastURLClassLoader(new URL[] { file.toURI().toURL() }); | |
99 | + //읽어온 .class파일을 이용해 해당되는 패키지 내에 있는 class를 로드해 옴 | |
100 | + Class<?> c = classLoader.loadClass(classFullName); | |
101 | + //class를 new 객체 생성함 | |
102 | + return newInstance(c); | |
103 | + } catch (Exception e) { | |
104 | + e.printStackTrace(); | |
105 | + return null; | |
106 | + } | |
107 | + } | |
108 | + | |
109 | + /** | |
110 | + * @author 최정우 | |
111 | + * @since 2019.11.17 | |
112 | + * | |
113 | + * classLoad - 어플리케이션 내부 OR 외부의 class 파일을 저장된 경로를 통해 class 파일 로드 후, 객체 생성 | |
114 | + * 주로 외부 class파일을 로드할 때 쓰임 | |
115 | + * class명을 모를 때 사용 | |
116 | + * | |
117 | + * classFilePath - 클래스파일 절대경로 | |
118 | + */ | |
119 | + public static Object classLoad (String classFilePath) { | |
120 | + try { | |
121 | + File file = new File(classFilePath); | |
122 | + //실제 경로상에 있는 .class파일을 통해 class를 읽어옴 | |
123 | + ParentLastURLClassLoader classLoader = new ParentLastURLClassLoader(new URL[] { file.toURI().toURL() }); | |
124 | + //읽어온 .class파일을 이용해 해당되는 패키지 내에 있는 class를 로드해 옴 | |
125 | + Class<?> c = classLoader.getClass(); | |
126 | + //class를 new 객체 생성함 | |
127 | + return newInstance(c); | |
128 | + } catch (Exception e) { | |
129 | + e.printStackTrace(); | |
130 | + return null; | |
131 | + } | |
132 | + } | |
133 | + | |
134 | + /** | |
135 | + * @author 최정우 | |
136 | + * @since 2019.11.17 | |
137 | + * | |
138 | + * newInstance - 객체 인스턴스화(로드) | |
139 | + */ | |
140 | + public static Object newInstance(Class<?> c) { | |
141 | + try { | |
142 | + return c.newInstance(); | |
143 | + } catch (Exception e) { | |
144 | + e.printStackTrace(); | |
145 | + return null; | |
146 | + } | |
147 | + } | |
148 | + | |
149 | + /******************************************** Class 단 ********************************************/ | |
150 | + | |
151 | + | |
152 | + | |
153 | + /******************************************** Method 단 ********************************************/ | |
154 | + /** | |
155 | + * @author 최정우 | |
156 | + * @since 2019.11.17 | |
157 | + * | |
158 | + * invokeByMethodName - 메소드 이름을 통한 메소드 호출 | |
159 | + * | |
160 | + * clazz - 인스턴스화(로드)된 객체 | |
161 | + * methodName - 메소드명 | |
162 | + * paramValues - 메소드의 파라메터 값 | |
163 | + * paramTypes - 메소드의 파라메터 타입 | |
164 | + * (주의 paramValues, paramTypes 순서가 같아야함) | |
165 | + */ | |
166 | + public static Object invokeByMethodName (Object clazz, String methodName, Object[] paramValues, Class<?>[] paramTypes) { | |
167 | + try { | |
168 | + Method method = null; | |
169 | + if (paramValues != null && paramTypes != null | |
170 | + && paramValues.length > 0 && paramTypes.length > 0 | |
171 | + && paramValues.length == paramTypes.length) { | |
172 | + | |
173 | + System.out.println("clazz getPackage : " + clazz.getClass().getPackage()); | |
174 | + System.out.println("clazz name : " + clazz.getClass().getName()); | |
175 | + if (paramValues != null && paramValues.length > 0) { | |
176 | + System.out.println("clazz param value : " + paramValues[0].toString()); | |
177 | + System.out.println("clazz param type : " + paramTypes[0].getTypeName()); | |
178 | + } | |
179 | + | |
180 | + //메소드 객체 가지고오기 | |
181 | + method = clazz.getClass().getMethod(methodName, paramTypes); | |
182 | + } else { | |
183 | + //메소드 객체 가지고오기 | |
184 | + method = clazz.getClass().getMethod(methodName); | |
185 | + } | |
186 | + | |
187 | + //메소드 호출 | |
188 | + return invoke(clazz, method, paramValues); | |
189 | + | |
190 | + } catch (Exception e) { | |
191 | + e.printStackTrace(); | |
192 | + return null; | |
193 | + } | |
194 | + | |
195 | + } | |
196 | + | |
197 | + /** | |
198 | + * @author 최정우 | |
199 | + * @since 2019.11.17 | |
200 | + * | |
201 | + * invoke - 메소드 호출 | |
202 | + * | |
203 | + * clazz - 인스턴스화(로드)된 객체 | |
204 | + * method - 메소드 객체 | |
205 | + * paramValues - 메소드의 파라메터 값 | |
206 | + */ | |
207 | + public static Object invoke (Object clazz, Method method, Object[] paramValues) { | |
208 | + try { | |
209 | + if (paramValues != null && paramValues.length > 0) { | |
210 | + //메소드 호출 | |
211 | + return method.invoke(clazz, paramValues); | |
212 | + } else { | |
213 | + //메소드 호출 | |
214 | + return method.invoke(clazz); | |
215 | + } | |
216 | + } catch (Exception e) { | |
217 | + e.printStackTrace(); | |
218 | + return null; | |
219 | + } | |
220 | + | |
221 | + } | |
222 | + /******************************************** Method 단 ********************************************/ | |
223 | +} |
+++ src/main/java/com/ajin/ajinerp/common/vo/CheckMessage.java
... | ... | @@ -0,0 +1,73 @@ |
1 | +package com.ajin.ajinerp.common.vo; | |
2 | + | |
3 | +import lombok.Getter; | |
4 | +import lombok.Setter; | |
5 | + | |
6 | +/** | |
7 | + * @author 김성원 | |
8 | + * @since 2024.01.04 | |
9 | + * | |
10 | + * 데이터 체크, 유효성 검사 등과 같이 검사와 관련된 변수를 정의한 Class 입니다. | |
11 | + */ | |
12 | +@Getter | |
13 | +@Setter | |
14 | +public class CheckMessage { | |
15 | + | |
16 | + public CheckMessage() {} | |
17 | + | |
18 | + public CheckMessage(boolean isSuccess) { | |
19 | + this.isSuccess = isSuccess; | |
20 | + } | |
21 | + | |
22 | + public CheckMessage(String message) { | |
23 | + this.message = message; | |
24 | + } | |
25 | + | |
26 | + public CheckMessage(boolean isSuccess, String message) { | |
27 | + this.isSuccess = isSuccess; | |
28 | + this.message = message; | |
29 | + } | |
30 | + | |
31 | + public CheckMessage(boolean isSuccess, String message, int status) { | |
32 | + this.isSuccess = isSuccess; | |
33 | + this.message = message; | |
34 | + this.status = status; | |
35 | + } | |
36 | + | |
37 | + public CheckMessage(boolean isSuccess, String message, String error) { | |
38 | + this.isSuccess = isSuccess; | |
39 | + this.message = message; | |
40 | + this.error = error; | |
41 | + } | |
42 | + | |
43 | + /** | |
44 | + * 체크 완료(사용가능 or 성공) 여부 | |
45 | + */ | |
46 | + private boolean isSuccess; | |
47 | + | |
48 | + /** | |
49 | + * 체크한 상태의 메세지값 | |
50 | + */ | |
51 | + private String message; | |
52 | + | |
53 | + /** | |
54 | + * 에러 메세지 | |
55 | + */ | |
56 | + private String error; | |
57 | + | |
58 | + /** | |
59 | + * 체크한 상태의 상태값 -> 상황마다 다름 | |
60 | + */ | |
61 | + private int status; | |
62 | + | |
63 | + | |
64 | + // 오류처리 | |
65 | + public void setError(String message) { | |
66 | + this.message = message; | |
67 | + this.error = message; | |
68 | + this.isSuccess = false; | |
69 | + this.status = 0; | |
70 | + } | |
71 | + | |
72 | + | |
73 | +} |
+++ src/main/java/com/ajin/ajinerp/common/vo/CustomeResultMap.java
... | ... | @@ -0,0 +1,27 @@ |
1 | +package com.ajin.ajinerp.common.vo; | |
2 | +import lombok.Getter; | |
3 | +import lombok.Setter; | |
4 | +import org.springframework.http.HttpStatus; | |
5 | + | |
6 | +import java.util.HashMap; | |
7 | + | |
8 | +/** | |
9 | + * 컨트롤러의 데이터를 반환할 기본 Map클래스 | |
10 | + * | |
11 | + * @author 김성원 | |
12 | + * @since 2023.12.28 | |
13 | + */ | |
14 | +@Getter | |
15 | +@Setter | |
16 | +public class CustomeResultMap { | |
17 | + | |
18 | + // 결과메세지 | |
19 | + private CheckMessage checkMessage; | |
20 | + | |
21 | + // 결과 데이터 | |
22 | + private HashMap<String,Object> resultData = new HashMap<String,Object>(); | |
23 | + | |
24 | + public CustomeResultMap(){ | |
25 | + checkMessage = new CheckMessage(true, "성공" , 200); | |
26 | + } | |
27 | +} |
+++ src/main/java/com/ajin/ajinerp/common/vo/SearchObject.java
... | ... | @@ -0,0 +1,43 @@ |
1 | +package com.ajin.ajinerp.common.vo; | |
2 | +import lombok.Getter; | |
3 | +import lombok.Setter; | |
4 | + | |
5 | +/** | |
6 | + * @author 김성원 | |
7 | + * @since 2024.01.09 | |
8 | + * | |
9 | + * 공통 검색용 VO 입니다 | |
10 | + */ | |
11 | +@Getter | |
12 | +@Setter | |
13 | +public class SearchObject { | |
14 | + | |
15 | + /** | |
16 | + * 검색 key | |
17 | + */ | |
18 | + private String key; | |
19 | + | |
20 | + /** | |
21 | + * 검색 값 | |
22 | + */ | |
23 | + private Object value; | |
24 | + | |
25 | + | |
26 | + /** | |
27 | + * 검색 key | |
28 | + */ | |
29 | + private String key2; | |
30 | + | |
31 | + /** | |
32 | + * 검색 값 | |
33 | + */ | |
34 | + private Object value2; | |
35 | + | |
36 | + | |
37 | + /** | |
38 | + * 데이터 타입(날짜 : date, 숫자 : int, 문자 : string, 체크 : bool, 날짜쌍 : dates) | |
39 | + */ | |
40 | + private String type; | |
41 | + | |
42 | + | |
43 | +} |
+++ src/main/java/com/ajin/ajinerp/common/vo/SearchVO.java
... | ... | @@ -0,0 +1,80 @@ |
1 | +package com.ajin.ajinerp.common.vo; | |
2 | +import java.util.ArrayList; | |
3 | +import java.util.List; | |
4 | + | |
5 | +import com.sun.jna.platform.win32.Sspi; | |
6 | +import com.sun.jna.platform.win32.Sspi.TimeStamp; | |
7 | +import jdk.jfr.Timestamp; | |
8 | +import lombok.Getter; | |
9 | +import lombok.Setter; | |
10 | + | |
11 | +/** | |
12 | + * @author 김성원 | |
13 | + * @since 2024.01.09 | |
14 | + * | |
15 | + * 공통 검색 VO 입니다 | |
16 | + */ | |
17 | +@Getter | |
18 | +@Setter | |
19 | +public class SearchVO { | |
20 | + | |
21 | + /** | |
22 | + * 검색Keyword | |
23 | + */ | |
24 | + private List<SearchObject> searchObjectList = new ArrayList<SearchObject>(); | |
25 | + | |
26 | + | |
27 | + /** | |
28 | + * 정렬 기준 (컬럼명) | |
29 | + */ | |
30 | + private String order = ""; | |
31 | + | |
32 | + /** | |
33 | + * 정렬 타입 | |
34 | + * true - ASC | |
35 | + * false - DESC | |
36 | + */ | |
37 | + private boolean orderASC = true; | |
38 | + | |
39 | + /** | |
40 | + * 현재페이지 | |
41 | + */ | |
42 | + private int currentPage = 1; | |
43 | + | |
44 | + /** | |
45 | + * 페이지갯수 | |
46 | + */ | |
47 | + private int perPage = 10; | |
48 | + | |
49 | + /** | |
50 | + * 총 개시물 수 | |
51 | + */ | |
52 | + private int totalRows; | |
53 | + | |
54 | + /** | |
55 | + * 검색 key | |
56 | + */ | |
57 | + private String searchText; | |
58 | + | |
59 | + /** | |
60 | + * 검색 값 | |
61 | + */ | |
62 | + private Object value; | |
63 | + | |
64 | + | |
65 | + /** | |
66 | + * 검색 key | |
67 | + */ | |
68 | + private String key2; | |
69 | + | |
70 | + /** | |
71 | + * 검색 값 | |
72 | + */ | |
73 | + private Object value2; | |
74 | + | |
75 | + | |
76 | + /** | |
77 | + * 데이터 타입(날짜 : date, 숫자 : int, 문자 : string, 체크 : bool, 날짜쌍 : dates) | |
78 | + */ | |
79 | + private String type; | |
80 | +} |
+++ src/main/java/com/ajin/ajinerp/user/member/dao/LoginDAO.java
... | ... | @@ -0,0 +1,25 @@ |
1 | +package com.ajin.ajinerp.user.member.dao; | |
2 | + | |
3 | +import com.ajin.ajinerp.user.member.vo.LoginLogVO; | |
4 | +import com.ajin.ajinerp.user.member.vo.Member; | |
5 | +import org.apache.ibatis.annotations.Mapper; | |
6 | + | |
7 | +/** | |
8 | + * @author 이세현 | |
9 | + * @since 2024.03.08 | |
10 | + * | |
11 | + * 로그인 처리 관련 DAO 클래스 | |
12 | + */ | |
13 | +@Mapper | |
14 | +public interface LoginDAO { | |
15 | + /** | |
16 | + * @author 이세현 | |
17 | + * @since 2024.03.08 | |
18 | + * | |
19 | + * 로그인 LOG정보 저장 | |
20 | + */ | |
21 | + public int insertLoginLog (Member member) throws Exception; | |
22 | + | |
23 | + public int insertLoginLog (LoginLogVO loginLog) throws Exception; | |
24 | + | |
25 | +} |
+++ src/main/java/com/ajin/ajinerp/user/member/dao/MemberDAO.java
... | ... | @@ -0,0 +1,73 @@ |
1 | +package com.ajin.ajinerp.user.member.dao; | |
2 | + | |
3 | +import com.ajin.ajinerp.user.member.vo.Member; | |
4 | +import org.apache.ibatis.annotations.Mapper; | |
5 | + | |
6 | +/** | |
7 | + * @author 이세현 | |
8 | + * @since 2024-03-08 | |
9 | + * | |
10 | + * 회원(개인) 관련된 SQL문에 접근하는 DAO Class | |
11 | + */ | |
12 | +@Mapper | |
13 | +public interface MemberDAO { | |
14 | + /** | |
15 | + * @author 이세현 | |
16 | + * @since 2024.03.08 | |
17 | + * | |
18 | + * 회원 이름 조회 | |
19 | + */ | |
20 | + Member getNameById(String userId) throws Exception; | |
21 | + | |
22 | + /** | |
23 | + * @author 이세현 | |
24 | + * @since 2024.03.10 | |
25 | + * | |
26 | + * 회원 이미지 조회 | |
27 | + */ | |
28 | + Member getImageById(String userId) throws Exception; | |
29 | + | |
30 | + | |
31 | + /** | |
32 | + * @author 이세현 | |
33 | + * @since 2024.03.10 | |
34 | + * | |
35 | + * 아이디로 회원(COUNT) 조회 | |
36 | + */ | |
37 | + int getCountById(String userId) throws Exception; | |
38 | + | |
39 | + /** | |
40 | + * @author 이세현 | |
41 | + * @since 2024.03.10 | |
42 | + * | |
43 | + * 회원 조회 | |
44 | + */ | |
45 | + Member getMember(Member member) throws Exception; | |
46 | + | |
47 | + /** | |
48 | + * @author 이세현 | |
49 | + * @since 2024.03.10 | |
50 | + * | |
51 | + * 회원 조회(COUNT) | |
52 | + */ | |
53 | + int getMemberCount(Member member) throws Exception; | |
54 | + | |
55 | + /** | |
56 | + * @author 이세현 | |
57 | + * @since 2024.03.10 | |
58 | + * | |
59 | + * 회원 마지막 비밀번호 변경일 조회 | |
60 | + */ | |
61 | + int checkPasswordExpiry(String userId) throws Exception; | |
62 | + | |
63 | + /** | |
64 | + * @author 이세현 | |
65 | + * @since 2024.03.10 | |
66 | + * | |
67 | + * 회원 비밀번호 변경 | |
68 | + */ | |
69 | + int updatePassword(Member member) throws Exception; | |
70 | + | |
71 | + | |
72 | + | |
73 | +} |
+++ src/main/java/com/ajin/ajinerp/user/member/service/LoginService.java
... | ... | @@ -0,0 +1,31 @@ |
1 | +package com.ajin.ajinerp.user.member.service; | |
2 | + | |
3 | +import com.ajin.ajinerp.common.vo.CustomeResultMap; | |
4 | +import com.ajin.ajinerp.user.member.vo.Member; | |
5 | + | |
6 | +public interface LoginService { | |
7 | + /** | |
8 | + * @author 이세현 | |
9 | + * @since 2024.03.08 | |
10 | + * | |
11 | + * 유저로그인 처리 | |
12 | + */ | |
13 | + CustomeResultMap userLogin(Member member) throws Exception; | |
14 | + | |
15 | + /** | |
16 | + * @author 이세현 | |
17 | + * @since 2024.03.08 | |
18 | + * | |
19 | + * 세션 무효화 (로그아웃 처리) | |
20 | + */ | |
21 | + CustomeResultMap userLogout() throws Exception; | |
22 | + | |
23 | + /** | |
24 | + * @author 이세현 | |
25 | + * @since 2024.03.11 | |
26 | + * | |
27 | + * 로그인 정보 확인 | |
28 | + */ | |
29 | + CustomeResultMap getLoginInfo() throws Exception; | |
30 | + | |
31 | +} |
+++ src/main/java/com/ajin/ajinerp/user/member/service/MemberService.java
... | ... | @@ -0,0 +1,58 @@ |
1 | +package com.ajin.ajinerp.user.member.service; | |
2 | + | |
3 | + | |
4 | +import com.ajin.ajinerp.common.vo.CustomeResultMap; | |
5 | +import com.ajin.ajinerp.user.member.vo.Member; | |
6 | + | |
7 | +public interface MemberService { | |
8 | + | |
9 | + /** | |
10 | + * @author 이세현 | |
11 | + * @since 2024.03.08 | |
12 | + * | |
13 | + * 아이디로 사용자조회 | |
14 | + */ | |
15 | + CustomeResultMap getNameById(String userId) throws Exception; | |
16 | + | |
17 | + /** | |
18 | + * @author 이세현 | |
19 | + * @since 2024.03.08 | |
20 | + * | |
21 | + * 회원 이미지 조회 | |
22 | + */ | |
23 | + CustomeResultMap getImageById(String userId) throws Exception; | |
24 | + | |
25 | + /** | |
26 | + * @author 이세현 | |
27 | + * @since 2024.03.08 | |
28 | + * | |
29 | + * 아이디 비밀번호로 사용자 조회 | |
30 | + */ | |
31 | + int getMemberCount(Member member) throws Exception; | |
32 | + | |
33 | + /** | |
34 | + * @author 이세현 | |
35 | + * @since 2024.03.10 | |
36 | + * | |
37 | + * 회원 조회 및 로그 남기기 | |
38 | + */ | |
39 | + CustomeResultMap getMemberCountWithLog(Member member) throws Exception; | |
40 | + | |
41 | + /** | |
42 | + * @author 이세현 | |
43 | + * @since 2024.03.10 | |
44 | + * | |
45 | + * 회원 마지막 비밀번호 변경일 조회 | |
46 | + */ | |
47 | + CustomeResultMap checkPasswordExpiry(Member member) throws Exception; | |
48 | + | |
49 | + /** | |
50 | + * @author 이세현 | |
51 | + * @since 2024.03.10 | |
52 | + * | |
53 | + * 회원 비밀번호 변경 | |
54 | + */ | |
55 | + CustomeResultMap updatePassword(Member member) throws Exception; | |
56 | + | |
57 | + | |
58 | +} |
+++ src/main/java/com/ajin/ajinerp/user/member/service/impl/LoginServiceImpl.java
... | ... | @@ -0,0 +1,275 @@ |
1 | +package com.ajin.ajinerp.user.member.service.impl; | |
2 | + | |
3 | +import com.ajin.ajinerp.common.util.*; | |
4 | +import com.ajin.ajinerp.common.vo.CustomeResultMap; | |
5 | +import com.ajin.ajinerp.user.member.dao.LoginDAO; | |
6 | +import com.ajin.ajinerp.user.member.dao.MemberDAO; | |
7 | +import com.ajin.ajinerp.user.member.service.LoginService; | |
8 | +import com.ajin.ajinerp.user.member.service.MemberService; | |
9 | +import com.ajin.ajinerp.user.member.vo.LoginLogVO; | |
10 | +import com.ajin.ajinerp.user.member.vo.Member; | |
11 | +import jakarta.servlet.http.HttpServletRequest; | |
12 | +import jakarta.servlet.http.HttpSession; | |
13 | +import lombok.RequiredArgsConstructor; | |
14 | +import org.springframework.stereotype.Service; | |
15 | +import org.springframework.transaction.annotation.Transactional; | |
16 | + | |
17 | +import java.util.HashMap; | |
18 | +import java.util.List; | |
19 | + | |
20 | +import static com.ajin.ajinerp.user.member.vo.LoginStatus.*; | |
21 | + | |
22 | +/** | |
23 | + * @author 이세현 | |
24 | + * @since 2024.03.08 | |
25 | + * | |
26 | + * 로그인 관련 처리 서비스 클래스 | |
27 | + */ | |
28 | + | |
29 | +@Service | |
30 | +@RequiredArgsConstructor | |
31 | +public class LoginServiceImpl implements LoginService { | |
32 | + private final MemberService memberService; | |
33 | + private final MemberDAO memberDAO; | |
34 | + private final LoginDAO loginDAO; | |
35 | + | |
36 | +// @Override | |
37 | +// @Transactional(rollbackFor = Exception.class) | |
38 | +// public CustomeResultMap userLogin(Member member) { | |
39 | +// CustomeResultMap resultMap = new CustomeResultMap(); | |
40 | +// LoginLogVO loginLogVO = new LoginLogVO(); | |
41 | +// try { | |
42 | +// loginLogInit(loginLogVO); | |
43 | +// | |
44 | +// if (member.getUserid() != null) { | |
45 | +// Member memberById = memberDAO.getMember(member); | |
46 | +// if (memberById != null) { | |
47 | +// if (member.getNewwrd().equals(memberById.getNewwrd())) { | |
48 | +// if(memberDAO.getMemberCount(member) != 1){ | |
49 | +// //로그인 실패 | |
50 | +// | |
51 | +// } | |
52 | +// //로그인성공 로그 + 세션저장 | |
53 | +// loginLogVO.updateLoginStatus(LOGIN_SUCCESS,member.getUserid(),member.getUsernm()); | |
54 | +// resultMap = login(member); | |
55 | +// } else { | |
56 | +// //로그인실패 | |
57 | +// loginLogVO.updateLoginStatus(LOGIN_FAILED_PASSWORD_NOT_MATCH,member.getUserid(),member.getUsernm()); | |
58 | +// throw new Exception("비밀번호가 틀렸습니다."); | |
59 | +// } | |
60 | +// } else { | |
61 | +// //아이디가 존재하지 않습니다. | |
62 | +// loginLogVO.updateLoginStatus(ID_NOT_FOUND,member.getUserid()); | |
63 | +// } | |
64 | +// } else { | |
65 | +// //아이디를 입력하세요. | |
66 | +// loginLogVO.updateLoginStatus(NO_ID_INPUT); | |
67 | +// } | |
68 | +// | |
69 | +// int result = loginDAO.insertLoginLog(loginLogVO); | |
70 | +// if(result != 1){ | |
71 | +// throw new Exception("로그 등록 실패입니다."); | |
72 | +// } | |
73 | +// resultMap.getResultData().put("result",loginDAO.insertLoginLog(loginLogVO)); | |
74 | +// } catch(Exception e){ | |
75 | +// e.printStackTrace(); | |
76 | +// resultMap.getCheckMessage().setError(loginLogVO.getErrxxx()); | |
77 | +// } | |
78 | +// | |
79 | +// return resultMap; | |
80 | +// } | |
81 | +@Override | |
82 | +@Transactional(rollbackFor = Exception.class) | |
83 | +public CustomeResultMap userLogin(Member member) throws Exception { | |
84 | + CustomeResultMap resultMap = new CustomeResultMap(); | |
85 | + LoginLogVO loginLogVO = new LoginLogVO(); | |
86 | + loginLogInit(loginLogVO); | |
87 | + | |
88 | + try { | |
89 | + if (member.getUserid() == null) { | |
90 | + loginLogVO.updateLoginStatus(NO_ID_INPUT); | |
91 | + // 로그 기록 | |
92 | + loginDAO.insertLoginLog(loginLogVO); | |
93 | + | |
94 | + resultMap.getCheckMessage().setError("아이디를 입력하세요."); | |
95 | + return resultMap; | |
96 | + } | |
97 | + | |
98 | + Member memberById = memberDAO.getNameById(member.getUserid()); | |
99 | + if (memberById == null) { | |
100 | + loginLogVO.updateLoginStatus(ID_NOT_FOUND, member.getUserid()); | |
101 | + // 로그 기록 | |
102 | + loginDAO.insertLoginLog(loginLogVO); | |
103 | + | |
104 | + resultMap.getCheckMessage().setError("아이디가 존재하지 않습니다."); | |
105 | + return resultMap; | |
106 | + } | |
107 | + | |
108 | + if (memberDAO.getMemberCount(member) != 1) { | |
109 | + loginLogVO.updateLoginStatus(LOGIN_FAILED_PASSWORD_NOT_MATCH, member.getUserid(), member.getUsernm()); | |
110 | + // 로그 기록 | |
111 | + loginDAO.insertLoginLog(loginLogVO); | |
112 | + | |
113 | + resultMap.getCheckMessage().setError("비밀번호가 틀렸습니다."); | |
114 | + return resultMap; | |
115 | + } | |
116 | + | |
117 | + // 로그인 성공 로그 + 세션 저장 | |
118 | + loginLogVO.updateLoginStatus(LOGIN_SUCCESS, member.getUserid(), member.getUsernm()); | |
119 | + resultMap = login(member); | |
120 | + | |
121 | + // 여기서도 로그 기록 | |
122 | + loginDAO.insertLoginLog(loginLogVO); | |
123 | + } catch (Exception e) { | |
124 | + e.printStackTrace(); | |
125 | + resultMap.getCheckMessage().setError("로그 등록에 실패했습니다."); | |
126 | + } | |
127 | + return resultMap; | |
128 | +} | |
129 | + | |
130 | + private void loginLogInit(LoginLogVO loginLogVO){ | |
131 | + HttpServletRequest request = CommonUtil.getHttpServletRequest(); | |
132 | + String ip = null; | |
133 | + ip = request.getHeader("X-Forwarded-For"); | |
134 | + if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) { | |
135 | + ip = request.getHeader("Proxy-Client-IP"); | |
136 | + } | |
137 | + if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) { | |
138 | + ip = request.getHeader("WL-Proxy-Client-IP"); | |
139 | + } | |
140 | + if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) { | |
141 | + ip = request.getHeader("HTTP_CLIENT_IP"); | |
142 | + } | |
143 | + if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) { | |
144 | + ip = request.getHeader("HTTP_X_FORWARDED_FOR"); | |
145 | + } | |
146 | + if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) { | |
147 | + ip = request.getHeader("X-Real-IP"); | |
148 | + } | |
149 | + if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) { | |
150 | + ip = request.getHeader("X-RealIP"); | |
151 | + } | |
152 | + if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) { | |
153 | + ip = request.getHeader("REMOTE_ADDR"); | |
154 | + } | |
155 | + if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) { | |
156 | + ip = request.getRemoteAddr(); | |
157 | + } | |
158 | + | |
159 | + loginLogVO.setIpaddr(ip); | |
160 | + loginLogVO.setTmlreg(System.getenv("COMPUTERNAME")); | |
161 | + } | |
162 | + | |
163 | + /** | |
164 | + * @author 김성원 | |
165 | + * @since 2024.01.09 | |
166 | + * | |
167 | + * 유저로그인 처리(userId, userPassword) | |
168 | + */ | |
169 | + public CustomeResultMap login(Member member) throws Exception { | |
170 | + | |
171 | + // 결과맵 생성 | |
172 | + CustomeResultMap resultMap = new CustomeResultMap(); | |
173 | + | |
174 | + //사용자 정보 조회 | |
175 | + Member memberInfo = memberDAO.getMember(member); | |
176 | + | |
177 | + // 사용자 정보 있음 | |
178 | + if(memberInfo != null && !StringUtil.isEmpty(memberInfo.getUserid())) { | |
179 | + | |
180 | + /** 로그인 처리이후, 세션처리 (시작) **/ | |
181 | + //세션 무효화 처리 | |
182 | + userLogout(); | |
183 | + | |
184 | + //현재 로그인할 userId와 동일한 로그인 session을 가진 session ID 목록 조회 | |
185 | + List<String> sessionIds = SesssionEventListener.duplicationLoginSessionIdSelectListByUserId(member.getUserid()); | |
186 | + | |
187 | + /** | |
188 | + * 현재 로그인 요청한 userId와 동일한 접속 session이 1명 이상 있고, | |
189 | + * 중복 로그인 가능 유무가 true이면 -> 중복 로그인 처리 진행 | |
190 | + * 중복 로그인 가능 유무가 false이면 -> 기존 로그인 유저를 session에서 제거 | |
191 | + */ | |
192 | + if (sessionIds.size() > 0 && AuthUtil.IS_POSSIBLE_DUPLICATION_LOGIN == true) { | |
193 | + //기존 로그인 유저 session에서 제거 | |
194 | + SesssionEventListener.duplicationLoginSessionDeleteByUserId(member.getUserid()); | |
195 | + } | |
196 | + | |
197 | + //현재 Http Request 객체 가지고 오기 | |
198 | + HttpServletRequest request = CommonUtil.getHttpServletRequest(); | |
199 | + | |
200 | + //기존 session이 존재하더라도 제거하고 새로운 세션 생성 | |
201 | + HttpSession session = request.getSession(true); | |
202 | + | |
203 | + //세션 timeout(30분) | |
204 | + session.setMaxInactiveInterval(60 * 30); | |
205 | + | |
206 | + // session 저장 정보 생성 | |
207 | + HashMap<String, Object> LoginUserInfo = new HashMap<>(); | |
208 | + LoginUserInfo.put("userid", memberInfo.getUserid()); | |
209 | + LoginUserInfo.put("prjcod", memberInfo.getPrjcod()); | |
210 | + LoginUserInfo.put("kangub", memberInfo.getKangub()); | |
211 | + LoginUserInfo.put("usernm", memberInfo.getUsernm()); | |
212 | + LoginUserInfo.put("compcd", memberInfo.getCompcd()); | |
213 | + // session 생성 | |
214 | + session.setAttribute(AuthUtil.LOGIN_USER_SESSION, LoginUserInfo); | |
215 | + resultMap.getResultData().put("LoginUserInfo", LoginUserInfo); | |
216 | + resultMap.getCheckMessage().setMessage(memberInfo.getUserid() + "님 환영합니다."); | |
217 | + | |
218 | + // 성공로직 아래에 만들기 | |
219 | +// loginDAO.loginSuccess(member); | |
220 | + | |
221 | + | |
222 | + }else { | |
223 | + resultMap.getCheckMessage().setError("일치하는 정보가 없습니다.<br />사용자 정보를 확인해 주세요"); | |
224 | + } | |
225 | + return resultMap; | |
226 | + } | |
227 | + | |
228 | + | |
229 | + /** | |
230 | + * @author 이세현 | |
231 | + * @since 2024.03.11 | |
232 | + * | |
233 | + * 세션 무효화 (로그아웃 처리) | |
234 | + */ | |
235 | + @Override | |
236 | + public CustomeResultMap userLogout() throws Exception { | |
237 | + //현재 Http Request 객체 가지고 오기 | |
238 | + HttpServletRequest request = CommonUtil.getHttpServletRequest(); | |
239 | + //기존 session이 존재하면 session값을 받아오고, 존재하지 않으면 null | |
240 | + HttpSession session = request.getSession(false); | |
241 | + //기존 session이 존재하면 -> session 삭제 | |
242 | + if (session != null) { | |
243 | + //session 삭제 | |
244 | + session.invalidate(); | |
245 | + } | |
246 | + CustomeResultMap map = new CustomeResultMap(); | |
247 | + return map; | |
248 | + } | |
249 | + | |
250 | + | |
251 | + /** | |
252 | + * @author 이세현 | |
253 | + * @since 2024.03.11 | |
254 | + * | |
255 | + * 로그인 정보 확인 | |
256 | + */ | |
257 | + @Override | |
258 | + public CustomeResultMap getLoginInfo() throws Exception { | |
259 | + // 결과맵 생성 | |
260 | + CustomeResultMap resultMap = new CustomeResultMap(); | |
261 | + //현재 Http Request 객체 가지고 오기 | |
262 | + HttpServletRequest request = CommonUtil.getHttpServletRequest(); | |
263 | + //기존 session이 존재하면 session값을 받아오고, 존재하지 않으면 null | |
264 | + HttpSession session = request.getSession(false); | |
265 | + // 세션 받아오기 | |
266 | + if(session != null && session.getAttribute(AuthUtil.LOGIN_USER_SESSION) != null) { | |
267 | + HashMap<String, Object> LoginUserInfo = (HashMap<String, Object>)session.getAttribute(AuthUtil.LOGIN_USER_SESSION); | |
268 | + resultMap.getResultData().put("LoginUserInfo", LoginUserInfo); | |
269 | + }else { | |
270 | + resultMap.getCheckMessage().setStatus(0); | |
271 | + } | |
272 | + return resultMap; | |
273 | + } | |
274 | + | |
275 | +} |
+++ src/main/java/com/ajin/ajinerp/user/member/service/impl/MemberServiceImpl.java
... | ... | @@ -0,0 +1,217 @@ |
1 | +package com.ajin.ajinerp.user.member.service.impl; | |
2 | + | |
3 | +import com.ajin.ajinerp.common.util.CommonUtil; | |
4 | +import com.ajin.ajinerp.common.vo.CheckMessage; | |
5 | +import com.ajin.ajinerp.common.vo.CustomeResultMap; | |
6 | +import com.ajin.ajinerp.user.member.dao.LoginDAO; | |
7 | +import com.ajin.ajinerp.user.member.dao.MemberDAO; | |
8 | +import com.ajin.ajinerp.user.member.service.MemberService; | |
9 | +import com.ajin.ajinerp.user.member.vo.LoginLogVO; | |
10 | +import com.ajin.ajinerp.user.member.vo.Member; | |
11 | +import jakarta.servlet.http.HttpServletRequest; | |
12 | +import lombok.RequiredArgsConstructor; | |
13 | +import org.springframework.stereotype.Service; | |
14 | +import org.springframework.transaction.annotation.Transactional; | |
15 | + | |
16 | +import java.util.Base64; | |
17 | + | |
18 | +import static com.ajin.ajinerp.user.member.vo.LoginStatus.*; | |
19 | + | |
20 | +/** | |
21 | + * @author 이세현 | |
22 | + * @since 2024.03.08 | |
23 | + * | |
24 | + * 사용자 관련 처리 서비스 로직 | |
25 | + */ | |
26 | + | |
27 | +@Service | |
28 | +@RequiredArgsConstructor | |
29 | +public class MemberServiceImpl implements MemberService { | |
30 | + private final MemberDAO memberDAO; | |
31 | + private final LoginDAO loginDAO; | |
32 | + | |
33 | + /** | |
34 | + * @author 이세현 | |
35 | + * @since 2024.03.10 | |
36 | + * | |
37 | + * 아이디로 이름 조회 | |
38 | + */ | |
39 | + @Override | |
40 | + public CustomeResultMap getNameById(String userid) throws Exception { | |
41 | + Member member = memberDAO.getNameById(userid); | |
42 | + CustomeResultMap resultMap = new CustomeResultMap(); | |
43 | + resultMap.getResultData().put("member",member); | |
44 | + return resultMap; | |
45 | + } | |
46 | + | |
47 | + /** | |
48 | + * @author 이세현 | |
49 | + * @since 2024.03.10 | |
50 | + * | |
51 | + * 아이디로 이미지 조회 | |
52 | + */ | |
53 | + @Override | |
54 | + public CustomeResultMap getImageById(String userid) throws Exception { | |
55 | + userid = (userid == null || userid.isEmpty()) ? "ADMIN" : userid; | |
56 | + Member member = memberDAO.getImageById(userid); | |
57 | + if( member == null || member.getImagex() == null || member.getImagex().length == 0) { | |
58 | + memberDAO.getImageById("ADMIN"); | |
59 | + } | |
60 | + if( member != null && member.getImagex() != null){ | |
61 | + member.setBase64Image(encodeFileToBase64(member.getImagex())); | |
62 | + } | |
63 | + CustomeResultMap resultMap = new CustomeResultMap(); | |
64 | + resultMap.getResultData().put("member",member); | |
65 | + return resultMap; | |
66 | + } | |
67 | + | |
68 | + /** | |
69 | + * @author 이세현 | |
70 | + * @since 2024.03.10 | |
71 | + * | |
72 | + * 바이너리 데이터 -> base64 인코딩 | |
73 | + */ | |
74 | + private String encodeFileToBase64(byte[] imagex) { | |
75 | + return Base64.getEncoder().encodeToString(imagex); | |
76 | + } | |
77 | + | |
78 | + /** | |
79 | + * @author 이세현 | |
80 | + * @since 2024.03.10 | |
81 | + * | |
82 | + * 회원 조회(COUNT) | |
83 | + */ | |
84 | + @Override | |
85 | + public int getMemberCount(Member member) throws Exception { | |
86 | + return memberDAO.getMemberCount(member); | |
87 | + } | |
88 | + | |
89 | + /** | |
90 | + * @author 이세현 | |
91 | + * @since 2024.03.10 | |
92 | + * | |
93 | + * 회원 마지막 비밀번호 변경일 조회 | |
94 | + */ | |
95 | + @Override | |
96 | + @Transactional(rollbackFor = Exception.class) | |
97 | + public CustomeResultMap checkPasswordExpiry(Member member) throws Exception { | |
98 | + CustomeResultMap resultMap = new CustomeResultMap(); | |
99 | + if (getMemberCount(member) == 1) { | |
100 | + resultMap.getResultData().put("haveToChangePassword", memberDAO.checkPasswordExpiry(member.getUserid()) == 1); | |
101 | + } else { | |
102 | + resultMap.getCheckMessage().setError("비밀번호가 일치하지 않습니다."); | |
103 | + } | |
104 | + return resultMap; | |
105 | + } | |
106 | + | |
107 | + /** | |
108 | + * @author 이세현 | |
109 | + * @since 2024.03.10 | |
110 | + * | |
111 | + * 회원 비밀번호 변경 | |
112 | + */ | |
113 | + @Override | |
114 | + @Transactional(rollbackFor = Exception.class) | |
115 | + public CustomeResultMap updatePassword(Member member) throws Exception { | |
116 | + CustomeResultMap resultMap = new CustomeResultMap(); | |
117 | + | |
118 | + Member getMember = memberDAO.getMember(member); | |
119 | + if(getMember == null ||getMember.getUserid().isEmpty() || !member.getUserid().equals(getMember.getUserid())){ | |
120 | + resultMap.getCheckMessage().setMessage("비밀번호가 일치하지 않습니다."); | |
121 | + } | |
122 | + member.setNewwrd(member.getChangeWrd()); | |
123 | + member.setOldwrd(getMember.getNewwrd()); | |
124 | + member.setIduptx(member.getUserid()); | |
125 | + member.setTmlupt(System.getenv("COMPUTERNAME")); | |
126 | + | |
127 | + resultMap.getResultData().put("result", memberDAO.updatePassword(member) == 1); | |
128 | + return resultMap; | |
129 | + } | |
130 | + | |
131 | + /** | |
132 | + * @author 이세현 | |
133 | + * @since 2024.03.10 | |
134 | + * | |
135 | + * 회원 조회 및 로그 남기기 | |
136 | + */ | |
137 | + @Override | |
138 | + @Transactional(rollbackFor = Exception.class) | |
139 | + public CustomeResultMap getMemberCountWithLog(Member member) throws Exception { | |
140 | + CustomeResultMap resultMap = new CustomeResultMap(); | |
141 | + LoginLogVO loginLogVO = new LoginLogVO(); | |
142 | + int result = 0; | |
143 | + loginLogInit(loginLogVO); | |
144 | + | |
145 | + if (member.getUserid().isEmpty()) { | |
146 | + loginLogVO.updateLoginStatus(NO_ID_INPUT); | |
147 | + } else { | |
148 | + processLoginAttempt(member, loginLogVO); | |
149 | + } | |
150 | + | |
151 | + result = loginDAO.insertLoginLog(loginLogVO); | |
152 | + if (result != 1) { | |
153 | + resultMap.getCheckMessage().setError("로그 저장에 실패하였습니다."); | |
154 | + } | |
155 | + resultMap.getResultData().put("result", memberDAO.getMemberCount(member) == 1); | |
156 | + return resultMap; | |
157 | + } | |
158 | + | |
159 | + //로그 남기기 | |
160 | + private void processLoginAttempt(Member member, LoginLogVO loginLogVO) throws Exception { | |
161 | + String requestURL = member.getRequestURL(); | |
162 | + int countById = memberDAO.getCountById(member.getUserid()); | |
163 | + | |
164 | + if(countById != 1){ | |
165 | + loginLogVO.updateLoginStatus(ID_NOT_FOUND, member.getUserid()); | |
166 | + return; | |
167 | + } | |
168 | + | |
169 | + boolean isPasswordMatch = memberDAO.getMemberCount(member) == 1; | |
170 | + if("IMAGECHANGE".equals(requestURL)){ | |
171 | + if(isPasswordMatch){ | |
172 | + loginLogVO.updateLoginStatus(IMG_CHANGE_CONNECTION_SUCCESS, member.getUserid(), member.getUsernm()); | |
173 | + } else { | |
174 | + loginLogVO.updateLoginStatus(LOGIN_FAILED_PASSWORD_NOT_MATCH, member.getUserid(), member.getUsernm()); | |
175 | + } | |
176 | + } else if("PASSWORDCHANGE".equals(requestURL)){ | |
177 | + if(isPasswordMatch){ | |
178 | + loginLogVO.updateLoginStatus(PW_CHANGE_CONNECTION_SUCCESS, member.getUserid(), member.getUsernm()); | |
179 | + } else { | |
180 | + loginLogVO.updateLoginStatus(PW_CHANGE_FAILED_PASSWORD_NOT_MATCH, member.getUserid(), member.getUsernm()); | |
181 | + } | |
182 | + } | |
183 | + } | |
184 | + | |
185 | + private void loginLogInit(LoginLogVO loginLogVO){ | |
186 | + HttpServletRequest request = CommonUtil.getHttpServletRequest(); | |
187 | + String ip = null; | |
188 | + ip = request.getHeader("X-Forwarded-For"); | |
189 | + if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) { | |
190 | + ip = request.getHeader("Proxy-Client-IP"); | |
191 | + } | |
192 | + if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) { | |
193 | + ip = request.getHeader("WL-Proxy-Client-IP"); | |
194 | + } | |
195 | + if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) { | |
196 | + ip = request.getHeader("HTTP_CLIENT_IP"); | |
197 | + } | |
198 | + if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) { | |
199 | + ip = request.getHeader("HTTP_X_FORWARDED_FOR"); | |
200 | + } | |
201 | + if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) { | |
202 | + ip = request.getHeader("X-Real-IP"); | |
203 | + } | |
204 | + if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) { | |
205 | + ip = request.getHeader("X-RealIP"); | |
206 | + } | |
207 | + if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) { | |
208 | + ip = request.getHeader("REMOTE_ADDR"); | |
209 | + } | |
210 | + if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) { | |
211 | + ip = request.getRemoteAddr(); | |
212 | + } | |
213 | + | |
214 | + loginLogVO.setIpaddr(ip); | |
215 | + loginLogVO.setTmlreg(System.getenv("COMPUTERNAME")); | |
216 | + } | |
217 | +} |
+++ src/main/java/com/ajin/ajinerp/user/member/vo/LoginLogVO.java
... | ... | @@ -0,0 +1,48 @@ |
1 | +package com.ajin.ajinerp.user.member.vo; | |
2 | + | |
3 | +import lombok.Getter; | |
4 | +import lombok.Setter; | |
5 | + | |
6 | +/** | |
7 | + * @author 이세현 | |
8 | + * @since 2024.03.08 | |
9 | + * | |
10 | + * 로그인 로그 VO | |
11 | + */ | |
12 | +@Getter @Setter | |
13 | +public class LoginLogVO { | |
14 | + //접속자ID | |
15 | + private String userid; | |
16 | + //접속자명 | |
17 | + private String usernm; | |
18 | + //성공여부 | |
19 | + private String contgu; | |
20 | + //접속내용 | |
21 | + private String errxxx; | |
22 | + //접속단말IP | |
23 | + private String ipaddr; | |
24 | + //접속단말명 | |
25 | + private String tmlreg; | |
26 | + //MAC address | |
27 | + private String macadd; | |
28 | + //접속일자(YYYYMMDD) | |
29 | + private String sysdat; | |
30 | + //접속시간(HHMMSS) | |
31 | + private String systim; | |
32 | + | |
33 | + public void updateLoginStatus(LoginStatus status, String userid, String usernm) { | |
34 | + this.userid = userid; | |
35 | + this.usernm = usernm; | |
36 | + updateLoginStatus(status); | |
37 | + } | |
38 | + | |
39 | + public void updateLoginStatus(LoginStatus status, String userid) { | |
40 | + this.userid = userid; | |
41 | + updateLoginStatus(status); | |
42 | + } | |
43 | + | |
44 | + public void updateLoginStatus(LoginStatus status) { | |
45 | + this.contgu = status.getContgu(); | |
46 | + this.errxxx = status.getErrxxx(); | |
47 | + } | |
48 | +} |
+++ src/main/java/com/ajin/ajinerp/user/member/vo/LoginStatus.java
... | ... | @@ -0,0 +1,24 @@ |
1 | +package com.ajin.ajinerp.user.member.vo; | |
2 | + | |
3 | +import lombok.Getter; | |
4 | + | |
5 | +@Getter | |
6 | +public enum LoginStatus { | |
7 | + LOGIN_SUCCESS("Y", "LOGIN 연결 성공!!!"), | |
8 | + NO_ID_INPUT("N", "ID를 입력하세요."), | |
9 | + ID_NOT_FOUND("N", "해당 ID가 존재하지 않습니다."), | |
10 | + PW_CHANGE_FAILED_PASSWORD_NOT_MATCH("N", "PW Change 화면 연결 실패!!! Password가 일치하지 않습니다."), | |
11 | + IMG_CHANGE_CONNECTION_SUCCESS("Y", "이미지 변경 선택 성공!!!"), | |
12 | + LOGIN_FAILED_PASSWORD_NOT_MATCH("N", "LOGIN 연결 실패!!! Password가 일치하지 않습니다."), | |
13 | + PW_CHANGE_CONNECTION_SUCCESS("Y", "PW Change 화면 연결 성공!!!"); | |
14 | + | |
15 | + //성공여부 | |
16 | + private final String contgu; | |
17 | + //접속내역 | |
18 | + private final String errxxx; | |
19 | + | |
20 | + LoginStatus(String contgu, String errxxx) { | |
21 | + this.contgu = contgu; | |
22 | + this.errxxx = errxxx; | |
23 | + } | |
24 | +} |
+++ src/main/java/com/ajin/ajinerp/user/member/vo/Member.java
... | ... | @@ -0,0 +1,55 @@ |
1 | +package com.ajin.ajinerp.user.member.vo; | |
2 | + | |
3 | +import com.ajin.ajinerp.common.util.CryptoUtil; | |
4 | +import lombok.Getter; | |
5 | +import lombok.Setter; | |
6 | + | |
7 | +/** | |
8 | + * @author 이세현 | |
9 | + * @since 2024.03.08 | |
10 | + * | |
11 | + * 회원정보 VO | |
12 | + */ | |
13 | + | |
14 | +@Getter @Setter | |
15 | +public class Member { | |
16 | + //사용자ID(사원번호) | |
17 | + private String userid; | |
18 | + //사용자명 | |
19 | + private String usernm; | |
20 | + //구 비밀번호 | |
21 | + private String oldwrd; | |
22 | + //새 비밀번호 | |
23 | + private String newwrd; | |
24 | + //비밀번호 변경일 | |
25 | + private String pw_ymd; | |
26 | + //업무구분 | |
27 | + private String prjcod; | |
28 | + //사업장코드 | |
29 | + private String compcd; | |
30 | + //부서코드 | |
31 | + private String buscod; | |
32 | + //권한(0.총괄관리자, 1.일반관리자, 2.총괄사용자, 3.일반사용자) | |
33 | + private Integer kangub; | |
34 | + //사용여부(Y/N) | |
35 | + private String saygub; | |
36 | + //로그인 성공여부 | |
37 | + private String loginResult; | |
38 | + //로그 작성시 사용할 메세지 | |
39 | + private String errorMsg; | |
40 | + //이미지(Long Raw) | |
41 | + private byte[] imagex; | |
42 | + //이미지(BASE64) | |
43 | + private String base64Image; | |
44 | + //갱신자id | |
45 | + private String iduptx; | |
46 | + //갱신일시 | |
47 | + private String dtmupt; | |
48 | + //갱신단말명 | |
49 | + private String tmlupt; | |
50 | + //요청URL | |
51 | + private String requestURL; | |
52 | + //변경할 비밀번호 | |
53 | + private String changeWrd; | |
54 | + | |
55 | +} |
+++ src/main/java/com/ajin/ajinerp/user/member/web/LoginController.java
... | ... | @@ -0,0 +1,54 @@ |
1 | +package com.ajin.ajinerp.user.member.web; | |
2 | + | |
3 | +import com.ajin.ajinerp.common.vo.CustomeResultMap; | |
4 | +import com.ajin.ajinerp.user.member.service.LoginService; | |
5 | +import com.ajin.ajinerp.user.member.vo.Member; | |
6 | +import lombok.RequiredArgsConstructor; | |
7 | +import org.springframework.web.bind.annotation.PostMapping; | |
8 | +import org.springframework.web.bind.annotation.RequestBody; | |
9 | +import org.springframework.web.bind.annotation.RestController; | |
10 | + | |
11 | +@RestController | |
12 | +@RequiredArgsConstructor | |
13 | +public class LoginController { | |
14 | + private final LoginService loginService; | |
15 | + | |
16 | + /** | |
17 | + * @author 이세현 | |
18 | + * @since 2024.03.11 | |
19 | + * | |
20 | + * 로그인 | |
21 | + */ | |
22 | + @PostMapping(value = "/login.json") | |
23 | + public CustomeResultMap login(@RequestBody Member member) throws Exception { | |
24 | + CustomeResultMap map = loginService.userLogin(member); | |
25 | + return map; | |
26 | + } | |
27 | + | |
28 | + /** | |
29 | + * @author 이세현 | |
30 | + * @since 2024.03.11 | |
31 | + * | |
32 | + * 로그아웃 | |
33 | + */ | |
34 | + @PostMapping(value = "/logout.json") | |
35 | + public CustomeResultMap logout() throws Exception { | |
36 | + CustomeResultMap map = loginService.userLogout(); | |
37 | + return map; | |
38 | + } | |
39 | + | |
40 | + /** | |
41 | + * @author 이세현 | |
42 | + * @since 2024.03.11 | |
43 | + * | |
44 | + * 로그인 정보 조회 | |
45 | + */ | |
46 | + @PostMapping(value = "/getLoginInfo.json") | |
47 | + public CustomeResultMap getLoginInfo() throws Exception { | |
48 | + CustomeResultMap map = loginService.getLoginInfo(); | |
49 | + return map; | |
50 | + } | |
51 | + | |
52 | + | |
53 | + | |
54 | +} |
+++ src/main/java/com/ajin/ajinerp/user/member/web/MemberController.java
... | ... | @@ -0,0 +1,63 @@ |
1 | +package com.ajin.ajinerp.user.member.web; | |
2 | + | |
3 | +import com.ajin.ajinerp.common.vo.CustomeResultMap; | |
4 | +import com.ajin.ajinerp.user.member.service.MemberService; | |
5 | +import com.ajin.ajinerp.user.member.vo.Member; | |
6 | +import lombok.RequiredArgsConstructor; | |
7 | +import org.springframework.web.bind.annotation.*; | |
8 | + | |
9 | +@RestController | |
10 | +@RequiredArgsConstructor | |
11 | +public class MemberController { | |
12 | + private final MemberService memberService; | |
13 | + | |
14 | + /** | |
15 | + * @author 이세현 | |
16 | + * @since 2024.03.10 | |
17 | + * | |
18 | + * 아이디로 이름, 이미지 조회 | |
19 | + */ | |
20 | + @PostMapping(value = "/getMemberById.json") | |
21 | + public CustomeResultMap getMemberById(@RequestBody Member member) throws Exception { | |
22 | + CustomeResultMap map = new CustomeResultMap(); | |
23 | + map.getResultData().put("getNameById",memberService.getNameById(member.getUserid())); | |
24 | + map.getResultData().put("getImageById",memberService.getImageById(member.getUserid())); | |
25 | + return map; | |
26 | + } | |
27 | + | |
28 | + /** | |
29 | + * @author 이세현 | |
30 | + * @since 2024.03.10 | |
31 | + * | |
32 | + * 사용자 마지막 비밀번호 변경날짜 확인 | |
33 | + */ | |
34 | + @PostMapping(value = "/checkPasswordExpiry.json") | |
35 | + public CustomeResultMap checkPasswordExpiry(@RequestBody Member member) throws Exception { | |
36 | + CustomeResultMap map = memberService.checkPasswordExpiry(member); | |
37 | + return map; | |
38 | + } | |
39 | + | |
40 | + /** | |
41 | + * @author 이세현 | |
42 | + * @since 2024.03.10 | |
43 | + * | |
44 | + * 사용자 비밀번호 변경 | |
45 | + */ | |
46 | + @PostMapping(value = "/updatePassword.json") | |
47 | + public CustomeResultMap updatePassword(@RequestBody Member member) throws Exception { | |
48 | + CustomeResultMap map = memberService.updatePassword(member); | |
49 | + return map; | |
50 | + } | |
51 | + | |
52 | + /** | |
53 | + * @author 이세현 | |
54 | + * @since 2024.03.10 | |
55 | + * | |
56 | + * 회원 조회 | |
57 | + */ | |
58 | + @PostMapping(value = "/getUserInfo.json") | |
59 | + public CustomeResultMap getUserInfo(@RequestBody Member member) throws Exception { | |
60 | + CustomeResultMap map = memberService.getMemberCountWithLog(member); | |
61 | + return map; | |
62 | + } | |
63 | +} |
--- src/main/resources/application.properties
+++ src/main/resources/application.properties
... | ... | @@ -4,10 +4,14 @@ |
4 | 4 |
#Datasource Configuration |
5 | 5 |
spring.datasource.hikari.maximum-pool-size=4 |
6 | 6 |
spring.datasource.driver-class-name=net.sf.log4jdbc.sql.jdbcapi.DriverSpy |
7 |
-spring.datasource.url=jdbc:log4jdbc:postgresql://210.180.118.83:5432/bi_manager?currentSchema=bi_manager |
|
8 |
-spring.datasource.username=takensoft |
|
9 |
-spring.datasource.password=tts96314728!@ |
|
10 |
-spring.sql.init.platform=postgres |
|
7 |
+#spring.datasource.url=jdbc:log4jdbc:postgresql://210.180.118.83:5432/ajin_test?currentSchema=ajin_test |
|
8 |
+#spring.datasource.username=takensoft |
|
9 |
+#spring.datasource.password=tts96314728!@ |
|
10 |
+#spring.sql.init.platform=postgres |
|
11 |
+spring.datasource.url=jdbc:log4jdbc:oracle:thin:@192.168.0.17:1521/xe |
|
12 |
+spring.datasource.username=c##takensoft |
|
13 |
+spring.datasource.password=123456 |
|
14 |
+spring.sql.init.platform=oracle |
|
11 | 15 |
|
12 | 16 |
|
13 | 17 |
# Mapper Xml Location |
... | ... | @@ -15,14 +19,14 @@ |
15 | 19 |
mybatis.config-location=classpath:/spring/mapper/mybatis-config.xml |
16 | 20 |
|
17 | 21 |
|
18 |
-# 업로드 파일 용량 설정 |
|
22 |
+# ���ε� ���� �뷮 ���� |
|
19 | 23 |
spring.servlet.multipart.maxFileSize=200MB |
20 | 24 |
spring.servlet.multipart.maxRequestSize=200MB |
21 |
-##catalina log 설정 |
|
25 |
+##catalina log ���� |
|
22 | 26 |
#logging.level.org.apache.catalina=INFO |
23 | 27 |
#logging.file.name=logs/catalina.out |
24 | 28 |
# |
25 |
-##access log 설정 |
|
29 |
+##access log ���� |
|
26 | 30 |
#server.tomcat.basedir=./ |
27 | 31 |
#server.tomcat.accesslog.enabled=true |
28 | 32 |
#server.tomcat.accesslog.directory=logs/access(파일 끝에 줄바꿈 문자 없음) |
--- src/main/resources/spring/mapper/mybatis-config.xml
+++ src/main/resources/spring/mapper/mybatis-config.xml
... | ... | @@ -14,7 +14,10 @@ |
14 | 14 |
</settings> |
15 | 15 |
|
16 | 16 |
<typeAliases> |
17 |
- |
|
17 |
+ <!-- 회원정보 객체 --> |
|
18 |
+ <typeAlias type="com.ajin.ajinerp.user.member.vo.Member" alias="Member"/> |
|
19 |
+ <!-- 로그인로그 객체 --> |
|
20 |
+ <typeAlias type="com.ajin.ajinerp.user.member.vo.LoginLogVO" alias="LoginLogVO"/> |
|
18 | 21 |
</typeAliases> |
19 | 22 |
|
20 | 23 |
</configuration>(파일 끝에 줄바꿈 문자 없음) |
+++ src/main/resources/spring/mapper/user/login-SQL.xml
... | ... | @@ -0,0 +1,41 @@ |
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 | +<mapper namespace="com.ajin.ajinerp.user.member.dao.LoginDAO"> | |
6 | + <!-- 로그인 매퍼 --> | |
7 | + <resultMap id="loginLog" type="LoginLogVO"> | |
8 | + <result property="userid" column="USERID" /> | |
9 | + <result property="usernm" column="USERNM" /> | |
10 | + <result property="contgu" column="CONTGU" /> | |
11 | + <result property="errxxx" column="ERRXXX" /> | |
12 | + <result property="ipaddr" column="IPADDR" /> | |
13 | + <result property="tmlreg" column="TMLREG" /> | |
14 | + <result property="macadd" column="MACADD" /> | |
15 | + <result property="sysdat" column="SYSDAT" /> | |
16 | + <result property="systim" column="SYSTIM" /> | |
17 | + </resultMap> | |
18 | + | |
19 | + <!-- 2.로그인 로그 --> | |
20 | + <insert id="insertLoginLog" parameterType="LoginLogVO"> | |
21 | + INSERT INTO USLOGXXT | |
22 | + ( | |
23 | + USERID, | |
24 | + USERNM, | |
25 | + CONTGU, | |
26 | + ERRXXX, | |
27 | + IPADDR, | |
28 | + TMLREG, | |
29 | + SYSDAT, | |
30 | + SYSTIM) | |
31 | + VALUES | |
32 | + (#{userid}, | |
33 | + #{usernm}, | |
34 | + #{contgu}, | |
35 | + #{errxxx}, | |
36 | + #{ipaddr}, | |
37 | + #{tmlreg}, | |
38 | + TO_CHAR(SYSDATE, 'YYYYMMDD'), -- 현재 날짜를 YYYYMMDD 포맷으로 변환 | |
39 | + TO_CHAR(SYSDATE, 'HH24MISS')) -- 현재 시간을 HH24MISS 포맷으로 변환 | |
40 | + </insert> | |
41 | +</mapper>(파일 끝에 줄바꿈 문자 없음) |
+++ src/main/resources/spring/mapper/user/member-SQL.xml
... | ... | @@ -0,0 +1,97 @@ |
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 | +<mapper namespace="com.ajin.ajinerp.user.member.dao.MemberDAO"> | |
6 | + | |
7 | + <!-- 사용자 매퍼 --> | |
8 | + <resultMap id="memberResult" type="Member"> | |
9 | + <result property="userid" column="USERID" /> | |
10 | + <result property="usernm" column="USERNM" /> | |
11 | + <result property="oldwrd" column="OLDWRD" /> | |
12 | + <result property="newwrd" column="NEWWRD" /> | |
13 | + <result property="pw_ymd" column="PW_YMD" /> | |
14 | + <result property="prjcod" column="PRJCOD" /> | |
15 | + <result property="compcd" column="COMPCD" /> | |
16 | + <result property="buscod" column="BUSCOD" /> | |
17 | + <result property="kangub" column="KANGUB" /> | |
18 | + <result property="saygub" column="SAYGUB" /> | |
19 | + <result property="iduptx" column="IDUPTX" /> | |
20 | + <result property="dtmupt" column="DTMUPT" /> | |
21 | + <result property="tmlupt" column="TMLUPT" /> | |
22 | + <result property="imagex" column="IMAGEX" /> | |
23 | + </resultMap> | |
24 | + | |
25 | + <!-- 1.아이디로 이름 조회--> | |
26 | + <select id="getNameById" parameterType="String" resultMap="memberResult"> | |
27 | + SELECT NVL(USERID, '') AS USERID | |
28 | + , NVL(USERNM, '') AS USERNM | |
29 | + FROM US01001T | |
30 | + WHERE USERID = #{userid} | |
31 | + AND SAYGUB = 'Y' | |
32 | + </select> | |
33 | + | |
34 | + <!-- 2. 아이디로 회원 조회 COUNT--> | |
35 | + <select id="getCountById" parameterType="String" resultType="int"> | |
36 | + SELECT COUNT(*) | |
37 | + FROM US01001T | |
38 | + WHERE USERID = #{userid} | |
39 | + AND SAYGUB = 'Y' | |
40 | + </select> | |
41 | + | |
42 | + <!-- 2.아이디로 이미지 조회 --> | |
43 | + <select id="getImageById" parameterType="String" resultMap="memberResult"> | |
44 | + SELECT IMAGEX | |
45 | + FROM US01003T | |
46 | + WHERE USERID = #{userid} | |
47 | + </select> | |
48 | + | |
49 | + <!-- 3.사용자 이미지 변경--> | |
50 | + <update id="updateUserImage" parameterType="String"> | |
51 | + UPDATE US01003T | |
52 | + SET IMAGEX = #{imagex} | |
53 | + WHERE USERID = #{userid} | |
54 | + </update> | |
55 | + | |
56 | + <!-- 4.사용자 마지막 비밀번호 변경 날짜 조회 --> | |
57 | + <select id="checkPasswordExpiry" parameterType="String" resultType="int"> | |
58 | + SELECT COUNT(*) FROM US01001T WHERE USERID = #{userid} AND MONTHS_BETWEEN(SYSDATE, TO_DATE(PW_YMD, 'YYYYMMDD')) >= 2 | |
59 | + </select> | |
60 | + | |
61 | + <!-- 5.사용자 비밀번호 변경 --> | |
62 | + <update id="updatePassword" parameterType="Member"> | |
63 | + UPDATE US01001T | |
64 | + SET OLDWRD = #{oldwrd} | |
65 | + , NEWWRD = #{newwrd} | |
66 | + , IDUPTX = #{userid} | |
67 | + , DTMUPT = SYSDATE | |
68 | + , TMLUPT = #{tmlupt} | |
69 | + WHERE USERID = #{userid} | |
70 | + </update> | |
71 | + | |
72 | + <!-- 6.아이디 비밀번호로 회원 조회 --> | |
73 | + <select id="getMember" parameterType="Member" resultMap="memberResult"> | |
74 | + SELECT NVL(USERID, '') AS USERID | |
75 | + , NVL(USERNM, '') AS USERNM | |
76 | + , NVL(OLDWRD, '') AS OLDWRD | |
77 | + , NVL(NEWWRD, '') AS NEWWRD | |
78 | + , NVL(PW_YMD, '') AS PW_YMD | |
79 | + , NVL(PRJCOD, '') AS PRJCOD | |
80 | + , NVL(COMPCD, '') AS COMPCD | |
81 | + , NVL(KANGUB, '') AS KANGUB | |
82 | + , NVL(SAYGUB, '') AS SAYGUB | |
83 | + FROM US01001T | |
84 | + WHERE USERID = #{userid} | |
85 | + AND NEWWRD = #{newwrd} | |
86 | + AND SAYGUB = 'Y' | |
87 | + </select> | |
88 | + | |
89 | + <!-- 7.아이디 비밀번호로 회원 조회 COUNT --> | |
90 | + <select id="getMemberCount" parameterType="Member" resultType="int"> | |
91 | + SELECT COUNT(*) | |
92 | + FROM US01001T | |
93 | + WHERE USERID = #{userid} | |
94 | + AND NEWWRD = #{newwrd} | |
95 | + AND SAYGUB = 'Y' | |
96 | + </select> | |
97 | +</mapper>(파일 끝에 줄바꿈 문자 없음) |
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?