SpringBoot入门(四)请求参数处理(一)
发布日期:2022-03-04 11:48:24 浏览次数:1 分类:技术文章

本文共 9966 字,大约阅读时间需要 33 分钟。

目录


第七章 Web开发

7.3 请求参数处理

7.3.1 请求映射

7.3.1.1 Rest使用与原理

在一个方法上加注解@RequestMapping,来声明这个方法能处理什么请求,这个声明过程就是请求映射。

  • Rest风格支持:使用Http请求方式的动词来表示对资源的操作
    • 以前:/getUser   获取用户  /deleteUser 删除用户   /editUser  修改用户   /saveUser 保存用户
    • 现在:/user(路径都是一样的) GET-获取用户 DELETE-删除用户 PUT-修改用户 POST-保存用户
    • Rest风格实现的核心Filter:HiddenHttpMethodFilter
      • WebMvcAutoConfiguration类中有一个方法hiddenHttpMethodFilter()

      • OrderedHiddenHttpMethodFilter要继承HiddenHttpMethodFilter

      • 用法:表单method=post,使用post请求方式。隐藏域_method=put

      • SpringBoot中手动开启

@Bean@ConditionalOnMissingBean({HiddenHttpMethodFilter.class})@ConditionalOnProperty(
prefix = "spring.mvc.hiddenmethod.filter",
name = {"enabled"})public OrderedHiddenHttpMethodFilter hiddenHttpMethodFilter() {
return new OrderedHiddenHttpMethodFilter();}
public class OrderedHiddenHttpMethodFilter extends HiddenHttpMethodFilter implements OrderedFilter {}
public class HiddenHttpMethodFilter extends OncePerRequestFilter {
private static final List  ALLOWED_METHODS;
public static final String DEFAULT_METHOD_PARAM = "_method";
private String methodParam = "_method";//后续可以在自定义的组件中修改这个参数实现自定义名字
//允许put、delete、patch
static {
ALLOWED_METHODS = Collections.unmodifiableList(Arrays.asList(HttpMethod.PUT.name(), HttpMethod.DELETE.name(), HttpMethod.PATCH.name()));
}
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
HttpServletRequest requestToUse = request;
//需要是post请求方式,参数是_method
if ("POST".equals(request.getMethod()) && request.getAttribute("javax.servlet.error.exception") == null) {
//获取_method属性的值
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);
}}
private static class HttpMethodRequestWrapper extends HttpServletRequestWrapper {
private final String method;
public HttpMethodRequestWrapper(HttpServletRequest request, String method) {
super(request);
this.method = method;//保存新的请求方式,即从_method中得到的值
}
public String getMethod() {
return this.method;//然后把这个新的请求方式返回
}}

   具体实现:

spring:  mvc:
hiddenmethod:
  filter:
enabled: true #手动开启该功能

  • Rest原理(表单提交使用Rest的时候):总体来看就是用一个过滤器把原生请求的getMethod方法重写了,换成了新的请求方式。
    • 表单提交会带上_method=PUT
    • 请求过来被HiddenHttpMethodFilter拦截
      • 请求是否正常,并且是POST
        • 获取到_method的值

        • 兼容以下请求;PUT.DELETE.PATCH

        • 原生request(post),包装模式requesWrapper重写了getMethod方法,返回的是_method的值。
        • 过滤器链放行的时候用wrapper。以后的方法调用getMethod是调用requesWrapper的。
  • Rest如果使用客户端工具
    • 如PostMan可以直接发送put、delete等请求方式,就不需要这个Filter了。此时请求一开始就不是post了,也就没有进入后续方法的条件。

  • SpringBoot中因此也产生了新注解,但其实底层实现的就是@RequestMapping
    • @GetMapping("/user")
    • @PostMapping("/user")
    • @PutMapping("/user")
    • @DeleteMapping("/user")
  • 如何修改_method,改成自定义的
    • 底层实现是如果没有手动写HiddenHttpMethodFilter.class这个组件,那么默认就会自动创建一个这个组件,默认判断的就是_method
    • 可以自己定义一个HiddenHttpMethodFilter.class。

7.3.1.2 请求映射原理

   底层还是SpringMVC,所有请求都会到DispatcherServlet

   SpringMVC功能分析都从org.springframework.web.servlet.DispatcherServlet->doDispatch()

protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {
//传入原生的request、response
HttpServletRequest processedRequest = request;
HandlerExecutionChain mappedHandler = null;
boolean multipartRequestParsed = false;//是不是一个文件上传请求
WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);//异步管理器
try {
try {
ModelAndView mv = null;
Object dispatchException = null;
try {
//checkMultipart检查是否是文件上传请求
processedRequest = this.checkMultipart(request);
//如果是文件上传请求,进行一个转化
multipartRequestParsed = processedRequest != request;
//找到当前请求使用哪个Handler(Controller的方法)处理
mappedHandler = this.getHandler(processedRequest);

        getHandler方法中,handlerMapping:处理器映射。/xxx->>xxxx,即各种映射规则。

@Nullableprotected 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;}

        RequestMappingHandlerMapping:保存了所有@RequestMapping注解和handler的映射

      规则。

        比如请求调用getUser()过程,先按照写的"/user"找到四种可能的(get、post、delete、put),

      再从这四种中找到最匹配的那个。注意因此要求对同一种请求,只能有一个最匹配的处理方

      式

   应用一启动,SpringMVC自动扫描所有的controller并解析注解,把这些注解信息全部保存到handlerMapppings中。然后挨个找所有得请求映射,看哪个可以处理请求。

  • 所有的请求映射都在handlerMappings中
    • SpringBoot自动配置欢迎页的WelcomePageHandlerMapping 。访问"/"能访问到index.html
    • SpringBoot自动配置了默认的RequestMappingHandlerMapping
    • 请求进来,挨个尝试所有的HandlerMapping看是否有请求信息

      • 如果有就找到这个请求对应的handler
      • 如果没有就比较下一个 HandlerMapping
    • 我们需要一些自定义的映射处理,我们也可以自己给容器中放HandlerMapping,自定义 HandlerMapping

7.3.2 普通参数与基本注解

7.3.2.1 注解

   @PathVariable:接受请求路径中占位符的值。可以将URL占位符参数{xxx}绑定到处理器类的方法形参中@PathVariable(“xxx“)。

        ①可以一个个取路径中的值

        ②也可以把路径中的所有参数及其值放在一个Map<String,String>中

   @RequestHeader:获取请求头中的数据,通过指定参数value的值来获取请求头中指定的参数值。

        ①可以一个个取请求头中的参数

        ②也可以直接把请求头中的所有参数放在一个Map<String,String>中

   @ModelAttribute运用在参数上,会将客户端传递过来的参数按名称注入到指定对象中,并且会将这个对象自动加入ModelMap中,便于View层使用;被@ModelAttribute注释的方法会在此controller的每个方法执行前被执行 ,如果有返回值,则自动将该返回值加入到ModelMap中。

   @RequestParam:将请求参数绑定到控制器的方法参数上(是springmvc中接收普通参数的注解)

        ①可以一个个取请求参数

        ②也可以直接把所有请求参数放在一个Map<String,String>中

   @MatrixVariable:注解拓展了URl请求地址的功能。使用@MatrixVariable注解时多个变量可以使用;(分号)分隔。矩阵变量绑定在路径变量中。SpringBoot默认关闭这个功能,要自己手动开启。

        原理:WebMvcAutoConfiguration类中的静态类WebMvcAutoConfigurationAdapter中有一个

      方法configurePathMatch(),再查看类UrlPathHelper,里面有一个属性

      removeSemicolonContent,当设置为true时会把URL中";"后面的去掉,而默认为true。需要

      自定义规则:@Configuration + 实现WebMvcConfigurer接口来来自定义规则。

public void configurePathMatch(PathMatchConfigurer configurer) {
if (this.mvcProperties.getPathmatch().getMatchingStrategy() == MatchingStrategy.PATH_PATTERN_PARSER) {
configurer.setPatternParser(WebMvcAutoConfiguration.pathPatternParser);
}
configurer.setUseSuffixPatternMatch(this.mvcProperties.getPathmatch().isUseSuffixPattern());
configurer.setUseRegisteredSuffixPatternMatch(this.mvcProperties.getPathmatch().isUseRegisteredSuffixPattern());
this.dispatcherServletPath.ifAvailable((dispatcherPath) -> {
String servletUrlMapping = dispatcherPath.getServletUrlMapping();
if (servletUrlMapping.equals("/") && this.singleDispatcherServlet()) {
UrlPathHelper urlPathHelper = new UrlPathHelper();
urlPathHelper.setAlwaysUseFullPath(true);
configurer.setUrlPathHelper(urlPathHelper);
}
});}

 

@Configuration(
proxyBeanMethods = false
)@Import({WebMvcAutoConfiguration.EnableWebMvcConfiguration.class})@EnableConfigurationProperties({WebMvcProperties.class, WebProperties.class})@Order(0)public static class WebMvcAutoConfigurationAdapter implements WebMvcConfigurer, ServletContextAware {}public interface WebMvcConfigurer {
default void configurePathMatch(PathMatchConfigurer configurer) {
}}

        第一种实现WebMvcConfigurer接口方式:直接让配置类实现该接口,然后重写方法。

        第二种实现WebMvcConfigurer接口方式:直接在容器中放一个这个类型的组件。

   @CookieValue:用来获取Cookie中的值。

   @RequestBody:用来接收前端传递给后端的json字符串中的数据的(请求体中的数据的),所以只能发送POST请求。GET方式无请求体,所以使用@RequestBody接收数据时,前端不能使用GET方式提交数据,而是用POST方式进行提交。@RequestBody与@RequestParam()可以同时使用,@RequestBody最多只能有一个,而@RequestParam()可以有多个。注:一个请求,只有一个RequestBody;一个请求,可以有多个RequestParam。

   @RequestAttribute:获取request域属性,即获取HTTP的请求(request)对象属性值,用来传递给控制器的参数。

   @ResponseBody:作用是将java对象转为json格式的数据。将controller的方法返回的对象通过适当的转换器转换为指定的格式之后,写入到response对象的body区。

        比如有以下请求:

          get请求:

          post请求:

@RestControllerpublic class ParameterTestController {
//  car/2/owner/zhangsan
@GetMapping("/car/{id}/owner/{username}")
public Map  getCar(@PathVariable("id") Integer id,
 @PathVariable("username") String name,
 @PathVariable Map  pv,
 @RequestHeader("User-Agent") String userAgent,
 @RequestHeader Map  header,
 @RequestParam("age") Integer age,
 @RequestParam("inters") List  inters,
 @RequestParam Map  params,
 @CookieValue("_ga") String _ga,
 @CookieValue("_ga") Cookie cookie){
Map  map = new HashMap<>();//
map.put("id",id);//
map.put("name",name);//
map.put("pv",pv);//
map.put("userAgent",userAgent);//
map.put("headers",header);
map.put("age",age);
map.put("inters",inters);
map.put("params",params);
map.put("_ga",_ga);
System.out.println(cookie.getName()+"===>"+cookie.getValue());
return map;
}
@PostMapping("/save")
public Map postMethod(@RequestBody String content){
Map  map = new HashMap<>();
map.put("content",content);
return map;
}
//1、语法: 请求路径:/cars/sell;low=34;brand=byd,audi,yd
//2、SpringBoot默认是禁用了矩阵变量的功能
//
  手动开启:原理。对于路径的处理。UrlPathHelper进行解析。
//
  removeSemicolonContent(移除分号内容)支持矩阵变量的
//3、矩阵变量必须有url路径变量才能被解析
@GetMapping("/cars/{path}")
public Map carsSell(@MatrixVariable("low") Integer low,
@MatrixVariable("brand") List  brand,
@PathVariable("path") String path){
Map  map = new HashMap<>();
map.put("low",low);
map.put("brand",brand);
map.put("path",path);
return map;
}
// url:/boss/1;age=20/2;age=10
@GetMapping("/boss/{bossId}/{empId}")
public Map boss(@MatrixVariable(value = "age",pathVar = "bossId") Integer bossAge,
@MatrixVariable(value = "age",pathVar = "empId") Integer empAge){
Map  map = new HashMap<>();
map.put("bossAge",bossAge);
map.put("empAge",empAge);
return map;
}}
@Controllerpublic class RequestController {
@GetMapping("/goto")
public String gotoPage(HttpServletRequest request) {
request.setAttribute("msg","成功了"); //向请求作用域中加入参数
request.setAttribute("code",200);
return "forward:/success"; //转发到/success
}
@ResponseBody
@GetMapping("/success")
public Map success(@RequestAttriubute("msg") String msg,
   @RequestAttriubute("code") Integer code,
   HttpServletRequest request) {
Object msg1 = request.getAttribute("msg");
Map  map = new HashMap<>;
map.put("reqMethod_msg",msg1);
map.put("annnotation_masg",msg);
return map;
}}

PS:根据尚硅谷视频整理,如有侵权,联系删除。

转载地址:https://blog.csdn.net/xxyneymar/article/details/122562779 如侵犯您的版权,请留言回复原文章的地址,我们会给您删除此文章,给您带来不便请您谅解!

上一篇:SpringBoot入门(三)yaml文件和静态资源访问及原理
下一篇:力扣题24两两交换链表中的节点

发表评论

最新留言

不错!
[***.36.149.34]2022年07月29日 03时11分32秒

关于作者

    喝酒易醉,品茶养心,人生如梦,品茶悟道,何以解忧?唯有杜康!
-- 愿君每日到此一游!

最新文章