Spring에서 BizException 처리는 어떻게 하나요?

2,021 views
Skip to first unread message

찬욱 손

unread,
Dec 29, 2009, 5:03:09 AM12/29/09
to Korea Spring User Group
안녕하세요.
매번 메일만 받아보다가 궁금한 것이 있어 한 글자 적어봅니다.

SpringFramework에서 사용자 메시지를 처리하고자 합니다.
즉, 업무적 메시지를 view로 던지기 위한 방법 중
가장 심플한 방법이 뭐가 있는지 여러분들의 의견을 듣고 싶습니다.

제가 처리한 방법은
요청한 request가 들어오면 업무로직이 타다가, 업무적으로 사용자에게
이건 불가하다는 메시지를 보내기 위해서 사용자 Exception을 만들어 사용합니다.

BizException을 만들어서 코드값을 셋팅해서 업무로직 중에 던지는 겁니다.
그러면 controller 단에서 잡아서 코드값을 세팅해서 다시 view로 던져서 메시지 출력을 하는 것입니다.
물론, Tx은 Service단에서 BizException일 경우는 록백을 CommitBizException 처리를 하고
Controller단으로 넘겨져 옵니다.

근데 문제는 이게 모든 Controller에 다 나와야 중복 코딩되어야 한다는 거죠 ㅋ

예를 한번 보시죠

try {
userMgr.createUser(user);

mav.setViewName("zz/userMgr/UserRM");
mav.addObject("user", userMgr.findUser(user));
mav.addObject("messageCode", "ZZ.INF.001");
mav.addObject("messageArguments", user.getUserId());
mav.addObject("messageArgumentSeparator", ",");
<!-- 항상추가되는 부분 시작 -->
} catch(BizException be) {
mav.setViewName("zz/userMgr/UserCM");
mav.addObject("messageCode", be.getMessageCode());
mav.addObject("messageArguments", be.getMessageArguments());
mav.addObject("messageArgumentSeparator",
be.getMessageArgumentSeparator());
}
<!-- 항상추가되는 부분 끝 -->

어떻게 하는게 좋을까요? AOP를 써도 적절하지 않고,
intercepter도 안맞고
어떤게 좋을까요?
여러분들의 고견을 듣고 싶습니다.

그리고,,, 해피뉴 이어예요 ㅋㅋ

백기선

unread,
Dec 29, 2009, 5:13:23 AM12/29/09
to ks...@googlegroups.com
http://static.springsource.org/spring/docs/3.0.x/spring-framework-reference/html/mvc.html#mvc-exceptionhandlers

이건 어떤가요?

스프링 3을 사용하신다면 간단하게 @ExceptionHandler를 이용해서 예외 핸들러를 마치 일반적인 컨트롤러 핸들러처럼 작성하실 수도 있습니다.

2009년 12월 29일 오후 7:03, 찬욱 손 <scu...@gmail.com>님의 말:

--

Google 그룹스 'Korea Spring User Group' 그룹에 가입했으므로 본 메일이 전송되었습니다.
이 그룹에 게시하려면 ks...@googlegroups.com(으)로 이메일을 보내세요.
그룹에서 탈퇴하려면 ksug+uns...@googlegroups.com로 이메일을 보내주세요.
더 많은 옵션을 보려면 http://groups.google.com/group/ksug?hl=ko에서 그룹을 방문하세요.





--
좋은 하루 되세요~

손찬욱

unread,
Dec 29, 2009, 5:16:00 AM12/29/09
to ks...@googlegroups.com
spring 3.0이면 좋은데...
spring 2.5.6에서는 어떻게 하죠?
그리고 controller 자체가 annotation Controller 이면?? ㅠㅠ

2009년 12월 29일 오후 7:13, 백기선 <whites...@gmail.com>님의 말:

백기선

unread,
Dec 29, 2009, 5:31:02 AM12/29/09
to ks...@googlegroups.com
어떤 형태의 컨트롤러를 사용하던지 상관없구요. Spring 3이 아니라면


