Notice
Recent Posts
Recent Comments
Link
«   2024/11   »
1 2
3 4 5 6 7 8 9
10 11 12 13 14 15 16
17 18 19 20 21 22 23
24 25 26 27 28 29 30
Archives
Today
Total
관리 메뉴

hellokiseok

@ExceptionHandler 사용법 + Content-Type 별 처리 본문

Spring

@ExceptionHandler 사용법 + Content-Type 별 처리

hellokiseok 2013. 8. 14. 14:12
RESTful 서비스에서, 하나의 URI 에서 Content-Type 에 따라 다른 Exception 처리를 하고싶을때 어떻게 해야할까?

Content-Type 이 application/json 일때 exception 정보를 json 데이터로 받아 볼수 없을까

방법은 간단하다. 아래 소스를 보면 HttpRequestHeader 정보에서 Content-Type 정보를 읽어올수 있다. 그래서 Response Content-Type 에 따라 다른 ModelAndView 를 생성해주면 된다. json 데이터로 넘겨주고 싶을땐 "jsonView" 를 생성하고 html 로 넘겨주고 싶을때는 jsp view 를 생성해주면 된다. 

이렇게 하면 동일한 URI 에서 Content-Type 별로 다른 결과를 받아 볼수 있다. Exception 처리를 원하는 Controller 에서 extends 받으면 된다. (모든 Controller에 일괄 적용하는 방법은 아니다.)

Ajax 요청시 반드시 Header 에 {"Content-Type":"application/json"} 추가 해야 한다.

(흔히 쓰는 javascript 라이브 러리에서는 ajax 요청시 자동으로 {X-Requested-With : XMLHttpRequest} 가 해더로 포함되니 참고하시기 바랍니다.)



MyExceptionHandler.java
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseStatus;
import org.springframework.web.servlet.ModelAndView;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;


public class MyExceptionHandler {

    @ExceptionHandler(value = Exception.class)
    @ResponseStatus (HttpStatus.INTERNAL_SERVER_ERROR)
    public ModelAndView exceptionHandler(
            HttpServletRequest request,
            HttpServletResponse response,
            Exception exception) {


        String contentType = request.getHeader("Content-Type");
        ModelAndView model=null;
        String reason= HttpStatus.INTERNAL_SERVER_ERROR.getReasonPhrase();;
        int statusCode= HttpStatus.INTERNAL_SERVER_ERROR.value();


        // Content-Type 확인, json 만 View를 따로 처리함.
        if(contentType!=null && MediaType.APPLICATION_JSON_VALUE.equals(contentType)){
            model = new ModelAndView("jsonView");
            ResponseStatus annotation = exception.getClass().getAnnotation(ResponseStatus.class);

            if(annotation!=null){
                reason = annotation.reason();
                statusCode = annotation.value().value();
            }


        } else {
            //json 이 아닐경우 error page 로 이동
            model = new ModelAndView("error.jsp");
        }

        model.addObject("reason",reason);
        model.addObject("statusCode",statusCode);
        response.setStatus(statusCode);

        return model;
    }
}


MyController.java

import org.springframework.stereotype.Controller;
import org.springframework.ui.ModelMap;
import org.springframework.web.bind.annotation.RequestMapping;

@Controller
public class MyController extends MyExceptionHandler {
    @RequestMapping(value = "/", method = RequestMethod.GET)
    public String test(ModelMap model){
       throw new MyException();
    }
}

MyException.java
import org.springframework.http.HttpStatus;
import org.springframework.web.bind.annotation.ResponseStatus;
@ResponseStatus(value = HttpStatus.FORBIDDEN,reason = "Forbidden Error!!!!")
public class MyException extends RuntimeException {
    public MyException() {
        super("Forbidden Error!!!!");
    }
}


Controller 에서 발생되는 Exception 을 그냥 throw 하는것은 좋지 않다, 미리 RuntimeException 으로  따로 정의 하자, 그리고 @ResponseStatus Annotation 을 이용해 reason  HttpStatus 를 지정한다. 

일반적인 서버 오류는 500, "Internal Server Error" 를 주로 사용하지만 Custome 하게 메시지를 구성해도 상관 없다. 하지만 HttpStatus 는 미리 정의 된것을 사용하자. (HttpStatus.java 를 참고하면 정의된 Status 목록을 확인할수 있다.)