1. 创建spring boot项目

File => New Module => Spring Boot

勾选web开发相关依赖: Web => Spring Web

2. 开发步骤

在包下新建 XXController

类前加注解 @RestController

方法前加注解 @RequestMapping("")

启动时,运行SpringBootApplication即可

例子:

package com.itheima;
​
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
​
@RestController //标识当前类是一个请求处理类
public class HelloController {
​
    @RequestMapping("/hello") //标识请求路径
    public String hello(String name){
        System.out.println("HelloController ... hello: " + name);
        return "Hello " + name;
    }
​
}

为什么一个SpringBootApplication就可以启动web程序?因为我们在创建springboot项目的时候,选择了web开发的起步依赖 spring-boot-starter-web。而spring-boot-starter-web依赖,又依赖了spring-boot-starter-tomcat,由于maven的依赖传递特性,那么在我们创建的springboot项目中也就已经有了tomcat的依赖,这个其实就是springboot中内嵌的tomcat。 而我们运行引导类中的main方法,其实启动的就是springboot中内嵌的Tomcat服务器。 而我们所开发的项目,也会自动的部署在该tomcat服务器中,并占用8080端口号

RestController注解中 包含有ResonseBody,其作用是将 controller 返回值直接作为响应体的数据,

过程是 controller 返回值 -> json -> 响应体

3. bean对象

  • @Data:生成 Getter、Setter、toString()equals()hashCode() 方法。

  • @NoArgsConstructor:生成无参构造函数。

  • @AllArgsConstructor:生成全参构造函数。

4. 三层结构

原始版本的代码逻辑:

  1. 接受页面请求,先从数据库中读取数据

  2. 对读取的数据进行业务逻辑处理

  3. 返回处理好的数据

三层结构设计:

职责分离:每一层只负责特定的功能,职责清晰,便于理解和维护

降低耦合性:各层之间通过接口或依赖注入进行交互,降低了代码的耦合性

便于扩展:当需要新增功能时,可以在不影响其他层的情况下进行扩展

便于测试:每一层可以独立测试,便于定位问题和修复 Bug

4.1 controller层(表示层)

Controller 只负责接收请求和返回响应,不涉及具体的业务逻辑或数据操作

  • 接收用户请求:处理 HTTP 请求(如 GET、POST 等)。

  • 调用 Service 层:将用户请求传递给业务逻辑层进行处理。

  • 返回响应:将处理结果封装成 JSON、HTML 或其他格式,返回给客户端。

4.2 Service 层(业务逻辑层)

  • 处理业务逻辑:实现具体的业务规则和流程。

  • 调用 Dao 层:通过 Dao 层访问数据库或其他数据源。

  • 事务管理:确保业务操作的原子性和一致性。

4.3 Dao 层(数据访问层)

  • 与数据库交互:执行数据的增删改查操作。

  • 封装数据访问细节:隐藏数据库的具体实现(如 SQL 语句、ORM 框架等)。

代码书写逻辑

  1. 先写dao层的接口,在impl的实现类中实现该接口的方法,返回读取来的原始数据

  2. 在service层中写接口,在impl的实现类中,new一个dao层的对象来调用方法获取原始数据,然后对原始数据进行业务处理,返回处理好的数据

  3. 在controller层中,new一个service层的对象来调用方法获取处理好的数据,直接返回给前端

5. 分层解耦

先前代码的缺点: controller层中有 new service层对象的代码,service层有new dao层对象的代码,这样导致三层之间具有耦合性

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

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

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

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

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

  • bean对象:IOC容器中创建、管理的对象,称之为:bean对象。

解决方法:将Dao、service层的实现类,交给IOC容器管理(在实现类前加@Component);

为controller、service注入所依赖的对象(在声明变量前加 @Autowired

5.1 IOC

规范注解:controller层前加 @RestController

service层实现类前加 @Service

dao层实现类前加 @Repository

修改在IOC容器中bean对象的名字:例如@Service("userService")

注解

说明

位置

@Component

声明bean的基础注解

不属于以下三类时,用此注解

@Controller

@Component的衍生注解

标注在控制层类上

@Service

@Component的衍生注解

标注在业务层类上

@Repository

@Component的衍生注解

标注在数据访问层类上(由于与mybatis整合,用的少)

以上注解要生效,必须由 @ComponentScan 组件来扫描。

application启动类中的 @SpringBootApplication就包含了 @ComponentScan 组件,它会扫描文件所在包及其子包下的所有注解

5.2 DI

1). 属性注入

@RestController
public class UserController {
​
    //方式一: 属性注入
    @Autowired
    private UserService userService;
    
  }
  • 优点:代码简洁、方便快速开发。

  • 缺点:隐藏了类之间的依赖关系、可能会破坏类的封装性。

2). 构造函数注入

@RestController
public class UserController {
​
    //方式二: 构造器注入
    private final UserService userService;
    
    @Autowired //如果当前类中只存在一个构造函数, @Autowired可以省略
    public UserController(UserService userService) {
        this.userService = userService;
    }
    
 }   
  • 优点:能清晰地看到类的依赖关系、提高了代码的安全性。

  • 缺点:代码繁琐、如果构造参数过多,可能会导致构造函数臃肿。

  • 注意:如果只有一个构造函数,@Autowired注解可以省略。(通常来说,也只有一个构造函数)

3). setter注入

/**
 * 用户信息Controller
 */
@RestController
public class UserController {
    
    //方式三: setter注入
    private UserService userService;
    
    @Autowired
    public void setUserService(UserService userService) {
        this.userService = userService;
    }
    
}    
  • 优点:保持了类的封装性,依赖关系更清晰。

  • 缺点:需要额外编写setter方法,增加了代码量。

推荐 第一种第二种 方式

存在多个相同类型的bean对象,会报错

解决方案:

方案一:使用@Primary注解

当存在多个相同类型的Bean注入时,加上@Primary注解,来确定优先注入的bean。

@Primary
@Service
public class UserServiceImpl implements UserService {
}

方案二:使用@Qualifier注解

指定当前要注入的bean对象。 在@Qualifier的value属性中,指定注入的bean的名称。 @Qualifier注解不能单独使用,必须配合@Autowired使用。

@RestController
public class UserController {
​
    @Qualifier("userServiceImpl")
    @Autowired
    private UserService userService;

方案三:使用@Resource注解

是按照bean的名称进行注入。通过name属性指定要注入的bean的名称。

@RestController
public class UserController {
        
    @Resource(name = "userServiceImpl")
    private UserService userService;

面试题:@Autowird 与 @Resource的区别

  • @Autowired 是spring框架提供的注解,而@Resource是JDK提供的注解

  • @Autowired 默认是按照类型注入,而@Resource是按照名称注入

6. 原理