sssSpringBoot启动自动加载 xxxAutoConfiguration 自动配置类
sssSpringMVC功能的自动配置类大都集中在 ==》 WebMvcAutoConfiguration ,生效
@Configuration(proxyBeanMethods = false
)
@ConditionalOnWebApplication(type = Type.SERVLET
)
@ConditionalOnClass({Servlet.class, DispatcherServlet.class, WebMvcConfigurer.class})
@ConditionalOnMissingBean({WebMvcConfigurationSupport.class}) // 没有 WebMvcConfigurationSupport 类生效💦
@AutoConfigureOrder(-2147483638)
@AutoConfigureAfter({DispatcherServletAutoConfiguration.class, TaskExecutionAutoConfiguration.class, ValidationAutoConfiguration.class})
public class WebMvcAutoConfiguration {... ... .... .... ... ...
}
sssWebMvcAutoConfiguration 生效给容器中配置了什么?
// WebMvcAutoConfiguration 内部类@Configuration( proxyBeanMethods = false ) @Import({WebMvcAutoConfiguration.EnableWebMvcConfiguration.class})@EnableConfigurationProperties({WebMvcProperties.class, ResourceProperties.class}) //配置文件的相关属性和xxx进行了绑定@Order(0)public static class WebMvcAutoConfigurationAdapter implements WebMvcConfigurer {... ... ...}
sss配置文件的相关属性和xxx进行了绑定:
ssdssWebMvcProperties ==》 spring.mvc ResourceProperties ==》 sources
ssdssWebProperties ==》 spring.web
ssdssWebMvcAutoConfigurationAdapter 只有一个有参构造器,有参构造器所有参数值都会从容器中确定。如下:
/**
@ ResourceProperties :获取和spring.web绑定的所有的值的对象
@ WebMvcProperties :获取和spring.mvc绑定的所有的值的对象
@ ListableBeanFactory :Spring的beanFactory
@ HttpMessageConverters :找到所有的HttpMessageConverters
@ ResourceHandlerRegistrationCustomizer :找到资源处理器的自定义器
@ DispatcherServletPath
@ ServletRegistrationBean 给应用注册Servlet、
*/public WebMvcAutoConfigurationAdapter(ResourceProperties resourceProperties, WebMvcProperties mvcProperties, ListableBeanFactory beanFactory, ObjectProvider<HttpMessageConverters> messageConvertersProvider, ObjectProvider<WebMvcAutoConfiguration.ResourceHandlerRegistrationCustomizer> resourceHandlerRegistrationCustomizerProvider, ObjectProvider<DispatcherServletPath> dispatcherServletPath, ObjectProvider<ServletRegistrationBean<?>> servletRegistrations) {sourceProperties = resourceProperties;this.mvcProperties = mvcProperties;this.beanFactory = ssageConvertersProvider = sourceHandlerRegistrationCustomizer = (WebMvcAutoConfiguration.IfAvailable();this.dispatcherServletPath = dispatcherServletPath;this.servletRegistrations = servletRegistrations;}
sss资源处理的默认规则:
public void addResourceHandlers(ResourceHandlerRegistry registry) {// addMappings默认为true,即允许静态资源💦//并且因为调用resourceProperties属性,点进去发现是属于ResourceProperties类,相对应于容器的组件,看注1💦if (!sourceProperties.isAddMappings()) {logger.debug("Default resource handling disabled");} else {//设置缓存的时间Duration cachePeriod = Cache().getPeriod();CacheControl cacheControl = Cache().getCachecontrol().toHttpCacheControl();// 设置 webjars 中静态资源访问规则💦if (!registry.hasMappingForPattern("/webjars/**")) {this.customizeResourceHandlerRegistration(registry.addResourceHandler(new String[]{"/webjars/**"}).addResourceLocations(new String[]{"classpath:/META-INF/resources/webjars/"}).Seconds(cachePeriod)).setCacheControl(cacheControl));}// 设置静态资源的路径 StaticLocations() 获得,默认为 "/**",可以修改💦String staticPathPattern = StaticPathPattern();if (!registry.hasMappingForPattern(staticPathPattern)) {this.customizeResourceHandlerRegistration(registry.addResourceHandler(new String[]{staticPathPattern}).StaticLocations())).Seconds(cachePeriod)).setCacheControl(cacheControl));}}}
sss【注1】:
public class ResourceProperties {private static final String[] CLASSPATH_RESOURCE_LOCATIONS = new String[]{"classpath:/META-INF/resources/", "classpath:/resources/", "classpath:/static/", "classpath:/public/"};private String[] staticLocations;public ResourceProperties() {this.staticLocations = CLASSPATH_RESOURCE_LOCATIONS;this.addMappings = true;this.chain = new ResourceProperties.Chain();this.cache = new ResourceProperties.Cache();}public String[] getStaticLocations() { return this.staticLocations;}
spring: resources: # 禁用所有静态资源 add-mappings: false # 设置缓存 cache: period: 11000 # 修改静态资源路径 static-locations: classpath:/stat_resources/
sss欢迎页处理规则:
//HandlerMapping:处理器映射。保存了每一个Handler能处理那些请求。@Beanpublic WelcomePageHandlerMapping welcomePageHandlerMapping(ApplicationContext applicationContext, FormattingConversionService mvcConversionService, ResourceUrlProvider mvcResourceUrlProvider) {// 跳转欢迎页,看注【注2】💦WelcomePageHandlerMapping welcomePageHandlerMapping = new WelcomePageHandlerMapping(new TemplateAvailabilityProviders(applicationContext), applicationContext, WelcomePage(), StaticPathPattern());welcomePageHandlerMapping.Interceptors(mvcConversionService, mvcResourceUrlProvider));welcomePageHandlerMapping.CorsConfigurations());return welcomePageHandlerMapping;}
sss【注2】:
WelcomePageHandlerMapping(TemplateAvailabilityProviders templateAvailabilityProviders, ApplicationContext applicationContext, Optional<Resource> welcomePage, String staticPathPattern) {// 要使用欢迎页必须是 “ /** ”💦if (welcomePage.isPresent() && "/**".equals(staticPathPattern)) {logger.info("Adding welcome page: " + ());this.setRootViewName("forward:index.html");} else if (this.welcomeTemplateExists(templateAvailabilityProviders, applicationContext)) {// 静态资源路径不是默认配置,就调用 Controller 处理 /index 请求💦logger.info("Adding welcome page template: index");this.setRootViewName("index");}}
sss【注3】:•favicon :浏览器默认会发请求访问 /favicon.ico当静态资源请求规则是 /** 时,可以访问。如果自己指定了静态资源请求路径则不能访问。
sssrest使用:
ssdssRest风格支持(使用HTTP请求方式动词表示对资源的操作)
ssdss以前: ○ 以前:/getUser 获取用户 /deleteUser 删除用户 /editUser 修改用户 /saveUser 保存用户
sdssdsdsd s ○ 现在: /user GET-获取用户 DELETE-删除用户 PUT-修改用户 POST-保存用户
sdssdsdsd s ○ 核心Filter :HiddenHttpMethodFilter
ssdsdsddsdsdss ■ 用法: 表单method=post,隐藏域 _method=put
ssdsdsddsdsdss ■ SpringBoot中手动开启
spring:mvc:hiddenmethod:filter:enabled: true #开启页面表单的Rest功能
@RestController
public class HelloController {@RequestMapping("/bug.jpg")public String hello(){return "aaaa";}// @RequestMapping(value = "/user",method = RequestMethod.GET)@GetMapping("/user")public String getUser(){return "GET-张三";}// @RequestMapping(value = "/user",method = RequestMethod.POST)@PostMapping("/user")public String saveUser(){return "POST-张三";}// @RequestMapping(value = "/user",method = RequestMethod.PUT)@PutMapping("/user")public String putUser(){return "PUT-张三";}@DeleteMapping("/user")
// @RequestMapping(value = "/user",method = RequestMethod.DELETE)public String deleteUser(){return "DELETE-张三";}
}
sss rest 原理 (表单提交要使用REST的时候):
ssdss前提 :表单提交会带上_method=PUT (这里应该是_method=希望使用的提交方法)
ssdss1、请求过来被HiddenHttpMethodFilter拦截 (源码) :
ssdssHiddenHttpMehodFilter的核心方法:
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {//原生的servlet请求:HttpServletRequest request💦HttpServletRequest requestToUse = request;// 2、请求是否是POST请求并且正常💦if ("POST".Method()) && Attribute("exception") == null) {// 4、获取到_method的值,默认methodParam = "_method" 💦String paramValue = hodParam);if (StringUtils.hasLength(paramValue)) {//或者methodParam的前缀,并将其转换成大写,比如 delete_method,所以会获取到 DELETE String method = UpperCase(Locale.ENGLISH);//ALLOWED_METHODS == PUT、DELETE、PATCH💦if (ains(method)) {//就是一种包装,通过调用HiddenHttpMethodFilter的内部类HttpMethodRequestWrapper的💦//getMethod()方法返回输入的method而不是post💦requestToUse = new HiddenHttpMethodFilter.HttpMethodRequestWrapper(request, method);}}}filterChain.doFilter((ServletRequest)requestToUse, response);
}
sdssd s 2、 请求是否正常,并且是POST
ssdsdsddsdsdss 3、 用法: 表单method=post,隐藏域 _method=put
ssdsdsddsdsdss 4、 获取到_method的值(无论value是大写还是小写,底层都会统一转换为大写)
ssdsdsddsdsdss 5、 兼容以下请求 :PUT.DELETE. PATCH
ssdsdsddsdsdss 6、原生request(post),包装模式requesWrapper重写了getMethod方法,返回的是传入的值
ssdsdsddsdsdss 7、过滤器链放行的时候用wrapper。以后的方法调用getMethod是调用requesWrapper的。
sss【注 5】:通过源码可知,methodParam = “_method”; 但是可以通过setMethodParam(String methodParam)方法改变methodParam值,因此这时候 我们可以通过把_method 换成我们自己自定义得值,比如_m:
@Configuration(proxyBeanMethods = false)
public class config {@Beanpublic HiddenHttpMethodFilter hiddenHttpMethodFilter(){HiddenHttpMethodFilter hiddenHttpMethodFilter = new HiddenHttpMethodFilter();hiddenHttpMethodFilter.setMethodParam("_m");return hiddenHttpMethodFilter;}
}
sss【注 6】:ALLOWED_METHODS值的设置方式,通过静态块赋值:
sss【注 7】:requestToUse = new HiddenHttpMethodFilter.HttpMethodRequestWrapper(request, method);
源码:
sss【注 8】:Rest使用客户端工具,如PostMan直接发送Put、delete等方式请求,无需Filter。因为:
sss【注 9】:
@ DeleteMapping实质就是 @RequestMapping ( method = { RequestMethod.DELETE} )
@ PutMapping实质就是 @RequestMapping ( method = { RequestMethod.PUT} )
@ PostMapping实质就是 @RequestMapping ( method = { RequestMethod.POST} )
@ GetMapping实质就是 @RequestMapping ( method = { RequestMethod.GET} )
dasdasdas
sssDispatcherServlet调用FrameworkServlet中的doGet和doPost
sssdoGet和doPost ==> processRequest(request, response) ==> doService(request, response)
sssdoService是一个抽象方法,并未做具体实现
sss FrameworkServlet的子类DispatcherServlet实现了doService
sssDispatcherServlet的doService ==> doDispatch(request, response)
sss请求映射流程:
sdsdsss请求进来 ==> HttpServlet的doGet和doPost
sdsdsdsdsddsdsdsss==> FrameworkServlet中的doGet和doPost
sdsdsddsdsdsddsdsdsss==> DispatcherServlet的doService
sdsdsdsddsdsdsdsdsdsdsss==> doService中调用doDispatch(request, response)
sss[注10]: SpringMVC功能分析都从 org.springframework.web.servlet.DispatcherServlet-》doDispatch()
sss找到当前请求使用哪个Handler : mappeHandler = hHandler(processedRequest); 😒
dasdas
ssshandlerMappings:处理器映射,有五个值
sss[注11]: 第一各处理器映射:RequestMappingHandlerMapping:保存了所有@RequestMapping 和handler的映射规则
所有的请求映射都在HandlerMapping中。
sss1. SpringBoot自动配置欢迎页的 WelcomePageHandlerMapping 。访问 /能访问到index.html;
sss2. SpringBoot自动配置了默认 的 RequestMappingHandlerMapping
sss3. 请求进来,挨个尝试所有的HandlerMapping看是否有请求信息(在request)。(同样的请求信息只能有一个)
sdsss• 如果有就找到这个请求对应的handler
ssdss• 如果没有就是下一个 HandlerMapping
sss4. 我们需要一些自定义的映射处理,我们也可以自己给容器中放HandlerMapping。自定义 HandlerMapping (映射每一个请求到对应的Handler)
sss[注12]: getHandler就是我们寻找相应处理器方法的方法:
sss[注13]: 点击DispatcherServlet的getHandler方法,进入到AbstractHandlerMapping的getHandler方法,
sss[注14]: 再进入getHandlerInternal(request):
sss[注15]: 再进入getHandlerInternal(request)方法:就是核心部分:
sss[注16]: 通过lookupHandlerMethod(lookupPath, request)获取相应的处理方法:
本文发布于:2024-02-04 19:27:16,感谢您对本站的认可!
本文链接:https://www.4u4v.net/it/170714739458788.html
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。
留言与评论(共有 0 条评论) |