spring--自定义ReturnValueHandler
来源:互联网 发布:js valueof 比较大小 编辑:程序博客网 时间:2024/06/05 02:15
由于某些时候需要对controller的返回对象作统一的封装,例如一个业务系统中统一的返回格式。这里可以使用到ReturnValueHandler,当然也可以使用ResponseBody、Convertor或者View等。
- 编写类ResultBeanReturnValueHandler实现接口HandlerMethodReturnValueHandler;
- 将handler类注册到mvc中;
1.编写类ResultBeanReturnValueHandler实现接口HandlerMethodReturnValueHandler;
/** * 结果封装类 */public class ResultBeanReturnValueHandler implements HandlerMethodReturnValueHandler { /** * 类似ResponseBody,仅有添加ResultBeanResponseBody注解的method才会触发 */@Overridepublic boolean supportsReturnType(MethodParameter returnType) { return (AnnotationUtils.findAnnotation(returnType.getContainingClass(), ResultBeanResponseBody.class) != null || returnType.getMethodAnnotation(ResultBeanResponseBody.class) != null);}/** * 使用统一的结果封装类ResultInfo,并序列化成json */@Overridepublic 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)@Documentedpublic@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.*/@Overridepublic 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));}
阅读全文
0 0
- spring--自定义ReturnValueHandler
- Spring 代理自定义异常
- Spring自定义属性编辑器
- Spring自定义属性编辑器
- spring 自定义注解
- Spring PropertyPlaceholderConfigurer 自定义扩展
- Spring的自定义PropertyEditor
- 自定义加载Spring配置文件
- spring自定义标签
- spring scope自定义
- spring自定义scope
- spring 自定义schema
- spring security 自定义验证
- Spring 自定义json converter
- 自定义spring容器
- spring mvc --自定义converse
- spring自定义标签实现
- spring 自定义标签 学习
- Deformable Convolutional Networks 的caffe实现
- wireshark抓包图解 TCP三次握手和四次挥手详解
- 2017-12-20 购买系统
- 第一个小爬虫--爬取图片并保存
- Android中的visibility属性
- spring--自定义ReturnValueHandler
- C语言:可变参数宏以及##和#符的使用
- win32开发(绘制bitmap)
- Alpha-beta剪枝-井字棋
- Codeforces Round #453 (Div. 2) A
- java多线程[9]:线程池(ExecutorService)
- 汇编语言的执行过程
- 离合器预减振超载造成变速箱怠速异响matlab仿真分析
- 【Laravel】数据库事务