이글을 참조해보세요.

2009년 12월 29일 오후 7:16, 손찬욱 <scu...@gmail.com>님의 말:



--
좋은 하루 되세요~

손찬욱

unread,
Dec 29, 2009, 9:10:25 AM12/29/09
to ks...@googlegroups.com
SimpleExceptionHandler는 사용하고 있고요,
^^ 제가 하고자 하는 것은 이것과 좀 다른것 같네요 ㅋ

업무 로직 중에 에러가 날 경우, 메시지를 BizException 형태로 특정 View화면 초기에 띄우는 방법에 대한 예기입니다.

가령, Annotation으로 Contoller를 만들었을 경우에는 return값이 String이나, ModelAndView, void 등과 같은 걸로
만드는 경우, 각 유형별로 메시지를 view에 넘기는 거죠 ^^



2009년 12월 29일 오후 7:31, 백기선 <whites...@gmail.com>님의 말:

chanwo...@gmail.com

unread,
Dec 29, 2009, 11:02:51 AM12/29/09
to Korea Spring User Group
ExceptionHandler 자체를 직접 구현하셔서 예외 처리를 표준화 하시면 될듯 한데요.
저랑 이름 같아 깜짝 놀랐습니다^^;

BlackBerry® 에서 보냈습니다.


From: 손찬욱 <scu...@gmail.com>
Date: Tue, 29 Dec 2009 23:10:25 +0900
Subject: Re: Spring에서 BizException 처리는 어떻게 하나요?

백기선

unread,
Dec 29, 2009, 8:05:56 PM12/29/09
to ks...@googlegroups.com
SimpleExceptionHandler라는건 스프링에 없구요. 손찬욱님께서는 아마도 SimpleMappingExceptionResolver를 사용하고 계신것 같네요.

저라면 스프링 3으로 올리고 @ExceptionHandler를 써서 반복되는 코드를 그 안으로 옮기겠지만, 굳이 2.5.6를 쓰셔야 한다면 ExceptionHandler가 아니라 HandlerExceptionResolver를 확장한 클래스를 만들고 빈으로 등록하셔야 될 듯 합니다.

http://forum.springsource.org/archive/index.php/t-9726.html

위 링크에 있는 코드를 예제 삼아 만들면 될 듯 싶습니다.

ps: 그런데 궁금한게 있는데요. 스프링 2.5.6에서 애노테이션 기반 MVC 개발을 하고 계시면서 스프링 3으로 올리지 않을 이유가 있을까요? 어떤 크리티컬한 이유라도 있는건지 궁금합니다.

2009년 12월 29일 오후 11:10, 손찬욱 <scu...@gmail.com>님의 말:



--
좋은 하루 되세요~

chanwook park

unread,
Dec 29, 2009, 8:24:44 PM12/29/09
to ks...@googlegroups.com
기선님이 말씀해주신 HandlerExceptionResolver이 맞습니다.
ExceptionHandler는 제가 만드는 프레임웍에서 HandlerExceptionResolver을 확장해서 구성해 놓은 클래스 이름인데 이렇게 헷갈립니다@@

예외 처리 구현은  케이스에 따라 선택적으로 사용하시면 됩니다.
@ExceptionHandler나 Multiactioncontroller에서 exception handling 메소드를 등록하는 방법은 특정 핸들러 클래스나 메소드에 필요한 예외 처리 시에 사용하시면 되고, HandlerExceptionResolver을 확장해서 구현하신 예외 처리 클래스는 애플리케이션 전체에 적용하는 예외 처리 메카니즘을 구현해서 적용하시면 되겠습니다.

전체적인 예외 처리 방식을 정하시고, 해당 예외 처리 코드가 갖는 범위를 생각하셔서 구현하시면 될것 같습니다.


--
================================
Blog : http://chanwook.tistory.com
E-mail: chanwo...@gmail.com
Google talk: chanwo...@gmail.com

