Spring 支持 Restful风格 源码分析
来源:互联网 发布:北京淘宝美工培训2ds 编辑:程序博客网 时间:2024/06/03 12:49
Spring 支持 Restful风格 源码分析
Restful风格API接口开发springMVC -- jsonRestful 请求处理 和 响应RequestResponseBodyMethodProcessor return parameter.hasParameterAnnotation(RequestBody.class); //解析方法-属性带有@RequestBody的参数for (HttpMessageConverter<?> converter : this.messageConverters) { } //遍历所有的消息转换器,包括我们自定义的this.messageConverters // 在什么时候初始化的??AnnotationMethodHandlerAdapter -- RequestMappingHandlerAdapter //配置文件 -- 实际操作的RequestMappingHandlerAdapter.afterPropertiesSet() //由于RequestMappingHandlerAdapter实现InitializingBean接口,所以容器初始化时(启动的时候) 就会去执行这个方法,完成一些初始化的工作RequestMappingHandlerAdapter.getDefaultArgumentResolvers() //完成如下一些参数解析器类的初始化resolvers.add(new RequestParamMethodArgumentResolver(getBeanFactory(), false));resolvers.add(new RequestParamMapMethodArgumentResolver());resolvers.add(new PathVariableMethodArgumentResolver());resolvers.add(new PathVariableMapMethodArgumentResolver());resolvers.add(new MatrixVariableMethodArgumentResolver());resolvers.add(new MatrixVariableMapMethodArgumentResolver());resolvers.add(new ServletModelAttributeMethodProcessor(false));resolvers.add(new RequestResponseBodyMethodProcessor(getMessageConverters()));resolvers.add(new RequestPartMethodArgumentResolver(getMessageConverters()));resolvers.add(new RequestHeaderMethodArgumentResolver(getBeanFactory()));resolvers.add(new RequestHeaderMapMethodArgumentResolver());resolvers.add(new ServletCookieValueMethodArgumentResolver(getBeanFactory()));resolvers.add(new ExpressionValueMethodArgumentResolver(getBeanFactory()));// Type-based argument resolutionresolvers.add(new ServletRequestMethodArgumentResolver());resolvers.add(new ServletResponseMethodArgumentResolver());resolvers.add(new HttpEntityMethodProcessor(getMessageConverters()));resolvers.add(new RedirectAttributesMethodArgumentResolver());resolvers.add(new ModelMethodProcessor());resolvers.add(new MapMethodProcessor());resolvers.add(new ErrorsMethodArgumentResolver());resolvers.add(new SessionStatusMethodArgumentResolver());resolvers.add(new UriComponentsBuilderMethodArgumentResolver());RequestMappingHandlerAdapter extends AbstractHandlerMethodAdapter //同时该类还继承 private List<HttpMessageConverter<?>> messageConverters; //且有成员变量消息转换器的list集合//并完成默认构造器来注册默认的消息转换器public RequestMappingHandlerAdapter() { StringHttpMessageConverter stringHttpMessageConverter = new StringHttpMessageConverter(); stringHttpMessageConverter.setWriteAcceptCharset(false); // See SPR-7316 this.messageConverters = new ArrayList<HttpMessageConverter<?>>(); this.messageConverters.add(new ByteArrayHttpMessageConverter()); this.messageConverters.add(stringHttpMessageConverter); this.messageConverters.add(new SourceHttpMessageConverter<Source>()); this.messageConverters.add(new AllEncompassingFormHttpMessageConverter());}//而对应自定义的AnnotationMethodHandlerAdapter 依赖的MappingJacksonHttpMessageConverter,通过xml文件的解析可以将消息转换器注册到RequestMappingHandlerAdapter//判断给定的类是否可以由这个转换器读取。if (converter.canRead(targetClass, contentType)) { //使用这个消息转换器去转换 return ((HttpMessageConverter<T>) converter).read(targetClass, inputMessage);}StringHttpMessageConverter //String请求的消息转换器//去解析处理clazz:是一个String的类型,inputMessage:是一个请求输入流的类型StringHttpMessageConverter{return readInternal(clazz, inputMessage);} //把HttpRequest请求参数解析成一个StringBuilder,并返回return StreamUtils.copyToString(inputMessage.getBody(), charset);//回去socket请求的输入流,解析输入流于StringBuilder,并返回给调用者public static String copyToString(InputStream in, Charset charset) throws IOException { Assert.notNull(in, "No InputStream specified"); StringBuilder out = new StringBuilder(); InputStreamReader reader = new InputStreamReader(in, charset); char[] buffer = new char[BUFFER_SIZE]; int bytesRead = -1; while ((bytesRead = reader.read(buffer)) != -1) { out.append(buffer, 0, bytesRead); } return out.toString();}//前台请求虽然有多个消息转换器,但实际就只有一个去处理请求,StringHttpMessageConverter,所以我们经常说前后台交互就是String类型//当StringHttpMessageConverter处理完了就直接返回处理结果了,就不会再执行别的消息转换器了//所以在controller配置入参转换器是没有意义的,如:@ResponeBody String param,是体现不了json转换器的//拿到通过请求参数数组args来调用具体Method的invok(),调用成功后返回调用结果,returnValue为值ServletInvocableHandlerMethod.invokeAndHandle(){ Object returnValue = invokeForRequest(webRequest, mavContainer, providedArgs);}//如:public Map | String | List xxx 代表了请求后响应也对应了有多种情况,对应各种类型//处理返回值,也对应了返回值类型的装换HandlerMethodReturnValueHandlerComposite.handleReturnValue()//还是对应了Handler来处理返回值,还是采用相同的策略模式来处理HandlerMethodReturnValueHandler handler = getReturnValueHandler(returnType);handler.handleReturnValue(returnValue, returnType, mavContainer, webRequest);//这是RequestMappingHandlerAdapter在初始化的时候所注册的一些实例,就包括了方法参数解析器和方法返回参数解析器相关类的初始化public void afterPropertiesSet() { if (this.argumentResolvers == null) { List<HandlerMethodArgumentResolver> resolvers = getDefaultArgumentResolvers(); this.argumentResolvers = new HandlerMethodArgumentResolverComposite().addResolvers(resolvers); } if (this.initBinderArgumentResolvers == null) { List<HandlerMethodArgumentResolver> resolvers = getDefaultInitBinderArgumentResolvers(); this.initBinderArgumentResolvers = new HandlerMethodArgumentResolverComposite().addResolvers(resolvers); } if (this.returnValueHandlers == null) { List<HandlerMethodReturnValueHandler> handlers = getDefaultReturnValueHandlers(); this.returnValueHandlers = new HandlerMethodReturnValueHandlerComposite().addHandlers(handlers); } initControllerAdviceCache();}//当返回值是String类型的,对应的HandlerMethodReturnValueHandler就会去处理对应返回类型//将返回值包装到ModelAndViewContainer容器中ViewNameMethodReturnValueHandler.handleReturnValue(){ //其中ModelAndViewContainer mavContainer else if (returnValue instanceof String) { String viewName = (String) returnValue; mavContainer.setViewName(viewName); //返回的值就是一个视图的名称,就是一个具体的页面, if (isRedirectViewName(viewName)) { mavContainer.setRedirectModelScenario(true); }}//这个方法是支持@ResponeBody Map | String | List 以json类型返回的调用方法RequestResponseBodyMethodProcessor.handleReturnValue(){ public void handleReturnValue(Object returnValue, MethodParameter returnType, ModelAndViewContainer mavContainer, NativeWebRequest webRequest) throws IOException, HttpMediaTypeNotAcceptableException { mavContainer.setRequestHandled(true); //*****很重要 if (returnValue != null) { writeWithMessageConverters(returnValue, returnType, webRequest); } }}//遍历消息转换器for (HttpMessageConverter<?> messageConverter : messageConverters) { //和入参使用的消息转换器是一致的 //判断是否写 if (messageConverter.canWrite(returnValueClass, selectedMediaType)) { //使用消息转换器回写给调用者 ((HttpMessageConverter<T>) messageConverter).write(returnValue, selectedMediaType, outputMessage); return; }}//创建ServletServerHttpRequest和ServletServerHttpResponseAbstractMessageConverterMethodProcessor.writeWithMessageConverters(T returnValue, //调用方法返回的值,如string | "5555" map | "name:55" MethodParameter returnType, //HandlerMethodReturnValueHandler NativeWebRequest webRequest) throws IOException, HttpMediaTypeNotAcceptableException {ServletServerHttpRequest inputMessage = createInputMessage(webRequest); ServletServerHttpResponse outputMessage = createOutputMessage(webRequest);writeWithMessageConverters(returnValue, returnType, inputMessage, outputMessage);}//object:是调用方法后的返回值 outputMessage:HttpOutputMessage 响应值MappingJacksonHttpMessageConverter.writeInternal(Object object, HttpOutputMessage outputMessage)//调用jackson api this.objectMapper.writeValue(jsonGenerator, object);//调用jackson api后将调用后的数据刷入outputMessage实体中(相当于给调用者的返回)writeInternal(t, outputMessage);outputMessage.getBody().flush();//重要,负者参数的解析和参数的返回RequestMappingHandlerAdapter.invokeAndHandle(){ 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); }}//很重要** 相当于包装成ModelAndView返回给调用者return RequestMappingHandlerAdapter.getModelAndView(mavContainer, modelFactory, webRequest);//获取视图和实体信息private ModelAndView getModelAndView(ModelAndViewContainer mavContainer, ModelFactory modelFactory, NativeWebRequest webRequest) throws Exception { modelFactory.updateModel(webRequest, mavContainer); if (mavContainer.isRequestHandled()) { //当为@ResponeBody的时候为true,就直接返回给了数据,没有返回对应的页面 return null; } ModelMap model = mavContainer.getModel(); ModelAndView mav = new ModelAndView(mavContainer.getViewName(), model); // 构造视图响应 if (!mavContainer.isViewReference()) { mav.setView((View) mavContainer.getView()); } if (model instanceof RedirectAttributes) { Map<String, ?> flashAttributes = ((RedirectAttributes) model).getFlashAttributes(); HttpServletRequest request = webRequest.getNativeRequest(HttpServletRequest.class); RequestContextUtils.getOutputFlashMap(request).putAll(flashAttributes); } return mav;}//在此之前已经完成了ModelAndView实体的构建,接下来要完成视图的解析和渲染DispatcherServlet.processDispatchResult() //进程调度的结果{ render(mv, request, response); //渲染}// 解析视图view = resolveViewName(mv.getViewName(), mv.getModelInternal(), locale, request);// 遍历所有的视图解析器去解析视图,如internalResolverViewfor (ViewResolver viewResolver : this.viewResolvers) { View view = viewResolver.resolveViewName(viewName, locale); //viewName : 就是对应的返回页面 if (view != null) { return view; }}InternalResourceView.renderMergedOutputModel(){ // 确定请求调度程序的路径。如:WEB-INFO/index.jsp String dispatcherPath = prepareForRendering(requestToExpose, response); //为目标资源获取一个RequestDispatcher(通常是一个JSP)。 RequestDispatcher rd = getRequestDispatcher(requestToExpose, dispatcherPath);}RequestDispatcher //就相当于一个servletrd.forward(requestToExpose, response); //可以做相应的转发工作,转发到一个页面mappedHandler.triggerAfterCompletion(request, response, null); //接着调用后置过滤器MappingJacksonHttpMessageConverter 的定义的作用,如果在配置文件中没有定义消息转换器,并且spring也没给你做消息转换这样在controller中使用@ResponeBody 是不支持Restful - json 风格的响应的//在实际返回值的时候是交给具体的自定义messageConverters消息转换器来转换的,不注册这个消息装换器是无法正常解析给调用者返回值的jsonfor (HttpMessageConverter<?> messageConverter : messageConverters) { if (messageConverter.canWrite(returnValueClass, selectedMediaType)) { ((HttpMessageConverter<T>) messageConverter).write(returnValue, selectedMediaType, outputMessage); if (logger.isDebugEnabled()) { logger.debug("Written [" + returnValue + "] as \"" + selectedMediaType + "\" using [" + messageConverter + "]"); } return; }}//不加这个MappingJacksonHttpMessageConverter 是无法直接支持restful - json格式的//处理给前端返回map,list,string 还可以直接返回一个实体,这个实体可以用@ResponeBody+配置json装换器,来让它支持restful的响应
阅读全文
0 0
- Spring 支持 Restful风格 源码分析
- Spring MVC 支持RestFul风格尝试
- springmvc restful风格支持
- Spring Restful 风格示例
- Spring MVC Restful风格
- SpringMVC的Restful风格支持
- Spring 支持 RESTful 功能
- Spring RESTful风格url示例
- Spring RESTful风格url示例
- Spring RESTful风格url示例
- Spring RESTful风格url示例
- Spring RESTful风格url示例
- spring boot restful API风格
- 【Spring专题-⑤】Spring RESTful风格
- Spring Security3源码分析-SSL支持
- Spring MVC 示例-注解; RESTful 风格
- CXF+spring构建restful风格的webservice
- 基于Restful风格实现Spring MVC
- php JSON数据格式化方法
- ►奇说总002期:《战争中隐秘的智慧较量》10.12
- 每日区块链:日本三家银行巨头联合开展区块链P2P转账“现场测试”;IBM、超级账本加入区块链身份联盟
- 非旋转/可持久化treap(转自Sengxian's Blog)
- Codeforces Round #438 C. Qualification Rounds
- Spring 支持 Restful风格 源码分析
- 一张图,告诉你什么是js执行上下文
- Codeforces 808F Card Game(和是素数二分图建图+二分图带权最大独立集)
- 全球最大成人网站 PornHub 也用上了AI,目的是让用户更 Happy
- 马云豪掷三千亿,你又如何能分到100个月季度奖?
- Python中的排序
- iOS【根据经纬度获取地名,根据地名获取经纬度】
- 指针常量、常量指针;指针数组、数组指针;指针函数、函数指针
- git .ssh/config 文件配置 修改端口号等