springmvc核心之HandlerMethodReturnValueHandler

在springmvc當中@ResponseBody的做用估計不少人都知道,在controller中使用了@ResponseBody就會返回對應的數據結果(json格式),而不是jsp頁面或者其餘視圖。若是不加,那麼它就返回了一個具體的視圖,如jsp/html等。springmvc是如何作到這個效果的呢?其實springmvc爲處理各類返回值提供了不少的處理類,這些處理類大多類都是已ReturnValueHandler或者Processor(包含了參數處理)結尾,這些處理類的核心接口就是:html

org.springframework.messaging.handler.invocation.HandlerMethodReturnValueHandlerweb

 

/**spring

 * Strategy interface to handle the value returned from the invocation of ajson

 * handler method .mvc

 *app

 * @author Arjen Poutsmajsp

 * @since 3.1ide

 */ui

public interface HandlerMethodReturnValueHandler {this

 

/**

 * Whether the given {@linkplain MethodParameter method return type} is

 * supported by this handler.

 * @param returnType the method return type to check

 * @return {@code true} if this handler supports the supplied return type;

 * {@code false} otherwise

 */

boolean supportsReturnType(MethodParameter returnType);

 

/**

 * Handle the given return value by adding attributes to the model and

 * setting a view or setting the

 * {@link ModelAndViewContainer#setRequestHandled} flag to {@code true}

 * to indicate the response has been handled directly.

 * @param returnValue the value returned from the handler method

 * @param returnType the type of the return value. This type must have

 * previously been passed to

 * {@link #supportsReturnType(org.springframework.core.MethodParameter)}

 * and it must have returned {@code true}

 * @param mavContainer the ModelAndViewContainer for the current request

 * @param webRequest the current request

 * @throws Exception if the return value handling results in an error

 */

void handleReturnValue(Object returnValue, MethodParameter returnType,

ModelAndViewContainer mavContainer, NativeWebRequest webRequest) throws Exception;

 

}

 

HandlerMethodReturnValueHandler包含2個方法:

1.supportsReturnType()決定了哪類類型的返回值將將使用該返回值處理器

2.handleReturnValue()則是主要處理返回值的處理邏輯,而且將處理好的值返回給model,還能夠處理該返回什麼視

 

HandlerMethodReturnValueHandler是初始化過程:

在初始化RequestMappingHandlerAdapter時候,springmvc默認初始化了一系列返回值處理器,而且提供了自定義的HandlerMethodReturnValueHandler的入口(因此咱們能夠開發本身的HandlerMethodReturnValueHandler)。

private List<HandlerMethodReturnValueHandler> getDefaultReturnValueHandlers() {

List<HandlerMethodReturnValueHandler> handlers = new ArrayList<HandlerMethodReturnValueHandler>();

// Single-purpose return value types

handlers.add(new ModelAndViewMethodReturnValueHandler());

handlers.add(new ModelMethodProcessor());

handlers.add(new ViewMethodReturnValueHandler());

handlers.add(new HttpEntityMethodProcessor(getMessageConverters(), this.contentNegotiationManager));

handlers.add(new CallableMethodReturnValueHandler());

handlers.add(new DeferredResultMethodReturnValueHandler());

handlers.add(new AsyncTaskMethodReturnValueHandler(this.beanFactory));

// Annotation-based return value types

handlers.add(new ModelAttributeMethodProcessor(false));

handlers.add(new RequestResponseBodyMethodProcessor(getMessageConverters(), this.contentNegotiationManager));

// Multi-purpose return value types

handlers.add(new ViewNameMethodReturnValueHandler());

handlers.add(new MapMethodProcessor());

// Custom return value types

if (getCustomReturnValueHandlers() != null) {

handlers.addAll(getCustomReturnValueHandlers());

}

// Catch-all

if (!CollectionUtils.isEmpty(getModelAndViewResolvers())) {

handlers.add(new ModelAndViewResolverMethodReturnValueHandler(getModelAndViewResolvers()));

}

else {

handlers.add(new ModelAttributeMethodProcessor(true));

}

return handlers;

}

 

HandlerMethodReturnValueHandler的匹配是按照初始化的順序,請看下面的處理器以及對應的處理類型。

 

處理器                                                                    處理類型

針對一種類型

ModelAndViewMethodReturnValueHandler         ModelAndView

ModelMethodProcessor                                    Model

