Spring MVC 请求处理方法签名

@RequestMapping 像一个迎宾,将 HTTP 请求正确地迎接到主人的面前(负责处理该请求的方法头主人起身相迎,进而与 HTTP 请求交杯换盏、把酒言欢;最后在欢声笑语中送走 HTTP 请求(返回响应)。Spring MVC 通过分析处理方法的签名,将 HTTP 请求信息绑定到处理方法的相应入参中,然后再调用处理方法得到返回值,最后对返回值进行处理并返回响应。

Spring MVC 对控制器处理方法签名的限制是很宽松的,用户几乎可以按自己喜欢的方式进行方法签名。在必要时对方法及方法入参标注相应的注解(如@PathVariable、@RequestParam、@RequestHeader等)即可,Spring MVC 会优雅地完成剩下的工作:将 HTTP 请求的信息绑定到相应的方法入参中,并根据方法返回值类型做出相应的后续处理。

一般情况下,处理方法的返回值类型为 ModelAndView 或 String,前者包含模型和逻辑视图名,而后者仅代表一个逻辑视图名。下面来看几个典型的方法签名,如下代码所示。

// ①请求参数按名称匹配的方式绑定到方法入参中,方法返回对应的字符串代表逻辑视图名
@RequestMapping(value = "/handle1")
public String handle1(@RequestParam("userName") String userName,
        @RequestParam("password") String password,
        @RequestParam("realName") String realName) {
    return "success";
}

// ②将Cooke值及报文头属性绑定到入参中、方法返回ModelAndView
@RequestMapping(value = "/handle2")
public ModelAndView handle2(@CookieValue("JSESSIONID") String sessionId,
        @RequestHeader("Accept-Language") String accpetLanguage) {
    ModelAndView mav = new ModelAndView();
    mav.setViewName("success");
    mav.addObject("user", new User());
    return mav;
}

// ③请求参数按名称匹配的方式绑定到user的属性中、方法返回对应的字符串代表逻辑视图名
@RequestMapping(value = "/handle3")
public String handle3(User user) {
    return "success";
}

// ④直接将HTTP请求对象传递给处理方法、方法返回对应的字符串代表逻辑视图名
@RequestMapping(value = "/handle4")
public String handle4(HttpServletRequest request) {
    return "success";
}

从上面代码中可以发现,Spring MVC 会结合方法入参类型、入参的注解、返回值的类型,按照“契约”进行相应的处理。

1.使用 @RequestParam 绑定请求参数值

Java 类反射对象默认不记录方法入参的名称,因此需要在方法入参处使用 @RequestParam 注解指定其对应的请求参数。@RequestParam 注解有以下3个参数。

1)value:参数名。

2)required:是否必需,默认为true,表示请求中必须包含对应的参数名,如果不存在则抛出异常。

3)defaultvalue:默认参数名,在设置该参数时,自动将 required 设为 false。极少情况需要使用该参数,也不推荐使用该参数。

下面的实例将 userName 和 age 请求参数分别绑定到 handlel11() 方法的 userName 和 age 中,并自动完成类型转换。如果不存在 age 请求参数,则将抛出异常。

@RequestMapping(value = "/handle11")
public String handle11(
  @RequestParam(value = "userName", required = false) String userName,
  @RequestParam("age") int age) {
  ...
}

2.使用 @CookieValue 绑定请求中的 Cookie 值

使用 @CookieValue 可让处理方法入参绑定某个 Cookie 的值,它和 @RequestParam 拥有3个一样的参数。来看一个使用 @CookieValue 的实例,代码如下:

@RequestMapping(value = "/handle12")
public String handle12(
  @CookieValue(value = "sessionId", required = false) String sessionId,
  @RequestParam("age") int age) {
  ...
}

3.使用 @RequestHeader 绑定请求报文头的属性值

请求报文包含了若干个报文头属性,服务器可据此获知客户端的信息,通过 @RequestHeader 即可将报文头属性值绑定到处理方法的入参中。

