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

网站建设描述怎么写营销团队

网站建设描述怎么写,营销团队,同源大厦 网站建设,安康微网站建设目录 1:静态资源 1.1:静态资源访问 1.2:静态资源源码解析-到WebMvcAutoConfiguration 2:Rest请求绑定(设置put和delete) 2.1:代码实例 2.2:源码分析到-WebMvcAutoConfiguratio…

目录

1:静态资源

1.1:静态资源访问

1.2:静态资源源码解析-到WebMvcAutoConfiguration

2:Rest请求绑定(设置put和delete)

2.1:代码实例

2.2:源码分析到-WebMvcAutoConfiguration

3:请求参数处理

3.1:代码实例

3.2:转发重定向

3.2:源码分析到-DispatcherServlet

4:响应返回值处理

4.1:代码实例

4.2:源码分析到-DispatcherServlet


1:静态资源

1.1:静态资源访问

在springBoot项目中,我们首先来查看静态资源的访问位置,当我们配置项目,我们直接访问项目可以查看这些路径中的资源。

一个问题:

1:我们怎么知道静态资源放到哪里可以直接访问?

首先查看项目路径和配置文件如下


#默认静态资源访问路径  默认路径路径是/static(或/public或/resources或/META-INF/resources) #3.png路径错误访问不了
spring.mvc.static-path-pattern=/**
##修改静态资源访问路径 http://localhost:8080/res/4.png 静态资源前边必须加 res 和文件路径无关
#配置自定义路径  欢迎页面进不来 需要http://localhost:8080/res/index.html
#spring.mvc.static-path-pattern=/res/**上边的下边的二选一配置即可#自定义静态资源位置 add-mappings=false 禁用掉静态资源访问
spring.web.resources.add-mappings=true#静态资源缓存 默认是秒
spring.web.resources.cache.period=1001
#自定义 静态资源缓存 会覆盖掉系统默认的静态资源路径
spring.web.resources.static-locations=classpath:/自定义静态资源路径/#开启rest请求 WebMvcAutoConfiguration中查看源码
spring.mvc.hiddenmethod.filter.enabled=true

然后访问浏览器

http://localhost:8080/   进入static下边的index.html

http://localhost:8080/1.png 或者2.png 4.png都可以访问,但是3.png不行 

1.2:静态资源源码解析-到WebMvcAutoConfiguration

回到上边的问题,我们怎么知道静态资源应该放到哪里?可以顺利访问呢?

查看源码如下,主要看第一的解释,所以3.png的路径不对 访问不了

 @Configuration(proxyBeanMethods = false)@Import(WebMvcAutoConfiguration.EnableWebMvcConfiguration.class)//第一:WebMvcProperties.class spring.mvc 配置//默认静态资源访问路径  默认路径路径是/static(或/public或/resources或/META-INF/resources) 3.png路径错误访问不了//spring.mvc.static-path-pattern=/*//修改静态资源访问路径 http://localhost:8080/res/4.png 静态资源前边必须加res,和文件路径无关,配置自定义路径,欢迎页面进不来//#spring.mvc.static-path-pattern=/res/**//第二:WebProperties.class spring.web 配置