ViewMethodReturnValueHandler                      View

ResponseBodyEmitterReturnValueHandler         ResponseEntity<ResponseBodyEmitter>

StreamingResponseBodyReturnValueHandler         ResponseEntity<StreamingResponseBody>

HttpHeadersReturnValueHandler                           HttpHeaders

CallableMethodReturnValueHandler                     Callable

DeferredResultMethodReturnValueHandler     DeferredResult、ListenableFuture、CompletionStage

AsyncTaskMethodReturnValueHandler          WebAsyncTask

針對註解

ModelAttributeMethodProcessor                 @ModelAttribute(require=false)

RequestResponseBodyMethodProcessor         @ResponseBody

處理多種類型

ViewNameMethodReturnValueHandler         void、CharSequence(V4.2)

MapMethodProcessor                                Map

自定義返回值處理器

ModelAndViewResolverMethodReturnValueHandler 默認處理,若是以上的都不知足就會進入

ModelAttributeMethodProcessor                 @ModelAttribute(require=true)

 

 

下面以@ResponseBody進行講解一下

@ResponseBody的處理類是RequestResponseBodyMethodProcessor

public boolean supportsReturnType(MethodParameter returnType) {

//處理支持的類型,也就是帶ResponseBody註解的controller

return (returnType.getMethodAnnotation(ResponseBody.class) != null);

}

 

 

mavContainer.setRequestHandled(true);//請求是否已經徹底在處理程序中處理過,這裏設置爲true代表已經處理過,無需其餘處理器處理。若是爲fasle,則繼續流轉到對應的視圖,若是設置爲true,則不會再流轉到其餘處理器,默認是false。

public void handleReturnValue(Object returnValue, MethodParameter returnType,

ModelAndViewContainer mavContainer, NativeWebRequest webRequest)

throws IOException, HttpMediaTypeNotAcceptableException {

//若是沒有視圖,則必須設置爲true,不然會返回視圖層

mavContainer.setRequestHandled(true);

if (returnValue != null) {

writeWithMessageConverters(returnValue, returnType, webRequest);

}

}

 

使用案例:

1、定義一個註解(加了註解就進行加密處理)

@Target ( {ElementType.TYPE, ElementType.METHOD})

@Retention (RetentionPolicy.RUNTIME)

@Documented

public @interface ResponseBodyModel {

    String encrypt() default true;

}

 

2、自定義處理器

CustomerHandlerMethodReturnValueHandler

public class CustomerHandlerMethodReturnValueHandler implements HandlerMethodReturnValueHandler {

    @Override

    public boolean supportsReturnType(MethodParameter returnType) {

        return (returnType.getMethodAnnotation(ResponseBodyModel.class) != null);

    }

    

    @Override

    public void handleReturnValue(Object returnValue, MethodParameter returnType, ModelAndViewContainer mavContainer, NativeWebRequest webRequest) throws Exception {

        KingsResponseBody anno = returnType.getMethodAnnotation(KingsResponseBody.class);

        mavContainer.setRequestHandled(true);

        boolean encrypt = anno.encrypt();

        HttpServletResponse response = webRequest.getNativeResponse(HttpServletResponse.class);

        response.setContentType("text/json;charset=UTF-8");

  try (PrintWriter out = response.getWriter()) {

if(encrypt){

        //TODO 加密返回

 

}else{

//不加密返回

Gson jb = new Gson();

             out.write(jb.toJson(returnValue));

             out.flush();

}

   } catch (IOException e) {

            throw e;

        }

    }

}

 

3、在spring的配置文件中註冊CustomerHandlerMethodReturnValueHandler處理器

<bean id="handler" class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter">

<property name="customReturnValueHandlers">

<list>

<bean class="com.customer.mvc.CustomerHandlerMethodReturnValueHandler"></bean>

</list>

</property>

</bean>

 

4、在controller使用該註解

 

@Controller

public class HandlerMethodReturnValueHandlerDemoController {

    

    @RequestMapping (value="encrypt",method=GET)

    @ResponseBodyModel(encrypt=false)

    public List<Person> demo() {

        Person p = new Person();

        p.setName("huangjinjin");

        Person p = new Person();

        p.setName("huangzl");

        return Lists.newArrayList(p,p);

    }

}

參考:https://my.oschina.net/kings0/blog/735449

更多技術分享

相關文章
相關標籤/搜索