본문 바로가기
  • 실행력이 모든걸 결정한다
Spring Series/Spring Framework

[Spring] 메시지 컨버터를 이용하는 Ajax 컨트롤러

by 김코더 김주역 2022. 9. 28.
반응형

1. 메시지 컨버터 소개

- 메시지 컨버터는 HTTP 요청/응답 메시지 본문 자체를 메시지로 다룬다.

- 메시지 컨버터는 AnnotationMethodHandlerAdapter를 통해 등록할 수 있다. 여러 개의 메시지 컨버터를 등록해두고 요청 타입이나 오브젝트 타입에 따라 선택되게 하는 것이 일반적이다.

 

 

 

2. 메시지 컨버터의 종류

1) 디폴트로 등록된 메시지 컨버터

(1) ByteArrayHttpMessageConverter

- byte[] 타입의 오브젝트를 지원한다.

- 미디어 타입은 모든 종류를 다 허용한다.

- @RequestBody로 전달받을 때는 모든 종류의 HTTP 요청 메시지 본문을 byte[] 타입으로 가져올 수 있고, @ResponseBody로 응답할 때는 application/octet-stream이라는 컨텐트 타입으로 전달된다.

 

(2) StringHttpMessageConverter

- String 타입의 오브젝트를 지원한다.

- 미디어 타입은 모든 종류를 다 허용한다.

- HTTP 요청의 본문을 그대로 String 타입으로 가져올 수 있고, 응답할 때는 text/plain이라는 컨텐트 타입으로 전달된다. 단순 문자열로 응답을 보낼 때는 @ResponseBody와 함께 String 타입으로 리턴해주면 된다.

 

(3) FormHttpMessageConverter

- MultiValueMap<K, V> 타입의 오브젝트를 지원한다. 이 타입은 Map<K,List<V>>을 상속받기 때문에, 하나의 이름을 가진 여러 파라미터가 존재할 수 있는 요청 파라미터를 처리할 수 있다.

- 컨텐트 타입이 application/x-www-form-urlencoded인 폼 데이터를 주고 받을 때 사용한다.

- 폼 정보를 받을 때 FormHttpMessageConverter보다는 @ModelAttribute를 사용하는 것이 나을 것 같다.

 

(4) SourceHttpMessageConverter

- javax.xml.transform.Source 타입인 DOMSource, SAXSource, StreamSource 타입의 오브젝트를 지원한다.