//    自定义静态资源位置 add-mappings=false 禁用掉静态资源访问
//    spring.web.resources.add-mappings=true
//    静态资源缓存 默认是秒
//    spring.web.resources.cache.period=1001
//    spring.web.resources.static-locations=classpath:/自定义静态资源路径/
//    开启rest请求 WebMvcAutoConfiguration中查看源码
//    spring.mvc.hiddenmethod.filter.enabled=true@EnableConfigurationProperties({ WebMvcProperties.class, WebProperties.class })@Order(0)public static class WebMvcAutoConfigurationAdapter implements WebMvcConfigurer, ServletContextAware {//此处代码省略public WebMvcAutoConfigurationAdapter(WebProperties webProperties, WebMvcProperties mvcProperties,ListableBeanFactory beanFactory, ObjectProvider<HttpMessageConverters> messageConvertersProvider,ObjectProvider<WebMvcAutoConfiguration.ResourceHandlerRegistrationCustomizer> resourceHandlerRegistrationCustomizerProvider,ObjectProvider<DispatcherServletPath> dispatcherServletPath,ObjectProvider<ServletRegistrationBean<?>> servletRegistrations) {//在getResources() 可以看到默认的访问路径是
//            private static final String[] CLASSPATH_RESOURCE_LOCATIONS = { "classpath:/META-INF/resources/",
//                    "classpath:/resources/", "classpath:/static/", "classpath:/public/" };this.resourceProperties = webProperties.getResources();this.mvcProperties = mvcProperties;this.beanFactory = beanFactory;this.messageConvertersProvider = messageConvertersProvider;this.resourceHandlerRegistrationCustomizer = resourceHandlerRegistrationCustomizerProvider.getIfAvailable();this.dispatcherServletPath = dispatcherServletPath;this.servletRegistrations = servletRegistrations;this.mvcProperties.checkConfiguration();}//静态资源文件路径 处理方法public void addResourceHandlers(ResourceHandlerRegistry registry) {if (!this.resourceProperties.isAddMappings()) {logger.debug("Default resource handling disabled");return;}addResourceHandler(registry, "/webjars/**", "classpath:/META-INF/resources/webjars/");addResourceHandler(registry, this.mvcProperties.getStaticPathPattern(), (registration) -> {//resourceProperties.getStaticLocations() 自己不配置 默认是系统的静态资源路径//resourceProperties.getStaticLocations() 自己配置的话自定义的文件路径//spring.web.resources.static-locations=classpath:/自定义静态资源路径/registration.addResourceLocations(this.resourceProperties.getStaticLocations());if (this.servletContext != null) {ServletContextResource resource = new ServletContextResource(this.servletContext, SERVLET_LOCATION);registration.addResourceLocations(resource);}});}

源码分析我们知道在WebMvcAutoConfiguration类中,默认了静态资源的位置,所以才可以直接访问的。如果自己配置了自定义的静态资源,那么系统默认的失效,以自己为准。

2:Rest请求绑定(设置put和delete)

2.1:代码实例

Java代码如下:

@RestController
public class RestControllerTest {@GetMapping(value = "user")public String get() {System.out.println("get请求!");return "get请求!";}@PostMapping(value = "user")public String post() {System.out.println("post请求!");return "post请求!";}@PutMapping(value = "user")public String put() {System.out.println("put请求!");return "put请求!";}@DeleteMapping(value = "user")public String delete() {System.out.println("delete请求!");return "delete请求!";}
}

html表单如下:

<form method="get" action="user"><input type="submit" value="get提交">
</form><form method="post" action="user"><input type="submit" value="post提交">
</form><form method="post" action="user"><!-- 隐藏表单,设置除了get、post以外的表单属性,表单必须是post,name必须是_method--><input name="method" value="PUT" hidden="hidden"><input type="submit" value="put提交">
</form><form method="post" action="user"><!-- 隐藏表单,设置除了get、post以外的表单属性,表单必须是post,name必须是_method--><input name="method" value="DELETE" hidden="hidden"><input type="submit" value="delete提交">
</form>

开启rest请求

#开启rest请求 WebMvcAutoConfiguration中查看源码
spring.mvc.hiddenmethod.filter.enabled=true

结果如下:点击put,到后台的put的Controller

 总结:表单要有隐藏域,name默认是_method,提交方式是post

2.2:源码分析到WebMvcAutoConfiguration

