Spring MVC 请求参数及数据传入

  • HttpServlet中,可以通过request.getParameter()获取请求传入的参数、通过request.getHeader()获取请求头内容、通过request.getRequestURL()获取请求的URL。
  • 而在Spring MVC中,可以直接通过注解的方式获取请求相关的各类信息。
  • Spring MVC 框架会将 HTTP 请求的信息绑定到相应的方法入参中,并根据方法的返回值类型做出相应的后续处理。

@RequestParam注解

  • 在处理方法入参处使用 @RequestParam 可以把请求参数传递给请求方法
    • value:参数名
    • required:是否必须。默认为 true, 表示请求参数中必须包含对应的参数,若不存在,将抛出异常
    • defaultValue: 默认值,当没有传递参数时使用该值

代码

@RequestMapping("/requestParamTest")
String requestParamTest(@RequestParam(value = "id", defaultValue = "0") Integer id,
                        @RequestParam(value = "name", required = true) String name) {
  System.out.println("id : " + id);
  System.out.println("name : " + name);
  System.out.println("Person : " + new Person(name, id));
  return "hello";
}
<form action="requestParamTest" method="get">
    <label>id
        <input type="text" name="id"/>
    </label><br/>
    <label>name
        <input type="text" name="name"/>
    </label><br/>
    <input type="submit" value="submit">
</form><br/>

通过@RequestParamvalue值和input标签的name值对应。

  @RequestMapping("/requestParamTest3")
  String requestParamTest3(Integer id, String name) {
    System.out.println("id : " + id);
    System.out.println("name : " + name);
    System.out.println("Person : " + new Person(name, id));
    return "hello";
  }
    <form action="requestParamTest3" method="get">
        <label>id
            <input type="text" name="id"/>
        </label><br/>
        <label>name
            <input type="text" name="name"/>
        </label><br/>
        <input type="submit" value="submit">
    </form><br/>

当@RequestParamvalue值和input标签的name值相同时,注解可以省略

@RequestHeader 注解

  • 通过 @RequestHeader 即可将请求头中的属性值绑定到处理方法的入参中

代码

@RequestMapping("/requestHeaderTest")
String requestHeaderTest(@RequestHeader("Accept-Language") String acceptLanguage,
                         @RequestHeader("User-Agent")String userAgent) {
  System.out.println("Accept-Language : " + acceptLanguage);
  System.out.println("User-Agent : " + userAgent);
  return "hello";
}

@CookieValue 注解

  • @CookieValue 可让处理方法入参绑定某个 Cookie 值

代码

@RequestMapping("/cookieValueTest")
String cookieValueTest(@CookieValue(value="JSESSIONID", required=false) String JSESSIONID) {
  System.out.println("JSESSIONID : " + JSESSIONID);
  return "hello";
}

@PathVariable 注解

  • 常用于Rest风格的参数传入。在URL上添加参数,然后在处理的时候,直接将参数提取,作为参数输入到方法上。

代码

@GetMapping("/testPathVariable/{variable}")
public String testPathVariable(@PathVariable Integer variable) {
  log.info(variable.toString());
  return variable.toString();
}

http://localhost:8080/testPathVariable/10输入时,variable 为 10

@RequestBody 注解

  • 当注解方法入参的时候,如果是对应的Java Bean,就会对Java Bean的属性进行注入;如果参数是String类型,就会将整个请求体交给该参数。
  • @RequestBody 标注,可以处理json格式的请求体

代码

@RequestMapping("/getJsonTest")
  public String getJsonTest(@RequestBody Employee employee) {
    System.out.println(employee);
    return "success";
  }

  @RequestMapping("/requestBodyTest")
  public String requestBodyTest(@RequestBody String requestBody) {
    System.out.println(requestBody); // {"id":0,"name":"john","gender":"male"}
    return "success";
  }

@MatrixVariable 注解

  • 可以实现通过另一种方式,传递参数。在路径变量上,通过; 分割,添加多个参数。如http://localhost:8080/testMatrixVariable/a;mv1=b;mv2=c
    @GetMapping("/testMatrixVariable/{pathVariable}")
      public Map<String, Object> testMatrixVariable(@PathVariable String pathVariable,
                                                    @MatrixVariable("mv1") String mv1,
                                                    @MatrixVariable("mv2") String mv2) {
        log.info(pathVariable);  // a
        log.info(mv1);  // b
        log.info(mv2);  // c
        Map<String, Object> map = new HashMap<>();
        map.put("pathVariable", pathVariable);
        map.put("mv1", mv1);
        map.put("mv2", mv2);
        return map;
      }
    
  • 但是,该方法默认不能实现。因为底层有一个UrlPathHelper 用于处理请求过来的Url,默认将private boolean removeSemicolonContent = true;,将分号后面的内容去除。因此,还需要自己配置,将该值设为false
    @Configuration(proxyBeanMethods = false)
    public class Config {
      @Bean
      public WebMvcConfigurer webMvcConfigurer() {
        return new WebMvcConfigurer() {
          @Override
          public void configurePathMatch(PathMatchConfigurer configurer) {
            UrlPathHelper urlPathHelper = new UrlPathHelper();
            urlPathHelper.setRemoveSemicolonContent(false);
            configurer.setUrlPathHelper(urlPathHelper);
          }
        };
      }
    }
    