@RequestMapping(value = "/handle13")
public String handle13(@RequestHeader("Accept-Encoding") String encoding,
  @RequestHeader("Keep-Alive") long keepAlive) {
  ...
}

4.使用命令/表单对象绑定请求参数值

所谓命令/表单对象并不需要实现任何接口,仅是一个拥有若干属性的POJO。Spring MVC 会按请求参数名和命令/表单对象属性名匹配的方式,自动为该对象填充属性值。支持级联的属性名,如 dept.deptld、dept.address.tel 等。

@RequestMapping(value = "/handle14")
public String handle14(User user) {
    ...
}

假设 User 类的结构如下图所示,则如下的 URL 请求,其请求参数将正确地填充到 User 对象中。

/handle14.html?userName=tom&dept.deptId=1&dept.address.tel=102

5.使用Servlet API 对象作为入参

在 Spring MVC 中,控制器类可以不依赖任何 Servlet API 对象,但是 Spring MVC 并不能阻止我们使用 Servlet API 的类作为处理方法的入参。以下处理方法都可以正确地工作,如下面代码所示。

@RequestMapping(value = "/handle21")
public void handle21(HttpServletRequest request,
        HttpServletResponse response) {
    String userName = request.getParameter("userName");
    response.addCookie(new Cookie("userName", userName));
}

@RequestMapping(value = "/handle22")
public ModelAndView handle22(HttpServletRequest request) {
    String userName = WebUtils.findParameterValue(request, "userName");
    ModelAndView mav = new ModelAndView();
    mav.setViewName("success");
    mav.addObject("userName", userName);
    return mav;
}

@RequestMapping(value = "/handle23")
public String handle23(HttpSession session) {
    session.setAttribute("sessionId", 1234);
    return "success";
}

@RequestMapping(value = "/handle24")
public String handle24(HttpServletRequest request,
        @RequestParam("userName") String userName) {

    return "success";
}

在使用 Servlet API 的类作为入参时,Spring MVC 会自动将 web 层对应的 Servlet 对象传递给处理方法的入参。处理方法入参可以同时使用 Servlet API 类的入参和其他符合要求的入参,它们之间的位置顺序没有特殊要求。

值得注意的是,如果处理方法自行使用 HttpServletResponse 返回响应,则处理方法的返回值设置成 void 即可,如 handle21 所示。

Spring MVC 在 org.springframework.web.context.request 包中定义了若干个可代理 Servlet 原生 API 类的接口,如 WebRequest 和 NativeWebRequest,它们也允许作为处理类的入参,通过这些代理类可访问请求对象的任何信息,如下:

@RequestMapping(value = "/handle25")
public String handle25(WebRequest request) {
    String userName = request.getParameter("userName");
    return "success";
}

6.使用 I/O 对象作为入参

Servlet 的 ServletRequest 拥有 getInputStream() 和 getReader() 方法,可以通过它们读取请求的信息。相应的,Servlet 的 ServletResponse 拥有 getOutputStream() 和 getWriter() 方法,可以通过它们输出响应信息。

Spring MVC 允许控制器的处理方法使用 java.io.InputStream/java.io.Reader 及
java.io.OutputStream/java.io.Writer 作为方法的入参,Spring MVC 将获取 ServletRequest 的 InputStream/Reader 或 ServIetResponse 的 OutputStream/Writer,然后传递给控制器的处理方法,如下代码所示。

@RequestMapping(value = "/handle31")
public void handle31(OutputStream os) throws IOException {
    Resource res = new ClassPathResource("/image.jpg");
    FileCopyUtils.copy(res.getInputStream(), os);
}

7.其他类型的参数

控制器处理方法的入参除支持以上类型的参数外,还支持 java.util.Locale、java.security.Principal,可以通过Servlet 的 HttpServletRequest 的 getLocale() 和 getUserPrincipal() 方法得到相应的值。如果处理方法的入参类型为 Locale 或 Principal,则 Spring MVC 自动从请求对象中获取相应的对象并传递给处理方法的入参。

原文地址:https://www.cnblogs.com/jwen1994/p/11146591.html