//如果没有HiddenHttpMethodFilter的bean
//如果没有开启配置 默认是spring.mvc.hiddenmethod.filter=false 
//不会创建HiddenHttpMethodFilter 只有配置了true 才会执行下边的代码//默认spring.mvc.hiddenmethod.filter=false 没有开启处理Rest的filter@Bean@ConditionalOnMissingBean(HiddenHttpMethodFilter.class)@ConditionalOnProperty(prefix = "spring.mvc.hiddenmethod.filter", name = "enabled")public OrderedHiddenHttpMethodFilter hiddenHttpMethodFilter() {return new OrderedHiddenHttpMethodFilter();}//HiddenHttpMethodFilter 代码分析/** 默认的name参数必须是_method */public static final String DEFAULT_METHOD_PARAM = "_method";private String methodParam = DEFAULT_METHOD_PARAM;@Overrideprotected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)throws ServletException, IOException {HttpServletRequest requestToUse = request;//代码分析 form表单只有post才能设置 put delete请求if ("POST".equals(request.getMethod()) && request.getAttribute(WebUtils.ERROR_EXCEPTION_ATTRIBUTE) == null) {
//获取input标签中的 name= "_method" 的属性 这里是put deleteString paramValue = request.getParameter(this.methodParam);if (StringUtils.hasLength(paramValue)) {String method = paramValue.toUpperCase(Locale.ENGLISH);
//大小写转换  装饰器模式 创建新的HttpMethodRequestWrapper 这里是装饰器模式request
//ALLOWED_METHODS=(delete,put,patch)if (ALLOWED_METHODS.contains(method)) {requestToUse = new HttpMethodRequestWrapper(request, method);}}}
//执行过滤链 这里调用链模式filterChain.doFilter(requestToUse, response);}//分割线 我的表单时name是method不是_method这个时候就需要我们配置自己的HiddenHttpMethodFilter@Beanpublic HiddenHttpMethodFilter hiddenHttpMethodFilter(){HiddenHttpMethodFilter hiddenHttpMethodFilter = new HiddenHttpMethodFilter();
//设置自定义的name为method 这个时候会覆盖系统的_method hiddenHttpMethodFilter.setMethodParam("method");return hiddenHttpMethodFilter;}

3:请求参数处理

3.1:代码实例

@RestController
public class 请求参数Controller {/*** 路径参数 @PathVariable* 请求头 @RequestHeader* 方法参数 @RequestParam* cookie参数 @CookieValue* 他们都能封装成map 但是map有缺陷 key想同会丢失参数** @RequestParam Map<String, String> paramMap 会丢失key一致的参数 多个likes 只能保存一个**///http://localhost:8080/t1/1/blog/test?name=张三&age=28&likes=语文&likes=数学@GetMapping(value = "/t1/{id}/blog/{type}")public Map t1(@PathVariable("id") Integer id,//绑定指定的路径id到参数@PathVariable("type") String type,//绑定指定的路径type到参数@PathVariable Map<String,String> pathMap,//绑定所有的路径参数到Map@RequestHeader("Accept") String accept, //绑定指定的head到参数@RequestHeader Map<String,String> headMap, //绑定所有的head到Map@RequestParam(value = "name",required = false) String name,//绑定指定参数@RequestParam(value = "age",required = false) Integer age,//绑定指定参数@RequestParam(value = "likes",required = false) List<String> likes,//绑定指定参数到likes@RequestParam Map<String, String> paramMap, //绑定所有的参数到Map 因为是map类型 会丢失key一致的参数 比如like@CookieValue(value = "__utma",required = false) String cookieId,@CookieValue(value = "__utmv",required = false) Cookie cookie) {System.out.println("=======请求路径参数==========");System.out.println("rest路径参数id:"+id);System.out.println("rest路径参数type:"+type);pathMap.forEach((key,value)-> System.out.println(key+"=="+value));System.out.println();System.out.println("=======请求头参数==========");System.out.println("rest路径head参数Accept:"+accept);headMap.forEach((key,value)->{System.out.println(key+"=="+value);});System.out.println();System.out.println("=======请求参数==========");System.out.println("rest路径请求参数name:"+name);System.out.println("rest路径请求参数age:"+age);for (String like : likes) {System.out.println("rest路径请求参数like:"+like);}paramMap.forEach((key,value)->{System.out.println(key+"=="+value);});System.out.println();System.out.println("=======请求cookie==========");System.out.println("rest路径请求参数cookie:"+cookieId);System.out.println(cookie.getName()+":"+cookie.getValue());Map<String, Object> map = new HashMap();map.put("请求","参数");return map;}/*** @RequestBody 获取post的请求体参数*///http://localhost:8080/t2/2 body的参数postMan 自己创造@PostMapping(value = "/t2/{id}")public Map t2(@PathVariable("id") Integer id,@RequestParam("name") String name,@RequestBody String body //获取post的请求体参数) {System.out.println("=======post获取请求体==========");System.out.println("rest路径参数id:"+id);System.out.println("rest请求参数name:"+name);System.out.println("rest请求body的参数:"+body);Map<String, Object> map = new HashMap();map.put("请求","参数");return map;}/*** 矩阵变量 @PathVariable*  http://localhost:8080/t3/2;low=34;like=eng;like=yuwen*  http://localhost:8080/t3/1;low=34;likes=eng;likes=yuwen/2;demo=dd*/@GetMapping(value = "/t3/{path}/{path1}")public Map t3(@PathVariable("path") String path,@PathVariable("path1") String path1,@MatrixVariable(value = "low",pathVar = "path") String low,@MatrixVariable(value = "likes",pathVar = "path") List<String> likes,@MatrixVariable(value = "demo",pathVar = "path1") String demo) {System.out.println("=======get获取矩阵变量==========");System.out.println("rest路径矩阵变量path:"+path);System.out.println("rest路径矩阵变量path1:"+path1);System.out.println("rest路径矩阵变量demo:"+demo);System.out.println("rest路径矩阵变量low:"+low);for (String like : likes) {System.out.println("rest路径矩阵变量like:"+like);}Map<String, Object> map = new HashMap();map.put("请求","参数");return map;}/*** 请求参数转换实体* http://localhost:8080/person?id=1&name=张三&date=2023-03-04 14:30:38&cat.id=2&cat.name=波斯猫*/@GetMapping("/person")public Person get(Person person){System.out.println(person);return person;}
}