- 지원하는 컨텐트 타입은 application/xml, applitation/*+xml, text/xml이다.

- XML 문서를 Source 타입의 오브젝트로 전환할 때 사용된다.

 

 

2) 디폴트로 등록되지 않은 메시지 컨버터

- 필요시에 AnnotationMethodHandlerAdapter bean의 messageConverters 프로퍼티에 직접 등록해야 하는 메시지 컨버터들이다. 전략 프로퍼티를 직접 등록하면 디폴트 전략은 자동으로 추가되지 않기 때문에 모두 직접 추가해줘야 한다.

<bean class="org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter">
    <property name="messageConverters">
       <list>
           <bean class="org.springframework.http.converter.json.MappingJacksonHttpMessageConverter"/>
       </list>
    </property>
</bean>

- 커스텀 메시지 컨버터를 만들기 위해서는 HttpMessageConverter를 구현하면 된다.

 

(1) Jaxb2RootElementHttpMessageConverter

- JAXB2의 @XmlRootElement와 @XmlType이 붙은 클래스를 이용해서 XML과 자바 오브젝트 사이의 변환을 지원한다.

- 지원하는 컨텐트 타입은 기본적으로 application/xml, applitation/*+xml, text/xml이다.

- JAXB2의 스키마 컴파일러를 통해 생성된 바인딩용 클래스를 이용해서 손쉽게 XML과 자바 오브젝트 사이의 메시지 변환이 가능하다.

 

(2) MarshallingHttpMessageConverter

- Spring OXM 추상화의 Marshaller와 Unmarshaller를 이용해서 XML과 자바 오브젝트 사이의 변환을 지원한다. Marshaller은 오브젝트를 XML로 변환하는 기능을 추상화한 인터페이스고, Unmarshaller은 XML을 오브젝트로 변환해주는 기능을 추상화한 인터페이스다.

- OXM 기술을 자유롭게 선택해서 MarshallingHttpMessageConverter bean의 marshaller와 unmarshaller 프로퍼티에 넣어주면 된다.

- 지원하는 오브젝트는 unmarshaller의 support() 메소드를 호출해서 판단한다.

- 지원하는 컨텐트 타입은 기본적으로 application/xml, applitation/*+xml, text/xml이다.

 

(3) MappingJacksonHttpMessageConverter

- Jackson ObjectMapper을 이용해서 JSON과 자바 오브젝트 사이의 변환을 지원한다. 부가적인 변환 기능이 필요하다면 ObjectMapper를 확장해서 적용하면 된다.

- 오브젝트 타입에 제한은 없지만 자바빈 스타일이거나 HashMap을 이용해야 정확한 변환이 가능하다.

- 지원하는 컨텐트 타입은 application/json이다.

 

 

 

3. JSON 기반의 AJAX 컨트롤러

- MappingJacksonHttpMessageConverter를 AnnotationMethodHandlerAdapter bean의 messageConverters 프로퍼티에 등록해야 한다.

 

- JSON 오브젝트를 반환하는 컨트롤러를 만들기 위한 방법으로는 아래 두 가지가 있다. 아래의 방법을 사용하면 컨트롤러가 리턴하는 자바 오브젝트는 JSON 메시지로 변환된다.

  • JSON 지원 뷰 사용 : MappingJacksonJsonView를 이용한다. 다른 포맷의 뷰를 동시에 사용할 경우에는 .json 확장자를 자동인식하는 ContentNegotiatingViewResolver를 사용한다.
  • @ResponseBody 사용 : 컨트롤러 메소드에 @ResponseBody를 붙여준다. 항상 JSON 오브젝트로 반환하는 경우에 사용하기 편리한 방법이다.

※ Spring 4.0부터는 @RestController 어노테이션을 지원한다. 컨트롤러에 @Controller 대신에 @RestController 어노테이션을 붙이면 @Controller 역할도 수행하면서 모든 컨트롤러 메소드에 일괄적으로 @ResponseBody가 적용된다. 필자가 개인적으로 추천하는 방법이다.

 

- Ajax 컨트롤러에서 post 요청을 처리하는 메소드가 필요할 수도 있다. 대표적으로 폼 정보를 받는 경우다.

@RequestMapping(value="/register", method=RequestMethod.POST)
@ResponseBody
public User register(@RequestBody User user) {
    // user 검증과 등록
    return user;
}

메소드 파라미터에 @RequestBody를 붙여서 application/json 콘텐트 타입으로 전달되는 요청을 MappingJacksonHttpMessageConverter에 의해 자바 오브젝트로 변환되도록 하면 된다. 자바 오브젝트를 굳이 만들고 싶지 않다면 Map<String, Object> 타입으로 받아도 된다.

자바스크립트 코드에 의해 서버로 전송되는 HTTP 요청의 메시지 본문은 다음과 같이 JSON 형식으로 만들어져야 한다.

{"id":"jooyeok", "password":"1234", "name":"Kim Joo Yeok"}

그리고 실제 폼을 받아버리면 웹 페이지가 갱신되어버리기 때문에 ajax를 사용하는 의미가 없어진다. 그래서 아래 자바스크립트 코드와 같이 submit 이벤트 메소드에서 false를 반환하도록 해야한다. 폼의 id는 "user"라고 가정한다.

$('#user').submit(function() {
    // JSON 형식의 메시지 본문 생성
    // POST 요청
    // 요청 결과에 기반하여 웹 페이지에 안내 메시지 출력
    return false;
});

 

Javascript 예시 코드 (JQuery 사용)

더보기

// 메소드 참고 : https://cofs.tistory.com/m/184
jQuery.fn.serializeObject = function() {
    var obj = null;
    try {
        if (this[0].tagName && this[0].tagName.toUpperCase() == "FORM") {
            var arr = this.serializeArray();
            if (arr) {
                obj = {};
                jQuery.each(arr, function() {
                    obj[this.name] = this.value;
                });
            }
        }
    } catch (e) {
        alert(e.message);
    } finally {}

    return obj;
};

$('#answer-form').submit(function() {
    startTimeout();
    var serializedFormData = $('#answer-form').serializeObject();
    console.log(serializedFormData)
    $.ajax({
        url:"http://localhost:8080/test/grading",
        data: JSON.stringify(serializedFormData),
        type: "POST",
        dataType: "json",
        contentType : "application/json"
    })
    .done(function(json) {
        console.log(json);
    })
    .fail(function(xhr, status, errorThrown){
        alert("요청 실패");
    })
    return false;
});

 

 

● 참고 자료 : 토비의 스프링 3.1 Vol.2

 

반응형

댓글