today_is

[ spring ] RestController 본문

spring

[ spring ] RestController

ye_rang 2024. 1. 16. 22:57

오늘의 목표

json 와 ajax 에 대해서 알아보고, ajax 전용 컨트롤러인 @RestController를 사용해보자.


JSON

: javaScript Object Notation

 

자바스크립트 토대로 개발되었으며, 여러 프로그래밍언어에도 사용할 수 있는 독립형 언어이다.

 

데이터 객체의 형태는 속성 - 값 쌍 형태

 

주로, 웹 브라우저와 웹 서버간 비동기 통신, 데이터 교환 등에 사용된다 

 

 

 

home.jsp

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>

<style>
	table {
		border : 2px solid black;
		border-collapse: collapse;
	}
	td {
		padding: 5px 10px;
		border: 1px solid grey;
	}
</style>
</head>
<body>

<h1>day10</h1>

<hr>


<ul>
	<li><a href="ex01">ex01 - ajax(1) 정수반환</a></li>
	<li><a href="ex02">ex02 - ajax(2) 문자열 반환</a></li>
	<li><a href="ex03">ex03 - ajax(3) map 반환</a></li>
	<li><a href="ex04">ex04 - ajax(4) List&lt; DTO 반환(DB 이용 O)</a></li>
</ul>



<div id="root"></div>

<script>
	let url = "https://apis.data.go.kr/6260000/BusanRainfalldepthInfoService/getRainfallInfo";
	
	const param = {
			serviceKey : 'fPywZzdX80yEsvW3nt%2F4DyY9NZVrqZDUOFBN5Kuw7UkhbMsuXNXY%2FzsT4iAZm6Z1ILayJYsElZPCr4JWUooiQg%3D%3D',
			pageNo : '1',
			numOfRows : '25',
			resultType: 'json',
	}
	
	url += '?'
	
	for(let key in param) {
		url += key + '=' + param[key] + '&'
	}
	
	
	fetch(url)				//	지정한 요청 주소로 보낸다
		.then(resp => resp.json())	//	요청 이후 돌아오는 응답을 JSON 객체로 변환한다
		.then(json => {			//	변환된 JSON 객체를 이용하여, { } 블럭 내부 코드를 수행한다 
		//	console.log(json.getRainfallInfo.body.items.item)
	
		const arr = json.getRainfallInfo.body.items.item.map(e => {
			const ob = {}
			ob.clientName = e.clientName
			ob.level6 = e.level6
			return ob
		})
		//	console.log(arr)
		const tr1 = document.createElement('tr')
		const tr2 = document.createElement('tr')
	
		
		for(let i in arr) {
			const td1 = document.createElement('td')
			td1.innerText = arr[i].clientName
			tr1.appendChild(td1)
			
			const td2 = document.createElement('td')
			td2.innerText = arr[i].level6
			tr2.appendChild(td2)
		}
		
		const table = document.createElement('table')
		table.appendChild(tr1)
		table.appendChild(tr2)
		
		const root = document.getElementById('root')
		root.appendChild(table)
		
	})

</script>


</body>
</html>

 

 

Ex01Controller

: 일반적인 스프링 컨트롤러 함수는 viewName을 반환해서, JSP로 포워딩 혹은 리다이렉트하는 것이 주 목적이다

package com.itbank.controller;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;

@Controller
public class Ex01Controller {

	@GetMapping("/ex01")
	public void ex01() {}

}

 

 

ex01.jsp

: 정수 덧셈의 결과를 보여줌

 

이때, 사용된 url 은 ex01Ajax 를 이용하는데, 이것은 AjaxController 에 GetMapping 으로 선언되어있음 

->   const url = '${cpath}/ex01Ajax?n1=' + n1 + '&n2=' + n2

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<c:set var="cpath" value="${pageContext.request.contextPath }" />
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>

<h1>ex01 - 두 정수의 덧셈</h1>
<hr>

<p>
	<input type="number" name="n1" min="0" max="20" placeholder="n1">
	+
	<input type="number" name="n2" min="0" max="20" placeholder="n2">
	<button id="btn">=</button>
	<span id="result"></span>
</p>

