学习笔记:SpringBootWeb、HTTP、三层架构、IOC/D

40 阅读7分钟

结合常见的 Java 后端入门核心知识点(SpringBootWeb、HTTP、三层架构、IOC/DI),核心内容梳理如下:

核心模块关键知识点
SpringBootWeb项目搭建、Controller 编写、请求 / 响应处理、内嵌容器(Tomcat)
HTTP 协议请求 / 响应结构、GET/POST 请求、状态码(200/404/500)、无状态特性
三层架构表现层(Controller)、业务层(Service)、持久层(Mapper)职责与解耦
IOC/DI控制反转(容器管理 Bean)、依赖注入(@Autowired / 构造器 / Setter)

二、核心示例代码

1. SpringBootWeb 项目基础示例(完整可运行)

步骤 1:pom.xml 核心依赖(SpringBoot 2.7.x)

xml

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.7.10</version>
        <relativePath/>
    </parent>
    <groupId>com.example</groupId>
    <artifactId>springboot-web-demo</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>springboot-web-demo</name>
    <description>SpringBootWeb入门示例</description>
    
    <dependencies>
        <!-- SpringBootWeb核心依赖 -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <!-- 简化代码(可选) -->
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </dependency>
        <!-- 测试依赖 -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
                <configuration>
                    <excludes>
                        <exclude>
                            <groupId>org.projectlombok</groupId>
                            <artifactId>lombok</artifactId>
                        </exclude>
                    </excludes>
                </configuration>
            </plugin>
        </plugins>
    </build>
</project>
步骤 2:主启动类

java

运行

package com.example.demo;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class SpringbootWebDemoApplication {
    public static void main(String[] args) {
        SpringApplication.run(SpringbootWebDemoApplication.class, args);
    }
}
步骤 3:三层架构核心代码
1. 表现层(Controller)- 处理 HTTP 请求

java

运行

package com.example.demo.controller;

import com.example.demo.entity.User;
import com.example.demo.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;

import java.util.List;

/**
 * 用户模块Controller(表现层)
 */
@RestController // 等同于@Controller + @ResponseBody
@RequestMapping("/users") // 统一请求路径前缀
public class UserController {

    // 依赖注入:字段注入(简化版,生产推荐构造器注入)
    @Autowired
    private UserService userService;

    /**
     * GET请求:查询所有用户
     */
    @GetMapping // 匹配GET /users
    public List<User> listAll() {
        return userService.listAll();
    }

    /**
     * GET请求:根据ID查询用户(路径参数)
     */
    @GetMapping("/{id}") // 匹配GET /users/1
    public User getById(@PathVariable Integer id) {
        return userService.getById(id);
    }

    /**
     * POST请求:新增用户(请求体传参)
     */
    @PostMapping // 匹配POST /users
    public String add(@RequestBody User user) {
        boolean success = userService.add(user);
        return success ? "新增成功" : "新增失败";
    }

    /**
     * PUT请求:修改用户
     */
    @PutMapping // 匹配PUT /users
    public String update(@RequestBody User user) {
        boolean success = userService.update(user);
        return success ? "修改成功" : "修改失败";
    }

    /**
     * DELETE请求:删除用户
     */
    @DeleteMapping("/{id}") // 匹配DELETE /users/1
    public String delete(@PathVariable Integer id) {
        boolean success = userService.delete(id);
        return success ? "删除成功" : "删除失败";
    }
}
2. 实体类(User)

java

运行

package com.example.demo.entity;

import lombok.Data;

/**
 * 用户实体类
 */
@Data // Lombok:自动生成get/set/toString等方法
public class User {
    private Integer id;
    private String username;
    private String password;
    private Integer age;
}
3. 业务层(Service)- 处理业务逻辑

java

运行

package com.example.demo.service;

import com.example.demo.entity.User;

import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;

/**
 * 用户模块Service(业务层)
 */
public interface UserService {
    List<User> listAll();
    User getById(Integer id);
    boolean add(User user);
    boolean update(User user);
    boolean delete(Integer id);
}

// 业务层实现类
@org.springframework.stereotype.Service // 标记为Spring Bean(业务层)
class UserServiceImpl implements UserService {

