1了解使用注解扫描注册Java Web三大组件,能够简述使用注解扫描注册Java Web三大组件的步骤
2掌握自定义Spring MVC配置,能够自定义配置Spring MVC中的静态资源映射、视图控制器、拦截器
3掌握自定义Spring MVC配置,能够自定义配置Spring MVC中的静态资源映射、视图控制器、拦截器
4掌握文件上传,能够在Spring Boot项目中实现文件上传
5掌握Spring Boot自定义异常处理,能够在Spring Boot项目中自定义异常处理
Spring Boot 注册 Servlet / Filter / Listener 三大组件详解
在 Spring Boot (底层基于 Servlet 容器:Tomcat、Jetty 等)中,Servlet、Filter、Listener 是 Java Web 原生的三大核心组件,Spring Boot 对其做了自动化配置简化,我们先搞懂每个组件的核心作用,再讲 Spring Boot 中如何注册使用。
一、三大组件核心作用(通俗 + 专业版)
1. Servlet ------ 请求处理器(核心)
专业定义 :处理客户端请求,生成响应结果的核心组件,是 Web 请求的「真正执行者」。通俗理解 :浏览器 / 客户端发送请求 → Servlet 接收请求 → 执行业务逻辑(查库、计算)→ 返回响应(页面 / JSON 数据)。
核心职责:
- 接收
HttpServletRequest请求 - 处理业务逻辑
- 封装
HttpServletResponse响应 - 是 Spring MVC
DispatcherServlet的底层基础
2. Filter ------ 过滤器(请求拦截器)
专业定义 :对请求和响应进行拦截预处理 / 后处理 ,基于链式调用,不主动生成响应。通俗理解 :请求到达 Servlet 之前 → Filter 先拦截(做校验、过滤、增强)→ 放行后才到 Servlet;响应返回客户端之前 → Filter 还能再次拦截处理。
核心职责:
- 统一编码设置(UTF-8)
- 请求权限校验(登录验证)
- 敏感词过滤
- 请求参数加密 / 解密
- 日志记录、性能监控
特点:双向拦截(请求进、响应出),可拦截所有 Web 资源。
3. Listener ------ 监听器(事件监听者)
专业定义 :监听 Web 应用中域对象的创建、销毁、属性变更 等事件,自动触发回调。通俗理解 :Web 容器发生特定事件(如服务启动、会话创建)→ Listener 自动感知并执行代码,无需手动调用。
核心职责:
- 监听应用启动 / 关闭(项目初始化加载数据)
- 监听用户会话(Session)创建 / 销毁(统计在线人数)
- 监听请求域属性变更
- 系统初始化、资源释放、全局日志埋点
二、三者关系(一句话总结)
- Listener 监听容器生命周期(出生 / 死亡)
- Filter 拦截请求,做前置 / 后置处理
- Servlet 最终处理请求,生成响应
执行顺序:Web 应用启动(Listener 触发) → 请求到达 → Filter 拦截 → Servlet 处理 → Filter 后置处理 → 响应返回
三、Spring Boot 中注册三大组件(两种方式)
Spring Boot 没有 web.xml,推荐两种注册方式:
方式 1:注解版(最简单,推荐)
直接在组件类上加注解,启动类开启扫描即可。
1. 注册 Servlet
java
运行
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
// 注解声明 Servlet,绑定访问路径
@WebServlet(urlPatterns = "/myServlet")
public class MyServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) {
// 处理请求
}
}
2. 注册 Filter
java
运行
import javax.servlet.annotation.WebFilter;
import javax.servlet.*;
import java.io.IOException;
// 拦截所有请求
@WebFilter(urlPatterns = "/*")
public class MyFilter implements Filter {
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
throws IOException, ServletException {
// 1. 请求预处理
chain.doFilter(request, response); // 放行
// 2. 响应后处理
}
}
3. 注册 Listener
java
运行
import javax.servlet.ServletContextEvent;
import javax.servlet.annotation.WebListener;
import javax.servlet.ServletContextListener;
// 监听应用启动/关闭
@WebListener
public class MyListener implements ServletContextListener {
@Override
public void contextInitialized(ServletContextEvent sce) {
// 项目启动时执行(初始化资源)
}
@Override
public void contextDestroyed(ServletContextEvent sce) {
// 项目关闭时执行(释放资源)
}
}
最后:启动类开启组件扫描
java
运行
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.web.servlet.ServletComponentScan;
@SpringBootApplication
@ServletComponentScan // 扫描 @WebServlet/@WebFilter/@WebListener 注解
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
方式 2:配置类注册(无注解,灵活控制)
创建配置类,手动注册 Bean,适用于第三方组件无法修改源码的场景。
java
运行
import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.boot.web.servlet.ServletListenerRegistrationBean;
import org.springframework.boot.web.servlet.ServletRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class WebComponentConfig {
// 1. 注册 Servlet
@Bean
public ServletRegistrationBean<MyServlet> myServlet() {
ServletRegistrationBean<MyServlet> bean = new ServletRegistrationBean<>();
bean.setServlet(new MyServlet());
bean.addUrlMappings("/myServlet");
return bean;
}
// 2. 注册 Filter
@Bean
public FilterRegistrationBean<MyFilter> myFilter() {
FilterRegistrationBean<MyFilter> bean = new FilterRegistrationBean<>();
bean.setFilter(new MyFilter());
bean.addUrlPatterns("/*");
return bean;
}
// 3. 注册 Listener
@Bean
public ServletListenerRegistrationBean<MyListener> myListener() {
ServletListenerRegistrationBean<MyListener> bean = new ServletListenerRegistrationBean<>();
bean.setListener(new MyListener());
return bean;
}
}
四、高频面试题总结
- Servlet 作用:处理请求,生成响应。
- Filter 作用:拦截请求,做统一预处理 / 后处理。
- Listener 作用:监听 Web 事件,自动执行初始化 / 销毁逻辑。
- 执行顺序:Listener 启动 → Filter 拦截 → Servlet 处理。
- Spring Boot 注册 :
@ServletComponentScan+ 原生注解 最简便。
总结
- Servlet:处理请求、生成响应,是 Web 请求的核心处理器
- Filter:拦截请求 / 响应,做统一校验、编码、过滤等增强操作
- Listener:监听容器生命周期,自动执行初始化、资源释放等逻辑
- Spring Boot 中用 @ServletComponentScan 可一键注册三大原生组件
完成 Spring MVC 自定义配置,包含你要的三大功能:
- 静态资源映射(图片、CSS、JS 等)
- 视图控制器(直接页面跳转,不用写 Controller)
- 拦截器(登录校验、日志等)
全程复制粘贴就能用,我会讲清楚每一步做什么。
第一步:创建配置类(核心)
创建一个类,实现 WebMvcConfigurer 接口这是 Spring Boot 推荐的自定义 Spring MVC 配置方式
java
运行
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
/**
* Spring MVC 扩展配置
* 实现 WebMvcConfigurer 即可自定义:静态资源、视图、拦截器、消息转换器等
*/
@Configuration
public class MyMvcConfig implements WebMvcConfigurer {
}
第二步:添加 静态资源映射(最常用)
作用:让 Spring MVC 识别你的图片、JS、CSS、HTML 等静态资源
在配置类里添加方法:
java
运行
@Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
// 1. 访问路径:/images/** 映射到 项目里的:classpath:/images/
registry.addResourceHandler("/images/**")
.addResourceLocations("classpath:/images/");
// 2. 访问路径:/css/** 映射到 classpath:/css/
registry.addResourceHandler("/css/**")
.addResourceLocations("classpath:/css/");
// 3. 访问路径:/js/** 映射到 classpath:/js/
registry.addResourceHandler("/js/**")
.addResourceLocations("classpath:/js/");
// 4. 页面(可选)
registry.addResourceHandler("/pages/**")
.addResourceLocations("classpath:/pages/");
}
作用说明
- 浏览器访问
http://localhost:8080/images/1.jpg - 自动去项目
resources/images/1.jpg找文件
第三步:添加 视图控制器(直接跳转页面)
不用写 Controller,直接让 URL 映射到页面
java
运行
@Override
public void addViewControllers(ViewControllerRegistry registry) {
// 访问 /index → 跳转到 index.html
registry.addViewController("/index").setViewName("index.html");
// 访问 /login → 跳转到 login.html
registry.addViewController("/login").setViewName("login.html");
// 访问 /home → 跳转到 home.html
registry.addViewController("/home").setViewName("home.html");
}
效果
访问:
plaintext
http://localhost:8080/index
直接显示页面,不需要写 Controller!
第四步:添加 拦截器(最关键)
4.1 先创建一个拦截器类
java
运行
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.HandlerInterceptor;
/**
* 自定义拦截器:登录校验、日志、权限等
*/
@Component
public class LoginInterceptor implements HandlerInterceptor {
// 在Controller执行之前执行
@Override
public boolean preHandle(HttpServletRequest request,
HttpServletResponse response,
Object handler) throws Exception {
System.out.println("拦截器生效:" + request.getRequestURI());
// 这里可以写登录校验
// return false 表示拦截
// return true 表示放行
return true;
}
}
4.2 把拦截器注册到 Spring MVC
回到 MyMvcConfig 配置类,添加:
java
运行
@Autowired
private LoginInterceptor loginInterceptor;
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(loginInterceptor)
.addPathPatterns("/**") // 拦截所有请求
.excludePathPatterns( // 放行不拦截
"/login",
"/register",
"/static/**",
"/images/**",
"/css/**",
"/js/**",
"/*.html"
);
}
1. 启动项目
控制台无报错 = 配置成功
2. 测试静态资源
在 resources 下创建
- images
- css
- js
放入 1.jpg访问:
plaintext
http://localhost:8080/images/1.jpg
能显示图片 = 成功
3. 测试视图控制器
访问:
plaintext
http://localhost:8080/index
直接跳转到页面 = 成功
4. 测试拦截器
访问任何接口,控制台打印:
plaintext
拦截器生效:/xxx
= 拦截器成功
实现 Spring Boot 文件上传 ,从代码到测试,全程复制粘贴就能跑通,保证一次成功!
一、先记住:Spring Boot 文件上传超简单
只需要 3 步:
- 写一个 接收文件的接口
- 配置 上传大小限制
- 测试上传
我现在直接带你写完整代码!
第一步:创建文件上传接口(核心代码)
直接新建一个 FileController
java
运行
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;
import java.io.File;
import java.io.IOException;
import java.util.UUID;
@RestController
public class FileController {
// 文件上传保存的目录(自己改路径)
private static final String UPLOAD_DIR = "C:/upload/";
@PostMapping("/upload")
public String upload(@RequestParam("file") MultipartFile file) {
// 1. 判断文件是否为空
if (file.isEmpty()) {
return "上传失败,请选择文件";
}
// 2. 获取文件原始名字
String originalFilename = file.getOriginalFilename();
// 3. 生成唯一文件名(防止重名覆盖)
String suffix = originalFilename.substring(originalFilename.lastIndexOf("."));
String newFileName = UUID.randomUUID() + suffix;
// 4. 创建目标文件
File destFile = new File(UPLOAD_DIR + newFileName);
// 如果目录不存在,自动创建
if (!destFile.getParentFile().exists()) {
destFile.getParentFile().mkdirs();
}
// 5. 上传(把内存文件写到磁盘)
try {
file.transferTo(destFile);
return "上传成功!路径:" + destFile.getAbsolutePath();
} catch (IOException e) {
e.printStackTrace();
return "上传失败:" + e.getMessage();
}
}
}
第二步:配置文件上传大小(application.yml/properties)
推荐用 yml 格式:
yaml
spring:
servlet:
multipart:
max-file-size: 10MB # 单个文件最大 10MB
max-request-size: 100MB # 一次请求总文件最大 100MB
enabled: true # 开启文件上传
如果是 properties 格式:
properties
spring.servlet.multipart.max-file-size=10MB
spring.servlet.multipart.max-request-size=100MB
spring.servlet.multipart.enabled=true
第三步:创建上传目录
在电脑 C 盘 新建一个文件夹
plaintext
C:\upload
确保有写入权限。
第四步:测试上传(最简单)
方法 1:用 Postman 测试
- 打开 Postman
- 请求方式选 POST
- URL 输入:
http://localhost:8080/upload - Body → form-data
- Key 输入:
file - Value 选择一个图片 / 文件
点击发送 → 返回上传成功!
方法 2:用网页表单测试(不用 Postman)
在 resources/static 下新建 upload.html
html
预览
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>文件上传</title>
</head>
<body>
<h1>Spring Boot 文件上传</h1>
<form action="/upload" method="post" enctype="multipart/form-data">
<input type="file" name="file">
<button type="submit">上传</button>
</form>
</body>
</html>
访问:
plaintext
http://localhost:8080/upload.html
选文件 → 上传 → 成功!
你现在已经实现了 ✅
- 单文件上传
- 自动生成唯一文件名
- 自动创建目录
- 文件大小限制
- 简单易用的接口
我可以继续带你升级功能(你想要哪个?)
二、一共 4 步,带你彻底搞定
步骤 1:统一返回结果类(前后端交互必备)
创建一个 Result 类,所有接口成功 / 失败都用它返回。
java
运行
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
@Data
@NoArgsConstructor
@AllArgsConstructor
public class Result<T> {
private int code; // 响应码 200成功 500错误
private String msg; // 提示信息
private T data; // 返回数据
// 成功
public static <T> Result<T> success(T data) {
return new Result<>(200, "操作成功", data);
}
public static <T> Result<T> success() {
return success(null);
}
// 失败
public static <T> Result<T> fail(String msg) {
return new Result<>(500, msg, null);
}
public static <T> Result<T> fail(int code, String msg) {
return new Result<>(code, msg, null);
}
}
步骤 2:自定义业务异常类(主动抛出异常)
专门用来抛业务错误,比如:登录失败、参数错误。
java
运行
import lombok.Getter;
@Getter
public class BusinessException extends RuntimeException {
private final int code;
// 自定义异常信息
public BusinessException(String msg) {
super(msg);
this.code = 500;
}
// 自定义异常码 + 信息
public BusinessException(int code, String msg) {
super(msg);
this.code = code;
}
}
步骤 3:全局异常处理器(最重要!)
用 @RestControllerAdvice 统一捕获所有异常。
java
运行
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;
// 全局异常捕获
@RestControllerAdvice
public class GlobalExceptionHandler {
// 1. 捕获我们自定义的业务异常
@ExceptionHandler(BusinessException.class)
public Result<?> handleBusinessException(BusinessException e) {
return Result.fail(e.getCode(), e.getMessage());
}
// 2. 捕获所有其他异常(系统未知错误)
@ExceptionHandler(Exception.class)
public Result<?> handleException(Exception e) {
e.printStackTrace(); // 打印错误日志
return Result.fail("系统异常,请联系管理员");
}
}
步骤 4:测试异常(Controller 测试)
写一个测试接口,主动抛异常看效果。
java
运行
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class TestController {
@GetMapping("/test")
public Result<String> test() {
// 模拟业务异常(比如:用户名不存在)
throw new BusinessException("用户不存在!");
}
}
三、启动项目测试
访问:
plaintext
http://localhost:8080/test
返回结果(统一 JSON 格式):
json
{
"code": 500,
"msg": "用户不存在!",
"data": null
}
✅ 自定义异常处理成功!
四、扩展:常用异常你都能处理
我给你直接写好,复制就能用:
1. 参数校验异常
java
运行
@ExceptionHandler(MethodArgumentNotValidException.class)
public Result<?> handleValidException(MethodArgumentNotValidException e) {
String msg = e.getBindingResult().getFieldError().getDefaultMessage();
return Result.fail(400, msg);
}
2. 空指针异常
java
运行
@ExceptionHandler(NullPointerException.class)
public Result<?> handleNullPointerException(NullPointerException e) {
return Result.fail(500, "空指针异常");
}
3. 文件上传过大异常
java
运行
@ExceptionHandler(MaxUploadSizeExceededException.class)
public Result<?> handleMaxUploadSizeExceededException(MaxUploadSizeExceededException e) {
return Result.fail(400, "文件大小超出限制!");
}
五、你现在彻底掌握了
你已经学会 Spring Boot 全局异常处理!
接下来你想让我带你做什么?
-
多文件上传
-
上传后返回可访问的图片 URL
-
图片上传 + 预览
-
文件大小、类型校验(只允许图片)
-
上传到阿里云 OSS / 腾讯云 COS
超清晰 带你掌握 Spring Boot 全局自定义异常处理,这是面试必问、项目必用的核心技能,全程复制粘贴就能用!
一、先搞懂:自定义异常处理有什么用?
-
统一项目的错误返回格式(全部返回 JSON,不再返回杂乱页面)
-
捕获所有 Controller 的异常,不用每个方法写
try-catch -
自定义业务异常(比如:用户名不存在、密码错误、未登录)
-
让项目更优雅、更好维护
-
统一返回结果 ✅
-
整合 MyBatis Plus
-
做 登录拦截 + Token
-
做 完整后台管理系统
-
学习 AOP 面向切面编程
- 自定义业务异常 ✅
- 全局异常捕获 ✅
- 各种系统异常处理 ✅