当前位置: 首页 > news >正文

绿园区住房和城乡建设局网站网站开发服务流程

绿园区住房和城乡建设局网站,网站开发服务流程,波莱网站开发,沈阳的网站制作公司一、前言 web相关知识探索五中研究了请求中所带的参数是如何映射到接口参数中的#xff0c;也即请求参数如何与接口参数绑定。主要有四种、分别是注解方式、Servlet API方式、复杂参数、以及自定义对象参数。web相关知识探索五中主要研究自定义对象参数数据绑定底层原理。本次…一、前言 web相关知识探索五中研究了请求中所带的参数是如何映射到接口参数中的也即请求参数如何与接口参数绑定。主要有四种、分别是注解方式、Servlet API方式、复杂参数、以及自定义对象参数。web相关知识探索五中主要研究自定义对象参数数据绑定底层原理。本次主要是研究数据响应与内容协商底层原理。 二、数据响应与内容协商  一、数据响应 接口的数据响应分两种 一、响应页面发送一个请求跳转到指定页面。一般常见于开发单体项目 二、响应数据发送一个请求相应相关格式数据。常见于前后端分离项目。 1、响应JSON格式数据 2、响应xml格式数据 3、响应xls数据 4、图片、音视频 5、自定义协议数据 二、响应JSON数据 在前后端分离项目的日常开发中一般后端返回的都是JSON类型的数据。想要返回JSON类型的数据就需要在项目中引入Jackson.jar 和在接口上加上ResponseBody 注解项目中只需引入         dependency             groupIdorg.springframework.boot/groupId             artifactIdspring-boot-starter-web/artifactId         /dependency 即可。web场景自动引入了json场景 一、JSON数据响应原理 一、设置返回值处理器 在前几篇研究中处理器适配器类RequestMappingHandlerAdapter里面有一个方法invokeHandlerMethod这个方法提前加载了参数解析器以及返回值处理器。其中返回值处理器有15个具体如图片所示 二、执行接口方法获取返回值 三、返回值处理 // ServletInvocableHandlerMethod类里面的方法 public void invokeAndHandle(ServletWebRequest webRequest, ModelAndViewContainer mavContainer, Object... providedArgs) throws Exception {// 请求参数解析绑定接口参数执行接口方法。获取到返回值Object returnValue this.invokeForRequest(webRequest, mavContainer, providedArgs);// 设置各种返回的状态。this.setResponseStatus(webRequest);if (returnValue null) {if (this.isRequestNotModified(webRequest) || this.getResponseStatus() ! null || mavContainer.isRequestHandled()) {this.disableContentCachingIfNecessary(webRequest);mavContainer.setRequestHandled(true);return;}} else if (StringUtils.hasText(this.getResponseStatusReason())) {mavContainer.setRequestHandled(true);return;}mavContainer.setRequestHandled(false);Assert.state(this.returnValueHandlers ! null, No return value handlers);try {// 这里就会处理返回值当前返回值是一个对象这里就会把对象变为JSONthis.getReturnValueType(returnValue)获取到返回值的类型this.returnValueHandlers.handleReturnValue(returnValue, this.getReturnValueType(returnValue), mavContainer, webRequest);} catch (Exception var6) {if (logger.isTraceEnabled()) {logger.trace(this.formatErrorForReturnValue(returnValue), var6);}throw var6;}}// 请求会返回各种状态这里会将返回的状态设置到HttpServletResponse当中private void setResponseStatus(ServletWebRequest webRequest) throws IOException {HttpStatus status this.getResponseStatus();if (status ! null) {HttpServletResponse response webRequest.getResponse();if (response ! null) {String reason this.getResponseStatusReason();if (StringUtils.hasText(reason)) {response.sendError(status.value(), reason);} else {response.setStatus(status.value());}}webRequest.getRequest().setAttribute(View.RESPONSE_STATUS_ATTRIBUTE, status);}} 从 this.returnValueHandlers.handleReturnValue(returnValue, this.getReturnValueType(returnValue), mavContainer, webRequest);方法进入里面就是将返回值转换为JSON对象的逻辑  // HandlerMethodReturnValueHandlerComposite类里面的方法public void handleReturnValue(Nullable Object returnValue, MethodParameter returnType, ModelAndViewContainer mavContainer, NativeWebRequest webRequest) throws Exception {// 获取能够处理返回值的处理器returnValue返回值对象returnType返回值类型HandlerMethodReturnValueHandler handler this.selectHandler(returnValue, returnType);if (handler null) {throw new IllegalArgumentException(Unknown return value type: returnType.getParameterType().getName());} else {// 使用获取到的返回值处理器处理返回值handler.handleReturnValue(returnValue, returnType, mavContainer, webRequest);}}// 获取能够处理返回值的处理器private HandlerMethodReturnValueHandler selectHandler(Nullable Object value, MethodParameter returnType) {// 判断是否是异步返回值boolean isAsyncValue this.isAsyncReturnValue(value, returnType);// 遍历返回值处理器一共15个Iterator var4 this.returnValueHandlers.iterator();HandlerMethodReturnValueHandler handler;do {do {if (!var4.hasNext()) {return null;}handler (HandlerMethodReturnValueHandler)var4.next();// 如果是异步返回值同时这个处理器有时异步处理器就跳出循环} while(isAsyncValue !(handler instanceof AsyncHandlerMethodReturnValueHandler));// 判断当前处理器是否支持处理当前返回值} while(!handler.supportsReturnType(returnType));return handler;} handler.supportsReturnType(returnType)其实返回值处理器就是第一个接口          public interface HandlerMethodReturnValueHandler {     boolean supportsReturnType(MethodParameter var1);     void handleReturnValue(Nullable Object var1, MethodParameter var2, ModelAndViewContainer var3, NativeWebRequest var4) throws Exception; }   然后有多个实现类每个实现类的都是实现上面两个方法逻辑都不同源码里面就是遍历多个实现类看看那个实现类支持处理当前返回值就用那个返回值处理器。 原理就是 public boolean supportsReturnType(MethodParameter returnType) {return AnnotatedElementUtils.hasAnnotation(returnType.getContainingClass(), ResponseBody.class) || returnType.hasMethodAnnotation(ResponseBody.class); } AnnotatedElementUtils.hasAnnotation(returnType.getContainingClass(), ResponseBody.class)这段话也就是方法标了ResponseBody注解所以支持处理。 通过循环遍历所有的返回值处理器的supportsReturnType方法就可以知道springmvc到底支持处理那些返回值。sprringmvc能够处理的返回值类型。 ModelAndView Model View ResponseEntity  ResponseBodyEmitter StreamingResponseBody HttpEntity HttpHeaders Callable DeferredResult ListenableFuture CompletionStage WebAsyncTask 有 ModelAttribute 且为对象类型的 ResponseBody 注解 --- RequestResponseBodyMethodProcessor 然后开始调用RequestResponseBodyMethodProcessor这个处理器的handleReturnValue方法对返回值进行处理。可以处理返回值标了ResponseBody 注解的 public void handleReturnValue(Nullable Object returnValue, MethodParameter returnType, ModelAndViewContainer mavContainer, NativeWebRequest webRequest) throws IOException, HttpMediaTypeNotAcceptableException, HttpMessageNotWritableException {mavContainer.setRequestHandled(true);// 将原生请求和响应包装一下ServletServerHttpRequest inputMessage this.createInputMessage(webRequest);ServletServerHttpResponse outputMessage this.createOutputMessage(webRequest);// 使用消息转换器进行写出操作。这个是最终处理返回值的方法也就是Person对象转JSON的核心方法this.writeWithMessageConverters(returnValue, returnType, inputMessage, outputMessage);} 四、内容协商 writeWithMessageConverters(returnValue, returnType, inputMessage, outputMessage)方法 这个方法就是最终处理返回值的方法。主要就是利用MessageConverters消息转换器 进行处理 将数据写为json。而这里面就涉及到内容协商原理。 一、什么是内容协商这里大致说一下之后再细究 浏览器默认会以请求头的方式告诉服务器他能接受什么样的内容类型服务器最终根据自己自身的能力决定服务器能生产出什么样内容类型的数据。 /**T value:返回值数据内容这里的数据已经绑定到了接口方法的返回值类型当中MethodParameter returnType接口需要返回的数据类型也即返回值类型例如这个接口PostMapping(/test)public MapString,Object testEntity(Person person){value就是Map里面的数据returnType就是Map类型**/// 使用消息转换器进行写出操作protected T void writeWithMessageConverters(Nullable T value, MethodParameter returnType, ServletServerHttpRequest inputMessage, ServletServerHttpResponse outputMessage) throws IOException, HttpMediaTypeNotAcceptableException, HttpMessageNotWritableException {// 返回值数据Object body;// 返回值数据的class对象Class valueType;// 返回值数据类型一般和valueType是相同的Object targetType;// 返回值等于字符串进入if (value instanceof CharSequence) {body value.toString();valueType String.class;targetType String.class;} else {body value;valueType this.getReturnValueType(value, returnType);targetType GenericTypeResolver.resolveType(this.getGenericType(returnType), returnType.getContainingClass());}if (this.isResourceType(value, returnType)) {outputMessage.getHeaders().set(Accept-Ranges, bytes);if (value ! null inputMessage.getHeaders().getFirst(Range) ! null outputMessage.getServletResponse().getStatus() 200) {Resource resource (Resource)value;try {ListHttpRange httpRanges inputMessage.getHeaders().getRange();outputMessage.getServletResponse().setStatus(HttpStatus.PARTIAL_CONTENT.value());body HttpRange.toResourceRegions(httpRanges, resource);valueType body.getClass();targetType RESOURCE_REGION_LIST_TYPE;} catch (IllegalArgumentException var19) {outputMessage.getHeaders().set(Content-Range, bytes */ resource.contentLength());outputMessage.getServletResponse().setStatus(HttpStatus.REQUESTED_RANGE_NOT_SATISFIABLE.value());}}}MediaType selectedMediaType null;// 从响应请求头中获取媒体类型如果前面使用了aop等切面技术处理了请求媒体类型这里就是拿到处理后的媒体类型MediaType contentType outputMessage.getHeaders().getContentType();boolean isContentTypePreset contentType ! null contentType.isConcrete();if (isContentTypePreset) {if (this.logger.isDebugEnabled()) {this.logger.debug(Found Content-Type: contentType in response);}// 如果前面有处理过媒体类型这里就直接拿到媒体类型赋值过去即可selectedMediaType contentType;} else {// 一般正常请求都是进来这部分逻辑HttpServletRequest request inputMessage.getServletRequest();List acceptableTypes;try {// 这里就是获取到浏览器发送请求时请求头携带的Accept字段里面接受的类型acceptableTypes this.getAcceptableMediaTypes(request);} catch (HttpMediaTypeNotAcceptableException var20) {int series outputMessage.getServletResponse().getStatus() / 100;if (body ! null series ! 4 series ! 5) {throw var20;}if (this.logger.isDebugEnabled()) {this.logger.debug(Ignoring error response content (if any). var20);}return;}// valueType当前返回值数据是什么类型也就是接口方法的返回值类型targetType接口方法返回值类型。一般来说valueType和targetType是相同的。// 整个方法原理就是当前服务器能够响应什么样的类型ListMediaType producibleTypes this.getProducibleMediaTypes(request, valueType, (Type)targetType);if (body ! null producibleTypes.isEmpty()) {throw new HttpMessageNotWritableException(No converter found for return value of type: valueType);}ListMediaType mediaTypesToUse new ArrayList();Iterator var15 acceptableTypes.iterator();// 其实就是循环遍历浏览器能够支持的媒体类型MediaType mediaType;while(var15.hasNext()) {mediaType (MediaType)var15.next();Iterator var17 producibleTypes.iterator();// 然后再里面循环遍历服务器能够支持的媒体类型拿浏览器能够支持的媒体类型一个个和服务器能够支持的媒体类型进行比较然后得到两方都能接受的内容类型。可能会有多个while(var17.hasNext()) {MediaType producibleType (MediaType)var17.next();if (mediaType.isCompatibleWith(producibleType)) {mediaTypesToUse.add(this.getMostSpecificMediaType(mediaType, producibleType));}}}if (mediaTypesToUse.isEmpty()) {if (body ! null) {throw new HttpMediaTypeNotAcceptableException(producibleTypes);}if (this.logger.isDebugEnabled()) {this.logger.debug(No match for acceptableTypes , supported: producibleTypes);}return;}MediaType.sortBySpecificityAndQuality(mediaTypesToUse);var15 mediaTypesToUse.iterator();// 这里其实就是找到浏览器能够接受的类型且服务器能够转换的类型中最合适的一个类型while(var15.hasNext()) {mediaType (MediaType)var15.next();if (mediaType.isConcrete()) {selectedMediaType mediaType;break;}if (mediaType.isPresentIn(ALL_APPLICATION_MEDIA_TYPES)) {selectedMediaType MediaType.APPLICATION_OCTET_STREAM;break;}}if (this.logger.isDebugEnabled()) {this.logger.debug(Using selectedMediaType , given acceptableTypes and supported producibleTypes);}}HttpMessageConverter converter;GenericHttpMessageConverter genericConverter;label183: {if (selectedMediaType ! null) {selectedMediaType selectedMediaType.removeQualityValue();Iterator var23 this.messageConverters.iterator();// 这里就开始遍历消息转换器找到能够转换最佳类型的那个消息转换器。一旦确定了最佳类型SpringMVC会挨个遍历所有容器底层的 HttpMessageConverter 看谁能处理while(var23.hasNext()) {converter (HttpMessageConverter)var23.next();genericConverter converter instanceof GenericHttpMessageConverter ? (GenericHttpMessageConverter)converter : null;if (genericConverter ! null) {if (((GenericHttpMessageConverter)converter).canWrite((Type)targetType, valueType, selectedMediaType)) {break label183;}} else if (converter.canWrite(valueType, selectedMediaType)) {break label183;}}}if (body ! null) {SetMediaType producibleMediaTypes (Set)inputMessage.getServletRequest().getAttribute(HandlerMapping.PRODUCIBLE_MEDIA_TYPES_ATTRIBUTE);if (!isContentTypePreset CollectionUtils.isEmpty(producibleMediaTypes)) {throw new HttpMediaTypeNotAcceptableException(this.getSupportedMediaTypes(body.getClass()));}throw new HttpMessageNotWritableException(No converter for [ valueType ] with preset Content-Type contentType );}return;}// 拿到需要处理的返回数据就是接口返回数据body this.getAdvice().beforeBodyWrite(body, returnType, selectedMediaType, converter.getClass(), inputMessage, outputMessage);if (body ! null) {LogFormatUtils.traceDebug(this.logger, (traceOn) - {return Writing [ LogFormatUtils.formatValue(body, !traceOn) ];});// 响应请求的头部添加信息this.addContentDispositionHeader(inputMessage, outputMessage);if (genericConverter ! null) {// 拿到执行的消息转换器调用写入操作genericConverter.write(body, (Type)targetType, selectedMediaType, outputMessage);} else {converter.write(body, selectedMediaType, outputMessage);}} else if (this.logger.isDebugEnabled()) {this.logger.debug(Nothing to write: null body);}} 二、HTTPMessageConverter原理 HTTPMessageConverter消息转换器这是一个接口定义了消息转换器的规范也就是各个方法。 HttpMessageConverter: 看是否支持将 此 Class类型的对象转为MediaType类型的数据。 例子canWrite:Person对象转为JSON。canRead:JSON转为Person 十种消息转换器能够处理的数据类型这里只是每个转换器调用support方法简单判断了一下接口返回值是否是指定类型的。如果想要进一步判断是否将接口返回值转为期望的媒体类型还是需要调用canWriter方法 0 - 只支持Byte类型的也就是只支持接口返回值是byte类型的 1 - String只支持接口返回值是String类型的以下同理 2 - String 3 - Resource 4 - ResourceRegion 5 - DOMSource.class \ SAXSource.class) \ StAXSource.class \StreamSource.class \Source.class 6 - MultiValueMap 7 - truejackson2类继承了AbstractGenericHttpMessageConverter类这个类里面默认写死了为true 8 - true 9 - 支持注解方式xml处理的。 //AbstractJackson2HttpMessageConverter类判断能够转换目标类型的方法public boolean canWrite(Class? clazz, Nullable MediaType mediaType) {// 判断是否支持目标媒体类型if (!this.canWrite(mediaType)) {return false;} else {if (mediaType ! null mediaType.getCharset() ! null) {Charset charset mediaType.getCharset();if (!ENCODINGS.containsKey(charset.name())) {return false;}}ObjectMapper objectMapper this.selectObjectMapper(clazz, mediaType);if (objectMapper null) {return false;} else {AtomicReferenceThrowable causeRef new AtomicReference();// Jackson底层组件判断如果能够处理就返回trueif (objectMapper.canSerialize(clazz, causeRef)) {return true;} else {this.logWarningIfNecessary(clazz, (Throwable)causeRef.get());return false;}}}}// AbstractHttpMessageConverter类里面方法protected boolean canWrite(Nullable MediaType mediaType) {// 如果目标类型不为空循环遍历Jackson能够支持转换的类型一般有两个application/json和application/*jsonif (mediaType ! null !MediaType.ALL.equalsTypeAndSubtype(mediaType)) {Iterator var2 this.getSupportedMediaTypes().iterator();MediaType supportedMediaType;do {if (!var2.hasNext()) {return false;}supportedMediaType (MediaType)var2.next();// 这里主要就是对比浏览器接受类型和var2那个类型更加匹配} while(!supportedMediaType.isCompatibleWith(mediaType));return true;} else {// 如果目标类型为空也是支持的return true;}} // AbstractGenericHttpMessageConverter类里面的方法public final void write(T t, Nullable Type type, Nullable MediaType contentType, HttpOutputMessage outputMessage) throws IOException, HttpMessageNotWritableException {HttpHeaders headers outputMessage.getHeaders();// 设置默认响应头为目标响应类型this.addDefaultHeaders(headers, t, contentType);if (outputMessage instanceof StreamingHttpOutputMessage) {StreamingHttpOutputMessage streamingOutputMessage (StreamingHttpOutputMessage)outputMessage;streamingOutputMessage.setBody((outputStream) - {this.writeInternal(t, type, new HttpOutputMessage() {public OutputStream getBody() {return outputStream;}public HttpHeaders getHeaders() {return headers;}});});} else {// 这里就会跳转到jackson里面的writeInternal方法进行json转换AbstractJackson2HttpMessageConverter至于具体是如何进行转化的这个就是Jackson的底层原理了this.writeInternal(t, type, outputMessage);// 到这里就完成了转化并且写入到了响应流当中outputMessage.getBody().flush();}} MappingJackson2HttpMessageConverter 把对象转为JSON利用底层的jackson的objectMapper转换的  总结 一、返回值处理器判断是否支持这种类型返回值 supportsReturnType 二、返回值处理器调用 handleReturnValue 进行处理 三、RequestResponseBodyMethodProcessor 可以处理返回值标了ResponseBody 注解的。 1. 利用 MessageConverters 进行处理 将数据写为json         1、内容协商浏览器默认会以请求头的方式告诉服务器他能接受什么样的内容类型         2、服务器最终根据自己自身的能力决定服务器能生产出什么样内容类型的数据         3、SpringMVC会挨个遍历所有容器底层的 HttpMessageConverter 看谁能处理 1、得到MappingJackson2HttpMessageConverter可以将对象写为json2、利用MappingJackson2HttpMessageConverter将对象转为json再写出去。
http://www.tj-hxxt.cn/news/131855.html

