[Spring 18-1] REST(Representational State Transfer) ์˜ˆ์ œ

์ž„์Šนํ˜„ยท2023๋…„ 3์›” 6์ผ

Spring

๋ชฉ๋ก ๋ณด๊ธฐ
43/46

๐Ÿ“ขREST(Representational State Transfer) : ์ž์›(Resource)์˜ ํ‘œํ˜„(Representation)์— ์˜ํ•œ ์ƒํƒœ(State)๋ฅผ ์ „๋‹ฌ(Transfer)ํ•˜๋Š” ๊ฒƒ์„ ์˜๋ฏธ
โ†’ ํŽ˜์ด์ง€ ์š”์ฒญ์— ๋Œ€ํ•œ ์ฒ˜๋ฆฌ๊ฒฐ๊ณผ๋ฅผ ํด๋ผ์ด์–ธํŠธ์—๊ฒŒ XML ์ด๋‚˜ JSON ํ˜•์‹์˜ ํ…์ŠคํŠธ ๋ฐ์ดํ„ฐ๋กœ ์‘๋‹ต
๐Ÿ“ขRestful API : REST ๊ธฐ๋Šฅ์„ ์‚ฌ์šฉํ•˜์—ฌ ๋‘ ์ปดํ“จํ„ฐ์˜ ์‹œ์Šคํ…œ์ด ์•ˆ์ „ํ•˜๊ฒŒ ๊ฐ’์„ ์ฃผ๊ณ  ๋ฐ›๊ธฐ ์œ„ํ•œ ํ”„๋กœ๊ทธ๋žจ
โ†’ ์Šค๋งˆํŠธ๊ธฐ๊ธฐ์˜ ํ”„๋กœ๊ทธ๋žจ(์•ฑ) ์ •๋ณด๋ฅผ ์ „๋‹ฌ๋ฐ›์•„ ์ €์žฅํ•˜๊ฑฐ๋‚˜ ๊ฒ€์ƒ‰๊ฒฐ๊ณผ๋ฅผ ์ œ๊ณตํ•˜์—ฌ ์ถœ๋ ฅํ•˜๊ธฐ ์œ„ํ•ด ์‚ฌ์šฉ

๐ŸŒˆController ํด๋ž˜์Šค ์ƒ์„ฑ

๐Ÿ“ƒRestfulController.java

โ€ป xyz.itwill10.controller ํŒจํ‚ค์ง€์— RestfulController.java ํด๋ž˜์Šค ์ƒ์„ฑ

