From d2bebb01853384cced71e0d7ae8c3d549a7d297f Mon Sep 17 00:00:00 2001 From: JIUNG GU <60885635+JIUNG9@users.noreply.github.com> Date: Tue, 23 Jan 2024 13:40:21 +0900 Subject: [PATCH] feat: add the extract business number from the image --- .../flower/auth/common/config/WebConfig.java | 7 ++ .../filter/JwtAuthenticationFilter.java | 3 +- ...shInRedisTokenWhenAccessTokenExpired.java} | 3 +- ...thenticationShouldNotFilterAntMatcher.java | 1 + .../auth/store/dto/BusinessImageUrlDto.java | 13 ++ .../auth/store/dto/ImageRequestDto.java | 53 +++++++++ .../auth/store/dto/ImageResponseDto.java | 111 ++++++++++++++++++ .../store/dto/StoreMangerSignUpCommand.java | 2 + .../StoreManagerRestController.java | 14 ++- .../StoreMangerAuthorizationFilter.java | 3 +- .../store/service/NaverClovaOCRService.java | 76 ++++++++++++ ...RequestBusinessNumberFromImageService.java | 9 ++ 12 files changed, 289 insertions(+), 6 deletions(-) rename src/main/java/com/bit/lot/flower/auth/common/service/{RenewRefreshTokenWhenAccessTokenExpired.java => RenewRefreshInRedisTokenWhenAccessTokenExpired.java} (96%) create mode 100644 src/main/java/com/bit/lot/flower/auth/store/dto/BusinessImageUrlDto.java create mode 100644 src/main/java/com/bit/lot/flower/auth/store/dto/ImageRequestDto.java create mode 100644 src/main/java/com/bit/lot/flower/auth/store/dto/ImageResponseDto.java create mode 100644 src/main/java/com/bit/lot/flower/auth/store/service/NaverClovaOCRService.java create mode 100644 src/main/java/com/bit/lot/flower/auth/store/service/RequestBusinessNumberFromImageService.java diff --git a/src/main/java/com/bit/lot/flower/auth/common/config/WebConfig.java b/src/main/java/com/bit/lot/flower/auth/common/config/WebConfig.java index d2347f69..f894d2b2 100644 --- a/src/main/java/com/bit/lot/flower/auth/common/config/WebConfig.java +++ b/src/main/java/com/bit/lot/flower/auth/common/config/WebConfig.java @@ -5,6 +5,9 @@ import lombok.RequiredArgsConstructor; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; +import org.springframework.security.config.annotation.web.builders.WebSecurity; +import org.springframework.security.web.firewall.DefaultHttpFirewall; +import org.springframework.security.web.firewall.HttpFirewall; import org.springframework.web.client.RestTemplate; import org.springframework.web.servlet.config.annotation.CorsRegistry; import org.springframework.web.servlet.config.annotation.EnableWebMvc; @@ -51,7 +54,11 @@ public void addCorsMappings(CorsRegistry registry) { .allowedHeaders("*") .exposedHeaders("*") .allowCredentials(false); + } + @Bean + public HttpFirewall defaultHttpFirewall() { + return new DefaultHttpFirewall(); } diff --git a/src/main/java/com/bit/lot/flower/auth/common/http/interceptor/filter/JwtAuthenticationFilter.java b/src/main/java/com/bit/lot/flower/auth/common/http/interceptor/filter/JwtAuthenticationFilter.java index d9176d0c..4b029932 100644 --- a/src/main/java/com/bit/lot/flower/auth/common/http/interceptor/filter/JwtAuthenticationFilter.java +++ b/src/main/java/com/bit/lot/flower/auth/common/http/interceptor/filter/JwtAuthenticationFilter.java @@ -67,7 +67,8 @@ private boolean shouldNotFilterBySystemPolicy(HttpServletRequest request) { return requestURI.contains(JWTAuthenticationShouldNotFilterAntMatcher.SIGNUP_ANT) || requestURI.contains(JWTAuthenticationShouldNotFilterAntMatcher.LOGIN_ANT) || requestURI.contains(JWTAuthenticationShouldNotFilterAntMatcher.EMAIL_ANT) - || requestURI.contains(JWTAuthenticationShouldNotFilterAntMatcher.REFRESH_ANT); + || requestURI.contains(JWTAuthenticationShouldNotFilterAntMatcher.REFRESH_ANT) + || requestURI.contains(JWTAuthenticationShouldNotFilterAntMatcher.STORE_MANAGER_OCR); } diff --git a/src/main/java/com/bit/lot/flower/auth/common/service/RenewRefreshTokenWhenAccessTokenExpired.java b/src/main/java/com/bit/lot/flower/auth/common/service/RenewRefreshInRedisTokenWhenAccessTokenExpired.java similarity index 96% rename from src/main/java/com/bit/lot/flower/auth/common/service/RenewRefreshTokenWhenAccessTokenExpired.java rename to src/main/java/com/bit/lot/flower/auth/common/service/RenewRefreshInRedisTokenWhenAccessTokenExpired.java index 32eda252..708ff9dc 100644 --- a/src/main/java/com/bit/lot/flower/auth/common/service/RenewRefreshTokenWhenAccessTokenExpired.java +++ b/src/main/java/com/bit/lot/flower/auth/common/service/RenewRefreshInRedisTokenWhenAccessTokenExpired.java @@ -10,7 +10,6 @@ import io.jsonwebtoken.ExpiredJwtException; import io.jsonwebtoken.MalformedJwtException; import io.jsonwebtoken.UnsupportedJwtException; -import java.io.IOException; import java.util.HashMap; import java.util.Map; import javax.servlet.http.HttpServletRequest; @@ -22,7 +21,7 @@ @RequiredArgsConstructor @Service -public class RenewRefreshTokenWhenAccessTokenExpired implements +public class RenewRefreshInRedisTokenWhenAccessTokenExpired implements RenewRefreshTokenStrategy { private final RedisBlackListTokenUtil redisBlackListTokenUtil; diff --git a/src/main/java/com/bit/lot/flower/auth/common/valueobject/JWTAuthenticationShouldNotFilterAntMatcher.java b/src/main/java/com/bit/lot/flower/auth/common/valueobject/JWTAuthenticationShouldNotFilterAntMatcher.java index d1c5a571..522084a7 100644 --- a/src/main/java/com/bit/lot/flower/auth/common/valueobject/JWTAuthenticationShouldNotFilterAntMatcher.java +++ b/src/main/java/com/bit/lot/flower/auth/common/valueobject/JWTAuthenticationShouldNotFilterAntMatcher.java @@ -6,6 +6,7 @@ public class JWTAuthenticationShouldNotFilterAntMatcher { public static final String EMAIL_ANT = "/emails"; public static final String SIGNUP_ANT = "/signup"; public static final String REFRESH_ANT = "/refresh"; + public static final String STORE_MANAGER_OCR ="/stores/business-image-number"; } diff --git a/src/main/java/com/bit/lot/flower/auth/store/dto/BusinessImageUrlDto.java b/src/main/java/com/bit/lot/flower/auth/store/dto/BusinessImageUrlDto.java new file mode 100644 index 00000000..21dce43b --- /dev/null +++ b/src/main/java/com/bit/lot/flower/auth/store/dto/BusinessImageUrlDto.java @@ -0,0 +1,13 @@ +package com.bit.lot.flower.auth.store.dto; + +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.NoArgsConstructor; + +@AllArgsConstructor +@NoArgsConstructor +@Getter +public class BusinessImageUrlDto { + + private String imageUrl; +} diff --git a/src/main/java/com/bit/lot/flower/auth/store/dto/ImageRequestDto.java b/src/main/java/com/bit/lot/flower/auth/store/dto/ImageRequestDto.java new file mode 100644 index 00000000..2c54cde7 --- /dev/null +++ b/src/main/java/com/bit/lot/flower/auth/store/dto/ImageRequestDto.java @@ -0,0 +1,53 @@ +package com.bit.lot.flower.auth.store.dto; + +import com.fasterxml.jackson.annotation.JsonProperty; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Getter; +import lombok.NoArgsConstructor; + +@AllArgsConstructor +@NoArgsConstructor +@Getter +@Builder +public class ImageRequestDto { + + @JsonProperty("images") + private Image[] images; + + @JsonProperty("lang") + private String lang; + + @JsonProperty("requestId") + private String requestId; + + @JsonProperty("resultType") + private String resultType; + + @JsonProperty("timestamp") + private long timestamp; + + @JsonProperty("version") + private String version; + + @AllArgsConstructor + @NoArgsConstructor + @Getter + @Builder + public static class Image { + + @JsonProperty("format") + private String format; + + @JsonProperty("name") + private String name; + + @JsonProperty("data") + private Object data; + + @JsonProperty("url") + private String url; + + + } +} diff --git a/src/main/java/com/bit/lot/flower/auth/store/dto/ImageResponseDto.java b/src/main/java/com/bit/lot/flower/auth/store/dto/ImageResponseDto.java new file mode 100644 index 00000000..ad986d25 --- /dev/null +++ b/src/main/java/com/bit/lot/flower/auth/store/dto/ImageResponseDto.java @@ -0,0 +1,111 @@ +package com.bit.lot.flower.auth.store.dto; + + +import com.fasterxml.jackson.annotation.JsonProperty; +import java.util.List; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Getter; +import lombok.NoArgsConstructor; + +@AllArgsConstructor +@NoArgsConstructor +@Getter +@Builder +public class ImageResponseDto { + + @JsonProperty("version") + private String version; + + @JsonProperty("requestId") + private String requestId; + + @JsonProperty("timestamp") + private long timestamp; + + @JsonProperty("images") + private List images; + + + @AllArgsConstructor + @NoArgsConstructor + @Getter + @Builder + public static class ImageInfo { + + @JsonProperty("uid") + private String uid; + + @JsonProperty("name") + private String name; + + @JsonProperty("inferResult") + private String inferResult; + + @JsonProperty("message") + private String message; + + @JsonProperty("validationResult") + private ValidationResult validationResult; + + @JsonProperty("fields") + private List fields; + + + @AllArgsConstructor + @NoArgsConstructor + @Getter + @Builder + public static class ValidationResult { + + @JsonProperty("result") + private String result; + + + } + + @AllArgsConstructor + @NoArgsConstructor + @Getter + @Builder + public static class FieldInfo { + + @JsonProperty("valueType") + private String valueType; + + @JsonProperty("boundingPoly") + private BoundingPoly boundingPoly; + + @JsonProperty("inferText") + private String inferText; + + @JsonProperty("inferConfidence") + private double inferConfidence; + + @AllArgsConstructor + @NoArgsConstructor + @Getter + @Builder + public static class BoundingPoly { + + @JsonProperty("vertices") + private List vertices; + + + @AllArgsConstructor + @NoArgsConstructor + @Getter + @Builder + public static class Vertex { + + @JsonProperty("x") + private double x; + + @JsonProperty("y") + private double y; + + } + } + } + } +} diff --git a/src/main/java/com/bit/lot/flower/auth/store/dto/StoreMangerSignUpCommand.java b/src/main/java/com/bit/lot/flower/auth/store/dto/StoreMangerSignUpCommand.java index f827c453..6b42eb72 100644 --- a/src/main/java/com/bit/lot/flower/auth/store/dto/StoreMangerSignUpCommand.java +++ b/src/main/java/com/bit/lot/flower/auth/store/dto/StoreMangerSignUpCommand.java @@ -32,4 +32,6 @@ public class StoreMangerSignUpCommand { @URL @NotNull private String businessNumberImage; + @NotNull + private String businessNumber; } diff --git a/src/main/java/com/bit/lot/flower/auth/store/http/controller/StoreManagerRestController.java b/src/main/java/com/bit/lot/flower/auth/store/http/controller/StoreManagerRestController.java index a45fba92..45901660 100644 --- a/src/main/java/com/bit/lot/flower/auth/store/http/controller/StoreManagerRestController.java +++ b/src/main/java/com/bit/lot/flower/auth/store/http/controller/StoreManagerRestController.java @@ -3,6 +3,7 @@ import bloomingblooms.response.CommonResponse; import com.bit.lot.flower.auth.common.valueobject.AuthId; +import com.bit.lot.flower.auth.store.dto.BusinessImageUrlDto; import com.bit.lot.flower.auth.store.dto.StoreManagerLoginResponseWithNameAndStoreId; import com.bit.lot.flower.auth.store.dto.StoreMangerSignUpCommand; import com.bit.lot.flower.auth.store.http.message.StoreManagerNameRequest; @@ -10,6 +11,7 @@ import com.bit.lot.flower.auth.store.mapper.StoreManagerMessageMapper; import com.bit.lot.flower.auth.store.message.StoreMangerCreateRequest; import com.bit.lot.flower.auth.store.service.EmailDuplicationCheckerService; +import com.bit.lot.flower.auth.store.service.RequestBusinessNumberFromImageService; import com.bit.lot.flower.auth.store.service.StoreManagerService; import com.bit.lot.flower.auth.store.valueobject.StoreId; import com.fasterxml.jackson.core.JsonProcessingException; @@ -18,6 +20,7 @@ import lombok.extern.slf4j.Slf4j; import org.springframework.security.core.annotation.AuthenticationPrincipal; import org.springframework.security.core.context.SecurityContextHolder; +import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestBody; @@ -26,13 +29,20 @@ @Slf4j @RequiredArgsConstructor @RestController -public class StoreManagerRestController{ +public class StoreManagerRestController { private final StoreManagerNameRequest storeManagerNameRequest; - private final StoreManagerStoreIdRequest storeManagerStoreIdRequest; + private final StoreManagerStoreIdRequest storeManagerStoreIdRequest; private final EmailDuplicationCheckerService emailDuplicationCheckerService; private final StoreManagerService storeManagerService; private final StoreMangerCreateRequest storeMangerCreateRequest; + private final RequestBusinessNumberFromImageService requestBusinessNumberFromImageService; + + @PostMapping("/stores/business-image-number") + public CommonResponse getBusinessNumber(@RequestBody BusinessImageUrlDto dto) { + return CommonResponse.success( + requestBusinessNumberFromImageService.getBusinessNumber(dto.getImageUrl())); + } @PostMapping("/stores/emails/{email}") diff --git a/src/main/java/com/bit/lot/flower/auth/store/http/filter/StoreMangerAuthorizationFilter.java b/src/main/java/com/bit/lot/flower/auth/store/http/filter/StoreMangerAuthorizationFilter.java index 54bee272..eaa92912 100644 --- a/src/main/java/com/bit/lot/flower/auth/store/http/filter/StoreMangerAuthorizationFilter.java +++ b/src/main/java/com/bit/lot/flower/auth/store/http/filter/StoreMangerAuthorizationFilter.java @@ -20,7 +20,8 @@ protected boolean shouldNotFilter(HttpServletRequest request) { String requestURI = request.getRequestURI(); return !requestURI.contains("/stores") || requestURI.contains("/stores/login") || requestURI.contains("/stores/signup") || - requestURI.contains("/stores/emails"); + requestURI.contains("/stores/emails") || + requestURI.contains("/stores/business-image-number"); } diff --git a/src/main/java/com/bit/lot/flower/auth/store/service/NaverClovaOCRService.java b/src/main/java/com/bit/lot/flower/auth/store/service/NaverClovaOCRService.java new file mode 100644 index 00000000..54af70a4 --- /dev/null +++ b/src/main/java/com/bit/lot/flower/auth/store/service/NaverClovaOCRService.java @@ -0,0 +1,76 @@ +package com.bit.lot.flower.auth.store.service; + +import com.bit.lot.flower.auth.store.dto.ImageRequestDto; +import com.bit.lot.flower.auth.store.dto.ImageResponseDto; +import com.bit.lot.flower.auth.store.dto.ImageResponseDto.ImageInfo.FieldInfo; +import java.net.URLEncoder; +import java.nio.charset.StandardCharsets; +import java.util.Optional; +import lombok.RequiredArgsConstructor; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.http.HttpEntity; +import org.springframework.http.HttpHeaders; +import org.springframework.http.MediaType; +import org.springframework.stereotype.Service; +import org.springframework.web.client.RestTemplate; + +@RequiredArgsConstructor +@Service +public class NaverClovaOCRService implements + RequestBusinessNumberFromImageService { + + private final RestTemplate restTemplate; + @Value("${ocr.naver.secret}") + private String ocrSecret; + + @Override + public String getBusinessNumber(String imageUrl) { + + HttpHeaders headers = new HttpHeaders(); + headers.setContentType(MediaType.APPLICATION_JSON); + + headers.set("X-OCR-SECRET", ocrSecret); + ImageRequestDto requestDto = createImageRequestDtoByImageUrl(imageUrl); + + HttpEntity requestEntity = new HttpEntity<>(requestDto, headers); + + String apiUrl = "https://5uwmtf47oq.apigw.ntruss.com/custom/v1/27880/634611cfef823f53c9ee0a045d3cbfddfa75b4154fbb56e2b30019466f39fedc/general"; + + + ImageResponseDto response = restTemplate.postForObject(apiUrl, requestEntity, + ImageResponseDto.class); + + return getBusinessNumberFromResponse(response); + + + } + + private String getBusinessNumberFromResponse(ImageResponseDto responseDto) { + + Optional businessNumberfield = responseDto.getImages().stream() + .flatMap(imageInfo -> imageInfo.getFields().stream()) + .filter(fieldInfo -> fieldInfo.getInferText().contains("-")) + .findFirst(); + + if (businessNumberfield.isPresent()) { + return businessNumberfield.get().getInferText(); + } + + throw new IllegalArgumentException("사업자 등록 번호를 찾을 수 없습니다."); + } + + private ImageRequestDto createImageRequestDtoByImageUrl(String imageUrl) { + ImageRequestDto.Image[] image = {createImage(imageUrl)}; + return ImageRequestDto.builder().images(image).lang("ko").requestId("string") + .resultType("string") + .version("V1").timestamp(System.currentTimeMillis()).build(); + } + + private ImageRequestDto.Image createImage(String imageUrl) { + return ImageRequestDto.Image.builder().data(null).format("jpg").name("medium").url(imageUrl) + .build(); + + + } + +} diff --git a/src/main/java/com/bit/lot/flower/auth/store/service/RequestBusinessNumberFromImageService.java b/src/main/java/com/bit/lot/flower/auth/store/service/RequestBusinessNumberFromImageService.java new file mode 100644 index 00000000..d07dd151 --- /dev/null +++ b/src/main/java/com/bit/lot/flower/auth/store/service/RequestBusinessNumberFromImageService.java @@ -0,0 +1,9 @@ +package com.bit.lot.flower.auth.store.service; + +import org.springframework.stereotype.Service; + +@Service +public interface RequestBusinessNumberFromImageService { + + public String getBusinessNumber(String imageUrl); +}