SpringBoot第七天 - Web参数处理

本文详细探讨了SpringBoot中Web参数的处理方式,包括注解方式、Servlet API、复杂参数和自定义POJO类型参数的绑定原理。重点讲解了@MatrixVariable注解,用于接收请求路径中的矩阵变量,以及参数解析器如何工作来处理各种类型的参数。
摘要由CSDN通过智能技术生成

SpringBoot - Web参数处理

探讨SpringBoot接收和处理参数的方式。

1. 注解方式

SpringMVC为我们提供了许多注解来接收参数。

1.1 常用注解

SpringMVC常用的9个参数绑定注解:

  1. @RequestParam 接收请求中的参数;
  2. @RequestBody 接收请求体内容;
  3. @RequestHeader 接收请求头内容;
  4. @RequestAttribute 接收Request域中的参数;
  5. @PathVariable 接收请求路径中的路径变量;
  6. @CookieValue 接收Cookie中的参数;
  7. @SessionAttributes 接收Session域中的参数;
  8. @ModelAttribute 接收隐含模型中的参数;
  9. @MatrixVariable 接收请求路径中的矩阵变量。

1.2 @MatrixVariable

其他注解在学习SpringMVC时就已经了解过了,现在单独学习@MatrixVariable。

1.2.1 矩阵变量

一道经典的面试题:

现在Cookie被禁用了,如何获取Session域中的内容?

由于服务器是按照Cookie中的一个参数JSESSIONID(初次访问服务器才会有)来查找Session对象,
从而获取Session域中的内容。现在Cookie被禁用,服务器无法获取JSESSIONID,
所以也就无法获取Session域的内容。

我们可以使用URL重写的方式让URL携带JSESSIONID:

localhost:8080/example;JSESSIONID=ghco9xdnaco31gmafukxchph

使用这种方式传递的参数就叫矩阵变量,可以使用@MatrixVariable注解接收并绑定。

1.2.2 矩阵变量的语法

在路径变量后面加分号后写在后面,多个矩阵变量用分号隔开,
可以在任何路径变量后加:

localhost:8080/example;id=1/example;id=2;name=张三
1.2.3 矩阵变量的类型
  • 单个类型,不可再分的类型(如数字,字符串等):
localhost:8080/example;name=张三;sex=男
  • 集合类型(List):
第一种写法:变量值可以写在一起,多个值用逗号隔开:
localhost:8080/example;sex=男,女

第二种写法:变量值不写在一起,多个值用分号隔开:
localhost:8080/example;sex=男;sex=女
1.2.4 作用

注解@MatrixVariable用来接收请求路径中的矩阵变量。

1.2.5 作用范围
  • 方法参数(ElementType.PARAMETER)
1.2.6 属性
  • String name/value:指定接收的矩阵变量的名称;
  • String pathVar:指定矩阵变量所在的路径变量:

    当不同的路径变量位置的矩阵变量同名时,可以指定此值来作为区分;
  • boolean required:指定该变量不存在时是否抛出异常;
  • String defaultValue:指定该变量不存在时的默认值。
1.2.7 使用方式(原理)

SpringBoot默认禁用了矩阵变量,原理分析:

在SpringBoot对WebMVC的自动配置类中:

// org.springframework.boot.autoconfigure.web.servlet.WebMvcAutoConfiguration
// WebMvcAutoConfiguration.java Line:179~322

// ... 省略其他代码
// 此类为WebMvcAutoConfiguration自动配置类的内部类,为WebMVC的配置类,实现了WebMvcConfigurer接口。
public static class WebMvcAutoConfigurationAdapter implements WebMvcConfigurer {
   

    // ... 省略其他代码
    
    // 此方法配置了路径匹配规则
    @Override
    public void configurePathMatch(PathMatchConfigurer configurer) {
   
        if (this.mvcProperties.getPathmatch()
                .getMatchingStrategy() == WebMvcProperties.MatchingStrategy.PATH_PATTERN_PARSER) {
   
            configurer.setPatternParser(new PathPatternParser());
        }
        configurer.setUseSuffixPatternMatch(this.mvcProperties.getPathmatch().isUseSuffixPattern());
        configurer.setUseRegisteredSuffixPatternMatch(
                this.mvcProperties.getPathmatch().isUseRegisteredSuffixPattern());
        this.dispatcherServletPath.ifAvailable((dispatcherPath) -> {
   
            String servletUrlMapping = dispatcherPath.getServletUrlMapping();
            if (servletUrlMapping.equals("/") && singleDispatcherServlet()) {
   
                // 使用UrlPathHelper帮助解析请求路径
                UrlPathHelper urlPathHelper = new UrlPathHelper();
                urlPathHelper.setAlwaysUseFullPath(true);
                configurer.setUrlPathHelper(urlPathHelper);
            }
        });
    }
    
