国产亚洲精品福利在线无卡一,国产精久久一区二区三区,亚洲精品无码国模,精品久久久久久无码专区不卡

當(dāng)前位置: 首頁 > news >正文

北京十佳網(wǎng)站建設(shè)廣告網(wǎng)站大全

北京十佳網(wǎng)站建設(shè),廣告網(wǎng)站大全,網(wǎng)站維護(hù)建設(shè)招標(biāo),兩學(xué)一做 專題網(wǎng)站目錄 1、SpringMVC自動配置概覽 2、簡單功能分析 2.1、靜態(tài)資源訪問 1、靜態(tài)資源目錄 2、靜態(tài)資源訪問前綴 2.2、歡迎頁支持 2.3、自定義 Favicon 2.4、靜態(tài)資源配置原理 3、請求參數(shù)處理 0、請求映射 1、rest使用與原理 2、請求映射原理 1、普通參數(shù)與基本注解 …

f9676610780b25a2bbe4477df668b119.png

目錄

1、SpringMVC自動配置概覽?

2、簡單功能分析

2.1、靜態(tài)資源訪問

1、靜態(tài)資源目錄

2、靜態(tài)資源訪問前綴

2.2、歡迎頁支持

2.3、自定義 Favicon

2.4、靜態(tài)資源配置原理

3、請求參數(shù)處理

0、請求映射

1、rest使用與原理

2、請求映射原理

1、普通參數(shù)與基本注解

1.1、注解:

1.2、Servlet API:

1.3、復(fù)雜參數(shù):

1.4、自定義對象參數(shù):

2、POJO封裝過程

3、參數(shù)處理原理

3.1、HandlerAdapter(處理器映射器)

3.2、執(zhí)行目標(biāo)方法

?3.3、參數(shù)解析器-HandlerMethodArgumentResolver

3.4、返回值處理器

3.5、如何確定目標(biāo)方法每一個參數(shù)的值

3.5.1、循環(huán)所有參數(shù)解析器,看哪個支持解析這個參數(shù)

3.5.2、解析這個參數(shù)的值

3.5.3、解析自定義類型參數(shù)-封裝POJO

3.6、目標(biāo)方法執(zhí)行完成

4、數(shù)據(jù)響應(yīng)與內(nèi)容協(xié)商

1、響應(yīng)JSON

原理解析

1.2、SpringMVC到底支持哪些返回值

1.3、HTTPMessageConverter原理

2、內(nèi)容協(xié)商


1、SpringMVC自動配置概覽?

Spring Boot provides auto-configuration for Spring MVC that works well with most applications.(大多場景我們都無需自定義配置)

The auto-configuration adds the following features on top of Spring’s defaults:

  • Inclusion of ContentNegotiatingViewResolver and BeanNameViewResolver beans.
    • 內(nèi)容協(xié)商視圖解析器和BeanName視圖解析器
  • Support for serving static resources, including support for WebJars (covered later in this document)).
    • 靜態(tài)資源(包括webjars)
  • Automatic registration of Converter, GenericConverter, and Formatter beans.
    • 自動注冊 Converter,GenericConverter,Formatter
  • Support for HttpMessageConverters (covered later in this document).
    • 支持 HttpMessageConverters (后來我們配合內(nèi)容協(xié)商理解原理)
  • Automatic registration of MessageCodesResolver (covered later in this document).
    • 自動注冊 MessageCodesResolver (國際化用)
  • Static index.html support.
    • 靜態(tài)index.html 頁支持
  • Custom Favicon support (covered later in this document).
    • 自定義 Favicon
  • Automatic use of a ConfigurableWebBindingInitializer bean (covered later in this document).
    • 自動使用 ConfigurableWebBindingInitializer ,(DataBinder負(fù)責(zé)將請求數(shù)據(jù)綁定到JavaBean上)

If you want to keep those Spring Boot MVC customizations and make more MVC customizations (interceptors, formatters, view controllers, and other features), you can add your own @Configuration class of type WebMvcConfigurer but without @EnableWebMvc.

不用@EnableWebMvc注解。使用 @Configuration + WebMvcConfigurer 自定義規(guī)則

If you want to provide custom instances of RequestMappingHandlerMapping, RequestMappingHandlerAdapter, or ExceptionHandlerExceptionResolver, and still keep the Spring Boot MVC customizations, you can declare a bean of type WebMvcRegistrations and use it to provide custom instances of those components.

聲明 WebMvcRegistrations 改變默認(rèn)底層組件

If you want to take complete control of Spring MVC, you can add your own @Configuration annotated with @EnableWebMvc, or alternatively add your own @Configuration-annotated DelegatingWebMvcConfiguration as described in the Javadoc of @EnableWebMvc.

使用 @EnableWebMvc+@Configuration+DelegatingWebMvcConfiguration 全面接管SpringMVC

