SpringbootWeb请求和响应 - 三重解耦(IOC和DI)

110 阅读7分钟

SpringbootWeb请求和响应 - 三重解耦(IOC和DI)

1 请求

1.1 作用

​ 请求前端发送过来的数据

1.2 简单参数

​ 常用于前端发送过来的数据量比较小的时候

​ ps: 接收数据建议使用包装类,否则输入null会报空指针异常

​ 简单参数:参数名与形参变量名相同,定义形参即可接收参数。

// Responsebody + Controller
@RestController
public class mainController{

}
    @RequestMapping("/simpleParam")
    public String method(String name, Integer age) {
        System.out.println(name + "," + age);
        return "OK";
    }

​ 简单参数:如果方法形参名称与请求参数名称不匹配,可以使用 @RequestParam 完成映射。

    //@RequestParam  -绑定参数关系
	@RequestMapping("/simpleParam")
    public String method(@RequestParam (name = "name") String username, Integer age) {
        System.out.println(username + "," + age);
        return "OK";
    }
1.3 实体参数

​ 常用于前端发送过来的数据比较多的时候

​ 简单实体对象:请求参数名与形参对象属性名相同,定义POJO接收即可, 类放置于pojo文件夹中, 类成员变量的名字一定要和请求的参数名字一样

    @RequestMapping("/simplePojo")
    public String simplePojo(User user) {
        System.out.println(user);
        return "ok";
    }

​ 复杂实体对象:请求参数名与形参对象属性名相同,按照对象层次结构关系即可接收嵌套POJO属性参数。 如果返回的对象有包括xxx.yyy则一定为对象表达

    @RequestMapping("/complexPojo")
    public String complexPojoMtd(Student student, Address address) {
        System.out.println(student);
        return "OK";
    }
1.4 数组集合参数

​ 常用于多选框的时候,使用数组或者集合。【前端发送过来的多个键名字是一样的时候】

​ 数组参数:请求参数名与形参数组名称相同且请求参数为多个,定义数组类型形参即可接收参数

    @RequestMapping("/arrayParam")
    public String arrayParamMtd(@RequestParam(name = "hobby") String[] arr) {
        System.out.println(Arrays.toString(arr));
        return "OK";
    }

​ 集合参数:请求参数名与形参集合名称相同且请求参数为多个,@RequestParam 绑定参数关系

    @RequestMapping("/listParam")
    public String listParamMtd(@RequestParam(name = "hobby") List<String> hobby) {
        System.out.println(hobby);
        return "OK";
    }
1.5 日期参数

​ 日期参数:需要使用@DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss") 指定时间的格式

// 日期+时间
@RequestMapping("/dateParam")
 	 public  String dateParamMtd(@DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss") @RequestParam(name = "updateTime") LocalDateTime ldt){
     System.out.println(ldt);
     return "OK";
 }
//仅日期
@RequestMapping("/dateParam")
    public String dateParamMtd(@DateTimeFormat(pattern = "yyyy-MM-dd") @RequestParam(name = "updateTime") LocalDate ldt) {
        System.out.println(ldt);
        return "OK";
    }
1.6 Json参数

JSON参数:JSON数据键名与形参对象属性名相同,定义POJO类型形参即可接收参数,需要使用 @RequestBody 标识, 注意此时的JSON对象位于body中

    @RequestMapping("jsonParam")
    public String getjson(@RequestBody User user){
        System.out.println(user);
        return "OK";
    }
1.7 路径参数

路径参数:通过请求URL直接传递参数,使用{…}来标识该路径参数,需要使用 @PathVariable 获取路径参数, 注意定义的变量名要和路径中变量名一致

   //单层路径
	@RequestMapping("/path/{id}")
    public String getIdOnce(@PathVariable String id) {
        System.out.println(id);
        return "OK";
    }
    //多层路径
	@RequestMapping("/path/{id1}/{id2}")
    public String getIdTwice(@PathVariable String id1, @PathVariable String id2) {
        System.out.println(id1 + " == >  " + id2);
        return "OK";
    }

2 响应

2.1 作用

​ 把后端的数据响应给前端

2.2 @ResponseBody注解

​ ResponseBody注解可以添加在Controller方法上或者类上, 当添加在类上时, 将自动 给类下的方法附加注解, 从而将方法返回值直接响应,如果返回值类型是 实体对象/集合 ,将会转换为JSON格式响应.

​ @RestController = @Controller + @ResponseBody ;

2.3 响应的格式

​ 一般为了代码格式统一, 应响应一个Result类, 包括有code(0,1代表状态), msg(String 代表响应信息), data(代表响应数据)

代码实现:

//Result类
public class Result {
    // 响应的状态码  0 / 1
    private Integer code;
    // 响应给前端的信息
    private String msg;
    // 响应数据
    private Object data;
	//以下省略JavaBean
    
    public static Result failure(String msg, Object data) {
        return new Result(0, msg, data);
    }
        
    public static Result uccess(String msg, Object data) {
        return new Result(1, msg, data);
    }
    

@RestController
public class responseController {

