3 minute read

개요

: 스프링 프로젝트에서 에러가 발생하면 직접 생성한 JSP 페이지를 띄우도록 한다.

잠깐!)오류공통페이지를 설정안하면?
기본 오류페이지가 보이면 404, 500 등등 오류 발생 원인을 확인이 가능해진다. (SQL 관련 오류의 경우 Query문이 보이기도 한다.) 따라서, 보안상 취약점이 발생할 수 있기 때문에 커스텀한 오류 페이지를 구현한다. 다른 측면에서는 이런 부분을 설정하지 않으면 미관상 관리되지 않는 것처럼 보일 수 있다.

다양한 오류페이지 호출의 우선순위

: 여러 호출 방법에서 우선순위는 다음과 같다.

  1. JSP 안에 Error 페이지 선언하는 방법.
  2. web.xml > exception-type 에 에러를 선언하는 방법.
  3. web.xml > error-code 에 선언하는 방법.
  4. WebContainer 가 제공하는 기본 에러페이지 호출 (오류내용 그대로 표시, 보안취약)

오류의 종류

발생 오류 정보의 종류

  • javax.servlet.error.status_code (오류 상태 코드)
  • javax.servlet.error.exception_type (예외처리 클래스)
  • javax.servlet.error.message (오류 메시지)
  • javax.servlet.error.request_uri (오류가 발생한 요청 URI)
  • javax.servlet.error.exception (발생한 예외처리 내용)
  • javax.servlet.error.servelt_name (오류가 발생한 Servlet)

발생 오류 정보의 사용예시

JAVA

log.info("STATUS_CODE : "+request.getAttribute("javax.servlet.error.status_code"));
log.info("EXCEPTION_TYPE : "+request.getAttribute("javax.servlet.error.exception_type"));
log.info("MESSAGE : "+ request.getAttribute("javax.servlet.error.message"));
log.info("REQUEST_URI : "+ request.getAttribute("javax.servlet.error.request_uri"));
log.info("EXCEPTION : "+ request.getAttribute("javax.servlet.error.exception"));
log.info("SERVLET_NAME : "+ request.getAttribute("javax.servlet.error.servlet_name"));

JSP(jstl)

<c:out value="${requestScope['javax.servlet.error.status_code']}"> </c:out>
<c:out value="${requestScope['javax.servlet.error.exception_type']}"> </c:out>
<c:out value="${requestScope['javax.servlet.error.message']}"> </c:out>
<c:out value="${requestScope['javax.servlet.error.request_uri']}"> </c:out>
<c:out value="${requestScope['javax.servlet.error.exception']}"> </c:out>
<c:out value="${requestScope['javax.servlet.error.servlet_name']}"> </c:out>

오류페이지 호출

web.xml > error-code 에 선언하는 방법.

: (5 Line 부터) 기존 운영하던 간단한 페이지는 아래 방법과 내용으로만 구현했었다. 직관적이여서 설명은 생략한다.

xml

<error-page>
    <exception-type>java.lang.Throwable</exception-type>
    <location>/WEB-INF/views/jsp/cmn/errorPage.jsp</location>
</error-page>
<error-page>
    <error-code>404</error-code>
    <location>/WEB-INF/views/jsp/cmn/error404.jsp</location>
</error-page>
<error-page>
    <error-code>405</error-code>
    <location>/WEB-INF/views/jsp/cmn/error405.jsp</location>
</error-page>
<error-page>
    <error-code>500</error-code>
    <location>/WEB-INF/views/jsp/cmn/error500.jsp</location>
</error-page>

web.xml > exception-type 에 에러를 선언하는 방법.

: 필요한 경우 Java Exception에 대해서도 설정이 가능하다.

xml

<!-- 예시 -->
<error-page>
    <exception-type> Java Exception Class명 </exception-type>
    <location>JSP 절대경로 or Controller에 선언된 URL Mapping 주소 </location>
</error-page>

<!-- 구현 -->
<error-page>
    <exception-type>java.lang.Throwable</exception-type>
    <location>/WEB-INF/views/jsp/cmn/errorPage.jsp</location>
</error-page>

실전예제

응용1

: 기본적인 공통오류페이지 구현해보기

요약

  1. 에러발생(404)
  2. web.xml 404로 정의된 jsp 리다이렉트 수행
xml
404 에러가 발생하면 web.xml 안에 정의된 로케이션으로 JSP(커스텀에러페이지) 호출
<error-page>
    <error-code>404</error-code>
    <location>/WEB-INF/jsp/error/error.jsp</location>
</error-page>

응용2

: 심플한 공통오류페이지 구현해보기

요약

  1. 에러발생(404)
  2. web.xml 404로 정의된 url 요청 수행
  3. 요청에 맞는 컨트롤러(ErrorController) 로직 수행
  4. 에러 코드별 조건문 분기처리
  5. 분기처리 된 화면명으로 뷰 리턴하여 공통 에러페이지 구현
xml
404 에러가 발생하면 web.xml 안에 정의된 로케이션으로 컨트롤러 요청 수행
<error-page>
    <error-code>404</error-code>
    <location>/error/error</location>
</error-page>

