SpringMVC的核心架构与请求处理流程

Spring MVC 核心架构


核心组件

组件作用类比
DispatcherServlet前端控制器,统一接收请求并协调各组件处理一个餐厅的前台
HandlerMapping根据请求URL映射到对应的处理器(Controller)路由表
HandlerAdapter执行处理器方法,处理参数绑定、方法调用等适配器(兼容不同处理器)
ViewResolver将逻辑视图名解析为物理视图(如JSP、Thymeleaf)地图导航
View渲染模型数据生成最终响应(HTML/JSON等)厨师(加工数据)
HandlerExceptionResolver统一处理控制器抛出的异常故障应急小组

分层架构

客户端 => DispatcherServlet => HandlerMapping

=> Controller => ModelAndView => View => 响应

相当于

客户端 => 前端控制器 => 处理器映射器 => 处理器 =>模型与视图容器 => 响应器 =>响应

请求处理的流程

  1. 请求到达:客户端发送http请求到前端控制器DispatcherServelt
  2. 查找处理器:前端控制器DispatcherServlet调用HandlerMapping确定目标控制器Controller
  3. 获取适配器:通过处理器适配器HandlerAdapter执行控制器方法
  4. 拦截器预处理:执行拦截器链的preHandle()
  5. 参数绑定:适配器解析请求参数(路径变量、表单数据等),传递给控制器方法
  6. 执行控制器:调用控制器Controller方法执行业务逻辑
  7. 返回模型与视图:控制器Controller返回ModelAndView(或String视图名、@ResponseBody等)
  8. 拦截器后处理:执行拦截器链后的postHandle()
  9. 视图解析:视图解析器ViewResolver将逻辑视图名转换为具体View对象
  10. 视图渲染:响应器View渲染模型数据产生响应内容(HTML/JSON)
  11. 拦截器完成:执行拦截器链的afterCompletion()

关键环节:HTTP请求 → Java对象

当请求到达控制器方法前,Spring MVC会自动提取请求中的各种数据

@RequestParam:获取URL查询字符串参数

// 请求:/search?keyword=spring
@GetMapping("/search")
public String search(@RequestParam("keyword") String keyword) {// keyword = "spring"
}

@PathVariable:获取URL路径中的变量

// 请求:/users/123/profile
@GetMapping("/users/{userId}/profile")
public String profile(@PathVariable("userId") Long id) {// id = 123
}

@RequestBody:将JSON/XML请求体转换为Java对象

// 请求体:{"name":"John","age":30}
@PostMapping("/users")
public User createUser(@RequestBody User user) {// user.getName() = "John"// user.getAge() = 30
}

表单绑定:自动将表单字段映射到对象属性

// 表单字段:username=admin&password=123
@PostMapping("/login")
public String login(UserForm form) {// form.getUsername() = "admin"
}

配置视图解析器的流程

(假如控制器返回一个字符串“success”)

控制器返回字符串 => return ‘success’=> 视图解析器=> 检查配置

=> 前缀+字符串success+后缀=> 合成地址/WEB-INF/views/success.jsp=> 范文实际视图文件

应用配置的前缀和后缀

resolver.setPrefix("/WEB-INF/views/"); // 视图文件目录
resolver.setSuffix(".jsp");            // 文件扩展名

配置文件示例:

@Configuration
public class WebConfig {@Beanpublic ViewResolver viewResolver() {InternalResourceViewResolver resolver = new InternalResourceViewResolver();resolver.setPrefix("/WEB-INF/views/"); // 视图存放目录resolver.setSuffix(".jsp");            // 文件扩展名return resolver;}
}

异常的分层处理

方法级处理(优先级最高)

@Controller
public class UserController {@ExceptionHandler(UserNotFoundException.class)public ResponseEntity<String> handleUserNotFound() {return ResponseEntity.status(404).body("用户不存在");}
}

控制器级处理

@Controller
@ExceptionHandler({IllegalArgumentException.class, DataAccessException.class})
public ResponseEntity<String> handleControllerExceptions() {// 处理本控制器所有指定异常
}

全局处理(最常用)

@ControllerAdvice // 作用于所有控制器
public class GlobalExceptionHandler {// 处理特定异常@ExceptionHandler(ResourceNotFoundException.class)public ResponseEntity<ErrorResponse> handleResourceNotFound(ResourceNotFoundException ex) {ErrorResponse error = new ErrorResponse("NOT_FOUND",ex.getMessage(),System.currentTimeMillis());return new ResponseEntity<>(error, HttpStatus.NOT_FOUND);}// 兜底处理所有未捕获异常@ExceptionHandler(Exception.class)public ResponseEntity<ErrorResponse> handleAllExceptions(Exception ex) {// 返回通用错误响应}
}

关于用户访问个人资料页面的示例

请求GET /users/123/profile

参数绑定:提取路径变量 userId=123

控制器方法处理:

@GetMapping("/users/{userId}/profile")
public String userProfile(@PathVariable Long userId, Model model) {User user = userService.findById(userId); // 可能抛出异常model.addAttribute("user", user);return "user/profile"; // 逻辑视图名
}

处理异常:若用户不存在,抛出UserNotFoundException

视图解析:将"user/profile"转换为/WEB-INF/views/user/profile.jsp

渲染页面并返回响应

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若转载,请注明出处:http://www.pswp.cn/news/916992.shtml
繁体地址,请注明出处:http://hk.pswp.cn/news/916992.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

css 不错的按钮动画

效果图wxml <view class"{{status?active:}}"><view class"up-top btn"><text>向上</text></view><view class"up-left btn"><text>向左</text></view><view class"up-center b…

若依框架RuoYi-Vue-Plus-5.X的启动,本地安装docker,再部署 Redis、PG数据库(智慧水务)SmartWaterServer

一、部署redis数据库拉取镜像 docker pull redis启动Redis容器docker run -d --name redis-server -p 6379:6379 -v redis-data:/data redis redis-server --requirepass 123redis版本二、部署PostgreSQL 数据库拉取镜像docker pull postgres:15 创建数据存储目录、建议将数据挂…

Idea 清除无用的引用类

在IntelliJ IDEA中&#xff0c;你可以通过以下方式将选中的代码设置为大写&#xff1a;1. 使用快捷键(推荐)Windows/Linux&#xff1a;Ctrl Shift UMac&#xff1a;Cmd Shift U操作步骤&#xff1a;选中文本按下快捷键&#xff0c;即可在大小写之间切换。2. 通过菜单操作选…

同个主机拉取不同权限仓库的方法

背景&#xff1a;因为某些神奇的原因&#xff0c;无法同时授权仓库权限给自己。 1.本地电脑只有权限访问web仓库地址&#xff0c;无权限访问backend仓库&#xff1b; 2.堡垒机服务器只有权限访问backend仓库&#xff0c;无权限访问web仓库地址。 web仓库地址 &#xff1a;codeu…

快速搭建Node.js服务指南

Node.js是构建高效、可扩展网络应用的理想选择。以下是几种快速搭建Node.js服务的方法。 方法一&#xff1a;使用Express&#xff08;最流行框架&#xff09; 1. 初始化项目 mkdir my-node-service cd my-node-service npm init -y2. 安装Express npm install express3. 基础服…

通义千问Qwen3-30B-A3B-Thinking-2507技术解析:推理模型的工程实践突破

Qwen3-30B-A3B模型架构图2025年7月30日&#xff0c;阿里云通义千问团队发布了Qwen3-30B-A3B-Thinking-2507推理模型&#xff0c;这是继Qwen3-30B-A3B-Instruct-2507后的又一力作。作为专注于推理任务的专用模型&#xff0c;它在数学能力测试AIME25上取得85.0分&#xff0c;超越…

【源力觉醒 创作者计划】文心一言与deepseek集成springboot开发哪个更方便

一.实验背景 当前文心一言和deepseek都开源了&#xff0c;二者都可以作为大模型应用开发的模型基础了&#xff0c;我们都可以编写springboot项目来集成deepseek和文心一言了 二.实验目标 本文基于实际操作&#xff0c;通过实际操作来对比文心一言和deepseek在集成到springbo…

核磁共振数据T2几何均值计算

1、T₂ 几何均值公式如下&#xff1a;2、核磁T2几何均值计算代码 CSV 文件文件格式&#xff1a; 每一行是一个样点&#xff08;样品深度&#xff09;&#xff0c;列为&#xff1a;第一列是“深度”或其他&#xff1b;第二列及以后&#xff08;如 TASPEC0 ~ TASPEC199&#xff0…

微服务架构技巧篇——接口类设计技巧

目录 一、微服务架构的特点 二、微服务接口类设计技巧 2.1、BFF(Backend For Frontend) 2.1.1、 服务分布式带来的第一个挑战导致的几个典型问题 2.1.2、什么是 BFF 2.1.3、BFF 应用场景 2.1.4、BFF 落地经验 2.1.4.1、前端负责 BFF 开发优缺点 2.1.4.2、后端负责 BFF 开发优…

C++游戏开发(2)

直接上代码 1.首先是头文件编写 #include <iostream> #include <graphics.h> #include <string> 2,添加画布 长1280&#xff0c;宽720 initgraph(1280, 720); 3.添加主循环 bool running true; while(runing) { } 4.定义结构体变量msg ExMessge msg; 5.开…

Unity开发2D类银河恶魔城游戏学习笔记目录

Unity开发2D类银河恶魔城游戏学习笔记 Unity教程&#xff08;零&#xff09;Unity和VS的使用相关内容 玩家状态机 Unity教程&#xff08;一&#xff09;开始学习状态机 Unity教程&#xff08;二&#xff09;角色移动的实现 Unity教程&#xff08;三&#xff09;角色跳跃的实现…

智慧社区项目开发(三)——基于 Spring Boot 实现动态路由加载:从数据库到前端菜单的完整方案

在后台管理系统中&#xff0c;不同用户角色往往拥有不同的操作权限&#xff0c;对应的菜单展示也需动态调整。动态路由加载正是解决这一问题的核心方案 —— 根据登录用户的权限&#xff0c;从数据库查询其可访问的菜单&#xff0c;封装成前端所需的路由结构并返回。本文将详细…

Python在自动化与运维领域的核心角色:工具化、平台化与智能化

&#x1f4dd;个人主页&#x1f339;&#xff1a;慌ZHANG-CSDN博客 &#x1f339;&#x1f339;期待您的关注 &#x1f339;&#x1f339; 引言 在 IT 系统日益复杂、运维任务持续增长的今天&#xff0c;自动化已成为企业基础设施管理的关键方向。Python 以其简洁的语法、强大…

RAG实战指南 Day 28:RAG系统缓存与性能优化

【RAG实战指南 Day 28】RAG系统缓存与性能优化 开篇 欢迎来到"RAG实战指南"系列的第28天&#xff01;今天我们将深入探讨RAG系统的缓存机制与性能优化策略。在实际生产环境中&#xff0c;RAG系统往往面临高并发、低延迟的需求&#xff0c;而合理的缓存设计和性能优…

swanlab实验优雅起名

init中的参数的作用project&#xff1a;整个实验的名字&#xff1b;experiment_name&#xff1a;在这个实验中&#xff0c;你的名字是什么&#xff1b; 比如说现在我们要进行对比实验&#xff0c;PEAN和Triflownet分别是对比方法的名字&#xff0c;这样的好处是&#xff0c;她们…

Nestjs框架: NestJS 核心机制解析 —— DI(依赖注入)容器与模块化工作原理

理解 NestJS 的 DI 管理机制 我们想要了解依赖注入&#xff08;Dependency Injection, DI&#xff09;最核心的工作逻辑NestJS 拥有自己的一套 DI 管理系统&#xff0c;它通过一个称为 DI 容器 的机制&#xff0c;来统一管理应用中所有类&#xff08;class&#xff09;的依赖关…

日语学习-日语知识点小记-构建基础-JLPT-N3阶段(12):文法+单词

日语学习-日语知识点小记-构建基础-JLPT-N3阶段&#xff08;12&#xff09;&#xff1a;文法单词 1、前言&#xff08;1&#xff09;情况说明&#xff08;2&#xff09;工程师的信仰2、知识点&#xff11;ーたぶん 多分&#xff12;ーV&#xff08;て&#xff09;いく ・ V&…

【赵渝强老师】OceanBase租户的资源管理

OceanBase数据库是多租户的数据库系统&#xff0c;一个集群内可包含多个相互独立的租户&#xff0c;每个租户提供独立的数据库服务。在OceanBase数据库中&#xff0c;使用资源配置&#xff08;Unit Config&#xff09;、资源单元&#xff08;Unit&#xff09;和资源池&#xff…

8K、AI、低空智联,H.266能否撑起下一代视频通路?

一、&#x1f4c8; 爆发式增长的 AI 与视频数据&#xff1a;智能时代的“数据燃料革命” 随着生成式 AI、大模型推理、多模态理解等技术的迅猛发展&#xff0c;视频数据从“记录工具”转变为“感知基础设施”&#xff0c;其在现代智能系统中的战略地位日益凸显。 1️⃣ 视频数…

保姆级别IDEA关联数据库方式、在IDEA中进行数据库的可视化操作(包含图解过程)

本文以mysql为例&#xff0c;学会了Mysql&#xff0c;其它的数据库也是类似的模版~如果您觉得这边文章对你有帮助&#xff0c;可以收藏防止找不到~如果您觉得这篇文章不错&#xff0c;也感谢您的点赞对我创作的支持1.1 打开侧边栏的Database2.2 选择要连接的数据库&#xff08;…