package xyz.itwill10.controller;
//
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import xyz.itwill10.dto.Member;
//
//REST(Representational State Transfer) : ์ž์›(Resource)์˜ ํ‘œํ˜„(Representation)์— ์˜ํ•œ ์ƒํƒœ(State)๋ฅผ ์ „๋‹ฌ(Transfer)ํ•˜๋Š” ๊ฒƒ์„ ์˜๋ฏธ
//โ†’ ํŽ˜์ด์ง€ ์š”์ฒญ์— ๋Œ€ํ•œ ์ฒ˜๋ฆฌ๊ฒฐ๊ณผ๋ฅผ ํด๋ผ์ด์–ธํŠธ์—๊ฒŒ XML ์ด๋‚˜ JSON ํ˜•์‹์˜ ํ…์ŠคํŠธ ๋ฐ์ดํ„ฐ๋กœ ์‘๋‹ต
//Restful API : REST ๊ธฐ๋Šฅ์„ ์‚ฌ์šฉํ•˜์—ฌ ๋‘ ์ปดํ“จํ„ฐ์˜ ์‹œ์Šคํ…œ์ด ์•ˆ์ „ํ•˜๊ฒŒ ๊ฐ’์„ ์ฃผ๊ณ  ๋ฐ›๊ธฐ ์œ„ํ•œ ํ”„๋กœ๊ทธ๋žจ
//โ†’ ์Šค๋งˆํŠธ๊ธฐ๊ธฐ์˜ ํ”„๋กœ๊ทธ๋žจ(์•ฑ) ์ •๋ณด๋ฅผ ์ „๋‹ฌ๋ฐ›์•„ ์ €์žฅํ•˜๊ฑฐ๋‚˜ ๊ฒ€์ƒ‰๊ฒฐ๊ณผ๋ฅผ ์ œ๊ณตํ•˜์—ฌ ์ถœ๋ ฅํ•˜๊ธฐ ์œ„ํ•ด ์‚ฌ์šฉ
//
@Controller
public class RestfulController {
	@RequestMapping(value = "/rest", method = RequestMethod.GET)
	public String rest() {
		return "rest/input";
	}
	//
	/*
	//@RequestParam ์–ด๋…ธํ…Œ์ด์…˜์„ ์‚ฌ์šฉํ•˜์—ฌ ํ•˜๋‚˜์˜ ์ „๋‹ฌ๊ฐ’์„ ํ•˜๋‚˜์˜ ๋งค๊ฐœ๋ณ€์ˆ˜์— ์ €์žฅ๋ฐ›์•„ ์‚ฌ์šฉ
	@RequestMapping(value = "/rest", method = RequestMethod.POST)
	public String rest(@RequestParam String id, @RequestParam String name, Model model) {
		model.addAttribute("id", id);
		model.addAttribute("name", name);
		//๋ฐ˜ํ™˜๋˜๋Š” ๋ฌธ์ž์—ด(ViewName)์„ ์ด์šฉํ•˜์—ฌ ViewResolver ๊ฐ์ฒด๊ฐ€ ๋ทฐ๋กœ ์™„์„ฑํ•˜์—ฌ ์‘๋‹ต ์ฒ˜๋ฆฌ
		return "rest/output";
	}
	*/
	//
	//@ResponseBody : ์š”์ฒญ ์ฒ˜๋ฆฌ ๋ฉ”์†Œ๋“œ์˜ ๋ฐ˜ํ™˜๊ฐ’(๋ฌธ์ž์—ด)์„ ๋ฆฌ์Šคํฐ์ฆˆ ๋ฉ”์„ธ์ง€ ๋ชธ์ฒด๋ถ€์— ์ €์žฅํ•˜์—ฌ ํด๋ผ์ด์–ธํŠธ์—๊ฒŒ ์ง์ ‘ ํ…์ŠคํŠธ ๋ฐ์ดํ„ฐ๋กœ ์‘๋‹ต๋˜๋„๋ก ์„ค์ •ํ•˜๋Š” ์–ด๋…ธํ…Œ์ด์…˜
	//โ†’ ๋ฐ˜ํ™˜๋˜๋Š” ๋ฌธ์ž์—ด์„ ViewResolver ๊ฐ์ฒด๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ๋ทฐ๋กœ ๋ณ€ํ™˜ํ•˜์—ฌ ์‘๋‹ตํ•˜์ง€ ์•Š๊ณ  ๋ฆฌ์Šคํฐ์ฆˆ ๋ฉ”์„ธ์ง€ ๋ชธ์ฒด๋ถ€์— ์ €์žฅํ•˜์—ฌ Front Controller๊ฐ€ ์ง์ ‘ ์‘๋‹ต ์ฒ˜๋ฆฌ
	//โ†’ Java ๊ฐ์ฒด๋Š” ๋ฆฌ์Šคํฐ์ฆˆ ๋ฉ”์„ธ์ง€ ๋ชธ์ฒด๋ถ€์— ์ €์žฅ ๋ถˆ๊ฐ€๋Šฅํ•˜๋ฏ€๋กœ ์‘๋‹ต ๋ถˆ๊ฐ€๋Šฅ
	//@RequestBody : ๋ฆฌํ€˜์ŠคํŠธ ๋ฉ”์„ธ์ง€ ๋ชธ์ฒด๋ถ€์— ์ €์žฅ๋˜์–ด ๋ชจ๋“  ์ „๋‹ฌ๊ฐ’์„ ๋ฌธ์ž์—ด๋กœ ์ œ๊ณต๋ฐ›๊ธฐ ์œ„ํ•œ ์–ด๋…ธํ…Œ์ด์…˜
	//โ†’ POST, PUT, PATCH, DELETE ๋“ฑ์˜ ์š”์ฒญ๋ฐฉ์‹์— ์˜ํ•ด ๋ฆฌํ€˜์ŠคํŠธ ๋ฉ”์„ธ์ง€ ๋ชธ์ฒด๋ถ€์— ์ €์žฅ๋˜์–ด ์ „๋‹ฌ๋œ ๋ชจ๋“  ๊ฐ’์„ ๋ฌธ์ž์—ด๋กœ ์ œ๊ณต๋ฐ›์•„ ์‚ฌ์šฉ ๊ฐ€๋Šฅ 
	//โ†’ GET ๋ฐฉ์‹์€ ๋ฆฌํ€˜์ŠคํŠธ ๋ฉ”์„ธ์ง€ ๋ชธ์ฒด๋ถ€๊ฐ€ ๋น„์–ด ์žˆ์œผ๋ฏ€๋กœ @RequestBody ์–ด๋…ธํ…Œ์ด์…˜ ์‚ฌ์šฉ ๋ถˆ๊ฐ€๋Šฅ
	//โ†’ ๋ฆฌํ€˜์ŠคํŠธ ๋ฉ”์„ธ์ง€ ๋ชธ์ฒด๋ถ€์— ์ €์žฅ๋˜์–ด ์ „๋‹ฌ๋œ JSON ํ˜•์‹(application/json)์˜ ๊ฐ’์€ ๋งค๊ฐœ๋ณ€์ˆ˜์— Java ๊ฐ์ฒด๋กœ ์ œ๊ณต๋ฐ›์•„ ์‚ฌ์šฉ ๊ฐ€๋Šฅ - ์ „๋‹ฌ๊ฐ’์€ ๊ฐ์ฒด ํ•„๋“œ์— ์ €์žฅ 
	@RequestMapping(value = "/rest", method = RequestMethod.POST)
	@ResponseBody
	public String rest(@RequestBody String input) {
		return input;
	}
	//
	//@ResponseBody ์–ด๋…ธํ…Œ์ด์…˜์„ ์‚ฌ์šฉํ•˜์—ฌ ์š”์ฒญ ์ฒ˜๋ฆฌ ๋ฉ”์†Œ๋“œ์˜ ๋ฐ˜ํ™˜๊ฐ’(Member ๊ฐ์ฒด)์„ ๋ฆฌ์Šคํฐ์ฆˆ ๋ฉ”์„ธ์ง€์˜ ๋ชธ์ฒด๋ถ€์— ์ €์žฅํ•˜์—ฌ ํ…์ŠคํŠธ ๋ฐ์ดํ„ฐ์˜ ํšŒ์›์ •๋ณด๋ฅผ ํด๋ผ์ด์–ธํŠธ์—๊ฒŒ ์ „๋‹ฌํ•˜์—ฌ ์‘๋‹ต ์ฒ˜๋ฆฌ
	//๋ฌธ์ œ์ )๋ฆฌ์Šคํฐ์ฆˆ ๋ฉ”์„ธ์ง€์˜ ๋ชธ์ฒด๋ถ€์— Java ๊ฐ์ฒด๋ฅผ ์ €์žฅ ๋ถˆ๊ฐ€๋Šฅ - ์—๋Ÿฌ ๋ฐœ์ƒ(406)
	//ํ•ด๊ฒฐ๋ฒ•)๋ฐ˜ํ™˜๋˜๋Š” Java ๊ฐ์ฒด๋ฅผ ํ…์ŠคํŠธ ๋ฐ์ดํ„ฐ(XML ๋˜๋Š” JSON)์˜ ๋ฌธ์ž์—ด๋กœ ์ž๋™ ๋ณ€ํ™˜๋˜๋„๋ก ์„ค์ •ํ•˜์—ฌ ์‘๋‹ต ์ฒ˜๋ฆฌ ๊ฐ€๋Šฅ
	//โ†’ jackson-databind ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋ฅผ ํ”„๋กœ์ ํŠธ์— ๋นŒ๋“œ ์ฒ˜๋ฆฌํ•˜๋ฉด ์ž๋™์œผ๋กœ Java ๊ฐ์ฒด๊ฐ€ JSON
	//ํ˜•์‹์˜ ํ…์ŠคํŠธ ๋ฐ์ดํ„ฐ๋กœ ๋ณ€ํ™˜ํ•˜์—ฌ ๋ฐ˜ํ™˜ - ๋ฉ”์ด๋ธ : pom.xml
	@RequestMapping("/rest_member")
	@ResponseBody
	public Member restMember() {
		Member member=new Member();
		member.setId("abc123");
		member.setPasswd("123456");
		member.setName("ํ™๊ธธ๋™");
		member.setEmail("abc@itwill.xyz");
		//
		//jackson-databind ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ์— ์˜ํ•ด Member ๊ฐ์ฒด๊ฐ€ JavaScript Object ๊ฐ์ฒด๋กœ ๋ณ€ํ™˜๋˜์–ด ์‘๋‹ต
		return member;
	}
	//
	//@ResponseBody ์–ด๋…ธํ…Œ์ด์…˜์„ ์‚ฌ์šฉํ•˜์—ฌ ์š”์ฒญ ์ฒ˜๋ฆฌ ๋ฉ”์†Œ๋“œ์˜ ๋ฐ˜ํ™˜๊ฐ’(List ๊ฐ์ฒด)์„ ๋ฆฌ์Šคํฐ์ฆˆ ๋ฉ”์„ธ์ง€์˜ ๋ชธ์ฒด๋ถ€์— ์ €์žฅํ•˜์—ฌ ํ…์ŠคํŠธ ๋ฐ์ดํ„ฐ์˜ ํšŒ์›๋ชฉ๋ก์„ ํด๋ผ์ด์–ธํŠธ์—๊ฒŒ ์ „๋‹ฌํ•˜์—ฌ ์‘๋‹ต ์ฒ˜๋ฆฌ
	@RequestMapping("/rest_list")
	@ResponseBody
	public List<Member> restMemberList() {
		List<Member> memberList=new ArrayList<Member>();
		//
		Member member1=new Member();
		member1.setId("abc123");
		member1.setPasswd("123456");
		member1.setName("ํ™๊ธธ๋™");
		member1.setEmail("abc@itwill.xyz");
		memberList.add(member1);
		//
		Member member2=new Member();
		member2.setId("xyz789");
		member2.setPasswd("789456");
		member2.setName("์ž„๊บฝ์ •");
		member2.setEmail("xyz@itwill.xyz");
		memberList.add(member2);
		//		
		//jackson-databind ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ์— ์˜ํ•ด List ๊ฐ์ฒด๊ฐ€ JavaScript Array ๊ฐ์ฒด๋กœ ๋ณ€ํ™˜๋˜์–ด ์‘๋‹ต
		return memberList;
	}
	//
	@RequestMapping("/rest_map")
	@ResponseBody
	public Map<String, Object> restMap() {
		Map<String, Object> map=new HashMap<String, Object>();
		map.put("id", "abc123");
		map.put("passwd", "123456");
		map.put("name", "ํ™๊ธธ๋™");
		map.put("email", "abc@itwill.xyz");
		//	
		//jackson-databind ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ์— ์˜ํ•ด Map ๊ฐ์ฒด๊ฐ€ JavaScript Object ๊ฐ์ฒด๋กœ ๋ณ€ํ™˜๋˜์–ด ์‘๋‹ต
		return map;
	}
	//
	@RequestMapping(value = "/rest/map", method = RequestMethod.GET)
	public String restInput() {
		return "rest/input";
	}
	//
	//๋ชจ๋“  ์ „๋‹ฌ๊ฐ’์ด Map ๊ฐ์ฒด์˜ ์—”ํŠธ๋ฆฌ์— ์ €์žฅ๋˜์–ด ๋งค๊ฐœ๋ณ€์ˆ˜๋กœ ์ œ๊ณต๋ฐ›์•„ ์‚ฌ์šฉ ๊ฐ€๋Šฅ
	//โ†’ ๋ชจ๋“  ์ „๋‹ฌ๊ฐ’์„ Map ๊ฐ์ฒด๋กœ ์ œ๊ณต๋ฐ›๊ธฐ ์œ„ํ•ด ๋ฐ˜๋“œ์‹œ @RequestParam ์–ด๋…ธํ…Œ์ด์…˜ ์‚ฌ์šฉ
	@RequestMapping(value = "/rest/map", method = RequestMethod.POST)
	@ResponseBody
	public Map<String, Object> restOutput(@RequestParam Map<String, Object> map) {
		return map;
	}
}