<script>
	const btn = document.getElementById('btn')
	const clickHandler = function() {
		const n1 = document.querySelector('input[name="n1"]').value
		const n2 = document.querySelector('input[name="n2"]').value
		const url = '${cpath}/ex01Ajax?n1=' + n1 + '&n2=' + n2
				
		fetch(url)
			.then(resp => resp.text())
			.then(text => {
				//	실행할 내용 (문서 요소에 응답 내용을 반환한다)
				const result = document.getElementById('result')
				result.innerText = text
			})
	}
	btn.onclick = clickHandler

</script>

</body>
</html>

 

 

 

AjaxController

: @RestController 이용

 

 

Ajax 이용한 코드들은 @RestController 선언한  Controller에 모아두기 !!

 

 

@RestController
: 문서 내용을 응답하지 않고, 순수 데이터를 응답하기 위한 AJAX 전용 컨트롤러
모든 함수에 자동으로 @ResponseBody 가 적용된다 (포워드 및 리다이렉트가 기본값이 아님)
포워딩을 안함. 요청 받은 그대로를 전달함 

package com.itbank.controller;

import java.util.HashMap;
import java.util.List;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestController;

import com.itbank.model.MemberDTO;
import com.itbank.service.MemberService;




@RestController
public class AjaxController {

	
	@Autowired private MemberService service;
	
	
	//	AJAX 요청에 대응하는 컨트롤러 함수는 기본 자료형 배열, 리스트, 맵, DTO 등 여러타입을 반환할 수 있다
	//	반환값이 viewName 이 아닌, 응답 그 자체임을 명시해야한다 
	@GetMapping("/ex01Ajax")
	@ResponseBody
	public int ex01Ajax(int n1, int n2) {
		return n1 + n2;
	}
	
	
	
	@PostMapping("/ex03Ajax")
	@ResponseBody		//	@ResponseBody : 반환하는 내용 그 자체가 응답이다
	public HashMap<String, Object> ex03Ajax(@RequestBody HashMap<String, Object> param) {	//	@RequestBody : 요청에 담긴 내용이 파라미터로 그대로 사용
																							//	즉, 요청 그 자체가 파라미터이다
		System.out.println("userid : " + param.get("userid"));
		HashMap<String, Object> map = new HashMap<>();
		int count = service.checkDuplicate(param);
		map.put("count", count);
		map.put("msg", count != 0 ? "이미 사용중인 아이디 입니다" : "사용가능한 아이디 입니다");
		
//		String result = objectMapper.writeValueAsString(map);
//		원래는, 자바 객체를 JSON 규칙에 맞춰 문자열로 변환한 후에 반환해야하지만,
//		ObjectMapper 가 자동으로 변환을 처리함 
		
		return map;
	}
	
	
	@GetMapping("/ex04Ajax")
	public List<MemberDTO> ex04Ajax() {
		return service.getMemberList();
	}
	
}

 

 

Ex03Controller

 

objectMapper 

: 얘가 자동으로 mapping해서 변환 해주고 있다 생각하면 됨 ( jackson-databind )

objectMapper 를 이용하면 JSON 데이터를 java객체로 변환하거나

java 객체를 JSON 형식으로 변환할 수 있다.

 

package com.itbank.controller;


import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;

import com.fasterxml.jackson.databind.ObjectMapper;

@Controller
public class Ex03Controller {

	private ObjectMapper objectMapper = new ObjectMapper();		
    
	@GetMapping("/ex03")
	public void ex03() {}
	

	
}

 

 

ex03.jsp

: 회원가입 중복체크

 

 

 유의할 점 

자바스크립트에서는 -(대시) 를 사용하지 않기 때문에  따옴표('')로 묶어서 처리 

->  'Content-Type' : 'application/json; charset=utf-8'

 

 

 

 

[ result 요소 ]

userid가 중복이 아니라면, 파란색 글자로 결과표시

userid 가 중복이라면, 빨강색 글자로 결과표시

 

AjaxController 에 msg 로 결과 텍스트
->   map.put("msg", count != 0 ? "이미 사용중인 아이디 입니다" : "사용가능한 아이디 입니다");

 

즉, 중복이 아니라면 '사용가능한 아이디 입니다' (파란색 글씨로)

중복이라면 '이미 사용중인 아이디 입니다' (빨간색 글씨로)

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<c:set var="cpath" value="${pageContext.request.contextPath }" />


<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>

<h1>ex03 - 회원 중복 가입 체크</h1>
<hr>

<p>
	<input type="text" name="userid" placeholder="ID" required autofocus>
	<button id="btn">중복 확인</button>
