SpringMVC(2) 接收数据
2023-12-12 17:05:13 # Backend # SpringMVC

1. 访问路径设置

  1. 精准路径匹配
  • @RequestMapping注解指定 URL 地址时,不使用任何通配符,按照请求地址进行精确匹配

  • value属性是一个字符串类型的数组,表示该请求映射能够匹配多个请求地址所对应的请求

1
2
3
4
5
@RequestMapping(value = {"/user/login"})
@ResponseBody
public String login(){
return "login success!!";
}
  1. 模糊路径匹配
  • @RequestMapping注解指定 URL 地址时,通过使用通配符,匹配多个类似的地址
  • /*: 只能匹配URL地址中的一层,如果想准确匹配两层,重复两次即可,如代码示例
  • /**: 可以匹配URL地址中的任意层, 在使用**时,只能使用/**/xxx的方式
1
2
3
4
5
@RequestMapping("/product/*/*")
@ResponseBody
public String show(){
return "product show!";
}
  1. 类和方法级别区别

@RequestMapping 注解可以用于类级别和方法级别

1
2
3
4
5
6
7
8
//1.标记到handler方法
@RequestMapping("/user/login")

//2.优化标记类+handler方法
//类上
@RequestMapping("/user")
//handler方法上
@RequestMapping("/login")
  1. 附带请求方式限制

HTTP 协议定义了八种请求方式,在 SpringMVC 中封装到了下面这个枚举类:

1
2
3
public enum RequestMethod {
GET, HEAD, POST, PUT, PATCH, DELETE, OPTIONS, TRACE
}

默认情况下:@RequestMapping("/logout") 任何请求方式都可以访问, 也可以通过method参数指定

1
2
3
4
5
6
7
8
9
10
11
12
13
@Controller
public class UserController {
/**
* method = RequestMethod.POST 可以指定单个或者多个请求方式!
* 注意:违背请求方式会出现405异常!
*/
@RequestMapping(value = {"/user/login"}, method = {RequestMethod.POST, RequestMethod.GET})
@ResponseBody
public String login(){
System.out.println("UserController.login");
return "login success!!";
}
}
  1. 进阶注解

@RequestMapping 的 HTTP 方法特定快捷方式变体:

  • @GetMapping
  • @PostMapping
  • @PutMapping
  • @DeleteMapping
  • @PatchMapping

注意:进阶注解只能添加到handler方法上,无法添加到类上

目前浏览器只支持get和post,若在form表单提交时,为method设置了其他请求方式的字符串(put或delete),则按照默认的请求方式get处理

若要发送put和delete请求,则需要通过spring提供的过滤器HiddenHttpMethodFilter

  1. @RequestMapping注解的 params 属性

params属性是一个字符串类型的数组,可以通过四种表达式设置请求参数和请求映射的匹配关系

  • “param”:要求请求映射所匹配的请求必须携带param请求参数

  • “!param”:要求请求映射所匹配的请求必须不能携带param请求参数

  • “param=value”:要求请求映射所匹配的请求必须携带param请求参数且param=value

  • “param!=value”:要求请求映射所匹配的请求必须携带param请求参数但是param!=value

1
2
3
4
5
@RequestMapping(
value = {"/testRequestMapping", "/test"}
,method = {RequestMethod.GET, RequestMethod.POST}
,params = {"username","password!=123456"}
)

若当前请求满足 @RequestMapping 注解的 value 和 method 属性,但是不满足 params 属性,此时页面会报错400

  1. @RequestMapping注解的headers属性

headers属性是一个字符串类型的数组,可以通过四种表达式设置请求头信息和请求映射的匹配关系

  • “header”:要求请求映射所匹配的请求必须携带header请求头信息

  • “!header”:要求请求映射所匹配的请求必须不能携带header请求头信息

  • “header=value”:要求请求映射所匹配的请求必须携带header请求头信息且header=value

  • “header!=value”:要求请求映射所匹配的请求必须携带header请求头信息且header!=value

