230531 WebClient

Myung A Lee·2023년 5월 31일
0

Code Review

목록 보기
5/5
post-thumbnail

SpringBoot

REST API

웹상에서 URL을 통해 원하는 정보를 얻어오거나 특정한 요청을 하는 것을 REST API라고 한다.
REST API는 Client와 Server 사이에서 일어나지만 Server와 Server 사이에도 일어난다.
우리는 Client의 요청을 Server에서 받아 다른 Server에 요청을 보내고 그 응답 값을 Client에게 다시 전달 할 것.
즉 index.html에서 ajax를 통해 요청을 SendController 보내고 SendController는 ApiService에서 다른 서버인 ReceiveController로 요청을 보낸다. ReceiveController에서는 응답을 Client인 index.html에 돌려보낸다.

pom.xml

<!-- webclient(webflux) -->
<!-- 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({
			type:'get',
			url:'/get/send/'+$('#msg').val(),
			data:{},
			dataType:'json',
			success:function(data){
				console.log(data);
			},
			error:function(e){
				console.log(e);
			}
		});
	}
	
	
	// 숫자ㅣ 전송 -> 숫자만큼 리스트를 가져온다.
	// 헤더에 값을 넣는다. 
	
	function postSend(){
		$.ajax({
			type:'post',
			url:'/post/send/'+$('#cnt').val(),
			data:{},
			dataType:'json',
			beforeSend:function(header){
				console.log(header);
				header.setRequestHeader("Authorization","ASDFG456789");
			},
			success:function(data){
				console.log(data);
			},
			error:function(e){
				console.log(e);
			}
		});
		}
		
	function fluxTest(){
		$.ajax({
			type:'get',
			url:'/get/fluxTest',
			data:{},
			dataType:'json',
			success:function(data){
				console.log(data);
			},
			error:function(e){
				console.log(e);
			}
			
		});
	}

</script>
</html>

SendController.java

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(this.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("msg : "+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.java

package kr.co.gudi.service;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.stream.Collectors;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;
import org.springframework.web.reactive.function.BodyInserters;
import org.springframework.web.reactive.function.BodyInserters.FormInserter;
import org.springframework.web.reactive.function.client.WebClient;


import reactor.core.publisher.Mono;

@Service

public class ApiService {
	Logger logger = LoggerFactory.getLogger(this.getClass());
	
	// WebClient는 spring 5.0부터 지원한다. 
	// HttpConnecttion -> RestTemplate -> WebClient(webFlux)
	// WebClient는 non-blocking (비동기)방식을 지원하며, 속도가 빠르다.

	public HashMap<String, String> getSend(String msg) {
		// 1. 전송할 URL 설정
		WebClient client = WebClient.create("http://192.168.12.25");
		
		// 2. 전송받식 선택  3. 추가 URL 설정 4.전송(어떻게 보낼 것인지/무엇을 받을 것인지?) 5. 받아올 방식 설정 (형태, 처리방식)
		// retrieve() : body 값만 가져온다.
		
		
		
		// exchange() : body + header + status 등도 가져온다.
		Mono<HashMap> mono = client.get().uri("/return/"+msg).retrieve().bodyToMono(HashMap.class);
		
		// 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에 파라메터를 보냈지만
		

		
		WebClient client = WebClient.create("http://localhost");

		//post 에서는 바디에 보내야한다. 그래서 아래와 같이 파라메터를 넣는다. 
		FormInserter<String> form = BodyInserters.fromFormData("cnt",cnt);
		
		Mono<ArrayList> mono =  client.post().uri("/listReturn")
								.header("authorization", key).body(form)
								.retrieve().bodyToMono(ArrayList.class);
		
		// block()은 사용이 편리하지만 사용을 권고하지 않는다. ( 동기방식이라 효율성이 떨어진다)
		// 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");
		
		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());
		
		return list;
	}
	
}

ReceiveController.java

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
public class ReceiveController {
	
	Logger logger = LoggerFactory.getLogger(this.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 = 1; i <= cnt; i++) {
			map = new HashMap<String, Object>();
			map.put("no", i);
			map.put("name", "kim");
			map.put("salary", i*100000);
			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>>();
		
		for (int i = 1; i <= 10; i++) {
			
			list.add(params);
		}
		
		return list;
	}
}

0개의 댓글