Spring MVC核心原理与实战指南
当前,使用Spring Boot的
spring-boot-starter-web可以快速构建Web应用,其内嵌了Spring MVC。本文旨在深入理解Spring MVC的基础原理和工作流程
一、特点
- 轻量级:基于核心Spring IOC容器,非侵入式设计。
- 高效:基于请求-响应模型的MVC框架。
- 与Spring容器无缝集成:可在Spring IOC容器中注册Bean,方便依赖注入和管理。
- 约定优于配置:提供了很多默认配置,简化开发。
- 功能丰富:原生支持RESTful风格、数据验证、格式化、拦截器等。
二、原理
核心是前端控制器原理,所有请求通过一个统一的入口DispatcherServlet进行分发
- 发起的请求被前置的控制器拦截到请求
- 根据请求参数生成代理请求并找到对应的实际控制器
- 控制器处理请求
- 创建数据模型
- 访问数据库并将模型响应给中心控制器
- 控制器使用模型和视图渲染视图结果并返回给中心控制器,最后返回给用户
三、执行流程

-
接收请求:
DispathcerServlet表示前置控制器,是整个SpringMvc的控制中心,用户发出请求,DispathcerServlet接受请求并拦截请求比如有个URL地址:http://localhost8080/SpringMvc/hello。
这个可以拆成三部分:
服务器域名:http://localhost8080
SpringMvc部署在服务器上的web站点
hello表示控制器
整合起来就是:请求位于服务器localhost:8080上的SpringMvc站点的hello控制器
-
查找处理器:
DispatcherServlet查询HandlerMapping(处理器映射器),根据URL找到对应的Handler(处理器,通常就是我们的Controller)及其拦截器,形成HandlerExecutionChain(处理器执行链)。 -
执行处理器:
DispatcherServlet通过HandlerAdapter(处理器适配器)来适配并执行找到的Handler。HandlerAdapter会调用我们Controller中的具体方法,处理业务逻辑(访问Service、数据库等)。 -
处理返回结果:Controller方法执行完毕后,会返回一个结果(可能是
ModelAndView,也可能是一个数据对象)。HandlerAdapter将此结果返回给DispatcherServlet。 -
解析视图:如果返回的结果包含视图信息,
DispatcherServlet会调用ViewResolver(视图解析器)将逻辑视图名解析为具体的View对象(如JSP、Thymeleaf模板)。 -
渲染响应:
DispatcherServlet将模型数据传递给View对象,由View对象进行渲染(生成HTML等),最终将渲染结果通过HttpServletResponse返回给用户。
按自己的话来说:
- 首先作为前端控制器
DispatcherServlet接收到用户请求- 然后查找对应的
Handler处理映射器,返回处理程序执行链给前端控制器。- 紧接着控制器要着手去按照执行链去请求适配器
HandlerAdapter(也就是Controller)执行,经过Service和数据库返回具体信息如ModelAndView给前端控制器。- 得到了
ModelAndView后控制器要请求视图解析知道要给用户呈现什么页面,返回View对象,最后响应客户请求
四、使用注解开发SpringMvc
现代Spring MVC开发几乎完全基于注解,极大简化了配置。
1. 创建Controller
Controller提供访问应用程序的行为,通常通过接口定义或注解实现
接口实现(比较老)当前开发不再使用,只做了解
//实现接口,就是一个控制器了 public class ControllerTest1 implements Controller{ public ModelAndView handleRequest(HttpServletRequest req,HttpServletResponse res)throws Exception{ ModelAndView mv=new ModelAndView(); mv.addObject("msg","Test1Controller"); mv.setViewName("test"); return mv; } }然后在Spring配置文件中注册请求Bean;name对应请求路径,class对应请求的类
<bean name="/t1" class="com.example.controller.ControllerTest1"
当前开发主要使用注解方式@Controller
使用@Controller注解将一个类声明为控制器,Spring IOC容器会自动扫描并注册它。
@Controller // 让Spring IOC容器初始化时自动扫描到
@RequestMapping("/user") // 类级别的RequestMapping,可省略
public class UserController {
@RequestMapping("/hello") // 映射URL路径
public String hello(Model model) {
model.addAttribute("msg", "Hello, Spring MVC!");
return "hello"; // 返回逻辑视图名,由视图解析器处理
}
}
2. 配置组件扫描和视图解析器
在Spring配置文件中(如springmvc-servlet.xml),需要开启注解扫描并配置视图解析器。
<!-- 自动扫描包,让指定包下的注解生效 -->
<context:component-scan base-package="com.example.controller"/>
<!-- 视图解析器:将逻辑视图名解析为具体页面路径 -->
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver" id="viewResolver">
<property name="prefix" value="/WEB-INF/jsp/"/> <!-- 前缀 -->
<property name="suffix" value=".jsp"/> <!-- 后缀 -->
</bean>
对于上述Controller,访问 /user/hello,视图解析器会将其指向 /WEB-INF/jsp/hello.jsp文件。
3. @RestController注解
它是@Controller和@ResponseBody的组合注解。它的作用是直接将方法的返回值写入HTTP响应体,通常用于返回JSON/XML数据,而不是跳转到一个视图页面。这是开发RESTful API的基石。
@RestController // 等价于 @Controller + @ResponseBody
public class ApiController {
@GetMapping("/data")
public User getData() {
return new User("张三", 25); // 方法返回的对象将被转换为JSON
}
}
五、RestFul风格
概念
资源定位以及资源操作的风格,让软件更简洁、有层次、更易于实现缓存等机制
平时我们URL地址是
localhost:8080/method?add,RestFul风格的URL地址就是localhost:8080/method/add
功能
互联网中的所有事务可抽象成为资源
| 操作 | 传统 | RestFul URL |
|---|---|---|
| 查询用户 | GET /user/queryUser?id=1 | GET /user/1 |
| 新增用户 | POST /user/saveUser | POST /user |
| 更新用户 | POST /user/updateUser | PUT /user/1 |
| 删除用户 | GET /user/deleteUser?id=1 | DELETE /user/1 |
- 通过使用
POST、DELETE、PUT、GET,使用不同的方法对资源进行对应操作(添加、删除、修改、请求)
传统方式操作资源时方法单一,使用POST和GET,比如:
http://127.0.0.1/item/queryItem.action?id=1 查询GET
http://127.0.0.1/item/saveItem.action 新增,POST
但是使用RestFul操作资源时,虽然请求地址相同,但是可以通过不同的请求方式来实现不同的效果。这一定程度上提高了安全性
在Spring MVC中实现
在SpringMVC中我们可以使用@PathVariable注解,让方法参数的值对应绑定到一个URL模板变量上。
@RestController
public class RestFulController {
// @GetMapping 是 @RequestMapping(method = RequestMethod.GET) 的快捷方式
@GetMapping("/commit/{p1}/{p2}")
public String index(@PathVariable int p1, @PathVariable int p2, Model model) {
int result = p1 + p2;
model.addAttribute("msg", "结果:" + result);
return "test";
}
// 更典型的RESTful API示例
@GetMapping("/users/{id}")
public ResponseEntity<User> getUserById(@PathVariable Long id) {
User user = userService.findById(id);
return ResponseEntity.ok(user); // 返回200状态码和用户数据
}
}
六、结果跳转方式(了解即可)
在SpringMVC出现以前,有几种方法可以实现结果跳转:
-
通过设置ModelAndView对象,根据View名称和视图解析器跳到指定的页面。
-
ServletAPI中我们不需要视图解析器,通过
- HttpServletResponse进行输出
- 通过HttpServletResponse实现重定向
sendRedirect() - 通过HttpServletResponse实现转发
getRequestDispatcher()
-
到SpringMVC,我们无需视图解析器即可实现该功能,只需在原基础上注释掉解析器,在控制层方法上添加return “Redirect:/index.jsp”
可以点击回顾
七、接收请求参数及数据回显
1. 接收请求参数
@RequestParam:获取URL查询参数或表单数据。
@GetMapping("/search")
public String search(@RequestParam("keyword") String keyword,
@RequestParam(value = "page", defaultValue = "1") Integer page) {
// 处理 /search?keyword=Java&page=2 的请求
return "result";
}
@PathVariable:获取URL路径参数(如上文RestFul示例)。
@RequestBody:获取请求体中的JSON/XML数据,并转换为Java对象(常用于POST/PUT请求)。
@PostMapping("/user")
public User createUser(@RequestBody User user) { // 将请求体的JSON自动绑定到User对象
return userService.save(user);
}
自动绑定到对象:表单提交时,参数名与对象属性名匹配即可自动绑定。
@PostMapping("/user")
public String saveUser(User user) { // 表单字段name="userName"会自动set到user.setUserName()
// ...
return "redirect:/user/list";
}
2. 数据回显
数据回显主要指将数据从Controller传递到View(如JSP)进行展示。
使用 Model对象:最常用方式。
@GetMapping("/user/edit/{id}")
public String editUser(@PathVariable Long id, Model model) {
User user = userService.findById(id);
model.addAttribute("user", user); // 将user对象放入model,在视图中通过 ${user} 获取
return "user/edit";
}
使用 ModelAndView对象:可以同时设置视图名称和模型数据。
@ModelAttribute注解:可将方法返回值或方法参数自动添加到Model中。
八、乱码问题
有时在提交表单查看页面时会发现乱码问题,一般是从后端启动开始就出现问题,我们最先想到的就是使用HttpServlet中的setEncodingCharset,但是试验后是无效的,这时我们会想到过滤器可以解决。在过滤器doFilter中调用setEncodingCharset来解决
在web.xml中配置Spring MVC提供的字符编码过滤器,是解决POST请求乱码的标准做法。
<filter>
<filter-name>characterEncodingFilter</filter-name>
<filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
<init-param>
<param-name>encoding</param-name>
<param-value>UTF-8</param-value>
</init-param>
<!-- 强制请求和响应都使用该编码 -->
<init-param>
<param-name>forceEncoding</param-name>
<param-value>true</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>characterEncodingFilter</filter-name>
<url-pattern>/*</url-pattern> <!-- 过滤所有请求 -->
</filter-mapping>
九、拦截器
是AOP思想在Web层面的应用,用于对处理器进行预处理和后处理。SpringMVC的处理器类似Servlet开发中的过滤器Filter,开发者可以自己定义一些拦截器来实现特定的功能
过滤器和拦截器的区别
| 方面 | 过滤器 | 拦截器 |
|---|---|---|
| 归属 | Servlet规范,任何Java Web工程都能用 | Spring MVC框架自身的组件 |
| 拦截范围 | 更广,能拦截所有资源(JSP, JS, CSS等) | 只拦截访问控制器方法 (Controller) 的请求 |
| 依赖 | 依赖Servlet容器(如Tomcat) | 依赖Spring MVC框架 |
自定义拦截器
自定义的需要实现拦截器的3个方法:preHandler、postHandler和afterCompletion
public class MyInterceptor implements HandlerInterceptor {
// 在Controller方法执行前调用。return true则放行,false则中断。
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
System.out.println("预处理...");
return true; // 放行
}
// 在Controller方法执行后,视图渲染前调用。
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
System.out.println("后处理...");
}
// 在整个请求完成(视图渲染完毕)后调用,常用于资源清理。
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
System.out.println("请求完成...");
}
}
最后:正不断学习,如有错误请大佬指出🙏
更多推荐

所有评论(0)