若当前请求满足 @RequestMapping 注解的 value 和 method 属性,但是不满足 headers 属性,此时页面显示404错误,即资源未找到

2. 接收参数

2.1 param 和 json 参数比较

  1. 参数编码:

    param 类型的参数会被编码为 ASCII 码。而 JSON 类型的参数会被编码为 UTF-8。

  2. 参数顺序:

    param 类型的参数没有顺序限制。但是,JSON 类型的参数是有序的。JSON 采用键值对的形式进行传递,其中键值对是有序排列的。

  3. 数据类型:

    param 类型的参数仅支持字符串类型、数值类型和布尔类型等简单数据类型。而 JSON 类型的参数则支持更复杂的数据类型,如数组、对象等。

  4. 嵌套性:

    param 类型的参数不支持嵌套。但是,JSON 类型的参数支持嵌套,可以传递更为复杂的数据结构。

常见的做法是:在 GET 请求中采用 param 类型的参数,而在 POST 请求中采用 JSON 类型的参数传递。

2.2 param 参数接收

只要形参数名和类型与传递参数相同,即可自动接收

1
2
3
4
5
6
7
8
9
10
11
12
/**
* 前端请求: http://localhost:8080/param/value?name=xx&age=18
*
* 可以利用形参列表, 直接接收前端传递的param参数!
* 要求: 参数名 = 形参名 类型相同
*/
@GetMapping(value="/value")
@ResponseBody
public String setupForm(String name, int age){
System.out.println("name = " + name + ", age = " + age);
return name + age;
}

@RequestParam 注解

  • value:指定为形参赋值的请求参数的参数名
  • required:设置是否必须传输此请求参数,默认值为true
  • defaultValue:不管required属性值为true或false,当value所指定的请求参数没有传输或传输的值为””时,则使用默认值为形参赋值

特殊情况:

  1. 一名多值: 多选框,提交的数据的时候一个key对应多个值,可以使用集合进行接收
    如果使用一个字符串变量,接收到的是使用逗号拼接的结果
1
2
3
4
5
6
7
8
9
10
11
/**
* 前端请求: http://localhost:8080/param/mul?hbs=吃&hbs=喝
*
* 一名多值,可以使用集合接收即可!但是需要使用@RequestParam注解指定
*/
@GetMapping(value="/mul")
@ResponseBody
public Object mulForm(@RequestParam List<String> hbs){
System.out.println("hbs = " + hbs);
return hbs;
}
  1. 实体接收: 要求属性名必须等于参数名
1
2
3
4
5
6
7
@RequestMapping(value = "/user", method = RequestMethod.POST)
@ResponseBody
public String addUser(User user) {
// 在这里可以使用 user 对象的属性来接收请求参数
System.out.println("user = " + user);
return "success";
}

2.3 路径参数接收

@PathVariable 注解

1
2
3
4
5
6
7
8
9
10
11
12
13
14
/**
* 动态路径设计: /user/{动态部分}/{动态部分} 动态部分使用{}包含即可! {}内部动态标识!
* 形参列表取值: @PathVariable Long id 如果形参名 = {动态标识} 自动赋值!
* @PathVariable("动态标识") Long id 如果形参名 != {动态标识} 可以通过指定动态标识赋值!
*
* 访问测试: /user/1/root -> id = 1 uname = root
*/
@GetMapping("/user/{id}/{name}")
@ResponseBody
public String getUser(@PathVariable Long id,
@PathVariable("name") String uname) {
System.out.println("id = " + id + ", uname = " + uname);
return "user_detail";
}

2.4 JSON参数接收

@RequestBody 注解

1
2
3
4
5
6
@PostMapping("/person")
@ResponseBody
public String addPerson(@RequestBody Person person) {
// 在这里可以使用 person 对象来操作 JSON 数据中包含的属性
return "success";
}

注意:springmvc handlerAdpater要配置json转化器, 配置类需要明确

