์ด๋ณด ๊ฐ๋ฐ์๋ค์ ์ํ AJAX์ ๋ํ ์ ๋ฆฌ
๋ณธ ๊ธ์ https://github.com/kdevkr/spring-demo-ajax ์์ ์ ๊ณตํ๋ ์ ๋ณด์ ๋๋ค.
๋ค์ด๊ฐ๋ฉฐ
์น ์๋น์ค๋ฅผ ๋ง๋ค ๋ ์์ฃผ ์ฌ์ฉ๋๋ ๋น๋๊ธฐ ํต์ ๊ธฐ์ ์ธ AJAX๋ฅผ ์คํ๋ง ํ๋ ์์ํฌ์ ์ฐ๊ณํ์ฌ ํ์ฉํ๋ ๋ค์ํ ๋ฐฉ์์ ๋ํด์ ์์๋ณด๊ณ ์ ํฉ๋๋ค.
XHR(XMLHttpRequest)๋ฅผ ์ง์ ์ ์ผ๋ก ์ด์ฉํ๋ ๊ฒ๋ณด๋ค๋ JQuery์์ ์ง์ํ๋ AJAX(Asynchronos Javascript And XML)๊ธฐ๋ฅ์ ํ์ฉํ๋๋ก ํ๋ ๊ฒ์ด ๋์ ๊ฒ ๊ฐ๋ค๋ ์๊ฐ์ ๋๋ค.
JQuery ์ด์ธ์๋ ajax๋ฅผ ์ง์ํ๋ ๋ค์ํ ๋ผ์ด๋ธ๋ฌ๋ฆฌ๊ฐ ์กด์ฌํฉ๋๋ค. ์๋ฅผ ๋ค์ด, Prototypejs๋ ๋ง์ด ์ฌ์ฉ๋๋ ์ ํธ์ฑ ๋ผ์ด๋ธ๋ฌ๋ฆฌ ์ค ํ๋์ ๋๋ค. ๊ทธ๋ฌ๋ ์ ์ ๊ฐ์ ์ด๋ณด์ ๋ฐ ์ ์ ๊ฐ๋ฐ์๋ค์ JQuery์ ์ต์ํ๋ฏ๋ก JQuery๊ฐ ์ง์ํ๋ Ajax ๊ธฐ๋ฅ์ ๋ํด์ ์ดํด๋ณด๊ณ ์ ํฉ๋๋ค.
Vue.js์์๋ axios๋ฅผ ์ ํธํ๋ค๊ณ ํฉ๋๋ค.
JQuery.ajax
์ ์ด์ฟผ๋ฆฌ์์ ์ ๊ณตํ๋ ํจ์๋ ๋ค์๊ณผ ๊ฐ์ ๊ตฌ์กฐ๋ก ๊ตฌ์ฑ๋์ด ์์ต๋๋ค. ๋ฌผ๋ก ์ด์ธ์๋ ์๋ต๋ ๋ค์ํ ํ๋กํผํฐ๋ค์ด ์กด์ฌํ๋ฏ๋ก ๋ ์ฐพ์๋ณด์๋ฉด ์ข์ ๊ฒ ๊ฐ์ต๋๋ค. ์๋์ ํํ๋ ์๋ง๋ ์์ฃผ ์ฌ์ฉ๋๋ ํ๋กํผํฐ๋ง ๋ชจ์๋์ ๋ถ๋ถ์ด๋ผ๊ณ ํ ์ ์์ต๋๋ค.
$.ajax({
type : "GET", //์์ฒญ ๋ฉ์๋ ํ์
url : "url", //์์ฒญ ๊ฒฝ๋ก
async : true, //๋น๋๊ธฐ ์ฌ๋ถ
data : {key : value}, //์์ฒญ ์ ํฌํจ๋์ด์ง ๋ฐ์ดํฐ
processData : true, //๋ฐ์ดํฐ๋ฅผ ์ปจํ
ํธ ํ์
์ ๋ง๊ฒ ๋ณํ ์ฌ๋ถ
cache : true, //์บ์ ์ฌ๋ถ
contentType : "application/json", //์์ฒญ ์ปจํ
ํธ ํ์
"application/x-www-form-urlencoded; charset=UTF-8"
dataType : "json", //์๋ต ๋ฐ์ดํฐ ํ์ ๋ช
์ํ์ง ์์ ๊ฒฝ์ฐ ์๋์ผ๋ก ์ถ์ธก
beforeSend : function(){
// XHR Header๋ฅผ ํฌํจํด์ HTTP Request๋ฅผ ํ๊ธฐ์ ์ ํธ์ถ๋ฉ๋๋ค.
},
success : function(data, status, xhr){
// ์ ์์ ์ผ๋ก ์๋ต ๋ฐ์์ ๊ฒฝ์ฐ์๋ success ์ฝ๋ฐฑ์ด ํธ์ถ๋๊ฒ ๋ฉ๋๋ค.
// ์ด ์ฝ๋ฐฑ ํจ์์ ํ๋ผ๋ฏธํฐ์์๋ ์๋ต ๋ฐ๋, ์๋ต ์ฝ๋ ๊ทธ๋ฆฌ๊ณ XHR ํค๋๋ฅผ ํ์ธํ ์ ์์ต๋๋ค.
},
error : function(xhr, status, error){
// ์๋ต์ ๋ฐ์ง ๋ชปํ์๋ค๊ฑฐ๋ ์ ์์ ์ธ ์๋ต์ด์ง๋ง ๋ฐ์ดํฐ ํ์์ ํ์ธํ ์ ์๊ธฐ ๋๋ฌธ์ error ์ฝ๋ฐฑ์ด ํธ์ถ๋ ์ ์์ต๋๋ค.
// ์๋ฅผ ๋ค์ด, dataType์ ์ง์ ํด์ ์๋ต ๋ฐ์ ๋ฐ์ดํฐ ํ์์ ์ง์ ํ์์ง๋ง, ์๋ฒ์์๋ ๋ค๋ฅธ ๋ฐ์ดํฐํ์์ผ๋ก ์๋ตํ๋ฉด error ์ฝ๋ฐฑ์ด ํธ์ถ๋๊ฒ ๋ฉ๋๋ค.
},
complete : function(xhr, status){
// success์ error ์ฝ๋ฐฑ์ด ํธ์ถ๋ ํ์ ๋ฐ๋์ ํธ์ถ๋ฉ๋๋ค.
// try - catch - finally์ finally ๊ตฌ๋ฌธ๊ณผ ๋์ผํฉ๋๋ค.
}
});
์ฌ๊ธฐ์ ์ ๊น! GET๊ณผ POST์ ์ฐจ์ด๋ ๋ฌด์์ธ์ง ์์๋์?
๋ฐ๋ก ๋ฐ์ดํฐ๊ฐ ์ด๋์ ์์นํ๋๊ฐ์ ์์ต๋๋ค. POST ์์ฒญ์์ URL์ ํ๋ผ๋ฏธํฐ๊ฐ ๋ณด์ด์ง ์๋ ์ด์ ๋ ๋ฐ์ดํฐ๊ฐ ์์ฒญ ๋ฐ๋์ ํฌํจ๋๊ธฐ ๋๋ฌธ์ ๋๋ค. ๊ทธ๋ ๊ธฐ ๋๋ฌธ์ GET๊ณผ POST์ ๋ฐ๋ผ ๋ฐ์ดํฐ๋ฅผ URL์ ์ถ๊ฐํด์ผํ ์ง ์์ฒญ ๋ฐ๋์ ์ถ๊ฐํด์ผํ ์ง๋ฅผ ์๊ณ ์์ด์ผ๋ง ํฉ๋๋ค.
์๋ฅผ ๋ค์ด, processData๋ผ๋ ์์ฑ์ GET ์์ฒญ์ธ๋ฐ data์ ์ค๋ธ์ ํธ๊ฐ ์ง์ ๋ ๊ฒฝ์ฐ์ ์์ฒญํ๊ธฐ์ ์ ๊ทธ ๋ฐ์ดํฐ๋ฅผ ํ๋ผ๋ฏธํฐ ํ์์ผ๋ก URL์ ์ถ๊ฐํด์ฃผ๋ ์ญํ ์ ํ๊ฒ ๋ฉ๋๋ค.
์ด์ธ์๋ JQuery์์๋ ๋ค์ํ ajax ๊ธฐ๋ฅ์ ์ ๊ณตํ๊ณ ์์ต๋๋ค. ๋ง์ฝ, ์คํ๋ง ์ํ๋ฆฌํฐ๋ฅผ ์ ์ฉํด์ HTTP ํต์ ์์ CSRF ํ ํฐ์ด ํ์ํ๋ค๋ฉด ๋ค์๊ณผ ๊ฐ์ด XHR Header์ CSRF ํ ํฐ์ ์ถ๊ฐํด์ ๋ณด๋ผ ์ ์์ต๋๋ค.
// ์คํ๋ง ์ํ๋ฆฌํฐ ํ๊ทธ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ก ๋ฉํ ํ๊ทธ์ ํ ํฐ ์ ๋ณด๋ฅผ ์ ์ฉํ๋ค๋ ๊ฐ์ ์
๋๋ค.
var token = $("meta[name='_csrf']").attr("content");
var header = $("meta[name='_csrf_header']").attr("content");
$.ajaxSetup({
beforeSend: function(xhr) {
xhr.setRequestHeader(header, token);
}
});
JQuery.ajax์ ๋ํด์๋ ์ด ์ ๋๊น์ง๋ง ์์๋ ๋ฉ๋๋ค.
Spring Controller
์คํ๋ง ํ๋ ์์ํฌ์์๋ ajax ํต์ ์ ์ํด์ ์คํ๋ง @MVC๋ก ๋ค์ํ ์ด๋ ธํ ์ด์ ์ ์ง์ํฉ๋๋ค. ๋ค์ํ ์ด๋ ธํ ์ด์ ์ ํ์ธํ๋ฉด์ ๊ตฌ์กฐ๋ฅผ ์ตํ๋ณด๋๋ก ํ๊ฒ ์ต๋๋ค. ์คํ๋ง ์ ํ๋ฆฌ์ผ์ด์ ์ ๊ธฐ๋ณธ์ ์ผ๋ก ๋ทฐ ๋ฆฌ์กธ๋ฒ๋ฅผ ํตํด์ ์์ฒญ์ ๋ํ ์๋ต์ ํ๊ฒ ๋ฉ๋๋ค. ์ผ๋ฐ์ ์ธ HTTP ์์ฒญ์ ๊ฒฝ์ฐ์๋ JstlView๋ก์จ ์๋ต์ ํ๊ฒ ๋์ง๋ง, XHR ์์ฒญ์ ์ํด์ ๋ค์ํ ๋ฐ์ดํฐ ํ์์ผ๋ก ์๋ตํ๊ธฐ ์ํ ๋ฉ์์ง ์ปจ๋ฒํฐ๋ผ๋ ๊ฒ์ ์ง์ํฉ๋๋ค.
Message Converter List
- StringHttpMessageConverter
- FormHttpMessageConverter
- ByteArrayMessageConverter
- MarshallingHttpMessageConverter
- MappingJacksonHttpMessageConverter
- MappingJackson2HttpMessageConverter
- SourceHttpMessageConverter
- BufferedImagedHttpMessageConverter
์คํ๋ง์
์ ๋ง์ ์ญํ ์ ํด์ฃผ๋๋ฐ, ๊ทธ ์ค ํ๋๊ฐ ๋ํดํธ ๋ฉ์์ง ์ปจ๋ฒํฐ๋ฅผ ๋ฑ๋กํด์ค๋๋ค. ๋ค๋ง, MappingJacksonHttpMessageConverter๋ jackson ๋ผ์ด๋ธ๋ฌ๋ฆฌ๊ฐ ์กด์ฌํ ๋๋ง ๋ฑ๋กํฉ๋๋ค.
์ฐ๋ฆฌ๊ฐ AJAX๋ฅผ ์ด์ฉํ ๋ ๋ฐ์ดํฐ ํ์์ JSON์ผ๋ก ๋ง์ด ์ฌ์ฉํฉ๋๋ค. ๋ฐ๋ผ์, List, Map๋ฑ๊ณผ ๊ฐ์ ์ค๋ธ์ ํธ๋ค์ JSON ํํ๋ก ์๋ตํ๊ณ ์ถ๋ค๋ฉด, ModelAndView๋ฅผ ์ด์ฉํ๊ฑฐ๋ ๋ฉ์์ง์ปจ๋ฒํฐ๋ฅผ ๋ฑ๋กํด์ผํฉ๋๋ค.
๋ณธ ๋ฌธ์์์๋ ModelAndView๋ก์จ ์๋ตํ๋ ๋ฐฉ์์ ์ค๋ช ํ์ง ์๊ฒ ์ต๋๋ค. ์ฌ๊ธฐ์ ํ์ธํ๋๋ก ํฉ์๋ค
๊ทธ๋ฌ๋ ์คํ๋ง 3 ์ด์ ๋ถํฐ๋ jackson ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ฅผ ์์กด์ฑ์ผ๋ก ์ถ๊ฐํ ๊ฒฝ์ฐ์ ์๋์ ์ผ๋ก MappingJacksonHttpMessageConverter๋ฅผ ์ ์ฉํด์ค๋๋ค.
์ฌ๊ธฐ์ ์ ๊น!
์คํ๋ง 3.1.2 ๋ถํฐ๋ jackson 2.0์ ์ง์ํ๋๋ก ์ถ๊ฐ๋์์ต๋๋ค. jackson 2.0์ MappingJackson2HttpMessageConverter๋ก ๋ฑ๋ก๋ฉ๋๋ค.
์์ธํ ์ฌํญ์ ์คํ๋ง ๋ฒ์ ๋ณ jackson ๋ผ์ด๋ธ๋ฌ๋ฆฌ ๋ฒ์ ํญ๋ชฉ์์ ํ์ธํ์๊ธฐ ๋ฐ๋๋๋ค.
์คํ๋ง ๋ถํธ์์๋ ์ด๋ฌํ ๋ถ๋ถ๋ ๊ด๋ฆฌํด์ฃผ๋ฏ๋ก ์ถ๊ฐ์ ์ผ๋ก jackson ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ฅผ pom.xml์ ์ถ๊ฐํ ํ์๊ฐ ์์ต๋๋ค.
์คํ๋ง ๋ฒ์ ๋ณ ์ฌ์ฉ๋๋ Jackson Library
์คํ๋ง 3.0 ์ด์๋ถํฐ๋ jackson ๊ด๋ จ ๋ผ์ด๋ธ๋ฌ๋ฆฌ์ ๋ฐ๋ผ ๋ฉ์์ง ์ปจ๋ฒํฐ๋ฅผ ๋ฑ๋กํด์ค๋๋ค.
Spring 3.0.x
<dependency>
<groupId>org.codehaus.jackson</groupId>
<artifactId>jackson-mapper-asl</artifactId>
<version>${org.codehaus.jackson}</version>
</dependency>
Spring 3.1.2
MappingJackson2HttpMessageConverter๋ก jackson 2.0์ ์ง์ํฉ๋๋ค
<dependency>
<groupId>org.codehaus.jackson</groupId>
<artifactId>jackson-mapper-asl</artifactId>
<version>${org.codehaus.jackson}</version>
</dependency>
<!-- Jackson 2.0 -->
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-core</artifactId>
<version>${com.fasterxml.jackson}</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>${com.fasterxml.jackson}</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-annotations</artifactId>
<version>${com.fasterxml.jackson}</version>
</dependency>
Spring 4.0.0
GsonHttpMessageConverter ์ง์
MappingJacksonHttpMessageConverter ๋ฏธ์ง์
<!-- Jackson 2.0 -->
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-core</artifactId>
<version>${com.fasterxml.jackson}</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>${com.fasterxml.jackson}</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-annotations</artifactId>
<version>${com.fasterxml.jackson}</version>
</dependency>
<!-- gson -->
<dependency>
<groupId>com.google.code.gson</groupId>
<artifactId>gson</artifactId>
<version>2.3.1</version>
</dependency>
https://github.com/spring-projects/spring-framework/wiki/Migrating-to-Spring-Framework-4.x#jackson-1819
์ ๋ฌธ์์ ๋ฐ๋ฅด๋ฉด ์คํ๋ง 4.1 ๋ถํฐ๋ org.codehaus.jackson(1.8 or 1.9)์ ์ง์์ ์ค๋จํ์์ต๋๋ค.
- ๋ฒ์ ๋ณ ๋ฉ์์ง ์ปจ๋ฒํฐ ์ง์ํ
Spring Version | org.codehaus.jackson(1.8 or 1.9) | com.fasterxml.jackson(2.0) | gson |
---|---|---|---|
3.0.x | MappingJacksonHttpMessageConverter | ||
3.1.2 | MappingJacksonHttpMessageConverter | MappingJackson2HttpMessageConverter | |
4.+ | MappingJackson2HttpMessageConverter | GsonHttpMessageConverter |
Annotations
๊ทธ๋ผ ์ด์ ์คํ๋ง ์ปจํธ๋กค๋ฌ์์ ์ฌ์ฉ๋๋ ์ด๋ ธํ ์ด์ ๋ค์ ์์๋ณด๊ฒ ์ต๋๋ค.
@RequestMapping
@RequestMapping์๋ ์์ฒญ๊ณผ ์๋ต๊ณผ ๊ด๋ จํ ํ๋กํผํฐ๋ฅผ ์ค์ ํ ์ ์์ต๋๋ค. produces์ consumes๋ ํ์คํ ์๊ณ ๋์ด๊ฐ์ ์ผ ํฉ๋๋ค.
- method=RequestMethod.GET
method๋ ์ด๋ ํ ์์ฒญ ํ์ ์ ์ฒ๋ฆฌํ ๊ฒ์ธ๊ฐ๋ฅผ ๊ฒฐ์ ํ๋ ๋ถ๋ถ์ ๋๋ค. - produces=MediaType.APPLICATION_JSON_VALUE
produces๋ ์ด๋ ํ ๋ฐ์ดํฐ ํ์์ผ๋ก ์๋ตํ ๊ฒ์ธ๊ฐ๋ฅผ ๊ฒฐ์ ํ๋ ๋ถ๋ถ์ ๋๋ค. - consumes=MediaType.APPLICATION_JSON_VALUE
consumes๋ ์ด๋ ํ ์์ฒญ์ ๋ํด์ ์ฒ๋ฆฌํ ๊ฒ์ธ๊ฐ๋ฅผ ๊ฒฐ์ ํ๋ ๋ถ๋ถ์ ๋๋ค.
produces์ consumes ํ๋กํผํฐ๋ Spring 3.1์์ ๋ถํฐ ์ง์ํฉ๋๋ค.
@ModelAttribute, @ReqeustParam
์ด ๋๊ฐ์ ์ด๋ ธํ ์ด์ ์ GET๊ณผ DELETE ์์ฒญ์์ ํ์ฉํ ์ ์์ต๋๋ค. ๊ทธ ์ด์ ๋ ํ๋ผ๋ฏธํฐ ๊ฐ์ ํ์ธํด์ ๋ฐ์ดํฐ๋ฅผ ๋ฐ์ธ๋ฉํด์ฃผ๊ธฐ ๋๋ฌธ์ ๋๋ค. @RequestParam์ request.getParameter()๋ก์จ ๊ฐ์ ธ์ค๋ ๋ฐ๋ฉด์ @ModelAttribute๋ ์๋ฐ ํด๋์ค์ Getter, Setter์ ์ํด ๋ฐ์ดํฐ๋ฅผ ๋ฐ์ธ๋ฉ์ํค๋ ๊ฒ์ ๋๋ค. ๊ทธ๋ ๊ธฐ ๋๋ฌธ์ ๋ง์ฝ ๊ฐ์ฒด ๋จ์๋ก ๋ฐ์ธ๋ฉํ๊ณ ์ถ๋ค๋ฉด @ModelAttribute๋ฅผ ์ด์ฉํด์ผ ํ๋ค๋ ๊ฒ์ ๋๋ค.
์ง์ ํ์ธํ๊ณ ์ถ์ผ์๋ค๋ฉด ๋ณธ ํ๋ก์ ํธ๋ฅผ ๋์์์ผ ajaxList์ ajaxListModel์ ์ฐจ์ด๋ฅผ ํ์ธํ์๊ธฐ ๋ฐ๋๋๋ค.
@RequestBody
์ด ์ด๋ ธํ ์ด์ ์ POST์ PUT ์ฒ๋ผ ๋ฐ์ดํฐ๊ฐ HTTP ์์ฒญ ๋ฐ๋์ ํฌํจ๋๋ ๊ฒฝ์ฐ์ ์ด๋ฅผ ํ์ธํด์ ๋ฐ์ดํฐ๋ฅผ ๋ฐ์ธ๋ฉ ํด์ค๋๋ค. ์ด ์ด๋ ธํ ์ด์ ์ ์ค์ํ ๋ถ๋ถ์ GET ์์ฒญ๊ณผ ๊ฐ์ด ํ๋ผ๋ฏธํฐ๋ฅผ ํตํด ์ ๊ณต๋๋ ๋ฐ์ดํฐ๋ ๋ฐ์ธ๋ฉํ ์ ์๋ค๋ ์ ์ ๋๋ค.
์ง์ ํ์ธํ๊ณ ์ถ์ผ์๋ค๋ฉด ๋ณธ ํ๋ก์ ํธ๋ฅผ ๋์์์ผ ajaxMap์ ajaxMapGet์ ์ฐจ์ด๋ฅผ ํ์ธํ์๊ธฐ ๋ฐ๋๋๋ค. ajaxMapGet์ ์์ฒญ์ด ์ ์คํจํ๋์ง์ ๋ํด์ ์๋ฒ์ธก ๋ก๊ทธ๋ฅผ ์ดํด๋ณด์๊ธฐ ๋ฐ๋๋๋ค.
@ResponseBody
์ด ์ด๋ ธํ ์ด์ ์ ์๋ต๋๋ ๋ฐ์ดํฐ์ ๋ํ์ฌ ๋ฑ๋ก๋ ๋ฉ์์ง ์ปจ๋ฒํฐ๋ฅผ ํตํด ๋ณํ์์ผ ์๋ตํ๊ฒ ๋ฉ๋๋ค. ๋ฐ๋ผ์, ๋ทฐ์ ๋ชจ๋ธ๋ก์ ๋ฐ์ดํฐ๋ฅผ ์ถ๊ฐ์์ผ ์๋ตํ๋ ๊ฒ์ด ์๋๋ผ ๋ฐ์ดํฐ๋ฅผ HTTP ๋ณธ๋ฌธ์ผ๋ก ์๋ตํ๊ฒ ๋๋ค๋ ๊ฒ์ ๋๋ค.
ajaxList์ ajaxListNobody๋ฅผ ํตํด์ @ResponseBody๊ฐ ์์ ๊ฒฝ์ฐ๋ ์์ ๊ฒฝ์ฐ๋ฅผ ๋น๊ตํด๋ณด์ธ์. ์ @ResponseBody๊ฐ ์์ ๋ ViewResolver๋ฅผ ์ฐพ๋ ๊ฒ ๊ฐ๋์?
@RestController
์ด ์ด๋ ธํ ์ด์ ์ ์คํ๋ง 4 ๋ถํฐ ์ง์ํฉ๋๋ค. ํด๋น ์ปจํธ๋กค๋ฌ์ ๋ฉ์๋๋ค์ @ResponseBody ์ด๋ ธํ ์ด์ ์ ์ ์ฉํฉ๋๋ค. ์ข ๋ ํธ์์ฑ์ ์ ๊ณตํ๋ค๊ณ ๋ณด์๋ฉด ๋ฉ๋๋ค.
Test Case
๋ณธ ํ๋ก์ ํธ์์ ํ์ฌ ์งํํ ํ ์คํธ ์ผ์ด์ค๋ ๋ค์๊ณผ ๊ฐ์ต๋๋ค.
1. GET, @ResponseBody์ @ModelAttribute, @RequestParm์ ํ์ธํ ์ ์๋ ์ผ์ด์ค
2. GET, 1๋ฒ๊ณผ ๋์ผํ๋ @ModelAttribute๋ฅผ ํตํด์ ๊ฐ์ฒด ๋จ์๋ก ๋ฐ์ธ๋ฉํ๋ ๊ฒ์ ํ์ธํ ์ ์๋ ์ผ์ด์ค
3. GET, 1๋ฒ๊ณผ ๋์ผํ๋ @ResponseBody๋ฅผ ์ง์ ํ์ง ์์์ ๊ฒฝ์ฐ๋ฅผ ํ์ธํ ์ ์๋ ์ผ์ด์ค
4. PUT, @ResponseBody์ @RequestBody๋ฅผ ์ง์ ํ์ ๊ฒฝ์ฐ๋ฅผ ํ์ธํ ์ ์๋ ์ผ์ด์ค
5. GET, 4๋ฒ๊ณผ ๋์ผํ๋ GET ์์ฒญ์ @RequestBody๋ฅผ ์ง์ ํ์ ๊ฒฝ์ฐ๋ฅผ ํ์ธํ ์ ์๋ ์ผ์ด์ค
6. POST, ResponseEntity๋ฅผ ํตํด์ HttpStatus๋ ์ง์ ํ ์ ์๋ ๊ฒ์ ํ์ธํ๋ ์ผ์ด์ค
7. POST, 6๋ฒ๊ณผ ๋์ผํ๋ @ResponseBody๋ฅผ ์ง์ ํ์ง ์์ ๊ฒฝ์ฐ๋ฅผ ํ์ธํ ์ ์๋ ์ผ์ด์ค
8. POST, 7๋ฒ๊ณผ ๋์ผํ๋ URL์ ํ๋ผ๋ฏธํฐ๋ฅผ ํจ๊ป ์์ฒญ์์ @RequestParam ์ง์์ฌ๋ถ๋ฅผ ํ์ธํ ์ ์๋ ์ผ์ด์ค
6๋ฒ๊ณผ 7๋ฒ์ ์์ํดํ์ค ์ ์์ผ์ค ๊ฒ๋๋ค. ์ด์ ๊ด๋ จ๋ ์ ๋ณด๋ ์ฌ๊ธฐ์์ ํ์ธํ์ค ์ ์์ต๋๋ค. ๊ฐ๋จํ ๋งํ๋ฉด ResponseEntity๋ ์๋ต ํค๋์ ๋ฐ๋๋ฅผ ๊ฐ์ง๋ ๊ฐ์ฒด๋ฅผ ์๋ตํ๋ ๊ฒ์ด๋ผ๊ณ ๋ณด๋ฉด ๋ฉ๋๋ค.
๋ง์ง๋ง์ผ๋ก ์ด๋ณด์๋ค์ด ์๋ชป ์ฌ์ฉํ๊ฑฐ๋ ์ ๊ทผํ๋ ๊ฒฝ์ฐ๋ฅผ ์์๋ด ์๋ค.
Okky์์ Ajax ๊ด๋ จ ์ง๋ฌธ์ด ์ฌ๋ผ์จ๋ค๋ฉด ์ง์์ ์ผ๋ก ์ถ๊ฐํ๋๋ก ํ๊ฒ ์ต๋๋ค.
1. ์ ๋ ์ ๋๋ก ๊ตฌํํ ๊ฒ ๊ฐ์๋ฐ ์๋ฌ๋ก ์๋ต๋ฐ์ต๋๋ค.
- dataType์ ์ง์ ํ ๋ค ๊ทธ ํ์์ผ๋ก ์๋ตํ์ง ์๋๋ค๋ฉด ์ ์์ ์ผ๋ก ์๋ตํด๋ ์๋ฌ ์ฝ๋ฐฑ์ด ํธ์ถ๋ ๊ฐ๋ฅ์ฑ์ด ์์ต๋๋ค. ์๋ฅผ ๋ค์ด, ์คํ๋ง ์ปจํธ๋กค๋ฌ์์๋ ๋ฌธ์์ด์ด๋ null์ ์๋ตํ๋๋ฐ ajax์์๋ json์ผ๋ก ์ง์ ํ ๊ฒฝ์ฐ์๋ ์๋ฒ์์๋ ์ ์์ ์ผ๋ก ์๋ต๋์ง๋ง ํด๋ผ์ด์ธํธ์์๋ ํด๋น ๋ฐ์ดํฐ๋ฅผ json์ผ๋ก ํ์ฑํ ์ ์๊ธฐ ๋๋ฌธ์ ์๋ฌ ์ฝ๋ฐฑ์ด ํธ์ถ๋ฉ๋๋ค.
๋๋ถ๋ถ์ Ajax ๊ด๋ จ ์ง๋ฌธ์ ์ฌ๊ธฐ์ ํด๋น๋๋ ๊ฒฝ์ฐ๊ฐ ๋ง์์ต๋๋ค. ๋จ์ํ error๊ฐ ๋๋ค๊ณ ํด์ ์ ์์ ์ผ๋ก ์๋ต๋ฐ์ง ๋ชปํ๋ค๊ณ ํ๋จํ๊ณ ๊ณ์ จ์ต๋๋ค. ์๋ฒ๋ html๋ฌธ์๋ฅผ ์๋ตํ๋๋ฐ ajax ๋ฐ์ดํฐ ํ์์ด json์ด๋ฉด ์ค๋ฅ๊ฐ ๋๋ค๋ ๊ฒ์ ๊ธฐ์ตํด์ฃผ์๊ธฐ ๋ฐ๋๋๋ค.
2. ๋ฐ์ดํฐ๋ฅผ ์๋ฒ์์ ๋ฐ์์ฌ ์ ์์ต๋๋ค.
- ์์ฒญ ๋ฉ์๋ ํ์ ์ด GET์ผ ๋ processData๋ฅผ false๋ก ์ง์ ํ ๊ฒฝ์ฐ์๋ ๋ฐ์ดํฐ๋ฅผ url์ ์ง์ ํฌํจ์์ผ์ค์ผ ํฉ๋๋ค. ๋ง์ฝ, POST๊ฐ์ ์์ฒญ์ ๊ฒฝ์ฐ์๋ ๋ฐ์ดํฐ๊ฐ ์์ฒญ ๋ฐ๋์ ํฌํจ๋์ด์ ธ์ผ ํ๋ค๋ ๊ฒ์ ์์ง ๋ง์๊ธฐ ๋ฐ๋๋๋ค.
POST์ ๊ฒฝ์ฐ์๋ url์ ํ๋ผ๋ฏธํฐ๊ฐ ํฌํจ๋๋ค๋ฉด @RequestParam ์ด๋ ธํ ์ด์ ์ ํตํด ๋ฐ์์ฌ ์ ์์ต๋๋ค.
3. GET ์์ฒญ์ ํตํด ๋ณด๋ด๋๋ฐ ์ผ์ ๋ฐ์ดํฐ ํฌ๊ธฐ์ด์ ๋ณด๋ด์ง์ง ์์ต๋๋ค.
- ๋ธ๋ผ์ฐ์ ๋ณ๋ก URL์ ์ง์ ํฌ๊ธฐ๊ฐ ๋ค๋ฆ ๋๋ค. ๊ทธ๋ ๊ธฐ ๋๋ฌธ์ POST๋ก ์์ฒญ ๋ฐ๋์ ๋ฐ์ดํฐ๋ฅผ ํฌํจ์์ผ ๋ณด๋ด๋ ์ด์ ๋ ๋ฐ๋ก ์ด ๋๋ฌธ์ ๋๋ค. ๋ฌผ๋ก ์๋ฒ ์ธก์์๋ ์์ฒญ ๋ฐ๋์ ๋ํ ํฌ๊ธฐ๋ฅผ ์ ํํ ์ ๋ ์์ต๋๋ค.
๋ง์ ์ ์ ๋ฉด์ ์์ GET๊ณผ POST์ ์ฐจ์ด๋ฅผ ๋ฌป๋ ์ด์ ์ด๊ธฐ๋ ํฉ๋๋ค. ๋จ์ํ ๋ณด์ ๋๋ฌธ์ ๊ตฌ๋ถํด์ ์ฌ์ฉํ๋ ๊ฒ์ ์๋๋ผ๋ ์ ์ ๋๋ค.
4. 406 - Not Acceptable ์๋ตํด์ ใ ใ [2017-02-14]
- ํน์ @ResponseBody๋ก List๋ Map์ ์๋ตํ๊ณ ๊ณ์ ๊ฐ์? ์๋ตํ๊ธฐ ์ํด์๋ annotation-driven ์ค์ ์ด ๋์ด์์ด์ผ ํ๊ณ ์์ฒญํ๋ ์๋ต ๋ฐ์ดํฐ๋ก ๋ณํํ ์ ์๋๋ก ๋ฉ์์ง ์ปจ๋ฒํฐ๊ฐ ํ์ํฉ๋๋ค.
์คํ๋ง ๋ฒ์ ์ ๋ฐ๋ผ์ ๋ค๋ฅด๊ฒ ์ง๋ง ์คํ๋ง 3 ๋ถํฐ๋ annotation-driven ์ค์ ์ ํ๊ณ jackson ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ฅด ์ถ๊ฐํ๋ค๋ฉด ๋ํดํธ ์ ๋ต์ผ๋ก ๋ฉ์์ง์ปจ๋ฒํฐ๊ฐ ๋ฑ๋ก๋ฉ๋๋ค.
5. MessageConverter๋ฅผ ์ด์ฉํ๊ณ ์ถ์ง ์์์ [2017-04-20]
- ๋ฉ์์ง ์ปจ๋ฒํฐ๋ฅผ ์ด์ฉํ์ง ์๊ณ ๋ JSON์ผ๋ก ์๋ตํ ์ ์๋ ๋ฐฉ๋ฒ์ด ์์ต๋๋ค. ๋ฐ๋ก ContentNegotiatingViewResolver๋ฅผ ์ด์ฉํ๋ฉด ๋ฉ๋๋ค. ํ์ฅ์๋ฅผ ์ด์ฉํ๋ ๋ฐฉ์์ ๋๋ค.
<beans:bean class="org.springframework.web.servlet.view.ContentNegotiatingViewResolver">
<!-- ViewResolver ์ฐ์ ์์ ์ค์ -->
<beans:property name="order" value="1" />
<beans:property name="mediaTypes">
<!-- ๋งตํ๋ ํ์ฅ์ ์ ์ -->
<beans:map>
<beans:entry key="json" value="application/json" />
</beans:map>
</beans:property>
<beans:property name="defaultViews">
<beans:list>
<!-- JSON ์์ฒญ์ ์ฒ๋ฆฌํ ๋ทฐ -->
<beans:bean class="org.springframework.web.servlet.view.json.MappingJacksonJsonView"/>
</beans:list>
</beans:property>
<beans:property name="ignoreAcceptHeader" value="true" />
</beans:bean>
@RequestMapping("/api/test.json")
public void api(final ModelMap map){
Message message = new Message("Message Bean");
map.put("response", message);
}
ModelMap์ ์ถ๊ฐํ์ฌ JSON ํํ๋ก ์ถ๋ ฅํ ์ ์๊ฒ ๋ฉ๋๋ค.
์ฐธ์กฐ : http://ismydream.tistory.com/139