복붙노트

[SPRING] 컨트롤러 핸들러 메서드 지원 반환 유형

SPRING

컨트롤러 핸들러 메서드 지원 반환 유형

Spring 프레임 워크를 배울 때 Spring in Action이라는 책에서 저자는 컨트롤러에서 ModelandView 메소드 리턴 타입을 사용하지 않는다는 것을 알았다. 작성자는 컨트롤러 메소드를 String의 리턴 유형으로 선언하고 메소드의 return 절은 return "/ views / theview"와 같은 문자열을 리턴합니다.

누군가가 어떻게 작동하는지 내부적 인 차이점을 정교하게 해석 할 수 있습니까?

해결법

  1. ==============================

    1.다음은 심층적 인 모습입니다.

    다음은 심층적 인 모습입니다.

    Spring은 일반적으로 모든 요청을 처리하는 DispatcherServlet 클래스를 제공합니다. doDispatch (HttpServletRequest 요청, HttpServletResponse 응답) 메소드에서이를 수행합니다.

    // Actually invoke the handler.
    mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
    

    여기서 mv는 최종 ModelAndView 객체이고, ha는 @RequestMapping으로 주석 된 컨트롤러 메소드에 대한 래퍼입니다.

    이것은 일반적으로 ServletInvocableHandlerMethod.invokeAndHandle에서 끝나는 메소드 호출 스택을 거친다.

    at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle
    at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandleMethod
    at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal
    at org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle
    at org.springframework.web.servlet.DispatcherServlet.doDispatch
    

    근원을 보면서

    public final void invokeAndHandle(ServletWebRequest webRequest,
                    ModelAndViewContainer mavContainer, Object... providedArgs) throws Exception {
    
        Object returnValue = invokeForRequest(webRequest, mavContainer, providedArgs);
    
        setResponseStatus(webRequest);
    
        if (returnValue == null) {
            if (isRequestNotModified(webRequest) || hasResponseStatus() || mavContainer.isRequestHandled()) {
                mavContainer.setRequestHandled(true);
                return;
            }
        } else if (StringUtils.hasText(this.responseReason)) {
            mavContainer.setRequestHandled(true);
            return;
        }
    
        mavContainer.setRequestHandled(false);
    
        try {
            this.returnValueHandlers.handleReturnValue(returnValue, getReturnValueType(returnValue), mavContainer, webRequest);
        }
        catch (Exception ex) {
            if (logger.isTraceEnabled()) {
                logger.trace(getReturnValueHandlingErrorMessage("Error handling return value", returnValue), ex);
            }
            throw ex;
        }
    }
    

    returnValue는 @RequestMapping 메서드에서 반환 한 객체입니다. 그것은 통과한다.

    this.returnValueHandlers.handleReturnValue
    

    여기서 Spring은 해당 객체를 처리 할 HandlerMethodReturnValueHandler를 결정합니다.

    public void handleReturnValue(
            Object returnValue, MethodParameter returnType,
            ModelAndViewContainer mavContainer, NativeWebRequest webRequest)
            throws Exception {
    
        HandlerMethodReturnValueHandler handler = getReturnValueHandler(returnType); // returns the appropriate handler
        Assert.notNull(handler, "Unknown return value type [" + returnType.getParameterType().getName() + "]");
        handler.handleReturnValue(returnValue, returnType, mavContainer, webRequest);
    }
    

    getReturnValueHandler (returnType); 적절한 핸들러를 반환합니다. HandlerMethodReturnValueHandler는 핸들러가 해당 유형 (String, View, ResponseEntity 등 (지원되는 리턴 유형 검색))을 지원하는 경우 true를 리턴하는 supportsReturnType 메소드가있는 인터페이스입니다. 따라서이 메서드는 해당 형식을 지원하는 첫 번째 처리기를 반환하고이를 실행합니다.

    Spring은 초기화시 HandlerMethodReturnValueHandler의 전체 구현을 등록합니다. 기본적으로 javadoc에 알려진 모든 구현 클래스.

    예를 들어 String을 반환하면 Spring은 ViewNameMethodReturnValueHandler를 사용하여 응답을 처리합니다.

    이제 어떤 반환 유형을 사용할지는 귀하에게 달려 있습니다. 모델을 리턴하여 jsp 뷰에서 요청 속성을 사용할 수있게하려면, Spring이 메소드에 Model 인스턴스를 전달하도록하거나, Model 객체를 직접 생성하여 반환 할 ModelAndView에 전달할 수있다. 대부분의 경우 스타일의 문제입니다.

  2. ==============================

    2.기능상 현명한 차이점이 없다. 둘 다 동일하다.

    기능상 현명한 차이점이 없다. 둘 다 동일하다.

    @RequestMapping(..)
    public String requestMapping1(Model model){
        model.addAttribute("attr1", attr1);
        return "viewName";
    }
    
    @RequestMapping(..)
    public ModelAndView requestMapping2(){
        ModelAndView modelAndView = new ModelAndView("viewName");
        modelAndView.addObject("attr1", attr1);
        return modelAndView;
    }
    

    그러나 선호되는 접근법은 전자이고 저자가 책 샘플에서 후자를 사용하지 않은 이유입니다.

  3. ==============================

    3.스프링 소스 코드에서는 org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter 클래스를 볼 수있다. public ModelAndView getModelAndView (...) 메소드에서 sping-mvc가 ModelAandView 객체를 생성하는 방법을 얻을 수 있습니다.

    스프링 소스 코드에서는 org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter 클래스를 볼 수있다. public ModelAndView getModelAndView (...) 메소드에서 sping-mvc가 ModelAandView 객체를 생성하는 방법을 얻을 수 있습니다.

    if (returnValue instanceof HttpEntity) { // returnValue is returned Value of Handler method
                handleHttpEntityResponse((HttpEntity<?>) returnValue, webRequest);
                return null;
            }
            else if (AnnotationUtils.findAnnotation(handlerMethod, ResponseBody.class) != null) {
                handleResponseBody(returnValue, webRequest);
                return null;
            }
            else if (returnValue instanceof ModelAndView) {
                ModelAndView mav = (ModelAndView) returnValue;
                mav.getModelMap().mergeAttributes(implicitModel);
                return mav;
            }
            else if (returnValue instanceof Model) {
                return new ModelAndView().addAllObjects(implicitModel).addAllObjects(((Model) returnValue).asMap());
            }
            else if (returnValue instanceof View) {
                return new ModelAndView((View) returnValue).addAllObjects(implicitModel);
            }
            else if (AnnotationUtils.findAnnotation(handlerMethod, ModelAttribute.class) != null) {
                addReturnValueAsModelAttribute(handlerMethod, handlerType, returnValue, implicitModel);
                return new ModelAndView().addAllObjects(implicitModel);
            }
            else if (returnValue instanceof Map) {
                return new ModelAndView().addAllObjects(implicitModel).addAllObjects((Map) returnValue);
            }
            else if (returnValue instanceof String) { // String is here, return new ModelAndView
                return new ModelAndView((String) returnValue).addAllObjects(implicitModel);
            }
    

    따라서이 메소드에서 Spring-MVC는 ModleAndView 객체를 구현하기 위해 반환되는 여러 유형의 핸들러 메소드를 처리 할 수 ​​있음을 알 수 있습니다.

  4. from https://stackoverflow.com/questions/18242454/controller-handler-method-supported-return-types by cc-by-sa and MIT license