spring--自定义ReturnValueHandler

xiaoxiao2021-02-28  23

由于某些时候需要对controller的返回对象作统一的封装,例如一个业务系统中统一的返回格式。这里可以使用到 ReturnValueHandler,当然也可以使用ResponseBody、Convertor或者View等。 编写类ResultBeanReturnValueHandler实现接口HandlerMethodReturnValueHandler;将handler类注册到mvc中; 1.编写类ResultBeanReturnValueHandler实现接口HandlerMethodReturnValueHandler; /** * 结果封装类 */ public class ResultBeanReturnValueHandler implements HandlerMethodReturnValueHandler { /** * 类似ResponseBody,仅有添加ResultBeanResponseBody注解的method才会触发 */ @Override public boolean supportsReturnType(MethodParameter returnType) { return (AnnotationUtils.findAnnotation(returnType.getContainingClass(), ResultBeanResponseBody.class) != null || returnType.getMethodAnnotation(ResultBeanResponseBody.class) != null); } /** * 使用统一的结果封装类ResultInfo,并序列化成json */ @Override public void handleReturnValue(Object returnValue, MethodParameter returnType, ModelAndViewContainer mavContainer, NativeWebRequest webRequest) throws Exception { ResultInfo resultInfo = new ResultInfo<>(ResultInfo.OK, "success", returnValue); HttpServletResponse response = webRequest.getNativeResponse(HttpServletResponse.class); response.addHeader("Content-Type", MediaType.APPLICATION_JSON_UTF8_VALUE); response.getWriter().append(JSON.toJSONString(resultInfo)); } } @Target({ElementType.TYPE, ElementType.METHOD}) @Retention(RetentionPolicy.RUNTIME) @Documented public@interfaceResultBeanResponseBody{ } 2.将handler类注册到mvc中; 可以使用mvc标签; <mvc:annotation-driven> <mvc:return-value-handlers> <bean class="com.netease.vcloud.statics.dqs.system.returnhandler.ResultBeanReturnValueHandler" /> </mvc:return-value-handlers> <mvc:message-converters> <bean class="org.springframework.http.converter.StringHttpMessageConverter"> <property name="supportedMediaTypes"> <list> <value>text/plain;charset=UTF-8</value> <value>text/html;charset=UTF-8</value> </list> </property> </bean> </mvc:message-converters> </mvc:annotation-driven> 也可以直接在RequestMappingHandlerAdapter中注入; 这里直接上源码看吧 <--  太懒了 public class RequestMappingHandlerAdapter extends AbstractHandlerMethodAdapter implements BeanFactoryAware, InitializingBean { /** * 这里可以看到只要 注册到customArgumentResolvers里就可以了 */ private List<HandlerMethodArgumentResolver> customArgumentResolvers; /** * Provide resolvers for custom argument types. Custom resolvers are ordered * after built-in ones. To override the built-in support for argument * resolution use {@link #setArgumentResolvers} instead. */ public void setCustomArgumentResolvers(List<HandlerMethodArgumentResolver> argumentResolvers) { this.customArgumentResolvers = argumentResolvers; } /** * Return the custom argument resolvers, or {@code null}. */ public List<HandlerMethodArgumentResolver> getCustomArgumentResolvers() { return this.customArgumentResolvers; } /** * Return the list of return value handlers to use including built-in and * custom handlers provided via {@link #setReturnValueHandlers}. */ 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 ResponseBodyEmitterReturnValueHandler(getMessageConverters())); handlers.add(new StreamingResponseBodyReturnValueHandler()); handlers.add(new HttpEntityMethodProcessor(getMessageConverters(), this.contentNegotiationManager, this.requestResponseBodyAdvice)); handlers.add(new HttpHeadersReturnValueHandler()); handlers.add(new CallableMethodReturnValueHandler()); handlers.add(new DeferredResultMethodReturnValueHandler()); handlers.add(new AsyncTaskMethodReturnValueHandler(this.beanFactory)); handlers.add(new ListenableFutureReturnValueHandler()); if (completionStagePresent) { handlers.add(new CompletionStageReturnValueHandler()); } // Annotation-based return value types handlers.add(new ModelAttributeMethodProcessor(false)); handlers.add(new RequestResponseBodyMethodProcessor(getMessageConverters(), this.contentNegotiationManager, this.requestResponseBodyAdvice)); // 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; } } 附赠一个使用过程中的小问题: @Controller @RequestMapping("/live/block") public class LiveBlockController { @RequestMapping("/getCdnBlockRateByAreaAndIsp") public @ResultBeanResponseBody String getCdnBlockRateByAreaAndIsp( @RequestParam("countory") String countory, @RequestParam("province") String province, @RequestParam("city") String city, @RequestParam("isp") String isp){ return "123123"; } } 这里本想可以统一进行处理,但是一直执行不到我的 ResultBeanReturnValueHandler类中,于是直接翻看 RequestMappingHandlerAdapter类的 源码,找到 invokeHandlerMethod函数 /** * Invoke the {@link RequestMapping} handler method preparing a {@link ModelAndView} * if view resolution is required. * @since 4.2 * @see #createInvocableHandlerMethod(HandlerMethod) */ protected ModelAndView invokeHandlerMethod(HttpServletRequest request, HttpServletResponse response, HandlerMethod handlerMethod) throws Exception { ServletWebRequest webRequest = new ServletWebRequest(request, response); WebDataBinderFactory binderFactory = getDataBinderFactory(handlerMethod); ModelFactory modelFactory = getModelFactory(handlerMethod, binderFactory); ServletInvocableHandlerMethod invocableMethod = createInvocableHandlerMethod(handlerMethod); invocableMethod.setHandlerMethodArgumentResolvers(this.argumentResolvers); invocableMethod.setHandlerMethodReturnValueHandlers(this.returnValueHandlers); invocableMethod.setDataBinderFactory(binderFactory); invocableMethod.setParameterNameDiscoverer(this.parameterNameDiscoverer); ModelAndViewContainer mavContainer = new ModelAndViewContainer(); mavContainer.addAllAttributes(RequestContextUtils.getInputFlashMap(request)); modelFactory.initModel(webRequest, mavContainer, invocableMethod); mavContainer.setIgnoreDefaultModelOnRedirect(this.ignoreDefaultModelOnRedirect); AsyncWebRequest asyncWebRequest = WebAsyncUtils.createAsyncWebRequest(request, response); asyncWebRequest.setTimeout(this.asyncRequestTimeout); WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request); asyncManager.setTaskExecutor(this.taskExecutor); asyncManager.setAsyncWebRequest(asyncWebRequest); asyncManager.registerCallableInterceptors(this.callableInterceptors); asyncManager.registerDeferredResultInterceptors(this.deferredResultInterceptors); if (asyncManager.hasConcurrentResult()) { Object result = asyncManager.getConcurrentResult(); mavContainer = (ModelAndViewContainer) asyncManager.getConcurrentResultContext()[0]; asyncManager.clearConcurrentResult(); if (logger.isDebugEnabled()) { logger.debug("Found concurrent result value [" + result + "]"); } invocableMethod = invocableMethod.wrapConcurrentResult(result); } invocableMethod.invokeAndHandle(webRequest, mavContainer); if (asyncManager.isConcurrentHandlingStarted()) { return null; } return getModelAndView(mavContainer, modelFactory, webRequest); } 大致过下前情,一个请求进来时,DispatcherServlet会找到其匹配的HandlerMapping和HandlerAdapter,然后会执行 HandlerAdapter的 handle方法-> handleInternal方法-> invokeHandlerMethod方法。 最后追到 invocableMethod.invokeAndHandle ->  returnValueHandlers .handleReturnValue函数; 整个过程总结就是对请求进行封装和前置处理,然后执行对应的controller.method方法,最后对结果进行封装。 追踪源码的顺序是 HandlerAdapter. handle ->  handleInternal ->  invokeHandlerMethod ->  invocableMethod.invokeAndHandle ->  returnValueHandlers .handleReturnValue <-- 这就是目标函数了 函数 handleReturnValue下会进行结果处理类 ReturnValueHandler 的选择和执行。 /** * Iterate over registered {@link HandlerMethodReturnValueHandler}s and invoke the one that supports it. * @throws IllegalStateException if no suitable {@link HandlerMethodReturnValueHandler} is found. */ @Override public void handleReturnValue(Object returnValue, MethodParameter returnType, ModelAndViewContainer mavContainer, NativeWebRequest webRequest) throws Exception { HandlerMethodReturnValueHandler handler = selectHandler(returnValue, returnType); Assert.notNull(handler, "Unknown return value type [" + returnType.getParameterType().getName() + "]"); handler.handleReturnValue(returnValue, returnType, mavContainer, webRequest); } private HandlerMethodReturnValueHandler selectHandler(Object value, MethodParameter returnType) { boolean isAsyncValue = isAsyncReturnValue(value, returnType); for (HandlerMethodReturnValueHandler handler : this.returnValueHandlers) { if (isAsyncValue && !(handler instanceof AsyncHandlerMethodReturnValueHandler)) { continue; } if (handler.supportsReturnType(returnType)) { return handler; } } return null; } 在debug的时候发现被 ViewNameMethodReturnValueHandler抢先了,因为我的返回值是一个string类型的对象。 public boolean supportsReturnType(MethodParameter returnType) { Class<?> paramType = returnType.getParameterType(); return (void.class == paramType || CharSequence.class.isAssignableFrom(paramType)); }
转载请注明原文地址: https://www.6miu.com/read-2150260.html

最新回复(0)