스프링에서 InternalResourceView 의 renderMergedOutputModel 에 대해서 질문을 드립니다.

1,527 views
Skip to first unread message

굴러라

unread,
Nov 20, 2009, 6:54:09 AM11/20/09
to Korea Spring User Group
안녕하세요. 스프링으로 개발중에 알수 없는 상황에 처해서 여러분께 도움을 요청 합니다.

컨트롤러에서 처리된 결과를

ModelAndView mav = new ModelAndView(); 를 통해서 jsp 와 맵핑 시켜주는 상황에서

상황 : A(정회원) B(준회원)

Log 를 살펴 보니

A의 경우에는

org.springframework.web.servlet.view.InternalResourceView.renderMergedOutputModel
(InternalResourceView.java:238) - Forwarding to resource [/WEB-INF/
jsp/mypage/paymentResult.jsp] in InternalResourceView 'mypage/
paymentResult'

라고 나오면서 원하는 대로 시스템이 작동되고( 결제화면에서 iFrame 화면으로 submit을 날리고
paymentResult.jsp 에서 부모페이지의 로케이션을 바꾸는 흐름입니다.)

B의 경우에는
org.springframework.web.servlet.view.InternalResourceView.renderMergedOutputModel
(InternalResourceView.java:229) - Including resource [/WEB-INF/jsp/
mypage/paymentResult.jsp] in InternalResourceView 'mypage/
paymentResult'

라고 나오고 paymentResult.jsp를 아예 로드를 못하는거 같습니다.

InternalResourceView를 확인해 본결과 아래와 같은 소스 이던데..

