欢迎您访问 最编程 本站为您分享编程语言代码,编程技术文章!
您现在的位置是: 首页

123.【透析SpringBoot源码B】(第三部分)

最编程 2023-12-31 13:30:31
...
(1.2)、资源处理的默认规则
因为这里分析得到: 假如resourceProperties.isAddMappings()为false下面的业务逻辑都不生效,也就是说默认配置的路径都不会生效。
@Override
    public void addResourceHandlers(ResourceHandlerRegistry registry) {
    // 静态资源是否全部生效
  ⭐   if (!this.resourceProperties.isAddMappings()) {
        logger.debug("Default resource handling disabled");
        return;
      }
      Duration cachePeriod = this.resourceProperties.getCache().getPeriod();
      CacheControl cacheControl = this.resourceProperties.getCache().getCachecontrol().toHttpCacheControl();
      //webjars的规则
            if (!registry.hasMappingForPattern("/webjars/**")) {
        customizeResourceHandlerRegistration(registry.addResourceHandler("/webjars/**")
            .addResourceLocations("classpath:/META-INF/resources/webjars/")
            .setCachePeriod(getSeconds(cachePeriod)).setCacheControl(cacheControl));
      }
            
            //
      String staticPathPattern = this.mvcProperties.getStaticPathPattern();
      if (!registry.hasMappingForPattern(staticPathPattern)) {
        customizeResourceHandlerRegistration(registry.addResourceHandler(staticPathPattern)
      ⭐     .addResourceLocations(getResourceLocations(this.resourceProperties.getStaticLocations()))
            .setCachePeriod(getSeconds(cachePeriod)).setCacheControl(cacheControl));
      }
    }
spring:
  mvc:
#    静态资源路径
    static-path-pattern: /res/**
  web:
    resources:
#    静态资源目录位置
      static-locations: classpath:/haha
      add-mappings: false   禁止访问静态页面

网络异常,图片无法展示
|

@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;
(1.3)、静态页的欢迎规则
HandlerMapping:处理器映射。保存了每一个Handler能处理哪些请求。  
  @Bean
    public WelcomePageHandlerMapping welcomePageHandlerMapping(ApplicationContext applicationContext,
        FormattingConversionService mvcConversionService, ResourceUrlProvider mvcResourceUrlProvider) {
      WelcomePageHandlerMapping welcomePageHandlerMapping = new WelcomePageHandlerMapping(
          new TemplateAvailabilityProviders(applicationContext), applicationContext, getWelcomePage(),
          this.mvcProperties.getStaticPathPattern());
      welcomePageHandlerMapping.setInterceptors(getInterceptors(mvcConversionService, mvcResourceUrlProvider));
      welcomePageHandlerMapping.setCorsConfigurations(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)) {
            // 调用Controller  /index
      logger.info("Adding welcome page template: index");
      setRootViewName("index");
    }
  }

欢迎页 静态资源路径如果不是 /** 那么欢迎页将不会生效

网络异常,图片无法展示
|

3.请求参数处理

(1).请求映射
(1.1)、rest使用与原理
  • @xxxMapping;
  • Rest风格支持(使用HTTP请求方式动词来表示对资源的操作)
  • 以前:/getUser 获取用户 /deleteUser 删除用户 /editUser 修改用户 /saveUser 保存用户
  • 现在: /user GET-获取用户 DELETE-删除用户 PUT-修改用户 POST-保存用户
  • 核心Filter;HiddenHttpMethodFilter
  • 用法: 表单method=post,隐藏域 _method=put
  • SpringBoot中手动开启
  • 扩展:如何把_method 这个名字换成我们自己喜欢的。
  1. 前端页面

问题:我们后端有四种风格提交Http的风格,而前端只有两种分别为: post、get。如果我们强制把前端的两种提交方式修改成 DELETE风格和 PUT风格,我们发现在后端运行的时候会默认给我们走成 GET风格。这里的原因是我们需要对SpringMVC源码进行查看。

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<h1>你好</h1>
<form action="/user" method="post">
    <button type="submit">Post方式进行跳转</button>
</form>
<form action="/user" method="get">
    <button type="submit">Get方式进行跳转</button>
</form>
<form action="/user" method="post">
    <input name="_method" type="hidden" value="DELETE">
    <button type="submit">DELETE方式进行跳转</button>
</form>
<form action="/user" method="post">
    <input name="_method" type="hidden" value="PUT">
    <button type="submit">PUT方式进行跳转</button>
</form>
</body>
</html>

业务控制层:

package com.jsxs.controller;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;
/**
 * @Author Jsxs
 * @Date 2023/7/2 10:54
 * @PackageName:com.jsxs.controller
 * @ClassName: HelloController
 * @Description: TODO
 * @Version 1.0
 */
@Controller
@ResponseBody
public class HelloController {
    @GetMapping("/1.jpg")
    public String hello(){
        return "aaa";
    }
    @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-张三";
    }
}

在没有配置和遵从SpringMVC源码的情况下,我们是不能实现对多种提交方式进行处理的。

网络异常,图片无法展示
|

  1. SpringMvc源码

所有的提交方式源码在这里

@Bean
    @ConditionalOnMissingBean({HiddenHttpMethodFilter.class})
    @ConditionalOnProperty(
        prefix = "spring.mvc.hiddenmethod.filter",
        name = {"enabled"},
        matchIfMissing = false
    )
    public OrderedHiddenHttpMethodFilter hiddenHttpMethodFilter() {
 ⭐       return new OrderedHiddenHttpMethodFilter();
    }

点进OrderedHiddenHttpMethodFilter

//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by FernFlower decompiler)
//
package org.springframework.boot.web.servlet.filter;
import org.springframework.web.filter.HiddenHttpMethodFilter;
public class OrderedHiddenHttpMethodFilter extends ⭐ HiddenHttpMethodFilter implements OrderedFilter {
    public static final int DEFAULT_ORDER = -10000;
    private int order = -10000;
    public OrderedHiddenHttpMethodFilter() {
    }
    public int getOrder() {
        return this.order;
    }
    public void setOrder(int order) {
        this.order = order;
    }
}

点进 HiddenHttpMethodFilter

public class HiddenHttpMethodFilter extends OncePerRequestFilter {
    private static final List<String> ALLOWED_METHODS;
    public static final String DEFAULT_METHOD_PARAM = "_method";
    private String methodParam = "_method";
  
    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);
    }
}

得出结论: 假如我们要使用其他的提交方式,首先我们要对 spring.mvc.hiddenmethod.filter.enables 默认的false更改为true。然后我们表单的提交方式要设置为 post 方式进行提交。然后再添加一个隐藏的文本框,将其的name设置成 源码需要的 _methods 并对这个隐藏的文本框进行设置值为 我们想要的提交方式 (DELETEPUT)

Rest原理(表单提交要使用REST的时候)

  • 表单提交会带上_method=PUT
  • 请求过来被HiddenHttpMethodFilter拦截
  • 请求是否正常,并且是POST
  • 获取到_method的值。
  • 兼容以下请求;PUT.DELETE.PATCH
  • 原生request(post),包装模式requesWrapper重写了getMethod方法,返回的是传入的值。
  • 过滤器链放行的时候用wrapper。以后的方法调用getMethod是调用requesWrapper的。

Rest使用客户端工具

  • 如PostMan直接发送Put、delete等方式请求,无需Filter。

上一篇: Krita笔刷使用心得(MyPaint笔刷资源)-声明:线稿来源于网络。

下一篇: (6.1)每日一练_18 题目:使用Java剔除字符串中的所有非数字字符(例如:将“ab123you“转换为“123“)