• 后端工程化 | SpringBoot 知识点



    [SpringBoot] 后端工程化

    1 需求

    • 需求:基于SpringBoot的方式开发一个web应用,浏览器发起请求“/hello”后,给浏览器返回字符串 “Hello World ”。

    SpringBoot通信流程-2023-10-2917:12:43.png

    2 开发流程

    • 创建SpringBoot工程项目

    第一步:用 IDEA 基于Spring官方骨架,创建SpringBoot工程。

    SpringBoot工程骨架-2023-10-2917:15:16.png

    第二步:选择 SpringBoot 框架版本,勾选web开发相关依赖。

    SpringBoot 框架版本-2023-10-2917:17:41.png

    • 定义RequestController类,添加方法hello,并添加注解

    在主包名下,创建 controller 包 + pojo 包

    SpringBoot项目的架构-2023-10-2917:23:43.png

    package com.itheima.controller;
    import org.springframework.web.bind.annotation.*;
    
    @RestController
    public class RequestController {
    
        @RequestMapping("/hello")
        public String hello(){
            System.out.println("Hello World ~");
            return "Hello World !";
        } 
    } 
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 测试运行

    运行 SprintBootWebObjectApplication

    3 RequestController 类(操作类)

    • 作用:接收前端的表单数据
    3.1 简单参数(形参名和请求参数名一致)
    • 前端
    - 请求方式:GET
    - URL: http://localhost:8080/simpleParam?name=lisi&age=45
    
    • 1
    • 2
    • 后端
    @RestController
    public class RequestController {
        // 第1个请求参数: name=Tom   参数名:name,参数值:Tom
        // 第2个请求参数: age=10     参数名:age , 参数值:10
        
        //springboot方式
        @RequestMapping("/simpleParam")
        public String simpleParam(String name , Integer age ){//形参名和请求参数名保持一致
            System.out.println(name+"  :  "+age);
            return "OK"; //返回数据
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    3.2 简单参数(形参名和请求参数名不一致)
    • 前端
    - 请求方式:GET
    - URL: http://localhost:8080/simpleParam?name=lisi&age=45
    
    • 1
    • 2
    • 后端
    @RestController
    public class RequestController {
        // 第1个请求参数: name=Tom   参数名:name,参数值:Tom
        // 第2个请求参数: age=10     参数名:age , 参数值:10
        
        //springboot方式
        @RequestMapping("/simpleParam")
        public String simpleParam(@RequestParam(name = "name", required = false) String username , Integer age ){// name:请求参数名,required:参数是否必须
            System.out.println(username+"  :  "+age);
            return "OK"; //返回数据
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    3.3 复杂实体参数
    • 前端
    - 请求方式:GET
    - URL: http://localhost:8080/complexPojo?username=李四&age=10&address.province=背景&address.city=上海
    
    • 1
    • 2
    • 后端
    @RestController
    public class RequestController {  
        //springboot方式
        @RequestMapping("/complexPojo")
        public String complexPojo(User user) {
            System.out.println(user);
            return "ok";
        }
        
        User{
            private String username;
        	private int age;
        	private Address address;
            GetSet 方法;
            ToString 方法;
        }
        
        Address{
            private String province;
        	private String city;
            GetSet 方法;
            ToString 方法;
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    3.4 数组参数
    • 前端
    - 请求方式:GET
    - URL: http://localhost:8080/arrayParam?hobby=string&hobby=java&hobby=python
    
    • 1
    • 2
    • 后端
    @RestController
    public class RequestController {
        //springboot方式
        @RequestMapping("/arrayParam")
        public String arrayParam(String[] hobby) {
            System.out.println(Arrays.toString(hobby));
            return "ok,arrayParam";
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    3.5 集合参数
    • 前端
    - 请求方式:GET
    - URL: http://localhost:8080/listParam?hobby=string&hobby=java&hobby=python
    
    • 1
    • 2
    • 后端
    @RestController
    public class RequestController {
        //springboot方式
        @RequestMapping("/listParam")
        public String listParam(@RequestParam List<String> hobby) {
            System.out.println(hobby);
            return "ok,listParam";
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    3.6 时间参数
    • 前端
    - 请求方式:GET
    - URL: http://localhost:8080/dateParam?date=2023-02-09 12:08:09
    
    • 1
    • 2
    • 后端
    @RestController
    public class RequestController {
        //springboot方式
        @RequestMapping("/dateParam")
        public String dateParam(@DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss") LocalDateTime date) {
            System.out.println(date);
            return "ok,dateParam";
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    3.7 json参数
    • 前端
    - 请求方式:POST
    - URL: http://localhost:8080/jsonParam
    - 请求体:
    {
        "username": "lisi",
        "age": 23,
        "address": {
           "province": "beijing",
           "city": "上海"
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 后端
    @RestController
    public class RequestController {
        // 第1个请求参数: name=Tom   参数名:name,参数值:Tom
        // 第2个请求参数: age=10     参数名:age , 参数值:10
        
        //springboot方式
         @RequestMapping("/jsonParam")
        public String jsonParam(@RequestBody User user) {
            System.out.println(user);
            return "ok,jsonParam";
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    3.8 单个路径参数
    • 前端
    - 请求方式:GET
    - URL: http://localhost:8080/path/1000
    
    • 1
    • 2
    • 后端
    @RestController
    public class RequestController {
        //springboot方式
        @RequestMapping("/path/{id}")
        public String pathParam(@PathVariable Integer id) {
            System.out.println(id);
            return "ok,pathParam";
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    3.9 多个路径参数
    • 前端
    - 请求方式:GET
    - URL: http://localhost:8080/path/1000/Lisi
    
    • 1
    • 2
    • 后端
    @RestController
    public class RequestController {
        //springboot方式
        @RequestMapping("/path/{id}/{name}")
        public String pathParam(@PathVariable Integer id, @PathVariable String name) {
            System.out.println(id);
            System.out.println(name);
            return "ok,pathParam";
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    4 RequestController 类(查询类)

    4.1 @ResponseBody
    • 由于 @RestController = @Controller + @ResponseBody ,所以不用重复添加。
    4.2 统一响应结果
    • 定义在一个实体类 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);
        }
    }
    
    • 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
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49

    5 分层解耦

    5.1 三层架构
    • 请求处理、响应数据(Controller):控制层。负责接收页面的请求,给页面响应数据。
    • 逻辑处理(Service):业务逻辑层。负责业务逻辑处理的代码。
    • 数据访问(Dao):数据访问层(Data Access Object),也称为持久层。负责业务数据的维护操作,包括增、删、改、查等操作。

    在这里插入图片描述

    5.2 分层目录及代码

    1698590017953-2023-10-2922:33:38.png

    5.2.1 数据访问层
    • 负责数据的访问操作,包含数据的增、删、改、查

    • 数据访问接口

    //数据访问层接口(制定标准)
    public interface EmpDao {
        //获取员工列表数据
        public List<Emp> listEmp();
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 数据访问实现类
    //数据访问实现类
    public class EmpDaoA implements EmpDao {
        @Override
        public List<Emp> listEmp() {
            //1. 加载并解析emp.xml
            String file = this.getClass().getClassLoader().getResource("emp.xml").getFile();
            System.out.println(file);
            List<Emp> empList = XmlParserUtils.parse(file, Emp.class);
            return empList;
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    5.2.2 业务逻辑
    • 处理具体的业务逻辑

    • 业务接口

    //业务逻辑接口(制定业务标准)
    public interface EmpService {
        //获取员工列表
        public List<Emp> listEmp();
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 业务实现类
    //业务逻辑实现类(按照业务标准实现)
    public class EmpServiceA implements EmpService {
        //dao层对象
        private EmpDao empDao = new EmpDaoA();
    
        @Override
        public List<Emp> listEmp() {
            //1. 调用dao, 获取数据
            List<Emp> empList = empDao.listEmp();
    
            //2. 对数据进行转换处理 - gender, job
            empList.stream().forEach(emp -> {
                //处理 gender 1: 男, 2: 女
                String gender = emp.getGender();
                if("1".equals(gender)){
                    emp.setGender("男");
                }else if("2".equals(gender)){
                    emp.setGender("女");
                }
    
                //处理job - 1: 讲师, 2: 班主任 , 3: 就业指导
                String job = emp.getJob();
                if("1".equals(job)){
                    emp.setJob("讲师");
                }else if("2".equals(job)){
                    emp.setJob("班主任");
                }else if("3".equals(job)){
                    emp.setJob("就业指导");
                }
            });
            return empList;
        }
    }
    
    • 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
    5.2.3 控制层
    • 接收前端发送的请求,对请求进行处理,并响应数据
    @RestController
    public class EmpController {
        //业务层对象
        private EmpService empService = new EmpServiceA();
    
        @RequestMapping("/listEmp")
        public Result list(){
            //1. 调用service层, 获取数据
            List<Emp> empList = empService.listEmp();
    
            //3. 响应数据
            return Result.success(empList);
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    5.3 分层解耦
    5.3.1 耦合问题
    • 内聚:软件中各个功能模块内部的功能联系。

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

    软件设计原则:高内聚低耦合。

    高内聚:一个模块中的代码,各个代码块之间关系越紧密,则内聚性越高。

    低耦合:软件中各个层、模块之间的依赖(相互关联)性越低,则耦合度越低。

    高内聚、低耦合-2023-11-621:24:47.png

    5.3.2 解耦思路
    • 解决思路

      1. 提供一个容器,容器中存储一些对象(例:EmpService对象)
      2. controller程序从容器中获取EmpService类型的对象
    • 解耦操作

      • 控制反转:[ Inversion Of Control ],简称IOC。对象的创建控制权由程序自身转移到外部(容器),这种思想称为控制反转。

        对象的创建权由程序员主动创建转移到容器(由容器创建、管理对象)。这个容器称为:IOC容器或Spring容器

      • 依赖注入:[ Dependency Injection ],简称DI。容器为应用程序提供运行时,所依赖的资源,称之为依赖注入。

        程序运行时需要某个资源,此时容器就为其提供这个资源。

        例:EmpController程序运行时需要EmpService对象,Spring容器就为其提供并注入EmpService对象

    5.4 IOC & DI
    5.4.1 Bean的声明(IOC)
    • ICO 容器管理:IOC控制反转,就是将对象的控制权交给Spring的IOC容器,由IOC容器创建及管理对象。IOC容器创建的对象称为bean对象。

    把某个对象交给IOC容器管理,需要在类上添加一个注解:@Component

    注解说明位置
    @Component声明bean的基础注解全部类通用注解(除控制类)
    @Controller@Component的衍生注解标注在控制器类上
    @Service@Component的衍生注解标注在业务逻辑类上
    @Repository@Component的衍生注解标注在数据访问类上(由于与mybatis整合,用的少)

    • @RestController = @Controller + @ResponseBody
    • 声明bean的时候,可以通过value属性指定bean的名字,如果没有指定,默认为类名首字母小写。
    • 使用以上四个注解都可以声明bean,但是在springboot集成web开发中,声明控制器bean只能用@Controller。
    5.4.2 组件扫描(IOC)
    • Bean 想要生效,还需要被组件扫描。
    // 使用四大注解声明的 Bean,要想生效,还需要被组件扫描注解 @ComponentScan 扫描
    @ComponentScan("dao", "com.Jiacheng")
    @SpringBootApplication
    public class SprintBootWebObjectApplication {
        public static void main(String[] args) {
           SpringApplication.run(SprintBootWebObjectApplication.class, args);
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    :不推荐组件扫描,按照 SprintBoot 项目结构创建目录即可

    5.4.3 DI
    • 依赖注入:IOC容器要为应用程序去提供运行时所依赖的资源,而资源指的就是对象。
    // 依赖注入:@Autowired注解,按照类型进行自动装配。
    @Autowired
    private EmpService empService;
    
    • 1
    • 2
    • 3
    • 依赖冲突:在 IOC 容器中,存在多个相同类型的 Bean 对象,程序运行会报错。
    注解说明位置
    @Autowired按照类型自动装配 Bean 对象类内
    @Primary让当前类的 Bean 生效类上
    @Qualifier(“serviceA”)指定注入的 Bean 对象(搭配@Autowired)类内
    @Resource(name = “serviceB”)按照 Bean的名称进行注入类内
    // 1.@Autowired 注入
    @Autowired
    private EmpService empService;
    
    // 2.@Primary 注入
    @Primary
    public class EmpServiceA implements EmpService {}
    
    // 3.@Qualifier() 注入,指定当前要注入的bean对象
    @Autowired
    @Qualifier("empServiceA")
    private EmpService empService;
    
    // 4.@Resource() 注入
    @Resource(name = "empServiceB")
    private EmpService empService;
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 面试题 : @Autowird 与 @Resource的区别?
    1. @Autowired 是spring框架提供的注解,而@Resource是JDK提供的注
    2. @Autowired 默认是按照类型注入,而@Resource是按照名称注入
  • 相关阅读:
    TFM—用于实时监控和数据管理的远程试验管理平台
    Springboot+Vue实现物业管理系统
    Mac中隐私安全性设置-打开任何来源
    docker介绍和安装
    【太阳能多电平逆变器】采用SPWM技术的太阳能供电多电平逆变器研究(simulink)
    【SpringMVC】之自定义注解
    支付宝"手机网站支付"主域名申请了,二级域名还要申请吗
    【calcite】calcite实现SQL列级数据血缘 data lineage 查询
    springcloud环境搭建
    Docker 介绍
  • 原文地址:https://blog.csdn.net/qq_52099094/article/details/134256264