1
2
3
4
5
6
7
8
9
10
11
//TODO: SpringMVC对应组件的配置类 [声明SpringMVC需要的组件信息]

//TODO: 导入handlerMapping和handlerAdapter的三种方式
//1.自动导入handlerMapping和handlerAdapter [推荐]
//2.可以不添加, springmvc会检查是否配置handlerMapping和handlerAdapter, 没有配置默认加载
//3.使用@Bean方式配置handlerMapper和handlerAdapter
@EnableWebMvc //json数据处理,必须使用此注解,因为他会加入json处理器
@Configuration
@ComponentScan(basePackages = "com.atguigu.controller")
public class SpringMvcConfig implements WebMvcConfigurer {
}

pom 添加 jackson 依赖

@CookieValue 注解

1
JSESSIONID=415A4AC178C59DACE0B2C9CA727CDD84
1
2
3
4
@GetMapping("/demo")
public void handle(@CookieValue("JSESSIONID") String cookie) {
//...
}

@CookieValue 注解一共有三个属性:value、required、defaultValue,用法同@RequestParam

4. 接受请求头数据

@RequestHeader 注解

1
2
3
4
5
6
Host                    localhost:8080
Accept text/html,application/xhtml+xml,application/xml;q=0.9
Accept-Language fr,en-gb;q=0.7,en;q=0.3
Accept-Encoding gzip,deflate
Accept-Charset ISO-8859-1,utf-8;q=0.7,*;q=0.7
Keep-Alive 300
1
2
3
4
5
@GetMapping("/demo")
public void handle(@RequestHeader("Accept-Encoding") String encoding,
@RequestHeader("Keep-Alive") long keepAlive) {
//...
}

@RequestHeader 注解一共有三个属性:value、required、defaultValue,用法同@RequestParam

5. 原生 API 对象操作

官方文档

1
2
3
4
5
6
7
8
9
10
11
12
13
/**
* 如果想要获取请求或者响应对象,或者会话等,可以直接在形参列表传入,并且不分先后顺序!
* 注意: 接收原生对象,并不影响参数接收!
*/
@GetMapping("api")
@ResponseBody
public String api(HttpSession session , HttpServletRequest request,
HttpServletResponse response){
String method = request.getMethod();
System.out.println("method = " + method);
String username = request.getParameter("username");
return "api";
}

6. 共享域对象操作

6.1 属性(共享)域作用回顾

在 JavaWeb 中,共享域指的是在 Servlet 中存储数据,以便在同一 Web 应用程序的多个组件中进行共享和访问。常见的共享域有四种:ServletContextHttpSessionHttpServletRequestPageContext

  1. ServletContext 共享域:ServletContext 对象可以在整个 Web 应用程序中共享数据,是最大的共享域。一般可以用于保存整个 Web 应用程序的全局配置信息,以及所有用户都共享的数据。在 ServletContext 中保存的数据是线程安全的。
  2. HttpSession 共享域:HttpSession 对象可以在同一用户发出的多个请求之间共享数据,但只能在同一个会话中使用。比如,可以将用户登录状态保存在 HttpSession 中,让用户在多个页面间保持登录状态。
  3. HttpServletRequest 共享域:HttpServletRequest 对象可以在同一个请求的多个处理器方法之间共享数据。比如,可以将请求的参数和属性存储在 HttpServletRequest 中,让处理器方法之间可以访问这些数据。
  4. PageContext 共享域:PageContext 对象是在 JSP 页面Servlet 创建时自动创建的。它可以在 JSP 的各个作用域中共享数据,包括pageScoperequestScopesessionScopeapplicationScope 等作用域。

共享域的作用是提供了方便实用的方式在同一 Web 应用程序的多个组件之间传递数据,并且可以将数据保存在不同的共享域中,根据需要进行选择和使用。

img

6.2 Request级别属性(共享)域

  1. 使用 Model 类型的形参
