Spring MVC 的核心知识点梳理

MVC 是什么

MVC 不是 Spring 发明的,而是一种设计模式,目的是"解耦"。

  • M(Model,模型) :数据 + 业务逻辑。比如 Teacher 类,TeacherService。
  • V(View,视图):展示数据的界面。比如 JSP、Thymeleaf 模板,或者是现代返回 JSON 的前端页面。
  • C(Controller,控制器):接收用户请求,调用 Model,最后选择 View 来展示。

流程:用户点击一个链接 → Controller 拿到请求 → 调 Service 拿到数据(Model)→ 把数据交给 View 渲染 → 返回 HTML 给浏览器。

Spring MVC 就是把这个流程在 Java Web 环境里落地的一套框架。

核心组件与处理流程

Spring MVC 最核心的就是一个 前端控制器(Front Controller) ------DispatcherServlet。

组件 作用 常见实现
DispatcherServlet 统一入口,调度一切 Spring 提供,我们只需配置
HandlerMapping 根据请求 URL 找到对应的处理器 RequestMappingHandlerMapping
HandlerAdapter 执行找到的处理器(Controller 方法) RequestMappingHandlerAdapter
HandlerInterceptor 拦截器,在处理方法前后做增强 自定义
ViewResolver 根据视图名找到真正的视图文件 InternalResourceViewResolver (JSP)
HandlerExceptionResolver 处理异常 ExceptionHandlerExceptionResolver

一个请求的完整生命周期(回顾前面讲过的流程图):

  1. 请求到达 DispatcherServlet。
  2. DispatcherServlet 找 HandlerMapping:谁处理这个 URL?
  3. HandlerMapping 返回一个 HandlerExecutionChain(包含 Controller 方法 + 一堆拦截器)。
  4. DispatcherServlet 找 HandlerAdapter:谁能执行这个 Controller 方法?
  5. HandlerAdapter 执行具体方法(期间会做参数绑定、类型转换、校验等)。
  6. 方法返回 ModelAndView(或 @ResponseBody 直接返回数据)。
  7. 若有视图名,ViewResolver 解析出真正的 JSP 等视图。
  8. 渲染视图,响应给浏览器。

Controller 与注解:从入门到精通

@Controller & @RestController

java 复制代码
@Controller  // 声明这是一个控制器类,方法通常返回视图名
public class TeacherController { ... }

@RestController  // = @Controller + @ResponseBody,所有方法默认返回 JSON
public class TeacherRestController { ... }

@RequestMapping 及衍生注解

java 复制代码
@RequestMapping("/teacher")   // 类级别映射
public class TeacherController {

    @RequestMapping(value = "/list", method = RequestMethod.GET)
    public String list() { ... }  // 等价于 @GetMapping("/list")
}

@GetMapping、@PostMapping、@PutMapping、@DeleteMapping 等都是 @RequestMapping 的快捷方式。

参数绑定注解(重点对比)

注解 从哪里拿数据 示例
@RequestParam URL 问号后的参数或表单数据 ?name=Tom → @RequestParam("name") String name
@PathVariable URI 路径中的占位符 /teacher/{id} → @PathVariable("id") Long id
@RequestBody 请求体中的 JSON/XML POST 的 JSON {"name":"Tom"} 自动转成 Teacher 对象
@ModelAttribute ① 从 Model 中取;② 把参数绑定到对象 常用于表单提交自动封装对象,
@RequestHeader 请求头 @RequestHeader("User-Agent") String ua
@CookieValue Cookie @CookieValue("JSESSIONID") String sid

把参数自动封装成对象

Spring 可以直接将表单字段或 JSON 映射成一个 Java Bean。

表单提交示例:

jsp 复制代码
<form action="/teacher/save" method="post">
    <input name="name"/>     <!-- Teacher.name -->
    <input name="age"/>      <!-- Teacher.age -->
    <input type="submit"/>
</form>
java 复制代码
@PostMapping("/teacher/save")
public String save(@ModelAttribute Teacher teacher) {
    // teacher 对象已被自动填充 name 和 age
    teacherService.save(teacher);
    return "redirect:/teacher/list";
}

底层原理:DataBinder + BeanWrapper 负责属性拷贝。

自定义类型转换器:String → Date

很多时候,请求参数是 String,但你想转成 Date、LocalDate 或自定义类型。

Spring 内置的转换器和格式化器

  • Converter<S, T> :源类型 → 目标类型,如 StringToDateConverter。
  • Formatter :专为字符串和对象互转设计,支持国际化,适合 String <-> Date。

自定义一个 String → Date 的 Converter 示例

