HTTP请求与响应
池慕睡不着
1.请求
1.2 简单参数
简单参数:在向服务器发起请求时,向服务器传递的是一些普通的请求数据。
那么在后端程序中,如何接收传递过来的普通参数数据呢?
我们在这里讲解两种方式:
- 原始方式
- SpringBoot方式
1.2.1 原始方式
在原始的Web程序当中,需要通过Servlet中提供的API:HttpServletRequest(请求对象),获取请求的相关信息。比如获取请求参数:
Tomcat接收到http请求时:把请求的相关信息封装到HttpServletRequest对象中
在Controller中,我们要想获取Request对象,可以直接在方法的形参中声明 HttpServletRequest 对象。然后就可以通过该对象来获取请求信息:
1 2
| String request.getParameter("参数名")
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| @RestController public class RequestController { @RequestMapping("/simpleParam") public String simpleParam(HttpServletRequest request){
String name = request.getParameter("name"); String ageStr = request.getParameter("age");
int age = Integer.parseInt(ageStr); System.out.println(name+" : "+age); return "OK"; } }
|
以上这种方式,我们仅做了解。(在以后的开发中不会使用到)
1.2.2 SpringBoot方式
在Springboot的环境中,对原始的API进行了封装,接收参数的形式更加简单。 如果是简单参数,参数名与形参变量名相同,定义同名的形参即可接收参数。
1 2 3 4 5 6 7 8 9 10 11 12 13
| @RestController public class RequestController { @RequestMapping("/simpleParam") public String simpleParam(String name , Integer age ){ System.out.println(name+" : "+age); return "OK"; } }
|
postman测试( GET 请求):
postman测试( POST请求 ):
结论:不论是GET请求还是POST请求,对于简单参数来讲,只要保证==请求参数名和Controller方法中的形参名保持一致==,就可以获取到请求参数中的数据值。
1.2.3 参数名不一致
如果方法形参名称与请求参数名称不一致,controller方法中的形参还能接收到请求参数值吗?
1 2 3 4 5 6 7 8 9 10 11 12
| @RestController public class RequestController {
@RequestMapping("/simpleParam") public String simpleParam(String username , Integer age ){ System.out.println(username+" : "+age); return "OK"; } }
|
答案:运行没有报错。 controller方法中的username值为:null,age值为20
- 结论:对于简单参数来讲,请求参数名和controller方法中的形参名不一致时,无法接收到请求数据
那么如果我们开发中,遇到了这种请求参数名和controller方法中的形参名不相同,怎么办?
解决方案:可以使用Spring提供的@RequestParam注解完成映射
在方法形参前面加上 @RequestParam 然后通过value属性执行请求参数名,从而完成映射。代码如下:
1 2 3 4 5 6 7 8 9 10 11 12
| @RestController public class RequestController {
@RequestMapping("/simpleParam") public String simpleParam(@RequestParam("name") String username , Integer age ){ System.out.println(username+" : "+age); return "OK"; } }
|
注意事项:
@RequestParam中的required属性默认为true(默认值也是true),代表该请求参数必须传递,如果不传递将报错
如果该参数是可选的,可以将required属性设置为false
1 2 3 4 5
| @RequestMapping("/simpleParam") public String simpleParam(@RequestParam(name = "name", required = false) String username, Integer age){ System.out.println(username+ ":" + age); return "OK"; }
|
1.3 实体参数
在使用简单参数做为数据传递方式时,前端传递了多少个请求参数,后端controller方法中的形参就要书写多少个。如果请求参数比较多,通过上述的方式一个参数一个参数的接收,会比较繁琐。
此时,我们可以考虑将请求参数封装到一个实体类对象中。 要想完成数据封装,需要遵守如下规则:请求参数名与实体类的属性名相同
1.3.1 简单实体对象
定义POJO实体类:
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 28 29
| public class User { private String name; private Integer age;
public String getName() { return name; }
public void setName(String name) { this.name = name; }
public Integer getAge() { return age; }
public void setAge(Integer age) { this.age = age; }
@Override public String toString() { return "User{" + "name='" + name + '\'' + ", age=" + age + '}'; } }
|
Controller方法:
1 2 3 4 5 6 7 8 9
| @RestController public class RequestController { @RequestMapping("/simplePojo") public String simplePojo(User user){ System.out.println(user); return "OK"; } }
|
Postman测试:
1.3.2 复杂实体对象
上面我们讲的呢是简单的实体对象,下面我们在来学习下复杂的实体对象。
复杂实体对象指的是,在实体类中有一个或多个属性,也是实体对象类型的。如下:
- User类中有一个Address类型的属性(Address是一个实体类)
复杂实体对象的封装,需要遵守如下规则:
- 请求参数名与形参对象属性名相同,按照对象层次结构关系即可接收嵌套实体类属性参数。
定义POJO实体类:
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 28
| public class Address { private String province; private String city;
public String getProvince() { return province; }
public void setProvince(String province) { this.province = province; }
public String getCity() { return city; }
public void setCity(String city) { this.city = city; }
@Override public String toString() { return "Address{" + "province='" + province + '\'' + ", city='" + city + '\'' + '}'; } }
|
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 28 29 30 31 32 33 34 35 36 37 38
| public class User { private String name; private Integer age; private Address address;
public String getName() { return name; }
public void setName(String name) { this.name = name; }
public Integer getAge() { return age; }
public void setAge(Integer age) { this.age = age; }
public Address getAddress() { return address; }
public void setAddress(Address address) { this.address = address; }
@Override public String toString() { return "User{" + "name='" + name + '\'' + ", age=" + age + ", address=" + address + '}'; } }
|
Controller方法:
1 2 3 4 5 6 7 8 9
| @RestController public class RequestController { @RequestMapping("/complexPojo") public String complexPojo(User user){ System.out.println(user); return "OK"; } }
|
Postman测试:
1.4 数组集合参数
数组集合参数的使用场景:在HTML的表单中,有一个表单项是支持多选的(复选框),可以提交选择的多个值。
多个值是怎么提交的呢?其实多个值也是一个一个的提交。
后端程序接收上述多个值的方式有两种:
- 数组
- 集合
1.4.1 数组
数组参数:请求参数名与形参数组名称相同且请求参数为多个,定义数组类型形参即可接收参数
Controller方法:
1 2 3 4 5 6 7 8 9
| @RestController public class RequestController { @RequestMapping("/arrayParam") public String arrayParam(String[] hobby){ System.out.println(Arrays.toString(hobby)); return "OK"; } }
|
Postman测试:
在前端请求时,有两种传递形式:
方式一: xxxxxxxxxx?hobby=game&hobby=java
方式二:xxxxxxxxxxxxx?hobby=game,java
1.4.2 集合
集合参数:请求参数名与形参集合对象名相同且请求参数为多个,@RequestParam 绑定参数关系
默认情况下,请求中参数名相同的多个值,是封装到数组。如果要封装到集合,要使用@RequestParam绑定参数关系
Controller方法:
1 2 3 4 5 6 7 8 9
| @RestController public class RequestController { @RequestMapping("/listParam") public String listParam(@RequestParam List<String> hobby){ System.out.println(hobby); return "OK"; } }
|
Postman测试:
方式一: xxxxxxxxxx?hobby=game&hobby=java
方式二:xxxxxxxxxxxxx?hobby=game,java
1.5 日期参数
上述演示的都是一些普通的参数,在一些特殊的需求中,可能会涉及到日期类型数据的封装。比如,如下需求:
因为日期的格式多种多样(如:2022-12-12 10:05:45 、2022/12/12 10:05:45),那么对于日期类型的参数在进行封装的时候,需要通过@DateTimeFormat注解,以及其pattern属性来设置日期的格式。
- @DateTimeFormat注解的pattern属性中指定了哪种日期格式,前端的日期参数就必须按照指定的格式传递。
- 后端controller方法中,需要使用Date类型或LocalDateTime类型,来封装传递的参数。
Controller方法:
1 2 3 4 5 6 7 8 9
| @RestController public class RequestController { @RequestMapping("/dateParam") public String dateParam(@DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss") LocalDateTime updateTime){ System.out.println(updateTime); return "OK"; } }
|
Postman测试:
1.6 JSON参数
在学习前端技术时,我们有讲到过JSON,而在前后端进行交互时,如果是比较复杂的参数,前后端通过会使用JSON格式的数据进行传输。 (JSON是开发中最常用的前后端数据交互方式)
我们学习JSON格式参数,主要从以下两个方面着手:
- Postman在发送请求时,如何传递json格式的请求参数
- 在服务端的controller方法中,如何接收json格式的请求参数
Postman发送JSON格式数据:
服务端Controller方法接收JSON格式数据:
- 传递json格式的参数,在Controller中会使用实体类进行封装。
- 封装规则:JSON数据键名与形参对象属性名相同,定义POJO类型形参即可接收参数。需要使用 @RequestBody标识。
- @RequestBody注解:将JSON数据映射到形参的实体类对象中(JSON中的key和实体类中的属性名保持一致)
实体类:Address
1 2 3 4 5 6
| public class Address { private String province; private String city; }
|
实体类:User
1 2 3 4 5 6 7
| public class User { private String name; private Integer age; private Address address; }
|
Controller方法:
1 2 3 4 5 6 7 8 9
| @RestController public class RequestController { @RequestMapping("/jsonParam") public String jsonParam(@RequestBody User user){ System.out.println(user); return "OK"; } }
|
Postman测试:
1.7 路径参数
传统的开发中请求参数是放在请求体(POST请求)传递或跟在URL后面通过?key=value的形式传递(GET请求)。
在现在的开发中,经常还会直接在请求的URL中传递参数。例如:
1 2
| http://localhost:8080/user/1 http://localhost:880/user/1/0
|
上述的这种传递请求参数的形式呢,我们称之为:路径参数。
学习路径参数呢,主要掌握在后端的controller方法中,如何接收路径参数。
路径参数:
- 前端:通过请求URL直接传递参数
- 后端:使用{…}来标识该路径参数,需要使用@PathVariable获取路径参数
Controller方法:
1 2 3 4 5 6 7 8 9
| @RestController public class RequestController { @RequestMapping("/path/{id}") public String pathParam(@PathVariable Integer id){ System.out.println(id); return "OK"; } }
|
Postman测试:
传递多个路径参数:
Postman:
Controller方法:
1 2 3 4 5 6 7 8 9
| @RestController public class RequestController { @RequestMapping("/path/{id}/{name}") public String pathParam2(@PathVariable Integer id, @PathVariable String name){ System.out.println(id+ " : " +name); return "OK"; } }
|