안녕하세요. 명월입니다.
이 글은 Web Spring framework의 Controller에서 ajax의 요청시 json을 반환하는 방법에 대한 글입니다.
이전 글에서 Web Spring에서 Controller를 다루는 방법에 대해서 설명했습니다.
link - [Java] 40. Web Spring framework에서 Controller를 다루는 방법
Controller이란 웹 브라우저에서 요청이 오면 실행되는 함수를 찾아서 실행하여 다시 웹 브라우저로 응답하는 역할까지 합니다.
그런데 여기서 Controller 메서드는 기본적으로 String 값을 리턴하게 되어 있습니다. 이 String값은 view 파일명을 탐색하기 위해 작성하게 되어 있습니다.
그러나 우리가 ajax로 웹 페이지의 html의 데이터를 받는 경우도 없는 것은 아니지만 보통은 json 형식으로 된 데이터 값을 리턴을 받습니다.
그렇다면 view의 html 파일을 매핑하면 안되겠네요.. 반대로 이 return 값을 데이터 값을 받아야할 필요가 있습니다. 서블릿처럼 말입니다.
return 값을 null이나 문자가 없는 String을 리턴하고 파라미터로 받은 HttpServletResponse의 getWriter 함수를 사용하는 건 어떨까요? 가능합니다.
그런데 그렇게 사용하게 되면 Spring framework에서 servlet 문법을 사용하는 느낌이 드네요.
좀 더 Spring처럼 사용하는 방법을 소개하겠습니다.
이전에 제가 Spring 환경 설정할 때, mvc-config.xml로 설정한다고 설명한 적이 있습니다.
link - [Java] 39. Spring web framework를 이용해서 웹 서비스 프로젝트를 만드는 법
여기서 ajax를 위한 설정을 추가하도록 합시다.
먼저 mvc-ajax-config.xml를 추가합니다.
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/mvc
http://www.springframework.org/schema/mvc/spring-mvc.xsd
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd">
<!-- 컨트럴러 패키지 설정 -->
<context:component-scan base-package="controller.ajax" />
<!-- 웹 브라우저로 응답하는 데이터 타입 UTF-8 타입-->
<mvc:annotation-driven>
<mvc:message-converters>
<bean class="org.springframework.http.converter.StringHttpMessageConverter">
<property name="supportedMediaTypes">
<list>
<!-- json타입으로 반환하기 때문에 설정 -->
<value>application/json;charset=UTF-8</value>
</list>
</property>
</bean>
</mvc:message-converters>
</mvc:annotation-driven>
<!-- view 폴더 설정 -->
<!-- ajax의 경우는 view 파일이 필요가 없기 때문에 값을 비운다 -->
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix" value="" />
<property name="suffix" value="" />
</bean>
</beans>
위 xml를 web.xml에 연결하도록 하겠습니다.
<servlet>
<servlet-name>dispatcherServletAjax</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/mvc-ajax-config.xml</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>dispatcherServletAjax</servlet-name>
<url-pattern>*.json</url-pattern>
</servlet-mapping>
여기서 이전의 컨트럴러 패키지는 controller 였습니다만 ajax 컨트럴러 패키지는 controller.ajax입니다.
controller.ajax 패키지 안에 클래스를 생성합니다.
package controller.ajax;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;
// 컨트롤 표시하는 어트리뷰트
@Controller
public class Test {
// 클래스에서 분류된 아래의 주소를 탐색한다.
// 이 예제에서는 /test.json의 GET방식으로 호출된다.
@RequestMapping(value = "test.json", method = RequestMethod.GET)
// @ResponseBody를 사용하면 view 파일을 탐색하는 것이 아니고 return 되는 값이 반환한다.
@ResponseBody
// 이 매핑 함수는 view와 매핑되는 것이 아니기 때문에 ModelMap은 필요없다.
public String index(HttpSession session, HttpServletRequest req, HttpServletResponse res) {
// json 타입의 String 문자를 리턴한다.
return "{\"data\":\"hello world\"}";
}
}
여기서 중요한 부분은 @ResponseBody 어트리뷰트입니다. @ResponseBody를 설정하면 view를 탐색하지 않고 return 값을 바로 응답합니다.
그럼 이전의 index.jsp를 조금 수정해서 확인해 보겠습니다.
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>
<!-- controller에서 ModelMap으로 표시되는 데이터 -->
${Data}
<!-- ajax의 값을 담을 div 태그 -->
<div id="result"></div>
<script>
// 브라우저 로딩이 끝나면 발생하는 이벤트
window.onload = function() {
// 비동기 XMLHttpRequest 객체 생성
var xhr = new XMLHttpRequest();
// 상태가 변할 때의 이벤트
xhr.onreadystatechange = function() {
// 수신이 완료가 되면
if (xhr.readyState === XMLHttpRequest.DONE && xhr.status === 200) {
// 결과를 String에서 javascript 구조체로 변환
var result = JSON.parse(xhr.response);
// result 태그에 표시
document.querySelector("#result").innerHTML = result.data;
}
}
// url 설정 GET방식으로 비동기(async)로 처리한다.
xhr.open("GET", "test.json", true);
// 송신
xhr.send();
}
</script>
</body>
</html>
위 결과를 보시면 test.json으로 요청을 하게 되면 브라우저에서 json 데이터를 수신하여 처리한 결과가 브라우저에 표시가 되네요.
우리가 비동기 ajax를 꼭 json 타입으로 받지는 않습니다. xml 타입으로도 받을 수 있고 byte데이터나 base64 타입으로도 받을 수 있습니다.
그러나 위 설정에서 mvc-ajax-config.xml에서 application/json으로 설정을 해버렸네요.
그럼 xml에서 설정하면 context-type을 변경할 수 없을까?
기본적으로 우리는 호출 함수에서 반환 값은 String으로 설정했습니다.
String이 아닌 byte[]형식으로 반환할 수도 있고 context-type에 따른 json 타입이 아닌 octet-stream타입이나 xml타입으로도 반환할 수 있습니다.
이러한 설정을 ResponseEntity 클래스를 반환해서 반환 데이터를 설정할 수 있습니다.
package controller.ajax;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;
// 컨트롤 표시하는 어트리뷰트
@Controller
public class Test {
// 클래스에서 분류된 아래의 주소를 탐색한다.
// 이 예제에서는 /test.json의 GET방식으로 호출된다.
// 호출하는 produces의 구분으로 호출 함수를 구분한다.
@RequestMapping(value = "test.json", method = RequestMethod.GET, produces = {"application/JSON"})
// @ResponseBody를 사용하면 view 파일을 탐색하는 것이 아니고 return 되는 값이 반환한다.
@ResponseBody
public String index(HttpSession session, HttpServletRequest req, HttpServletResponse res) {
// json 타입의 String 문자를 리턴한다.
return "{\"data\":\"hello world\"}";
}
// 클래스에서 분류된 아래의 주소를 탐색한다.
// 이 예제에서는 /test.json의 GET방식으로 호출된다.
// 호출하는 produces의 구분으로 호출 함수를 구분한다.
@RequestMapping(value = "test.json", method = RequestMethod.GET, consumes = {"application/XML"})
// @ResponseBody를 사용하면 view 파일을 탐색하는 것이 아니고 return 되는 값이 반환한다.
@ResponseBody
public ResponseEntity<String> index1(HttpSession session, HttpServletRequest req, HttpServletResponse res) {
// 응답 해더를 설정하기 위한 인스턴스 생성
HttpHeaders header = new HttpHeaders();
// ContentType을 application/XML로 설정
header.setContentType(MediaType.APPLICATION_XML);
// ResponseEntity 클래스로 리턴한다.
return new ResponseEntity<String>("<?xml version=\"1.0\" encoding=\"UTF-8\"?><data>xml</data>", header, HttpStatus.OK);
}
}
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>
<!-- controller에서 ModelMap으로 표시되는 데이터 -->
${Data}
<!-- ajax의 값을 담을 div 태그 -->
<div id="result"></div>
<!-- xml의 값을 담을 div 태그 -->
<div id="result1"></div>
<script>
// ajax를 보내기 위한 함수
function ajax(obj) {
// 비동기 XMLHttpRequest 객체 생성
let xhr = new XMLHttpRequest();
// 상태가 변할 때의 이벤트
xhr.onreadystatechange = function() {
if (xhr.readyState === XMLHttpRequest.DONE && xhr.status === 200) {
// callback 함수 호출
obj.done.call(this, xhr);
}
}
// url 설정 GET방식으로 비동기(async)로 처리한다.
xhr.open("GET", obj.url, true);
// 요청 Content-Type설정
xhr.setRequestHeader("Content-Type", obj.type);
// 송신
xhr.send();
}
// 브라우저 로딩이 끝나면 발생하는 이벤트
window.onload = function() {
// ajax 함수 호출
ajax({
url : "test.json", // url
type : "application/json", // contentType 설정
done : function(res) { // 요청이 완료되면
// 결과를 String에서 javascript 구조체로 변환
let result = JSON.parse(res.response);
// result 태그에 표시
document.querySelector("#result").innerHTML = result.data;
}
});
// ajax 함수 호출
ajax({
url : "test.json", // url
type : "application/xml", // contentType 설정
done : function(res) {
// 결과를 xml 구조체로 변환
let result = res.responseXML;
// result 태그에 표시
document.querySelector("#result1").innerHTML = result.getElementsByTagName("data")[0].nodeName;
}
});
}
</script>
</body>
</html>
결과는 두번의 test.json을 호출했습니다.
그 중 하나는 application/xml로 요청을 했고, 응답도 application/xml로 왔습니다. 당연히 결과도 xml로 왔기 때문에 화면에 data 결과가 표시되었습니다.
여기까지 Web Spring framework의 Controller에서 ajax의 요청시 json을 반환하는 방법에 대한 글이었습니다.
궁금한 점이나 잘못된 점이 있으면 댓글 부탁드립니다.
'Study > Java' 카테고리의 다른 글
[Java] 45. JPA 설정하는 방법 (0) | 2021.06.11 |
---|---|
[Java] 44. Web Spring framework의 view에서 사용하는 언어(JSTL) - XML (0) | 2021.06.10 |
[Java] 43. Web Spring framework의 view에서 사용하는 언어(JSTL) - 함수, 데이터베이스 (0) | 2021.06.09 |
[Java] 42. Web Spring framework의 view에서 사용하는 언어(JSTL) - 코어, 포멧팅 (0) | 2021.06.07 |
[Java] 40. Web Spring framework에서 Controller를 다루는 방법 (0) | 2021.06.03 |
[Java] 39. Spring web framework를 이용해서 웹 서비스 프로젝트를 만드는 법 (0) | 2021.06.02 |
[Java] 38. Java에서 웹 서비스 프로젝트(JSP Servlet)를 작성하는 방법 (0) | 2021.05.31 |
[Java] 37. 이클립스(eclipse)에서 톰켓을 설정하는 방법 (0) | 2020.06.18 |