2021-08-30 SpringBoot 学习笔记(Web开发)

WEB开发

简单功能分析

静态资源访问

  1. 静态资源目录
    类路径下/static, /public, /resources, /META-INF/resources,这些目录里的资源都可以直接通过url访问:当前项目根路径/ + 静态资源名
    原理:静态映射/**
    请求进来,先去controller找,看有没有对应的controller可以处理,如果没有就交给静态资源处理器,如果静态资源也找不到就404

  2. 静态资源访问前缀
    默认无前缀

spring:
  mvc:
    static-path-pattern: /res/**
如果要改变前缀,就用如上的配置,此时访问静态资源的路径为:当前项目根路径/res+ 静态资源名
spring:
  mvc:
    static-path-pattern: /res/**
  web:
    resources:
      static-locations: classpath:/haha/
static-locations是改变保存静态文件夹的位置,默认是/static, /public, /resources, /META-INF/resources这些文件夹下,按着上面的更改,静态文件夹变成了haha文件夹

欢迎页支持

  • 静态资源路径下的index.html
    在静态资源文件夹里新建一个index.html,那么在项目启动后会自动弹出页面

    如果更改了静态资源访问路径( static-path-pattern: /res/**),那么欢迎页会失效

  • controller里有对/index路径的映射

自定义Favicon

在静态资源文件夹下创建favicon.ico,文件名不能变,此时访问网页时在访问栏会出现自定义的图标。
跟上面一样,如果更改了静态资源访问路径也会导致失效。

静态资源配置原理

主要依赖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 {

该类WebMvcAutoConfiguration 下的核心类WebMvcAutoConfigurationAdapter 如下

与配置文件绑定:
WebMvcProperties <> “spring.mvc”
ResourceProperties <> “spring.resources”
WebProperties <> “spring.web”

 @Configuration(
        proxyBeanMethods = false
    )
    @Import({WebMvcAutoConfiguration.EnableWebMvcConfiguration.class})
    @EnableConfigurationProperties({WebMvcProperties.class, ResourceProperties.class, WebProperties.class})
    @Order(0)
    public static class WebMvcAutoConfigurationAdapter implements WebMvcConfigurer, ServletContextAware {

这个类有一个构造器,其中的参数都是从容器中获取
ResourceProperties :获取配置文件里spring.resources的配置
WebProperties :获取配置文件里spring.web的配置
WebMvcProperties :获取配置文件里spring.mvc的配置
ListableBeanFactory:IOC容器

        public WebMvcAutoConfigurationAdapter(ResourceProperties resourceProperties, WebProperties webProperties, WebMvcProperties mvcProperties, ListableBeanFactory beanFactory, ObjectProvider<HttpMessageConverters> messageConvertersProvider, ObjectProvider<WebMvcAutoConfiguration.ResourceHandlerRegistrationCustomizer> resourceHandlerRegistrationCustomizerProvider, ObjectProvider<DispatcherServletPath> dispatcherServletPath, ObjectProvider<ServletRegistrationBean<?>> servletRegistrations) {
            this.resourceProperties = (Resources)(resourceProperties.hasBeenCustomized() ? resourceProperties : webProperties.getResources());
            this.mvcProperties = mvcProperties;
            this.beanFactory = beanFactory;
            this.messageConvertersProvider = messageConvertersProvider;
            this.resourceHandlerRegistrationCustomizer = (WebMvcAutoConfiguration.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");
            } else {
                this.addResourceHandler(registry, "/webjars/**", "classpath:/META-INF/resources/webjars/");
                this.addResourceHandler(registry, this.mvcProperties.getStaticPathPattern(), (registration) -> {
                    registration.addResourceLocations(this.resourceProperties.getStaticLocations());
                    if (this.servletContext != null) {
                        ServletContextResource resource = new ServletContextResource(this.servletContext, "/");
                        registration.addResourceLocations(new Resource[]{resource});
                    }

                });
            }
        }
  • 先获取配置文件里add-mappings的值,默认是true,如果改成false,那么静态资源加载的默认规则就不生效了
  • 获取webjars下的静态资源,解释了当引入jquery后直接在根路径下输入webjars就会显示jquery的静态资源
  • 获取配置文件里的static-path-pattern和static-locations的值
spring:
  mvc:
    static-path-pattern: /res/**
  web:
    resources:
      static-locations: classpath:/haha/
      add-mappings: true

staticLocations 的默认值是{“classpath:/META-INF/resources/”, “classpath:/resources/”, “classpath:/static/”, “classpath:/public/”}

    public static class Resources {
        private static final String[] CLASSPATH_RESOURCE_LOCATIONS = new String[]{"classpath:/META-INF/resources/", "classpath:/resources/", "classpath:/static/", "classpath:/public/"};
        private String[] staticLocations;
        private boolean addMappings;
        private boolean customized;
        private final WebProperties.Resources.Chain chain;
        private final WebProperties.Resources.Cache cache;

        public Resources() {
            this.staticLocations = CLASSPATH_RESOURCE_LOCATIONS;
            this.addMappings = true;
            this.customized = false;
            this.chain = new WebProperties.Resources.Chain();
            this.cache = new WebProperties.Resources.Cache();
        }

欢迎页原理

也是在WebMvcAutoConfiguration 这个配置类下有一个EnableWebMvcConfiguration 配置类

    @Configuration(
        proxyBeanMethods = false
    )
    @EnableConfigurationProperties({WebProperties.class})
    public static class EnableWebMvcConfiguration extends DelegatingWebMvcConfiguration implements ResourceLoaderAware {
        private final Resources resourceProperties;
        private final WebMvcProperties mvcProperties;
        private final WebProperties webProperties;
        private final ListableBeanFactory beanFactory;
        private final WebMvcRegistrations mvcRegistrations;
        private ResourceLoader resourceLoader;

        public EnableWebMvcConfiguration(ResourceProperties resourceProperties, WebMvcProperties mvcProperties, WebProperties webProperties, ObjectProvider<WebMvcRegistrations> mvcRegistrationsProvider, ObjectProvider<WebMvcAutoConfiguration.ResourceHandlerRegistrationCustomizer> resourceHandlerRegistrationCustomizerProvider, ListableBeanFactory beanFactory) {
            this.resourceProperties = (Resources)(resourceProperties.hasBeenCustomized() ? resourceProperties : webProperties.getResources());
            this.mvcProperties = mvcProperties;
            this.webProperties = webProperties;
            this.mvcRegistrations = (WebMvcRegistrations)mvcRegistrationsProvider.getIfUnique();
            this.beanFactory = beanFactory;
        }

这个配置类下有一个welcomePageHandlerMapping方法就是配置欢迎页的核心方法

        @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的构造器中写死了如果staticPathPattern不是/** ,就从controller中找,所以这也解释了当自己配置了静态资源访问路径之后,也就是staticPathPattern不为 /* *了,所以只能进入else里

    WelcomePageHandlerMapping(TemplateAvailabilityProviders templateAvailabilityProviders, ApplicationContext applicationContext, Resource welcomePage, String staticPathPattern) {
        if (welcomePage != null && "/**".equals(staticPathPattern)) {
            logger.info("Adding welcome page: " + welcomePage);
            this.setRootViewName("forward:index.html");
        } else if (this.welcomeTemplateExists(templateAvailabilityProviders, applicationContext)) {
            logger.info("Adding welcome page template: index");
            this.setRootViewName("index");
        }

    }

请求参数处理

请求映射

Rest风格支持(使用HTTP请求方式动词来表示对资源的操作)

  • 以前: /getUser:获取用户 /deleteUser:删除用户 /editUser:修改用户 /saveUser:保存用户
  • 现在: /user GET-获取用户 DELETE-删除用户 PUT-修改用户 POST-保存用户
  • 核心Filter:HiddenHttpMethodFilter
    要想使filter生效,需要现在配置文件中将spring.mvc.hiddenmethod.filter变成可用的
    @Bean
    @ConditionalOnMissingBean({HiddenHttpMethodFilter.class})
    @ConditionalOnProperty(
        prefix = "spring.mvc.hiddenmethod.filter",
        name = {"enabled"}
    )
    public OrderedHiddenHttpMethodFilter hiddenHttpMethodFilter() {
        return new OrderedHiddenHttpMethodFilter();
    }
   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);
    }

因为表单提交只能提交get和post请求,如果要提交delete和put请求,需要指定表单是post请求,并且要有name为_method的参数,value是delete或put,大小写都可以

<form method="post">
	<input name="_method" type="hidden" value="delete"/>
</form>

原理:
需要指定表单是post请求:

if ("POST".equals(request.getMethod())

不用区分大小写,代码里会统一转为大写

String method = paramValue.toUpperCase(Locale.ENGLISH);

value必须是delete或put时才会被识别

    static {
        ALLOWED_METHODS = Collections.unmodifiableList(Arrays.asList(HttpMethod.PUT.name(), HttpMethod.DELETE.name(), HttpMethod.PATCH.name()));
    }

以上只适用于表单提交
如果是用客户端提交,比如post,直接发送delete或put请求,此时就不会转成HttpMethodRequestWrapper

也可以自定义name,默认是_method,创建完以下配置之后,name就是_m了

package com.study.springboot2.config;

import org.springframework.context.annotation.Configuration;
import org.springframework.web.filter.HiddenHttpMethodFilter;

@Configuration(proxyBeanMethods = false)
public class WebConfig {

    public HiddenHttpMethodFilter hiddenHttpMethodFilter(){
        HiddenHttpMethodFilter methodFilter = new HiddenHttpMethodFilter();
        methodFilter.setMethodParam("_m");
        return methodFilter;
    }
}

请求映射原理

所有的请求都会使用DispatcherServlet,直接在idea里使用Ctrl+n搜索该类。
该类下的核心方法
会有五种handlerMapping

  • RequestMappingHandlerMapping:自定义controller的请求映射都在这个HandlerMapping里
  • BeanNameUrlHandlerMapping
  • RouterFunctionMapping
  • SimpleUrlHandlerMapping
  • WelcomePageHandlerMapping: 欢迎页的请求处理
    @Nullable
    protected HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
        if (this.handlerMappings != null) {
            Iterator var2 = this.handlerMappings.iterator();

            while(var2.hasNext()) {
                HandlerMapping mapping = (HandlerMapping)var2.next();
                HandlerExecutionChain handler = mapping.getHandler(request);
                if (handler != null) {
                    return handler;
                }
            }
        }

        return null;
    }
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
好的,我可以和你分享一些关于Spring Boot的学习笔记。 1. Spring Boot是什么? Spring Boot是一个基于Spring框架的快速开发框架,它能够帮助开发者快速搭建Spring项目,简化了Spring应用开发的繁琐过程,提高了开发效率。 2. Spring Boot的优点有哪些? Spring Boot的优点有很多,其中包括: - 简化了Spring应用的开发,提高了开发效率; - 集成了很多常用的第三方库,减少了依赖管理的工作; - 自动化配置,减少了配置文件的编写工作; - 内嵌了Tomcat等Web容器,使得应用的部署更加便捷; - 提供了Actuator等模块,使得应用的监控和管理更加便捷。 3. Spring Boot的核心注解有哪些? Spring Boot的核心注解包括: - @SpringBootApplication:标注在启动类上,代表这是一个Spring Boot应用; - @Controller:标注在控制器类上,处理HTTP请求; - @Service:标注在服务类上,用于处理业务逻辑; - @Repository:标注在数据访问类上,用于数据库访问; - @Configuration:标注在配置类上,用于配置Spring应用上下文。 4. Spring Boot的配置文件有哪些? Spring Boot的配置文件包括: - application.properties:基于Key-Value的属性文件; - application.yml:基于YAML语法的配置文件。 5. 如何使用Spring Boot集成数据库? 使用Spring Boot集成数据库需要完成以下几个步骤: - 在pom.xml中添加相关数据库依赖; - 配置数据源和JPA/Hibernate等相关配置; - 编写实体类和DAO层代码。 以上就是一些关于Spring Boot的学习笔记,希望能对你有所帮助。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值