스프링

 

34.  try  ~ catch 을 제거하고 throws Exception  을 사용 해 코드의 가독성을 높이자. 

그리고  에러는 스프링의 @ControllerAdvice  에게 맞기도록 설정 해보자. 

 

 

 

try catch

많이 사용하는 예외처리 방식이며,  흔히 볼 수 있는 예외처리이다.

예외처리라기 보다는 방어코드라는 얘기도 있다.

 

장점

- 직관적이며 간편하게 사용할 수 있다.

 

단점

- 가독성이 떨어 진다.

- 중복이 많다.

- 예외관리가 어렵다.

 

 try catch 로 특별한 에러가 발생해서 특별한 처리를 하고 싶지 않는 한  throws Exception 처리로 예외 처리를 하고자 한다.

 

Controller 쪽에서 Exception 을 처리하기 위해서 다음과 같은 방식들 사용한다.

@ExceptionHandler 애노테이션을 이용한 처리

@ControllerAdvice 를 이용한 처리

@ResponseStatus 를 이용한 Http 상태 코드 처리

 

@ControllerAdvice ,   @ExceptionHandle,  @ResponseStatus 에 대한 상세 내용은 구글링을 통해 알아보자.

 

 

@ControllerAdvice  의 @ResponseStatus 의 응답 상태 코드 에러는 스프링 프레임워크 에 부담을 줄 수 있다.

400 , 404, 414, 500 에러는 web.xml  추가 하자.

 web.xml  는   /WEB-INF/web.xml 에 파일이 있다.

 

400(잘못된 요청):  서버가 요청의 구문을 인식하지 못했다.

404(찾을 수 없음):   서버가 요청한 페이지를 찾을 수 없다.

예를 들어 서버에 존재하지 않는 페이지에 대한 요청이 있을 경우 서버는 이 코드를 제공 한다.

414(요청 URI가 너무 긺):  요청 URI(일반적으로 URL)가 너무 길어 서버가 처리할 수 없다.

500(내부 서버 오류): 서버에 오류가 발생하여 요청을 수행할 수 없다.

 

이미지 처럼 파일을 만들자.


 

header.jsp

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html> 
<head>
    <title>Macaronics</title>
    <meta charset="utf-8">
    <!-- 합쳐지고 최소화된 최신 CSS -->
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.2/css/bootstrap.min.css">
<!-- 부가적인 테마 -->
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.2/css/bootstrap-theme.min.css">
<!-- 합쳐지고 최소화된 최신 자바스크립트 -->
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.2/js/bootstrap.min.js"></script>
<!-- IE8 에서 HTML5 요소와 미디어 쿼리를 위한 HTML5 shim 와 Respond.js -->
<!-- WARNING: Respond.js 는 당신이 file:// 을 통해 페이지를 볼 때는 동작하지 않습니다. -->
<!--[if lt IE 9]>
  <script src="https://oss.maxcdn.com/html5shiv/3.7.2/html5shiv.min.js"></script>
  <script src="https://oss.maxcdn.com/respond/1.4.2/respond.min.js"></script>
<![endif]-->
<style type="text/css">
html, body, div{
    margin: 0;
    padding: 0;
    border: 0;
    font-size: 100%;
    font: inherit;
    vertical-align: baseline;
} 

#bagImg{
    width: 120%;
    height: 120%
    top:0;
    z-index: 1;
    margin: 0;
    padding: 0;
}

.container{
    z-index: 555;
    position: fixed;
    top:30%;
    left:5%;
    height:30%;
    background-color: rgba(255, 255, 255, 0.5);
    margin-bottom: 20px;
}
body{
    font-family: "굴림";
}
.link a{
    
    margin:10px;
}
</style>
</head>
<body>
<div>
 <img src="/resources/images/c2.png" id="bagImg">


 

error.jsp

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<jsp:include page="header.jsp"/>
    <!-- 시작 -->   
    <div class="container">
      <div class="page-header text-center">
        <h1> 에러 페이지 입니다.</h1>
      </div>
       <div class="text-center">   
          <h2>error </h2>  
             <h4 class="m-b-0 m-t-10px"></h4>
           <h1 class="link"><a class="btn btn-danger" href="/">홈가기</a><a class="btn btn-success" href="javascript:history.go(-1);">이전페이지 가기</a></h1> 
       </div> 
        
    </div>
</div>
</body>
</html>


    

 

notfound.jsp

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<jsp:include page="header.jsp"/>
    <!-- 시작 -->   
    <div class="container">
      <div class="page-header text-center">
        <h1>여긴 당신이 찾는 웹페이지가 아닙니다.</h1>
      </div>
       <div class="text-center">   
          <h2>404 page error </h2>  
             <h4 class="m-b-0 m-t-10px"></h4>
           <h1 class="link"><a class="btn btn-danger" href="/">홈가기</a><a class="btn btn-success" href="javascript:history.go(-1);">이전페이지 가기</a></h1> 
       </div> 
        
    </div>
