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. DispatcherServletHandlerMapping:谁处理这个 URL?
  3. HandlerMapping 返回一个 HandlerExecutionChain(包含 Controller 方法 + 一堆拦截器)。
  4. DispatcherServletHandlerAdapter:谁能执行这个 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,但你想转成 DateLocalDate 或自定义类型。

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", "服务器内部错误");
    }
}
相关推荐
@SmartSi1 小时前
AgentScope Java 入门系列:Spring AI Alibaba 与 AgentScope 的定位与区别
java·spring·agentscope
Jul1en_1 小时前
【SpringCloud】OpenFeign 与 Gateway 讲解与部署
spring·spring cloud·gateway
她说可以呀2 小时前
JWT令牌检验用户是否登录
java·spring boot·spring·java-ee·maven
庞轩px2 小时前
第三篇:SpringMVC——一个HTTP请求在Spring中经历了什么?
网络协议·spring·http·springmvc·handlermapping·前端控制器
前端不太难3 小时前
鸿蒙 App 的 Task 架构设计
华为·状态模式·harmonyos
空中海10 小时前
02 ArkTS 语言与工程规范
java·前端·spring
亚历克斯神10 小时前
Java 25 模式匹配增强:让代码更简洁优雅
java·spring·微服务
云烟成雨TD13 小时前
Spring AI Alibaba 1.x 系列【49】状态图运行时引擎:CompiledGraph 源码解析
java·人工智能·spring
Tutankaaa13 小时前
从10队到50队:知识竞赛软件的高并发场景如何设计?
java·经验分享·后端·spring