까오기

unread,
Dec 30, 2009, 2:08:35 AM12/30/09
to ks...@googlegroups.com
업무에 따라 Exception을 생성하고 SimpleMappingExceptionResolver 이용해서 구현하시고 예외적인 부분만 처리하면 좋을거 같습니다. 
예를 들어 주문관련 Excepton은 OrderException으로 처리하고 이 Exception이 발생하면 메시지 보여주고 이전페이지로 이동하게끔 구현하고 이 형태가 아닌 것만 controller에서 적절히 처리하세요.
컨트롤러에서 처리하는건 아래 방법도 좋을 거 같습니다. 

먼저 화면에 대한 공통을 뽑고 정형화 하세요 

UI 화면 처리case
- 메시지를 보여주고 뒤로돌아간다.
- 메시지를 보여주고 특정페이지로 이동한다.
- iframe에서 메시지를 보여준다.
- iframe에서 메시지를 보여주고 parent 페이지가 이동한다.
- 팝업에서 메시지를 보여준다.
- 팝업에서 메시지를 보여주고 창을 닫는다..
- 팝업에서 메시지를 보여주고 opener 페이지가 이동한다.
- ajax 호출시 코드와 메시지와 moveUrl을 결과로 뿌려준다. 

각각의 케이스별 page를 만들어서 쓰시면 중복을 많이 제거 할 수 있을 거 같습니다. 

try {
       userMgr.createUser(user);
       mav.setViewName("zz/userMgr/UserRM");
       mav.addObject("user", userMgr.findUser(user));
       mav.addObject("messageCode", "ZZ.INF.001");
       mav.addObject("messageArguments", user.getUserId());
       mav.addObject("messageArgumentSeparator", ",");
} catch(BizException be) {
       ViewCommonPage ui = new ViewMsgBackPage(be.getMessage());
       return ui.command();
} catch(BizOtherException boe) {
       ViewCommonPage ui = new ViewMsgMovePage(boe.getMessage(), "/index.jsp");
       return ui.command();
}


아래는 대충 만든 코드여~ 

public interface ViewCommonPage {
public ModelAndView command();
}


public class ViewMsgBackPage implements ViewCommonPage{

private final static String MSG_BACK_PAGE = "/common/viewMsgBack.jsp";
private final static String MSG_BACK_PAGE_KEY = "errorMsg";
        private String msg;
 
public ViewMsgBackPage(String msg){
this.msg = msg;
}
public ModelAndView command(){
ModelAndView mav = new ModelAndView(MSG_BACK_PAGE);
mav.addObject(MSG_BACK_PAGE_KEY, msg);
return mav;
}

}

public class ViewMsgMovePage implements ViewCommonPage{

private final static String MSG_MOVE_PAGE = "/common/viewMsgMove.jsp";
private final static String MSG_MOVE_MSG_KEY = "errorMsg";
private final static String MSG_MOVE_ADDR_KEY = "moveAddr";
        private String msg;
        private String addr;
 
public ViewMsgBackPage(String msg, String addr){
this.msg = msg;
this.addr = addr;
}
public ModelAndView command(){
ModelAndView mav = new ModelAndView(MSG_MOVE_PAGE);
mav.addObject(MSG_MOVE_MSG_KEY, this.msg);
mav.addObject(MSG_MOVE_ADDR_KEY, this.addr);
return mav;
}

}


공통 페이지
viewMsgMove.jsp
------------------------------------------------------------------------------------------------------

<%@page contentType="text/html; charset=euc-kr" %>
<%
    String resultMsg = (String)request.getAttribute("errorMsg");
    String resultUrl = (String)request.getAttribute("moveAddr");
%>
<script>
    alert("<%=resultMsg%>");
    location.href="<%=resultUrl%>";
</script>
------------------------------------------------------------------------------------------------------

도움이 될까요 ^^ 

좋은 하루되세요 

손찬욱