๐ŸŒˆJSP ์ž‘์„ฑ

๐Ÿ“ƒinput.jsp

โ€ป WEB-INF/views/rest ํด๋”์— input.jsp ์ž‘์„ฑ

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>SPRING</title>
</head>
<body>
	<h1>์ž…๋ ฅํŽ˜์ด์ง€</h1>
	<hr>
	<form method="post">
		<table>
			<tr>
				<td>์•„์ด๋””</td>
				<td><input type="text" name="id"></td>
			</tr>
			<tr>
				<td>์ด๋ฆ„</td>
				<td><input type="text" name="name"></td>
			</tr>
			<tr>
				<td colspan="2"><button type="submit">์ž…๋ ฅ์™„๋ฃŒ</button></td>
			</tr>
		</table>
	</form>
</body>
</html>

๐Ÿ“ƒoutput.jsp

โ€ป WEB-INF/views/rest ํด๋”์— output.jsp ์ž‘์„ฑ

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>SPRING</title>
</head>
<body>
	<h1>์ถœ๋ ฅํŽ˜์ด์ง€</h1>
	<hr>
	<p>์•„์ด๋”” = ${id }</p>
	<p>์ด๋ฆ„ = ${name }</p>
</body>
</html>

๐ŸŒˆ๋นŒ๋“œ ์ฒ˜๋ฆฌ

๐Ÿ“ƒpom.xml

<!-- https://mvnrepository.com/artifact/com.fasterxml.jackson.core/jackson-databind -->
<!-- โ†’ Java ๊ฐ์ฒด๋ฅผ JSON ํ˜•์‹์˜ ํ…์ŠคํŠธ ๋ฐ์ดํ„ฐ๋กœ ๋ณ€ํ™˜ํ•˜๊ธฐ ์œ„ํ•œ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ -->
<dependency>
    <groupId>com.fasterxml.jackson.core</groupId>
    <artifactId>jackson-databind</artifactId>
    <version>2.14.2</version>
</dependency>

0๊ฐœ์˜ ๋Œ“๊ธ€