请求和响应简单来说都是前端和后端互相沟通的一个方式,请求指的是前端程序向后端发送数据“请求”操作,响应指的是后端程序将前端的请求处理后做出的“回应”。
1 请求
1.1 软件选择
我们要发送请求首先需要有相应的插件,我们这里选择的是Postman。
Postman操作页面如下,比较简单,用一用就知道了。
后续内容中我们会在英文的基础上加上红字的说明来讲解,方便理解。
1.2 6种参数的写法
1.2.1 简单参数
@RequestMapping("/simpleParam")
public String simpleParam(String name , Integer age ){
System.out.println(name+" : "+age);
return "OK";
}
如果方法形参名称与请求参数名称不一致,可以在方法形参名前加上 @RequestParam 完成映射
1.2.2 实体参数
简单实体参数:只有一个实体类
@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";
}
只有在键值对这里有一点不同
1.2.3 数组集合参数
数组参数:请求参数名与形参对象属性名相同且请求参数为多个,定义数组类型形参即可接收参数
@RequestMapping("/arrayParam")
public String arrayParam(String[] hobby){
System.out.println(Arrays.toString(hobby));
return "OK";
}
集合参数:请求参数名与形参集合对象名相同且请求参数为多个,@RequestParam 绑定参数关系
本质区别不大,除了要加一个注解
@RequestMapping("/listParam")
public String listParam(@RequestParam List<String> hobby){
System.out.println(hobby);
return "OK";
}
1.2.4 日期时间参数
需要date就@DateFormat,需要time就@TimeFormat,都需要就@DataTimeFormat
@RequestMapping("/dateParam")
public String dateParam(@DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss") LocalDateTime updateTime){
System.out.println(updateTime);
return "OK";
}
1.2.5 JSON参数
前后端通常会使用JSON格式的数据进行传输。
JSON数据键名与形参对象属性名相同,定义POJO(类似javabean)类型形参即可接收参数。需要使用 @RequestBody 标识。
@RequestMapping("/jsonParam")
public String jsonParam(@RequestBody User user){
System.out.println(user);
return "OK";
}
1.2.6 路径参数
路径参数:通过请求URL直接传递参数,使用{…}来标识该路径参数,需要使用 @PathVariable 获取路径参数
@RequestMapping("/path/{id}")
public String pathParam(@PathVariable Integer id){
System.out.println(id);
return "OK";
}
@RequestMapping("/path/{id}/{name}")
public String pathParam2(@PathVariable Integer id, @PathVariable String name){
System.out.println(id+ " : " +name);
return "OK";
}
2 响应
2.1 响应各种数据
返回字符串数据
@RequestMapping("/simpleParam")
public String simpleParam( String name , Integer age){
System.out.println(name+" : "+age);
return "OK";
}
返回实体对象数据
@RequestMapping("/getUser")
public User getUser(){
User user = new User();
user.setName("Tom");
user.setAge(10);
return user;
}
返回集合数据
@RequestMapping("/list")
public List<User> list(){
User user = new User();
user.setName("Tom");
user.setAge(10);
List<User> userList = new ArrayList<>();
userList.add(user);
return userList;
}
2.2 ResposeBody
- 名称:@ResponseBody
- 类型:方法注解、类注解
- 位置:SpringMVC控制器方法上/类上
- 作用:将当前方法返回值直接返回,如果是 实体/集合 转换为JSON返回
而我们的案例中,并没有直接使用 @ResponseBody,原因是因为我们使用的是 @RestController注解,该注解中已经封装了@ResponseBody注解,已经包含了@ResponseBody注解的作用,我们无需要额外添加。
2.3 统一响应
在真实的项目开发中,无论是增删改查的那种方法,我们都会定义一个统一的返回结果,在这个返回结果中,包含以下信息:
A. 当前请求是成功,还是失败。
B. 当前给页面的提示信息。
C . 返回的数据。
对于上述的这些数据呢,我们一般都会定义在一个实体类Result中。 代码如下:
public class Result {
private Integer code;//响应码,1 代表成功; 0 代表失败
private String msg; //响应码 描述字符串
private Object 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(){
return new Result(1,"success",null);
}
//查询 成功响应
public static Result success(Object data){
return new Result(1,"success",data);
}
//失败响应
public static Result error(String msg){
return new Result(0,msg,null);
}
}
3 解耦
解耦:简单来说就是减少依赖
依赖:依赖指的是两个类之间的相互依赖关系,我用到你,我就依赖你
3.1 三层架构
分为Controller,Service,Dao三部分,具体实现的功能如下:
- Controller:接收前端发送的请求,对请求进行处理,并响应数据
- Service:处理具体的业务逻辑
- Dao:负责数据的访问操作,包含数据的增、删、改、查
3.2 耦合问题
1).内聚:软件中各个功能模块内部的功能联系。
2).耦合:衡量软件中各个层/模块之间的依赖、关联的程度。
3).软件设计原则:高内聚低耦合。
而在软件开发领域,我们经常会提到一种设计原则:高内聚,低耦合。 高内聚指的是:一个模块中各个元素之间的联系的紧密程度,如果各个元素(语句、程序段)之间的联系程度越高,则内聚性越高,即 "高内聚"。低耦合指的是:软件中各个层、模块之间的依赖关联程度越低越好。
高内聚、低耦合的目的是使程序模块的可重用性、移植性大大增强。
3.3 IOC&DI
1). 将对象交给容器管理的过程 , 称之为 控制反转。 Inversion Of Control,简称IOC。对象的创建控制权由程序自身转移到外部(容器),这种思想称为控制反转。 而这个容器, 称之为IOC容器,或者Spring容器。
2). 应用程序运行时, 容器为其提供运行时所需要的资源, 这个过程我们称之为依赖注入。 Dependency Injection,简称DI。
3). IOC容器中创建、管理的对象,称之为bean。
- Service层 及 Dao层的实现类,交给IOC容器管理。在类上加上 @Component 注解,就是将该类声明为IOC容器中的bean
@Component
public class UserServiceA implements UserService {
@Autowired
private UserDao userDao ;
public List<User> listUser() {
//调用 dao 层, 查询数据
List<User> userList = userDao.listUser();
//2. 对数据进行逻辑处理
for (User user : userList) {
Address address = user.getAddress();
address.setProvince(address.getProvince()+" 省/市A");
address.setCity(address.getCity()+" 区/县A");
user.setAddress(address);
}
return userList;
}
}
@Component
public class UserDaoA implements UserDao {
public List<User> listUser() {
//1. 从文件中查询数据
String file = UserController.class.getClassLoader().getResource("user.xml").getFile();
List<User> userList = XmlParserUtils.parse(file);
System.out.println(userList);
return userList;
}
}
- 为Controller及Service注入运行时依赖的对象。在成员变量上加上 @Autowired 注解,表示在程序运行时,Springboot会自动的从IOC容器中找到UserService类型的bean对象,然后赋值给该变量。
@RestController
public class UserController {
@Autowired
private UserService userService ;
@RequestMapping("/listUser")
public Result listUser() {
List<User> userList = userService.listUser();
return Result.success(userList);
}
}
3.3.1 依赖注入问题
但是需要注意:@Autowired注解,默认是按照类型进行,如果存在多个相同类型的bean,将会报出如下错误:
我们可以通过如下几种方案来解决:
1). @Primary 注解
当存在多个相同类型的Bean注入时,加上@Primary注解,来确定默认的实现。
2). @Qualifier 注解
可以通过@Autowired ,配合@Qualifier 来指定我们当前要注入哪一个bean对象。 在@Qualifier的value属性中,指定注入的bean的名称。
3). @Resource注解
通过@Resource注解,并指定其name属性,通过name指定要注入的bean的名称。这种方式呢,是按照bean的名称进行注入。
@Autowird 与 @Resource的区别:
- @Autowird 属于spring框架,默认按照bean的类型注入。 可以配合 @Qualifier注解,实现按照名称注入。
- @Resource是JavaEE自带的注解,根据bean的名称进行注入的。