    // 模拟内存数据库(实际开发替换为Mapper操作数据库)
    private static List<User> userList = new ArrayList<>();

    static {
        // 初始化测试数据
        userList.add(new User(1, "zhangsan", "123456", 20));
        userList.add(new User(2, "lisi", "654321", 22));
    }

    @Override
    public List<User> listAll() {
        return userList;
    }

    @Override
    public User getById(Integer id) {
        return userList.stream().filter(user -> user.getId().equals(id)).findFirst().orElse(null);
    }

    @Override
    public boolean add(User user) {
        user.setId(userList.size() + 1); // 模拟自增ID
        return userList.add(user);
    }

    @Override
    public boolean update(User user) {
        User oldUser = getById(user.getId());
        if (oldUser == null) {
            return false;
        }
        oldUser.setUsername(user.getUsername());
        oldUser.setPassword(user.getPassword());
        oldUser.setAge(user.getAge());
        return true;
    }

    @Override
    public boolean delete(Integer id) {
        return userList.removeIf(user -> user.getId().equals(id));
    }
}
4. 持久层(Mapper)- 模拟数据库操作(实际开发用 MyBatis/MyBatis-Plus)

java

运行

package com.example.demo.mapper;

import com.example.demo.entity.User;
import org.springframework.stereotype.Repository;

import java.util.List;

/**
 * 用户模块Mapper(持久层)- 模拟接口(实际开发加@Mapper注解)
 */
@Repository // 标记为Spring Bean(持久层)
public interface UserMapper {
    List<User> listAll();
    User getById(Integer id);
    int add(User user);
    int update(User user);
    int delete(Integer id);
}

2. IOC/DI 三种注入方式示例

java

运行

package com.example.demo.service;

import com.example.demo.mapper.UserMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

/**
 * DI依赖注入三种方式示例
 */
@Service
public class InjectDemoService {

    // 方式1:字段注入(简化,不推荐生产使用,不利于单元测试)
    @Autowired
    private UserMapper userMapper1;

    // 方式2:Setter注入(推荐,支持可选依赖)
    private UserMapper userMapper2;
    @Autowired
    public void setUserMapper2(UserMapper userMapper2) {
        this.userMapper2 = userMapper2;
    }

    // 方式3:构造器注入(最推荐,强制依赖,支持final,利于单元测试)
    private final UserMapper userMapper3;
    @Autowired // Spring4.3+后,单个构造器可省略@Autowired
    public InjectDemoService(UserMapper userMapper3) {
        this.userMapper3 = userMapper3;
    }
}

三、企业面试题(附标准答案)

1. SpringBootWeb 核心

面试题标准答案
SpringBoot 的核心优势是什么?和 Spring 的区别?核心优势:① 自动配置(减少 XML / 手动配置);② 起步依赖(简化 Maven/Gradle 依赖管理);③ 内嵌容器(Tomcat/Jetty,无需手动部署);④ 无 XML 配置(注解驱动);⑤ 监控 / 健康检查(Actuator)。区别:Spring 是基础框架,需手动配置;SpringBoot 是 “约定优于配置” 的快速开发框架,基于 Spring 封装,简化开发流程。
@Controller 和 @RestController 的区别?@Controller:标记表现层 Bean,返回值默认是视图名(配合 Thymeleaf 等模板引擎);@RestController:= @Controller + @ResponseBody,返回值直接转为 JSON/XML 响应体,适用于前后端分离项目。
@RequestMapping 和 @GetMapping/@PostMapping 的关系?@RequestMapping 是通用请求映射注解,可指定 method 属性(GET/POST 等);@GetMapping = @RequestMapping (method = RequestMethod.GET),@PostMapping 同理,是简化版注解,语义更清晰。
SpringBoot 如何修改内嵌 Tomcat 端口?① 配置文件方式:application.properties 中加server.port=8081;② 编程式:实现 WebServerFactoryCustomizer 接口,自定义 Tomcat 配置;③ 启动参数:java -jar xxx.jar --server.port=8081

2. HTTP 协议核心

