👉 博客主页:准Java全栈开发工程师
👉 00年出生,即将进入职场闯荡,目标赚钱,可能会有人觉得我格局小、觉得俗,但不得不承认这个世界已经不再是以一条线来分割的平面,而是围绕财富旋转的球面,成为有钱人不是为了去掌控球体的转向,而是当有人恶意掌控时,努力保护好家人和自己。
请求与响应
- SpringMVC 作为 Web 层框架,最主要的作用就是接收请求、接收数据、数据响应。所以,如果我们想扎实的掌握 SpringMVC ,搞懂这部分内容还是非常重要的。
一、如何避免映射路径同名问题
1、问题描述
- 我们在 controller 类中使用 @RequestMapping 注解指定映射路径时,不免会出现两个不同的 controller 类中出现同样的映射路径。
@Controller
public class UserController {
@ResponseBody
@RequestMapping("/select")
public String save(){
System.out.println("qdxorigin save ...");
return "{'msg':'qdxorigin'}";
}
}
@Controller
public class AccountController {
@ResponseBody
@RequestMapping("/select")
public String save(){
System.out.println("qdxorigin account save ...");
return "{'msg':'qdxorigin'}";
}
}
- 此时,我们运行项目启动 tomcat 时就会报错。
- 这是因为当在访问 /select 映射路径时,并不能清楚的知道应该与那个方法相匹配导致的。
2、解决方式
方式一
@Controller
public class UserController {
@ResponseBody
@RequestMapping("/user/select")
public String save(){
System.out.println("qdxorigin user save ...");
return "{'msg':'qdxorigin'}";
}
}
@Controller
public class AccountController {
@ResponseBody
@RequestMapping("/account/select")
public String save(){
System.out.println("qdxorigin account save ...");
return "{'msg':'qdxorigin'}";
}
}
- 在方法的映射路径上加上所在的类名,如上所示,这样就不会再出现重复的问题,但是如果 controller 中涉及到非常多的方法,都要一个一个在方法的映射路径上加上 “/user” 或 “/account” 吗?是不是很麻烦,且存在写错的问题。所以在解决映射路径重名问题时推荐使用方式二。
方式二
@Controller
@RequestMapping("/user")
public class UserController {
@ResponseBody
@RequestMapping("/select")
public String save(){
System.out.println("qdxorigin user save ...");
return "{'msg':'qdxorigin'}";
}
}
- 在每个 controller 类上,使用 @RequestMapping 注解指定路径前缀,之后在方法上就无需再添加 /user 这些,简便易修改还不易出错。
二、如何接收请求参数
1、接收普通参数
@Controller
@RequestMapping("/user")
public class UserController {
@ResponseBody
@RequestMapping("/select")
public String select(String name, Integer age){
System.out.println("name = " + name + " , age = " + age);
return "{'msg':'qdxorigin'}";
}
}
- 对于普通参数的接收,直接在方法的形参列表中添加即可。
- 使用 Postman 工具测试。
- 控制台返回数据。
- 在发送请求时,请求路径中的参数名和方法形参名是一致的,所以能够准确的赋值,但是如果请求路径中的参数名和方法形参名不同应该如何解决呢?解决方式也非常的简单,只需要在形参列表中使用 @RequestParam(“username”) 指定请求路径参数名即可。
@Controller
@RequestMapping("/user")
public class UserController {
@ResponseBody
@RequestMapping("/select")
public String select(@RequestParam("username") String name, Integer age){
System.out.println("name = " + name + " , age = " + age);
return "{'msg':'qdxorigin'}";
}
}
- 再次发送 GET 请求,查看是否能够成功接收到数据,此时请求路径的参数名已经改为了 username 。
- 在控制台仍然能够准确的获取数据,这是 @RequestParam(“username”) 起作用了。
2、接收实体类
@Controller
@RequestMapping("/user")
public class UserController {
@ResponseBody
@RequestMapping("/select2")
public String select2(User user){
System.out.println(user);
return "{'msg':'qdxorigin'}";
}
}
public class User {
private String name;
private Integer age;
private Account account;
}
- 不用过于纠结我的方法名和映射路径,只是为了对相应技术进行测试,在实际开发中,还是需要遵循见名知意的。
- 实体类的接收和普通类型非常相似,也是在方法形参中声明即可。
- 请求路径中的 key 值是需要和 User 类的属性名保持一致的,不一致就无法完成数据的绑定。
- 因为并没有为传 account 参数,数据绑定失败,以默认值代替。
3、接收嵌套实体类
@Controller
@RequestMapping("/user")
public class UserController {
@ResponseBody
@RequestMapping("/select2")
public String select2(User user){
System.out.println(user);
return "{'msg':'qdxorigin'}";
}
}
public class User {
private String name;
private Integer age;
private Account account;
}
public class Account {
private Integer id;
private Double money;
}
- 在上一个部分接收实体类参数时,没有传入 account 参数,是因为 account 自己也是一个实体类,他的传参方式有些许特别。
- 嵌套实体的传参方式为 “对象.属性”的方式,有点像我们调用时的形式。
- 这一次控制台可以完整的打印出 user 信息了。
4、接收数组类型的参数
@Controller
@RequestMapping("/user")
public class UserController {
@ResponseBody
@RequestMapping("/select3")
public String select3(String[] names){
System.out.println(Arrays.toString(names));
return "{'msg':'qdxorigin'}";
}
}
- 看到这,是否对接收方式有一点了解了,其实就是需要接收什么,就将它扔到形参列表中即可。
- 对于数组类型的参数,传参时提供多个同名的 key 即可,接收时回自动封装到数组中。
- 但是对于一个 Java 程序员来说,使用数组的机会不是很多,更多情况下我们都会选择使用集合来代替数组。
5、接收集合类型的参数
@Controller
@RequestMapping("/user")
public class UserController {
@ResponseBody
@RequestMapping("/select4")
public String select4(@RequestParam List<String> names){
System.out.println(names);
return "{'msg':'qdxorigin'}";
}
}
- 接收集合类型的参数时,除了在形参列表中声明外,还需要使用 @RequestParam 注解将传入的参数值映射到集合对象中,如果不指定,会报错,报错原因是错误的认为 List 集合是一个实体类,想要调用构造方法创建对象时,发现并没有提供对应的构造方法(因为 List 是一个接口,没有提供构造方法)。
- 传参方式和数组类型是一模一样的,就连打印结果也是一样的。
- 前面演示了这么多,都是演示的 GET 请求,接下来就简单演示一下 POST 请求,其实这两种方式是非常相似的。
6、POST 请求简单演示
- 首先需要将请求方式改为 POST ,除此之外,POST 请求的传参位置也有所变化,不再在 Params 中,而是转到了 Body 下的 x-www-form-urlencoded 中进行,之后的和 GET 请求并无太大差别。
- 控制台仍然能够正确接收。
- 对于其他类型的参数接收在此就不一一展示了,感兴趣的小伙伴可以自己测试一下。
三、json类型数据
- 异步调用作为最近比较流行的开发方式,也推动了 json 类型数据的使用,那么,我们该如何传输和接收 json 数据呢?
1、常见的 json 数据类型
- 普通数组:[“value1”,“value2”,“value3”,…]
- json对象:{key1:value1,key2:value2,…}
- 对象数组:[ {key1:value1,…},{key2:value2,…} ]
2、导入依赖
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.13.1</version>
</dependency>
- 为了能准确的完成 json 数据的绑定,我们需要导入相应的 jar 包才能实现。
3、配置类开启注解支持
@Configuration
@ComponentScan("qdxorigin.controller")
@EnableWebMvc
public class SpringMvcConfig {
}
- @EnableWebMvc 注解能够开启 json 数据类型自动转换,该注解的功能非常强大,还有其他用处,在此不一一介绍,用到时再做阐述。
4、接收普通数组
@Controller
@RequestMapping("/user")
public class UserController {
@RequestMapping("/forJson")
@ResponseBody
public String forJson(@RequestBody String[] names){
System.out.println(Arrays.toString(names));
return "{'msg':'qdxorigin'}";
}
}
- @RequestBody 注解将外部传递的 json 数组数据映射到形参的集合对象中。
- 传入 json 数据时,要在 Body 下的 raw 区域进行,类型选择为 JSON。
5、接收 json 对象
@Controller
@RequestMapping("/user")
public class UserController {
@RequestMapping("/forJson3")
@ResponseBody
public String forJson3(@RequestBody User user){
System.out.println(user);
return "{'msg':'qdxorigin'}";
}
}
public class User {
private String name;
private Integer age;
private Account account;
}
- 注意区分使用 “[ ]” 和 “{ }”。
6、接收对象数组
@Controller
@RequestMapping("/user")
public class UserController {
@RequestMapping("/forJson4")
@ResponseBody
public String forJson4(@RequestBody List<User> users){
System.out.println(users);
return "{'msg':'qdxorigin'}";
}
}
- 传入对象数组,其实就是对象和数组的结合,并没有什么吓人的。
7、@RequestBody VS @RequestParam
- @RequestParam 用于接收 url 地址传参,表单传参。
- @RequestBody 用于接收 json 数据。
四、日期类型参数
@Controller
@RequestMapping("/user")
public class UserController {
@RequestMapping("/forDate")
@ResponseBody
public String date(Date date,
@DateTimeFormat(pattern = "yyyy-MM-dd") Date date2,
@DateTimeFormat(pattern = "yyyy/MM/dd HH:mm:ss") Date date3){
System.out.println("yyyy/MM/dd : " + date);
System.out.println("yyyy-MM-dd : " + date2);
System.out.println("yyyy/MM/dd HH:mm:ss : " + date3);
return "{'msg':'qdxorigin'}";
}
}
- 对于日期类型的参数,如果传入的参数类型是 “yyyy/MM/dd” 的,则无需进行类型指定,能够自动封装。
- 除此之外的其他类型,都需要使用 @DateTimeFormat 注解设定日期时间型数据的格式。使用pattern 属性指定日期时间格式字符串。
- 所有的数据都能够准确接收。
- 修改一个小问题:上图中的 “yyyy/MM/ss" 应该改为”yyyy/MM/dd"。
五、响应
讲了这么久的请求问题,终于来到了响应问题。
1、响应页面
<!-- index.jsp页面 -->
<html>
<body>
<h2>Hello World!</h2>
<h2>index.jsp</h2>
<h2>qdxorigin</h2>
</body>
</html>
@Controller
@RequestMapping("/user")
public class UserController {
@RequestMapping("/forPage")
public String forPage(){
System.out.println("forPage ...");
return "index.jsp";
}
}
- 此处无需再添加 @ResponseBody 注解,因为返回的不再是字符串,而是需要被解析的页面。
- 在浏览器中输入网址测试,成功实现页面的跳转。
2、响应 JSON 数据
响应 POJO 类型数据
@Controller
@RequestMapping("/user")
public class UserController {
@RequestMapping("/forUser")
@ResponseBody
public User forUser(){
User user = new User();
user.setName("Tom");
user.setAge(35);
return user;
}
}
- 发送请求时,无需传递参数。
响应集合对象
@Controller
@RequestMapping("/user")
public class UserController {
@RequestMapping("/forList")
@ResponseBody
public List<User> forList(){
User user1 = new User();
user1.setName("Tom");
user1.setAge(35);
User user2 = new User();
user2.setName("Jerry");
user2.setAge(22);
ArrayList<User> users = new ArrayList<>();
users.add(user1);
users.add(user2);
return users;
}
}
👉 以上就是文章的全部内容啦,诸佬如果有任何建议都可以提哦。
👉 创作不易,如果觉得对您有帮助的话,欢迎关注✨点赞👍收藏📂哦。