반응형

외부기관 API를 통해서 데이터를 주고받고 하는 부분이 있어 RestTemplate을 사용하는 중에 발생한 에러 포스팅해볼게요.

public ResponseEntity<T2> post(String endpointUrl, T1 body, Class<T2> responseType, HeadersStrategy strategy) {
	HttpEntity<T1> httpEntity = new HttpEntity<>(body, headers(HttpMethod.POST, strategy));

	ResponseEntity<T2> response = restTemplate.postForEntity(endpointUrl, httpEntity, responseType);

	return response;
}

body부분에 VO class를 전달하고 post로 발송하니 서버 쪽에서는 parameter값이 없다 하여 확인을 했어요.

private static boolean romePresent =
			ClassUtils.isPresent("com.rometools.rome.feed.WireFeed",
					RestTemplate.class.getClassLoader());

private static final boolean jaxb2Present =
			ClassUtils.isPresent("javax.xml.bind.Binder",
					RestTemplate.class.getClassLoader());

private static final boolean jackson2Present =
			ClassUtils.isPresent("com.fasterxml.jackson.databind.ObjectMapper",
					RestTemplate.class.getClassLoader()) &&
			ClassUtils.isPresent("com.fasterxml.jackson.core.JsonGenerator",
					RestTemplate.class.getClassLoader());

private static final boolean jackson2XmlPresent =
			ClassUtils.isPresent("com.fasterxml.jackson.dataformat.xml.XmlMapper",
					RestTemplate.class.getClassLoader());

private static final boolean gsonPresent =
			ClassUtils.isPresent("com.google.gson.Gson",
					RestTemplate.class.getClassLoader());

실제 RestTemplate 소스 부분이에요. 기본적인 Converter들이에요 일반적인 json방식은 jackson으로 변환이 돼요.

public RestTemplate() {
	this.messageConverters.add(new ByteArrayHttpMessageConverter());
	this.messageConverters.add(new StringHttpMessageConverter());
	this.messageConverters.add(new ResourceHttpMessageConverter());
	this.messageConverters.add(new SourceHttpMessageConverter<Source>());
	this.messageConverters.add(new AllEncompassingFormHttpMessageConverter());

	if (romePresent) {
		this.messageConverters.add(new AtomFeedHttpMessageConverter());
		this.messageConverters.add(new RssChannelHttpMessageConverter());
	}

	if (jackson2XmlPresent) {
		this.messageConverters.add(new MappingJackson2XmlHttpMessageConverter());
	}
	else if (jaxb2Present) {
		this.messageConverters.add(new Jaxb2RootElementHttpMessageConverter());
	}

	if (jackson2Present) {
		this.messageConverters.add(new MappingJackson2HttpMessageConverter());
	}
	else if (gsonPresent) {
		this.messageConverters.add(new GsonHttpMessageConverter());
	}
}

생성자 소스 부분인데 여기에서 생성할 때 기본적인 Converter를 등록해요.

for (HttpMessageConverter<?> messageConverter : getMessageConverters()) {
	if (messageConverter instanceof GenericHttpMessageConverter) {
		GenericHttpMessageConverter<Object> genericMessageConverter = (GenericHttpMessageConverter<Object>) messageConverter;
			if (genericMessageConverter.canWrite(requestBodyType, requestBodyClass, requestContentType)) {
					if (!requestHeaders.isEmpty()) {
						for (Map.Entry<String, List<String>> entry : requestHeaders.entrySet()) {
								httpHeaders.put(entry.getKey(), new LinkedList<String>(entry.getValue()));
						}
					}
					if (logger.isDebugEnabled()) {
						if (requestContentType != null) {
							logger.debug("Writing [" + requestBody + "] as \"" + requestContentType +
										"\" using [" + messageConverter + "]");
							}
							else {
								logger.debug("Writing [" + requestBody + "] using [" + messageConverter + "]");
							}

						}
						genericMessageConverter.write(
								requestBody, requestBodyType, requestContentType, httpRequest);
						return;
						}
					}
					else if (messageConverter.canWrite(requestBodyClass, requestContentType)) {
						if (!requestHeaders.isEmpty()) {
							for (Map.Entry<String, List<String>> entry : requestHeaders.entrySet()) {
								httpHeaders.put(entry.getKey(), new LinkedList<String>(entry.getValue()));
							}
						}
						if (logger.isDebugEnabled()) {
							if (requestContentType != null) {
								logger.debug("Writing [" + requestBody + "] as \"" + requestContentType +
										"\" using [" + messageConverter + "]");
							}
							else {
								logger.debug("Writing [" + requestBody + "] using [" + messageConverter + "]");
							}

						}
						((HttpMessageConverter<Object>) messageConverter).write(
								requestBody, requestContentType, httpRequest);
						return;
					}
				}

RestTemplate에서 execute실행 전 소스인데 전달받은 body가 해당 converter에 해당되는지 판별하고 값을 write를 하고 있습니다. 저기에 해당이 안되면 body가 없이 전달이 되기 때문에 생성할 때 convert를 전달하거나 기본 내장된 convert를 사용해야 해요. 그래서 사용한 게 Spring에서 제공하는 MultiValueMap이에요. 해당 부분은 MAP처럼 parameter를 put을해서 사용하시면 돼요.

MultiValueMap<String, Object> mmap = new LinkedMultiValueMap<>();

 

 

사용 중에 값은 전달이 되는데 빨간 부분처럼 header에 "multipart/form-data"가 추가되어 API 서버에서 parameter를 못 받는 현상이 발견되어서 확인 중에VO변수 중에 Integer를 사용하는 변수들이 있는데 Integer -> String로 변경 후 실행하니 multipart가 add가 안되었습니다. 왜 Integer를 사용하면 붙는지는 소스를 더 확인을 안 하여 그냥 String을 사용하기로 하였습니다~~~ 

HttpComponentsClientHttpRequestFactory requestFactory = new HttpComponentsClientHttpRequestFactory();
requestFactory.setConnectTimeout(HTTP_CONNECT_TIMEOUT);
requestFactory.setReadTimeout(HTTP_READ_TIMEOUT);
farmLandInfoReqRequestTemplatProvider.get().setRequestFactory(requestFactory);

Map<String, Object> map = new HashMap<>();

MultiValueMap<String, Object> mmap = new LinkedMultiValueMap<>();
try {

  map = BeanConverter.toMap(request);
  mmap.setAll(map);

} catch (Exception e) {

}


return farmLandInfoReqRequestTemplatProvider.get().post(url, mmap, BaseReqResponse.class);

최종적으로 body부분을 MultivalueMap으로 변경하여 사용하였습니다.

 

반응형

+ Recent posts