publc class InternalResourceView{
....
protected void renderMergedOutputModel(
Map model, HttpServletRequest request, HttpServletResponse
response) throws Exception {

// Expose the model object as request attributes.
exposeModelAsRequestAttributes(model, request);

// Expose helpers as request attributes, if any.
exposeHelpers(request);

// Determine the path for the request dispatcher.
String dispatcherPath = prepareForRendering(request, response);

// Forward to the resource (typically a JSP).
// Note: The JSP is supposed to determine the content type itself.
RequestDispatcher rd = request.getRequestDispatcher(dispatcherPath);
if (rd == null) {
throw new ServletException(
"Could not get RequestDispatcher for [" + getUrl() + "]: check
that this file exists within your WAR");
}

// If already included or response already committed, perform
include, else forward.
if (useInclude(request, response)) {
rd.include(request, response);
if (logger.isDebugEnabled()) {
logger.debug("Included resource [" + getUrl() + "] in
InternalResourceView '" + getBeanName() + "'");
}
}
else {
rd.forward(request, response);
if (logger.isDebugEnabled()) {
logger.debug("Forwarded to resource [" + getUrl() + "] in
InternalResourceView '" + getBeanName() + "'");
}
}
}
....
}


제가 의도한 상황은 A와 B 모두의 경우에 useInclude () 의 결과로 false 가 나와야 하는 경우인거 같은데
(확실하지는 않음) 어떻게 하면 이상황을 타개 할수 있을까요?
덤으로 useInclude 이게 정확히 무엇인지 알고 싶습니다.


Sewon Ann

unread,
Nov 20, 2009, 9:18:58 AM11/20/09
to ks...@googlegroups.com
저도 모르는 내용이라 같이 헤딩 해 보시죠 :)

구글링을 해 보았더니 forward와 include 에 대해 설명하는 페이지가 나오네요. forward 는 알고 있었는데, include 는 처음 봤습니다. (http://www.roseindia.net/javacertification/wcd-guide/machanism.shtml)

model 값을 실제 페이지(view가 되겠지요) 에 전달하고, 최종적으로 사용자에게 화면을 전달할 때 forward 를 씁니다. include 의 경우 찾아보니 프로그램적으로 page include 를 하려고 할 때 쓴다고 하네요.

useinclude() 반환값이 true 가 문제인데 useinclude() 설명이 다음과 같으니, 조건을 하나하나 찾아보시면 되지 않을까요.

Determine whether to use RequestDispatcher's include or forward method.

Performs a check whether an include URI attribute is found in the request, indicating an include request, and whether the response has already been committed. In both cases, an include will be performed, as a forward is not possible anymore.


return (this.alwaysInclude || WebUtils.isIncludeRequest(request) || response.isCommitted());

1. 항상 include 로 실행되도록 설정되었다. <= 이건 아니고
2. WebUtils.isIncludeRequest()
3. 이미 status 가 commit 되었다

제 생각엔 3번 케이스가 농후하지 않을까 생각되는데, 일단 정회원과 준회원일 때 시스템 상태가 어떻게 다른지 확인해 보실 필요가 있을 것 같습니다. 제 생각으론 아마 앞단에서 "너 준회원이니 못가" 정도로 status commit 한 다음에 jsp 로 가려고 하니 문제가 되는 것 같습니다.


2009/11/20 굴러라 <dyd...@gmail.com>

이용희

unread,
Nov 20, 2009, 9:49:04 AM11/20/09
to ks...@googlegroups.com
예전에 순수하게 서블릿만을 이용해서(스프링이나 스트럿츠를 사용하지 않고) MVC패턴을 구현할 때,
 
RequestDispatcher view = request.getRequestDispatcher("result.jsp");
view.forward(request, response);
 
이런식으로 컨트롤러에서 view로 포워딩했었습니다.
여기에서 forward 매소드말고 include 매소드를 사용할 수 있는데,
이것은 JSP에서 include 지시자를 사용하는 것하고 비슷한 것이라고 알고 있습니다.
 
다시 말하면, view.forward 를 하면 제어권이 view 로 완전히 넘어가서 
이어지는 코드가 있어도 실행이 안되고((컨테이너에 따라서 exception이 발생하기도 합니다.),
view.include를 사용하면 이어지는 코드가 실행이 됩니다(flush를 하거나 response를 보낼때까지)
 
위의 내용을 꼼꼼히 읽어보진 못했지만,
B의 경우 view로 포워딩을 하는 것이 아니고 include가 실행된 것 처럼 보이는데,
제가 스프링은 잘 모릅니다만, view페이지를 호출할때 특정 조건에 따라서 내부적으로 forward, include를 선택해서
호출하는 것은 혹시 아닐까요?
쓰고 보니 별 도움이 안될 것 같네용..  ^^;;
 
PS: 예전 기억이라 틀린내용이 있을지도 모르니 잘못된 내용이 있으면 지적해 주세요~


 
2009년 11월 20일 오후 8:54, 굴러라 <dyd...@gmail.com>님의 말:



--
이용희(Yonghee Lee)
(주) 모비젠 / CNS사업본부
CN연구3팀 / 책임연구원
Tel : 010-5213-0417 / 031-730-0786
E-mail : yh...@mobigen.com
            yhl...@gmail.com

이용희

unread,
Nov 20, 2009, 10:00:27 AM11/20/09
to ks...@googlegroups.com

아.. 참 그리고,
아시는 내용이시겠지만 혹시나 해서 한마디 첨언하자면,
 
forward나 sendRedirect  모두 그 전에 flush()가 실행되거나 또는 response가 기록되고 나면 실행되지 않습니다.
 
paymentResult.jsp 가 아예 로드되지 않았다면, 위의 가능성이 큰 것으로 보여집니다.
 
보통 이런 상황에는 IllegalStateException이 발생하는데, flush()를 호출하기 전에는 exception이 발생하지 않는
문제도 있었습니다.(예전 톰캣에서 그랬는데 요즘 버전은 잘 모르겠습니다.)
예외를 잡아 보시던지, 톰캣 로그를 꼼꼼하게 확인해 보시는 것도 좋을 것 같습니다.
 
도움이 되시길 바라겠습니다. ^^;;
2009년 11월 20일 오후 8:54, 굴러라 <dyd...@gmail.com>님의 말:
안녕하세요. 스프링으로 개발중에 알수 없는 상황에 처해서 여러분께 도움을 요청 합니다.

박성철

unread,
Nov 20, 2009, 8:07:54 PM11/20/09
to ks...@googlegroups.com
useInclude()는 include를 쓸지 forward를 쓸지 판단하는 메소드입니다.

소스는 이렇습니다.

    protected boolean useInclude(HttpServletRequest request, HttpServletResponse response) {
        return (this.alwaysInclude || WebUtils.isIncludeRequest(request) || response.isCommitted());
    }

결국
  1. alwaysinclude가 true 이거나
  2. 지금 실행된 request가 다른 request에서 include 한 것이거나
  3. 이미 출력 결과가 전송되었으면 include가 사용됩니다.

지금 상황이 어디에 해당하는지 한번 살펴보시면 좋을 것 같습니다. Controller의 종료 바로 직전에 WebUtils.isIncludeRequest(request)와 response.isCommitted()의 결과를 stdout로 출력해보시면 원인을 알 수 있을 것 같네요.

굴러라 쓴 글:
Reply all
Reply to author
Forward
0 new messages