Rest API(application Programming Interface)
- REST API : 웹 상에서 URL을 통해 원하는 정보를 얻어오거나 특정한 요청을 하는 것(사용 설명서도 포함)
- Rest API는 Client와 Server 사이에 일어나지만 Server와 Server 사이에도 일어남
WebClient
- Client의 요청을 Server에서 받아 다른 Server에 요청 후 응답 값을 client에 다시 전달
- pom.xml
- Maven Repository에서 webflux 복붙
- project 생성 시 library추가해도 됨
<!-- https://mvnrepository.com/artifact/org.springframework.boot/spring-boot-starter-webflux -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-webflux</artifactId>
</dependency>
- index.html
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
<script src="https://code.jquery.com/jquery-3.6.3.min.js"></script>
</head>
<body>
<h3>INDEX PAGE</h3>
<input type="text" id="msg"/>
<button onclick="getSend()">GET SEND</button>
<br/><br/>
<input type="number" id="cnt"/>
<button onclick="postSend()">POST SEND</button>
<p><button onclick="fluxTest()">FLUX TEST</button></p>
</body>
<script>
function getSend(){
$.ajax({
url:'/get/send/'+$('#msg').val(),
type:'get',
dataType:'json',
success:function(data){
console.log(data);
},
error:function(e){
console.log(e);
}
});
}
// 숫자 전송 -> 숫자만큼 리스트를 가져옴
// 헤더에 값을 넣음(보안이 필요한 값은 헤더에 많이 넣음)
function postSend(){
$.ajax({
url:'/post/send/'+$('#cnt').val(),
type:'post',
dataType:'json',
beforeSend:function(header){
console.log(header);
header.setRequestHeader("Authorization","ASD123");
},
success:function(data){
console.log(data);
},
error:function(e){
console.log(e);
}
});
}
function fluxTest(){
$.ajax({
url:'/get/fluxTest',
type:'get',
dataType:'json',
success:function(data){
console.log(data);
},
error:function(e){
console.log(e);
}
});
}
</script>
</html>
- SendController
package kr.co.gudi.controller;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestHeader;
import org.springframework.web.bind.annotation.RestController;
import kr.co.gudi.service.ApiService;
@RestController
public class SendController {
Logger logger = LoggerFactory.getLogger(getClass());
private final ApiService service;
public SendController(ApiService service) {
this.service = service;
}
@GetMapping(value = "/get/send/{msg}")
public HashMap<String, String> getSend(@PathVariable String msg){
logger.info("getSend : "+msg);
return service.getSend(msg);
}
@PostMapping(value = "/post/send/{cnt}")
public ArrayList<HashMap<String, Object>> postSend(
@PathVariable String cnt, @RequestHeader HashMap<String, String> header){
logger.info("header : "+header);
return service.postSend(cnt,header.get("authorization"));
}
@GetMapping(value = "/get/fluxTest")
public List<HashMap<String, Object>> fluxTest(){
return service.fluxTest();
}
}
- ApiService
@Service
public class ApiService {
Logger logger = LoggerFactory.getLogger(getClass());
/* WebClient는 Spring 5.0부터 지원
* Httpconnection -> RestTemplate -> WebClient(webflux)
* WebClient : non-blocking 방식을 지원하며 속도가 빠름
*/
public HashMap<String, String> getSend(String msg) {
// 1. 전송 URL 설정(특정한 주소로 요청을 보내겠다)
// 지금은 하나의 서버로 했지만 다른 서버로 보낼 수도 있음
WebClient client = WebClient.create("http://localhost");
// 2. 전송방식 선택 // 3. 추가할 URL 설정
Mono<HashMap> mono = client.get().uri("/return/"+msg)
// retrieve() : body 값만 가져옴
// exchange() : body+header+status 등도 가져옴(사용지양-너무 많은 값을 가져옴(뭉탱이로))
// 4. 전송(어떻게 보낼것인지, 무엇을 받을 것인지에 따라 다름)
.retrieve()
// 5. 받아올 방식 설정(형태, 처리방식에 따라 다름)
.bodyToMono(HashMap.class);
// Mono, Flux : 데이터를 받아올 때 데이터를 알맹이 같이 감싼 상태로 뭉탱이로 떨어짐
//데이터를 감싸서 가져오는 껍데기 같은 느낌(future 객체와 비슷)
//혼자서는 아무것도 할 수 없기 때문에 아래와 같이 꺼내서 사용
// bodyToMono : 데이터가 0~1개 처리될 경우(동기식)
// bodyToFlux : 데이터가 한번에 여러개 처리될 경우(비동기식)
HashMap<String, String> resp = mono.block();
logger.info("resp : "+resp);
return resp;
}
public ArrayList<HashMap<String, Object>> postSend(String cnt, String key) {
// get에서는 url에 파라메터를 보냈지만
// post에서는 바디에 보내야 함
WebClient client = WebClient.create("http://localhost");
// post에서는 파라메터를 uri에 붙일 수 없어서 바디에 넣어서 보내야하기 때문에 다음과 같이 파라메터를 넣음
FormInserter<String> form = BodyInserters.fromFormData("cnt",cnt);
form.with("name","lee"); // 추가로 파라메터를 넣고 싶을 경우
Mono<ArrayList> mono = client.post().uri("/listReturn")
.header("headerName", key)
.body(form)
.retrieve().bodyToMono(ArrayList.class);
// block()은 사용이 편리하지만 사용을 권고하지 않음(동기방식이라 효율성이 떨어짐)
// ex) 선착순으로 하나씩 뽑으면 일시적으로 몰리는 현상이 발생함
//ArrayList<HashMap<String, Object>> resp = mono.block();
// 비동기로 받아놓고 -> 줄을 세워서 -> 하나씩 가져옴
ArrayList<HashMap<String, Object>> resp = mono.flux().toStream().findFirst().get();
logger.info("resp : "+resp);
return resp;
}
public List<HashMap<String, Object>> fluxTest() {
WebClient client = WebClient.create("http://localhost");
// json 형태로 파라메터 보내기
HashMap<String, Object> params = new HashMap<String, Object>();
params.put("age", 22);
params.put("name", "lee");
params.put("married", false);
params.put("scores", new int[] {30,40,50,60,70,80,90,100});
// json 형태로 데이터를 보낼때 bodyValue를 사용하면 됨
// 받을때는 @RequestBody로 받아야함
List<HashMap<String, Object>> list = client.post().uri("fluxReturn")
.bodyValue(params).retrieve()
.bodyToFlux(HashMap.class).toStream()
.collect(Collectors.toList()); //list 형태로 하나씩 수집해서 가져옴(list 형태로만 반환)
return list;
}
}
- ReceiveController
package kr.co.gudi.controller;
import java.util.ArrayList;
import java.util.HashMap;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.bind.annotation.CrossOrigin;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestHeader;
import org.springframework.web.bind.annotation.RestController;
@RestController
@CrossOrigin(value = "*") // 외부에서 어떤 요청이 올지 모르기 때문에 설정
public class ReceiveController {
Logger logger = LoggerFactory.getLogger(getClass());
//요청온 메세지를 그대로 돌려줌
@GetMapping(value = "/return/{msg}")
public HashMap<String, String> getReturn(@PathVariable String msg){
logger.info("다른 서버로 부터 받은 메시지 : "+msg);
HashMap<String, String> result = new HashMap<String, String>();
result.put("your_msg", msg);
return result;
}
@PostMapping(value = "/listReturn")
public ArrayList<HashMap<String, Object>> postReturn(
int cnt, @RequestHeader HashMap<String, String> header){
logger.info("receive : "+cnt);
logger.info("receive key : "+header.get("authorization"));
ArrayList<HashMap<String, Object>> list = new ArrayList<HashMap<String,Object>>();
HashMap<String, Object> map = null;
for (int i = 0; i < cnt; i++) {
map = new HashMap<String, Object>();
map.put("no", i);
map.put("name", "lee");
map.put("salary", i*10000000);
list.add(map);
}
return list;
}
@PostMapping(value = "/fluxReturn")
public ArrayList<HashMap<String, Object>> fluxReturn(@RequestBody HashMap<String, Object> params){
logger.info("params : "+params);
ArrayList<HashMap<String, Object>> list = new ArrayList<HashMap<String,Object>>();
HashMap<String, Object> map = null;
for (int i = 0; i < 10; i++) {
map = new HashMap<String, Object>();
map.put("no", i);
map.put("name", "lee");
map.put("salary", i*10000000);
list.add(map);
}
return list;
}
}
ApiServer
- index.html
<html>
<head>
<meta charset="UTF-8">
<title>J-QUERY</title>
<link rel="icon" href="../img/chrome.png">
<script src="https://code.jquery.com/jquery-3.6.3.min.js"></script>
<style>
ul{
list-style-type: none;
}
li{
height: 30;
width: 300;
border: 1px solid lightgray;
padding: 10;
font-size: 13;
margin-top: 5;
cursor: pointer;
}
a{
text-decoration: none;
color: black;
}
a:visited{
text-decoration: none;
color: gray;
}
.centerName{
font-weight: 600;
}
.address{
color: gray;
}
</style>
</head>
<body>
<ul id="list"></ul>
</body>
<script>
//var url = 'https://api.odcloud.kr/api/15077586/v1/centers';
//var key = '3CtbWp0yQsbTWajEO8gjZvITGmrmVWB0yh3fjbjhSKoFhCIYZ7tiI1ueDjJvAIX85vWdWiznj7ejkuFbEcKmKw==';
$.ajax({
url:'apiCall.ajax',
type:'get',
data:{
page:1,
perPage:10
},
dataType:'json',
success:function(obj){
console.log(obj);
var content = '';
obj.data.forEach(item => {
content += '<li>';
content += '<a href="https://www.google.com/maps/place/'+item.address+'">';
content += '<div class="centerName">'+item.centerName+'</div>';
content += '<div class="address">'+item.address+'</div>';
content += '</a>';
content += '</li>';
});
$('#list').html(content);
},
error:function(e){
console.log(e);
}
});
</script>
</html>
- ApiController
package kr.co.gudi.controller;
import java.util.Map;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import kr.co.gudi.service.ApiService;
@RestController
public class ApiController {
@Autowired ApiService service;
Logger logger = LoggerFactory.getLogger(getClass());
@GetMapping(value = "/apiCall.ajax")
public Map<String, Object> apiList(String page, String perPage){
logger.info(page+"/"+perPage);
return service.getList(page,perPage);
}
}
- ApiService
package kr.co.gudi.service;
import java.util.HashMap;
import java.util.Map;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;
import org.springframework.web.reactive.function.client.WebClient;
import org.springframework.web.util.DefaultUriBuilderFactory;
import org.springframework.web.util.DefaultUriBuilderFactory.EncodingMode;
import io.netty.handler.codec.http.multipart.HttpPostRequestEncoder.EncoderMode;
import reactor.core.publisher.Mono;
@Service
public class ApiService {
Logger logger = LoggerFactory.getLogger(getClass());
public Map<String, Object> getList(String page, String perPage) {
String url = "https://api.odcloud.kr/api/15077586/v1/centers";
// encoding key 사용
String key = "3CtbWp0yQsbTWajEO8gjZvITGmrmVWB0yh3fjbjhSKoFhCIYZ7tiI1ueDjJvAIX85vWdWiznj7ejkuFbEcKmKw%3D%3D";
//WebClient에서는 특수문자가 있는 경우 따로 인코딩 과정을 거쳐야함
DefaultUriBuilderFactory fac = new DefaultUriBuilderFactory(url);
fac.setEncodingMode(EncodingMode.VALUES_ONLY);
WebClient client = WebClient.builder().uriBuilderFactory(fac).baseUrl(url).build();
Mono<HashMap> mono = client.get().uri("?serviceKey="+key+"&page="+page+"&perPage="+perPage).retrieve().bodyToMono(HashMap.class);
Map<String, Object> resp = mono.flux().toStream().findFirst().get();
logger.info("resp : "+resp);
return resp;
}
}
'코딩도전기 > Spring Boot' 카테고리의 다른 글
Spring Boot - Scheduler / File Upload&Download (0) | 2023.06.07 |
---|---|
Spring Boot - Properties / AOP(Interceptor) (0) | 2023.06.02 |
String Boot - Restful Service (0) | 2023.05.30 |
Spring Boot - Transaction / Connection Pool / CSS 일괄적용 (0) | 2023.05.26 |
Spring Boot - 쿼리문 로고 찍기 / 동적쿼리 (0) | 2023.05.25 |