2026.07.23 — ARCHIVE — 4 MIN

Java Web 后端开发知识总结

把 Spring Boot 后端开发涉及的核心技术串在一起,从请求进入 Filter 到数据返回浏览器,每一层做了什么。


Java Web 后端开发知识总结

做后端开发这段时间,接触的技术点挺多的。

Spring MVC、Spring Boot、MyBatis、JWT、ThreadLocal……一个个学的时候感觉都懂了,但真正写项目的时候又经常忘。

现在回过头把整个后端开发的知识体系梳理一遍,算是给自己做个总结,也方便以后查。


一个请求从哪来到哪去

先说最核心的东西:一个 HTTP 请求从浏览器发出,到我返回响应,中间经过了哪些层。

浏览器 → Filter → Interceptor → Controller → Service → Mapper → MySQL
浏览器 ← Filter ← Interceptor ← Controller ← Service ← Mapper ← MySQL

每一层都有明确的职责,不能乱。

Filter 是 Servlet 规范的,所有请求都会经过它,适合做全局的预处理,比如解析 Token、设置编码。

Interceptor 是 Spring MVC 的,粒度更细,可以针对特定路径拦截,适合做登录校验、权限检查。

Controller 负责接收请求、解析参数、调用 Service、返回响应。

Service 是业务逻辑的核心,事务管理也在这里。

Mapper 负责和数据库打交道,执行 SQL。

把它们分开的好处是,改一层的代码不会影响其他层,维护起来方便很多。


Filter 和 Interceptor 的区别

这两个东西长得有点像,经常有人搞混。

Filter 是 JavaWeb 规范里的东西,不依赖 Spring,所有请求都经过它。可以在 Servlet 之前修改请求,在 Servlet 之后修改响应。

Interceptor 是 Spring MVC 提供的,只在 Controller 前后执行,不能修改请求和响应本身,只能决定放不放过这个请求。

常见的用法:

Filter 负责解析 Token,把用户信息存入 ThreadLocal。

Interceptor 负责校验 ThreadLocal 里有没有用户信息,没有就返回 401。

这样分工明确,Filter 做通用处理,Interceptor 做业务相关的校验。


Controller 层:接收请求返回响应

Controller 层做的事情比较直接:拿到请求参数,调 Service,包装响应。

@RestController
@RequestMapping("/emps")
public class EmpController {

    @Autowired
    private EmpService empService;

    @GetMapping
    public Result page(@RequestParam(defaultValue = "1") Integer page,
                       @RequestParam(defaultValue = "10") Integer pageSize) {
        return Result.success(empService.page(page, pageSize));
    }

    @PostMapping
    public Result save(@RequestBody Emp emp) {
        empService.save(emp);
        return Result.success();
    }

    @DeleteMapping("/{id}")
    public Result delete(@PathVariable Integer id) {
        empService.delete(id);
        return Result.success();
    }
}

常用的注解:

  • @RestController = @Controller + @ResponseBody,直接返回 JSON
  • @RequestMapping 映射请求路径
  • @GetMapping@PostMapping 指定请求方式
  • @RequestParam 获取查询参数
  • @RequestBody 获取请求体(JSON 转对象)
  • @PathVariable 获取 URL 路径参数

Service 层:业务逻辑 + 事务

Service 层是业务逻辑的核心,通常会有对应的 Impl 实现类。

@Service
public class EmpServiceImpl implements EmpService {

    @Autowired
    private EmpMapper empMapper;

    @Override
    @Transactional
    public void deleteEmpAndDept(Integer empId) {
        empMapper.deleteById(empId);
        // 删完员工再删部门,如果第二步失败,第一步回滚
        deptMapper.deleteById(...);
    }
}

@Transactional 标记事务,保证一组操作要么全成功要么全失败。

有几个坑要注意:

方法不是 public 的,事务不生效。同类内部调用绕过代理,事务也不生效。异常被 catch 了没重新抛出,事务也会提交而不是回滚。


IOC 和 DI:Spring 的核心思想

刚开始学 Spring 的时候,对 IOC 和 DI 这两个概念一直有点模糊。

后来想明白了,其实就一件事:把对象的创建权从程序员手里交出来,交给 Spring 容器。

以前要自己 new 对象:

UserService userService = new UserServiceImpl();

现在只需要声明依赖,Spring 会自动注入:

@Autowired
private UserService userService;

IOC 是思想,DI 是实现。

  • IOC(控制反转):对象的创建和管理权交给容器
  • DI(依赖注入):容器自动把依赖的对象注入进来

注入方式有三种,字段注入最常用,构造器注入最推荐(便于测试)。


AOP:横切关注点的分离

AOP 解决的问题是:有些功能不是核心业务,但每个地方都需要。

比如日志记录、权限校验、性能监控。

如果没有 AOP,这些逻辑要写在每个方法里,代码到处都是重复的。

有了 AOP,可以把这些公共逻辑抽成一个切面,自动织入到目标方法前后。

@Aspect
@Component
public class LogAspect {

