SpringMVC 学习笔记

SpringMVC

ServletAPI

SpringMVC 支持使用原始 ServletAPI 对象作为控制器方法的参数,支持原始 ServletAPI 对象有:

  • HttpServletRequest
  • HttpServletResponse
  • HttpSession
  • java.security.Principal
  • Locale
  • InputStream
  • OutputStream
  • Reader
  • Writer

我们可以直接把这些对象写在控制的方法参数中使用

1
2
3
4
5
6
@RequestMapping("/testServletAPI")
public String testServletAPI(HttpServletRequest request,
HttpServletResponse response,
HttpSession session) {
return "success";
}

常用注解

  • @RequestParam

    • 把请求中指定名称的参数给控制器中的形参赋值
    • 属性:
      • value: 请求参数中的名称。
      • required: 请求参数中是否必须提供此参数。默认值:true。表示必须提供,如果不提供将报错。
    1
    2
    3
    4
    5
    6
    @RequestMapping("/useRequestParam")
    public String useRequestParam(@RequestParam("name") String username,
    @RequestParam(value="age",required=false) Integer age){
    System.out.println(username+","+age);
    return "success";
    }
  • @RequestBody

    • 用于获取请求体内容。直接使用得到是 key=value&key=value... 结构的数据。
    • get 请求方式不适用。
    • 属性:
      • required: 是否必须有请求体。默认值是:true。当取值为 true 时,get 请求方式会报错。如果取值 为 false,get 请求得到是 null。
  • @PathVaribale

    • 用于绑定 url 中的占位符。例如:请求 url 中 /delete/{id},这个{id}就是 url 占位符
    • url 支持占位符是 spring3.0 之后加入的,是 springmvc 支持 rest 风格 URL 的一个重要标志。
    • 属性:
      • value: 用于指定 url 中占位符名称。
      • required: 是否必须提供占位符。
    1
    2
    3
    4
    5
    @RequestMapping("/usePathVariable/{id}")
    public String usePathVariable(@PathVariable("id") Integer id){
    System.out.println(id);
    return "success";
    }
  • @RequestHeader

    • 用于获取请求消息头
    • 在实际开发中一般不怎么用。
    • 属性:
      • value: 提供消息头名称。
      • required: 是否必须有此消息头。
  • @CookieValue

    • 用于把指定 cookie 名称的值传入控制器方法参数
    • 属性:
      • value:指定 cookie 的名称。
      • required:是否必须有此 cookie。
    1
    2
    3
    4
    5
    @RequestMapping("/useCookieValue")
    public String useCookieValue(@CookieValue(value="JSESSIONID",required=false) String cookieValue){
    System.out.println(cookieValue);
    return "success";
    }
  • @ModelAttribute

    • 用来将请求参数绑定到 Model 对象
    • 需要注意的是,因为模型对象要先于 controller 方法之前创建,所以被 @ModelAttribute 注解的方法会在 Controller 每个方法执行之前都执行。因此一个 Controller 映射多个 URL 时,要谨慎使用。
      • 因此可以用作控制登录权限,当然控制登录权限的方法有很多,例如拦截器、过滤器等。
1
2
3
4
5
6
7
8
9
10
11
12
// 方法有返回值
@ModelAttribute("name")
public String myModel(@RequestParam(required = false) String name) {
return name;
}
// 等同于 model.addAttribute("name", name);

// 方法无返回值
@ModelAttribute
public void myModel(@RequestParam(required = false) String name, Model model) {
model.addAttribute("name", name);
}

接受请求参数

Spring MVC Controller 接收请求参数的方式有很多种,有的适合 get 请求方式,有的适合 post 请求方式,有的两者都适合。主要有以下几种方式:

  • 通过实体 Bean 接收请求参数

  • 通过处理方法的形参接收请求参数

  • 通过 HttpServletRequest 接收请求参数

  • 通过 @PathVariable 接收 URL 中的请求参数

  • 通过 @RequestParam 接收请求参数

    • 通过实体 Bean 接收请求参数相比会报404错误
  • 通过 @ModelAttribute 接收请求参数

    • @ModelAttribute注解用于将多个请求参数封装到一个实体对象中,从而简化数据绑定流程,而且自动暴露为模型数据,在视图页面展示时使用

    • 通过实体 Bean 接收请求参数中只是将多个请求参数封装到一个实体对象,并不能暴露为模型数据

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      20
      21
      22
      23
      24
      25
      26
      27
      // 通过实体Bean接受请求参数
      @RequestMapping("/login")
      public String login(User user, Model model) {
      if ("bianchengbang".equals(user.getName())
      && "123456".equals(user.getPwd())) {

      model.addAttribute("message", "登录成功");
      return "main"; // 登录成功,跳转到 main.jsp
      } else {
      model.addAttribute("message", "用户名或密码错误");
      return "login";
      }
      }
      // 通过@ModelAttribute接受请求参数
      @RequestMapping("/login")
      public String login(@ModelAttribute("user") User user, Model model) {

      if ("bianchengbang".equals(name)
      && "123456".equals(pwd)) {

      model.addAttribute("message", "登录成功");
      return "main"; // 登录成功,跳转到 main.jsp
      } else {
      model.addAttribute("message", "用户名或密码错误");
      return "login";
      }
      }

重定向和转发

重定向(redirect):将用户从当前处理请求定向到另一个视图(例如 JSP)或处理请求,以前的请求(request)中存放的信息全部失效,并进入一个新的 request 作用域。

转发(forward):将用户对当前处理的请求转发给另一个视图或处理请求,以前的 request 中存放的信息不会失效

转发是服务器行为,重定向是客户端行为。

转发过程

