【SpringBoot学习笔记②】SpringBoot-web
SpringBoot-web
1 简单功能分析
1.1 静态资源访问
1.1.1静态资源目录:
/static (或/public 或/resources 或/META-INF/resources)
只要资源放在上路类路径下,访问根路径+静态资源名就可以访问到
原理:静态映射/**
请求进来,先去找Controller看能不能处理,如果不能处理的所有请求又都交给静态资源处理器。
静态资源会去指定的类路径下寻找,静态资源也找不到就会返回404
改变默认静态资源路径
static-locations: Classpath:/文件夹名/
1.1.2 静态资源访问前缀
默认无前缀
当前项目+static-path-pattern + 静态资源名 = 静态资源文件夹下找
1.1.3 webjar
自动映射
<dependency>
<groupId>org.webjars</groupId>
<artifactId>jquery</artifactId>
<version>3.5.1</version>
</dependency>
访问地址是:http://localhost:8080/webjars/jquery/3.5.1/jquery.js 后面地址要按照依赖的包路径
1.2 欢迎页支持
- 静态资源路径下 index.html
- 可以配置静态资源路径
- 但是不可以配置静态资源的访问前缀,否则导致index.html不能被默认访问
- controller能处理/index
1.3 自定义Favicon
配置静态资源的访问前缀,会导致Favicon失效
/favicon.ico
1.4 静态资源配置原理
- SpringBoot启动默认加载xxxAutoConfiguration(自动配置类)
- SpringMVC功能的自动配置类WebMVCAutoConfiguration,生效
- 给容器中配置:
- HiddenHttpMethodFilter
- WebMvcAutoConfigurationAdapter
- 配置文件的相关属性和xxx进行了绑定。WebMvcProperties == spring.mvc、ResourceProperties == spring.resources
- 一个配置类如果只有一个有参构造器,有参构造器所有参数的值都会从容器中确定
- HandlerMapping:处理器映射,保存了每一个Handler能处理哪些请求
2 请求参数处理
2.1 请求映射
@xxxMapping:
- Rest风格支持(使用Http请求方式动词来表示对资源的操作)
- 以前:/getUser 获取用户 /deleteUser 删除用户 /editUser 修改用户 /saveUser 保存用户
- 现在:/User GET-获取用户 DELETE-删除用户 PUT-修改用户 POST-保存用户
- 核心Filter:HiddenHttpMethodFilter
- 用法:表单method=post,隐藏域 _method=put
Rest风格原理(表单提交要使用rest的时候):
- 用法:表单method=post,隐藏域 _method=put
- 表单提交会带上_method=PUT或DELETE
- 请求过来会被HiddenHttpMethodFilter拦截
- 处理请求时判断原生请求方式是否是post,其次判断getAttribute中有无错误
- 获取_method的请求参数
- 自动大写
- 兼容以下请求:PUT/DELETE/PATCH
- 原生request(post),包装模式requesWrapper重写了getMethod方法,返回的是传入的值
- 过滤器链放行的时候用wrapper,以后的方法调用getMethod是调用requesWrapper的。
Rest使用客户端工具
- 处理请求时判断原生请求方式是否是post,其次判断getAttribute中有无错误
- 如postman直接发送put、delete等方式请求,无需filter。
可以重写hiddenHttpMethodFilter类,并调用setMethodParam方法,改变默认的_method
@ConditionalOnMissingBean(HiddenHttpMethodFilter.class)意味着
在没有HiddenHttpMethodFilter时,才执行hiddenHttpMethodFilter()。因此,我们可以自定义filter,改变默认的\_method。例如:
@Configuration(proxyBeanMethods = false)
public class WebConfig{
//自定义filter
@Bean
public HiddenHttpMethodFilter hiddenHttpMethodFilter(){
HiddenHttpMethodFilter methodFilter = new HiddenHttpMethodFilter();
methodFilter.setMethodParam("_m");
return methodFilter;
}
}
将\_method改成_m。
<form action="/user" method="post">
<input name="_m" type="hidden" value="DELETE"/>
<input value="REST-DELETE 提交" type="submit"/>
</form>
2.2 请求映射原理
- springmvc功能分析都从org.springframework.web.servlet.DispatcherServlet --> doDispatch
- RequestMappingHandlerMapping:保存了所有@RequestMapping和Handler的映射规则
- 同样的请求方式不能有多个方法同时处理,只能有一个
- 所有的请求映射都保存在HandlerMapping中,系统中默认的HandlerMapping
- springboot自动配置欢迎页的handlermapping,能访问到index页面
- springboot自动配置了默认的RequestMappingHandlerMapping
- 请求进来,挨个尝试所有的handlerMapping是否有请求信息
- 如果有就找到这个请求对应的handler
- 如果没有就下一个HandlerMapping
- 我们需要一些自定义的映射处理,我们也可以自己给容器中放HandlerMapping,自定义HandlerMapping
2.3 相关注解
@PathVariable(路径变量)
@RequestHeader(获取请求头)
@RequestParam(获取请求参数)
@CookieValue(获取cookie值)
@RequestAttribute(获取request域属性)
@RequestBody(获取请求体)
@MatrixVariable(矩阵变量):矩阵变量应该绑定在路径中
2.4 Servlet API
WebRequest/ServletRequest/MultipartRequest/HttpSession/javax.servlet.http.PushBuilder/Principal/InputStream/Reader/HttpMethod/Locale/TimeZone/Zoneid
2.5 复杂参数
Map、Errors/BindingResult、Model(map、model里面的数据会被放在request的请求域 request.setAttribute)、RedirectAttributes( 重定向携带数据)、ServlerResponse(response)、SessionStatus、UriComponentsBulider、ServletUriComponentsBulider
2.6 自定义对象参数:
可以自动类型转换与格式化,可以级联封装。
2.7 POJO封装过程
ServletModelAttributeMethodProcessor
3 响应数据与内容协商
3.1 响应JSON
3.1.1 jackson.jar+@ResponseBody
<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>
给前端自动返回json数据
3.1.2 返回值解析器原理
- 1 返回值处理器判断是否支持这种类型返回值 supportsReturnType
- 2 返回值处理器调用 handleReturnValue 进行处理
- 3 RequestResponseBodyMethodProcessor 可以处理返回值标了@ResponseBody 注解的。
- 1 利用 MessageConverters 进行处理 将数据写为json
- 1 内容协商(浏览器默认会以请求头的方式告诉服务器他能接受什么样的内容类型)
- 2 服务器最终根据自己自身的能力,决定服务器能生产出什么样内容类型的数据,
- 3 SpringMVC会挨个遍历所有容器底层的 HttpMessageConverter ,看谁能处理?
- 1、得到MappingJackson2HttpMessageConverter可以将对象写为json
- 2、利用MappingJackson2HttpMessageConverter将对象转为json再写出去。
- 1 利用 MessageConverters 进行处理 将数据写为json
3.2 SpringMVC具体支持的返回值:
ModelAndView
Model
View
ResponseEntity
ResponseBodyEmitter
StreamingResponseBody
HttpEntity
HttpHeaders
Callable
DeferredResult
ListenableFuture
CompletionStage
WebAsyncTask
有 @ModelAttribute 且为对象类型的
@ResponseBody 注解 ---> RequestResponseBodyMethodProcessor;
3.3 HTTPMessageConverter原理
3.3.1 MessageConverter规范
HttpMessageConverter: 看是否支持将 此 Class类型的对象,转为MediaType类型的数据。例子:Person对象转为JSON。或者 JSON转为Person
3.3.2 默认的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处理的。
3.4 内容协商
根据客户端接收能力不同,返回不同媒体类型的数据。
3.4.1 引入xml依赖
<dependency>
<groupId>com.fasterxml.jackson.dataformat</groupId>
<artifactId>jackson-dataformat-xml</artifactId>
</dependency>
3.4.2 postman分别测试返回json和xml
只需要改变请求头中Accept字段。Http协议中规定的,告诉服务器本客户端可以接收的数据类型。
3.4.3 开启浏览器参数方式内容协商功能
为了方便内容协商,开启基于请求参数的内容协商功能。
spring:
contentnegotiation:
favor-parameter: true #开启请求参数内容协商模式
3.4.4 内容协商原理
- 1 判断当前响应头中是否已经有确定的媒体类型。MediaType
- 2 获取客户端(PostMan、浏览器)支持接收的内容类型。(获取客户端Accept请求头字段)【application/xml】
- 3 遍历循环所有当前系统的 MessageConverter,看谁支持操作这个对象(Person)
- 4 找到支持操作Person的converter,把converter支持的媒体类型统计出来。
- 5 客户端需要【application/xml】。服务端能力【10种、json、xml】
- 6 进行内容协商的最佳匹配媒体类型
- 7 用 支持 将对象转为 最佳匹配媒体类型 的converter。调用它进行转化 。
3.5 自定义 MessageConverter
实现多协议数据兼容。json、xml、x-guigu
- 0、@ResponseBody 响应数据出去 调用 RequestResponseBodyMethodProcessor 处理
- 1、Processor 处理方法返回值。通过 MessageConverter 处理
- 2、所有 MessageConverter 合起来可以支持各种媒体类型数据的操作(读、写)
- 3、内容协商找到最终的 messageConverter;
- SpringMVC的什么功能。一个入口给容器中添加一个 WebMvcConfigurer
4 视图解析与模版引擎
视图解析:SpringBoot默认不支持JSP,需要引入第三方模版引擎技术实现页面渲染。
4.1、视图解析原理流程
- 1、目标方法处理的过程中,所有数据都会被放在 ModelAndViewContainer 里面。包括数据和视图地址
- 2、方法的参数是一个自定义类型对象(从请求参数中确定的),把他重新放在 ModelAndViewContainer
- 3、任何目标方法执行完成以后都会返回 ModelAndView(数据和视图地址)。
- 4、processDispatchResult 处理派发结果(页面改如何响应)
- 1、render(mv, request, response); 进行页面渲染逻辑
- 1、根据方法的String返回值得到 View 对象【定义了页面的渲染逻辑】
- 1、所有的视图解析器尝试是否能根据当前返回值得到View对象
- 2、得到了 redirect:/main.html --> Thymeleaf new RedirectView()
- 3、ContentNegotiationViewResolver 里面包含了下面所有的视图解析器,内部还是利用下面所有视图解析器得到视图对象。
- 4、view.render(mv.getModelInternal(), request, response); 视图对象调用自定义的render进行页面渲染工作
- RedirectView 如何渲染【重定向到一个页面】
- 1、获取目标url地址
- 2、response.sendRedirect(encodedURL);
- RedirectView 如何渲染【重定向到一个页面】
- 1、render(mv, request, response); 进行页面渲染逻辑
视图解析:
- 返回值以 forward: 开始: new InternalResourceView(forwardUrl); --> 转发request.getRequestDispatcher(path).forward(request, response);
- 返回值以 redirect: 开始: new RedirectView() --》 render就是重定向
- 返回值是普通字符串: new ThymeleafView()--->
4.2 引入Starter
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
自动配好的策略
- 1、所有thymeleaf的配置值都在 ThymeleafProperties
- 2、配置好了 SpringTemplateEngine
- 3、配好了 ThymeleafViewResolver
- 4、我们只需要直接开发页面
5 拦截器
5.1 HandlerInterceptor接口
/**
* 登录检查
* 1、配置好拦截器要拦截哪些请求
* 2、把这些配置放在容器中
*/
@Slf4j
public class LoginInterceptor implements HandlerInterceptor {
/**
* 目标方法执行之前
* @param request
* @param response
* @param handler
* @return
* @throws Exception
*/
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
String requestURI = request.getRequestURI();
log.info("preHandle拦截的请求路径是{}",requestURI);
//登录检查逻辑
HttpSession session = request.getSession();
Object loginUser = session.getAttribute("loginUser");
if(loginUser != null){
//放行
return true;
}
//拦截住。未登录。跳转到登录页
request.setAttribute("msg","请先登录");
// re.sendRedirect("/");
request.getRequestDispatcher("/").forward(request,response);
return false;
}
/**
* 目标方法执行完成以后
* @param request
* @param response
* @param handler
* @param modelAndView
* @throws Exception
*/
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
log.info("postHandle执行{}",modelAndView);
}
/**
* 页面渲染以后
* @param request
* @param response
* @param handler
* @param ex
* @throws Exception
*/
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
log.info("afterCompletion执行异常{}",ex);
}
}
5.2 配置拦截器
/**
* 1、编写一个拦截器实现HandlerInterceptor接口
* 2、拦截器注册到容器中(实现WebMvcConfigurer的addInterceptors)
* 3、指定拦截规则【如果是拦截所有,静态资源也会被拦截】
*/
@Configuration
public class AdminWebConfig implements WebMvcConfigurer {
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(new LoginInterceptor())
.addPathPatterns("/**") //所有请求都被拦截包括静态资源
.excludePathPatterns("/","/login","/css/**","/fonts/**","/images/**","/js/**"); //放行的请求
}
}
5.3 拦截器原理
- 1、根据当前请求,找到HandlerExecutionChain【可以处理请求的handler以及handler的所有 拦截器】
- 2、先来顺序执行 所有拦截器的 preHandle方法
- 1、如果当前拦截器prehandle返回为true。则执行下一个拦截器的preHandle
- 2、如果当前拦截器返回为false。直接倒序执行所有已经执行了的拦截器的 afterCompletion;
- 3、如果任何一个拦截器返回false。直接跳出不执行目标方法
- 4、所有拦截器都返回True。执行目标方法
- 5、倒序执行所有拦截器的postHandle方法。
- 6、前面的步骤有任何异常都会直接倒序触发 afterCompletion
- 7、页面成功渲染完成以后,也会倒序触发 afterCompletion
6 文件上传
6.1 表单页面
<form method="post" action="/upload" enctype="multipart/form-data">
<input type="file" name="file"><br>
<input type="submit" value="提交">
</form>
6.2 文件上传代码
/**
* MultipartFile自动封装上传来的文件
* @param email
* @param userName
* @param headerImg
* @param photos
* @return
*/
@PostMapping("/upload")
public String upload(@RequestParam("email") String email,
@RequestParam("userName") String userName,
@RequestPart("headerImg")MultipartFile headerImg,
@RequestPart("photos")MultipartFile[] photos) throws IOException {
log.info("上传的信息:email={},userName={},headerImg={},photos={}",
email,userName,headerImg.getSize(),photos.length);
if(!headerImg.isEmpty()){
//保存到文件服务器,oss服务器
String originalFilename = headerImg.getOriginalFilename();
headerImg.transferTo(new File("d:\\cache\\"+originalFilename));
}
if(photos.length>0){
for(MultipartFile photo:photos){
if(!photo.isEmpty()){
String originalFilename = photo.getOriginalFilename();
photo.transferTo(new File("d:\\cache\\"+originalFilename));
}
}
}
return "main";
}
6.3 文件上传自动配置原理
- 文件上传自动配置类-MultipartAutoConfiguration-MultipartProperties
- 自动配置好了 StandardServletMultipartResolver 【文件上传解析器】
- 原理步骤
- 1、请求进来使用文件上传解析器判断(isMultipart)并封装(resolveMultipart,返回MultipartHttpServletRequest)文件上传请求
- 2、参数解析器来解析请求中的文件内容封装成MultipartFile
- 3、将request中文件信息封装为一个Map;MultiValueMap<String, MultipartFile>
FileCopyUtils。实现文件流的拷贝
@PostMapping("/upload")
public String upload(@RequestParam("email") String email,
@RequestParam("username") String username,
@RequestPart("headerImg") MultipartFile headerImg,
@RequestPart("photos") MultipartFile[] photos)
7 异常处理
7.1 错误处理
7.1.1 默认规则
- 默认情况下,Spring Boot提供/error处理所有错误的映射
- 对于机器客户端,它将生成JSON响应,其中包含错误,HTTP状态和异常消息的详细信息。对于浏览器客户端,响应一个“ whitelabel”错误视图,以HTML格式呈现相同的数据
- 要对其进行自定义,添加View解析为error
- 要完全替换默认行为,可以实现 ErrorController 并注册该类型的Bean定义,或添加ErrorAttributes类型的组件以使用现有机制但替换其内容。
- error/下的4xx,5xx页面会被自动解析;
7.1.2 定制错误处理逻辑
- 自定义错误页
- error/404.html error/5xx.html;有精确的错误状态码页面就匹配精确,没有就找 4xx.html;如果都没有就触发白页
- @ControllerAdvice+@ExceptionHandler处理全局异常;底层是 ExceptionHandlerExceptionResolver 支持的
- @ResponseStatus+自定义异常 ;底层是 ResponseStatusExceptionResolver ,把responsestatus注解的信息底层调用 response.sendError(statusCode, resolvedReason);tomcat发送的/error
- Spring底层的异常,如 参数类型转换异常;DefaultHandlerExceptionResolver 处理框架底层的异常。
- response.sendError(HttpServletResponse.SC_BAD_REQUEST, ex.getMessage());
- 自定义实现 HandlerExceptionResolver 处理异常;可以作为默认的全局异常处理规则
- ErrorViewResolver 实现自定义处理异常;
- response.sendError 。error请求就会转给controller
- 你的异常没有任何人能处理。tomcat底层 response.sendError。error请求就会转给controller
- basicErrorController 要去的页面地址是 ErrorViewResolver ;
7.1.3 异常自动配置原理
- ErrorMvcAutoConfiguration 自动配置异常处理规则
- 容器中的组件:类型:DefaultErrorAttributes -> id:errorAttributes
- public class DefaultErrorAttributes implements ErrorAttributes, HandlerExceptionResolver
- DefaultErrorAttributes:定义错误页面中可以包含哪些数据。
- 容器中的组件:类型:BasicErrorController --> id:basicErrorController(json+白页 适配响应)
- 处理默认 /error 路径的请求;页面响应 new ModelAndView("error", model);
- 容器中有组件 View->id是error;(响应默认错误页)
- 容器中放组件 BeanNameViewResolver(视图解析器);按照返回的视图名作为组件的id去容器中找View对象。
- 容器中的组件:类型:DefaultErrorViewResolver -> id:conventionErrorViewResolver
- 如果发生错误,会以HTTP的状态码 作为视图页地址(viewName),找到真正的页面
- error/404、5xx.html
- 容器中的组件:类型:DefaultErrorAttributes -> id:errorAttributes
7.1.4 异常处理步骤流程
- 1、执行目标方法,目标方法运行期间有任何异常都会被catch、而且标志当前请求结束;并且用 dispatchException
- 2、进入视图解析流程(页面渲染?)
- processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);
- 3、mv = processHandlerException;处理handler发生的异常,处理完成返回ModelAndView;
- 1、遍历所有的 handlerExceptionResolvers,看谁能处理当前异常【HandlerExceptionResolver处理器异常解析器】
- 2、系统默认的 异常解析器;
- 1、DefaultErrorAttributes先来处理异常。把异常信息保存到rrequest域,并且返回null;
- 2、默认没有任何人能处理异常,所以异常会被抛出
- 1、如果没有任何人能处理最终底层就会发送 /error 请求。会被底层的BasicErrorController处理
- 2、解析错误视图;遍历所有的 ErrorViewResolver 看谁能解析。
- 3、默认的 DefaultErrorViewResolver ,作用是把响应状态码作为错误页的地址,error/500.html
- 4、模板引擎最终响应这个页面 error/500.html
8 Web原生组件注入(Servlet、Filter、Listener)
8.1、使用Servlet API
- @ServletComponentScan(basePackages = "com.atguigu.admin") :指定原生Servlet组件都放在那里
- @WebServlet(urlPatterns = "/my"):效果:直接响应,没有经过Spring的拦截器?
- @WebFilter(urlPatterns={"/css/","/images/"})
- @WebListener
8.2、使用RegistrationBean
- ServletRegistrationBean, FilterRegistrationBean, ServletListenerRegistrationBean
@Configuration
public class MyRegistConfig {
@Bean
public ServletRegistrationBean myServlet(){
MyServlet myServlet = new MyServlet();
return new ServletRegistrationBean(myServlet,"/my","/my02");
}
@Bean
public FilterRegistrationBean myFilter(){
MyFilter myFilter = new MyFilter();
// return new FilterRegistrationBean(myFilter,myServlet());
FilterRegistrationBean filterRegistrationBean = new FilterRegistrationBean(myFilter);
filterRegistrationBean.setUrlPatterns(Arrays.asList("/my","/css/*"));
return filterRegistrationBean;
}
@Bean
public ServletListenerRegistrationBean myListener(){
MySwervletContextListener mySwervletContextListener = new MySwervletContextListener();
return new ServletListenerRegistrationBean(mySwervletContextListener);
}
}
9 嵌入式Servlet容器
9.1 切换嵌入式Servlet容器
- 默认支持的webServer
- Tomcat, Jetty, or Undertow
- ServletWebServerApplicationContext 容器启动寻找ServletWebServerFactory 并引导创建服务器
- 切换服务器
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<exclusions>
<exclusion>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-tomcat</artifactId>
</exclusion>
</exclusions>
</dependency>
- 原理
- SpringBoot应用启动发现当前是Web应用。web场景包-导入tomcat
- web应用会创建一个web版的ioc容器 ServletWebServerApplicationContext
- ServletWebServerApplicationContext 启动的时候寻找 ServletWebServerFactory(Servlet 的web服务器工厂---> Servlet 的web服务器)
- SpringBoot底层默认有很多的WebServer工厂;TomcatServletWebServerFactory, JettyServletWebServerFactory, or UndertowServletWebServerFactory
- 底层直接会有一个自动配置类。ServletWebServerFactoryAutoConfiguration
- ServletWebServerFactoryAutoConfiguration导入了ServletWebServerFactoryConfiguration(配置类)
- ServletWebServerFactoryConfiguration 配置类 根据动态判断系统中到底导入了那个Web服务器的包。(默认是web-starter导入tomcat包),容器中就有 TomcatServletWebServerFactory
- TomcatServletWebServerFactory 创建出Tomcat服务器并启动;TomcatWebServer 的构造器拥有初始化方法initialize---this.tomcat.start();
- 内嵌服务器,就是手动把启动服务器的代码调用(tomcat核心jar包存在)
9.2 定制Servlet容器
- 实现 WebServerFactoryCustomizer
- 把配置文件的值和ServletWebServerFactory 进行绑定
- 修改配置文件 server.xxx
- 直接自定义 ConfigurableServletWebServerFactory
xxxxxCustomizer:定制化器,可以改变xxxx的默认规则
10 定制化原理
10.1 定制化的常见方式
- 修改配置文件;
- xxxxxCustomizer;
- 编写自定义的配置类 xxxConfiguration;+ @Bean替换、增加容器中默认组件;视图解析器
- Web应用 编写一个配置类实现 WebMvcConfigurer 即可定制化web功能;+ @Bean给容器中再扩展一些组件
@Configuration
public class AdminWebConfig implements WebMvcConfigurer
- @EnableWebMvc + WebMvcConfigurer —— @Bean 可以全面接管SpringMVC,所有规则全部自己重新配置; 实现定制和扩展功能
- 原理
- 1、WebMvcAutoConfiguration 默认的SpringMVC的自动配置功能类。静态资源、欢迎页.....
- 2、一旦使用 @EnableWebMvc 、。会 @Import(DelegatingWebMvcConfiguration.class)
- 3、DelegatingWebMvcConfiguration 的 作用,只保证SpringMVC最基本的使用
- 把所有系统中的 WebMvcConfigurer 拿过来。所有功能的定制都是这些 WebMvcConfigurer 合起来一起生效
- 自动配置了一些非常底层的组件。RequestMappingHandlerMapping、这些组件依赖的组件都是从容器中获取
- public class DelegatingWebMvcConfiguration extends WebMvcConfigurationSupport
- 4、WebMvcAutoConfiguration 里面的配置要能生效 必须 @ConditionalOnMissingBean(WebMvcConfigurationSupport.class)
- 5、@EnableWebMvc 导致了 WebMvcAutoConfiguration 没有生效。
10.2 原理分析套路
场景starter - xxxxAutoConfiguration - 导入xxx组件 - 绑定xxxProperties -- 绑定配置文件项
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 分享4款.NET开源、免费、实用的商城系统
· 全程不用写代码,我用AI程序员写了一个飞机大战
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· 白话解读 Dapr 1.15:你的「微服务管家」又秀新绝活了
· 上周热点回顾(2.24-3.2)