java
리퀘스트 객체에서 에러코드를 받고 다국어처리 후 뷰 리턴한다.
    @Controller
    @RequestMapping(value="/error")
    public class ErrorController {
        
        @RequestMapping(value="/error")
        public String error(HttpServletRequest request, Model model) {
            System.out.println("error start >>>> ");
            
            Integer httpStatusCode = (Integer) reqeust.getAttribute("javax.servlet.error.status_code");
            String exceptionMessage = (String) reqeust.getAttribute("javax.servlet.error.message");
            
            //Ex) 404 : (빈값)
            System.out.println(httpStatusCode + " : " + exceptionMessage);
            
            if (httpStatusCode != null) {
                //다국어처리 공통에러메세지
                //exceptionMessage = messageSource.getMessage("http.status." + httpStatusCode, null, Locale.getDefault());
            }
            model.addAttribute("exceptionMessage", httpStatusCode + " : " + exceptionMessage);

            return "error/error";
        }
    }

jsp
다국어처리 된 메세지를 가지고 리턴된 뷰 error/error 으로 이동되면 에러코드별 메세지를 SET 한다.

아래 jsp코드에는 한글로 하드코딩되어 처리했지만
실제로는 아래 코드를 응용하여 코드별로 분기처리해주는 로직만 넣어주면 된다.

    <%@ page language="java" contentType="text/html; charset=EUC-KR" pageEncoding="EUC-KR"%>

    <%
    String msg = ""; 
    String code = Integer.toString(response.getStatus());
    
    if(code.equals("404")) {
        msg = "입력하신 페이지를 찾을 수 없습니다.";     // 404 에러는 항상 해당 메시지를 출력
    }else {
        msg = "시스템에 일시적인 오류가 발생하였습니다.";  // 그 외 에러는 해당메세지 출력
    }

    <body class="login" onload="window_onload()">
        <h1>오류페이지</h1>
        <div class="center">
            <h3><%=msg></h3>   <!-- 동적 오류메세지 처리 출력 -->
            <br>
            <h3>지속적인 오류가 발생할 경우, 관리자에게 문의요망.</h3>
        </div>
    </body>

    <script type="text/javascript">
    function window_onload(){
        setTimeout('goto_index()', 3000);
    }

    function goto_index(){
        window.location.href = "/"
    }

응용2

: Spring 3.x부터 추가된 PathVariable 기능을 사용한다.

Spring3 에서 추가된 기능 @Pathvariable 어노테이션을 이용해 오류를 보다 효율적으로 처리 가능하다. Pathvariable 란 직역하면 경로(Path)에 변수(Variable)을 넣어주는 기능이다. 다소 생소할 수 있는 Pathvariable 기능이기 때문에 Controller 부터 설명한다.

java

    @RequestMapping(value="/common/error{error_code}.do")
    public ModelAndView error(HttpServletRequest request, @PathVariable String error_code) {
        ModelAndView mv = new ModelAndView("/common/error");
        String msg = (String) request.getAttribute("javax.servlet.error.message"); 
         
        Map<string, object=""> map = new HashMap<string, object="">();
        map.put("STATUS_CODE", request.getAttribute("javax.servlet.error.status_code"));
        map.put("REQUEST_URI", request.getAttribute("javax.servlet.error.request_uri"));
        map.put("EXCEPTION_TYPE", request.getAttribute("javax.servlet.error.exception_type"));
        map.put("EXCEPTION", request.getAttribute("javax.servlet.error.exception"));
        map.put("SERVLET_NAME", request.getAttribute("javax.servlet.error.servlet_name"));
         
        try {
            int status_code = Integer.parseInt(error_code);
            switch (status_code) {
            case 400: msg = "잘못된 요청입니다."; break;
            case 403: msg = "접근이 금지되었습니다."; break;
            case 404: msg = "페이지를 찾을 수 없습니다."; break;
            case 405: msg = "요청된 메소드가 허용되지 않습니다."; break;
            case 500: msg = "서버에 오류가 발생하였습니다."; break;
            case 503: msg = "서비스를 사용할 수 없습니다."; break;
            default: msg = "알 수 없는 오류가 발생하였습니다."; break;
            }
        } catch(Exception e) {
            msg = "기타 오류가 발생하였습니다.";
        } finally {
            map.put("MESSAGE", msg);
        }
         
        //logging
        if(map.isEmpty() == false ) {
            Iterator<entry<string,object>> iterator = map.entrySet().iterator();
            Entry<string,object> entry = null;
            while(iterator.hasNext()) {
                entry = iterator.next();
                log.info("key : "+entry.getKey()+", value : "+entry.getValue());
            }
        }
         
        mv.addObject("error", map);
        return mv;
    }
</string,object></entry<string,object></string,></string,>

가장 중요한 것은 @RequestMapping(value=”/common/error{error_code}.do”) 부분과 파라미터인 public ModelAndView error(HttpServletRequest request, @PathVariable String error_code) 이 두가지 부분이다.
요청변수를 Error_code 라는 이름으로 받아서 그대로 파라미터로 사용하게 된다. (이 Error_code 는 web.xml 에서 정의된 잊지말자) 이 변수에 따라 오류별 메시지를 분기처리하는 로직이다. xml 은 다음과 같을 것이다. 아래 web.xml 에서 정의한 태그값이 변수값이 되겠군..

xml

<error-page>
    <exception-type>java.lang.Throwable</exception-type>
    <location>/WEB-INF/views/jsp/cmn/errorPage.jsp</location>
</error-page>
<error-page>
    <error-code>404</error-code>
    <location>/WEB-INF/views/jsp/cmn/error404.jsp</location>
</error-page>
<error-page>
    <error-code>405</error-code>
    <location>/WEB-INF/views/jsp/cmn/error405.jsp</location>
</error-page>
<error-page>
    <error-code>500</error-code>
    <location>/WEB-INF/views/jsp/cmn/error500.jsp</location>
</error-page>

Leave a comment