面试题标准答案
GET 和 POST 的核心区别?① 参数位置:GET 参数在 URL 后(查询字符串),POST 在请求体;② 长度限制:GET 受浏览器 / 服务器 URL 长度限制,POST 无明确限制;③ 安全性:GET 参数暴露在 URL,POST 相对安全(但未加密仍可抓包);④ 幂等性:GET 幂等(多次请求结果一致),POST 非幂等(多次提交可能重复创建数据);⑤ 缓存:GET 可被浏览器缓存,POST 默认不缓存。
HTTP 是无状态的,如何解决状态保持问题?① Cookie:客户端存储(浏览器),服务器响应 Set-Cookie 头写入,后续请求自动携带;② Session:服务端存储,基于 Cookie 的 JSESSIONID 关联;③ Token(JWT):客户端存储(LocalStorage/Cookie),服务端无需存储,解析 Token 验证身份;④ Redis:结合 Session/Token,分布式场景共享状态。
常见 HTTP 状态码及含义?① 2xx 成功:200(请求成功)、201(创建成功);② 3xx 重定向:301(永久重定向)、302(临时重定向)、304(缓存未修改);③ 4xx 客户端错误:400(请求参数错误)、401(未授权)、403(禁止访问)、404(资源不存在)、405(请求方法不允许);④ 5xx 服务端错误:500(服务端异常)、502(网关错误)、503(服务不可用)。

3. 三层架构核心

面试题标准答案
为什么要使用三层架构?不分层的问题?分层目的:① 解耦(各层职责单一,修改一层不影响其他层);② 复用性(Service/Mapper 可被多个 Controller 复用);③ 可维护性(问题定位精准,比如 Controller 报错是请求处理问题,Service 报错是业务逻辑问题);④ 扩展性(比如替换持久层框架,只需改 Mapper 层)。不分层问题:代码耦合高、复用性差、难以维护、问题定位困难。
三层架构中,各层的职责是什么?① 表现层(Controller):接收前端 HTTP 请求,参数校验,调用 Service,返回响应(JSON / 视图);② 业务层(Service):处理核心业务逻辑(比如权限校验、数据校验、多表关联逻辑),调用 Mapper;③ 持久层(Mapper):仅负责数据库 CRUD 操作,不包含业务逻辑。
三层架构的扩展(四层):为什么加 DTO/VO?① DTO(数据传输对象):服务间 / 前后端传输数据,屏蔽实体类敏感字段(比如 User 实体的 password);② VO(视图对象):前端展示专用,按需封装字段(比如 UserVO 包含 username/age,不含 password);目的:解耦实体类与传输 / 展示层,避免敏感字段泄露,减少数据传输量。

4. IOC/DI 核心

面试题标准答案
什么是 IOC?Spring IOC 容器的实现原理?IOC(控制反转):将对象的创建权从程序员手动 new,转移给 Spring 容器管理,降低代码耦合。实现原理:① 扫描指定包下的注解(@Component/@Service/@Controller 等);② 通过反射创建 Bean 实例;③ 将 Bean 存入容器(Map 结构);④ 当其他 Bean 依赖时,从容器中获取并注入。
DI 的三种注入方式,各自的优缺点?① 字段注入:优点 - 代码简洁;缺点 - 无法注入 final 字段、不利于单元测试、可能出现空指针(依赖未注入),不推荐生产使用;② Setter 注入:优点 - 支持可选依赖、代码易读;缺点 - 无法注入 final 字段、依赖可被二次修改;③ 构造器注入:优点 - 强制依赖(必须传参)、支持 final 字段、利于单元测试、符合面向对象设计;缺点 - 代码稍繁琐(多依赖时),最推荐生产使用。
Spring Bean 的作用域有哪些?默认是什么?① singleton(单例):默认,容器中只有一个 Bean 实例,全局共享;② prototype(原型):每次获取 Bean 都创建新实例;③ request:每次 HTTP 请求创建新实例,仅 Web 环境有效;④ session:每个 Session 创建新实例,仅 Web 环境有效;⑤ application:整个 Web 应用一个实例,仅 Web 环境有效。