commons-configuration
diff --git a/mens-core/src/main/java/kr/xit/biz/ens/model/cmm/CmmEnsFileDTO.java b/mens-core/src/main/java/kr/xit/biz/ens/model/cmm/CmmEnsFileDTO.java
index c1b0cc3..8e8656f 100644
--- a/mens-core/src/main/java/kr/xit/biz/ens/model/cmm/CmmEnsFileDTO.java
+++ b/mens-core/src/main/java/kr/xit/biz/ens/model/cmm/CmmEnsFileDTO.java
@@ -33,7 +33,7 @@ public class CmmEnsFileDTO {
@NoArgsConstructor
@AllArgsConstructor
@SuperBuilder
- @JsonInclude(JsonInclude.Include.NON_EMPTY)
+ @JsonInclude(JsonInclude.Include.NON_NULL)
public static class FmcExcelUpload {
//-----------------------------------------------------------------------------------
@@ -95,7 +95,7 @@ public class CmmEnsFileDTO {
@NoArgsConstructor
@AllArgsConstructor
@SuperBuilder
- @JsonInclude(JsonInclude.Include.NON_EMPTY)
+ @JsonInclude(JsonInclude.Include.NON_NULL)
public static class FmcExcel {
//-----------------------------------------------------------------------------------
diff --git a/mens-core/src/main/java/kr/xit/biz/ens/model/kakao/KkopayDocAttrDTO.java b/mens-core/src/main/java/kr/xit/biz/ens/model/kakao/KkopayDocAttrDTO.java
index 33532c6..0cb4f61 100644
--- a/mens-core/src/main/java/kr/xit/biz/ens/model/kakao/KkopayDocAttrDTO.java
+++ b/mens-core/src/main/java/kr/xit/biz/ens/model/kakao/KkopayDocAttrDTO.java
@@ -36,7 +36,7 @@ public class KkopayDocAttrDTO {
@NoArgsConstructor
@AllArgsConstructor
@SuperBuilder
- @JsonInclude(JsonInclude.Include.NON_EMPTY)
+ @JsonInclude(JsonInclude.Include.NON_NULL)
public static class Send implements IApiResponse {
/**
* 발송할 문서의 제목 : 필수
@@ -91,7 +91,7 @@ public class KkopayDocAttrDTO {
@NoArgsConstructor
@AllArgsConstructor
@SuperBuilder
- @JsonInclude(JsonInclude.Include.NON_EMPTY)
+ @JsonInclude(JsonInclude.Include.NON_NULL)
public static class Receiver {
/**
* 받는이 CI
@@ -137,7 +137,7 @@ public class KkopayDocAttrDTO {
@Data
@SuperBuilder
@NoArgsConstructor
- @JsonInclude(JsonInclude.Include.NON_EMPTY)
+ @JsonInclude(JsonInclude.Include.NON_NULL)
public static class Property {
/**
* 본인인증 후 사용자에게 보여줄 웹페이지 주소 : 필수
@@ -185,7 +185,7 @@ public class KkopayDocAttrDTO {
@SuperBuilder
@NoArgsConstructor
@AllArgsConstructor
- @JsonInclude(JsonInclude.Include.NON_EMPTY)
+ @JsonInclude(JsonInclude.Include.NON_NULL)
public static class DocumentBinderUuid implements IApiResponse {
/**
* 카카오페이 문서식별번호(max:40) - 필수
@@ -200,7 +200,7 @@ public class KkopayDocAttrDTO {
@SuperBuilder
@NoArgsConstructor
@AllArgsConstructor
- @JsonInclude(JsonInclude.Include.NON_EMPTY)
+ @JsonInclude(JsonInclude.Include.NON_NULL)
public static class DocStatus implements IApiResponse {
/**
*
diff --git a/mens-core/src/main/java/kr/xit/biz/ens/model/kakao/KkopayDocBulkDTO.java b/mens-core/src/main/java/kr/xit/biz/ens/model/kakao/KkopayDocBulkDTO.java
index 33979f1..80271b4 100644
--- a/mens-core/src/main/java/kr/xit/biz/ens/model/kakao/KkopayDocBulkDTO.java
+++ b/mens-core/src/main/java/kr/xit/biz/ens/model/kakao/KkopayDocBulkDTO.java
@@ -85,7 +85,7 @@ public class KkopayDocBulkDTO extends KkopayDocAttrDTO {
@SuperBuilder
@NoArgsConstructor
@AllArgsConstructor
- @JsonInclude(JsonInclude.Include.NON_EMPTY)
+ @JsonInclude(JsonInclude.Include.NON_NULL)
public static class BulkSendRes {
/**
* 문서 아이디(외부)(max=40) - 필수
@@ -148,7 +148,7 @@ public class KkopayDocBulkDTO extends KkopayDocAttrDTO {
@SuperBuilder
@NoArgsConstructor
@AllArgsConstructor
- @JsonInclude(JsonInclude.Include.NON_EMPTY)
+ @JsonInclude(JsonInclude.Include.NON_NULL)
public static class BulkStatus {
/**
* 카카오페이 문서식별 번호(max:40) - 필수
diff --git a/mens-core/src/main/java/kr/xit/biz/ens/model/kakao/KkopayDocDTO.java b/mens-core/src/main/java/kr/xit/biz/ens/model/kakao/KkopayDocDTO.java
index 0181e0a..1c6eaed 100644
--- a/mens-core/src/main/java/kr/xit/biz/ens/model/kakao/KkopayDocDTO.java
+++ b/mens-core/src/main/java/kr/xit/biz/ens/model/kakao/KkopayDocDTO.java
@@ -106,7 +106,7 @@ public class KkopayDocDTO extends KkopayDocAttrDTO {
@SuperBuilder
@NoArgsConstructor
@AllArgsConstructor
- @JsonInclude(JsonInclude.Include.NON_EMPTY)
+ @JsonInclude(JsonInclude.Include.NON_NULL)
public static class ValidTokenResponse implements IApiResponse {
/**
* 토큰상태값(성공시 USED) : 필수
@@ -192,7 +192,7 @@ public class KkopayDocDTO extends KkopayDocAttrDTO {
@NoArgsConstructor
@AllArgsConstructor
@ToString
- @JsonInclude(JsonInclude.Include.NON_EMPTY)
+ @JsonInclude(JsonInclude.Include.NON_NULL)
@EqualsAndHashCode(callSuper = true)
public static class OneTimeToken extends ValidTokenRequest {
/**
diff --git a/mens-core/src/main/java/kr/xit/biz/ens/model/nice/NiceCiDTO.java b/mens-core/src/main/java/kr/xit/biz/ens/model/nice/NiceCiDTO.java
index b207433..103f1cd 100644
--- a/mens-core/src/main/java/kr/xit/biz/ens/model/nice/NiceCiDTO.java
+++ b/mens-core/src/main/java/kr/xit/biz/ens/model/nice/NiceCiDTO.java
@@ -2,9 +2,7 @@ package kr.xit.biz.ens.model.nice;
import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.annotation.JsonInclude.Include;
-import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.databind.PropertyNamingStrategies;
-import com.fasterxml.jackson.databind.PropertyNamingStrategy;
import com.fasterxml.jackson.databind.annotation.JsonNaming;
import io.swagger.v3.oas.annotations.media.Schema;
import io.swagger.v3.oas.annotations.media.Schema.RequiredMode;
@@ -12,9 +10,6 @@ import java.io.Serializable;
import java.util.HashMap;
import java.util.Map;
import javax.validation.Valid;
-import javax.validation.constraints.Max;
-import javax.validation.constraints.Min;
-import javax.validation.constraints.NotBlank;
import javax.validation.constraints.Size;
import kr.xit.biz.common.AuditFields;
import kr.xit.core.model.IApiResponse;
@@ -25,7 +20,6 @@ import lombok.Builder.Default;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.experimental.SuperBuilder;
-import org.hibernate.validator.constraints.Length;
/**
*
@@ -58,7 +52,7 @@ public class NiceCiDTO {
@NoArgsConstructor
@AllArgsConstructor
@Builder
- @JsonInclude(JsonInclude.Include.NON_EMPTY)
+ @JsonInclude(JsonInclude.Include.NON_NULL)
@JsonNaming(PropertyNamingStrategies.SnakeCaseStrategy.class)
public static class TokenRequest {
/**
@@ -90,7 +84,7 @@ public class NiceCiDTO {
@NoArgsConstructor
@AllArgsConstructor
@SuperBuilder
- @JsonInclude(JsonInclude.Include.NON_EMPTY)
+ @JsonInclude(JsonInclude.Include.NON_NULL)
public static class TokenResponse implements IApiResponse {
@Schema(requiredMode = RequiredMode.REQUIRED)
@Valid
@@ -111,7 +105,7 @@ public class NiceCiDTO {
@NoArgsConstructor
@AllArgsConstructor
@SuperBuilder
- @JsonInclude(JsonInclude.Include.NON_EMPTY)
+ @JsonInclude(JsonInclude.Include.NON_NULL)
public static class TokenRevokeResponse implements IApiResponse {
@Schema(requiredMode = RequiredMode.REQUIRED)
@@ -134,7 +128,7 @@ public class NiceCiDTO {
@NoArgsConstructor
@AllArgsConstructor
@SuperBuilder
- @JsonInclude(JsonInclude.Include.NON_EMPTY)
+ @JsonInclude(JsonInclude.Include.NON_NULL)
@JsonNaming(PropertyNamingStrategies.SnakeCaseStrategy.class)
public static class TokenResDataBody {
//-----------------------------------------------------------------------
@@ -210,7 +204,7 @@ public class NiceCiDTO {
@NoArgsConstructor
@AllArgsConstructor
@SuperBuilder
- @JsonInclude(JsonInclude.Include.NON_EMPTY)
+ @JsonInclude(JsonInclude.Include.NON_NULL)
public static class PublickeyRequest {
@Schema(requiredMode = RequiredMode.REQUIRED)
@Valid
@@ -231,8 +225,8 @@ public class NiceCiDTO {
@NoArgsConstructor
@AllArgsConstructor
@SuperBuilder
- @JsonInclude(JsonInclude.Include.NON_EMPTY)
- public static class PublickeyResponse implements IApiResponse {
+ @JsonInclude(JsonInclude.Include.NON_NULL)
+ public static class PublickeyResponse { //implements IApiResponse {
@Schema(requiredMode = RequiredMode.REQUIRED)
@Valid
private ResponseDataHeader dataHeader;
@@ -253,7 +247,7 @@ public class NiceCiDTO {
@NoArgsConstructor
@AllArgsConstructor
@SuperBuilder
- @JsonInclude(JsonInclude.Include.NON_EMPTY)
+ @JsonInclude(JsonInclude.Include.NON_NULL)
@JsonNaming(PropertyNamingStrategies.SnakeCaseStrategy.class)
public static class PublickeyReqDataBody {
/**
@@ -275,7 +269,7 @@ public class NiceCiDTO {
@NoArgsConstructor
@AllArgsConstructor
@SuperBuilder
- @JsonInclude(Include.NON_EMPTY)
+ @JsonInclude(Include.NON_NULL)
@JsonNaming(PropertyNamingStrategies.SnakeCaseStrategy.class)
public static class PublickeyResDataBody {
/**
@@ -354,7 +348,7 @@ public class NiceCiDTO {
@NoArgsConstructor
@AllArgsConstructor
@SuperBuilder
- @JsonInclude(JsonInclude.Include.NON_EMPTY)
+ @JsonInclude(JsonInclude.Include.NON_NULL)
public static class SymmetrickeyRegRequest {
@Schema(requiredMode = RequiredMode.REQUIRED)
@Valid
@@ -375,7 +369,7 @@ public class NiceCiDTO {
@NoArgsConstructor
@AllArgsConstructor
@SuperBuilder
- @JsonInclude(JsonInclude.Include.NON_EMPTY)
+ @JsonInclude(JsonInclude.Include.NON_NULL)
public static class SymmetrickeyRegResponse implements IApiResponse {
@Schema(requiredMode = RequiredMode.REQUIRED)
@Valid
@@ -397,7 +391,7 @@ public class NiceCiDTO {
@NoArgsConstructor
@AllArgsConstructor
@SuperBuilder
- @JsonInclude(JsonInclude.Include.NON_EMPTY)
+ @JsonInclude(JsonInclude.Include.NON_NULL)
@JsonNaming(PropertyNamingStrategies.SnakeCaseStrategy.class)
public static class SymmetrickeyRegReqDataBody {
/**
@@ -438,7 +432,7 @@ public class NiceCiDTO {
@NoArgsConstructor
@AllArgsConstructor
@SuperBuilder
- @JsonInclude(Include.NON_EMPTY)
+ @JsonInclude(Include.NON_NULL)
@JsonNaming(PropertyNamingStrategies.SnakeCaseStrategy.class)
public static class SymmetrickeyRegResDataBody {
/**
@@ -506,7 +500,7 @@ public class NiceCiDTO {
@NoArgsConstructor
@AllArgsConstructor
@SuperBuilder
- @JsonInclude(JsonInclude.Include.NON_EMPTY)
+ @JsonInclude(JsonInclude.Include.NON_NULL)
@JsonNaming(PropertyNamingStrategies.UpperSnakeCaseStrategy.class)
public static class RequestDataHeader {
@@ -540,7 +534,7 @@ public class NiceCiDTO {
@NoArgsConstructor
@AllArgsConstructor
@SuperBuilder
- @JsonInclude(JsonInclude.Include.NON_EMPTY)
+ @JsonInclude(JsonInclude.Include.NON_NULL)
@JsonNaming(PropertyNamingStrategies.UpperSnakeCaseStrategy.class)
public static class ResponseDataHeader {
/**
diff --git a/mens-core/src/main/java/kr/xit/core/spring/config/support/CustomJacksonConfig.java b/mens-core/src/main/java/kr/xit/core/spring/config/support/CustomJacksonConfig.java
new file mode 100644
index 0000000..d251612
--- /dev/null
+++ b/mens-core/src/main/java/kr/xit/core/spring/config/support/CustomJacksonConfig.java
@@ -0,0 +1,75 @@
+package kr.xit.core.spring.config.support;
+
+import com.fasterxml.jackson.annotation.JsonAutoDetect;
+import com.fasterxml.jackson.annotation.JsonInclude.Include;
+import com.fasterxml.jackson.annotation.PropertyAccessor;
+import com.fasterxml.jackson.databind.DeserializationFeature;
+import com.fasterxml.jackson.databind.MapperFeature;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.fasterxml.jackson.databind.SerializationFeature;
+import com.fasterxml.jackson.databind.cfg.CoercionAction;
+import com.fasterxml.jackson.databind.cfg.CoercionInputShape;
+import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
+import kr.xit.core.spring.util.SpringUtils;
+import kr.xit.core.support.utils.ConvertHelper;
+import kr.xit.core.support.utils.JsonUtils;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.context.annotation.Primary;
+
+/**
+ *
+ * description : Jackson(ObjectMapper) 설정 재정의
+ * 모든 ObjectMapper 사용시 이 설정이 적용되도록 해야 한다.
+ * - Cannot coerce empty String("") to ...
+ * value(but could if coercion was enabled using `CoercionConfig`) 에러 방어
+ * packageName : kr.xit.core.spring.config.support
+ * fileName : CustomJacksonConfig
+ * author : julim
+ * date : 2023-09-13
+ * ======================================================================
+ * 변경일 변경자 변경 내용
+ * ----------------------------------------------------------------------
+ * 2023-09-13 julim 최초 생성
+ *
+ *
+ * @see SpringUtils#getObjectMapper()
+ * @see JsonUtils
+ * @see ConvertHelper
+ * @see WebClientConfig
+ */
+@Configuration
+public class CustomJacksonConfig {
+
+ /**
+ *
+ * 기본 설정에 override
+ * Cannot coerce empty String("") to ...
+ * value(but could if coercion was enabled using `CoercionConfig`) 에러 방어
+ *
+ *
+ * @return
+ */
+ @Bean
+ @Primary
+ public ObjectMapper objectMapper() {
+ ObjectMapper om = new ObjectMapper()
+ .enable(MapperFeature.ACCEPT_CASE_INSENSITIVE_PROPERTIES)
+ .disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS)
+ .setSerializationInclusion(Include.NON_NULL)
+ .setVisibility(PropertyAccessor.FIELD, JsonAutoDetect.Visibility.ANY)
+ .configure(SerializationFeature.FAIL_ON_EMPTY_BEANS, false)
+ .configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false)
+ .configure(DeserializationFeature.ACCEPT_EMPTY_ARRAY_AS_NULL_OBJECT, false)
+ .registerModule(new JavaTimeModule());
+
+ om.coercionConfigDefaults()
+ .setCoercion(CoercionInputShape.EmptyString, CoercionAction.AsNull);
+// om.coercionConfigFor(LogicalType.Enum)
+// .setCoercion(CoercionInputShape.EmptyString, CoercionAction.AsNull);
+// om.coercionConfigFor(LogicalType.POJO)
+// .setCoercion(CoercionInputShape.EmptyString, CoercionAction.AsNull);
+
+ return om;
+ }
+}
diff --git a/mens-core/src/main/java/kr/xit/core/spring/config/support/WebClientConfig.java b/mens-core/src/main/java/kr/xit/core/spring/config/support/WebClientConfig.java
index e6ad12a..0800fd9 100644
--- a/mens-core/src/main/java/kr/xit/core/spring/config/support/WebClientConfig.java
+++ b/mens-core/src/main/java/kr/xit/core/spring/config/support/WebClientConfig.java
@@ -1,16 +1,24 @@
package kr.xit.core.spring.config.support;
+import com.fasterxml.jackson.databind.ObjectMapper;
import io.netty.channel.ChannelOption;
import io.netty.handler.timeout.ReadTimeoutHandler;
import io.netty.handler.timeout.WriteTimeoutHandler;
import java.time.Duration;
import java.util.concurrent.TimeUnit;
+import kr.xit.core.spring.util.error.ClientError;
+import kr.xit.core.spring.util.error.ServerError;
+import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
+import org.springframework.http.HttpStatus;
+import org.springframework.http.MediaType;
import org.springframework.http.client.reactive.ReactorClientHttpConnector;
import org.springframework.http.codec.LoggingCodecSupport;
+import org.springframework.http.codec.json.Jackson2JsonDecoder;
+import org.springframework.http.codec.json.Jackson2JsonEncoder;
import org.springframework.web.reactive.function.client.ExchangeFilterFunction;
import org.springframework.web.reactive.function.client.ExchangeStrategies;
import org.springframework.web.reactive.function.client.WebClient;
@@ -35,6 +43,7 @@ import reactor.netty.resources.ConnectionProvider;
*
*/
@Slf4j
+@RequiredArgsConstructor
@Configuration
public class WebClientConfig {
@@ -43,57 +52,40 @@ public class WebClientConfig {
@Value("${contract.connection.readTimeout:5000}")
private int readTimeout;
+ private final ObjectMapper objectMapper;
DefaultUriBuilderFactory factory = new DefaultUriBuilderFactory();
- // HttpClient 총 연결 시간
- HttpClient httpClient = HttpClient.create()
- .option(ChannelOption.CONNECT_TIMEOUT_MILLIS, connectTimeout)
- .responseTimeout(Duration.ofMillis(this.connectTimeout))
- .doOnConnected(conn ->
- conn.addHandlerLast(new ReadTimeoutHandler(readTimeout, TimeUnit.MILLISECONDS))
- .addHandlerLast(new WriteTimeoutHandler(readTimeout, TimeUnit.MILLISECONDS)));
-
-
/**
* setEncodingMode : GET 요청의 파라미터 셋팅을 하기 위한 URI 템플릿의 인코딩을 위한 설정
* @return
*/
@Bean
public WebClient webClient() {
- // 256KB 보다 큰 HTTP 메시지를 처리 시도 → DataBufferLimitException 에러 발생 방어
- ExchangeStrategies es = ExchangeStrategies.builder()
- .codecs(configurer -> {
- configurer.defaultCodecs().maxInMemorySize(2 * 1024 * 1024);
- //configurer.customCodecs().register(new Jackson2JsonDecoder());
- //configurer.customCodecs().register(new Jackson2JsonEncoder());
- })
- .build();
-
- //FIXME::rest call async 로깅
- // ExchangeStrategies를 통해 setEnableLoggingRequestDetails(true)로 설정
- // boot에서 로깅 org.springframework.web.reactive.function.client.ExchangeFunctions: DEBUG 하여 활성
- es.messageWriters()
- .stream()
- .filter(LoggingCodecSupport .class::isInstance)
- .forEach(writer -> ((LoggingCodecSupport)writer).setEnableLoggingRequestDetails(true));
-
-
-
factory.setEncodingMode(DefaultUriBuilderFactory.EncodingMode.VALUES_ONLY);
+
return WebClient.builder()
.uriBuilderFactory(factory)
- .clientConnector(new ReactorClientHttpConnector(httpClient))
+ .clientConnector(new ReactorClientHttpConnector(defaultHttpClient()))
.codecs(configurer -> configurer.defaultCodecs().maxInMemorySize(2 * 1024 * 1024))
- .exchangeStrategies(es)
+ .exchangeStrategies(defaultExchangeStrategies())
.filters(exchangeFilterFunctions -> {
- exchangeFilterFunctions.add(logRequest());
- exchangeFilterFunctions.add(logResponse());
- //TODO::에러발생시 점검필요
- //exchangeFilterFunctions.add(errorHandler());
+ exchangeFilterFunctions.add(requestFilter());
+ exchangeFilterFunctions.add(responseFilter());
})
.build();
}
+
+ @Bean
+ public HttpClient defaultHttpClient() {
+ return HttpClient.create(connectionProvider())
+ .option(ChannelOption.CONNECT_TIMEOUT_MILLIS, connectTimeout)
+ .responseTimeout(Duration.ofMillis(this.connectTimeout))
+ .doOnConnected(conn ->
+ conn.addHandlerLast(new ReadTimeoutHandler(readTimeout, TimeUnit.MILLISECONDS))
+ .addHandlerLast(new WriteTimeoutHandler(readTimeout, TimeUnit.MILLISECONDS)));
+ }
+
/**
* maxConnections : connection pool의 갯수
* pendingAcquireTimeout : 커넥션 풀에서 커넥션을 얻기 위해 기다리는 최대 시간
@@ -107,12 +99,33 @@ public class WebClientConfig {
.maxConnections(100)
.pendingAcquireTimeout(Duration.ofMillis(0))
.pendingAcquireMaxCount(-1)
- .maxIdleTime(Duration.ofMillis(1000L))
+ .maxIdleTime(Duration.ofMillis(2000L))
.build();
}
+ @Bean
+ public ExchangeStrategies defaultExchangeStrategies() {
+ // 256KB 보다 큰 HTTP 메시지를 처리 시도 → DataBufferLimitException 에러 발생 방어
+ ExchangeStrategies es = ExchangeStrategies.builder()
+ .codecs(config -> {
+ config.defaultCodecs().maxInMemorySize(2 * 1024 * 1024);
+ config.defaultCodecs().jackson2JsonEncoder(new Jackson2JsonEncoder(objectMapper, MediaType.APPLICATION_JSON));
+ config.defaultCodecs().jackson2JsonDecoder(new Jackson2JsonDecoder(objectMapper, MediaType.APPLICATION_JSON));
+ })
+ .build();
- private ExchangeFilterFunction logRequest() {
+ //FIXME::rest call async 로깅
+ // ExchangeStrategies를 통해 setEnableLoggingRequestDetails(true)로 설정
+ // boot에서 로깅 org.springframework.web.reactive.function.client.ExchangeFunctions: DEBUG 하여 활성
+ es.messageWriters()
+ .stream()
+ .filter(LoggingCodecSupport .class::isInstance)
+ .forEach(writer -> ((LoggingCodecSupport)writer).setEnableLoggingRequestDetails(true));
+
+ return es;
+ }
+
+ private ExchangeFilterFunction requestFilter() {
return ExchangeFilterFunction.ofRequestProcessor(clientRequest -> {
if (log.isDebugEnabled()) {
StringBuilder sb = new StringBuilder("\n>>>>>>>>>> Http Rest Request <<<<<<<<<<<<<\n");
@@ -125,13 +138,34 @@ public class WebClientConfig {
});
}
- private ExchangeFilterFunction logResponse() {
+ /**
+ * reponse logging && error Handling
+ * @return
+ */
+ private ExchangeFilterFunction responseFilter() {
return ExchangeFilterFunction.ofResponseProcessor(clientResponse -> {
- StringBuilder sb = new StringBuilder("\n>>>>>>>>>> Http Rest Response <<<<<<<<<<<<<\n");
- clientResponse.headers()
- .asHttpHeaders()
- .forEach((name, values) -> values.forEach(value -> sb.append(name).append(": ").append(value).append("\n")));
- log.debug(sb.toString());
+
+ HttpStatus status = clientResponse.statusCode();
+
+ if(clientResponse.statusCode().is4xxClientError()) {
+ return clientResponse.bodyToMono(String.class)
+ .flatMap(errorBody -> Mono.error(new ClientError(status, errorBody)));
+
+ } else if(clientResponse.statusCode().is5xxServerError()) {
+ return clientResponse.bodyToMono(String.class)
+ .flatMap(errorBody -> Mono.error(new ServerError(status, errorBody)));
+
+ }
+
+ if(log.isDebugEnabled()) {
+ StringBuilder sb = new StringBuilder(
+ "\n>>>>>>>>>> Http Rest Response <<<<<<<<<<<<<\n");
+ clientResponse.headers()
+ .asHttpHeaders()
+ .forEach((name, values) -> values.forEach(
+ value -> sb.append(name).append(": ").append(value).append("\n")));
+ log.debug(sb.toString());
+ }
return Mono.just(clientResponse);
});
}
diff --git a/mens-core/src/main/java/kr/xit/core/spring/util/ApiWebClientUtil.java b/mens-core/src/main/java/kr/xit/core/spring/util/ApiWebClientUtil.java
index 5ceb62a..6752cdf 100644
--- a/mens-core/src/main/java/kr/xit/core/spring/util/ApiWebClientUtil.java
+++ b/mens-core/src/main/java/kr/xit/core/spring/util/ApiWebClientUtil.java
@@ -12,6 +12,8 @@ import kr.xit.core.spring.util.error.ClientError;
import kr.xit.core.spring.util.error.ErrorParse;
import kr.xit.core.spring.util.error.ServerError;
import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.commons.lang3.ObjectUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpMethod;
@@ -19,6 +21,7 @@ import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.stereotype.Component;
import org.springframework.web.reactive.function.client.ExchangeFilterFunction;
+import org.springframework.web.reactive.function.client.WebClientResponseException;
import org.springframework.web.util.UriComponentsBuilder;
import reactor.core.publisher.Mono;
@@ -40,6 +43,7 @@ import reactor.core.publisher.Mono;
* @see ClientError
* @see ServerError
*/
+@Slf4j
@Component
@RequiredArgsConstructor
public class ApiWebClientUtil {
@@ -66,7 +70,7 @@ public class ApiWebClientUtil {
return webClientConfig.webClient().method(HttpMethod.POST)
.uri(url)
.headers(httpHeaders -> getHeaders(httpHeaders, headerMap))
- .bodyValue(requestDto)
+ .bodyValue(Objects.requireNonNullElse(requestDto, ""))
.retrieve()
.onStatus(
status -> status.is4xxClientError() || status.is5xxServerError(),
@@ -103,10 +107,51 @@ public class ApiWebClientUtil {
.uri(url)
.headers(httpHeaders -> getHeaders(httpHeaders, headerMap))
.bodyValue(Objects.requireNonNullElse(body, ""))
- .exchangeToMono(res -> res.bodyToMono(rtnClzz))
+ .exchangeToMono(res -> res.bodyToMono(rtnClzz)
+ .map(dto -> {
+ if (res.statusCode().is2xxSuccessful()) {
+ log.info("API 요청에 성공했습니다.");
+ return dto;
+ }
+
+ if (res.statusCode().is4xxClientError()) {
+ log.error("API 요청 중 4xx 에러가 발생했습니다. 요청 데이터를 확인해주세요.");
+ throw BizRuntimeException.create(String.format("4xx 외부 요청 오류. statusCode: %s, response: %s, header: %s", res.rawStatusCode(), res.bodyToMono(String.class), res.headers().asHttpHeaders()));
+ }
+
+ log.error("API 요청 중 Tree 서버에서 5xx 에러가 발생했습니다.");
+ throw BizRuntimeException.create(String.format("5xx 외부 시스템 오류. %s", res.bodyToMono(String.class)));
+ })
+ )
.block();
}
+// public T exchange(final String url, final HttpMethod method, final Object body, final Class rtnClzz, final Map headerMap) {
+//
+// return webClientConfig.webClient()
+// .method(method)
+// .uri(url)
+// .headers(httpHeaders -> getHeaders(httpHeaders, headerMap))
+// .bodyValue(Objects.requireNonNullElse(body, ""))
+// .exchangeToMono(res -> res.bodyToMono(rtnClzz)
+// .map(dto -> {
+// if (res.statusCode().is2xxSuccessful()) {
+// log.info("API 요청에 성공했습니다.");
+// return dto;
+// }
+//
+// if (res.statusCode().is4xxClientError()) {
+// log.error("API 요청 중 4xx 에러가 발생했습니다. 요청 데이터를 확인해주세요.");
+// throw BizRuntimeException.create(String.format("4xx 외부 요청 오류. statusCode: %s, response: %s, header: %s", res.rawStatusCode(), res.bodyToMono(String.class), res.headers().asHttpHeaders()));
+// }
+//
+// log.error("API 요청 중 Tree 서버에서 5xx 에러가 발생했습니다.");
+// throw BizRuntimeException.create(String.format("5xx 외부 시스템 오류. %s", res.bodyToMono(String.class)));
+// })
+// )
+// .block();
+// }
+
public ApiResponseDTO sendError(final Throwable e) {
Map map = ErrorParse.extractError(e.getCause());
@@ -119,7 +164,7 @@ public class ApiWebClientUtil {
}
private HttpHeaders getHeaders(final HttpHeaders headers, final Map map) {
-
+ if(ObjectUtils.isEmpty(map)) return headers;
for(Map.Entry e : map.entrySet()){
headers.add(e.getKey(), e.getValue());
}
diff --git a/mens-core/src/main/java/kr/xit/core/spring/util/SpringUtils.java b/mens-core/src/main/java/kr/xit/core/spring/util/SpringUtils.java
index 351937d..6aa5a87 100644
--- a/mens-core/src/main/java/kr/xit/core/spring/util/SpringUtils.java
+++ b/mens-core/src/main/java/kr/xit/core/spring/util/SpringUtils.java
@@ -1,5 +1,6 @@
package kr.xit.core.spring.util;
+import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.AccessLevel;
import lombok.NoArgsConstructor;
import org.apache.commons.configuration.PropertiesConfiguration;
@@ -86,4 +87,8 @@ public class SpringUtils {
public static CorsProperties getCorsProperties(){
return (CorsProperties)getBean(CorsProperties.class);
}
+
+ public static ObjectMapper getObjectMapper(){
+ return (ObjectMapper)getBean(ObjectMapper.class);
+ }
}
diff --git a/mens-core/src/main/java/kr/xit/core/support/utils/ConvertHelper.java b/mens-core/src/main/java/kr/xit/core/support/utils/ConvertHelper.java
index 9c19fc7..99696de 100644
--- a/mens-core/src/main/java/kr/xit/core/support/utils/ConvertHelper.java
+++ b/mens-core/src/main/java/kr/xit/core/support/utils/ConvertHelper.java
@@ -3,6 +3,7 @@ package kr.xit.core.support.utils;
import java.io.StringWriter;
import java.util.Map;
+import kr.xit.core.spring.util.SpringUtils;
import lombok.AccessLevel;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -34,7 +35,7 @@ import lombok.NoArgsConstructor;
@NoArgsConstructor(access = AccessLevel.PRIVATE)
public class ConvertHelper {
private static final Logger log = LoggerFactory.getLogger(ConvertHelper.class);
- private static final ObjectMapper OBJECT_MAPPER = new ObjectMapper();
+ private static final ObjectMapper OBJECT_MAPPER = SpringUtils.getObjectMapper();
private static final JsonFactory JSON_FACTORY = new JsonFactory();
/**
diff --git a/mens-core/src/main/java/kr/xit/core/support/utils/JsonUtils.java b/mens-core/src/main/java/kr/xit/core/support/utils/JsonUtils.java
index d78215e..36d2247 100644
--- a/mens-core/src/main/java/kr/xit/core/support/utils/JsonUtils.java
+++ b/mens-core/src/main/java/kr/xit/core/support/utils/JsonUtils.java
@@ -1,5 +1,8 @@
package kr.xit.core.support.utils;
+import com.fasterxml.jackson.databind.SerializationFeature;
+import com.fasterxml.jackson.databind.cfg.CoercionAction;
+import com.fasterxml.jackson.databind.cfg.CoercionInputShape;
import java.io.IOException;
import java.util.List;
import java.util.Map;
@@ -13,6 +16,7 @@ import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.ObjectMapper;
import kr.xit.core.exception.BizRuntimeException;
+import kr.xit.core.spring.util.SpringUtils;
import lombok.AccessLevel;
import lombok.NoArgsConstructor;
import org.apache.commons.lang3.StringUtils;
@@ -23,20 +27,16 @@ import org.apache.commons.lang3.StringUtils;
@NoArgsConstructor(access = AccessLevel.PRIVATE)
public class JsonUtils {
+ private static final ObjectMapper OM = SpringUtils.getObjectMapper();
+
/**
* Object -> json string
* @return String
* @param obj Object
*/
public static String toJson(Object obj) {
- ObjectMapper mapper = new ObjectMapper();
- // null 필드 제
- mapper.setSerializationInclusion(Include.NON_EMPTY);
- // No serializer found for class 에러 - private 필드
- mapper.setVisibility(PropertyAccessor.FIELD, JsonAutoDetect.Visibility.ANY);
-// mapper.setSerializationInclusion(Include.NON_EMPTY);
try {
- return obj != null ? mapper.writeValueAsString(obj) : null;
+ return obj != null ? OM.writeValueAsString(obj) : null;
} catch (JsonProcessingException e) {
throw BizRuntimeException.create(e.getLocalizedMessage());
}
@@ -49,10 +49,8 @@ public class JsonUtils {
* @param cls Class
*/
public static T toObject(String str, Class cls) {
- ObjectMapper om = new ObjectMapper();
- om.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
try {
- return str != null ? om.readValue(str, cls) : null;
+ return str != null ? OM.readValue(str, cls) : null;
} catch (JsonProcessingException e) {
throw BizRuntimeException.create(e.getLocalizedMessage());
}
@@ -66,13 +64,7 @@ public class JsonUtils {
*/
public static T toObjByObj(Object obj, Class cls) {
String str = toJson(obj);
- ObjectMapper om = new ObjectMapper();
- om.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
- try {
- return str != null ? om.readValue(str, cls) : null;
- } catch (JsonProcessingException e) {
- throw BizRuntimeException.create(e.getLocalizedMessage());
- }
+ return str != null ? toObject(str, cls) : null;
}
/**
@@ -83,11 +75,9 @@ public class JsonUtils {
* @throws IOException
*/
public static List toObjectList(String str, Class cls) {
- ObjectMapper om = new ObjectMapper();
- om.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
if(str != null){
try {
- return om.readValue(str, om.getTypeFactory().constructCollectionType(List.class, cls));
+ return OM.readValue(str, OM.getTypeFactory().constructCollectionType(List.class, cls));
} catch (JsonProcessingException e) {
throw BizRuntimeException.create(e.getLocalizedMessage());
}
@@ -102,9 +92,8 @@ public class JsonUtils {
* @return Map
*/
public static Map toMap(String str) {
- ObjectMapper om = new ObjectMapper();
try {
- return om.readValue(str, new TypeReference