</div>
</body>
</html>


    
    

 

 

internalservererror.jsp,  badrequest.jsp , requesturitoolong.jsp 는 유사하다.

 

 

400 , 404, 414, 500  제외한 나머지 에러는  @ControllerAdvice   처리하기로 한다.

 

package config.error; 

패키지에 에러를 담당한 CommonException 클래스를  다음과 같이 만들었다.

package config.error;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.http.HttpStatus;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.ResponseStatus;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.ModelAndView;

@ControllerAdvice
public class CommonException {

	private static final Logger logger = LoggerFactory.getLogger(CommonException.class);

	// 개발자 버전 - 에러메시지 상세 확인 error_datail 페이지로 이동
	public static final String DEFAULT_ERROR_VIEW = "error/error_developer";

	// 일반 - 에러메시지로 error 페이지로 이동
	// public static final String DEFAULT_ERROR_VIEW = "error/error";

		
	@ExceptionHandler(Exception.class)
	public String commonErrorMessage(Exception e) {
		logger.error("@ExceptionHandler(Exception.class) --  {}", errorMessge(e.getStackTrace()));
		return DEFAULT_ERROR_VIEW;
	}

	@ExceptionHandler(RuntimeException.class)
	private ModelAndView handleRuntimeExceptionErrorMessage(RuntimeException e) {
		
		ModelAndView modelAndView = new ModelAndView();
		modelAndView.setViewName(DEFAULT_ERROR_VIEW);
		modelAndView.addObject("exception", e);
		logger.error("@ExceptionHandler(RuntimeException.class) --  {}", errorMessge(e.getStackTrace()));
		
		return modelAndView;
	}

	
	@ExceptionHandler(Throwable.class)
	@ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
	public String methodAnnotationException(Throwable e, HandlerMethod handlerMethod) {
		ResponseBody methodAnnotation = handlerMethod.getMethodAnnotation(ResponseBody.class);			
		if (methodAnnotation != null) {
			// @ResponseBody  어노테이션이 있으면 이렇게 처리 하시오 . - ajax 
			logger.error(" @ResponseBody 에서 일어난 에러");	
		}
		
		logger.error("methodAnnotation() , {}" , errorMessge(e.getStackTrace()));	
		ModelAndView modelAndView =new ModelAndView();
		modelAndView.setViewName(DEFAULT_ERROR_VIEW);
		modelAndView.addObject("exception", e);
		
	  return DEFAULT_ERROR_VIEW;
	}

	
	private String errorMessge(StackTraceElement[] stes){
		StringBuffer buffer =new StringBuffer();
		buffer.append("\n\n");
		buffer.append("★ ★ ★     에러 메시지 시작 ★★★  \n\n");
		
		for(int i=0; i<stes.length; i++){
			if(i==0){
				buffer.append("★ 에러 시작 클래스 이름 className : " + stes[i].getClassName()+"\n" ); 						
				buffer.append("★ 에러 시작 메서드 이름(methodName) : " + stes[i].getMethodName() + ", line : " + stes[i].getLineNumber() +"\n\n");
			}else{
				buffer.append("STACKTRACE - className : " + stes[i].getClassName() + ", 메서드 이름(methodName) : " 
			              + stes[i].getMethodName() + ", line : " + stes[i].getLineNumber() +"\n");
			}
		}
		
		return buffer.toString();
	}

	
	
}




 

@ControllerAdvice  클래스의 메소드는 발생한 Excetpion 객체의 타입만을 파라미터로 사용할 수 있고, 일 반 Controller와 같이

Model 을 파라미터로 사용하는 것은 지원하지 않기 때문에 직접 ModelAndView 타입을 사용하는 형태로 해야 한다.

일반 유저가 아닌 개발 자는 에러의 상세 내용을 확인해야 한다.  따라서 다음과 같이 페이지를 분리하였다.

개발시에는  "error/error_developer";  이동한다.

개발자 페이지 에러   - public static final String DEFAULT_ERROR_VIEW = "error/error_developer";

일 반  유저 페이지 에러 -public static final String DEFAULT_ERROR_VIEW = "error/error";

 

그리고 콘솔 화면에서도 에러 메시지를 봐야 하기때문에 errorMessge(StackTraceElement[] stes)  메소드를 만들어 처리를 하였다.

메소드를 보면 시작부분에 별표로 구분해 놓았고  첫출 에도 별표가 나오도록 하였다. 보통 에러가 스택으로 쌓이기 때문에

에러 첫줄이 에러 발생 원인이 대부분이라  개발자가 빠르게  찾을 수 있도록 특별히 분리해서 콘솔에 나오도록 하였다.

 

