当前位置: 首页 > news >正文

Spring MVC 处理请求的完整流程详解

Spring MVC 处理请求的完整流程详解

Spring MVC 处理一个 HTTP 请求的完整流程涉及多个组件协同工作。下面我将详细说明每个步骤,并举例说明。

1. 整体流程图

Client → DispatcherServlet → HandlerMapping → Controller → HandlerAdapter → Controller Method → ModelAndView → ViewResolver → View → Response → Client

2. 详细步骤分析

步骤1:客户端发送请求

GET /users/123?name=John HTTP/1.1
Host: localhost:8080
Content-Type: application/json
Authorization: Bearer token123

步骤2:DispatcherServlet接收请求

DispatcherServlet是Spring MVC的核心前端控制器,负责接收所有HTTP请求。

// web.xml配置(传统方式)
<servlet><servlet-name>dispatcher</servlet-name><servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class><init-param><param-name>contextConfigLocation</param-name><param-value>/WEB-INF/spring-mvc.xml</param-value></init-param><load-on-startup>1</load-on-startup>
</servlet><servlet-mapping><servlet-name>dispatcher</servlet-name><url-pattern>/</url-pattern>
</servlet-mapping>// 或者通过Java配置
@SpringBootApplication
public class Application {public static void main(String[] args) {SpringApplication.run(Application.class, args);}
}

步骤3:HandlerMapping查找处理器

DispatcherServlet使用HandlerMapping来确定哪个Controller应该处理当前请求。

// Controller示例
@RestController
@RequestMapping("/users")
public class UserController {@Autowiredprivate UserService userService;@GetMapping("/{id}")public User getUser(@PathVariable Long id, @RequestParam(required = false) String name) {return userService.findById(id);}@PostMappingpublic User createUser(@RequestBody User user) {return userService.createUser(user);}
}

HandlerMapping会根据请求URL /users/123 找到对应的处理器方法 getUser

步骤4:HandlerAdapter调用处理器

HandlerAdapter负责实际调用Controller中的方法。

// HandlerAdapter处理流程示例
public class RequestMappingHandlerAdapter {public ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {// 1. 参数解析Object[] args = getArguments(request, handler);// 2. 反射调用Controller方法Object result = invokeHandlerMethod(handler, args);// 3. 处理返回结果return getModelAndView(result);}
}

步骤5:参数解析和绑定

Spring MVC自动解析和绑定请求参数。

@GetMapping("/{id}")
public User getUser(@PathVariable Long id,                           // 路径变量@RequestParam(required = false) String name,     // 查询参数@RequestHeader("Authorization") String token,    // 请求头@CookieValue("sessionId") String sessionId,      // Cookie值HttpServletRequest request) {                    // 原始请求对象System.out.println("ID: " + id);System.out.println("Name: " + name);System.out.println("Token: " + token);System.out.println("Session ID: " + sessionId);return userService.findById(id);
}

参数解析过程:

