From 34987b1064169e79987594427c5b49407b878e28 Mon Sep 17 00:00:00 2001 From: JuhyunPark Date: Sun, 17 Mar 2024 23:34:06 +0900 Subject: [PATCH 1/6] =?UTF-8?q?Email=20=EC=9D=B8=EC=A6=9D=20=EA=B5=AC?= =?UTF-8?q?=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- build.gradle | 2 + .../PlanIT/common/response/ErrorCode.java | 1 + .../PlanIT/common/util/RedisUtil.java | 22 +++++- .../PlanIT/config/EmailConfig.java | 36 +++++++++ .../user/controller/EmailController.java | 30 ++++++++ .../member/request/EmailSendReqeustDto.java | 13 ++++ .../request/EmailValidationRequestDto.java | 12 +++ .../domain/user/service/EmailService.java | 75 +++++++++++++++++++ src/main/resources/application.yml | 4 + 9 files changed, 192 insertions(+), 3 deletions(-) create mode 100644 src/main/java/com/sideProject/PlanIT/config/EmailConfig.java create mode 100644 src/main/java/com/sideProject/PlanIT/domain/user/controller/EmailController.java create mode 100644 src/main/java/com/sideProject/PlanIT/domain/user/dto/member/request/EmailSendReqeustDto.java create mode 100644 src/main/java/com/sideProject/PlanIT/domain/user/dto/member/request/EmailValidationRequestDto.java create mode 100644 src/main/java/com/sideProject/PlanIT/domain/user/service/EmailService.java diff --git a/build.gradle b/build.gradle index a02cd69..34a813a 100644 --- a/build.gradle +++ b/build.gradle @@ -47,6 +47,8 @@ dependencies { implementation 'com.sun.xml.bind:jaxb-impl:4.0.1' implementation 'com.sun.xml.bind:jaxb-core:4.0.1' implementation 'javax.xml.bind:jaxb-api:2.4.0-b180830.0359' + implementation 'org.springframework.boot:spring-boot-starter-mail' + implementation 'org.springframework.boot:spring-boot-starter-validation' } tasks.named('test') { diff --git a/src/main/java/com/sideProject/PlanIT/common/response/ErrorCode.java b/src/main/java/com/sideProject/PlanIT/common/response/ErrorCode.java index 8413d84..73ca98d 100644 --- a/src/main/java/com/sideProject/PlanIT/common/response/ErrorCode.java +++ b/src/main/java/com/sideProject/PlanIT/common/response/ErrorCode.java @@ -12,6 +12,7 @@ public enum ErrorCode { ALREADY_APPROVE_PROGRAM(400, "이미 등록된 프로그램입니다."), ALREADY_EXIST_EMAIL(400, "이미 존재하는 이메일입니다."), INVALID_PASSWORD(400, "비밀번호가 틀렸습니다."), + INVALID_EMAIL_AUTH(400, "인증번호가 틀렸습니다."), //401 INVALID_ACCESS_TOKEN(401, "ACCESS TOKEN 오류"), diff --git a/src/main/java/com/sideProject/PlanIT/common/util/RedisUtil.java b/src/main/java/com/sideProject/PlanIT/common/util/RedisUtil.java index 7523b8a..b078526 100644 --- a/src/main/java/com/sideProject/PlanIT/common/util/RedisUtil.java +++ b/src/main/java/com/sideProject/PlanIT/common/util/RedisUtil.java @@ -1,20 +1,36 @@ package com.sideProject.PlanIT.common.util; -import lombok.AllArgsConstructor; + +import lombok.RequiredArgsConstructor; +import org.springframework.beans.factory.annotation.Value; import org.springframework.data.redis.core.RedisTemplate; import org.springframework.data.redis.core.ValueOperations; import org.springframework.stereotype.Service; +import java.time.Duration; + @Service -@AllArgsConstructor +@RequiredArgsConstructor public class RedisUtil { + + @Value("${email.redis-timeLimit}") + private Long emailExpire; + + @Value("${jwt.refresh-token-expire}") + private Long refreshExpire; + private final RedisTemplate redisTemplate; + + public void setMailValidation(String email, String validationCode) { + ValueOperations valueOperations = redisTemplate.opsForValue(); + valueOperations.set(email, validationCode, Duration.ofMillis(emailExpire)); + } public void setRefreshToken(String refreshToken, Long member_id) { ValueOperations valueOperations = redisTemplate.opsForValue(); redisTemplate.delete(refreshToken); - valueOperations.set(refreshToken, member_id.toString()); + valueOperations.set(refreshToken, member_id.toString(), refreshExpire); } public String getData(String key) { diff --git a/src/main/java/com/sideProject/PlanIT/config/EmailConfig.java b/src/main/java/com/sideProject/PlanIT/config/EmailConfig.java new file mode 100644 index 0000000..d3af22a --- /dev/null +++ b/src/main/java/com/sideProject/PlanIT/config/EmailConfig.java @@ -0,0 +1,36 @@ +package com.sideProject.PlanIT.config; + +import org.springframework.beans.factory.annotation.Value; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.mail.javamail.JavaMailSender; +import org.springframework.mail.javamail.JavaMailSenderImpl; + +import java.util.Properties; + +@Configuration +public class EmailConfig { + @Value("${email.app-key}") + private String appKey; + @Bean + public JavaMailSender mailSender() { + JavaMailSenderImpl mailSender = new JavaMailSenderImpl(); + mailSender.setHost("smtp.gmail.com"); + mailSender.setPort(587); + mailSender.setUsername("planitvalidation@gmail.com"); + mailSender.setPassword(appKey); + + Properties javaMailProperties = new Properties(); + javaMailProperties.put("mail.transport.protocol", "smtp"); + javaMailProperties.put("mail.smtp.auth", "true"); + javaMailProperties.put("mail.smtp.socketFactory.class", "javax.net.ssl.SSLSocketFactory");//SSL 소켓 팩토리 클래스 사용 + javaMailProperties.put("mail.smtp.starttls.enable", "true");//STARTTLS(TLS를 시작하는 명령)를 사용하여 암호화된 통신을 활성화 + javaMailProperties.put("mail.debug", "true");//디버깅 정보 출력 + javaMailProperties.put("mail.smtp.ssl.trust", "smtp.naver.com");//smtp 서버의 ssl 인증서를 신뢰 + javaMailProperties.put("mail.smtp.ssl.protocols", "TLSv1.2");//사용할 ssl 프로토콜 버젼 + + mailSender.setJavaMailProperties(javaMailProperties); + + return mailSender; + } +} diff --git a/src/main/java/com/sideProject/PlanIT/domain/user/controller/EmailController.java b/src/main/java/com/sideProject/PlanIT/domain/user/controller/EmailController.java new file mode 100644 index 0000000..77c5fc6 --- /dev/null +++ b/src/main/java/com/sideProject/PlanIT/domain/user/controller/EmailController.java @@ -0,0 +1,30 @@ +package com.sideProject.PlanIT.domain.user.controller; + +import com.sideProject.PlanIT.common.response.ApiResponse; +import com.sideProject.PlanIT.domain.user.dto.member.request.EmailSendReqeustDto; +import com.sideProject.PlanIT.domain.user.dto.member.request.EmailValidationRequestDto; +import com.sideProject.PlanIT.domain.user.service.EmailService; +import jakarta.validation.Valid; +import lombok.RequiredArgsConstructor; +import org.springframework.web.bind.MethodArgumentNotValidException; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RestController; + +@RestController +@RequiredArgsConstructor +public class EmailController { + private final EmailService emailService; + + @PostMapping("/email") + public ApiResponse mailSend(@RequestBody @Valid EmailSendReqeustDto emailSendReqeustDto) { + return ApiResponse.ok(emailService.joinEmail(emailSendReqeustDto.getEmail())); + } + + @PostMapping("/check") + public ApiResponse mailValidation(@RequestBody @Valid EmailValidationRequestDto emailValidationRequestDto) { + return ApiResponse.ok(emailService.validEmail(emailValidationRequestDto)); + } + +} diff --git a/src/main/java/com/sideProject/PlanIT/domain/user/dto/member/request/EmailSendReqeustDto.java b/src/main/java/com/sideProject/PlanIT/domain/user/dto/member/request/EmailSendReqeustDto.java new file mode 100644 index 0000000..f1f7370 --- /dev/null +++ b/src/main/java/com/sideProject/PlanIT/domain/user/dto/member/request/EmailSendReqeustDto.java @@ -0,0 +1,13 @@ +package com.sideProject.PlanIT.domain.user.dto.member.request; + +import jakarta.validation.constraints.Email; +import lombok.AccessLevel; +import lombok.Getter; +import lombok.NoArgsConstructor; + +@Getter +@NoArgsConstructor(access = AccessLevel.PROTECTED) +public class EmailSendReqeustDto { + @Email + private String email; +} diff --git a/src/main/java/com/sideProject/PlanIT/domain/user/dto/member/request/EmailValidationRequestDto.java b/src/main/java/com/sideProject/PlanIT/domain/user/dto/member/request/EmailValidationRequestDto.java new file mode 100644 index 0000000..e47dabf --- /dev/null +++ b/src/main/java/com/sideProject/PlanIT/domain/user/dto/member/request/EmailValidationRequestDto.java @@ -0,0 +1,12 @@ +package com.sideProject.PlanIT.domain.user.dto.member.request; + +import lombok.AccessLevel; +import lombok.Getter; +import lombok.NoArgsConstructor; + +@Getter +@NoArgsConstructor(access = AccessLevel.PROTECTED) +public class EmailValidationRequestDto { + private String email; + private String validCode; +} diff --git a/src/main/java/com/sideProject/PlanIT/domain/user/service/EmailService.java b/src/main/java/com/sideProject/PlanIT/domain/user/service/EmailService.java new file mode 100644 index 0000000..d7d2772 --- /dev/null +++ b/src/main/java/com/sideProject/PlanIT/domain/user/service/EmailService.java @@ -0,0 +1,75 @@ +package com.sideProject.PlanIT.domain.user.service; + +import com.sideProject.PlanIT.common.response.CustomException; +import com.sideProject.PlanIT.common.response.ErrorCode; +import com.sideProject.PlanIT.common.util.RedisUtil; +import com.sideProject.PlanIT.domain.user.dto.member.request.EmailValidationRequestDto; +import jakarta.mail.MessagingException; +import jakarta.mail.internet.MimeMessage; +import lombok.RequiredArgsConstructor; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.mail.javamail.JavaMailSender; +import org.springframework.mail.javamail.MimeMessageHelper; +import org.springframework.stereotype.Service; + +import java.util.Objects; +import java.util.Optional; +import java.util.Random; + +@Service +@RequiredArgsConstructor +public class EmailService { + private final JavaMailSender mailSender; + + private final RedisUtil redisUtil; + + private int authNumber; + + public String validEmail(EmailValidationRequestDto emailValidationRequestDto) { + if (!emailValidationRequestDto.getValidCode().equals(redisUtil.getData(emailValidationRequestDto.getEmail()))) { + throw new CustomException(ErrorCode.INVALID_EMAIL_AUTH); + } + return "인증 완료"; + } + + public String joinEmail(String email) { + makeRandomNumber(); + String setFrom = "planitvalidation@gmail.com"; + String toMail = email; + String title = "[PlanIT] 회원 가입 인증 이메일 입니다."; + String content = + "PlanIT에 방문해주셔서 감사합니다." + + "

" + + "인증 번호는 [" + authNumber + "]입니다." + + "
" + + "인증번호를 입력해주세요"; //이메일 내용 삽입 + mailSend(setFrom, toMail, title, content); + redisUtil.setMailValidation(email, String.valueOf(authNumber)); + return "이메일 전송 완료"; + } + + private void mailSend(String setFrom, String toMail, String title, String content) { + MimeMessage message = mailSender.createMimeMessage(); + try { + MimeMessageHelper helper = new MimeMessageHelper(message,true,"utf-8"); + helper.setFrom(setFrom); + helper.setTo(toMail); + helper.setSubject(title); + helper.setText(content,true); + mailSender.send(message); + } catch (MessagingException e) { + e.printStackTrace(); + } + } + + private void makeRandomNumber() { + Random r = new Random(); + String randomNumber = ""; + for(int i = 0; i < 6; i++) { + randomNumber += Integer.toString(r.nextInt(10)); + } + + authNumber = Integer.parseInt(randomNumber); + } + +} diff --git a/src/main/resources/application.yml b/src/main/resources/application.yml index 437b9bb..7512ad6 100644 --- a/src/main/resources/application.yml +++ b/src/main/resources/application.yml @@ -20,6 +20,10 @@ jwt: access-token-expire: 2000 refresh-token-expire: 1209600000 +email: + app-key: ${EMAIL_APP_KEY} + redis-timeLimit: 300000 + # 환경변수 설정 # - DB USER_NAME, PASSWORD # - 파일 저장 디렉토리 경로 From 92e6d84f68dc795f18f18d1d5e9c3e0172b646ad Mon Sep 17 00:00:00 2001 From: JuhyunPark Date: Sun, 24 Mar 2024 17:24:52 +0900 Subject: [PATCH 2/6] =?UTF-8?q?Fix:=20=ED=8C=8C=EC=9D=BC=20=EC=B2=98?= =?UTF-8?q?=EB=A6=AC=20=EA=B8=B0=EB=8A=A5=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../PlanIT/common/modules/FileHandler.java | 32 +++++----- .../file/controller/FileController.java | 60 ++++++++++--------- .../domain/file/service/FileService.java | 16 ----- .../domain/file/service/FileServiceImpl.java | 54 ----------------- .../modules/FileHandlerTest.java} | 25 ++++---- 5 files changed, 63 insertions(+), 124 deletions(-) delete mode 100644 src/main/java/com/sideProject/PlanIT/domain/file/service/FileService.java delete mode 100644 src/main/java/com/sideProject/PlanIT/domain/file/service/FileServiceImpl.java rename src/test/java/com/sideProject/PlanIT/{domain/file/service/FileServiceTest/FileServiceTest.java => common/modules/FileHandlerTest.java} (82%) diff --git a/src/main/java/com/sideProject/PlanIT/common/modules/FileHandler.java b/src/main/java/com/sideProject/PlanIT/common/modules/FileHandler.java index 9ac9375..94645df 100644 --- a/src/main/java/com/sideProject/PlanIT/common/modules/FileHandler.java +++ b/src/main/java/com/sideProject/PlanIT/common/modules/FileHandler.java @@ -34,22 +34,24 @@ public String saveFile(MultipartFile file) { } } - public byte[] loadImage(String path) throws IOException { - String allPath = fileStorageDir +"images"+ path; - log.info(allPath); - File imageFile = new File(allPath); - if (imageFile.exists()) { - FileInputStream fileInputStream = new FileInputStream(imageFile); - byte[] imageBytes = IOUtils.toByteArray(fileInputStream); - fileInputStream.close(); - return imageBytes; - } else{ - throw new CustomException("이미지가 존재하지 않습니다.", ErrorCode.IMAGE_NOT_FOUND); - } + public byte[] loadImage(String imageName) throws IOException { + String allPath = fileStorageDir + File.separator + imageName; + return readFileBytes(allPath); + } + + public byte[] loadFile(String fileName) throws IOException { + String allPath = fileStorageDir + File.separator + fileName; + return readFileBytes(allPath); } - public MultipartFile sendFile(String dir) { - //todo: 파일 전송 - return null; + private byte[] readFileBytes(String filePath) throws IOException { + File file = new File(filePath); + if (file.exists()) { + try (FileInputStream fileInputStream = new FileInputStream(file)) { + return IOUtils.toByteArray(fileInputStream); + } + } else { + throw new CustomException("파일이 존재하지 않습니다.", ErrorCode.FILE_NOT_FOUND); + } } } diff --git a/src/main/java/com/sideProject/PlanIT/domain/file/controller/FileController.java b/src/main/java/com/sideProject/PlanIT/domain/file/controller/FileController.java index 14ca0c2..3f2f42b 100644 --- a/src/main/java/com/sideProject/PlanIT/domain/file/controller/FileController.java +++ b/src/main/java/com/sideProject/PlanIT/domain/file/controller/FileController.java @@ -1,44 +1,50 @@ package com.sideProject.PlanIT.domain.file.controller; -import com.sideProject.PlanIT.common.response.ApiResponse; -import com.sideProject.PlanIT.domain.file.service.FileService; -import com.sideProject.PlanIT.domain.post.dto.request.NoticeRequestDto; -import jakarta.servlet.http.HttpServletRequest; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.core.io.Resource; +import com.sideProject.PlanIT.common.modules.FileHandler; +import com.sideProject.PlanIT.common.response.CustomException; +import com.sideProject.PlanIT.common.response.ErrorCode; +import lombok.RequiredArgsConstructor; +import org.springframework.http.HttpHeaders; +import org.springframework.http.HttpStatus; import org.springframework.http.MediaType; import org.springframework.http.ResponseEntity; -import org.springframework.web.bind.annotation.*; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.RestController; import java.io.IOException; @RestController -@RequestMapping("/file") +@RequiredArgsConstructor public class FileController { - @Autowired - FileService fileService; + private final FileHandler fileHandler; - @PostMapping - public ApiResponse saveFile(@ModelAttribute NoticeRequestDto noticeRequestDto) { - return ApiResponse.ok(fileService.saveFile(noticeRequestDto.getImage())); - } - @GetMapping("/{file_name:.+}") - public ResponseEntity sendFile(@PathVariable String file_name, HttpServletRequest request) { - Resource resource = fileService.sendFile(file_name); - - String contentType = null; + @GetMapping("/image/{image_name}") + public ResponseEntity loadImage(@PathVariable String image_name) { try { - contentType = request.getServletContext().getMimeType(resource.getFile().getAbsolutePath()); + byte[] imageBytes = fileHandler.loadImage(image_name); + + HttpHeaders headers = new HttpHeaders(); + headers.setContentType(MediaType.IMAGE_JPEG); + + return new ResponseEntity<>(imageBytes, headers, HttpStatus.OK); } catch (IOException e) { - e.printStackTrace(); + throw new CustomException(ErrorCode.IMAGE_NOT_FOUND); } + } - if (contentType == null) { - contentType = "application/octet-stream"; - } + @GetMapping("/file/{file_name}") + public ResponseEntity loadFile(@PathVariable String file_name) { + try { + byte[] fileBytes = fileHandler.loadFile(file_name); + + HttpHeaders headers = new HttpHeaders(); + headers.setContentType(MediaType.APPLICATION_OCTET_STREAM); + headers.setContentDispositionFormData("attachment", file_name); - return ResponseEntity.ok() - .contentType(MediaType.parseMediaType(contentType)) - .body(resource); + return new ResponseEntity<>(fileBytes, headers, HttpStatus.OK); + } catch (IOException e) { + throw new CustomException(ErrorCode.FILE_NOT_FOUND); + } } } diff --git a/src/main/java/com/sideProject/PlanIT/domain/file/service/FileService.java b/src/main/java/com/sideProject/PlanIT/domain/file/service/FileService.java deleted file mode 100644 index 8fc7925..0000000 --- a/src/main/java/com/sideProject/PlanIT/domain/file/service/FileService.java +++ /dev/null @@ -1,16 +0,0 @@ -package com.sideProject.PlanIT.domain.file.service; - -import org.springframework.beans.factory.annotation.Value; -import org.springframework.core.io.FileSystemResource; -import org.springframework.core.io.Resource; -import org.springframework.stereotype.Service; -import org.springframework.web.multipart.MultipartFile; - -import java.io.File; -import java.io.IOException; -import java.util.UUID; - -public interface FileService { - public String saveFile(MultipartFile file); - public Resource sendFile(String fileName); -} diff --git a/src/main/java/com/sideProject/PlanIT/domain/file/service/FileServiceImpl.java b/src/main/java/com/sideProject/PlanIT/domain/file/service/FileServiceImpl.java deleted file mode 100644 index 816c2f8..0000000 --- a/src/main/java/com/sideProject/PlanIT/domain/file/service/FileServiceImpl.java +++ /dev/null @@ -1,54 +0,0 @@ -package com.sideProject.PlanIT.domain.file.service; - -import com.sideProject.PlanIT.common.response.CustomException; -import com.sideProject.PlanIT.common.response.ErrorCode; -import org.springframework.beans.factory.annotation.Value; -import org.springframework.core.io.FileSystemResource; -import org.springframework.core.io.Resource; -import org.springframework.stereotype.Service; -import org.springframework.web.multipart.MultipartFile; - -import java.io.File; -import java.io.IOException; -import java.net.MalformedURLException; -import java.util.UUID; - -@Service -public class FileServiceImpl implements FileService{ - @Value("${spring.fileStorage.dir}") - private String fileStorageDir; - - @Override - public String saveFile(MultipartFile file) { - if (file == null || file.isEmpty()) { - return null; - } - try { - UUID uuid = UUID.randomUUID(); - String fileName = uuid + file.getOriginalFilename(); - File dest = new File(fileStorageDir + File.separator + fileName); - file.transferTo(dest); - - return fileName; - } catch (IOException e) { - return "이미지 업로드 오류 발생"; - } - } - - @Override - public Resource sendFile(String fileName) { - try { - File file = new File(fileStorageDir + File.separator + fileName); - - Resource resource = new FileSystemResource(file); - - if (resource.exists() || resource.isReadable()) { - return resource; - } else { - throw new CustomException(ErrorCode.FILE_NOT_FOUND); - } - } catch (Exception e) { - throw new CustomException(ErrorCode.FILE_NOT_FOUND); - } - } -} diff --git a/src/test/java/com/sideProject/PlanIT/domain/file/service/FileServiceTest/FileServiceTest.java b/src/test/java/com/sideProject/PlanIT/common/modules/FileHandlerTest.java similarity index 82% rename from src/test/java/com/sideProject/PlanIT/domain/file/service/FileServiceTest/FileServiceTest.java rename to src/test/java/com/sideProject/PlanIT/common/modules/FileHandlerTest.java index 1c994de..cf0a5a4 100644 --- a/src/test/java/com/sideProject/PlanIT/domain/file/service/FileServiceTest/FileServiceTest.java +++ b/src/test/java/com/sideProject/PlanIT/common/modules/FileHandlerTest.java @@ -1,31 +1,30 @@ -package com.sideProject.PlanIT.domain.file.service.FileServiceTest; +package com.sideProject.PlanIT.common.modules; -import com.sideProject.PlanIT.domain.file.service.FileService; import lombok.extern.slf4j.Slf4j; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; import org.springframework.boot.test.context.SpringBootTest; -import org.springframework.core.io.Resource; import org.springframework.mock.web.MockMultipartFile; import org.springframework.test.context.ActiveProfiles; import org.springframework.web.multipart.MultipartFile; import java.io.*; import java.util.UUID; -import static org.assertj.core.api.Assertions.*; + +import static org.assertj.core.api.Assertions.assertThat; @Slf4j @SpringBootTest -@ActiveProfiles("dev") -public class FileServiceTest { +@ActiveProfiles("prod") +public class FileHandlerTest { @Value("${spring.fileStorage.dir}") private String fileStorageDir; @Autowired - FileService fileService; + FileHandler fileHandler; @Test @DisplayName("파일을 저장합니다") @@ -50,7 +49,7 @@ void saveFile() { } // when - String fileName = fileService.saveFile(multipartFile); + String fileName = fileHandler.saveFile(multipartFile); // then File savedFile = new File(fileStorageDir + File.separator + fileName); @@ -59,7 +58,7 @@ void saveFile() { @Test @DisplayName("저장된 파일을 가져옵니다") - void downloadFile() { + void downloadFile() throws IOException { // given File testFile = new File(fileStorageDir + "test.txt"); @@ -90,11 +89,13 @@ void downloadFile() { } // when - Resource resource = fileService.sendFile(fileName); + byte[] fileBytes = fileHandler.loadFile(fileName); // then - assertThat(resource.exists()).isTrue(); - assertThat(resource.isReadable()).isTrue(); + assertThat(fileBytes).isNotNull(); + + String fileContent = new String(fileBytes); + assertThat(fileContent).isEqualTo("Hello, World!"); } From 32f91b4148217bc4e5224b6d31086c00941e7c0a Mon Sep 17 00:00:00 2001 From: JuhyunPark Date: Sun, 24 Mar 2024 17:46:27 +0900 Subject: [PATCH 3/6] =?UTF-8?q?Fix:=20FileHandler=20lloadFile,=20loadImage?= =?UTF-8?q?=20=EB=A9=94=EC=84=9C=EB=93=9C=20=EB=B3=91=ED=95=A9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../com/sideProject/PlanIT/common/modules/FileHandler.java | 5 ----- .../PlanIT/domain/file/controller/FileController.java | 2 +- 2 files changed, 1 insertion(+), 6 deletions(-) diff --git a/src/main/java/com/sideProject/PlanIT/common/modules/FileHandler.java b/src/main/java/com/sideProject/PlanIT/common/modules/FileHandler.java index 94645df..6b2ff24 100644 --- a/src/main/java/com/sideProject/PlanIT/common/modules/FileHandler.java +++ b/src/main/java/com/sideProject/PlanIT/common/modules/FileHandler.java @@ -34,11 +34,6 @@ public String saveFile(MultipartFile file) { } } - public byte[] loadImage(String imageName) throws IOException { - String allPath = fileStorageDir + File.separator + imageName; - return readFileBytes(allPath); - } - public byte[] loadFile(String fileName) throws IOException { String allPath = fileStorageDir + File.separator + fileName; return readFileBytes(allPath); diff --git a/src/main/java/com/sideProject/PlanIT/domain/file/controller/FileController.java b/src/main/java/com/sideProject/PlanIT/domain/file/controller/FileController.java index 3f2f42b..2336f3d 100644 --- a/src/main/java/com/sideProject/PlanIT/domain/file/controller/FileController.java +++ b/src/main/java/com/sideProject/PlanIT/domain/file/controller/FileController.java @@ -22,7 +22,7 @@ public class FileController { @GetMapping("/image/{image_name}") public ResponseEntity loadImage(@PathVariable String image_name) { try { - byte[] imageBytes = fileHandler.loadImage(image_name); + byte[] imageBytes = fileHandler.loadFile(image_name); HttpHeaders headers = new HttpHeaders(); headers.setContentType(MediaType.IMAGE_JPEG); From 60ef984455b30d6593fc2479207a7fd70d999df0 Mon Sep 17 00:00:00 2001 From: moonjin-kim Date: Mon, 25 Mar 2024 15:59:07 +0900 Subject: [PATCH 4/6] =?UTF-8?q?bug:=20#97=20=EC=A1=B0=ED=9A=8C=20=EB=B2=84?= =?UTF-8?q?=EA=B7=B8=20=EC=88=98=EC=A0=95,=20=ED=8A=B9=EC=A0=95=20?= =?UTF-8?q?=ED=8A=B8=EB=A0=88=EC=9D=B4=EB=84=88=20=EC=A1=B0=ED=9A=8C=20?= =?UTF-8?q?=EA=B8=B0=EB=8A=A5=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .gitignore | 2 +- .../PlanIT/common/util/RedisUtil.java | 4 +-- .../PlanIT/config/EmailConfig.java | 2 +- .../controller/ReservationController.java | 17 ++++++++++ .../dto/response/ReservationResponse.java | 1 - .../service/ReservationService.java | 2 +- .../service/ReservationServiceImpl.java | 21 +++++++++--- src/main/resources/application-prod.yml | 33 ++++++++++++++++--- src/main/resources/application.yml | 6 ++-- 9 files changed, 69 insertions(+), 19 deletions(-) diff --git a/.gitignore b/.gitignore index 993ce84..ba2441d 100644 --- a/.gitignore +++ b/.gitignore @@ -7,7 +7,7 @@ build/ ## 서버 설정 정보 ## !**/src/main/resources/application.yml -!**/src/main/resources/application-dev.yml +src/main/resources/application-dev.yml ### STS ### .apt_generated diff --git a/src/main/java/com/sideProject/PlanIT/common/util/RedisUtil.java b/src/main/java/com/sideProject/PlanIT/common/util/RedisUtil.java index b078526..e44e1bb 100644 --- a/src/main/java/com/sideProject/PlanIT/common/util/RedisUtil.java +++ b/src/main/java/com/sideProject/PlanIT/common/util/RedisUtil.java @@ -13,10 +13,10 @@ @RequiredArgsConstructor public class RedisUtil { - @Value("${email.redis-timeLimit}") + @Value("${spring.email.redis-timeLimit}") private Long emailExpire; - @Value("${jwt.refresh-token-expire}") + @Value("${spring.jwt.refresh-token-expire}") private Long refreshExpire; private final RedisTemplate redisTemplate; diff --git a/src/main/java/com/sideProject/PlanIT/config/EmailConfig.java b/src/main/java/com/sideProject/PlanIT/config/EmailConfig.java index d3af22a..f7c8a17 100644 --- a/src/main/java/com/sideProject/PlanIT/config/EmailConfig.java +++ b/src/main/java/com/sideProject/PlanIT/config/EmailConfig.java @@ -10,7 +10,7 @@ @Configuration public class EmailConfig { - @Value("${email.app-key}") + @Value("${spring.email.app-key}") private String appKey; @Bean public JavaMailSender mailSender() { diff --git a/src/main/java/com/sideProject/PlanIT/domain/reservation/controller/ReservationController.java b/src/main/java/com/sideProject/PlanIT/domain/reservation/controller/ReservationController.java index 12f48c8..a6b837a 100644 --- a/src/main/java/com/sideProject/PlanIT/domain/reservation/controller/ReservationController.java +++ b/src/main/java/com/sideProject/PlanIT/domain/reservation/controller/ReservationController.java @@ -72,6 +72,23 @@ public ApiResponse>> findReservation( ); } + @GetMapping("/{employeeId}") + public ApiResponse>> findReservationByEmployee( + @RequestParam(value = "date", required = false) + @DateTimeFormat(iso = DateTimeFormat.ISO.DATE) LocalDate date, + @PathVariable("employeeId") Long employeeId + ) { + if (date == null) { + date = LocalDate.now(); // 파라미터가 없을 경우 기본값으로 오늘 날짜를 사용 + } + return ApiResponse.ok( + reservationService.findReservationForWeekByEmployee( + date, + employeeId + ) + ); + } + @DeleteMapping("/{reservationId}") public ApiResponse cancelReservation( @PathVariable("reservationId") Long reservationId, diff --git a/src/main/java/com/sideProject/PlanIT/domain/reservation/dto/response/ReservationResponse.java b/src/main/java/com/sideProject/PlanIT/domain/reservation/dto/response/ReservationResponse.java index 800b0fc..21905dd 100644 --- a/src/main/java/com/sideProject/PlanIT/domain/reservation/dto/response/ReservationResponse.java +++ b/src/main/java/com/sideProject/PlanIT/domain/reservation/dto/response/ReservationResponse.java @@ -48,7 +48,6 @@ public static ReservationResponse of(Reservation reservation) { if(reservation.getStatus() == ReservationStatus.POSSIBLE) { return ReservationResponse.builder() .id(reservation.getId()) - .member(MemberSemiResponseDto.of(reservation.getMember())) .employee(EmployeeSemiResponseDto.of(reservation.getEmployee())) .status(reservation.getStatus()) .build(); diff --git a/src/main/java/com/sideProject/PlanIT/domain/reservation/service/ReservationService.java b/src/main/java/com/sideProject/PlanIT/domain/reservation/service/ReservationService.java index 25a38e5..4c41a2c 100644 --- a/src/main/java/com/sideProject/PlanIT/domain/reservation/service/ReservationService.java +++ b/src/main/java/com/sideProject/PlanIT/domain/reservation/service/ReservationService.java @@ -11,6 +11,6 @@ public interface ReservationService { String changeAvailability(List times, Long employeeId, Long userId); String reservation(Long reservationId, Long userId, Long programId); Map> findReservationForWeekByMember(LocalDate day, Long id); - List findReservationForWeekByEmployee(LocalDate day, Long id); + Map> findReservationForWeekByEmployee(LocalDate day, Long id); String cancel(Long userId, Long reservationId); } diff --git a/src/main/java/com/sideProject/PlanIT/domain/reservation/service/ReservationServiceImpl.java b/src/main/java/com/sideProject/PlanIT/domain/reservation/service/ReservationServiceImpl.java index 5382db6..35b5e7d 100644 --- a/src/main/java/com/sideProject/PlanIT/domain/reservation/service/ReservationServiceImpl.java +++ b/src/main/java/com/sideProject/PlanIT/domain/reservation/service/ReservationServiceImpl.java @@ -61,7 +61,7 @@ public String changeAvailability(List reservedTimes, Long employe // 기존 예약 삭제 List reservedReservations = existingReservations.stream() .filter(reservation -> reservation.getStatus() == ReservationStatus.POSSIBLE) - .collect(Collectors.toList()); + .toList(); reservedReservations.forEach(reservationRepository::delete); // 새 예약 추가 (기존 예약이 없는 reservedTimes에 대해서만) @@ -141,15 +141,26 @@ public Map> findReservationForWeekByMember( reservations = reservationRepository.findByMemberAndDateTimeBetween(member,startOfWeek,endOfWeek); } - Map> reservationMap = reservations.stream() + return reservations.stream() .map(ReservationResponse::of) .collect(Collectors.groupingBy(response -> response.getReservationTime().toLocalDate())); - return reservationMap; } @Override - public List findReservationForWeekByEmployee(LocalDate date, Long employeeId) { - return List.of(ReservationResponse.builder().build(), ReservationResponse.builder().build()); + public Map> findReservationForWeekByEmployee(LocalDate date, Long employeeId) { + LocalDateTime startOfWeek = calStartOfWeek(date); + LocalDateTime endOfWeek = calEndOfWeek(date); + + List reservations; + //트레이너이면 + Employee employee = employeeRepository.findById(employeeId).orElseThrow(() -> + new CustomException("존재하지 않는 트레이너입니다.", ErrorCode.MEMBER_NOT_FOUND) + ); + reservations = reservationRepository.findByEmployeeAndDateTimeBetween(employee,startOfWeek,endOfWeek); + + return reservations.stream() + .map(ReservationResponse::of) + .collect(Collectors.groupingBy(response -> response.getReservationTime().toLocalDate())); } //그 주의 월요일 00:00:00 diff --git a/src/main/resources/application-prod.yml b/src/main/resources/application-prod.yml index d8f493c..89824f9 100644 --- a/src/main/resources/application-prod.yml +++ b/src/main/resources/application-prod.yml @@ -1,16 +1,15 @@ -# default spring: profiles: active: - on-profile : prod # 기본 환경을 dev로 + on-profile: prod # 기본 환경을 prod로 fileStorage: dir: ${FILE_STORAGE_DIR} jwt: secret-key: ${SECRET_KEY} - access-token-expire: 432000 - refresh-token-expire: 1209600000 + access-token-expire: ${ACCESS_EXPIRE} + refresh-token-expire: ${REFRESH_EXPIRE} datasource: url: jdbc:mysql://${DB_CONNECTION_URL}?serverTimezone=Asia/Seoul&characterEncoding=UTF-8 @@ -18,8 +17,32 @@ spring: password: ${PASSWORD} driver-class-name: com.mysql.cj.jdbc.Driver jpa: - hibernate.ddl-auto: update + hibernate.ddl-auto: create properties: hibernate: format_sql: true + data: + redis: + host: ${REDIS_HOST} + port: ${REDIS_PORT} + mvc: + cors: + allowed-origins: "*" + + + naver: + client-id: ${NAVER_CLIENT_ID} + client-secret: ${NAVER_CLIENT_SECRET} + login-uri: https://nid.naver.com/oauth2.0/authorize?response_type=code& + redirect-uri: http://localhost:8080/login/oauth2/code/naver + + google: + client-id: ${GOOGLE_CLIENT_ID} + client-secret: ${GOOGLE_CLIENT_SECRET} + login-uri: https://accounts.google.com/o/oauth2/v2/auth/oauthchooseaccount? + redirect-uri: http://localhost:8080/login/oauth2/code/google + + email: + app-key: ${EMAIL_APP_KEY} + redis-timeLimit: 300000 \ No newline at end of file diff --git a/src/main/resources/application.yml b/src/main/resources/application.yml index 37ddf43..ee17906 100644 --- a/src/main/resources/application.yml +++ b/src/main/resources/application.yml @@ -43,9 +43,9 @@ spring: login-uri: https://accounts.google.com/o/oauth2/v2/auth/oauthchooseaccount? redirect-uri: http://localhost:8080/login/oauth2/code/google -email: - app-key: ${EMAIL_APP_KEY} - redis-timeLimit: 300000 + email: + app-key: ${EMAIL_APP_KEY} + redis-timeLimit: 300000 # 환경변수 설정 # - DB USER_NAME, PASSWORD From 8bc2036519f27706e3fd0cd04e424db04093fca2 Mon Sep 17 00:00:00 2001 From: moonjin-kim Date: Mon, 25 Mar 2024 16:01:47 +0900 Subject: [PATCH 5/6] =?UTF-8?q?fix=20:=20trainer=20path=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../domain/reservation/controller/ReservationController.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/com/sideProject/PlanIT/domain/reservation/controller/ReservationController.java b/src/main/java/com/sideProject/PlanIT/domain/reservation/controller/ReservationController.java index a6b837a..917b4a9 100644 --- a/src/main/java/com/sideProject/PlanIT/domain/reservation/controller/ReservationController.java +++ b/src/main/java/com/sideProject/PlanIT/domain/reservation/controller/ReservationController.java @@ -72,7 +72,7 @@ public ApiResponse>> findReservation( ); } - @GetMapping("/{employeeId}") + @GetMapping("/trainer/{employeeId}") public ApiResponse>> findReservationByEmployee( @RequestParam(value = "date", required = false) @DateTimeFormat(iso = DateTimeFormat.ISO.DATE) LocalDate date, From 79b91b44a74f7818523f6f4a8c2a2ee8d63b83f3 Mon Sep 17 00:00:00 2001 From: moonjin-kim Date: Mon, 25 Mar 2024 16:08:43 +0900 Subject: [PATCH 6/6] =?UTF-8?q?build=20:=20application=20prod=20hibernate?= =?UTF-8?q?=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/resources/application-prod.yml | 2 +- src/main/resources/application.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/resources/application-prod.yml b/src/main/resources/application-prod.yml index 89824f9..fed56b4 100644 --- a/src/main/resources/application-prod.yml +++ b/src/main/resources/application-prod.yml @@ -17,7 +17,7 @@ spring: password: ${PASSWORD} driver-class-name: com.mysql.cj.jdbc.Driver jpa: - hibernate.ddl-auto: create + hibernate.ddl-auto: update properties: hibernate: format_sql: true diff --git a/src/main/resources/application.yml b/src/main/resources/application.yml index ee17906..0cf45a2 100644 --- a/src/main/resources/application.yml +++ b/src/main/resources/application.yml @@ -17,7 +17,7 @@ spring: password: ${PASSWORD} driver-class-name: com.mysql.cj.jdbc.Driver jpa: - hibernate.ddl-auto: create + hibernate.ddl-auto: update properties: hibernate: format_sql: true