ex) 서비스 영역에서  숫자를  0 으로 나눈는 에러 ArithmeticException 를 고의적으로  만들었을 때 다음과 같은 에러가 콘솔에 나온 모습이다.

서비스 

	@Override
	public List<MemberVO> errorReadListMember() {
		int a=1;
		int b=a/0;
		logger.info(" ajaxError ( )  -  {} " , b);
		return dao.readListMember();
	}

 

INFO : net.macaronics.web.controller.SampleController -  errorReadListMember() 
ERROR: config.error.CommonException - @ExceptionHandler(RuntimeException.class) --  

★ ★ ★     에러 메시지 시작 ★★★  

★ 에러 시작 클래스 이름 className : net.macaronics.web.service.MemberServiceImpl
★ 에러 시작 메서드 이름(methodName) : errorReadListMember, line : 64

STACKTRACE - className : net.macaronics.web.controller.SampleController, 메서드 이름(methodName) : errorReadListMember, line : 134
STACKTRACE - className : sun.reflect.NativeMethodAccessorImpl, 메서드 이름(methodName) : invoke0, line : -2
STACKTRACE - className : sun.reflect.NativeMethodAccessorImpl, 메서드 이름(methodName) : invoke, line : 62
STACKTRACE - className : sun.reflect.DelegatingMethodAccessorImpl, 메서드 이름(methodName) : invoke, line : 43
STACKTRACE - className : java.lang.reflect.Method, 메서드 이름(methodName) : invoke, line : 498
STACKTRACE - className : org.springframework.web.method.support.InvocableHandlerMethod, 메서드 이름(methodName) : doInvoke, line : 221

 

 

 

 

그리고 try catch 문의   가독성 문제,  반복적인 작업을 제거하고  다음과 같이 throws Exception 를 한다.

 @Controller 영역이다.  try catch 문은 볼수 없다.    throws Exception 을 처리해서  @ControllerAdvice  에서 전부 에러를 제어하도록 한 것이다.

try catch문의 일종의 방어코드라 할수있는 에러제어는   스프링의 @ControllerAdvice  에게 맞기자.

@Controller
public class SampleController {

     @RequestMapping("/testError")
    public String errorTest() throws Exception{
        logger.info(" errorTest ( )  - start " ); 
        int a=1;
        int b=a/0;
        logger.info(" errorTest ( )  -  {} " , b); 
        return "home";
    }
    
    
    @RequestMapping("/ajaxError")
    public @ResponseBody String ajaxErrorTest() throws Exception{
        logger.info(" ajaxError ( )  - start " ); 
        int a=1;
        int b=a/0;
        logger.info(" ajaxError ( )  -  {} " , b); 
        return "home";
    }
    
    @RequestMapping("/memberList")
    public String errorReadListMember() throws Exception{
        logger.info(" errorReadListMember() " ); 
        List<MemberVO> list =service.errorReadListMember();
        
        return "home";
    }
    

}

 

서비스 영역이이다. try ~ catch 문 대신에 throws Excption 처리를 하였다.

package net.macaronics.web.service;

import java.util.List;

import net.macaronics.web.domain.MemberVO;

public interface MemberService {
		//DB 시간정보 물러오기
		public String getTime() throws Exception;
		//멤버 생성
		public void createMember(MemberVO vo) throws Exception;
		//회원 한명 정보 불러오기 
		public MemberVO getReadMember(String userid, String userpw) throws Exception;
		//회원 목록 출력
		public List<MemberVO> readListMember() throws Exception;
		//회원 업데이트
		public void updateMember(MemberVO vo) throws Exception;
		//회원 삭제
		public void deleteMember(String userid) throws Exception;
		//회원수
		public Integer getCount() throws Exception;
		//에러 테스트
		public List<MemberVO> errorReadListMember() throws Exception;
}

 

 

 

 

개발자를 위한 에러 페이지 화면이다.

error_developer.jsp

 


서버 배포 후 일반 유저에게는 다음과 같은 화면을 보여주자.

error.jsp

 

 

 

 

35.  한글 처리  

 

/WEB-INF/web.xml 

web.xml  에 다음을 추가 하자.

	<!-- 한글 처리를 위한 인코딩 필터 -->
	<filter>
		<filter-name>encoding</filter-name>
		<filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
		<init-param>
			<param-name>encoding</param-name>
			<param-value>UTF-8</param-value>
		</init-param>
	</filter>
	<filter-mapping>
		<filter-name>encoding</filter-name>
		<url-pattern>/*</url-pattern>
	</filter-mapping>

 

 

 

 

 

 

 

제작 : macaronics.net - Developer  Jun Ho Choi

소스 :  소스가 필요한 분은 비밀 댓글로 작성해 주세요.

 

 

about author

PHRASE

Level 60  라이트

사랑은 홍역과 같다. 우리 모두가 한번은 겪고 지나가야 한다. -제롬

댓글 ( 5)

댓글 남기기

작성