unread,
Dec 30, 2009, 4:54:39 AM12/30/09
to ks...@googlegroups.com
감사합니다.
이렇게 해서 처리하긴 했는데...
딱 한가지 걸리는 것이있네요.
 
DispatchServlet에서 Exception으로 잡히니깐
에러 로그 trace가 나오네요 ㅋㅋ
그걸 없애려면 또, DispatchServlet을 상속받아야해서 ㅋㅋ
그럼 가능할것 같네요.
 
감사합니다. 꾸벅 ^^

2009년 12월 30일 오후 4:08, 까오기 <kkaok.pe.kr@gmail.com>님의 말:

--

박성철

unread,
Dec 30, 2009, 8:28:55 AM12/30/09
to ks...@googlegroups.com
이제야 글을 읽었는데 너무 늦은 건 아닌지 모르겠네요.
몇가지 방안을 생각해보다 결정하기에 정보가 부족하다 싶어 몇가지 여쭈어보기로 했습니다.

1) 쓰시는 게 spring mvc인가요? 아니면 @mvc인가요?

2) 중복된다고 보는 코드가 다음 중 어떤 건가요?

try {
} catch(BizException be) {
	mav.setViewName("zz/userMgr/UserCM");
	mav.addObject("messageCode", be.getMessageCode());
	mav.addObject("messageArguments", be.getMessageArguments());
	mav.addObject("messageArgumentSeparator", be.getMessageArgumentSeparator());
}
  

제가 보기에  위 코드가 다 반복되지만 mav.setViewName의 인자는 변할 것 같네요. 맞나요?

손찬욱

unread,
Dec 30, 2009, 7:49:44 PM12/30/09
to ks...@googlegroups.com
spring mvc입니다.
그리고,  mav.setViewName의 인자는 당연히 업무에 따라 바뀌게 됩니다. ^^

2009년 12월 30일 오후 10:28, 박성철 <gyu...@gmail.com>님의 말:

--

박성철

unread,
Dec 30, 2009, 9:36:12 PM12/30/09
to ks...@googlegroups.com

> spring mvc입니다.
> 그리고, mav.setViewName의 인자는 당연히 업무에 따라 바뀌게 됩니다. ^^
그렇다면 MultiActionController를 쓰느냐에 따라 HandlerExceptionResolver
를 통해 처리할 수 있는지 여부를 결정할 것 같습니다.
MultiActionController를 안 쓴다면 가능성이 있고 쓴다면 쓸 수 없거나 쓰더
라도 무척 비효율적인 상황이 되겠죠.
MultiActionController의 exception handler method에 에러가 난 method를
parameter로 전달해주면 처리하기 쉬울텐데 말이죠.

만약 MultiActionController가 아니라 모든 Controller가 한가지 request만
처리한다면 Controller에 특정 interface를 구현하도록해서 예외 발생시 실행
할 코드 중 바뀌는 부분을 넣어두면 될 것 같습니다.

예를 들어 이런 인터페이스를 하나 만들고요.

public interface ExceptionModelAndViewProvider {
public ModelAndView getExceptionModelAndView(HttpServletRequest
request, HttpServletResponse response, Exception exception);
}

모든 Controller가 이 인터페이스를 구현하고 예외 발생시 반환할
ModelAndView를 만들어 반환하게 합니다.

...
return new ModelAndView().setViewName("zz/UserMgr/UserCM");
....

그리고 ExceptionResolver에서 handler가 이 인터페이스를 구현한 놈이라면
해당 메소드를 호출해서 ModelAndView를 얻고 공통적으로 처리해야 할 로직을
거쳐 해당 view로 분기하도록 하면 될 것 같습니다.

인터페이스의 매개변수로 ModelAndView를 넘겨주는 것도 좋고 진짜 바뀌는 부
분이 view 뿐이라면 아애 view만 반환하는 간략한 인터페이스를 만들어도 될
것 같네요.

Reply all
Reply to author
Forward
0 new messages