客户浏览器发送 http 请求,Web 服务器接受此请求,调用内部的一个方法在容器内部完成请求处理和转发动作,将目标资源发送给客户;在这里转发的路径必须是同一个 Web 容器下的 URL,其不能转向到其他的 Web 路径上,中间传递的是自己的容器内的 request。

在客户浏览器的地址栏中显示的仍然是其第一次访问的路径,也就是说客户是感觉不到服务器做了转发的。转发行为是浏览器只做了一次访问请求。

重定向过程

客户浏览器发送 http 请求,Web 服务器接受后发送 302 状态码响应及对应新的 location 给客户浏览器,客户浏览器发现是 302 响应,则自动再发送一个新的 http 请求,请求 URL 是新的 location 地址,服务器根据此请求寻找资源并发送给客户。

在这里 location 可以重定向到任意 URL,既然是浏览器重新发出了请求,那么就没有什么 request 传递的概念了。在客户浏览器的地址栏中显示的是其重定向的路径,客户可以观察到地址的变化。重定向行为是浏览器做了至少两次的访问请求

特别的

在 Spring MVC 框架中,不管是重定向或转发,都需要符合视图解析器的配置,如果直接转发到一个不需要 DispatcherServlet 的资源,例如:

1
return "forward:/html/my.html";

则需要使用 mvc:resources 配置:

1
<mvc:resources location="/html/" mapping="/html/**" />

Model和ModelAndView

Model:每次请求中都存在的默认参数,利用其 addAttribute() 方法即可将服务器的值传递到客户端页面中。

ModelAndView:包含 model 和 view 两部分,使用时需要自己实例化,利用 ModelMap 来传值,也可以设置 view 的名称。

类型转换器

Converter<S, T>将一种数据类型转换成另一种数据类型的接口,源类型可以是任意数据类型

//TODO

格式化转换器

Formatter<T>将一种数据类型转换成另一种数据类型的接口,源类型必须是 String 类型

//TODO

HiddentHttpMethodFilter

作用

由于浏览器 form 表单只支持 GET 与 POST 请求,而 DELETE、PUT 等 method 并不支持,Spring3.0 添加了一个过滤器,可以将浏览器请求改为指定的请求方式,发送给我们的控制器方法,使得支持 GET、POST、PUT 与 DELETE 请求。

使用方法

第一步:在 web.xml 中配置该过滤器。

第二步:请求方式必须使用 post 请求。

第三步:按照要求提供_method 请求参数,该参数的取值就是我们需要的请求方式。

举个例子

1
2
3
4
5
<form action="springmvc/testRestDELETE/1" method="post">
<!--这里hidden的_method-->
<input type="hidden" name="_method" value="DELETE">
<input type="submit" value="删除">
</form>

Post方式

主要通过控制 Content-Type 来控制Post方式,主要包括以下四种方式。

application/x-www-form-urlencoded

key-value键值对拼接的形式,如name=abc&phone=123456

Java后端可以通过@RequestParam获取指定key对应的参数,或者直接通过对象映射,例如

方法一:

1
2
3
4
5
@RequestMapping(value = "/login", method = RequestMethod.POST)
public String doLogin(@Validated WebLoginParam webLoginParam) {
System.out.println(webLoginParam);
return null;
}
1
2
3
4
5
6
7
8
9
@Data
public class WebLoginParam {

@NotBlank(message = "用户名不能为空")
private String username;

@NotBlank(message = "密码不能为空")
private String password;
}

方法二:

1
2
3
4
5
6
7
8
9
10
11
12
@RequestMapping(value = "/login", method = RequestMethod.POST)
public String doLogin(@RequestParam Map<String, Object> webLoginParam) {
Set<Map.Entry<String, Object>> entries = webLoginParam.entrySet();
for (Map.Entry<String, Object> entry : entries) {
System.out.println(entry.getKey() + ": "+entry.getValue());
}
return null;
}
/*
username: abc
password: 123456
*/

若请求格式为http://localhost:8080/api/user?page=1&size=10&_search=1&username=&role=user&status=&createTime=&updateTime=

则 Map 对应存储的 key-value 为:

1
2
3
4
5
6
7
8
page: 1
size: 10
_search: 1
username: //value非null,而是空值""
role: user
status:
createTime:
updateTime:

application/json

以 json 格式,如{"name":"abc","phone":"123456"}

multipart/form-data

multipart/form-data是基于 post 方法来传递数据的,并且其请求内容格式为Content-Type: multipart/form-data,用来指定请求内容的数据编码格式。另外,该格式会生成一个 boundary 字符串来分割请求头与请求体的,具体的是以一个boundary=${boundary}来进行分割,伪码如下:

1
2
3
4
5
6
7
8
...
Content-Type: multipart/form-data; boundary=${boundary}

--${boundary}
...
...

--${boundary}--

举个例子:

1
2
3
4
5
6
7
8
9
10
11
12
13
POST http://www.example.com HTTP/1.1
Content-Type:multipart/form-data; boundary=----WebKitFormBoundaryrGKCBY7qhFd3TrwA

------WebKitFormBoundaryrGKCBY7qhFd3TrwA
Content-Disposition: form-data; name="text"

title
------WebKitFormBoundaryrGKCBY7qhFd3TrwA
Content-Disposition: form-data; name="file"; filename="chrome.png"
Content-Type: image/png

PNG ... content of chrome.png ...
------WebKitFormBoundaryrGKCBY7qhFd3TrwA--

SpringMVC 学习笔记
http://shijieq.github.io/2022/06/08/Java/Spring/SpringMVC学习笔记/
Author
ShijieQ
Posted on
June 8, 2022
Licensed under