2、簡單功能分析

2.1、靜態(tài)資源訪問

1、靜態(tài)資源目錄

只要靜態(tài)資源放在類路徑下: called?/static?(or?/public?or?/resources?or?/META-INF/resources

訪問:當(dāng)前項目根目錄/ + 靜態(tài)資源名

原理:靜態(tài)映射/**

接收到請求,先到dispatcherServlet轉(zhuǎn)發(fā)找對應(yīng)的Controller,若找不到對應(yīng)的Controller就交給靜態(tài)資源處理器。若靜態(tài)資源處理器還找不到,就返回404響應(yīng)頁面。

改變默認(rèn)的靜態(tài)資源路徑:

spring:mvc:static-path-pattern: /res/**resources:static-locations: [classpath:/haha/]

2、靜態(tài)資源訪問前綴

為了方便讓攔截器直接放行靜態(tài)資源的訪問,可以給靜態(tài)資源的訪問配置一個統(tǒng)一的前綴。

默認(rèn)是無前綴的。

spring:mvc:static-path-pattern: /res/**

當(dāng)前項目 + static-path-pattern + 靜態(tài)資源名 = 靜態(tài)資源文件夾下找

示例:

原本請求路徑:http://localhost:8080/res/xq.png

加了訪問前綴后:http://localhost:8080/res/xq.png

2.2、歡迎頁支持

可以有兩種方式:靜態(tài)資源、動態(tài)請求處理。

  • 靜態(tài)資源路徑下:index.html
    • 可以配置靜態(tài)資源路徑
    • 但是不可以配置靜態(tài)資源的訪問前綴,會導(dǎo)致index.html不能被默認(rèn)訪問
spring:mvc:static-path-pattern: /res/** # 配置之后導(dǎo)致welcome page 功能失效resources:static-locations: [ classpath:/haha/ ]
  • 編寫controller處理 /index 請求

2.3、自定義 Favicon

訪問圖標(biāo)。favicon.ico 放在靜態(tài)資源目錄下即可。

2.4、靜態(tài)資源配置原理

  • SpringBoot啟動默認(rèn)加載 xxxAutoConfiguration 類(自動配置類)
  • SpringMVC的自動配置類 WebMvcAutoConfiguration。查看是否生效。
@Configuration(proxyBeanMethods = false
)
@ConditionalOnWebApplication(type = Type.SERVLET
)
@ConditionalOnClass({Servlet.class, DispatcherServlet.class, WebMvcConfigurer.class})
@ConditionalOnMissingBean({WebMvcConfigurationSupport.class})
@AutoConfigureOrder(-2147483638)
@AutoConfigureAfter({DispatcherServletAutoConfiguration.class, TaskExecutionAutoConfiguration.class, ValidationAutoConfiguration.class})
public class WebMvcAutoConfiguration {..
  • 查看自動配置類 給Spring容器中注冊了哪些東西
@Configuration(proxyBeanMethods = false)
@Import({WebMvcAutoConfiguration.EnableWebMvcConfiguration.class})
@EnableConfigurationProperties({WebMvcProperties.class, ResourceProperties.class})
@Order(0)
public static class WebMvcAutoConfigurationAdapter implements WebMvcConfigurer {
  • 配置文件的相關(guān)屬性和xxx進(jìn)行了綁定。
    • WebMvcProperties==spring.mvc、
    • ResourceProperties==spring.resources

1、配置類只有一個有參構(gòu)造器

有參構(gòu)造器的所有參數(shù)的值都會從容器中確定。

//ResourceProperties resourceProperties;獲取和spring.resources綁定的所有的值的對象
//WebMvcProperties mvcProperties 獲取和spring.mvc綁定的所有的值的對象
//ListableBeanFactory beanFactory Spring的beanFactory
//HttpMessageConverters 找到所有的HttpMessageConverters
//ResourceHandlerRegistrationCustomizer 找到 資源處理器的自定義器。=========
//DispatcherServletPath  
//ServletRegistrationBean   給應(yīng)用注冊Servlet、Filter....public WebMvcAutoConfigurationAdapter(ResourceProperties resourceProperties, WebMvcProperties mvcProperties,ListableBeanFactory beanFactory, ObjectProvider<HttpMessageConverters> messageConvertersProvider,ObjectProvider<ResourceHandlerRegistrationCustomizer> resourceHandlerRegistrationCustomizerProvider,ObjectProvider<DispatcherServletPath> dispatcherServletPath,ObjectProvider<ServletRegistrationBean<?>> servletRegistrations) {this.resourceProperties = resourceProperties;this.mvcProperties = mvcProperties;this.beanFactory = beanFactory;this.messageConvertersProvider = messageConvertersProvider;this.resourceHandlerRegistrationCustomizer = resourceHandlerRegistrationCustomizerProvider.getIfAvailable();this.dispatcherServletPath = dispatcherServletPath;this.servletRegistrations = servletRegistrations;}

2、資源處理的默認(rèn)規(guī)則

public void addResourceHandlers(ResourceHandlerRegistry registry) {if (!this.resourceProperties.isAddMappings()) {logger.debug("Default resource handling disabled");} else {Duration cachePeriod = this.resourceProperties.getCache().getPeriod();CacheControl cacheControl = this.resourceProperties.getCache().getCachecontrol().toHttpCacheControl();if (!registry.hasMappingForPattern("/webjars/**")) {this.customizeResourceHandlerRegistration(registry.addResourceHandler(new String[]{"/webjars/**"}).addResourceLocations(new String[]{"classpath:/META-INF/resources/webjars/"}).setCachePeriod(this.getSeconds(cachePeriod)).setCacheControl(cacheControl));}String staticPathPattern = this.mvcProperties.getStaticPathPattern();if (!registry.hasMappingForPattern(staticPathPattern)) {this.customizeResourceHandlerRegistration(registry.addResourceHandler(new String[]{staticPathPattern}).addResourceLocations(WebMvcAutoConfiguration.getResourceLocations(this.resourceProperties.getStaticLocations())).setCachePeriod(this.getSeconds(cachePeriod)).setCacheControl(cacheControl));}}
}

可以發(fā)現(xiàn)使用配置可以禁用靜態(tài)資源規(guī)則。

spring:
#  mvc:
#    static-path-pattern: /res/**resources:add-mappings: false   禁用所有靜態(tài)資源規(guī)則
@ConfigurationProperties(prefix = "spring.resources", ignoreUnknownFields = false)
public class ResourceProperties {private static final String[] CLASSPATH_RESOURCE_LOCATIONS = { "classpath:/META-INF/resources/","classpath:/resources/", "classpath:/static/", "classpath:/public/" };/*** Locations of static resources. Defaults to classpath:[/META-INF/resources/,* /resources/, /static/, /public/].*/private String[] staticLocations = CLASSPATH_RESOURCE_LOCATIONS;

3、歡迎頁的處理規(guī)則

?? ?HandlerMapping:處理器映射器。保存了每一個Handler能處理哪些請求。?? ?

@Bean
public WelcomePageHandlerMapping welcomePageHandlerMapping(ApplicationContext
applicationContext, FormattingConversionService mvcConversionService, ResourceUrlProvider mvcResourceUrlProvider) {WelcomePageHandlerMapping welcomePageHandlerMapping = new WelcomePageHandlerMapping(new TemplateAvailabilityProviders(applicationContext), applicationContext, this.getWelcomePage(), this.mvcProperties.getStaticPathPattern());welcomePageHandlerMapping.setInterceptors(this.getInterceptors(mvcConversionService, mvcResourceUrlProvider));welcomePageHandlerMapping.setCorsConfigurations(this.getCorsConfigurations());return welcomePageHandlerMapping;
}
WelcomePageHandlerMapping(TemplateAvailabilityProviders templateAvailabilityProviders,ApplicationContext applicationContext, Optional<Resource> welcomePage, String staticPathPattern) {if (welcomePage.isPresent() && "/**".equals(staticPathPattern)) {//要用歡迎頁功能,必須是/**logger.info("Adding welcome page: " + welcomePage.get());setRootViewName("forward:index.html");}else if (welcomeTemplateExists(templateAvailabilityProviders, applicationContext)) {// 調(diào)用Controller  /indexlogger.info("Adding welcome page template: index");setRootViewName("index");}
}

4、favicon

瀏覽器會發(fā)送 /favicon 來獲取圖標(biāo),整個session期間不再獲取。

這就解釋了,在配置了靜態(tài)資源前綴下,瀏覽器獲取不到的ico的原因。

3、請求參數(shù)處理

0、請求映射

1、rest使用與原理

  • @xxxMapping;
  • Rest風(fēng)格支持(使用HTTP請求方式動詞來表示對資源的操作
    • 以前:/getUser ? 獲取用戶? /deleteUser 刪除用戶 ? /editUser ?修改用戶 ? /saveUser 保存用戶
    • 現(xiàn)在: /user GET-獲取用戶 DELETE-刪除用戶 PUT-修改用戶 POST-保存用戶
  • 核心Filter;HiddenHttpMethodFilter
    • 表單method=post,隱藏域 _method=put

@RestController
public class HelloController {@RequestMapping("/bug.jpg")public String hello() {return "hello";}@RequestMapping(value = "/user",method = RequestMethod.GET)public String getUser(){return "GET-張三";}@RequestMapping(value = "/user",method = RequestMethod.POST)public String saveUser(){return "POST-張三";}@RequestMapping(value = "/user",method = RequestMethod.PUT)public String putUser(){return "PUT-張三";}@RequestMapping(value = "/user",method = RequestMethod.DELETE)public String deleteUser(){return "DELETE-張三";}
}

源碼:

    @Bean@ConditionalOnMissingBean({FormContentFilter.class})@ConditionalOnProperty(prefix = "spring.mvc.formcontent.filter",name = {"enabled"},matchIfMissing = true)public OrderedFormContentFilter formContentFilter() {return new OrderedFormContentFilter();}
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {HttpServletRequest requestToUse = request;if ("POST".equals(request.getMethod()) && request.getAttribute("javax.servlet.error.exception") == null) {String paramValue = request.getParameter(this.methodParam);if (StringUtils.hasLength(paramValue)) {String method = paramValue.toUpperCase(Locale.ENGLISH);if (ALLOWED_METHODS.contains(method)) {requestToUse = new HiddenHttpMethodFilter.HttpMethodRequestWrapper(request, method);}}}filterChain.doFilter((ServletRequest)requestToUse, response);}

Rest原理(表單提交要使用Rest的時候)

  • 表單提交帶上 _method=PUT
  • 請求過來被HiddenHttpMethodFilter 攔截
    • 請求是否正常,并且是POST請求
      • 獲取到_method 的值,并轉(zhuǎn)成大寫英文。
      • 兼容以下請求:PUT、DELETE、PATCH
      • 原生request(post),包裝模式requesWrapper重寫了getMethod方法,返回的是傳入的值。
      • 過濾器鏈放行的時候用wrapper。以后的方法調(diào)用getMethod是調(diào)用requesWrapper的。
spring:mvc:hiddenmethod:filter:enabled: true

Rest使用客戶端工具

  • 如PostMan直接發(fā)送Put、delete等方式請求,無需Filter。

2、請求映射原理

SpringMVC功能分析都從 org.springframework.web.servlet.DispatcherServlet? 》 doDispatch

中開始。

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 {processedRequest = checkMultipart(request);multipartRequestParsed = (processedRequest != request);// 找到當(dāng)前請求使用哪個Handler(Controller的方法)處理mappedHandler = getHandler(processedRequest);//HandlerMapping:處理器映射。/xxx->>xxxx

RequestMappingHandlerMapping:保存了所有@RequestMapping 和handler的映射規(guī)則。

所有的請求映射都在HandlerMapping(處理器映射器)中。

  • SpringBoot自動配置歡迎頁的 WelcomePageHandlerMapping 。訪問 /能訪問到index.html;
  • SpringBoot自動配置了默認(rèn) 的 RequestMappingHandlerMapping。
  • 請求進(jìn)來,挨個嘗試所有的HandlerMapping看是否有請求信息。
    • 如果有就找到這個請求對應(yīng)的handler
    • 如果沒有就是下一個 HandlerMapping
  • 我們?nèi)绻枰恍┳远x的映射處理,我們也可以自己給容器中放HandlerMapping。

	protected HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {if (this.handlerMappings != null) {for (HandlerMapping mapping : this.handlerMappings) {HandlerExecutionChain handler = mapping.getHandler(request);if (handler != null) {return handler;}}}return null;}

1、普通參數(shù)與基本注解

1.1、注解:

  • @PathVariable(路徑變量)
  • @RequestHeader(獲取請求頭)
  • @ModelAttribute
  • @RequestParam(獲取請求參數(shù))
  • @MatrixVariable(矩陣變量)
  • @CookieValue(獲取cookie值)
  • @RequestBody(獲取請求體)

1.2、Servlet API:

  • WebRequest、
  • ServletRequest、
  • MultipartRequest、
  • HttpSession、
  • javax.servlet.http.PushBuilder、
  • Principal、
  • InputStream、
  • Reader、
  • HttpMethod、
  • Locale、
  • TimeZone、
  • ZoneId

?ServletRequestMethodArgumentResolver (方法參數(shù)解析器)來解析以上部的

@Overridepublic boolean supportsParameter(MethodParameter parameter) {Class<?> paramType = parameter.getParameterType();return (WebRequest.class.isAssignableFrom(paramType) ||ServletRequest.class.isAssignableFrom(paramType) ||MultipartRequest.class.isAssignableFrom(paramType) ||HttpSession.class.isAssignableFrom(paramType) ||(pushBuilder != null && pushBuilder.isAssignableFrom(paramType)) ||Principal.class.isAssignableFrom(paramType) ||InputStream.class.isAssignableFrom(paramType) ||Reader.class.isAssignableFrom(paramType) ||HttpMethod.class == paramType ||Locale.class == paramType ||TimeZone.class == paramType ||ZoneId.class == paramType);}

1.3、復(fù)雜參數(shù):

  • Map、Model(map、model里面的數(shù)據(jù)會被放在request的請求域中,相當(dāng)于調(diào)用?request.setAttribute)
  • Errors/BindingResult
  • RedirectAttributes( 重定向攜帶數(shù)據(jù))
  • ServletResponse(response)
  • SessionStatus
  • UriComponentsBuilder
  • ServletUriComponentsBuilder

Map<String,Object> map,  Model model, HttpServletRequest request 都是可以給request域中放數(shù)據(jù),
等價于 request.getAttribute();

無論是Map、Model類型的參數(shù),底層都是調(diào)用 mavContainer.getMode() 返回一個?BindingAwareModelMap,而它是Model,也是Map。

?

1.4、自定義對象參數(shù):

可以自動類型轉(zhuǎn)換與格式化,可以級聯(lián)封裝。

/***     姓名: <input name="userName"/> <br/>*     年齡: <input name="age"/> <br/>*     生日: <input name="birth"/> <br/>*     寵物姓名:<input name="pet.name"/><br/>*     寵物年齡:<input name="pet.age"/>*/
@Data
public class Person {private String userName;private Integer age;private Date birth;private Pet pet;}
==================================================
@Data
public class Pet {private String name;private String age;}
@PostMapping("/saveuser")
public Person saveUser(Person person) {return person;
}

2、POJO封裝過程

  • 自定義類型的參數(shù)解析器為:
    • ServletModelAttributeMethodProcessor

3、參數(shù)處理原理

  • HandlerMapping(處理器映射器)中找到能處理請求的Handler(Controller.method()),并返回處理器執(zhí)行鏈。
  • 為當(dāng)前Handler找到一個HandlerAdapter(處理器適配器);一般被@RequestMapping 標(biāo)記的方法找到的都是?RequestMappingHandlerAdapter
  • 適配器執(zhí)行目標(biāo)方法,并確定方法參數(shù)的每一個值。

3.1、HandlerAdapter(處理器映射器)

0 - 支持方法上標(biāo)注@RequestMapping

1 - 支持函數(shù)式編程的

xxxxxx

3.2、執(zhí)行目標(biāo)方法

// Actually invoke the handler.
//DispatcherServlet -- doDispatch
mv = ha.handle(processedRequest, response, mappedHandler.getHandler());

mav = invokeHandlerMethod(request, response, handlerMethod); //執(zhí)行目標(biāo)方法//ServletInvocableHandlerMethod
Object returnValue = invokeForRequest(webRequest, mavContainer, providedArgs);
//獲取方法的參數(shù)值
Object[] args = getMethodArgumentValues(request, mavContainer, providedArgs);

?3.3、參數(shù)解析器-HandlerMethodArgumentResolver

確定將要執(zhí)行的目標(biāo)方法的每一個參數(shù)的值是什么;

SpringMVC目標(biāo)方法能寫多少種參數(shù)類型。取決于參數(shù)解析器。

  • 支持就調(diào)用 resolveArgument
  • 當(dāng)前解析器是否支持解析這種參數(shù)

3.4、返回值處理器

3.5、如何確定目標(biāo)方法每一個參數(shù)的值

============InvocableHandlerMethod==========================
protected Object[] getMethodArgumentValues(NativeWebRequest request, @Nullable ModelAndViewContainer mavContainer,Object... providedArgs) throws Exception {MethodParameter[] parameters = getMethodParameters();if (ObjectUtils.isEmpty(parameters)) {return EMPTY_ARGS;}Object[] args = new Object[parameters.length];for (int i = 0; i < parameters.length; i++) {MethodParameter parameter = parameters[i];parameter.initParameterNameDiscovery(this.parameterNameDiscoverer);args[i] = findProvidedArgument(parameter, providedArgs);if (args[i] != null) {continue;}if (!this.resolvers.supportsParameter(parameter)) {throw new IllegalStateException(formatArgumentError(parameter, "No suitable resolver"));}try {args[i] = this.resolvers.resolveArgument(parameter, mavContainer, request, this.dataBinderFactory);}catch (Exception ex) {// Leave stack trace for later, exception may actually be resolved and handled...if (logger.isDebugEnabled()) {String exMsg = ex.getMessage();if (exMsg != null && !exMsg.contains(parameter.getExecutable().toGenericString())) {logger.debug(formatArgumentError(parameter, exMsg));}}throw ex;}}return args;}

3.5.1、循環(huán)所有參數(shù)解析器,看哪個支持解析這個參數(shù)

	@Nullableprivate HandlerMethodArgumentResolver getArgumentResolver(MethodParameter parameter) {HandlerMethodArgumentResolver result = this.argumentResolverCache.get(parameter);if (result == null) {for (HandlerMethodArgumentResolver resolver : this.argumentResolvers) {if (resolver.supportsParameter(parameter)) {result = resolver;this.argumentResolverCache.put(parameter, result);break;}}}return result;}

3.5.2、解析這個參數(shù)的值

調(diào)用各自 HandlerMethodArgumentResolver 的 resolveArgument 方法即可。

3.5.3、解析自定義類型參數(shù)-封裝POJO

1、找到參數(shù)解析器。

ServletModelAttributeMethodProcessor 判斷自定義類型是否為簡單類型,不是,則作為解析器處理此參數(shù)。

public static boolean isSimpleValueType(Class<?> type) {return (Void.class != type && void.class != type &&(ClassUtils.isPrimitiveOrWrapper(type) ||Enum.class.isAssignableFrom(type) ||CharSequence.class.isAssignableFrom(type) ||Number.class.isAssignableFrom(type) ||Date.class.isAssignableFrom(type) ||Temporal.class.isAssignableFrom(type) ||URI.class == type ||URL.class == type ||Locale.class == type ||Class.class == type));}

?2、WebDataBinder (Web數(shù)據(jù)綁定器)利用它里面的Converters(轉(zhuǎn)換器)將請求數(shù)據(jù)轉(zhuǎn)換成指定的數(shù)據(jù)類型。

核心源碼:?

@Override@Nullablepublic final Object resolveArgument(MethodParameter parameter, @Nullable ModelAndViewContainer mavContainer,NativeWebRequest webRequest, @Nullable WebDataBinderFactory binderFactory) throws Exception {Assert.state(mavContainer != null, "ModelAttributeMethodProcessor requires ModelAndViewContainer");Assert.state(binderFactory != null, "ModelAttributeMethodProcessor requires WebDataBinderFactory");String name = ModelFactory.getNameForParameter(parameter);ModelAttribute ann = parameter.getParameterAnnotation(ModelAttribute.class);if (ann != null) {mavContainer.setBinding(name, ann.binding());}Object attribute = null;BindingResult bindingResult = null;if (mavContainer.containsAttribute(name)) {attribute = mavContainer.getModel().get(name);}else {// Create attribute instancetry {attribute = createAttribute(name, parameter, binderFactory, webRequest);}catch (BindException ex) {if (isBindExceptionRequired(parameter)) {// No BindingResult parameter -> fail with BindExceptionthrow ex;}// Otherwise, expose null/empty value and associated BindingResultif (parameter.getParameterType() == Optional.class) {attribute = Optional.empty();}bindingResult = ex.getBindingResult();}}if (bindingResult == null) {// Bean property binding and validation;// skipped in case of binding failure on construction.WebDataBinder binder = binderFactory.createBinder(webRequest, attribute, name);if (binder.getTarget() != null) {if (!mavContainer.isBindingDisabled(name)) {bindRequestParameters(binder, webRequest);}validateIfApplicable(binder, parameter);if (binder.getBindingResult().hasErrors() && isBindExceptionRequired(binder, parameter)) {throw new BindException(binder.getBindingResult());}}// Value type adaptation, also covering java.util.Optionalif (!parameter.getParameterType().isInstance(attribute)) {attribute = binder.convertIfNecessary(binder.getTarget(), parameter.getParameterType(), parameter);}bindingResult = binder.getBindingResult();}// Add resolved attribute and BindingResult at the end of the modelMap<String, Object> bindingResultModel = bindingResult.getModel();mavContainer.removeAttributes(bindingResultModel);mavContainer.addAllAttributes(bindingResultModel);return attribute;}

GenericConversionService:在設(shè)置每一個值的時候,遍歷它里面所有的所有converter(124個),直到找到可以將當(dāng)前參數(shù)的數(shù)據(jù)類型(request帶來參數(shù)的字符串)轉(zhuǎn)換到指定的類型(JavaBean -- Integer)。

3、WebDataBinder 將轉(zhuǎn)換后的數(shù)據(jù)再次封裝到指定的JavaBean中。

3.6、目標(biāo)方法執(zhí)行完成

將所有的數(shù)據(jù)都放在 ModelAndViewContainer;包含要去的頁面地址View。還包含Model數(shù)據(jù)。

processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);

renderMergedOutputModel(mergedModel, getRequestToExpose(request), response);

InternalResourceView:
@Overrideprotected void renderMergedOutputModel(Map<String, Object> model, HttpServletRequest request, HttpServletResponse response) throws Exception {// Expose the model object as request attributes.exposeModelAsRequestAttributes(model, request);// Expose helpers as request attributes, if any.exposeHelpers(request);// Determine the path for the request dispatcher.String dispatcherPath = prepareForRendering(request, response);// Obtain a RequestDispatcher for the target resource (typically a JSP).RequestDispatcher rd = getRequestDispatcher(request, dispatcherPath);if (rd == null) {throw new ServletException("Could not get RequestDispatcher for [" + getUrl() +"]: Check that the corresponding file exists within your web application archive!");}// If already included or response already committed, perform include, else forward.if (useInclude(request, response)) {response.setContentType(getContentType());if (logger.isDebugEnabled()) {logger.debug("Including [" + getUrl() + "]");}rd.include(request, response);}else {// Note: The forwarded resource is supposed to determine the content type itself.if (logger.isDebugEnabled()) {logger.debug("Forwarding to [" + getUrl() + "]");}rd.forward(request, response);}}

關(guān)鍵點:

暴露模型作為請求域?qū)傩?// Expose the model object as request attributes.exposeModelAsRequestAttributes(model, request);
protected void exposeModelAsRequestAttributes(Map<String, Object> model,HttpServletRequest request) throws Exception {//model中的所有數(shù)據(jù)遍歷挨個放在請求域中model.forEach((name, value) -> {if (value != null) {request.setAttribute(name, value);}else {request.removeAttribute(name);}});}


4、數(shù)據(jù)響應(yīng)與內(nèi)容協(xié)商

數(shù)據(jù)響應(yīng)分為響應(yīng)頁面和響應(yīng)數(shù)據(jù)。

  • 響應(yīng)頁面:如何發(fā)送一個請求,跳轉(zhuǎn)到指定頁面。一般用于一個單體請求。后續(xù)在視圖解析器詳細(xì)說明。
  • 響應(yīng)數(shù)據(jù):通常用來開發(fā)前后端分離的項目。前端發(fā)送請求給后端,后端響應(yīng)數(shù)據(jù)、圖片、xls、自定義協(xié)議數(shù)據(jù)等。

1、響應(yīng)JSON

1.1、jackson.jar+@ResponseBody

引入web場景<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency>而web場景自動引入了json場景<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-json</artifactId><version>2.3.4.RELEASE</version><scope>compile</scope></dependency>

?主要引入的依賴為:

測試代碼與結(jié)果

@Controller
public class ResponseTestController {@ResponseBody@GetMapping("/test/person")public Person getPerson() {Person person = new Person();person.setAge(28);person.setBirth(new Date());person.setUserName("張三");return person;}
}

原理解析

1、返回值解析器

核心代碼:?this.returnValueHandlers.handleReturnValue

try {this.returnValueHandlers.handleReturnValue(returnValue, getReturnValueType(returnValue), mavContainer, webRequest);
}
	@Overridepublic void handleReturnValue(@Nullable Object returnValue, MethodParameter returnType,ModelAndViewContainer mavContainer, NativeWebRequest webRequest) throws Exception {HandlerMethodReturnValueHandler handler = selectHandler(returnValue, returnType);if (handler == null) {throw new IllegalArgumentException("Unknown return value type: " + returnType.getParameterType().getName());}handler.handleReturnValue(returnValue, returnType, mavContainer, webRequest);}
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.// 使用消息轉(zhuǎn)換器進(jìn)行寫出操作writeWithMessageConverters(returnValue, returnType, inputMessage, outputMessage);}

2、返回值解析器原理?

  • 1、返回值處理器判斷是否支持這種類型返回值 supportsReturnType;
  • 2、若支持,該返回值處理器調(diào)用 handleReturnValue 進(jìn)行處理。
  • 若標(biāo)記了@ResponseBody注解,則調(diào)用處理器為RequestResponseBodyMethodProcessor
    • 利用 MessageConverters 進(jìn)行處理 將數(shù)據(jù)寫為json,具體過程:

      • 1、內(nèi)容協(xié)商(瀏覽器默認(rèn)會以請求頭的方式告訴服務(wù)器他能接受什么樣的內(nèi)容類型)

      • 2、服務(wù)器最終根據(jù)自己自身的能力,決定服務(wù)器能生產(chǎn)出什么樣內(nèi)容類型的數(shù)據(jù);

      • 3、決定內(nèi)容類型后,SpringMVC會遍歷所有容器底層的 HttpMessageConverter(消息轉(zhuǎn)換器)看誰能處理

        • 1、得到MappingJackson2HttpMessageConverter可以將對象寫為json

        • 2、利用MappingJackson2HttpMessageConverter將對象轉(zhuǎn)為json再寫出去。

1.2、SpringMVC到底支持哪些返回值

ModelAndView
Model
View
ResponseEntity 
ResponseBodyEmitter
StreamingResponseBody
HttpEntity
HttpHeaders
Callable
DeferredResult
ListenableFuture
CompletionStage
WebAsyncTask
有 @ModelAttribute 且為對象類型的
@ResponseBody 注解 ---> RequestResponseBodyMethodProcessor;

1.3、HTTPMessageConverter原理

1、MessageConverter 接口規(guī)范

HttpMessageConverter: 看是否支持將 此 Class類型的對象,轉(zhuǎn)為MediaType類型的數(shù)據(jù)。

例子:Person對象轉(zhuǎn)為JSON。或者 JSON轉(zhuǎn)為Person

2、默認(rèn)的MessageConverter

0 - 只支持Byte類型的

1 - 只支持String

2 - 只支持String

3 - 只支持Resource

4 - 只支持ResourceRegion

5 - 只支持DOMSource.class \ SAXSource.class) \ StAXSource.class \StreamSource.class \Source.class

6 - 只支持MultiValueMap

7 - 直接返回true

8 - 直接返回true

9 - 支持注解方式xml處理的。

最終 MappingJackson2HttpMessageConverter 把對象轉(zhuǎn)為JSON(利用底層的jackson的objectMapper轉(zhuǎn)換的)

2、內(nèi)容協(xié)商

根據(jù)客戶端接收能力不同,返回不同媒體類型的數(shù)據(jù)。

假設(shè)現(xiàn)在有三種客戶端,接收的數(shù)據(jù)類型不同:

  • 瀏覽器:能接收所有類型內(nèi)容
  • 安卓客戶端:只能接收json
  • 另一種客戶端:只能接收xml

1、引入xml依賴

 <dependency><groupId>com.fasterxml.jackson.dataformat</groupId><artifactId>jackson-dataformat-xml</artifactId>
</dependency>

2、postman分別測試返回json和xml

只需要改變請求頭中Accept字段。

Http協(xié)議中規(guī)定的,告訴服務(wù)器本客戶端可以接收的數(shù)據(jù)類型。

發(fā)現(xiàn)服務(wù)代碼沒改動情況下,具備同時返回xml跟json兩種格式的能力。

3、開啟瀏覽器參數(shù)方式內(nèi)容協(xié)商功能

4、內(nèi)容協(xié)商原理

  • 1、判斷當(dāng)前響應(yīng)頭中是否已經(jīng)有確定的媒體類型。MediaType
  • 2、獲取客戶端(PostMan、瀏覽器)支持接收的內(nèi)容類型。(獲取客戶端Accept請求頭字段)【application/xml】

http://aloenet.com.cn/news/44087.html

相關(guān)文章:

  • 唐山住房和城鄉(xiāng)建設(shè)廳網(wǎng)站谷歌外貿(mào)seo
  • 景區(qū)網(wǎng)站建設(shè)教程如何免費發(fā)布廣告
  • 網(wǎng)站開發(fā)公司總匯seo基礎(chǔ)知識培訓(xùn)視頻
  • 購物商城開發(fā)seo優(yōu)化設(shè)計
  • 大連重工 央企江西seo推廣軟件
  • 音樂網(wǎng)站開發(fā)的目的杭州百度推廣代理公司哪家好
  • 網(wǎng)站建設(shè)教程 pdf營銷型網(wǎng)站建設(shè)論文
  • 電子商務(wù)網(wǎng)站建設(shè)模板代碼互聯(lián)網(wǎng)廣告銷售是做什么的
  • WordPress的目錄大綱杭州百度快照優(yōu)化排名
  • 高密市網(wǎng)站建設(shè)鄭州網(wǎng)站seo顧問
  • logo免費設(shè)計無水印seo搜索工具欄
  • 山東政務(wù)網(wǎng)站建設(shè)seo和sem的聯(lián)系
  • 無錫網(wǎng)站建設(shè) app百度的搜索引擎優(yōu)化
  • 網(wǎng)站備案查詢api逆冬seo
  • windowxp做網(wǎng)站服務(wù)器寧波技術(shù)好的企業(yè)網(wǎng)站制作
  • 公裝網(wǎng)站怎么做seo專業(yè)培訓(xùn)學(xué)費多少錢
  • 領(lǐng)卷網(wǎng)站怎么做的seo關(guān)鍵詞排名優(yōu)化教程
  • 優(yōu)秀北京網(wǎng)站建設(shè)武漢百度推廣多少錢
  • 114啦建站程序軍事最新消息
  • 外貿(mào)網(wǎng)站建設(shè)方法百度知道入口
  • vue做公司網(wǎng)站天津網(wǎng)站優(yōu)化公司
  • 茶葉網(wǎng)站建設(shè)公司做網(wǎng)站seo推廣公司
  • 怎么用服務(wù)器ip做網(wǎng)站谷歌官方網(wǎng)站首頁
  • 花錢做推廣廣告哪個網(wǎng)站好網(wǎng)絡(luò)營銷的發(fā)展現(xiàn)狀及趨勢
  • 怎么樣建設(shè)一個電影網(wǎng)站友情鏈接網(wǎng)自動收錄
  • 廣州市建設(shè)交易中心網(wǎng)站首頁深圳網(wǎng)絡(luò)推廣專員
  • 做短視頻的網(wǎng)站網(wǎng)址怎么申請注冊
  • 網(wǎng)站備案主體撤銷西安網(wǎng)站建設(shè)優(yōu)化
  • 愛眼護(hù)眼ppt模板免費下載 素材鶴壁seo
  • 湖北網(wǎng)站建設(shè)的釋義搜索網(wǎng)站有哪幾個