# RestTemplate - getForObject, postForObject
RestTemplate의 가장 기본적인 getForObject와 postForObject 예제 코드 입니다!
통신 프로세스
View ↔ [ ajax ] ↔ Controller ↔ [ RestTemplate ] ↔ RestController ↔ Service ↔ Mapper ↔ DataBase
1. getForObject 통신
2. postForObject 통신, ContentType: application/json
3. postForObject 통신, ContentType: application/x-www-form-urlencoded
# 환경
Tool : STS 4.13.0
Ver : 2.7.5 [GA]
java : 11
Repo : MAVEN
DB : ORACLE XE (11g)
View : Thymeleaf
jQuery: 3.6.0
Type : Client(WEB), Server(API)
# Page
# View
<body>
<h1>REST TEMPLATE V2 테스트 페이지 입니다.</h1>
<div>
<h3>SAMPLE REST CODE</h3>
<input type="button" onclick="call('get')" value="GET" style="display: inline;"/>
<input type="button" onclick="call('post-json')" value="POST-JSON" style="display: inline;"/>
<input type="button" onclick="call('post-form')" value="POST-FROM" style="display: inline;"/>
<br>
<input type="button" onclick="call('exchange-post')" value="POST" style="display: inline;"/>
<input type="button" onclick="call('exchange-put')" value="PUT" style="display: inline;"/>
<input type="button" onclick="call('exchange-delete')" value="DELETE" style="display: inline;"/>
<br>
</div>
</body>
<script type="text/javascript" th:inline="javascript">
function call(path) {
const target = `/test/rest-v2/${path}`;
$.ajax(target,
{
dataType: "json",
}).done(function(output) {
console.log(`OUTPUT[${path}]:`, JSON.stringify(output.result));
}).fail(function(jqXHR) {
console.log("ERROR:", jqXHR);
}
);
}
</script>
# Controller - Client(WEB)
@Controller
@RequestMapping("/test/rest-v2")
public class TestRestV2Controller {
@Value("${api.url.api}")
private String apiUrlApi;
@Autowired
private RestTemplate template;
@RequestMapping("/view")
public ModelAndView view(ModelAndView mav) {
mav.setViewName("test/restView2");
return mav;
}
/**
* RestTemplate getForObject( URI, responseType, [uriVariables] )
*/
@RequestMapping("/get")
public ModelAndView get() {
// 요청하려는 URL 설정.
String target = apiUrlApi.concat("/api-v1/test/rest/get/{pattern}");
// 요청하려는 DATA 설정.
String reqeust = "?data=한글";
// 요청 URL에 전달 할 uriVariables 설정.
Map<String, String> uriVariables = new HashMap<String, String>();
uriVariables.put("pattern", "YYYY-MM-DD HH24:MI:SS");
// GET 전송.
RestMessage message = template.getForObject(target.concat(reqeust), RestMessage.class, uriVariables);
// 응답 데이터 설정.
ModelAndView mav = new ModelAndView("jsonView");
mav.addObject("result", message.getData());
return mav;
}
/**
* RestTemplate postForObject( URI, request, responseType, [uriVariables] )
*/
@RequestMapping("/post-json")
public ModelAndView postJson() {
// 요청하려는 URL 설정.
String target = apiUrlApi.concat("/api-v1/test/rest/post-json");
// 요청 시 본문에 담을 데이터.
Map<String, String> request = new HashMap<String, String>();
request.put("pattern", "YYYY-MM-DD HH24:MI:SS");
// POST 전송.
RestMessage message = template.postForObject(target, request, RestMessage.class);
// 응답 데이터 설정.
ModelAndView mav = new ModelAndView("jsonView");
mav.addObject("result", message.getData());
return mav;
}
/**
* RestTemplate postForObject( URI, request, responseType, [uriVariables] )
*/
@RequestMapping("/post-form")
public ModelAndView postForm() {
// 요청하려는 URL 설정.
String target = apiUrlApi.concat("/api-v1/test/rest/post-form");
// 요청 시 본문에 담을 데이터.
MultiValueMap<String, Object> request = new LinkedMultiValueMap<String, Object>();
request.add("pattern", "YYYY-MM-DD HH24:MI:SS");
request.add("data", "테스트");
request.add("data", "TEST");
// POST 전송.
RestMessage message = template.postForObject(target, request, RestMessage.class);
// 응답 데이터 설정.
ModelAndView mav = new ModelAndView("jsonView");
mav.addObject("result", message.getData());
return mav;
}
}
# RestController - Server(API)
@Slf4j
@RestController
@RequestMapping("/api-v1/test/rest")
public class TestRestController {
@Autowired
private TestService testService;
/**
* PathVariable Annotation 사용
*/
@GetMapping("/get/{pattern}")
public RestMessage path(@PathVariable String pattern, @RequestParam String data) {
log.debug("[PARAMETER] [get/pattern] pattern: {}, data: {}", pattern, data);
String time = testService.time(pattern);
RestMessage message = new RestMessage();
message.setOk();
message.setData(time);
return message;
}
/**
* application/json 사용.
*/
@PostMapping("/post-json")
public RestMessage json(@RequestBody Map<String, String> input) {
log.debug("[PARAMETER] [post-json] pattern: {}", input);
String pattern = input.get("pattern");
String time = testService.time(pattern);
RestMessage message = new RestMessage();
message.setOk();
message.setData(time);
return message;
}
/**
* application/x-www-form-urlencoded 사용.
*/
@PostMapping("/post-form")
public RestMessage form(@RequestParam MultiValueMap<String, String> input) {
log.debug("[PARAMETER] [post-form] input: {}", input);
log.debug("[PARAMETER] [post-form] data : {}", input.get("data").get(0));
log.debug("[PARAMETER] [post-form] data : {}", input.get("data").get(1));
String pattern = input.get("pattern").get(0);
String time = testService.time(pattern);
RestMessage message = new RestMessage();
message.setOk();
message.setData(time);
return message;
}
}
# Service
@Service
public class TestService {
@Autowired
private TestMapper testMapper;
public String time(String pattern) {
return testMapper.time(pattern);
}
public List<TestRVO> domains(TestPVO testPVO) {
return testMapper.domains(testPVO);
}
}
# Mapper - Interface
@Mapper
public interface TestMapper {
String time(String pattern);
List<TestRVO> domains(TestPVO testPVO);
}
# Mapper - xml
<mapper namespace="com.prjt.blog.test.mapper.TestMapper">
<select id="time" parameterType="string" resultType="string">
/** 현재시간 **/ SELECT TO_CHAR(SYSDATE, #{pattern, jdbcType=VARCHAR}) as time FROM DUAL
</select>
<select id="domains" parameterType="com.prjt.blog.test.model.TestPVO" resultType="com.prjt.blog.test.model.TestRVO">
/** 도메인 **/
WITH domain_table AS (
SELECT null AS kr_name, null AS en_name, null AS addr_url, null AS delegator FROM dual
UNION ALL
SELECT '네이버', 'NAVER', 'https://www.naver.com', '최수연' FROM dual
UNION ALL
SELECT '구글', 'GOOGLE', 'https://www.google.com', '선다 피차이' FROM dual
UNION ALL
SELECT '카카오', 'KAKAO', 'https://www.kakocorp.com', '홍은택' FROM dual
)
SELECT *
FROM domain_table
<where>
AND kr_name is not null
<if test="krName != null and krName != ''">
AND kr_name = #{krName, jdbcType=VARCHAR}
</if>
</where>
</select>
</mapper>
# 테스트 로그
/* getForObject(): get 시간 순으로 나열 */
Client - [WEB] [REQ]: null
Client - [WEB] [URL]: (GET) http://localhost:8888/test/rest-v2/get
Client - [REST] [CALL]: data=한글
Client - [REST] [EXEC]: (GET) http://localhost:9999/api-v1/test/rest/get/YYYY-MM-DD%20HH24:MI:SS?data=%ED%95%9C%EA%B8%80
Server - [WEB] [REQ]: data=%ED%95%9C%EA%B8%80
Server - [WEB] [URL]: (GET) http://localhost:9999/api-v1/test/rest/get/YYYY-MM-DD%20HH24:MI:SS
Server - [PARAMETER] [get/pattern] pattern: YYYY-MM-DD HH24:MI:SS, data: 한글
DB SQL - ==> Preparing: /** 현재시간 **/ SELECT TO_CHAR(SYSDATE, ?) as time FROM DUAL
DB SQL - ==> Parameters: YYYY-MM-DD HH24:MI:SS(String)
DB SQL - <== Total: 1
Server - [WEB] [RES]: {"code":"0000","data":"2022-11-19 21:39:02"}
Client - [REST] [BACK]: (200) {"code":"0000","message":"정상적으로 처리 되었습니다.","data":"2022-11-19 21:39:02","args":null,"success":true}
Client - [WEB] [RES]: {"view":"jsonView","model":{"result":"2022-11-19 21:39:02"},"cleared":false}
View - OUTPUT[get]: "2022-11-19 21:39:02"
/* postForObject(): post-json 시간 순으로 나열 */
Client - [WEB] [REQ]: null
Client - [WEB] [URL]: (GET) http://localhost:8888/test/rest-v2/post-json
Client - [REST] [CALL]: {pattern=YYYY-MM-DD HH24:MI:SS}
Client - [REST] [EXEC]: (POST) http://localhost:9999/api-v1/test/rest/post-json
Server - [WEB] [REQ]: [{"pattern":"YYYY-MM-DD HH24:MI:SS"}]
Server - [WEB] [URL]: (POST) http://localhost:9999/api-v1/test/rest/post-json
Server - [PARAMETER] [post-json] pattern: {pattern=YYYY-MM-DD HH24:MI:SS}
DB SQL - ==> Preparing: /** 현재시간 **/ SELECT TO_CHAR(SYSDATE, ?) as time FROM DUAL
DB SQL - ==> Parameters: YYYY-MM-DD HH24:MI:SS(String)
DB SQL - <== Total: 1
Server - [WEB] [RES]: {"code":"0000","data":"2022-11-19 21:50:08"}
Client - [REST] [BACK]: (200) {"code":"0000","message":"정상적으로 처리 되었습니다.","data":"2022-11-19 21:50:08","args":null,"success":true}
Client - [WEB] [RES]: {"view":"jsonView","model":{"result":"2022-11-19 21:50:08"},"cleared":false}
View - OUTPUT[post-json]: "2022-11-19 21:50:08"
/* postForObject(): post-form 시간 순으로 나열 */
Client - [WEB] [REQ]: null
Client - [WEB] [URL]: (GET) http://localhost:8888/test/rest-v2/post-form
Client - [REST] [CALL]: pattern=YYYY-MM-DD+HH24%3AMI%3ASS&data=%ED%85%8C%EC%8A%A4%ED%8A%B8&data=TEST
Client - [REST] [EXEC]: (POST) http://localhost:9999/api-v1/test/rest/post-form
Server - [WEB] [REQ]: [{"pattern":["YYYY-MM-DD HH24:MI:SS"],"data":["테스트","TEST"]}]
Server - [WEB] [URL]: (POST) http://localhost:9999/api-v1/test/rest/post-form
Server - [PARAMETER] [post-form] input: {pattern=[YYYY-MM-DD HH24:MI:SS], data=[테스트, TEST]}
Server - [PARAMETER] [post-form] data : 테스트
Server - [PARAMETER] [post-form] data : TEST
DB SQL - ==> Preparing: /** 현재시간 **/ SELECT TO_CHAR(SYSDATE, ?) as time FROM DUAL
DB SQL - ==> Parameters: YYYY-MM-DD HH24:MI:SS(String)
DB SQL - <== Total: 1
Server - [WEB] [RES]: {"code":"0000","data":"2022-11-19 21:55:37"}
Client - [REST] [BACK]: (200) {"code":"0000","message":"정상적으로 처리 되었습니다.","data":"2022-11-19 21:55:37","args":null,"success":true}
Client - [WEB] [RES]: {"view":"jsonView","model":{"result":"2022-11-19 21:55:37"},"cleared":false}
View - OUTPUT[post-form]: "2022-11-19 21:55:37"
# 내용
3가지 방식으로 나누어 테스트 해보았고, 설정된 부분을 보면 조금 씩 다르다는 걸 알 수 있다.
1. getForObject
- HttpMethod: GET
- ContentType: application/x-www-form-urlencoded;charset=UTF-8
- URI: /api-v1/test/rest/get/{pattern}
- PathVariable: pattern
- 파라미터 맵핑: @RequestParam
- 파라미터 타입: String
2. postForObject - json
- HttpMethod: POST
- ContentType: application/json
- URI: /api-v1/test/rest/post-json
- 파라미터 맵핑: @RequestBody
- 파라미터 타입: Map<String, String>
3. postForObject - form
- HttpMethod: POST
- ContentType: application/x-www-form-urlencoded;charset=UTF-8
- URI: /api-v1/test/rest/post-form
- 파라미터 맵핑: @RequestParam
- 파라미터 타입: MultiValueMap<String, String>
첫번째로 RestTemplate은 기본적으로 application/json으로 설정되는데,
GET 방식으로 전송하거나, 전송 데이터의 타입을 MultiValueMap 으로 전송할 때에는 ContentType이 application/x-www-form-urlencoded;charset=UTF-8 으로 전송되는 걸 확인할 수 있다.
두번째로 ContentType이 json일 경우 @RequestBody로 Map이나 VO로 맵핑하여 받을 수 있고,
x-www-form-urlencoded일 결우 @RequestParam으로 원시형타입으로 하나씩 변수를 맵핑하거나, MultiValuMap으로 여러개의 변수를 맵핑할 수 있다.
모든 통신을 할 때 마찬가지 겠지만, RestTemplate을 이용하여 통신할 때에도 요청이 오는 ContentType이 뭔지 파악하고, ContentType에 따라 어떤 방식으로 변수를 맵핑할 지 생각하고 코드를 작성해야 된다.
# RestTemplate 시리즈
https://hjho95.tistory.com/35 getForObject, postForObject
https://hjho95.tistory.com/36 exchange (POST, PUT, DELETE)
https://hjho95.tistory.com/37 Configuration
https://hjho95.tistory.com/38 ClientHttpRequestInterceptor, ResponseErrorHandler
# RestTemplate 시리즈 참조 페이지
RestTemplate: https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/web/client/RestTemplate.html
RestTemplate: https://www.baeldung.com/rest-template
Interceptor: https://www.baeldung.com/spring-rest-template-interceptor
ErrorHandling: https://www.baeldung.com/spring-rest-template-error-handling
'스프링 부트' 카테고리의 다른 글
[SpringBoot] RestTemplate 구성하기! (0) | 2022.11.27 |
---|---|
[SpringBoot] RestTemplate - exchange (POST, PUT, DELETE) 로 통신하기! (1) | 2022.11.19 |
[SpringBoot] 스프링 부트 프로젝트 생성하기 (0) | 2022.11.06 |
[SpringBoot] 필터를 이용하여 요청 로그 남기기! (CommonsRequestLoggingFilter) (0) | 2022.10.22 |
[SpringBoot] Encrypt - SHA256(with salt) MessageDigest example code (2) | 2022.10.03 |