</p>

<h3 id="result"></h3>



<!-- 주소창에 내용이 노출되지 않는다는 이점  -->
<script>

	//	1) 이벤트의 대상이 될 요소를 불러온다
	const btn = document.getElementById('btn')

	//	2) 이벤트 발생 시 실행할 함수를 정의한다
	const clickHandler = function() {
		const userid = document.querySelector('input[name="userid"]').value
		const url = '${cpath}/ex03Ajax'		//	주소지정
		const opt = {				//	요청의 옵션들을 지정
				method : 'POST',	//	옵션 1) 요청 메서드는 POST
				
                //	옵션 2) POST의 전달 내용은 userid 를 포함하는 객체를 JSON 문자열 형식으로 전달
				body : JSON.stringify({	
					userid: userid
				}),					
				
                //	옵션 3) 헤더, 전송하는 데이터의 형식 및 인코딩을 지정
				headers : {				
					'Content-Type' : 'application/json; charset=utf-8'		
				},
		}
		
		fetch(url, opt)		//	요청 주소와 옵션을 함께 전달한다
			.then(resp => resp.json())
			.then(json => {
				console.log(json)
				const result = document.getElementById('result')
				result.innerText = json.msg
				if(json.count == 0) {
					result.style.color = 'blue'
				}
				else {
					result.style.color = 'red'
				}
			})
	}
	
	//	3) 이벤트 대상의 특정 상황 (클릭, 키, 스크롤 등)을 지정하여 이벤트 함수를 연결
	btn.onclick = clickHandler
	
	
</script>


</body>
</html>

 

 

 

Ex04Controller

package com.itbank.controller;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;

@Controller
public class Ex04Controller {

	@GetMapping("/ex04")
	public void ex04() {}
	
}

 

 

ex04.jsp

: 회원목록

 


DOM (Document Object Model)

: 문서의 내용을 하나하나 객체화하여, 객체의 모델관계로 해석하는 구조

 HTML 문서 내부의 태그를 '객체'로 취급하여, 여러 객체가 'Tree' 구조로 나열되어 있는 관계로 해석한다
 문서를 구성하는 각 요소(element) 혹은 객체(object) 를 DOM 이라고 부르기도 함 

->   document.addEventListener('DOMContentLoaded', loadHandler)

 


window.onload 와 loadHandler는 역할이 같음

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<c:set var="cpath" value="${pageContext.request.contextPath }" />

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>

<h1>ex04 - 회원 목록</h1>
<hr>

<div id="root"></div>

<script>
	function loadHandler() {
		const root = document.getElementById('root')		
		const url = '${cpath}/ex04Ajax'

		fetch(url) 
			.then(resp => resp.json()) 
			.then(json => {
				
				const arr = json
				let tag = '<table border="1" cellpadding="10" cellspacing="0">'
				for(let i = 0; i < arr.length; i++) {	//	i : 0, 1, 2, 3 ...
					const dto = arr[i]
					
					tag += '<tr>'
					for(let key in dto) {
						if(key != 'userpw') {
						tag += '<td>' + dto[key] + '</td>'
						}
					}
					tag += '</tr>'
				}
				tag += '</table>'
				root.innerHTML = tag
			})
	}
	
	document.addEventListener('DOMContentLoaded', loadHandler)
	//	window.onload == loadHandler


</script>

</body>
</html>

 


Study_review

처음에는 하나의 기능을 처리하는 코드를 일반 컨트롤러와 RestController로 나누어 작성하는 것이 어려웠다.

하지만 단순하게 접근하여, Ajax를 처리하는 부분만 @RestController에 작성해 보니,

코드의 목적이 명확해지고 구분이 쉬워졌다. 덕분에 이러한 작성 방식에 금방 익숙해질 수 있었다.

 

 

아직 헷갈리는 부분은 @ResponseBody 의 역할이다

 

챗지피티에 검색해본 결과로는 메서드가 반환하는 객체를 json 이나 xml 형식으로 변환해서 전송하는 역할을 한다고 한다.

또한 주로 RESTful 웹 서비스나 Ajax 요청 처리 시 사용된다고 알려져있다.

 

최근에 어노테이션에 대해 정리해봤지만, 막상 직접 사용하려니 이론으로 배운 부분을 바로 적용하는 것이 어렵게 느껴진다.