相关文章:

  • 上海seo网站优化软件ui设计培训班学费
  • 句容市网站seo优化排名wordpress 模版安装
  • 珠海网站建设 金蝶门户网站简单模板
  • 哈尔滨专业网站制作设计盈世企业邮箱
  • 付费阅读网站代码查信息的网站有哪些
  • 怎样创作网站精湛的企业网站建设
  • 杭州建设职业学校官方网站google海外推广
  • 国家工信部网站备案加盟型网站建设
  • 自己怎样建立网站另外网站是做的IPv4还是IPv6
  • 烟台网站建设便宜臻动传媒长沙企业网站模板
  • 成都自助建站模板全国水利建设市场信用信息平台门户网站
  • 网站服务器容量苏州外贸网站建设公司价格
  • 沙井做网站公司微信商城开发用华网天下卓越
  • 大兴高端网站建设wordpress的模板修改在哪个文件夹
  • 怎么自学网站建设水墨风格网站源码
  • 广西南宁做网站wordpress去掉分类目录
  • 建设部一建注册公示网站品牌建设管理办法
  • 陕西陕煤建设集团有限公司网站做关于家乡的网站
  • 中兴建设有限公司网站php+网站开发案例教程
  • 苏州企业网站建设服务中心无锡市锡山区建设局网站
  • 怎么让网站被百度收录沈阳男科医院哪家有名
  • 泛站群成都网红景点
  • 网站开发网站源码建视频网站系统吗
  • 网站做兼容处理怎么设置商务网站创建方案
  • 网站后台管理界面代码桂林象鼻山在哪
  • asp 网站信箱模板成立公司名字大全
  • 黄埔定制型网站建设结构设计软件有哪些
  • 学做沪江网站要多久360免费建站系统
  • 网站建设软件开发网站名称怎么备案
  • 规划网站开发总体方案找小程序