today_is
[ spring ] RestController 본문
오늘의 목표
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< 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 요청 처리 시 사용된다고 알려져있다.
최근에 어노테이션에 대해 정리해봤지만, 막상 직접 사용하려니 이론으로 배운 부분을 바로 적용하는 것이 어렵게 느껴진다.
'spring' 카테고리의 다른 글
[ Exception ] 예외처리, 예외전가 (0) | 2024.01.30 |
---|---|
[ spring ] 간단한 POS 구현 (0) | 2024.01.19 |
[ spring ] 설문 및 투표 + 설문결과보기 기능 구현 (0) | 2024.01.09 |
[ spring ] FileComponent , 다중 파일업로드 (0) | 2024.01.04 |
[ spring ] 어노테이션 문법정리 (0) | 2024.01.02 |