1
2
3
4
5
6
7
8
9
@RequestMapping("/attr/request/model")
@ResponseBody
public String testAttrRequestModel(Model model) {
// 我们将数据存入模型,SpringMVC 会帮我们把模型数据存入请求域
// 存入请求域这个动作也被称为暴露到请求域
model.addAttribute("requestScopeMessageModel","i am very happy[model]");

return "target";
}
  1. 使用 ModelMap 类型的形参
1
2
3
4
5
6
7
8
9
@RequestMapping("/attr/request/model/map")
@ResponseBody
public String testAttrRequestModelMap(ModelMap modelMap) {
// 我们将数据存入模型,SpringMVC 会帮我们把模型数据存入请求域
// 存入请求域这个动作也被称为暴露到请求域
modelMap.addAttribute("requestScopeMessageModelMap","i am very happy[model map]");

return "target";
}
  1. 使用 Map 类型的形参
1
2
3
4
5
6
7
8
9
@RequestMapping("/attr/request/map")
@ResponseBody
public String testAttrRequestMap(Map<String, Object> map) {
// 我们将数据存入模型,SpringMVC 会帮我们把模型数据存入请求域
// 存入请求域这个动作也被称为暴露到请求域
map.put("requestScopeMessageMap", "i am very happy[map]");

return "target";
}
  1. 使用原生 request 对象
1
2
3
4
5
6
7
@RequestMapping("/attr/request/original")
@ResponseBody
public String testAttrOriginalRequest(HttpServletRequest request) {
request.setAttribute("requestScopeMessageOriginal", "i am very happy[original]");

return "target";
}
  1. 使用 ModelAndView 对象
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
/**
* ModelAndView有Model和View的功能
* Model主要用于向请求域共享数据
* View主要用于设置视图,实现页面跳转
*/
@RequestMapping("/attr/request/mav")
public ModelAndView testAttrByModelAndView() {
// 1.创建ModelAndView对象
ModelAndView modelAndView = new ModelAndView();
// 2.存入模型数据
modelAndView.addObject("requestScopeMessageMAV", "i am very happy[mav]");
// 3.设置视图名称
modelAndView.setViewName("target");

return modelAndView;
}

Model、ModelMap、Map的关系

Model、ModelMap、Map类型的参数其实本质上都是 BindingAwareModelMap 类型的

1
2
3
4
public interface Model{}
public class ModelMap extends LinkedHashMap<String, Object> {}
public class ExtendedModelMap extends ModelMap implements Model {}
public class BindingAwareModelMap extends ExtendedModelMap {}

6.3 Session级别属性(共享)域

1
2
3
4
5
6
7
@RequestMapping("/attr/session")
@ResponseBody
public String testAttrSession(HttpSession session) {
//直接对session对象操作,即对会话范围操作!
session.setAttribute("testSessionScope", "hello,session");
return "target";
}

6.4 Application级别属性(共享)域

SpringMVC 会在初始化容器的时候,将 servletContext 对象存储到 IoC 容器中

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
@Autowired
private ServletContext servletContext;

@RequestMapping("/attr/application")
@ResponseBody
public String attrApplication() {
servletContext.setAttribute("appScopeMsg", "i am hungry...");
return "target";
}

// 或者通过session获取
@RequestMapping("/testApplication")
public String testApplication(HttpSession session){
ServletContext application = session.getServletContext();
application.setAttribute("testApplicationScope", "hello,application");
return "success";
}

7. 解决获取请求参数的乱码问题

解决获取请求参数的乱码问题,可以使用 SpringMVC 提供的编码过滤器CharacterEncodingFilter,但是必须在 web.xml 中进行注册

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
<!--配置springMVC的编码过滤器-->
<filter>
<filter-name>CharacterEncodingFilter</filter-name>
<filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
<init-param>
<param-name>encoding</param-name>
<param-value>UTF-8</param-value>
</init-param>
<init-param>
<param-name>forceResponseEncoding</param-name>
<param-value>true</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>CharacterEncodingFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>

注:

SpringMVC中处理编码的过滤器一定要配置到其他过滤器之前,否则无效