请求响应入门
请求响应
一、请求响应流程
请求响应的步骤:
- 启动内嵌的Tomcat服务器
- 打开浏览器,并通过访问路径,就可以访问到我们部署在Tomcat当中的应用程序了
- Controller接收到请求之后,会对请求进行处理,处理完毕之后,再给浏览器响应对应的结果(请求和响应都要遵循HTTP协议)
注意事项:
- Tomcat不能识别我们编写的
Controller
程序,但它是识别一项Java EE
规范里的技术的Servlet容器 - 而基于Spring boot开发的web程序中,Spring boot 底层给我们提供了一个非常核心的servlet程序——DispatcherServlet(前端控制器),有了它,前端浏览器发起的请求都会先经过
DispatcherServlet
,它会将解析后的所有信息封装到一个对象中——HttpServletRequest,由这个对象转给后面的各个Controller
程序,由这些Controller
程序再对请求进行处理,处理完毕,再将处理完的结果返回给DispatcherServlet
程序,再根据另外一个对象来响应数据——HttpServletResponse,之后再给浏览器响应数据
二、请求响应介绍和架构
- 请求(HttpServletRequest):获取请求数据
- 响应(HttpServletResponse):设置响应数据
- BS架构:Browser/Server,浏览器/服务器架构模式。客户端只需要浏览器,应用程序的逻辑和数据都存储在服务端(以上就是一个标准的BS架构,类似于网页)
- 维护方便,但体验一般
- CS架构:Client/Server,客户端/服务器架构模式(类似于APP)
- 开发、维护麻烦,但体验不错
三、请求
- 由于后端开发时,每开发完一个功能就需要去测试,可能会去从浏览器的地址栏直接输入这样一个地址,这样就可以访问到开发的web应用了,但是由地址栏发起的请求全部都是GET请求,无法测试POST请求,这时候可能需要自己编写前端的代码,然后再来进行后端的功能接口测试——此时我们可以借助一款功能强大的接口测试工具——postman
Postman
- Postman一款功能强大的网页调试与发送网页HTTP请求的chrome插件
- 作用:常用于进行接口测试
模拟页面发送各种请求
1、模拟GET请求
GET请求加上后缀?参数名1=参数1&参数名2=参数2
,下面的数据也会自动生成
2、模拟POST请求
选择POST请求后,输入这个请求的网址,并在Body
的x-www-form-urlencoded
中自己写入想要传递的数据
1、简单参数
1.1 原始方式
- 在原始的web程序中,获取请求参数,需要通过HttpServletRequest对象手动获取。
在Controller对象中编写以下程序:
// 测试请求参数
@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";
}
}
此时运行这个springboot项目,即会占用系统的8080端口,我们就可以用Postman去模拟浏览器测试发送请求
点击send方法,可以看到返回OK
,在后端代码中可以看到
返回了请求时路径的值。
- 但这种方法获取数据过于繁琐,且需要手动的类型转换
1.2 Springboot方式
-
简单参数:参数名与形参变量名相同,定义形参即可接收参数。
-
也就是说,只要前端的请求参数名与形参的变量名保持一致即可接收成功,而且在接收到的过程中会进行自动的类型转换
// 测试请求参数
@RestController
public class RequestController {
// Springboot方式
@RequestMapping("/simpleParam")
public String simpleParam(String name, Integer age) {
System.out.println(name + ":" + age);
return "OK";
}
}
运行结果和上述一样
注意事项:
- 如果形参名与前端的请求参数名不一致时,可以使用
@RequestParam
完成映射。
代码可以修改为:
// 测试请求参数
@RestController
public class RequestController {
// Springboot方式
@RequestMapping("/simpleParam")
public String simpleParam(@RequestParam(name = "name") String username, Integer age) {
System.out.println(username + ":" + age);
return "OK";
}
}
- 映射
@RequestParam(name/value = "请求参数名")
@RequestParam
中的required属性默认为true,代表该请求参数必须传递,如果不传递将会报错。因此如果请求参数中没有这个值时,就会报错;但可以修改一下required的值,没有也不会报错,有了也可以正常使用
改变required的值:
// 测试请求参数
@RestController
public class RequestController {
// Springboot方式
@RequestMapping("/simpleParam")
public String simpleParam(@RequestParam(name = "name", required = false) String username, Integer age) {
System.out.println(username + ":" + age);
return "OK";
}
}
这样不论有没有这个请求参数,请求都能正常执行!
2、实体参数
前提背景:
在简单参数接收中,前端传递了多少个请求参数,我们就需要在方法中声明多少个形参来接收,如果前端要传递的请求参数过多时,就不便于使用简单参数这种方式进行接收,这时候就需要将所有的实体对象都封装到一个实体类当中
-
简单实体对象:请求参数名与形参属性名相同,定义POJO接收即可
-
要想成功的封装,就要遵循一个原则:需要让请求的参数名与实体类的属性名保持一致。
2.1简单实体参数
我们可以使用请求的参数名,将他们都封装到一个实体类当中
- 创建一个
pojo
包,专门存放实体类
package com.springboot.springboot_webdemo02.pojo;
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
中写上:
@RestController
public class RequestController {
// 简单实体对象
@RequestMapping("/simplePojo")
public String simplepojo(User user) {
System.out.println(user);
return "OK";
}
}
此时点击Send
发送:
请求成功!
2.2复杂实体参数
根据请求参数可知,需要创建Address
类
- 在
Pojo
包中创建Address
类
package com.springboot.springboot_webdemo02.pojo;
public class Address {
private String province;
private String city;
@Override
public String toString() {
return "Address{" +
"province='" + province + '\'' +
", city='" + 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;
}
}
修改User
类中的代码:
package com.springboot.springboot_webdemo02.pojo;
public class User {
private String name;
private Integer age;
private Address address;
public Address getAddress() {
return address;
}
public void setAddress(Address address) {
this.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;
}
@Override
public String toString() {
return "User{" +
"name='" + name + '\'' +
", age=" + age +
", address=" + address +
'}';
}
}
然后可以在Controller
中写上:
@RestController
public class RequestController {
// 简单实体对象
@RequestMapping("/simplePojo")
public String simplepojo(User user) {
System.out.println(user);
return "OK";
}
// 复杂实体对象
@RequestMapping("/complexPojo")
public String complexpojo(User user) {
System.out.println(user);
return "OK";
}
}
此时点击Send
发送后:
请求成功!
3、数组参数
- 当用户填的表单为多选时,返回的参数就是以数组的形式进行传输的
然后可以在Controller
中加上:
// 数组集合参数
@RequestMapping("/arrayParam")
public String arrayParam(String[] hobby) {
System.out.println(Arrays.toString(hobby));
rerurn "OK";
}
此时点击Send
发送后:
数据请求成功!
4、集合参数
- 也可以将多选的值放进集合里
- 集合参数:请求参数名与形参集合名称相同且请求参数为多个,@RequestParam绑定参数关系
然后可以在Controller
中加上:
@RequestMapping("/listParam")
public String listParam(@RequestParam List<String> hobby) {
System.out.println(hobby);
return "OK";
}
此时点击Send
发送后:
数组集合参数:
- 数组:请求参数名与形参中数组变量名相同,可以直接使用数组进行封装
- 集合:请求参数名与形参中集合变量名相同,通过@RequestParam绑定参数关系
5、日期参数
- 在项目的前端表单页面,我们经常会遇到一些日期时间类参数,这时候就需要将其封装起来
- 日期参数:使用==@DateTimeFormat==注解完成日期参数格式转换(指定日期传递的格式)
然后可以在Controller
中加上:
// 日期时间参数
@RequestMapping("/dateParam")
public String dateParam(@DateTimeFormat(pattern = "yyyy:MM:dd HH:mm:ss")LocalDateTime updateTime) {
System.out.println(updateTime);
return "OK";
}
此时点击Send
发送后:
请求成功!
6、json参数
- 发送一个请求并且传递json格式的请求数据,需要将请求数据设置为POST,因为json格式的数据是需要方法请求体当中携带到服务端的
- JSON参数:JSON数据键名与形参对象属性名相同,定义POJO类型形参即可接收参数,需要使用==@RequestBody==标识(将JSON格式的数据封装到一个实体对象当中)
POST请求:
然后可以在Controller
中加上:
// json参数
@RequestMapping("/jsonParam")
public String jsonParam(@RequestBody User user) {
System.out.println(user);
return "OK";
}
- User和Address是上面出现过的类
此时点击Send
发送后:
7、路径参数
- 路径参数:通过请求URL直接传递参数,使用{…}来标识该路径参数,需要使用==@PathVariable==获取路径参数(将路径参数绑定为后面的形参)
然后可以在Controller
中加上:
@RequestMapping("/path/{id}")
public String pathParam(@PathVariable Integer id) {
System.out.println(id);
return "OK";
}
此时点击Send
发送后:
- 也可以改变路径参数,都可以获取到!
也可以同时传递多个请求参数:
然后可以在Controller
中变成:
@RequestMapping("/path/{id}/{name}")
public String pathParam(@PathVariable Integer id, @PathVariable String name) {
System.out.println(id + ":" + name);
return "OK";
}
发送后即可看见:
总结:
四、响应
- 其实上面的
Controller
方法中,都已经设置了响应数据return
值作为了返回数据,返回给了客户端浏览器,都依赖于一个核心的注解==@ResponseBody== - @ResponseBody:
- 类型:方法注解,类注解
- 位置:Controller方法上/Controller的类上
- 作用:将方法返回值直接响应,如果返回值类型是实体对象/集合,将会转换为JSON格式响应
- 说明:
@ResrController = @Controller + @ResponseBody
(所以上面可以直接通过返回值响应数据给客户端服务器)
1、响应-字符串
- 可以再定义一个类,专门用于存放
ResponseController
,并使用@RestController
注解
在这个类ResponseController
中加入:
@RequestMapping("/hello")
public String hello() {
System.out.println("Hello World!");
return "Hello World!";
}
发送后即可看见:
2、响应-对象json
请求可以写:(换个路径即可)
在这个类ResponseController
中加入:
@RequestMapping("/getAddr")
public Address getArr() {
Address addre = new Address();
addre.setProvince("山西");
addre.setCity("运城");
return addre;
}
发送后即可看见:
3、响应-集合json
请求也是换个自定义路径http://localhost:8080/listAddr
即可
在这个类ResponseController
中加入:
@RequestMapping("/listAddr")
public List<Address> listAddr() {
List<Address> list = new ArrayList<>();
Address addr = new Address();
addr.setProvince("山西");
addr.setCity("运城");
list.add(addr);
Address address = new Address();
address.setProvince("北京");
address.setCity("北京");
list.add(address);
return list;
}
发送后即可看见:
4、统一响应结果
以上的三种响应方式都不一样,前端需要分情况解析,当开发大型项目时,这样将会不便管理,且难以维护;所以在实际开发当中,我们都会给所以得功能接口(一个响应方法就是一个功能接口)设置一个统一的响应结果
- 统一响应结果:设置一个实体对象
Result
来接收
Result
对象的构建
在pojo
包中创建一个Result
类
public class Result {
private Integer code; // 1-成功 0-失败
private String msg; // 提示信息
private Object data; // 数据 data
public Result() {
}
public Result(Integer code, String msg, Object data) {
this.code = code;
this.msg = msg;
this.data = data;
}
public Integer getCode() {
return code;
}
public void setCode(Integer code) {
this.code = code;
}
public String getMsg() {
return msg;
}
public void setMsg(String msg) {
this.msg = msg;
}
public Object getData() {
return data;
}
public void setData(Object data) {
this.data = data;
}
// 定义静态方法,且返回值为当前类,便于外界直接用类名创建当前类的对象
public static Result success(Object data) {
return new Result(1, "success", data);
}
public static Result success() {
return new Result(1, "success", null);
}
public static Result error(String msg) {
return new Result(0, msg, null);
}
@Override
public String toString() {
return "Result{" +
"code=" + code +
", msg='" + msg + '\'' +
", data=" + data +
'}';
}
}
将ResponseController
类中的功能接口进行改造:
@RequestMapping("/hello")
public Result hello() {
System.out.println("Hello World!");
return Result.success("Hello World!");
}
@RequestMapping("/getAddr")
public Result getArr() {
Address addre = new Address();
addre.setProvince("山西");
addre.setCity("运城");
return Result.success(addre);
}
@RequestMapping("/listAddr")
public Result listAddr() {
List<Address> list = new ArrayList<>();
Address addr = new Address();
addr.setProvince("山西");
addr.setCity("运城");
list.add(addr);
Address address = new Address();
address.setProvince("北京");
address.setCity("北京");
list.add(address);
return Result.success(list);
}
此时发送可以看见:
都变成了统一的JSON格式!
拓展:
- Springboot项目的静态资源(html,css,js等前端资源)默认存放目录为
classpath:/static、classpath:/public、classpath:/resources
(对于Maven项目来说:resources
目录就是一个内路径(相当于classpath
))——一般直接放在resources
目录下的static
目录下即可。