2012-09-17 2 views
0

내 모든 컨트롤러를 생산하는 다음과 같은 추상 클래스 확장 : 또한강제 이상한 문제

public abstract class AbstractController { 

    public HttpServletRequest request; 
    public HttpServletResponse response; 
    public ModelMap model; 

} 

을, 나는 다음 인터셉터 구현 :

public class HttpRequestInterceptor implements HandlerInterceptor { 

    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws ServletException { 
     if (handler instanceof AbstractController) { 
      AbstractController controller = (AbstractController) handler; 
      controller.request = request; 
      controller.response = response; 
      controller.model = new ModelMap(); 
     } 
     return true; 
    } 

    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) { 
     if (handler instanceof AbstractController && modelAndView != null) { 
      AbstractController controller = (AbstractController) handler; 
      modelAndView.addAllObjects(controller.model); 
     } 
    } 

    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception { 
    } 

} 

컨트롤러의 메서드 매개 변수로 request, responsemodel을 전달할 필요가 없으므로이 코드는 인수 분해를 개선 한 것으로 나타났습니다. 두 가지 방법 중

public class HomeController extends AbstractController { 

    @RequestMapping 
    public void download1() { 
     // use the parent attribute response 
     File file = new File(MY_FILE_PATH); 
     InputStream in = new BufferedInputStream(new FileInputStream(file)); 
     ServletOutputStream out = response.getOutputStream(); 
     IOUtils.copy(in, out); 
     response.flushBuffer(); 
    } 

    @RequestMapping 
    public void download2(HttpServletResponse response) { 
     // use the response passed as parameter 
     File file = new File(MY_FILE_PATH); 
     InputStream in = new BufferedInputStream(new FileInputStream(file)); 
     ServletOutputStream out = response.getOutputStream(); 
     IOUtils.copy(in, out); 
     response.flushBuffer(); 
    } 

} 

모두 위의 파일을 다운로드 브라우저를 만들지 만, 그것은해야으로 download2 원본 파일을 생성하는 동안 download1 하나는 빈 파일을 생성 : 나는이 문제를 발견 할 때까지이 솔루션은 잘 작동합니다. 왜 그런가? 디버거

덕분에, I는 download1 하나가 통해 인스턴스를 생성하면서 인터셉터의 postHandle 방법에서는 download2있어서, null 동일 modelAndView 생성 것으로 확인. 이 문제에 대한 의미가 있어야하지만, 나는 무엇을 찾을 수 없습니다.

response가 컨트롤러 메소드의 매개 변수로 전달 될 때 어떻게 초기화됩니까?

+3

당신은'prototype' 범위에서 컨트롤러를 정의 하는가? 그렇지 않으면 자신의 필드에 대화 상태를 저장하면 안됩니다. 컨트롤러의 동일한 인스턴스가 모든 요청간에 공유되기 때문입니다. – axtavt

+0

'프로토 타입'범위에 대해 들어 본 적이 없습니까 ... 당신은 무엇을 의미합니까? – sp00m

+0

http://stackoverflow.com/q/8887831/106261 – NimChimpsky

답변

7

이 작업을 수행하지 마십시오 (BTW 싱글의 기본 범위가) 컨트롤러에

public abstract class AbstractController { 

    public HttpServletRequest request; 
    public HttpServletResponse response; 
    public ModelMap model; 

} 

인스턴스 변수는 나쁜 생각입니다.

+0

흠, 어떤 이유가? 나는 개발할 때 매우 편리하다고 느낀다 ... – sp00m

+5

봄과 요청 사이에서 관리되지 않는 인스턴스 변수를 공유하고있다. 컨트롤러는 여러 요청에 의해 동시에 액세스되므로 스레드로부터 안전해야합니다. 인스턴스 변수가 있으면이 값이됩니다. – NimChimpsky

3

그냥 (TXT 파일에) 이런 일을합니다

@RequestMapping(value="/download", method=RequestMethod.GET, produces=MediaType.APPLICATION_OCTET_STREAM_VALUE) 
@ResponseBody 
public String download(HttpServletResponse response) throws IOException { 
    response.setContentType("application/force-download"); 
    FileReader fr = new FileReader("/folder/file.extension"); 
    return IOUtils.toString(fr); // IOUtils come from Apache Commons IO 
} 
+0

Jackson 'ObjectMapper'가 파일을 직렬화하려고했기 때문에 테스트에 문제가있었습니다. 여기에 제시된 바와 같이 produce 속성을'@ RequestMapping'에 추가하는 문제를 해결했습니다. –