From 54e943c041893a49a8d8ebd69d62718b1ca21163 Mon Sep 17 00:00:00 2001 From: YoungJin Cho Date: Sat, 7 Oct 2023 09:41:25 +0900 Subject: [PATCH 1/2] =?UTF-8?q?#63=20Feat:=20=EC=B9=B4=EC=B9=B4=EC=98=A4?= =?UTF-8?q?=20=ED=8C=8C=EC=9D=BC=20=EB=A7=81=ED=81=AC=20=EC=B6=94=EC=B6=9C?= =?UTF-8?q?=20api=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../exception/GlobalExceptionHandler.java | 6 ++ .../linknamu/kakao/KakaoExceptionStatus.java | 19 ++++++ .../controller/KakaoSendMeController.java | 35 +++++++++++ .../kakao/dto/KakaoSendMeResponseDto.java | 9 +++ .../kakao/service/KaKaoSendMeService.java | 59 +++++++++++++++++++ 5 files changed, 128 insertions(+) create mode 100644 linknamu/src/main/java/com/kakao/linknamu/kakao/KakaoExceptionStatus.java create mode 100644 linknamu/src/main/java/com/kakao/linknamu/kakao/controller/KakaoSendMeController.java create mode 100644 linknamu/src/main/java/com/kakao/linknamu/kakao/dto/KakaoSendMeResponseDto.java create mode 100644 linknamu/src/main/java/com/kakao/linknamu/kakao/service/KaKaoSendMeService.java diff --git a/linknamu/src/main/java/com/kakao/linknamu/_core/exception/GlobalExceptionHandler.java b/linknamu/src/main/java/com/kakao/linknamu/_core/exception/GlobalExceptionHandler.java index a5703618..25a907c7 100644 --- a/linknamu/src/main/java/com/kakao/linknamu/_core/exception/GlobalExceptionHandler.java +++ b/linknamu/src/main/java/com/kakao/linknamu/_core/exception/GlobalExceptionHandler.java @@ -11,6 +11,7 @@ import org.springframework.web.bind.annotation.ExceptionHandler; import org.springframework.web.bind.annotation.RestControllerAdvice; import org.springframework.web.method.annotation.MethodArgumentTypeMismatchException; +import org.springframework.web.multipart.support.MissingServletRequestPartException; import java.util.List; @@ -36,6 +37,11 @@ public ResponseEntity dtoTypeMismatchException(Exception e) { return new ResponseEntity<>(ApiUtils.error("입력의 타입이 올바르지 않습니다.", HttpStatus.BAD_REQUEST.value()), HttpStatus.BAD_REQUEST); } + @ExceptionHandler({MissingServletRequestPartException.class}) + public ResponseEntity requestPartMissingException(Exception e) { + return new ResponseEntity<>(ApiUtils.error("form-data 형식에 file이라는 이름이 존재하지 않습니다.", HttpStatus.BAD_REQUEST.value()), HttpStatus.BAD_REQUEST); + } + @ExceptionHandler({Exception400.class, Exception401.class, Exception403.class, Exception404.class}) public ResponseEntity clientException(ClientException e) { return new ResponseEntity<>(e.body(), e.status()); diff --git a/linknamu/src/main/java/com/kakao/linknamu/kakao/KakaoExceptionStatus.java b/linknamu/src/main/java/com/kakao/linknamu/kakao/KakaoExceptionStatus.java new file mode 100644 index 00000000..f9b0a39c --- /dev/null +++ b/linknamu/src/main/java/com/kakao/linknamu/kakao/KakaoExceptionStatus.java @@ -0,0 +1,19 @@ +package com.kakao.linknamu.category; + +import com.kakao.linknamu._core.exception.BaseExceptionStatus; +import lombok.Getter; +import lombok.RequiredArgsConstructor; + +@RequiredArgsConstructor +public enum KakaoExceptionStatus implements BaseExceptionStatus { + + FILE_INVALID_FORMAT("파일이 txt 또는 csv 형식이 아닙니다.", 400), + FILE_NOTFOUND("파일이 존재하지 않습니다.", 400), + FILE_READ_FAILED("파일을 읽는 과정에서 오류가 발생했습니다.", 500); + + + @Getter + private final String message; + @Getter + private final int status; +} diff --git a/linknamu/src/main/java/com/kakao/linknamu/kakao/controller/KakaoSendMeController.java b/linknamu/src/main/java/com/kakao/linknamu/kakao/controller/KakaoSendMeController.java new file mode 100644 index 00000000..56084b04 --- /dev/null +++ b/linknamu/src/main/java/com/kakao/linknamu/kakao/controller/KakaoSendMeController.java @@ -0,0 +1,35 @@ +package com.kakao.linknamu.kakao.controller; + +import com.kakao.linknamu._core.util.ApiUtils; +import com.kakao.linknamu.kakao.dto.KakaoSendMeResponseDto; +import com.kakao.linknamu.kakao.service.KaKaoSendMeService; +import lombok.RequiredArgsConstructor; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestPart; +import org.springframework.web.bind.annotation.RestController; +import org.springframework.web.multipart.MultipartFile; + +import java.util.List; + +@RestController +@RequiredArgsConstructor +@RequestMapping("/api/kakao") +public class KakaoSendMeController { + + private final KaKaoSendMeService kaKaoSendMeService; + + + //1. 단순히 file만 요청 받을 경우 => @RequestParam 어노테이션과 MultipartFile 객체사용 + //2, file과 json 을 같이 받을 경우 => @RequestPart 어노테이션과 json을 받을 DTO에 key 값을 지정 + + @PostMapping("/send-me") + public ResponseEntity getKaKaoSendMeText(@RequestPart(value = "file") MultipartFile multipartFile) { + + List responseDtos = kaKaoSendMeService.extractLink(multipartFile); + + + return ResponseEntity.ok(ApiUtils.success(responseDtos)); + } +} diff --git a/linknamu/src/main/java/com/kakao/linknamu/kakao/dto/KakaoSendMeResponseDto.java b/linknamu/src/main/java/com/kakao/linknamu/kakao/dto/KakaoSendMeResponseDto.java new file mode 100644 index 00000000..7dae0c49 --- /dev/null +++ b/linknamu/src/main/java/com/kakao/linknamu/kakao/dto/KakaoSendMeResponseDto.java @@ -0,0 +1,9 @@ +package com.kakao.linknamu.kakao.dto; + +public record KakaoSendMeResponseDto( + String link + +) { + + +} diff --git a/linknamu/src/main/java/com/kakao/linknamu/kakao/service/KaKaoSendMeService.java b/linknamu/src/main/java/com/kakao/linknamu/kakao/service/KaKaoSendMeService.java new file mode 100644 index 00000000..43d0b9d6 --- /dev/null +++ b/linknamu/src/main/java/com/kakao/linknamu/kakao/service/KaKaoSendMeService.java @@ -0,0 +1,59 @@ +package com.kakao.linknamu.kakao.service; + +import com.kakao.linknamu._core.exception.Exception400; +import com.kakao.linknamu._core.exception.Exception500; +import com.kakao.linknamu.category.KakaoExceptionStatus; +import com.kakao.linknamu.kakao.dto.KakaoSendMeResponseDto; +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; +import org.springframework.web.multipart.MultipartFile; + +import java.io.IOException; +import java.nio.charset.StandardCharsets; +import java.util.ArrayList; +import java.util.List; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +@Transactional(readOnly = true) +@RequiredArgsConstructor +@Service +public class KaKaoSendMeService { + + + public List extractLink(MultipartFile multipartFile) { + + List responseDtos = new ArrayList<>(); + + if (multipartFile.isEmpty()) throw new Exception400(KakaoExceptionStatus.FILE_NOTFOUND); + + String contentType = multipartFile.getContentType(); + + boolean isSupportedFormat = (contentType.equals("text/plain")) || (contentType.equals("text/csv")); + + if (isSupportedFormat == false) throw new Exception400(KakaoExceptionStatus.FILE_INVALID_FORMAT); + + + try { + byte[] fileBytes = multipartFile.getBytes(); + String fileContent = new String(fileBytes, StandardCharsets.UTF_8); // byte 배열을 문자열로 변환 + +// https 링크를 추출하기 위한 정규 표현식 + String regex = "(https?://[a-zA-Z0-9\\-\\.]+(\\:[0-9]+)?\\.[a-zA-Z]{2,3}(\\S*)?)"; + +// \bhttps?://\S+ => 모든 http, https 도메인 검출 + Pattern pattern = Pattern.compile(regex); + Matcher matcher = pattern.matcher(fileContent); + while (matcher.find()) { + String httpsLink = matcher.group(); + responseDtos.add(new KakaoSendMeResponseDto(httpsLink)); + } + return responseDtos; + } catch (IOException e) { + throw new Exception500(KakaoExceptionStatus.FILE_READ_FAILED); + } + + + } +} From 762f5171e341c479fd6880ceb6372f7c9106c255 Mon Sep 17 00:00:00 2001 From: YoungJin Cho Date: Sat, 7 Oct 2023 10:27:51 +0900 Subject: [PATCH 2/2] =?UTF-8?q?#63=20Fix:=20=EB=A7=81=ED=81=AC=20=EC=B6=94?= =?UTF-8?q?=EC=B6=9C=20regex=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../com/kakao/linknamu/kakao/service/KaKaoSendMeService.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/linknamu/src/main/java/com/kakao/linknamu/kakao/service/KaKaoSendMeService.java b/linknamu/src/main/java/com/kakao/linknamu/kakao/service/KaKaoSendMeService.java index 43d0b9d6..719ebd2a 100644 --- a/linknamu/src/main/java/com/kakao/linknamu/kakao/service/KaKaoSendMeService.java +++ b/linknamu/src/main/java/com/kakao/linknamu/kakao/service/KaKaoSendMeService.java @@ -40,7 +40,8 @@ public List extractLink(MultipartFile multipartFile) { String fileContent = new String(fileBytes, StandardCharsets.UTF_8); // byte 배열을 문자열로 변환 // https 링크를 추출하기 위한 정규 표현식 - String regex = "(https?://[a-zA-Z0-9\\-\\.]+(\\:[0-9]+)?\\.[a-zA-Z]{2,3}(\\S*)?)"; + String regex = "https?://[a-zA-Z0-9\\-\\.]+(\\:[0-9]+)?\\.[a-zA-Z]{2,3}(\\S*)?"; + // \bhttps?://\S+ => 모든 http, https 도메인 검출 Pattern pattern = Pattern.compile(regex);