diff --git a/src/main/java/cokr/xit/adds/biz/nims/web/BizNimsController.java b/src/main/java/cokr/xit/adds/biz/nims/web/BizNimsController.java index bb3a7cf..8fb4607 100644 --- a/src/main/java/cokr/xit/adds/biz/nims/web/BizNimsController.java +++ b/src/main/java/cokr/xit/adds/biz/nims/web/BizNimsController.java @@ -1,6 +1,5 @@ package cokr.xit.adds.biz.nims.web; -import java.io.IOException; import java.util.List; import org.springframework.validation.annotation.Validated; @@ -12,8 +11,6 @@ import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.RestController; import org.springframework.web.multipart.MultipartFile; -import com.google.zxing.NotFoundException; - import cokr.xit.adds.biz.nims.model.BizNimsRequest; import cokr.xit.adds.biz.nims.model.BizNimsResponse; import cokr.xit.adds.biz.nims.service.BizNimsService; @@ -164,21 +161,13 @@ public class BizNimsController { @Operation(summary = "barcode 이미지 제품 제조 정보 조회", description = "barcode 이미지 제품 제조 정보 조회

barcode 이미지를 통한 제품 제조 정보 조회") @PostMapping(value = "/getProductInfoByQrcodeImg", consumes = { "multipart/form-data" }) //@PostMapping(value = "/api/biz/nims/v1/getQrcode") - public ApiBaseResponse> getProductInfoByQrcodeImg( + public ApiBaseResponse getProductInfoByQrcodeImg( @RequestParam("uploadFiles") - final List multipartFiles + final MultipartFile mf ) { - List list = multipartFiles.stream().map(mf -> { - //System.out.println(mf.getOriginalFilename()); - //System.out.println(mf.getSize()); - try { - return bizNimsService.getPrdMnfSeqInfoOfBarcode(XingUtils.readQrcodeFromFile(XingUtils.convert(mf))); - } catch (IOException | NotFoundException e) { - throw new RuntimeException(e); - } - }).toList(); - - return ApiBaseResponse.of(list); + return ApiBaseResponse.of( + bizNimsService.getPrdMnfSeqInfoOfBarcode(XingUtils.readQrcodeFromFile(XingUtils.convert(mf))) + ); } diff --git a/src/main/java/cokr/xit/adds/core/spring/config/WebMvcConfig.java b/src/main/java/cokr/xit/adds/core/spring/config/WebMvcConfig.java index 3cadf3b..799676d 100644 --- a/src/main/java/cokr/xit/adds/core/spring/config/WebMvcConfig.java +++ b/src/main/java/cokr/xit/adds/core/spring/config/WebMvcConfig.java @@ -18,14 +18,18 @@ import org.springframework.http.converter.HttpMessageConverter; import org.springframework.http.converter.xml.AbstractXmlHttpMessageConverter; import org.springframework.http.converter.xml.MappingJackson2XmlHttpMessageConverter; import org.springframework.web.filter.CommonsRequestLoggingFilter; +import org.springframework.web.servlet.config.annotation.CorsRegistry; import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; import cokr.xit.adds.core.Constants; +import cokr.xit.adds.core.spring.config.properties.CorsProperties; import cokr.xit.adds.core.spring.filter.ReadableRequestWrapperFilter; +import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; @Slf4j @Configuration +@RequiredArgsConstructor public class WebMvcConfig implements WebMvcConfigurer { /** * logging exclude path @@ -33,6 +37,8 @@ public class WebMvcConfig implements WebMvcConfigurer { @Value("${app.log.request.exclude-patterns:}") private List EXCLUDE_URL_REGEXS; + private final CorsProperties corsProperties; + /** * MappingJackson2XmlHttpMessageConverter 순서를 가장 후순위로 조정 * @param converters @@ -100,4 +106,16 @@ public class WebMvcConfig implements WebMvcConfigurer { bean.addUrlPatterns(Constants.API_URL_PATTERNS); return bean; } + + @Override + public void addCorsMappings(CorsRegistry registry) { + registry.addMapping("/api/**") + .allowedOriginPatterns("*") + .allowedOrigins(corsProperties.getAllowedOrigins()) + .allowedMethods(corsProperties.getAllowedMethods()) + .allowedHeaders(corsProperties.getAllowedHeaders()) + .allowCredentials(corsProperties.getAllowCredentials()) + .maxAge(corsProperties.getMaxAge()) + .exposedHeaders(corsProperties.getExposeHeader()); + } } diff --git a/src/main/java/cokr/xit/adds/core/spring/config/properties/CorsProperties.java b/src/main/java/cokr/xit/adds/core/spring/config/properties/CorsProperties.java new file mode 100644 index 0000000..75ae85e --- /dev/null +++ b/src/main/java/cokr/xit/adds/core/spring/config/properties/CorsProperties.java @@ -0,0 +1,54 @@ +package cokr.xit.adds.core.spring.config.properties; + +import org.springframework.boot.context.properties.ConfigurationProperties; + +import lombok.Getter; +import lombok.Setter; + +/** + *
+ * description : CORS Properties
+ *               - properties : app.cors 항목에 정의
+ * fileName    : CorsProperties
+ * author      : julim
+ * date        : 2023-04-28
+ * ======================================================================
+ * 변경일         변경자        변경 내용
+ * ----------------------------------------------------------------------
+ * 2023-04-28    julim       최초 생성
+ *
+ * 
+ */ +@Getter +@Setter +@ConfigurationProperties(prefix = "app.cors") +public class CorsProperties { + /** + * 헤더에 작성된 출처만 브라우저가 리소스를 접근할 수 있도록 허용함. + * * 이면 모든 곳에 공개 + */ + private String[] allowedOrigins; + /** + * 리소스 접근을 허용하는 HTTP 메서드를 지정 + */ + private String[] allowedMethods; + /** + * 요청을 허용하는 해더 + */ + private String[] allowedHeaders; + /** + * 클라이언트에서 preflight 의 요청 결과를 저장할 기간을 지정 + * 해당 시간 동안 preflight 요청을 캐시하는 설정으로, 첫 요청 이후 60초 동안은 OPTIONS 메소드를 사용하는 예비 요청을 보내지 않는다. + */ + private Long maxAge; + /** + * 클라이언트 요청이 쿠키를 통해서 자격 증명을 해야 하는 경우에 true. + * 자바스크립트 요청에서 credentials가 include일 때 요청에 대한 응답을 할 수 있는지를 나타낸다. + */ + private Boolean allowCredentials; + /** + * 기본적으로 브라우저에게 노출이 되지 않지만, 브라우저 측에서 접근할 수 있게 허용해주는 헤더를 지정 + * Content-Length + */ + private String exposeHeader; +} diff --git a/src/main/java/cokr/xit/adds/core/util/XingUtils.java b/src/main/java/cokr/xit/adds/core/util/XingUtils.java index 49ac862..bc840d9 100644 --- a/src/main/java/cokr/xit/adds/core/util/XingUtils.java +++ b/src/main/java/cokr/xit/adds/core/util/XingUtils.java @@ -5,6 +5,7 @@ import java.io.FileInputStream; import java.io.IOException; import java.nio.charset.StandardCharsets; import java.nio.file.Files; +import java.nio.file.Path; import java.nio.file.Paths; import java.util.HashMap; import java.util.Map; @@ -24,9 +25,11 @@ import com.google.zxing.Result; import com.google.zxing.WriterException; import com.google.zxing.client.j2se.BufferedImageLuminanceSource; import com.google.zxing.client.j2se.MatrixToImageWriter; +import com.google.zxing.common.BitMatrix; import com.google.zxing.common.HybridBinarizer; import com.google.zxing.qrcode.decoder.ErrorCorrectionLevel; +import cokr.xit.adds.core.spring.exception.ApiCustomException; import lombok.val; /** @@ -52,39 +55,45 @@ public class XingUtils { hashMap.put(EncodeHintType.ERROR_CORRECTION, ErrorCorrectionLevel.L); } - public static String readQrcodeFromPath(final String path) throws IOException, NotFoundException { - val binaryBitmap = - new BinaryBitmap( - new HybridBinarizer( - new BufferedImageLuminanceSource( - ImageIO.read( - new FileInputStream(path) - ) - ) - ) - ); + public static String readQrcodeFromPath(final String path) { + try { + BinaryBitmap binaryBitmap = new BinaryBitmap( + new HybridBinarizer( + new BufferedImageLuminanceSource( + ImageIO.read( + new FileInputStream(path) + ) + ) + ) + ); + final Result result = new MultiFormatReader().decode(binaryBitmap); + + return result.getText(); + } catch (NotFoundException | IOException e) { + throw ApiCustomException.create("QR코드 읽기 실패"); + } - final Result result = new MultiFormatReader().decode(binaryBitmap); - return result.getText(); } - public static String readQrcodeFromFile(final File file) throws IOException, NotFoundException { - val binaryBitmap = - new BinaryBitmap( - new HybridBinarizer( - new BufferedImageLuminanceSource( - ImageIO.read( - file - ) - ) - ) - ); - - final Result result = - new MultiFormatReader().decode(binaryBitmap); + public static String readQrcodeFromFile(final File file) { + try { + BinaryBitmap binaryBitmap = new BinaryBitmap( + new HybridBinarizer( + new BufferedImageLuminanceSource( + ImageIO.read( + file + ) + ) + ) + ); + final Result result = new MultiFormatReader().decode(binaryBitmap); + return result.getText(); + + } catch (NotFoundException | IOException e) { + throw ApiCustomException.create("QR코드 읽기 실패"); + } - return result.getText(); } /** @@ -99,38 +108,47 @@ public class XingUtils { final String charset, final Integer height, final Integer width - ) throws IOException, WriterException { - String cs = charset; - if (StringUtils.isEmpty(charset)) { - cs = StandardCharsets.UTF_8.name(); - } - val matrix = - new MultiFormatWriter().encode( - new String(data.getBytes(cs), cs), - format, - width, - height + ) { + + try { + String cs = charset; + if (StringUtils.isEmpty(charset)) { + cs = StandardCharsets.UTF_8.name(); + } + BitMatrix matrix = new MultiFormatWriter().encode( + new String(data.getBytes(cs), cs), + format, + width, + height + ); + val filePath = Paths.get(QR_CODE_PATH, path); + MatrixToImageWriter.writeToPath( + matrix, + path.substring(path.lastIndexOf('.') + 1), + filePath ); - val filePath = Paths.get(QR_CODE_PATH, path); - - MatrixToImageWriter.writeToPath( - matrix, - path.substring(path.lastIndexOf('.') + 1), - filePath - ); - } + } catch (WriterException | IOException e) { + throw ApiCustomException.create("QR코드 생성 실패"); + } + } - public static File convert(final MultipartFile mf) throws IOException { + public static File convert(final MultipartFile mf) { val name = mf.getOriginalFilename(); - assert name != null; - val ext = name.substring(name.lastIndexOf(".")); - val filename = name.substring(0, name.lastIndexOf(".")); - val path = Files.createTempFile(filename, ext); - mf.transferTo(path); - return path.toFile(); + try { + val ext = name.substring(name.lastIndexOf(".")); + val filename = name.substring(0, name.lastIndexOf(".")); + Path path = Files.createTempFile(filename, ext); + mf.transferTo(path); + return path.toFile(); + + } catch (IOException e) { + throw new RuntimeException(e); + } + + } public static void main(String[] args) throws IOException, WriterException, NotFoundException { diff --git a/src/main/resources/application.yml b/src/main/resources/application.yml index 2a68d5a..5c88a08 100644 --- a/src/main/resources/application.yml +++ b/src/main/resources/application.yml @@ -126,13 +126,24 @@ spring: activate: on-profile: local - # h2: - # console: - # enabled: true - # path: /h2-console - # settings: - # trace: false - # web-allow-others: true + datasource: + hikari: + driver-class-name: net.sf.log4jdbc.sql.jdbcapi.DriverSpy #org.mariadb.jdbc.Driver + #driver-class-name: org.mariadb.jdbc.Driver + #jdbc-url: jdbc:mariadb://211.119.124.9:4407/egov?useUnicode=true&characterEncoding=utf-8&rewriteBatchedStatements=true&autoReconnect=true + # jdbc-url: jdbc:log4jdbc:mariadb://211.119.124.9:4407/adds?useUnicode=true&characterEncoding=utf-8&rewriteBatchedStatements=true&autoReconnect=true + # username: addsweb + # password: addsweb1234 + jdbc-url: ENC(O26qFSqrfqMEjEU6jHUqrboYIPpTnwDIHIYQg2ddL0k7VsGvDbAMd/SwDeXjan17CykVLz3Qe++xW+VqxvQpT7/+Kxhl2ry1hTElOPxRHp6OrN/8GyhaScLCcBZgpxNcEAZ3a5qWJKIyLR/+KFk6YpW77lD10jFJvscNNYvFoWQIs/K5eAa/m3JnktX9Ed2RN8ttGgBET5g=) + username: ENC(M4g3XkH/bzupKW2w4WYH3Q==) + password: ENC(fzV0zekJQ7t/QHiz75k+xqdsDUWW6+MY) + auto-commit: false + + devtools: + restart: + enabled: false + livereload: + enabled: true sql: init: @@ -141,6 +152,8 @@ spring: # data-locations: classpath:database/data.sql app: + cors: + allowed-origins: http://localhost:9077 swagger: url: desc: 사고마약류폐기지원시스템 @@ -154,3 +167,38 @@ app: enabled: false # batch 실행 url 제외 패턴 exclude-patterns: '/api/batch/(.*), /api/batch/v1/*Bulks(.*)' + +--- +spring: + config: + activate: + on-profile: prod + + datasource: + hikari: + driver-class-name: net.sf.log4jdbc.sql.jdbcapi.DriverSpy #org.mariadb.jdbc.Driver + #driver-class-name: org.mariadb.jdbc.Driver + #jdbc-url: jdbc:mariadb://211.119.124.9:4407/egov?useUnicode=true&characterEncoding=utf-8&rewriteBatchedStatements=true&autoReconnect=true + # jdbc-url: jdbc:log4jdbc:mariadb://211.119.124.9:4407/adds?useUnicode=true&characterEncoding=utf-8&rewriteBatchedStatements=true&autoReconnect=true + # username: addsweb + # password: addsweb1234 + jdbc-url: ENC(O26qFSqrfqMEjEU6jHUqrboYIPpTnwDIHIYQg2ddL0k7VsGvDbAMd/SwDeXjan17CykVLz3Qe++xW+VqxvQpT7/+Kxhl2ry1hTElOPxRHp6OrN/8GyhaScLCcBZgpxNcEAZ3a5qWJKIyLR/+KFk6YpW77lD10jFJvscNNYvFoWQIs/K5eAa/m3JnktX9Ed2RN8ttGgBET5g=) + username: ENC(M4g3XkH/bzupKW2w4WYH3Q==) + password: ENC(fzV0zekJQ7t/QHiz75k+xqdsDUWW6+MY) + auto-commit: false + +springdoc: + api-docs: + enabled: true + swagger-ui: + enabled: true + path: /swagger-ui.html + csrf: + enabled: false + +app: + cors: + allowed-origins: http://localhost:9077, http://localhost:8081 + log: + parameter-enabled: true + response-enabled: true diff --git a/src/main/resources/config/application-app.yml b/src/main/resources/config/application-app.yml index a3ebcbe..ba77a11 100644 --- a/src/main/resources/config/application-app.yml +++ b/src/main/resources/config/application-app.yml @@ -10,6 +10,25 @@ app: secretKey: xit5811807!@ alg: PBEWithMD5AndDES type: base64 + + cors: + # 헤더에 작성된 출처만 브라우저가 리소스를 접근할 수 있도록 허용함. + # * 이면 모든 곳에 공개 + #allowed-origins: http://localhost:8080,http:127.0.0.1:8080 + # 리소스 접근을 허용하는 HTTP 메서드를 지정 + allowed-methods: GET, POST, PUT, DELETE + # 요청을 허용하는 해더 + allowed-headers: Origin, Accept, X-Requested-With, Content-Type, Access-Control-Request-Method, Access-Control-Request-Headers, X-Csrftoken, Authorization + #allowed-headers: Origin, Accept, X-Requested-With, Content-Type, Access-Control-Request-Method, Access-Control-Request-Headers, X-Csrftoken, Authorization, Content-Security-Policy + # 클라이언트에서 preflight 의 요청 결과를 저장할 기간을 지정 + # 60초 동안 preflight 요청을 캐시하는 설정으로, 첫 요청 이후 60초 동안은 OPTIONS 메소드를 사용하는 예비 요청을 보내지 않는다. + max-Age: 60 + # 클라이언트 요청이 쿠키를 통해서 자격 증명을 해야 하는 경우에 true. + # 자바스크립트 요청에서 credentials가 include일 때 요청에 대한 응답을 할 수 있는지를 나타낸다. + allow-Credentials: true + # 기본적으로 브라우저에게 노출이 되지 않지만, 브라우저 측에서 접근할 수 있게 허용해주는 헤더를 지정 + expose-Headers: Content-Length + token: typ: JWT alg: HS512