    // ... 省略其他代码
    
}

SpringMVC是使用了UrlPathHelper来帮助解析请求路径的,
对矩阵变量的处理如下:

// org.springframework.web.util.UrlPathHelper
// UrlPathHelper.java 

public class UrlPathHelper {
   
    
    // ... 省略其他代码

    // 是否移除分号内容(矩阵变量)
	private boolean removeSemicolonContent = true;
	
	// 是否移除矩阵变量的Setter
	public void setRemoveSemicolonContent(boolean removeSemicolonContent) {
   
		checkReadOnly();
		this.removeSemicolonContent = removeSemicolonContent;
	}
	
	// 获取是否应该移除矩阵变量
	public boolean shouldRemoveSemicolonContent() {
   
		checkReadOnly();
		return this.removeSemicolonContent;
	}

    // 过滤URI
	private String decodeAndCleanUriString(HttpServletRequest request, String uri) {
   
		// 此处将矩阵变量从URI中移除
	    uri = removeSemicolonContent(uri);
		uri = decodeRequestString(request, uri);
		uri = getSanitizedPath(uri);
		return uri;
	}

	// 移除矩阵变量
	public String removeSemicolonContent(String requestUri) {
   
	    // 判断是否需要移除矩阵变量,如果是那就移除,如果不是仅移除JSESSIONID
		return (this.removeSemicolonContent ?
				removeSemicolonContentInternal(requestUri) : removeJsessionid(requestUri));
	}

	// 移除矩阵变量的具体过程,这里就不在分析
	private static String removeSemicolonContentInternal(String requestUri) {
   
		int semicolonIndex = requestUri.indexOf(';');
		if (semicolonIndex == -1) {
   
			return requestUri;
		}
		StringBuilder sb = new StringBuilder(requestUri);
		while (semicolonIndex != -1) {
   
			int slashIndex = sb.indexOf("/", semicolonIndex + 1);
			if (slashIndex == -1) {
   
				return sb.substring(0, semicolonIndex);
			}
			sb.delete(semicolonIndex, slashIndex);
			semicolonIndex = sb.indexOf(";", semicolonIndex);
		}
		return sb.toString();
	}
	
	// ... 省略其他代码
	
}

可以看到UrlPathHelper是默认移除分号后的内容的,即禁用了矩阵变量。

我们可以定制化SpringBoot来启用矩阵变量。有两种定制化方式:

  1. 在容器中添加一个WebMvcConfigurer接口的实现类(可以使用匿名内部类),
    重写configurePathMatch方法并设置UrlPathHelper不移除分号内容:
@Bean
public WebMvcConfigurer matrixVariableEnabledWebConfigurer() {
   
    return new WebMvcConfigurer() {
   
        @Override
        public void configurePathMatch(PathMatchConfigurer configurer) {
   
            UrlPathHelper urlPathHelper = new UrlPathHelper();
            // 设置启用矩阵变量
            urlPathHelper.setRemoveSemicolonContent(false);
            configurer.setUrlPathHelper(urlPathHelper);
        }
    };
}
  1. 编写一个配置类并实现WebMvcConfigurer接口,
    重写configurePathMatch方法并设置UrlPathHelper不移除分号内容:
@Configuration
public class WebMvcConfig implements WebMvcConfigurer {
   
    @Override
    public void configurePathMatch(PathMatchConfigurer configurer) {
   
        UrlPathHelper urlPathHelper = new UrlPathHelper();
        // 设置启用矩阵变量
        urlPathHelper.setRemoveSemicolonContent(false);
        configurer.setUrlPathHelper(urlPathHelper);
    }
}

启用了矩阵变量之后就可以使用@MatrixVariable编写处理器了:

// 矩阵变量需要绑定一个路径变量
@RequestMapping("/example/{param}")
@ResponseBody
public Object matrixVariable(
    @PathVariable("param") String param,
    @MatrixVariable("id") Integer id,
    @MatrixVariable("value") List<String
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值