    @Around("execution(* com.myapp.service..*(..))")
    public Object log(ProceedingJoinPoint joinPoint) throws Throwable {
        long start = System.currentTimeMillis();
        Object result = joinPoint.proceed();
        long cost = System.currentTimeMillis() - start;
        System.out.println(joinPoint.getSignature().getName() + " 耗时 " + cost + "ms");
        return result;
    }
}

切入点表达式决定拦截哪些方法,通知类型决定在什么时候执行增强逻辑。


MyBatis:数据库访问

MyBatis 是持久层框架,负责把 Java 对象和数据库表映射起来。

可以用注解写 SQL,也可以用 XML 写,两种方式都行,看个人习惯。

注解方式简单直接:

@Mapper
public interface EmpMapper {
    @Select("SELECT * FROM emp WHERE id = #{id}")
    Emp findById(Integer id);

    @Insert("INSERT INTO emp(name, phone) VALUES(#{name}, #{phone})")
    void insert(Emp emp);
}

XML 方式更适合复杂的 SQL,尤其是动态 SQL:

<select id="selectByCondition" resultType="Emp">
    SELECT * FROM emp
    <where>
        <if test="name != null and name != ''">
            AND name LIKE CONCAT('%', #{name}, '%')
        </if>
        <if test="gender != null">
            AND gender = #{gender}
        </if>
    </where>
</select>

<if><where><foreach> 这些标签让动态 SQL 写起来很方便。


认证与授权:JWT + ThreadLocal

登录认证是 Web 项目的标配。

传统方案是 Session,服务器存会话数据,客户端存 Session ID。

现在前后端分离的项目,一般用 JWT(JSON Web Token),无状态认证。

流程是这样的:

用户登录,后端验证账号密码,生成 JWT 返回给前端。前端把 Token 存在 localStorage 里,后续请求在请求头带上 Token。后端用 Filter 解析 Token,把用户信息存入 ThreadLocal,后续的 Service 层可以直接从 ThreadLocal 取当前用户。

// Token 解析
String token = request.getHeader("token");
Claims claims = JwtUtils.parseToken(token);
Integer userId = claims.get("userId", Integer.class);

// 存入 ThreadLocal
UserContext.set(userId);
// Service 层直接取
Integer userId = UserContext.get();

ThreadLocal 的本质是每个线程有自己的专属变量,请求开始时存入,请求结束时清理。

记得清理,不然线程池复用线程的时候,上一个请求的数据可能会影响下一个请求。


全局异常处理

项目里难免会抛异常,不可能每个方法都 try-catch。

@RestControllerAdvice 可以统一处理所有 Controller 抛出的异常。

@RestControllerAdvice
public class GlobalExceptionHandler {

    @ExceptionHandler(BusinessException.class)
    public Result handleBusinessException(BusinessException e) {
        log.error("业务异常:", e);
        return Result.error(e.getMessage());
    }

    @ExceptionHandler(Exception.class)
    public Result handleException(Exception e) {
        log.error("未知异常:", e);
        return Result.error("系统繁忙,请稍后再试");
    }
}

这样不管哪个 Controller 出错,都能返回统一的错误格式。


Spring Boot:整合一切的底座

Spring Boot 本身不是一堆新技术,它是把 Spring framework、Spring MVC、MyBatis 这些框架整合到一起的工具。

两大核心特性:

起步依赖:一个 starter 引入一组相关依赖,版本都是官方测过的,不用自己管版本冲突。

自动配置:根据引入的依赖自动配置 Bean,引入 MyBatis 的 starter 就自动配好 SqlSessionFactory,不用手动写配置类。

启动类上的 @SpringBootApplication 包含三个注解:

  • @SpringBootConfiguration:声明这是一个配置类
  • @ComponentScan:扫描启动类所在包及其子包
  • @EnableAutoConfiguration:开启自动配置

知识体系全景

把以上所有内容串在一起,后端开发的知识体系大概是这样:

┌─────────────────────────────────────────────┐
│                 Spring Boot                  │
│         (起步依赖 + 自动配置,整合一切)      │
├──────────┬──────────────┬───────────────────┤
│  SpringMVC │  Spring Core │     MyBatis       │
│            │              │                   │
│  接收请求   │  IOC/DI      │  Mapper 接口      │
│  响应数据   │  AOP         │  动态 SQL        │
│  拦截器     │  事务管理     │  结果映射        │
│  全局异常   │              │                   │
├────────────┴──────────────┴───────────────────┤
│              JavaWeb 基础                      │
│         Filter、Cookie、Session                │
├────────────────────────────────────────────────┤
│              解决方案                           │
│      JWT(认证)、ThreadLocal(上下文)          │
└────────────────────────────────────────────────┘

小结

后端开发的核心就几件事:

  • 接收请求(Controller)
  • 处理业务(Service)
  • 操作数据库(Mapper)
  • 统一管理(Spring Boot)

理解了分层架构和各层职责,再结合 IOC/AOP/事务这些概念,整个后端开发的知识体系就清晰了。

学习过程就是不断踩坑、不断补基础的过程。前面觉得简单的东西,写到后面会发现坑还挺多。但每次解决一个问题,理解就会深一层。

End of plate