使用POJO作为参数

  • Spring MVC 会按请求参数名和 POJO 属性名进行自动匹配,自动为该对象填充属性值。支持级联属性

代码

// java bean
public class Father extends Person {
  private Person son;
  /*忽略get、set、toString方法*/
// java bean
public class Person {
	private Integer id;
	private String name;
	/*忽略get、set、toString方法*/
}
@RequestMapping("requestParamTest2")
String requestParamTest2(Person person) {
	System.out.println("Person : " + person);
	return "hello";
}
    <form action="requestParamTest2" method="get">
        <label>id
            <input type="text" name="id"/>
        </label><br/>
        <label>name
            <input type="text" name="name"/>
        </label><br/>
        <input type="submit" value="submit">
    </form><br/>

Spring MVC会根据 input 标签的 name 匹配 pojo 的属性。

  @RequestMapping("/requestParamTest4")
  String requestParamTest4(Father father) {
    System.out.println("father : " + father);
    return "hello";
  }
<form action="requestParamTest4" method="post">
    <label>id
        <input type="text" name="id"/>
    </label><br/>
    <label>name
        <input type="text" name="name"/>
    </label><br/>
    <label>son.id
        <input type="text" name="son.id"/>
    </label><br/>
    <label>son.name
        <input type="text" name="son.name"/>
    </label><br/>
    <input type="submit" value="submit">
</form><br/>

级联的pojo,通过属性名.属性名的方式定位。

使用Servlet原生API作为参数

  • MVC 的 Handler 方法(Controller中的方法)可以接受的ServletAPI 类型的参数
    • HttpServletRequest:就是Servlet中的那个request
    • HttpServletResponse:就是Servlet中的那个response
    • HttpSession:就是通过request.getSession()获取的那个session
    • java.security.Principal
    • Locale
    • InputStream:就是通过request.getInputStream()获取的那个InputStream
    • OutputStream:就是通过response.getOutputStream()获取的那个OutputStream
    • Reader:就是通过request.getReader()获取的那个Reader
    • Writer:就是通过response.getWriter()获取的那个Writer
@RequestMapping("/rawApiTest")
 String rawApiTest(Locale locale) {
   System.out.println(locale);
   return "hello";
 }

源代码解析

参数的传入过程

  • 重点是一个叫做HandlerMethodArgumentResolver 的参数解析器。通过该解析器,将传入的参数与方法参数进行一一绑定。
  • 执行步骤如下:
  • DispatcherServlet中的doDispatch()方法,真正执行处理请求。而到了真正方法执行的一步,会先查找参数,再通过反射执行方法
  • doDispatch(),执行方法
    在这里插入图片描述
  • 适配器中执行方法
    在这里插入图片描述
  • 依旧在适配器内,将所有的参数解析器放入要被一个叫invocableMethod 的对象中(该对象存储了要执行的方法和参数之类的信息)。此时有27个不同的参数解析器。
    在这里插入图片描述
    在这里插入图片描述
  • 再次进入一个要执行方法的对象
    在这里插入图片描述
  • 该方法里面,又有一个执行方法的方法
    在这里插入图片描述
  • 然后就先解析参数,再执行方法。这个应该是最重要的过程了。
    在这里插入图片描述
  • 首先,在getArgumentResolver 方法中找到指定的解析器,然后调用解析器的resolveArgument 方法,解析参数。
  • 而找到解析器的步骤也很简单,就是遍历所有解析器,看哪个支持,就直接返回该解析器。
      @Nullable
      public Object resolveArgument(MethodParameter parameter, @Nullable ModelAndViewContainer mavContainer, NativeWebRequest webRequest, @Nullable WebDataBinderFactory binderFactory) throws Exception {
        HandlerMethodArgumentResolver resolver = this.getArgumentResolver(parameter);
        if (resolver == null) {
          throw new IllegalArgumentException("Unsupported parameter type [" + parameter.getParameterType().getName() + "]. supportsParameter should be called first.");
        } else {
          return resolver.resolveArgument(parameter, mavContainer, webRequest, binderFactory);
        }
      }
      
      @Nullable
      private HandlerMethodArgumentResolver getArgumentResolver(MethodParameter parameter) {
        HandlerMethodArgumentResolver result = (HandlerMethodArgumentResolver)this.argumentResolverCache.get(parameter);
        if (result == null) {
          Iterator var3 = this.argumentResolvers.iterator();
    
          while(var3.hasNext()) {
            HandlerMethodArgumentResolver resolver = (HandlerMethodArgumentResolver)var3.next();
            if (resolver.supportsParameter(parameter)) {
              result = resolver;
              this.argumentResolverCache.put(parameter, resolver);
              break;
            }
          }
        }
    
        return result;
      }
    
  • 解析参数,如今就进入 了一个抽象的参数解析器内部了
    在这里插入图片描述
  • 进入到具体的参数解析器内部,并在request中找到了想要的参数。
    在这里插入图片描述
  • 至此,参数解析就完成了。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值