반응형

외부기관 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으로 변경하여 사용하였습니다.

 

반응형
반응형

어느덧 자동차 검사 기간이 되어 인터넷으로 예약을 하고 방문을 하려고 교통안전공단으로 접속을 하였어요.

www.cyberts.kr/srs/insp/selectInspResveCar1.do

 

사이버검사소 메인 | 스마트 자동차검사 예약시스템 한국교통안전공단_1

검사수수료는 검사 종류, 차종별로 다르며, 검사수수료 감면은 결제하기 단계에서 적용 가능합니다. 정보사용 및 SMS 수신동의 1. 개인정보의 수집·이용 목적 : 자동차검사 기간안내(문자&알림톡

www.cyberts.kr

자동차번호, 주민등록번호 앞자리 입력을하면 차량조회가 가능해요

조회 후 검사소 선택 예약일자 선택이 있는데 검사소 예약 부분은 캡처를 못했네요. 출장소 및 일반 검사 소등 선택을 할 수 있어요.

전체 달력 보기하면 전체 예약시간을 볼 수 있어요. 해당 시간 선택하고 확인하시면 예약이 가능해요. 예약 시 선 결제라 전 전 23,000원 결제를 했어요.

예약 후 위치 시간 등등 출력 기능도 있네요.

전 우편이 11월쯤 날라왔는데 다음 주까지가 마지막 기간이네요 기간을 넘겨버리면 벌금이 있으니 정기검사 우편이 날아오면 시간 내서 얼른 다녀오시기 바래요~~

반응형

'일상' 카테고리의 다른 글

관악산 등반  (0) 2021.05.23
볼링공 기름(오일)빼기  (0) 2021.05.17
구글 애드센스 검색엔진 붙이기  (8) 2021.01.02
새복 많이 받으세요.  (3) 2021.01.01
애드센스 PIN 등록  (4) 2020.12.28
반응형

요즘 자주 방문하는 신림동 무한리필 고깃집을 포스팅해볼게요.

위치는 신림역 6번 출구에서 직진으로 5분 정도 올라가면 돼요. 삼겹살, 우삼겹, 왕갈비, 스테이크 갈비, 껍데기가 있어요. 가격은 12,900원이에요

 

가게 입구 사진이에요.

기본 반찬 세팅이에요 전부 셀프로 가져올 수 있어요.

셀프바예요. 김치는 밑에 보이는 그릇에 올려서 불판에 구워 먹을 수 있어요

왕갈비는 뼈랑 같이 있는 거고 스테이크 갈비는 좀 두꺼운 갈비예요 맛은 스테이크 갈비가 더 맛나는데 굽는 시간은 좀 더 걸려요.

우삼겹이에요. 여기서 제일 좋아하는 메뉴예요.

배가 고프니깐 먼저 우삼겹부터 먹어야죠~~~

찌개는 1,000원인데 공깃밥을 시키면 찌개 하나는 서비스로 주니깐 공기밥 하나 시키면 돼요.

가성비 좋고 고기도 만족하고 반찬도 좋아요. 배불리 먹고 싶다 하면 한번 방문해 보는 것도 좋을 거 같아요.

 

 

반응형

+ Recent posts