java 复制代码
@Component
public class StringToDateConverter implements Converter<String, Date> {
    private final SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd");

    @Override
    public Date convert(String source) {
        try {
            return format.parse(source);
        } catch (ParseException e) {
            throw new IllegalArgumentException("日期格式必须为 yyyy-MM-dd");
        }
    }
}

在 Spring Boot 中,只需让它被容器管理(@Component)就会自动注册到转换器链。

在传统 Spring MVC XML 中,需要配置 FormattingConversionServiceFactoryBean。

使用场景

java 复制代码
@GetMapping("/teacher/search")
public String searchByDate(@RequestParam("date") Date date) {
    // /teacher/search?date=2025-01-01 → date 直接转换好
}

如果转换失败,会抛出 TypeMismatchException,我们可以用异常处理来统一返回友好信息。

拦截器(Interceptor)和过滤器(Filter)

两者都可以在请求前后做手脚,但层级不同。

对比维度 Filter(过滤器) Interceptor(拦截器)
归属 Servlet 规范,Java EE Spring MVC 框架
作用范围 能拦截所有进入 Servlet 的请求(包括静态资源) 只能拦截进到 Spring MVC 的请求(DispatcherServlet 处理)
是否能用 Spring Bean 不能直接注入(可以迂回) 可以正常注入其他 Bean
执行顺序 先经过 Filter,再进 DispatcherServlet 在 DispatcherServlet 之后,Controller 方法之前
典型场景 字符编码、跨域、权限安全检查 登录检查、日志记录、性能监控、用户权限补充

定义拦截器示例

java 复制代码
@Component
public class LoginInterceptor implements HandlerInterceptor {
    @Override
    public boolean preHandle(HttpServletRequest request, 
                             HttpServletResponse response, 
                             Object handler) {
        // 检查 session 中是否有用户
        if (request.getSession().getAttribute("user") == null) {
            response.sendRedirect("/login");
            return false;  // 不放行
        }
        return true;
    }
}

注册拦截器

java 复制代码
@Configuration
public class WebConfig implements WebMvcConfigurer {
    @Autowired
    private LoginInterceptor loginInterceptor;

    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(loginInterceptor)
                .addPathPatterns("/teacher/**")   // 要拦截的
                .excludePathPatterns("/teacher/login"); // 排除的
    }
}

异常处理:优雅地给前端报错

还记得我们之前聊过的"异常和错误"吗?常用的处理方式是:

局部异常处理

java 复制代码
@Controller
public class TeacherController {
    @ExceptionHandler(TeacherNotFoundException.class)
    public String handleNotFound(TeacherNotFoundException ex, Model model) {
        model.addAttribute("msg", ex.getMessage());
        return "error/404";   // 返回错误视图
    }
}

全局异常处理(推荐)

java 复制代码
@ControllerAdvice
public class GlobalExceptionHandler {

    @ExceptionHandler(MethodArgumentNotValidException.class)
    @ResponseStatus(HttpStatus.BAD_REQUEST)
    @ResponseBody
    public Map<String, String> handleValidation(MethodArgumentNotValidException ex) {
        // 返回校验失败信息,如 {"name":"不能为空"}
        ...
    }

    @ExceptionHandler(Exception.class)
    @ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
    @ResponseBody
    public Map<String, String> handleGeneral(Exception ex) {
        return Map.of("error", "服务器内部错误");
    }
}
相关推荐
Wx-bishekaifayuan6 分钟前
springboot房屋租赁系统11574-计算机课程设计、毕业设计
java·vue.js·spring boot·后端·sql·spring·课程设计
OxYGC14 小时前
[AI工程] Spring AI 第廿一篇:存量 REST 接口的 MCP 化改造实录——工具从哪条路径注册、参数描述怎么写、身份怎么过去
java·人工智能·spring
卓怡学长15 小时前
w198基于springboot始于足下健康打卡平台的设计与实现
java·spring boot·spring·intellij-idea
自强的小白19 小时前
Spring事务失效的场景
java·spring
换元不配限20 小时前
Android 架构演进实战:MVC → MVP → MVVM → MVI
android·架构·mvc·mvvm·mvp·mvi
幽络源小助理21 小时前
WordPress REST API 深度实战:从自定义端点到 Headless CMS 架构全拆解
架构·状态模式
dadaobusi1 天前
Trace-driven 建模(基于轨迹/踪迹的建模)
java·后端·spring
南归北隐1 天前
Spring AI Alibaba Graph框架实现Tools工具调用
java·后端·spring·spring ai·spring ai tools
步行cgn1 天前
Spring 注解使用详解
java·spring
一条小小yu1 天前
Spring IoC的理解
java·后端·spring