
--- build.gradle
+++ build.gradle
... | ... | @@ -81,6 +81,8 @@ |
81 | 81 |
|
82 | 82 |
// 에디터 태그 제거용 라이브러리 |
83 | 83 |
implementation 'org.jsoup:jsoup:1.19.1' |
84 |
+ // Gmail SMTP |
|
85 |
+ implementation 'org.springframework.boot:spring-boot-starter-mail' |
|
84 | 86 |
|
85 | 87 |
testImplementation 'org.springframework.boot:spring-boot-starter-test' |
86 | 88 |
testImplementation 'org.springframework.security:spring-security-test' |
--- src/main/java/com/takensoft/common/config/RedisConfig.java
+++ src/main/java/com/takensoft/common/config/RedisConfig.java
... | ... | @@ -6,6 +6,7 @@ |
6 | 6 |
import org.springframework.data.redis.connection.RedisConnectionFactory; |
7 | 7 |
import org.springframework.data.redis.connection.lettuce.LettuceConnectionFactory; |
8 | 8 |
import org.springframework.data.redis.core.RedisTemplate; |
9 |
+import org.springframework.data.redis.serializer.GenericJackson2JsonRedisSerializer; |
|
9 | 10 |
import org.springframework.data.redis.serializer.StringRedisSerializer; |
10 | 11 |
|
11 | 12 |
/** |
... | ... | @@ -38,5 +39,15 @@ |
38 | 39 |
redisTemp.setValueSerializer(new StringRedisSerializer()); |
39 | 40 |
return redisTemp; |
40 | 41 |
} |
42 |
+ @Bean |
|
43 |
+ public RedisTemplate<String, Object> redisTemplateObject(RedisConnectionFactory redisConnectionFactory) { |
|
44 |
+ RedisTemplate<String, Object> redisTemplate = new RedisTemplate<>(); |
|
45 |
+ redisTemplate.setConnectionFactory(redisConnectionFactory); |
|
46 |
+ redisTemplate.setKeySerializer(new StringRedisSerializer()); |
|
47 |
+ redisTemplate.setValueSerializer(new GenericJackson2JsonRedisSerializer()); |
|
48 |
+ redisTemplate.setHashKeySerializer(new StringRedisSerializer()); |
|
49 |
+ redisTemplate.setHashValueSerializer(new GenericJackson2JsonRedisSerializer()); |
|
50 |
+ return redisTemplate; |
|
51 |
+ } |
|
41 | 52 |
|
42 | 53 |
} |
+++ src/main/java/com/takensoft/common/exception/CustomEmailCodeNotMatchException.java
... | ... | @@ -0,0 +1,26 @@ |
1 | +package com.takensoft.common.exception; | |
2 | + | |
3 | +/** | |
4 | + * @author takensoft | |
5 | + * @since 2025.05.21 | |
6 | + * @modification | |
7 | + * since | author | description | |
8 | + * 2025.05.21 | 하석형 | 최초 등록 | |
9 | + * | |
10 | + * RuntimeException - 실행 중 발생하는 예외를 처리하는 기본 클래스 | |
11 | + * | |
12 | + * 이메일 인증코드 불일치 시 발생하는 예외 | |
13 | + */ | |
14 | +public class CustomEmailCodeNotMatchException extends RuntimeException { | |
15 | + | |
16 | + public CustomEmailCodeNotMatchException() { | |
17 | + | |
18 | + } | |
19 | + public CustomEmailCodeNotMatchException(String message) { | |
20 | + super(message); | |
21 | + } | |
22 | + | |
23 | + public CustomEmailCodeNotMatchException(String message, Throwable cause) { | |
24 | + super(message, cause); | |
25 | + } | |
26 | +} |
+++ src/main/java/com/takensoft/common/exception/CustomEmailSendFailException.java
... | ... | @@ -0,0 +1,26 @@ |
1 | +package com.takensoft.common.exception; | |
2 | + | |
3 | +/** | |
4 | + * @author takensoft | |
5 | + * @since 2025.05.21 | |
6 | + * @modification | |
7 | + * since | author | description | |
8 | + * 2025.05.21 | 하석형 | 최초 등록 | |
9 | + * | |
10 | + * RuntimeException - 실행 중 발생하는 예외를 처리하는 기본 클래스 | |
11 | + * | |
12 | + * 이메일 발송 실패 시 발생하는 예외 | |
13 | + */ | |
14 | +public class CustomEmailSendFailException extends RuntimeException { | |
15 | + | |
16 | + public CustomEmailSendFailException() { | |
17 | + | |
18 | + } | |
19 | + public CustomEmailSendFailException(String message) { | |
20 | + super(message); | |
21 | + } | |
22 | + | |
23 | + public CustomEmailSendFailException(String message, Throwable cause) { | |
24 | + super(message, cause); | |
25 | + } | |
26 | +} |
+++ src/main/java/com/takensoft/common/exception/CustomEmailVerifyExpireException.java
... | ... | @@ -0,0 +1,26 @@ |
1 | +package com.takensoft.common.exception; | |
2 | + | |
3 | +/** | |
4 | + * @author takensoft | |
5 | + * @since 2025.05.21 | |
6 | + * @modification | |
7 | + * since | author | description | |
8 | + * 2025.05.21 | 하석형 | 최초 등록 | |
9 | + * | |
10 | + * RuntimeException - 실행 중 발생하는 예외를 처리하는 기본 클래스 | |
11 | + * | |
12 | + * 이메일 인증시간 만료 시 발생하는 예외 | |
13 | + */ | |
14 | +public class CustomEmailVerifyExpireException extends RuntimeException { | |
15 | + | |
16 | + public CustomEmailVerifyExpireException() { | |
17 | + | |
18 | + } | |
19 | + public CustomEmailVerifyExpireException(String message) { | |
20 | + super(message); | |
21 | + } | |
22 | + | |
23 | + public CustomEmailVerifyExpireException(String message, Throwable cause) { | |
24 | + super(message, cause); | |
25 | + } | |
26 | +} |
+++ src/main/java/com/takensoft/common/exception/CustomEmailVerifyFailException.java
... | ... | @@ -0,0 +1,26 @@ |
1 | +package com.takensoft.common.exception; | |
2 | + | |
3 | +/** | |
4 | + * @author takensoft | |
5 | + * @since 2025.05.21 | |
6 | + * @modification | |
7 | + * since | author | description | |
8 | + * 2025.05.21 | 하석형 | 최초 등록 | |
9 | + * | |
10 | + * RuntimeException - 실행 중 발생하는 예외를 처리하는 기본 클래스 | |
11 | + * | |
12 | + * 이메일 인증 실패 시 발생하는 예외 | |
13 | + */ | |
14 | +public class CustomEmailVerifyFailException extends RuntimeException { | |
15 | + | |
16 | + public CustomEmailVerifyFailException() { | |
17 | + | |
18 | + } | |
19 | + public CustomEmailVerifyFailException(String message) { | |
20 | + super(message); | |
21 | + } | |
22 | + | |
23 | + public CustomEmailVerifyFailException(String message, Throwable cause) { | |
24 | + super(message, cause); | |
25 | + } | |
26 | +} |
--- src/main/java/com/takensoft/common/exception/GlobalExceptionHandler.java
+++ src/main/java/com/takensoft/common/exception/GlobalExceptionHandler.java
... | ... | @@ -324,6 +324,54 @@ |
324 | 324 |
} |
325 | 325 |
|
326 | 326 |
/** |
327 |
+ * @param cesfe - CustomEmailSendFailException 예외 객체 |
|
328 |
+ * @return CustomEmailSendFailException에 대한 HTTP 응답 |
|
329 |
+ * |
|
330 |
+ * CustomEmailSendFailException이 발생한 경우 |
|
331 |
+ */ |
|
332 |
+ @ExceptionHandler(CustomEmailSendFailException.class) |
|
333 |
+ public ResponseEntity<?> handleCustomEmailSendFailException(CustomEmailSendFailException cesfe) { |
|
334 |
+ logError(cesfe); |
|
335 |
+ return resUtil.errorRes(MessageCode.EMAIL_SEND_FAIL); |
|
336 |
+ } |
|
337 |
+ |
|
338 |
+ /** |
|
339 |
+ * @param cevee - CustomEmailVerifyExpireException 예외 객체 |
|
340 |
+ * @return CustomEmailVerifyExpireException에 대한 HTTP 응답 |
|
341 |
+ * |
|
342 |
+ * CustomEmailVerifyExpireException이 발생한 경우 |
|
343 |
+ */ |
|
344 |
+ @ExceptionHandler(CustomEmailVerifyExpireException.class) |
|
345 |
+ public ResponseEntity<?> handleCustomEmailVerifyExpireException(CustomEmailVerifyExpireException cevee) { |
|
346 |
+ logError(cevee); |
|
347 |
+ return resUtil.errorRes(MessageCode.EMAIL_VERIFY_EXPIRED); |
|
348 |
+ } |
|
349 |
+ |
|
350 |
+ /** |
|
351 |
+ * @param cevfe - CustomEmailVerifyFailException 예외 객체 |
|
352 |
+ * @return CustomEmailVerifyFailException에 대한 HTTP 응답 |
|
353 |
+ * |
|
354 |
+ * CustomEmailVerifyFailException이 발생한 경우 |
|
355 |
+ */ |
|
356 |
+ @ExceptionHandler(CustomEmailVerifyFailException.class) |
|
357 |
+ public ResponseEntity<?> handleCustomEmailVerifyFailException(CustomEmailVerifyFailException cevfe) { |
|
358 |
+ logError(cevfe); |
|
359 |
+ return resUtil.errorRes(MessageCode.EMAIL_VERIFY_FAIL); |
|
360 |
+ } |
|
361 |
+ |
|
362 |
+ /** |
|
363 |
+ * @param cecnme - CustomEmailCodeNotMatchException 예외 객체 |
|
364 |
+ * @return CustomEmailCodeNotMatchException에 대한 HTTP 응답 |
|
365 |
+ * |
|
366 |
+ * CustomEmailCodeNotMatchException이 발생한 경우 |
|
367 |
+ */ |
|
368 |
+ @ExceptionHandler(CustomEmailCodeNotMatchException.class) |
|
369 |
+ public ResponseEntity<?> handleCustomEmailCodeNotMatchException(CustomEmailCodeNotMatchException cecnme) { |
|
370 |
+ logError(cecnme); |
|
371 |
+ return resUtil.errorRes(MessageCode.CODE_NOT_MATCH); |
|
372 |
+ } |
|
373 |
+ |
|
374 |
+ /** |
|
327 | 375 |
* @param e - Exception 예외 객체 |
328 | 376 |
* @return 기타 예외에 대한 HTTP 응답 |
329 | 377 |
* |
--- src/main/java/com/takensoft/common/message/MessageCode.java
+++ src/main/java/com/takensoft/common/message/MessageCode.java
... | ... | @@ -66,7 +66,14 @@ |
66 | 66 |
LOGOUT_SUCCESS("user.logout.success", HttpStatus.OK), // 로그아웃 성공 |
67 | 67 |
|
68 | 68 |
// 파일 관련 |
69 |
- FILE_UPLOAD_FAIL("file.upload_fail", HttpStatus.INTERNAL_SERVER_ERROR); // 파일 업로드 실패 |
|
69 |
+ FILE_UPLOAD_FAIL("file.upload_fail", HttpStatus.INTERNAL_SERVER_ERROR), // 파일 업로드 실패 |
|
70 |
+ |
|
71 |
+ // 이메일 인증 관련 |
|
72 |
+ EMAIL_SEND_FAIL("email.send_fail", HttpStatus.INTERNAL_SERVER_ERROR), // 이메일 발송 실패 |
|
73 |
+ EMAIL_VERIFY_SUCCESS("email.verify_success", HttpStatus.OK), // 이메일 인증 성공 |
|
74 |
+ EMAIL_VERIFY_EXPIRED("email.verify_expired", HttpStatus.UNAUTHORIZED), // 이메일 인증 만료 |
|
75 |
+ EMAIL_VERIFY_FAIL("email.verify_fail", HttpStatus.UNAUTHORIZED), // 이메일 인증 실패 |
|
76 |
+ CODE_NOT_MATCH("email.code_not_match", HttpStatus.UNAUTHORIZED); // 인증 코드 불일치 |
|
70 | 77 |
|
71 | 78 |
private final String messageKey; // 메시지 |
72 | 79 |
private final HttpStatus status; // HTTP 상태 |
+++ src/main/java/com/takensoft/common/verify/dao/EmailDAO.java
... | ... | @@ -0,0 +1,19 @@ |
1 | +package com.takensoft.common.verify.dao; | |
2 | + | |
3 | +import com.takensoft.common.verify.vo.EmailVO; | |
4 | +import org.egovframe.rte.psl.dataaccess.mapper.Mapper; | |
5 | + | |
6 | +import java.util.HashMap; | |
7 | +import java.util.List; | |
8 | +/** | |
9 | + * @author : 하석형 | |
10 | + * @since : 2025.05.20 | |
11 | + * @modification | |
12 | + * since | author | description | |
13 | + * 2025.05.20 | 하석형 | 최초 등록 | |
14 | + * | |
15 | + * 이메일 관련 Mapper | |
16 | + */ | |
17 | +@Mapper("emailDAO") | |
18 | +public interface EmailDAO { | |
19 | +}(파일 끝에 줄바꿈 문자 없음) |
+++ src/main/java/com/takensoft/common/verify/service/EmailService.java
... | ... | @@ -0,0 +1,33 @@ |
1 | +package com.takensoft.common.verify.service; | |
2 | + | |
3 | +import com.takensoft.common.verify.vo.EmailVO; | |
4 | +import org.springframework.web.multipart.MultipartFile; | |
5 | + | |
6 | +import java.util.HashMap; | |
7 | +import java.util.List; | |
8 | +/** | |
9 | + * @author 하석형 | |
10 | + * @since 2025.05.20 | |
11 | + * @modification | |
12 | + * since | author | description | |
13 | + * 2025.05.20 | 하석형 | 최초 등록 | |
14 | + * | |
15 | + * 이메일 관련 인터페이스 | |
16 | + */ | |
17 | +public interface EmailService { | |
18 | + /** | |
19 | + * @param emailVO - 이메일 정보 | |
20 | + * @return boolean - 이메일 인증코드 발송 결과 | |
21 | + * | |
22 | + * 이메일 인증코드 발송 | |
23 | + */ | |
24 | + public boolean sendEmailVerifyCode(EmailVO emailVO); | |
25 | + | |
26 | + /** | |
27 | + * @param emailVO - 이메일 정보 | |
28 | + * @return boolean - 이메일 인증코드 확인 결과 | |
29 | + * | |
30 | + * 이메일 인증코드 확인 | |
31 | + */ | |
32 | + public boolean checkEmailVerifyCode(EmailVO emailVO); | |
33 | +}(파일 끝에 줄바꿈 문자 없음) |
+++ src/main/java/com/takensoft/common/verify/service/Impl/EmailServiceImpl.java
... | ... | @@ -0,0 +1,148 @@ |
1 | +package com.takensoft.common.verify.service.Impl; | |
2 | + | |
3 | +import com.takensoft.common.exception.*; | |
4 | +import com.takensoft.common.util.JWTUtil; | |
5 | +import com.takensoft.common.verify.dao.EmailDAO; | |
6 | +import com.takensoft.common.verify.service.EmailService; | |
7 | +import com.takensoft.common.verify.vo.EmailVO; | |
8 | +import lombok.RequiredArgsConstructor; | |
9 | +import org.egovframe.rte.fdl.cmmn.EgovAbstractServiceImpl; | |
10 | +import org.springframework.beans.factory.annotation.Qualifier; | |
11 | +import org.springframework.beans.factory.annotation.Value; | |
12 | +import org.springframework.dao.DataAccessException; | |
13 | +import org.springframework.data.redis.core.RedisTemplate; | |
14 | +import org.springframework.mail.SimpleMailMessage; | |
15 | +import org.springframework.mail.javamail.JavaMailSender; | |
16 | +import org.springframework.stereotype.Service; | |
17 | +import org.springframework.transaction.annotation.Transactional; | |
18 | + | |
19 | + | |
20 | +/** | |
21 | + * @author 하석형 | |
22 | + * @since 2025.05.20 | |
23 | + * @modification | |
24 | + * since | author | description | |
25 | + * 2025.05.20 | 하석형 | 최초 등록 | |
26 | + * | |
27 | + * EgovAbstractServiceImpl : 전자정부 상속 | |
28 | + * EmailService : 이메일 관련 인터페이스 상속 | |
29 | + * | |
30 | + * 이메일 관련 인터페이스 구현체 | |
31 | + */ | |
32 | +@Service("emailService") | |
33 | +@RequiredArgsConstructor | |
34 | +public class EmailServiceImpl extends EgovAbstractServiceImpl implements EmailService { | |
35 | + | |
36 | + private final EmailDAO emailDAO; | |
37 | + private final JWTUtil jwtUtil; | |
38 | + private final JavaMailSender mailSender; | |
39 | + @Qualifier("redisTemplateObject") | |
40 | + private final RedisTemplate<String, Object> redisTemplate; | |
41 | + | |
42 | + @Value("${spring.mail.verifyTime}") | |
43 | + private long verifyTime; // 인증코드 유효시간 | |
44 | + | |
45 | + @Value("${spring.mail.storeTime}") | |
46 | + private long storeTime; // 인증코드 저장시간 | |
47 | + | |
48 | + /** | |
49 | + * @param emailVO - 이메일 정보 | |
50 | + * @return boolean - 이메일 인증코드 발송 결과 | |
51 | + * @throws CustomEmailSendFailException - 이메일 발송 실패 시 | |
52 | + * @throws DataAccessException - db 관련 예외 발생 시 | |
53 | + * @throws Exception - 그 외 예외 발생 시 | |
54 | + * | |
55 | + * 이메일 인증코드 발송 | |
56 | + */ | |
57 | + @Override | |
58 | + @Transactional(rollbackFor = Exception.class) | |
59 | + public boolean sendEmailVerifyCode(EmailVO emailVO){ | |
60 | + try { | |
61 | + String email = emailVO.getEmail(); | |
62 | + String code = createRandomCode(); // 인증코드 생성 | |
63 | + emailVO.setCode(code); | |
64 | + long createdAt = System.currentTimeMillis(); // 현재 시간(millis) | |
65 | + emailVO.setCreatedAt(createdAt); | |
66 | + | |
67 | + boolean isSend = redisTemplate.hasKey("email:" + email); // 이메일 인증코드 발송여부 확인 | |
68 | + | |
69 | + if(isSend) { // 이미 인증코드가 발송된 경우 | |
70 | + EmailVO verifyVO = (EmailVO) redisTemplate.opsForValue().get("email:" + email); // 발송된 인증코드 | |
71 | + if(createdAt - verifyVO.getCreatedAt() > verifyTime) { // 인증코드 유효시간이 지났을 경우 | |
72 | + redisTemplate.delete("email:" + email); // 인증코드 삭제 | |
73 | + } | |
74 | + } | |
75 | + | |
76 | + // 이메일 발송 | |
77 | + SimpleMailMessage message = new SimpleMailMessage(); | |
78 | + message.setTo(email); | |
79 | + message.setSubject("이메일 인증 코드"); | |
80 | + message.setText("인증 코드는 " + code + " 입니다."); | |
81 | + try { | |
82 | + mailSender.send(message); | |
83 | + } catch (Exception e) { | |
84 | + throw new CustomEmailSendFailException("이메일 발송에 실패했습니다."); | |
85 | + } | |
86 | + | |
87 | + redisTemplate.opsForValue().set("email:" + email, emailVO, storeTime); // 인증코드 저장 | |
88 | + return true; | |
89 | + } catch (DataAccessException dae) { | |
90 | + throw dae; | |
91 | + } catch (Exception e) { | |
92 | + redisTemplate.delete("email:" + emailVO.getEmail()); // 실패시 인증코드 삭제 | |
93 | + throw e; | |
94 | + } | |
95 | + } | |
96 | + | |
97 | + /** | |
98 | + * @param emailVO - 이메일 정보 | |
99 | + * @return boolean - 이메일 인증코드 확인 결과 | |
100 | + * @throws CustomEmailVerifyExpireException - 이메일 인증 만료 시 | |
101 | + * @throws CustomEmailCodeNotMatchException - 이메일 인증코드 불일치 시 | |
102 | + * @throws CustomEmailVerifyFailException - 이메일 인증 실패 시 | |
103 | + * @throws DataAccessException - db 관련 예외 발생 시 | |
104 | + * @throws Exception - 그 외 예외 발생 시 | |
105 | + * | |
106 | + * 이메일 인증코드 확인 | |
107 | + */ | |
108 | + @Override | |
109 | + @Transactional(rollbackFor = Exception.class) | |
110 | + public boolean checkEmailVerifyCode(EmailVO emailVO){ | |
111 | + try { | |
112 | + String email = emailVO.getEmail(); | |
113 | + String code = emailVO.getCode(); | |
114 | + long createdAt = System.currentTimeMillis(); // 현재 시간(millis) | |
115 | + | |
116 | + boolean isSend = redisTemplate.hasKey("email:" + email); // 이메일 인증코드 발송여부 확인 | |
117 | + | |
118 | + if(isSend) { // 이미 인증코드가 발송된 경우 | |
119 | + EmailVO verifyVO = (EmailVO) redisTemplate.opsForValue().get("email:" + email); // 발송된 인증코드 | |
120 | + if(createdAt - verifyVO.getCreatedAt() > verifyTime) { // 인증코드 유효시간이 지났을 경우 | |
121 | + throw new CustomEmailVerifyExpireException("인증 시간이 만료되었습니다."); | |
122 | + } | |
123 | + String verifyCode = verifyVO.getCode(); // 발송된 인증코드 | |
124 | + if(verifyCode.equals(code)) { // 인증코드가 일치하는 경우 | |
125 | + redisTemplate.delete("email:" + email); // 인증코드 삭제 | |
126 | + } else { // 인증코드가 일치하지 않는 경우 | |
127 | + throw new CustomEmailCodeNotMatchException("인증코드가 일치하지 않습니다."); | |
128 | + } | |
129 | + } else { // 인증코드가 발송되지 않은 경우 | |
130 | + throw new CustomEmailVerifyFailException("이메일 인증에 실패했습니다."); | |
131 | + } | |
132 | + return true; | |
133 | + } catch (DataAccessException dae) { | |
134 | + throw dae; | |
135 | + } catch (Exception e) { | |
136 | + throw e; | |
137 | + } | |
138 | + } | |
139 | + | |
140 | + /** | |
141 | + * @return String - 이메일 인증코드 | |
142 | + * | |
143 | + * 이메일 인증코드 생성 | |
144 | + */ | |
145 | + private String createRandomCode() { | |
146 | + return String.valueOf((int)(Math.random() * 899999) + 100000); // 6자리 숫자 | |
147 | + } | |
148 | +}(파일 끝에 줄바꿈 문자 없음) |
+++ src/main/java/com/takensoft/common/verify/vo/EmailVO.java
... | ... | @@ -0,0 +1,25 @@ |
1 | +package com.takensoft.common.verify.vo; | |
2 | + | |
3 | +import lombok.*; | |
4 | + | |
5 | +import java.time.LocalDateTime; | |
6 | + | |
7 | +/** | |
8 | + * @author : 하석형 | |
9 | + * @since : 2025.05.20 | |
10 | + * @modification | |
11 | + * since | author | description | |
12 | + * 2025.05.20 | 하석형 | 최초 등록 | |
13 | + * | |
14 | + * 이메일 관련 VO | |
15 | + */ | |
16 | +@Setter | |
17 | +@Getter | |
18 | +@NoArgsConstructor | |
19 | +@AllArgsConstructor | |
20 | +public class EmailVO { | |
21 | + private String email; // 이메일 | |
22 | + private String code; // 인증코드 | |
23 | + private long createdAt; // 인증코드 생성일시 | |
24 | +// private LocalDateTime regDt; // 등록일시 | |
25 | +}(파일 끝에 줄바꿈 문자 없음) |
+++ src/main/java/com/takensoft/common/verify/web/EmailController.java
... | ... | @@ -0,0 +1,66 @@ |
1 | +package com.takensoft.common.verify.web; | |
2 | + | |
3 | +import com.takensoft.common.message.MessageCode; | |
4 | +import com.takensoft.common.util.ResponseUtil; | |
5 | +import com.takensoft.common.verify.service.EmailService; | |
6 | +import com.takensoft.common.verify.vo.EmailVO; | |
7 | +import jakarta.servlet.http.HttpServletResponse; | |
8 | +import lombok.RequiredArgsConstructor; | |
9 | +import lombok.extern.slf4j.Slf4j; | |
10 | +import org.springframework.http.ResponseEntity; | |
11 | +import org.springframework.web.bind.annotation.*; | |
12 | +import org.springframework.web.multipart.MultipartFile; | |
13 | + | |
14 | +import java.io.File; | |
15 | +import java.io.FileInputStream; | |
16 | +import java.io.OutputStream; | |
17 | +import java.net.URLEncoder; | |
18 | +import java.util.HashMap; | |
19 | +import java.util.Map; | |
20 | + | |
21 | +/** | |
22 | + * @author 하석형 | |
23 | + * @since 2025.05.20 | |
24 | + * @modification | |
25 | + * since | author | description | |
26 | + * 2025.05.20 | 하석형 | 최초 등록 | |
27 | + * | |
28 | + * 이메일 관련 Controller | |
29 | + */ | |
30 | +@RestController | |
31 | +@RequiredArgsConstructor | |
32 | +@Slf4j | |
33 | +@RequestMapping(value="/sys/email") | |
34 | +public class EmailController { | |
35 | + | |
36 | + private final EmailService emailService; | |
37 | + private final ResponseUtil resUtil; | |
38 | + | |
39 | + /** | |
40 | + * @param emailVO - 이메일 정보 | |
41 | + * @return ResponseEntity - 이메일 인증코드 발송 응답 결과 | |
42 | + * | |
43 | + * 이메일 인증코드 발송 | |
44 | + */ | |
45 | + @PostMapping("/sendEmailVerifyCode.json") | |
46 | + public ResponseEntity<?> sendEmailVerifyCode(@RequestBody EmailVO emailVO) { | |
47 | + | |
48 | + boolean result = emailService.sendEmailVerifyCode(emailVO); | |
49 | + | |
50 | + return resUtil.successRes(result, MessageCode.COMMON_SUCCESS); | |
51 | + } | |
52 | + | |
53 | + /** | |
54 | + * @param emailVO - 이메일 정보 | |
55 | + * @return ResponseEntity - 이메일 인증코드 확인 응답 결과 | |
56 | + * | |
57 | + * 이메일 인증코드 확인 | |
58 | + */ | |
59 | + @PostMapping("/checkEmailVerifyCode.json") | |
60 | + public ResponseEntity<?> checkEmailVerifyCode(@RequestBody EmailVO emailVO) { | |
61 | + | |
62 | + boolean result = emailService.checkEmailVerifyCode(emailVO); | |
63 | + | |
64 | + return resUtil.successRes(result, MessageCode.COMMON_SUCCESS); | |
65 | + } | |
66 | +} |
--- src/main/resources/application.yml
+++ src/main/resources/application.yml
... | ... | @@ -48,6 +48,23 @@ |
48 | 48 |
# 리눅스 환경 |
49 | 49 |
# static-locations: /home/cloud-user/uploadFiles |
50 | 50 |
|
51 |
+ # 이메일 인증 |
|
52 |
+ mail: |
|
53 |
+ host: smtp.gmail.com |
|
54 |
+ port: 587 |
|
55 |
+ username: dhars3000@gmail.com |
|
56 |
+ password: oejk enyp xowb mzsa |
|
57 |
+ # address: dhars3000@gmail.com |
|
58 |
+ # personal: TAKEN CMS SYSTEM |
|
59 |
+ properties: |
|
60 |
+ mail: |
|
61 |
+ smtp: # SMTP 관련 |
|
62 |
+ auth: true |
|
63 |
+ starttls: # 데이터 암호화 관련 |
|
64 |
+ enable: true |
|
65 |
+ verifyTime: 600000 # 인증가능 시간: 10분 |
|
66 |
+ storeTime: 86400000 # 보관 시간: 24시간 |
|
67 |
+ |
|
51 | 68 |
# Mybatis settings |
52 | 69 |
#mybatis: |
53 | 70 |
# type-aliases-package: com.takensoft.**.**.vo, com.takensoft.**.**.dto, com.takensoft.common |
--- src/main/resources/message/messages_ko.yml
+++ src/main/resources/message/messages_ko.yml
... | ... | @@ -58,4 +58,12 @@ |
58 | 58 |
|
59 | 59 |
# 파일 관련 |
60 | 60 |
file: |
61 |
- upload_fail: "파일 업로드에 실패했습니다."(파일 끝에 줄바꿈 문자 없음) |
|
61 |
+ upload_fail: "파일 업로드에 실패했습니다." |
|
62 |
+ |
|
63 |
+# 이메일 인증 관련 |
|
64 |
+email: |
|
65 |
+ send_fail: "이메일 발송에 실패했습니다." |
|
66 |
+ verify_success: "이메일 인증이 완료되었습니다." |
|
67 |
+ verify_expired: "인증 시간이 만료되었습니다." |
|
68 |
+ verify_fail: "이메일 인증에 실패했습니다." |
|
69 |
+ code_not_match: "인증 코드가 일치하지 않습니다." |
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?