3.2:转发重定向

@Controller
public class 转发重定向Controller {/**** http://localhost:8080/request1* 转发测试 forward  不能使用@RestController* @RequestAttribute(value = "name")  绑定转发的请求属性** http://localhost:8080/request1*/@GetMapping("/request1")public String request1(HttpServletRequest request){System.out.println("进入转发请求1");request.setAttribute("name","中文");return "forward:/request2";}@GetMapping("/request2")@ResponseBodypublic String request2(@RequestAttribute(value = "name") String name){System.out.println("进入转发请求2");System.out.println("获取转发的请求参数name:"+name);return "转发";}/**** http://localhost:8080/request11** 参数的map、model 的数据会放到request域中,相当于setAttribute*/@GetMapping("/request11")public String request11(HttpServletRequest request, HttpServletResponse response, Map map, Model model){System.out.println("进入转发请求11");map.put("map","hello map");model.addAttribute("model","hello model");request.setAttribute("name","中文");Cookie cookie=new Cookie("cookie","cookie_value");response.addCookie(cookie);return "forward:/request22";}@GetMapping("/request22")@ResponseBodypublic String request22(@RequestAttribute(value = "name") String name,HttpServletRequest request){System.out.println("进入转发请求22");System.out.println("获取转发的请求参数name:"+name);System.out.println("request获取属性name:"+request.getAttribute("name"));System.out.println("request获取属性map:"+request.getAttribute("map"));System.out.println("request获取属性model:"+request.getAttribute("model"));Cookie[] cookies = request.getCookies();for (Cookie cookie : cookies) {System.out.println(cookie.getName()+":"+cookie.getValue());}return "转发";}/*** http://localhost:8080/request3* 重定向测试 redirect* @RequestAttribute(value = "name") 绑定指定的值* @return*/@GetMapping("/request3")public String request3(HttpServletRequest request){System.out.println("进入重定向请求1");request.setAttribute("name","中文");return "redirect:request4";}@GetMapping("/request4")@ResponseBodypublic String request4(String name,String aa){System.out.println("进入重定向请求2");System.out.println("获取重定向的请求参数name:"+name);return "重定向";}
}

