SpringMVC 教程
1. SpringMVC 基本概念
SpringMVC 是 Spring 框架中用于构建 Web 应用程序的模块,它实现了 Model-View-Controller (MVC) 设计模式。其核心思想是将应用程序分为三个主要部分:
- Model(模型):处理应用程序的数据和业务逻辑
- View(视图):负责展示数据给用户的界面
- Controller(控制器):处理用户请求,协调模型和视图
这种分离使得代码结构更清晰、可维护性更高,同时也便于测试。
2. SpringMVC 核心组件
SpringMVC 框架包含以下核心组件:
2.1 前端控制器(DispatcherServlet)
- 作用:作为整个 SpringMVC 的核心,接收所有 HTTP 请求并协调其他组件工作
- 特性:是 Servlet 容器中的一个标准 Servlet,需要在 web.xml 中配置
- 职责:请求分发、组件协调、响应处理
2.2 处理器映射器(HandlerMapping)
- 作用:根据请求 URL 查找对应的处理器(Controller 方法)
- 常见实现类 :
RequestMappingHandlerMapping
:基于注解@RequestMapping
的映射SimpleUrlHandlerMapping
:基于简单 URL 路径规则的映射BeanNameUrlHandlerMapping
:根据 Bean 名称与 URL 进行映射
2.3 处理器适配器(HandlerAdapter)
- 作用:适配不同类型的处理器,确保它们能够被正确调用
- 常见实现类 :
RequestMappingHandlerAdapter
:支持基于注解的 Controller 方法SimpleControllerHandlerAdapter
:支持传统的 Controller 接口实现
2.4 处理器(Handler/Controller)
- 作用:执行具体的业务逻辑,处理请求并返回结果
- 实现方式 :使用
@Controller
注解或实现 Controller 接口
2.5 视图解析器(ViewResolver)
- 作用:将逻辑视图名称解析为具体的视图对象
- 常见实现类 :
InternalResourceViewResolver
:用于解析 JSP 视图FreeMarkerViewResolver
:用于解析 FreeMarker 视图
2.6 视图(View)
- 作用:渲染模型数据,生成最终的响应结果
- 类型:可以是 JSP、FreeMarker、Thymeleaf 等多种视图技术
3. SpringMVC 工作流程
SpringMVC 的工作流程可以分为以下几个关键步骤:
sql
客户端请求 → DispatcherServlet → HandlerMapping → HandlerAdapter → Controller → ModelAndView → ViewResolver → View → 响应客户端
详细流程解析
-
客户端发送 HTTP 请求:用户通过浏览器或其他客户端发送请求到服务器
-
DispatcherServlet 接收请求:所有请求首先被 DispatcherServlet 拦截
-
查找处理器:
- DispatcherServlet 向 HandlerMapping 询问当前请求应该由哪个处理器处理
- HandlerMapping 根据请求 URL、请求方式等信息,返回对应的 HandlerExecutionChain(包含目标 Controller 方法及拦截器)
-
执行处理器:
- DispatcherServlet 通过 HandlerAdapter 调用具体的 Controller 方法
- Controller 方法执行业务逻辑,可能调用 Service、Repository 等组件
- 处理完成后,返回 ModelAndView 对象(包含模型数据和视图名称)
-
解析与渲染视图:
- DispatcherServlet 将 ModelAndView 传递给 ViewResolver
- ViewResolver 将逻辑视图名称解析为具体的 View 对象
- View 对象渲染模型数据,生成最终的响应内容
-
响应客户端:DispatcherServlet 将渲染后的响应返回给客户端
4. SpringMVC 配置方式
SpringMVC 支持两种主要的配置方式:XML 配置和注解配置。
4.1 XML 配置方式
web.xml 配置
xml
<web-app>
<!-- 配置 DispatcherServlet -->
<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>
</web-app>
spring-mvc.xml 配置
xml
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="...">
<!-- 启用组件扫描 -->
<context:component-scan base-package="com.example.controller"/>
<!-- 启用 SpringMVC 注解支持 -->
<mvc:annotation-driven/>
<!-- 配置视图解析器 -->
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix" value="/WEB-INF/views/"/>
<property name="suffix" value=".jsp"/>
</bean>
<!-- 静态资源处理 -->
<mvc:resources mapping="/static/**" location="/static/"/>
</beans>
4.2 注解配置方式(Java Config)
配置类
java
@Configuration
@EnableWebMvc
@ComponentScan(basePackages = "com.example.controller")
public class WebConfig implements WebMvcConfigurer {
// 配置视图解析器
@Bean
public ViewResolver viewResolver() {
InternalResourceViewResolver resolver = new InternalResourceViewResolver();
resolver.setPrefix("/WEB-INF/views/");
resolver.setSuffix(".jsp");
return resolver;
}
// 配置静态资源处理
@Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
registry.addResourceHandler("/static/**").addResourceLocations("/static/");
}
}
初始化器
java
public class WebAppInitializer implements WebApplicationInitializer {
@Override
public void onStartup(ServletContext servletContext) {
// 创建根应用上下文
AnnotationConfigWebApplicationContext rootContext =
new AnnotationConfigWebApplicationContext();
rootContext.register(AppConfig.class);
// 注册 ContextLoaderListener
servletContext.addListener(new ContextLoaderListener(rootContext));
// 创建 SpringMVC 应用上下文
AnnotationConfigWebApplicationContext webContext =
new AnnotationConfigWebApplicationContext();
webContext.register(WebConfig.class);
// 注册 DispatcherServlet
ServletRegistration.Dynamic dispatcher =
servletContext.addServlet("dispatcher", new DispatcherServlet(webContext));
dispatcher.setLoadOnStartup(1);
dispatcher.addMapping("/");
}
}
5. SpringMVC 控制器开发
5.1 基本控制器示例
java
@Controller
@RequestMapping("/users")
public class UserController {
@Autowired
private UserService userService;
// GET 请求 - 获取用户列表
@GetMapping
public String listUsers(Model model) {
List<User> users = userService.findAllUsers();
model.addAttribute("users", users);
return "user/list"; // 返回视图名称
}
// GET 请求 - 显示添加用户表单
@GetMapping("/add")
public String showAddForm(Model model) {
model.addAttribute("user", new User());
return "user/add"; // 返回视图名称
}
// POST 请求 - 提交添加用户表单
@PostMapping
public String addUser(@ModelAttribute User user) {
userService.addUser(user);
return "redirect:/users"; // 重定向到用户列表页面
}
// GET 请求 - 根据 ID 获取用户详情
@GetMapping("/{id}")
public String getUserById(@PathVariable("id") Long id, Model model) {
User user = userService.getUserById(id);
model.addAttribute("user", user);
return "user/detail"; // 返回视图名称
}
// PUT 请求 - 更新用户
@PutMapping("/{id}")
public String updateUser(@PathVariable("id") Long id, @ModelAttribute User user) {
user.setId(id);
userService.updateUser(user);
return "redirect:/users"; // 重定向到用户列表页面
}
// DELETE 请求 - 删除用户
@DeleteMapping("/{id}")
public String deleteUser(@PathVariable("id") Long id) {
userService.deleteUser(id);
return "redirect:/users"; // 重定向到用户列表页面
}
}
5.2 RESTful API 控制器示例
java
@RestController
@RequestMapping("/api/users")
public class UserRestController {
@Autowired
private UserService userService;
// 获取所有用户
@GetMapping
public List<User> getAllUsers() {
return userService.findAllUsers();
}
// 根据 ID 获取用户
@GetMapping("/{id}")
public User getUserById(@PathVariable("id") Long id) {
return userService.getUserById(id);
}
// 添加用户
@PostMapping
public User addUser(@RequestBody User user) {
return userService.addUser(user);
}
// 更新用户
@PutMapping("/{id}")
public User updateUser(@PathVariable("id") Long id, @RequestBody User user) {
user.setId(id);
return userService.updateUser(user);
}
// 删除用户
@DeleteMapping("/{id}")
public void deleteUser(@PathVariable("id") Long id) {
userService.deleteUser(id);
}
}
6. 请求参数绑定与验证
6.1 请求参数绑定
SpringMVC 支持多种方式的参数绑定:
java
@Controller
public class ParamController {
// 基本类型参数绑定
@GetMapping("/param1")
public String param1(@RequestParam("id") Integer id,
@RequestParam("name") String name) {
// 处理业务逻辑
return "result";
}
// 路径变量绑定
@GetMapping("/param2/{id}")
public String param2(@PathVariable("id") Long id) {
// 处理业务逻辑
return "result";
}
// 请求头绑定
@GetMapping("/param3")
public String param3(@RequestHeader("User-Agent") String userAgent) {
// 处理业务逻辑
return "result";
}
// Cookie 值绑定
@GetMapping("/param4")
public String param4(@CookieValue("JSESSIONID") String sessionId) {
// 处理业务逻辑
return "result";
}
// 表单数据绑定到对象
@PostMapping("/param5")
public String param5(@ModelAttribute User user) {
// 处理业务逻辑
return "result";
}
// JSON 数据绑定到对象
@PostMapping("/param6")
public String param6(@RequestBody User user) {
// 处理业务逻辑
return "result";
}
}
6.2 数据验证
使用 SpringMVC 结合 Bean Validation(JSR-380)进行数据验证:
java
// 实体类添加验证注解
public class User {
@NotNull(message = "ID 不能为空")
private Long id;
@NotBlank(message = "用户名不能为空")
@Size(min = 2, max = 50, message = "用户名长度必须在 2-50 之间")
private String username;
@NotBlank(message = "邮箱不能为空")
@Email(message = "邮箱格式不正确")
private String email;
// getter 和 setter 方法
}
// 控制器中添加验证
@Controller
public class ValidationController {
@PostMapping("/validate")
public String validateUser(@Valid @ModelAttribute User user,
BindingResult bindingResult) {
// 检查验证结果
if (bindingResult.hasErrors()) {
// 处理验证错误
return "form";
}
// 处理业务逻辑
return "success";
}
}
7. 异常处理
7.1 全局异常处理器
java
@ControllerAdvice
public class GlobalExceptionHandler {
// 处理特定异常
@ExceptionHandler(UserNotFoundException.class)
public ModelAndView handleUserNotFound(UserNotFoundException ex) {
ModelAndView model = new ModelAndView("error");
model.addObject("errorMessage", ex.getMessage());
model.addObject("errorCode", "404");
return model;
}
// 处理所有异常
@ExceptionHandler(Exception.class)
public ModelAndView handleGenericException(Exception ex) {
ModelAndView model = new ModelAndView("error");
model.addObject("errorMessage", "发生未知错误");
model.addObject("errorCode", "500");
return model;
}
// 处理 REST API 异常
@ExceptionHandler(ValidationException.class)
@ResponseBody
public ResponseEntity<ErrorResponse> handleValidationException(ValidationException ex) {
ErrorResponse error = new ErrorResponse("400", ex.getMessage());
return new ResponseEntity<>(error, HttpStatus.BAD_REQUEST);
}
}
8. SpringMVC 与 Spring Boot 集成
在 Spring Boot 中使用 SpringMVC 变得更加简单:
8.1 基本配置
创建一个 Spring Boot 应用并添加依赖:
xml
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
8.2 应用主类
java
@SpringBootApplication
public class SpringBootMvcApplication {
public static void main(String[] args) {
SpringApplication.run(SpringBootMvcApplication.class, args);
}
}
8.3 控制器开发
与普通 SpringMVC 控制器相同,但无需额外配置:
java
@RestController
public class HelloController {
@GetMapping("/hello")
public String hello() {
return "Hello, Spring MVC with Spring Boot!";
}
}
9. 最佳实践
-
使用 RESTful 风格:遵循 REST 原则设计 API,使用合适的 HTTP 方法
-
合理使用注解 :使用
@RestController
简化 REST API 开发,使用@Controller
开发视图控制器 -
统一异常处理 :使用
@ControllerAdvice
实现全局异常处理 -
请求参数验证:使用 Bean Validation 进行输入验证
-
使用拦截器:处理横切关注点,如日志记录、权限验证等
-
优化静态资源处理:配置适当的资源处理器和缓存策略
-
使用 Spring Boot:简化配置,提高开发效率
-
性能优化:合理使用缓存、异步处理等技术提升性能
10. 总结
SpringMVC 是一个功能强大、灵活的 Web 框架,通过 DispatcherServlet 作为核心,协调各个组件完成请求处理和响应生成。它支持多种配置方式和视图技术,与 Spring 框架无缝集成,是构建 Java Web 应用的理想选择。
通过本教程,您应该能够理解 SpringMVC 的基本概念、核心组件和工作流程,并能够开始开发自己的 SpringMVC 应用程序。