  1. @PathVariable:从URL路径中提取参数 /users/123id=123
  2. @RequestParam:从查询字符串中提取参数 ?name=Johnname="John"
  3. @RequestHeader:从请求头中提取 Authorization: Bearer token123token="Bearer token123"
  4. 类型转换:字符串"123"自动转换为Long类型

步骤6:数据验证

@PostMapping
public User createUser(@Valid @RequestBody User user, BindingResult bindingResult) {// 验证失败处理if (bindingResult.hasErrors()) {List<String> errors = bindingResult.getFieldErrors().stream().map(error -> error.getField() + ": " + error.getDefaultMessage()).collect(Collectors.toList());throw new ValidationException(errors.toString());}return userService.createUser(user);
}// User实体类
public class User {@NotNull(message = "ID不能为空")private Long id;@NotBlank(message = "姓名不能为空")@Size(min = 2, max = 50, message = "姓名长度必须在2-50之间")private String name;@Email(message = "邮箱格式不正确")private String email;@Min(value = 0, message = "年龄不能小于0")@Max(value = 150, message = "年龄不能大于150")private Integer age;// getters and setters
}

步骤7:执行Controller方法

@RestController
@RequestMapping("/users")
public class UserController {@Autowiredprivate UserService userService;@GetMapping("/{id}")public ResponseEntity<User> getUser(@PathVariable Long id) {User user = userService.findById(id);if (user != null) {return ResponseEntity.ok(user);} else {return ResponseEntity.notFound().build();}}@PostMappingpublic ResponseEntity<User> createUser(@RequestBody User user) {User createdUser = userService.createUser(user);// 返回201状态码和创建的资源return ResponseEntity.status(HttpStatus.CREATED).body(createdUser);}
}

步骤8:处理返回值

Spring MVC支持多种返回值类型:

@Controller
public class ExampleController {// 1. 返回ModelAndView@RequestMapping("/page1")public ModelAndView showPage1() {ModelAndView mav = new ModelAndView("user/profile");mav.addObject("user", userService.getCurrentUser());return mav;}// 2. 返回String(视图名称)@RequestMapping("/page2")public String showPage2(Model model) {model.addAttribute("user", userService.getCurrentUser());return "user/profile";}// 3. 返回对象(@ResponseBody自动序列化为JSON)@GetMapping("/api/user/{id}")@ResponseBodypublic User getUserApi(@PathVariable Long id) {return userService.findById(id);}// 4. 使用@RestController自动序列化@GetMapping("/api/users")public List<User> getAllUsers() {return userService.findAll();}// 5. 返回ResponseEntity(包含状态码和响应头)@PostMapping("/api/users")public ResponseEntity<User> createUserWithResponse(@RequestBody User user) {User createdUser = userService.createUser(user);return ResponseEntity.created(URI.create("/api/users/" + createdUser.getId())).body(createdUser);}
}

步骤9:视图解析

如果返回的是视图名称,ViewResolver会解析视图:

// 视图解析器配置
@Configuration
@EnableWebMvc
public class WebConfig implements WebMvcConfigurer {@Beanpublic ViewResolver viewResolver() {InternalResourceViewResolver resolver = new InternalResourceViewResolver();resolver.setPrefix("/WEB-INF/views/");resolver.setSuffix(".jsp");return resolver;}
}// Controller返回视图名称
@Controller
public class HomeController {@RequestMapping("/home")public String home(Model model) {model.addAttribute("message", "Hello Spring MVC!");// 返回视图名称"home"return "home";}
}// 视图解析过程:
// ViewResolver将"home"解析为"/WEB-INF/views/home.jsp"

步骤10:视图渲染

<!-- /WEB-INF/views/home.jsp -->
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<html>
<head><title>Home Page</title>
</head>
<body><h1>Welcome</h1><p>${message}</p><c:if test="${not empty user}"><p>Hello, ${user.name}!</p></c:if>
</body>
</html>

步骤11:响应返回客户端

// 最终HTTP响应
HTTP/1.1 200 OK
Content-Type: text/html;charset=UTF-8
Content-Length: 1234<html>
<head><title>Home Page</title>
</head>
<body><h1>Welcome</h1><p>Hello Spring MVC!</p>
</body>
</html>

3. 完整示例演示

让我们通过一个完整的示例来演示整个流程:

// 1. 实体类
public class Product {private Long id;private String name;private BigDecimal price;private String category;// constructors, getters, setters
}// 2. Service层
@Service
public class ProductService {public Product findById(Long id) {// 模拟数据库查询return new Product(id, "Product " + id, new BigDecimal("99.99"), "Electronics");}public List<Product> findAll() {return Arrays.asList(new Product(1L, "Laptop", new BigDecimal("1299.99"), "Electronics"),new Product(2L, "Book", new BigDecimal("29.99"), "Education"));}public Product create(Product product) {product.setId(System.currentTimeMillis()); // 简单生成IDreturn product;}
}// 3. Controller层
@RestController
@RequestMapping("/api/products")
public class ProductController {@Autowiredprivate ProductService productService;// GET /api/products/1@GetMapping("/{id}")public ResponseEntity<Product> getProduct(@PathVariable Long id) {System.out.println("Processing request for product ID: " + id);Product product = productService.findById(id);if (product != null) {return ResponseEntity.ok(product);} else {return ResponseEntity.notFound().build();}}// GET /api/products?category=Electronics&page=0&size=10@GetMappingpublic ResponseEntity<List<Product>> getAllProducts(@RequestParam(required = false) String category,@RequestParam(defaultValue = "0") int page,@RequestParam(defaultValue = "10") int size) {System.out.println("Getting products - Category: " + category + ", Page: " + page + ", Size: " + size);List<Product> products = productService.findAll();return ResponseEntity.ok(products);}// POST /api/products@PostMappingpublic ResponseEntity<Product> createProduct(@Valid @RequestBody Product product) {System.out.println("Creating product: " + product.getName());Product createdProduct = productService.create(product);return ResponseEntity.created(URI.create("/api/products/" + createdProduct.getId())).body(createdProduct);}
}// 4. 全局异常处理
@ControllerAdvice
public class GlobalExceptionHandler {@ExceptionHandler(Exception.class)public ResponseEntity<String> handleException(Exception e) {return ResponseEntity.status(500).body("Internal Server Error: " + e.getMessage());}
}

4. 请求处理流程总结