3.2:源码分析到-DispatcherServlet

我们以一下代码做分析,将请求参数封装到Person

 /*** 请求参数转换实体* http://localhost:8080/person?id=1&name=张三&date=2023-03-04 14:30:38&cat.id=2&cat.name=波斯猫*/@GetMapping("/person")public Person get(Person person){//这一行输出代码打断点 debug运行System.out.println(person);return person;}

在源码分析之前,我想知道请求流程是怎么处理的,请求的参数是怎么绑定到我们指定的参数、或者pojo、或者map中的

我们先上一张SpringWeb的执行流程图,然后格局源码分析。

 我们查看源码

1:调用DispatcherServlet的doService()方法,DispatcherServlet也是个Servlet,从继承关系层层调用到doService方法

2:doService()方法调用了doDispatch(request, response);这个方法是核心,我们查看代码分析

从源码结合上边的流程图可以详细的看到具体流程

  //核心代码protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {HttpServletRequest processedRequest = request;HandlerExecutionChain mappedHandler = null;boolean multipartRequestParsed = false;WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);try {ModelAndView mv = null;Exception dispatchException = null;try {//检查是不是Multipart 文件上传的请求processedRequest = checkMultipart(request);multipartRequestParsed = (processedRequest != request);// 确认当前的请求 从5个handlerMapping中匹配到合适//这里就是RequestHandlerMapping 因为使用了@RequestMapping注解//这5个handlerMapping 分别是Request、welcome、BeanNamesUrl、RouterFunction等handlerMappingmappedHandler = getHandler(processedRequest);if (mappedHandler == null) {noHandlerFound(processedRequest, response);return;}// 根据前边的mappedHandler 找到HandlerAdapter//从4个中Adapter找到了RequestMappingHandlerAdapter 还是因为使用了@RequestMapping注解HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());// Process last-modified header, if supported by the handler.String method = request.getMethod();boolean isGet = HttpMethod.GET.matches(method);if (isGet || HttpMethod.HEAD.matches(method)) {long lastModified = ha.getLastModified(request, mappedHandler.getHandler());if (new ServletWebRequest(request, response).checkNotModified(lastModified) && isGet) {return;}}//执行拦截器的Pre方法 在Controller前执行if (!mappedHandler.applyPreHandle(processedRequest, response)) {return;}//执行真正的controller方法 反射调用//因为反射知道了Controller方法的参数和类型 所以我们就可以把request的参数//通过反射绑定到Controller的方法参数中  这就是核心原理//执行流程 核心方法 重点五颗星  具体的跳转流程已经标志 不做代码截取//handle->(没哈意思,只是跳转)handleInternal->(没哈意思,只是跳转)invokeHandlerMethod->(加载参数解析器27个、返回值参数解析器15个)invokeAndHandle->(调用执行invokeForRequest方法,获取返回值)invokeForRequest->(调用执行Controller方法,获取返回值)执行绑定参数方法getMethodArgumentValues->(对方法的参数遍历 调用参数绑定方法) 返回绑定好的pojoresolveArgument(逐个参数进行绑定,调用指定的参数解析器) 绑定到Pojo 返回mv = ha.handle(processedRequest, response, mappedHandler.getHandler());if (asyncManager.isConcurrentHandlingStarted()) {return;}applyDefaultViewName(processedRequest, mv);//调用拦截器的后置方法PostHandle controller后执行执行mappedHandler.applyPostHandle(processedRequest, response, mv);}catch (Exception ex) {dispatchException = ex;}catch (Throwable err) {// As of 4.3, we're processing Errors thrown from handler methods as well,// making them available for @ExceptionHandler methods and other scenarios.dispatchException = new NestedServletException("Handler dispatch failed", err);}processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);}catch (Exception ex) {triggerAfterCompletion(processedRequest, response, mappedHandler, ex);}catch (Throwable err) {triggerAfterCompletion(processedRequest, response, mappedHandler,new NestedServletException("Handler processing failed", err));}finally {if (asyncManager.isConcurrentHandlingStarted()) {// Instead of postHandle and afterCompletionif (mappedHandler != null) {//调用拦截器的after方法 最终执行mappedHandler.applyAfterConcurrentHandlingStarted(processedRequest, response);}}else {// Clean up any resources used by a multipart request.if (multipartRequestParsed) {cleanupMultipart(processedRequest);}}}}

 handlerMapping(5个)和handlerAdapters(4个)

 参数解析器(27个,对应各种注解比如@PathVariable、 @RequestHeader、@RequestParam、@CookieValue等注解的解析器)

返回值解析器(15个,对应ModelAndView、model、@responseBody的注解的解析器)

 

4:响应返回值处理

主要分析响应的返回值怎么在DispatcherServlet的doDispatch()方法中的执行流程

4.1:代码实例

 /*** http://localhost:8080/response/p1* *  @ResponseBody 注解返回json*/@GetMapping("/response/p1")@ResponseBodypublic Person p1(){Person person=new Person();person.setId(1);person.setName("麻子");person.setDate(new Date());return person;}

4.2:源码分析到-DispatcherServlet

源码分析第一步:执行controller方法,得到返回值。

源码分析第二步:根据返回值找到15个返回值处理器,遍历根据注解@ResponseBody,找到合适的返回值处理器

源码分析第三步:根据返回值处理器,去他的方法里边处理返回值

源码分析第四步:选择消息转换器(转换器很多,这里是jackson的消息转换器,把pojo转换成json)
 

//第一步 :执行controller方法,得到返回值public void invokeAndHandle (ServletWebRequest webRequest, ModelAndViewContainer mavContainer,Object...providedArgs) throws Exception {//这里就是执行controller方法得到的返回值Object returnValue = invokeForRequest(webRequest, mavContainer, providedArgs);setResponseStatus(webRequest);if (returnValue == null) {if (isRequestNotModified(webRequest) || getResponseStatus() != null || mavContainer.isRequestHandled()) {disableContentCachingIfNecessary(webRequest);mavContainer.setRequestHandled(true);return;}} else if (StringUtils.hasText(getResponseStatusReason())) {mavContainer.setRequestHandled(true);return;}mavContainer.setRequestHandled(false);Assert.state(this.returnValueHandlers != null, "No return value handlers");try {//将返回值封装成为自己指定的类型 比如json 或者xml等this.returnValueHandlers.handleReturnValue(returnValue, getReturnValueType(returnValue), mavContainer, webRequest);} catch (Exception ex) {if (logger.isTraceEnabled()) {logger.trace(formatErrorForReturnValue(returnValue), ex);}throw ex;}}//第二步:根据返回值找到15个返回值处理器,遍历 根据注解@ResponseBody,找到合适的返回值处理器@Overridepublic void handleReturnValue (@Nullable Object returnValue, MethodParameter returnType,ModelAndViewContainer mavContainer, NativeWebRequest webRequest) throws Exception {//在很多的返回值(15个如下图)处理器中选择合适的 返回json使用的是//RequestResponseBodyMethodProcessor 处理返回json的处理器HandlerMethodReturnValueHandler handler = selectHandler(returnValue, returnType);if (handler == null) {throw new IllegalArgumentException("Unknown return value type: " + returnType.getParameterType().getName());}//指定的json返回值处理方法handler.handleReturnValue(returnValue, returnType, mavContainer, webRequest);}//第三步:注解 @ResponseBody的方法 使用RequestResponseBodyMethodProcessor处理器@Overridepublic void handleReturnValue (@Nullable Object returnValue, MethodParameter returnType,ModelAndViewContainer mavContainer, NativeWebRequest webRequest)throws IOException, HttpMediaTypeNotAcceptableException, HttpMessageNotWritableException {mavContainer.setRequestHandled(true);ServletServerHttpRequest inputMessage = createInputMessage(webRequest);ServletServerHttpResponse outputMessage = createOutputMessage(webRequest);// Try even with null return value. ResponseBodyAdvice could get involved.//消息转化器 处理成json的方法writeWithMessageConverters(returnValue, returnType, inputMessage, outputMessage);}//第四步:选择消息转换器(转换器很多,这里是jackson的消息转换器,把pojo转换成json)protected <T > void writeWithMessageConverters (@Nullable T value, MethodParameter returnType,ServletServerHttpRequest inputMessage, ServletServerHttpResponse outputMessage)throws IOException, HttpMediaTypeNotAcceptableException, HttpMessageNotWritableException {Object body;Class<?> valueType;Type targetType;if (value instanceof CharSequence) {body = value.toString();valueType = String.class;targetType = String.class;} else {body = value;//value就是返回值 比如pojo的User的值valueType = getReturnValueType(body, returnType);//返回值类型UsertargetType = GenericTypeResolver.resolveType(getGenericType(returnType), returnType.getContainingClass());}if (isResourceType(value, returnType)) {outputMessage.getHeaders().set(HttpHeaders.ACCEPT_RANGES, "bytes");if (value != null && inputMessage.getHeaders().getFirst(HttpHeaders.RANGE) != null &&outputMessage.getServletResponse().getStatus() == 200) {Resource resource = (Resource) value;try {List<HttpRange> 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 ex) {outputMessage.getHeaders().set(HttpHeaders.CONTENT_RANGE, "bytes */" + resource.contentLength());outputMessage.getServletResponse().setStatus(HttpStatus.REQUESTED_RANGE_NOT_SATISFIABLE.value());}}}MediaType selectedMediaType = null;MediaType contentType = outputMessage.getHeaders().getContentType();boolean isContentTypePreset = contentType != null && contentType.isConcrete();if (isContentTypePreset) {if (logger.isDebugEnabled()) {logger.debug("Found 'Content-Type:" + contentType + "' in response");}selectedMediaType = contentType;} else {HttpServletRequest request = inputMessage.getServletRequest();List<MediaType> acceptableTypes;try {//这里是request的accept的类型 表示浏览器接受的类型 9个 逗号分割// Accept: text/html,application/xhtml+xml,application/xml;q=0.9,// image/avif,image/webp,image/apng,*/*;q=0.8,// application/signed-exchange;v=b3;q=0.7acceptableTypes = getAcceptableMediaTypes(request);} catch (HttpMediaTypeNotAcceptableException ex) {int series = outputMessage.getServletResponse().getStatus() / 100;if (body == null || series == 4 || series == 5) {if (logger.isDebugEnabled()) {logger.debug("Ignoring error response content (if any). " + ex);}return;}throw ex;}//这里就是服务器生产数据的类型//application.json等4个List<MediaType> producibleTypes = getProducibleMediaTypes(request, valueType, targetType);if (body != null && producibleTypes.isEmpty()) {throw new HttpMessageNotWritableException("No converter found for return value of type: " + valueType);}List<MediaType> mediaTypesToUse = new ArrayList<>();//服务器产出类型和浏览器接受类型的匹配for (MediaType requestedType : acceptableTypes) {for (MediaType producibleType : producibleTypes) {if (requestedType.isCompatibleWith(producibleType)) {mediaTypesToUse.add(getMostSpecificMediaType(requestedType, producibleType));}}}if (mediaTypesToUse.isEmpty()) {if (logger.isDebugEnabled()) {logger.debug("No match for " + acceptableTypes + ", supported: " + producibleTypes);}if (body != null) {throw new HttpMediaTypeNotAcceptableException(producibleTypes);}return;}MediaType.sortBySpecificityAndQuality(mediaTypesToUse);for (MediaType mediaType : mediaTypesToUse) {if (mediaType.isConcrete()) {selectedMediaType = mediaType;break;} else if (mediaType.isPresentIn(ALL_APPLICATION_MEDIA_TYPES)) {selectedMediaType = MediaType.APPLICATION_OCTET_STREAM;break;}}if (logger.isDebugEnabled()) {logger.debug("Using '" + selectedMediaType + "', given " +acceptableTypes + " and supported " + producibleTypes);}}if (selectedMediaType != null) {selectedMediaType = selectedMediaType.removeQualityValue();//这里就是消息转换器的类型messageConverters 遍历 有转json、xml、Model、modelView、view等好多个//找到转jackson的消息转换器for (HttpMessageConverter<?> converter : this.messageConverters) {GenericHttpMessageConverter genericConverter = (converter instanceof GenericHttpMessageConverter ?(GenericHttpMessageConverter<?>) converter : null);if (genericConverter != null ?((GenericHttpMessageConverter) converter).canWrite(targetType, valueType, selectedMediaType) :converter.canWrite(valueType, selectedMediaType)) {body = getAdvice().beforeBodyWrite(body, returnType, selectedMediaType,(Class<? extends HttpMessageConverter<?>>) converter.getClass(),inputMessage, outputMessage);if (body != null) {Object theBody = body;LogFormatUtils.traceDebug(logger, traceOn ->"Writing [" + LogFormatUtils.formatValue(theBody, !traceOn) + "]");addContentDispositionHeader(inputMessage, outputMessage);if (genericConverter != null) {genericConverter.write(body, targetType, selectedMediaType, outputMessage);} else {//这里就是真正的调用jacksonConverter消息转换器 将实体转换成json 放到Response中//依赖ObjectMapper mapper = new ObjectMapper();//String json = mapper.writeValueAsString(User);((HttpMessageConverter) converter).write(body, selectedMediaType, outputMessage);}} else {if (logger.isDebugEnabled()) {logger.debug("Nothing to write: null body");}}return;}}}if (body != null) {Set<MediaType> producibleMediaTypes =(Set<MediaType>) inputMessage.getServletRequest().getAttribute(HandlerMapping.PRODUCIBLE_MEDIA_TYPES_ATTRIBUTE);if (isContentTypePreset || !CollectionUtils.isEmpty(producibleMediaTypes)) {throw new HttpMessageNotWritableException("No converter for [" + valueType + "] with preset Content-Type '" + contentType + "'");}throw new HttpMediaTypeNotAcceptableException(getSupportedMediaTypes(body.getClass()));}}}

响应的参数解析的返回值处理器如下15个

浏览器接受格式、服务器返回格式、交集 

 

 消息转换器10个(可以处理String、byte、json、Resource等) 

http://www.ds6.com.cn/news/3791.html

相关文章:

  • cnblogs wordpress厦门seo招聘
  • 哪个酒店网站做的好看的短视频seo优化排名
  • 内网电脑做网站seo云优化外包
  • wordpress 页面url重写网站搜索引擎优化案例
  • 网站不清理缓存搜索引擎seo优化怎么做
  • 淘宝客网站域名备案吗品牌策划方案
  • wordpress 插件角色赣州seo
  • 大连网站开发费多少钱张北网站seo
  • 俄罗斯乌克兰地图seo网络营销公司
  • 建设网站有哪些微信软文
  • 中国江门网北京seo百度推广
  • 网站架构 seowin10优化工具
  • 重庆企业网站制作新人跑业务怎么找客户
  • 外国网站做问卷调查挣钱40个免费靠谱网站
  • 网站大全下载软件安装农产品推广方案
  • 网站开发合同范本电商网课
  • 销售系统软件抖音seo公司
  • 教做西餐的网站百度教育会员
  • 化妆品购物网站开发的意义seo模拟点击软件源码
  • 天津做网站找哪家公司seo怎么才能优化好
  • wordpress一键搭建泰安seo公司
  • 网络营销网站建设知识优化大师平台
  • 广州网站设计seo模拟点击工具
  • 苏州网站建设推广咨询平台石家庄关键词排名提升
  • 不用服务器怎么做网站济南网站建设公司选济南网络
  • php开源免费网站模板网络营销策划论文
  • 织梦做网站视频教程今日中央新闻
  • wap网站 什么意思优化推广服务
  • 专业优化网站建设百度搜索引擎关键词
  • 做网站建设与推广企业收录情况