   @RequestMapping("/login")
    public Result loginMtd(@RequestParam(name = "name") String username, @RequestParam(name = "password") String password) {
        if ("admin".equals(username) && "admin".equals(password)) {
            return Result.ok("登陆成功");
        } else {
            return Result.failure("失败");
        }
    }

}

3 分层解耦

3.1 三层架构

​ /\ Controller:控制层,接收前端发送的请求,对请求进行处理,并响应数据。 ​ /\ Service:业务逻辑层,处理具体的业务逻辑。 ​ /\ DAO:数据访问层(Data Access Object)(持久层),负责数据访问操作,包括数据的增、删、改、查。

3.2 分层解耦
3.2.1 为什么要分层解耦

​ /\ 内聚:软件中各个功能模块内部的功能联系。

	 /\ 耦合:衡量软件中各个层/模块之间的依赖、关联的程度。

​ ==> 软件设计原则:高内聚低耦合

​ ==> 1) 一个类只实现一个功能, 不要new别的对象, 把这个权力交给Spring容器 (IOC))

​ ==> 2) 把容器里的对象给接口去使用 (DI)

3.3 分层解耦的实现方法 - 三层架构

​ 开发顺序: 1) 构建架构

​ 2) controller -> service -> dao

3.3.1 controller

​ 接收请求,响应数据

​ Controller访问service, 获取处理完的数据

// 接收请求, 响应数据
@RestController
public class EmployeeControllerIocDi {
    @Autowired
    private EmpServiceImp empService;// = new EmpServiceImp();

    @RequestMapping("/listEmp")
    public Result listEmployee() {
        List list = empService.listEmployee();
        return new Result(1, "Success!", list);
    }
}
3.3.2 service

​ 指处理业务. 面向接口编程的实现方法 (所以均用多态创建对象), 访问dao, 获取数据, 并对数据进行分析和处理

//接口
public interface EmpService {

    public List listEmployee();
}

//service实现类
@Component
public class EmpServiceImp implements EmpService {
    @Autowired
    private EmpDao empDao; //= new EmpDaoImp();

    @Override
    public List listEmployee() {
        List<Emp> list = empDao.listEmployee();
        for (Emp emp : list) {
            if ("1".equals(emp.getGender())) {
                emp.setGender("男");
            } else {
                emp.setGender("女");
            }
            if ("1".equals(emp.getJob())) {
                emp.setJob("总经理");
            } else if ("2".equals(emp.getJob())) {
                emp.setJob("部门主管");
            } else {
                emp.setJob("组长");
            }
        }
        return list;
    }
}
3.3.3 dao

​ 面向接口编程的具体实现方法, 访问数据【包含数据的增删改查】

public interface EmpDao {
    public List listEmployee();
}
// 数据访问
@Component
public class EmpDaoImp implements EmpDao {

    @Override
    public List listEmployee() {
        //引入了一个jar包, 通过dom4j读取文档
        List list = XmlParserUtils.parse("D:\\code\\Web\\src\\main\\resources\\emp.xml", Emp.class);
        return list;
    }
}
3.3.4 上述代码利用了以下三种思维

​ /\ 控制反转: Inversion Of Control,简称IOC。对象的创建控制权由程序自身转移到外部(容器),或把对象的创建权力交给Spring容器, 这种思想称为控制反转。 ​ /\ 依赖注入: Dependency Injection,简称DI。容器为应用程序提供运行时,所依赖的资源,或把容器的对象注入到接口中, 称之为依赖注入。 ​ /\ Bean对象:IOC容器中创建、管理的对象,称之为bean。

3.2.4 IoC

​ 控制反转(Inversion of Control,简称IoC)指把某个对象交给IOC容器管理,将对象的创建、配置、依赖关系的管理等责任从应用程序代码中分离出来,转交给容器来完成的一种机制, 用于实现代码的松耦合和高内聚。需要在对应的类上加上如下注解之一

注解说明位置
@Component声明bean的基础注解不属于以下三类时,用此注解
@Controller@Component的衍生注解标注在控制器类上
@Service@Component的衍生注解标注在业务类上
@Repository@Component的衍生注解标注在数据访问类上(由于与mybatis整合,用的少)
3.2.5 DI

​ 依赖注入(Dependency Injection,DI)指 IoC 容器通过自动或手动注入对象的方式,解决对象之间的依赖关系。它会自动将依赖的对象注入到目标对象中,使得目标对象可以直接使用这些依赖对象。

  • @Autowired用于自动装配Bean,通过根据类型匹配进行依赖注入。

  • @Component是通用的Spring组件注解,被标记的类会被自动注册为Bean。

  • @Service是用于标识服务层组件的特殊@Component注解。

  • @Repository是用于标识数据访问层组件的特殊@Component注解。

    总的来说, IoC(Inversion of Control,控制反转)容器用于管理和组织应用程序中的对象(或称为 Bean)。它负责创建和管理这些对象的生命周期,并处理它们之间的依赖关系 (这时需要通过DI注入依赖)。

    IoC 容器的主要作用是实现对象的控制权反转,即将对象的创建和依赖关系的管理交给容器来完成,而不是由应用程序代码显式地创建和管理对象。这样可以降低对象之间的耦合度,提高代码的可维护性和扩展性。

3.2.7 Bean重复的解决办法

​ 如果同类型的bean存在多个: ​ @Primary ​ @Autowired + @Qualifier("bean的名称") ​ @Resource(name="bean的名称")

​ 添加bean名称从一定程度上增大了耦合

4 前后端分工

4.1 前端

​ 1) 发送请求

​ 2) 获取服务器返回的数据, 并做处理

4.2 后端

​ 1) 接收请求

​ 2) 从文件/数据库中先获取数据

​ 3) 再对数据进行处理

​ 4) 再把处理完的数据响应给前端