feat: Jackson (ObjectMapper) 설정 적용

dev
gitea-관리자 1 year ago
parent cf963cd135
commit 32beb10a24

@ -77,13 +77,6 @@ spring:
data-source-properties:
rewriteBatchedStatements: true
# @JsonInclude(JsonInclude.Include.NON_EMPTY) 설정
jackson:
default-property-inclusion=non_null: non_null
logging:
level:
root: error

@ -77,13 +77,6 @@ spring:
data-source-properties:
rewriteBatchedStatements: true
# @JsonInclude(JsonInclude.Include.NON_EMPTY) 설정
jackson:
default-property-inclusion=non_null: non_null
logging:
level:
root: error

@ -142,9 +142,9 @@ json <-> java class 변환 적용
*/
```
## Json 데이타 null 필드 제외
@JsonInclude(JsonInclude.Include.NON_EMPTY)
@JsonInclude(JsonInclude.Include.NON_NULL)
```text
@JsonInclude(JsonInclude.Include.NON_EMPTY)
@JsonInclude(JsonInclude.Include.NON_NULL)
@JsonNaming(PropertyNamingStrategies.UpperSnakeCaseStrategy.class)
public static class RequestDataHeader {

@ -290,6 +290,7 @@
<version>2.9.0</version>
</dependency>
<!-- fasterxml.jackson -->
<dependency>
<groupId>com.fasterxml.jackson.dataformat</groupId>
<artifactId>jackson-dataformat-xml</artifactId>
@ -302,6 +303,7 @@
<groupId>com.fasterxml.jackson.datatype</groupId>
<artifactId>jackson-datatype-jsr310</artifactId>
</dependency>
<!-- fasterxml.jackson -->
<dependency>
<groupId>commons-configuration</groupId>

@ -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 {
//-----------------------------------------------------------------------------------

@ -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 {
/**
* <pre>

@ -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) -

@ -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 {
/**

@ -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;
/**
* <pre>
@ -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 {
/**

@ -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;
/**
* <pre>
* 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
*
* </pre>
* @see SpringUtils#getObjectMapper()
* @see JsonUtils
* @see ConvertHelper
* @see WebClientConfig
*/
@Configuration
public class CustomJacksonConfig {
/**
* <pre>
* override
* Cannot coerce empty String("") to ...
* value(but could if coercion was enabled using `CoercionConfig`)
* </pre>
*
* @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;
}
}

@ -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;
* </pre>
*/
@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);
});
}

@ -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> T exchange(final String url, final HttpMethod method, final Object body, final Class<T> rtnClzz, final Map<String,String> 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 <T> ApiResponseDTO<T> sendError(final Throwable e) {
Map<String,Object> map = ErrorParse.extractError(e.getCause());
@ -119,7 +164,7 @@ public class ApiWebClientUtil {
}
private HttpHeaders getHeaders(final HttpHeaders headers, final Map<String, String> map) {
if(ObjectUtils.isEmpty(map)) return headers;
for(Map.Entry<String, String> e : map.entrySet()){
headers.add(e.getKey(), e.getValue());
}

@ -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);
}
}

@ -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();
/**

@ -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> T toObject(String str, Class<T> 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> T toObjByObj(Object obj, Class<T> 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 <T> List<T> toObjectList(String str, Class<T> 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<String, Object> toMap(String str) {
ObjectMapper om = new ObjectMapper();
try {
return om.readValue(str, new TypeReference<Map<String, Object>>(){});
return OM.readValue(str, new TypeReference<Map<String, Object>>(){});
} catch (JsonProcessingException e) {
throw BizRuntimeException.create(e.getLocalizedMessage());
}
@ -124,6 +113,25 @@ public class JsonUtils {
}
}
private static ObjectMapper getObjectMapper() {
ObjectMapper om = new ObjectMapper();
om.setSerializationInclusion(Include.NON_NULL);
// No serializer found for class 에러 - private 필드
om.setVisibility(PropertyAccessor.FIELD, JsonAutoDetect.Visibility.ANY);
om.configure(SerializationFeature.FAIL_ON_EMPTY_BEANS, false);
om.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
om.configure(DeserializationFeature.ACCEPT_EMPTY_ARRAY_AS_NULL_OBJECT, false);
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;
}
/**
* Json .
* @param json String json

Loading…
Cancel
Save