  1. 请求到达:客户端发送HTTP请求到服务器
  2. 前端控制器:DispatcherServlet接收请求
  3. 处理器映射:HandlerMapping根据URL找到对应的Controller方法
  4. 处理器适配:HandlerAdapter准备调用Controller方法
  5. 参数解析:解析并绑定请求参数到方法参数
  6. 数据验证:对输入数据进行验证
  7. 方法执行:通过反射调用Controller方法
  8. 返回处理:处理方法返回值
  9. 视图解析:如果需要,解析视图名称为具体视图
  10. 视图渲染:渲染视图生成响应内容
  11. 响应返回:将结果返回给客户端

整个流程中,Spring MVC通过各种组件的协同工作,大大简化了Web开发的复杂性,让开发者能够专注于业务逻辑的实现。

http://www.lryc.cn/news/619000.html

相关文章:

  • 【Unity】Spine重新播放动画时会闪烁上次动画的残影
  • 秋招笔记-8.12
  • Tauri Qt孰优孰劣
  • 【Unity】Unity中ContentSizeFitter有时无法及时自适应大小问题解决
  • 终端安全检测和防御技术总结
  • Python初学者笔记第二十四期 -- (面向对象编程)
  • SpringBoot集成MyBatis的SQL拦截器
  • MES系统怎么实现数字化闭环与设备预测性维护?
  • SQL180 每类试卷得分前3名
  • 单例模式,动态代理,微服务原理
  • 大数据技术入门精讲(Hadoop+Spark)
  • 当机械臂装上「智能大脑」:Deepoc具身智能模型如何重构传统自动化​
  • JavaEE 初阶第十八期:叩开网络世界的大门(上)
  • 自己动手造个球平衡机器人
  • 13.深度学习——Minst手写数字识别
  • 【自动化运维神器Ansible】playbook文件内变量定义全流程解析
  • 实时域自适应检测SOTA方案RT-DATR,刷新多个跨域检测榜单!
  • wordpress数据库文件sql导入时出现#1253错误
  • Java数据结构之ArrayList
  • 嵌入式分享合集136
  • 移动端调用大模型详解
  • 关于淘宝双十一
  • 数据分析小白训练营:基于python编程语言的Numpy库介绍(第三方库)(上篇)
  • DuckDB读取xlsx格式数据的方法比较
  • 【SpringBoot】MyBatis 动态 sql
  • 如何应对CAN总线冲突和数据丢包
  • 【c++深入系列】:万字详解模版(下)
  • 【项目设计】高并发内存池
  • AI赋能IT服务管理:从被动响应到智能驱动的跃迁
  • Linux驱动开发probe字符设备的完整创建流程