目录

springboot知识点以及源码解析2

springboot知识点以及源码解析(2)

web开发–静态规则与定制化

springboot对静态资源的映射规则:在类路径下面定义目录static或public或resources或者META-INF/resources,访问时项目根目录+静态资源的名称

https://i-blog.csdnimg.cn/direct/c961cf1cb99d4866941234cf3c3ef042.png

在springboot中,如果项目中存在同名的静态资源和同名的动态资源。那么我们会优先去访问动态资源,如果动态资源不存在,然后再去访问对应的静态资源,如果静态资源也找不到,那么就报404 的异常 ,为了解决这个问题。

  1. 可以在配置文件中自定义静态资源的映射规则,例如:spring.mvc.static-path-pattern=/resources/**,那么访问静态资源时根目录+resources+静态资源名称。

  2. 也可以给静态资源设置自定义的存放目录:例如spring:web:resourcesstatic-locations:[classpath:/hello/],那么在资源下创建hello这个文件夹,下面放静态资源

  3. 我们也可以访问webjars的资源(webjars 就是将静态资源打成jar包。)

    1、引入相关静态资源的jar包(依赖)

    org.webjars

    jquery</artifactId)

    3.5.1

    2、通过官方给定的访问路径去访问里面的资源

    http://localhost:8082/webjars/jquery/3.5.1/jquery.js


静态资源和首页映射规则底层原理

源码

webMvcAutoConfiguration底层是如何进行装配的。在org.springframework.boot.autoconfigure.web.servlet.WebMvcAutoConfiguration中的注解

https://i-blog.csdnimg.cn/direct/86cc84cc931e4733a439cb85995c2396.png

在这个类中,主要看WebMvcAutoConfigurationAdapter,是WebMvc自动配置的适配器,

https://i-blog.csdnimg.cn/direct/7f6391f6bc3e4948b1684fa82ff25430.png

看下面的这个方法 WebMvcAutoConfigurationAdapter,它是一个构造方法,参数从哪里来?

public WebMvcAutoConfigurationAdapter(WebProperties webProperties, WebMvcProperties mvcProperties, ListableBeanFactory beanFactory, ObjectProvider<HttpMessageConverters> messageConvertersProvider, ObjectProvider<ResourceHandlerRegistrationCustomizer> resourceHandlerRegistrationCustomizerProvider, ObjectProvider<DispatcherServletPath> dispatcherServletPath, ObjectProvider<ServletRegistrationBean<?>> servletRegistrations) {
            this.resourceProperties = webProperties.getResources();
            this.mvcProperties = mvcProperties;
            this.beanFactory = beanFactory;
            this.messageConvertersProvider = messageConvertersProvider;
            this.resourceHandlerRegistrationCustomizer = (ResourceHandlerRegistrationCustomizer)resourceHandlerRegistrationCustomizerProvider.getIfAvailable();
            this.dispatcherServletPath = dispatcherServletPath;
            this.servletRegistrations = servletRegistrations;
        }
  • WebProperties 和 WebMvcProperties: 被SpringBoot自动创建并填充到配置文件中,通过@EnableConfigurationProperties注解进行引入,上面图片可以看到
  • ListableBeanFactory
    代表了一个可以列出所有已注册bean定义的bean工厂。它是Spring IoC容器的一部分,不需要特别指定,Spring会 自动 将其传递给需要它的bean。
  • ObjectProvider 和 ObjectProvider
    这两个 ObjectProvider 是用来延迟加载特定类型的bean的。如果Spring上下文中存在类型为 HttpMessageConvertersResourceHandlerRegistrationCustomizer 的bean,那么它们就会被注入到这里。如果没有找到匹配的bean,也不会导致错误,因为 ObjectProvider 支持可选的依赖项
  • ObjectProvider 和 ObjectProvider<ServletRegistrationBean>
    类似地,这两个也是 ObjectProvider 实例,用于提供对 DispatcherServlet 路径和 ServletRegistrationBean 的访问。如果有相应的bean存在于上下文中,它们将会被注入。

那么适配器初始化这些信息后,那么静态资源是如何生效的?

静态资源是如何生效的

在这个类(

public static class WebMvcAutoConfigurationAdapter implements WebMvcConfigurer, ServletContextAware 

)下,有一个addResourceHandlers方法,下面进行图解。

https://i-blog.csdnimg.cn/direct/e668761492264733aa0063802fa046d4.png

也可以点进去,可以得到

欢迎页

在WelcomePageHandlerMapping类下的WelcomePageHandlerMapping方法中

WelcomePageHandlerMapping(TemplateAvailabilityProviders templateAvailabilityProviders, ApplicationContext applicationContext, Resource indexHtmlResource, String staticPathPattern) {
    this.setOrder(2); // 优先级为 2。
    // 确定是否有可用的欢迎页面
    WelcomePage welcomePage = WelcomePage.resolve(templateAvailabilityProviders, applicationContext, indexHtmlResource, staticPathPattern);

    if (welcomePage != WelcomePage.UNRESOLVED) { // 如果找到了欢迎页面
        // 根据欢迎页面是否为模板,记录日志
        logger.info(LogMessage.of(() -> {
            return !welcomePage.isTemplated() ? "Adding welcome page: " + String.valueOf(indexHtmlResource) : "Adding welcome page template: index";
        }));
        
        // 创建一个新的实例,可以指定视图名称
        ParameterizableViewController controller = new ParameterizableViewController();
        
        // 设置控制器的视图名称为欢迎页面的视图名称
        controller.setViewName(welcomePage.getViewName());
        
        // 将创建的控制器设置为此 HandlerMapping 的根处理器
        this.setRootHandler(controller);
    }
}

springboot中rest请求处理原理

@RestController
public class HelloController {

    @RequestMapping(value = "/hello",method = RequestMethod.GET)
    public String sayHello(){
        return "Hello World!";
    }
}

在非 REST 风格的传统代码中,为了执行数据的增删改查操作,通常需要将每个操作映射到不同的路径上。然而,采用 REST 风格后,可以使用相同的路径来表示同一个资源,并通过不同的 HTTP 方法(如 POST 用于创建, GET 用于查询, PUTPATCH 用于更新,以及 DELETE 用于删除)来区分这些操作。这样,我们就可以通过单一的端点路径结合适当的请求方法来管理资源,从而提高 API 的清晰度和可维护性。例如,在 Spring MVC 中,你可以通过 @RequestMapping 注解的 method 属性指定支持的 HTTP 方法类型,或者直接使用简化的组合注解如 @GetMapping , @PostMapping , @PutMapping , 和 @DeleteMapping 来实现这一点。同时, @RequestMapping 注解中的 pathvalue 属性互为别名,都可以用来指定请求路径。这样的设计有助于构建更加简洁、一致的服务接口。

import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class HelloController {

    @RequestMapping(value = "user",method = RequestMethod.GET)
    public String get(){
        return "Hello User Get!";
    }

    @RequestMapping(value = "user",method = RequestMethod.POST)
    public String post(){
        return "Hello User Post!";
    }

    @RequestMapping(value = "user",method = RequestMethod.PUT)
    public String put(){
        return "Hello User Put!";
    }

    @RequestMapping(value = "user",method = RequestMethod.DELETE)
    public String delete(){
        return "Hello User Delete!";
    }
}

// demo1.html
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
    <form action="/user" method="get">
        <input value="GET提交" type="submit">
    </form>

    <form action="/user" method="post">
        <input value="Post提交" type="submit">
    </form>

    <form action="/user" method="post">
        <input value="Put提交" type="submit">
    </form>

    <form action="/user" method="post">
        <input value="Delete提交" type="submit">
    </form>
</body>
</html>

由于表单中只能由get和post,没有put和delete,因此它们用post进行代替。设想点击不同的按钮进入不同的表单页,显示不同的值,是这样吗?来看下结果,结果显示:对于get和post提交是正常的,但是对于put和delete提交显示的是Hello User Post!这是由于表单中只能由get和post,为了弄清楚它,回到D:\java\mvn_repository\org\springframework\boot\spring-boot-autoconfigure\3.4.3\spring-boot-autoconfigure-3.4.3.jar!\org\springframework\boot\autoconfigure\web\servlet\这个路径下的WebMvcAutoConfiguration.class类中。过滤器默认不开启,开启需要添加配置文件

https://i-blog.csdnimg.cn/direct/2ecfc4e221d44e72bb89b3ec3df8134e.png

在HiddenHttpMethodFilter中,有一个doFilterInternal方法,

进行debug,先发送get请求,进不到if,执行filterChain.doFilter((ServletRequest)requestToUse, response);进行放行 https://i-blog.csdnimg.cn/direct/f8c2ce38e90b40ed972bf459f54cc012.png

https://i-blog.csdnimg.cn/direct/d87267460fff421796e4f3921e94f9ea.png 下面看下post请求,其中this.methodParam是一个_method参数,需要在html文件中进行配置

https://i-blog.csdnimg.cn/direct/8efbaf98e9dd48b79be10a7b22466f0c.png

下面看下加上_method的put请求,delete同理

https://i-blog.csdnimg.cn/direct/7101d13123ca429592ea942b655c847f.png 注意:下面两者等价

@RequestMapping(value = "user",method = RequestMethod.GET)
@GetMapping("user")

springboot处理器映射器工作原理

在SpringMVC中有一个组件DispatcherServlet,在DispatcherServlet.class这个类下,它是用于处理前端用户的请求。体系结构如下:

https://i-blog.csdnimg.cn/direct/1e5f642b2aa4498789a81c3e2a49c0cd.png

进入FrameworkServlet中,有doGet,doPost,doPut和doDelete,它们四个处理Http请求,这四个方法都调用了processRequest方法,在processRequest方法中,首先进行一些初始化,然后在doService方法中提供服务,doService方法中又有doDispatch方法,这个方法中关注这句话:mappedHandler = this.getHandler(processedRequest);

https://i-blog.csdnimg.cn/direct/ed120af094a440e19a0d162d83cdb68e.png

https://i-blog.csdnimg.cn/direct/fa14c8f694714aae9525c14996ab8c15.png https://i-blog.csdnimg.cn/direct/d982e513d5de45b2a63ba79b58b0e825.png

https://i-blog.csdnimg.cn/direct/4a560098a72e412d872e3d7372e3a40b.png

如果是不大于1的话:

https://i-blog.csdnimg.cn/direct/979c8b023a384b01a57bb53b328f4002.png

总结:用户的请求交给DispatcherServlet前端控制器中的doDispatch方法进行处理,其中被doDispath方法中的getHandler获取想要的handler对象,这个handler对象被包装到HandlerExecutionChain里面。那么handler如何被获取?mappedHandler=this.getHandler(processedRequest)方法帮助处理,this.getHandler内部,有5个映射器,RequestMappingHandlerMapping处理被@RequestMapping注解修饰的处理器方法,返回一个handler。这个handler最终交给处理器适配器进行处理。