SpringMVC 教程

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 → 响应客户端

详细流程解析

  1. 客户端发送 HTTP 请求:用户通过浏览器或其他客户端发送请求到服务器

  2. DispatcherServlet 接收请求:所有请求首先被 DispatcherServlet 拦截

  3. 查找处理器

    • DispatcherServlet 向 HandlerMapping 询问当前请求应该由哪个处理器处理
    • HandlerMapping 根据请求 URL、请求方式等信息,返回对应的 HandlerExecutionChain(包含目标 Controller 方法及拦截器)
  4. 执行处理器

    • DispatcherServlet 通过 HandlerAdapter 调用具体的 Controller 方法
    • Controller 方法执行业务逻辑,可能调用 Service、Repository 等组件
    • 处理完成后,返回 ModelAndView 对象(包含模型数据和视图名称)
  5. 解析与渲染视图

    • DispatcherServlet 将 ModelAndView 传递给 ViewResolver
    • ViewResolver 将逻辑视图名称解析为具体的 View 对象
    • View 对象渲染模型数据,生成最终的响应内容
  6. 响应客户端: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. 最佳实践

  1. 使用 RESTful 风格:遵循 REST 原则设计 API,使用合适的 HTTP 方法

  2. 合理使用注解 :使用 @RestController 简化 REST API 开发,使用 @Controller 开发视图控制器

  3. 统一异常处理 :使用 @ControllerAdvice 实现全局异常处理

  4. 请求参数验证:使用 Bean Validation 进行输入验证

  5. 使用拦截器:处理横切关注点,如日志记录、权限验证等

  6. 优化静态资源处理:配置适当的资源处理器和缓存策略

  7. 使用 Spring Boot:简化配置,提高开发效率

  8. 性能优化:合理使用缓存、异步处理等技术提升性能

10. 总结

SpringMVC 是一个功能强大、灵活的 Web 框架,通过 DispatcherServlet 作为核心,协调各个组件完成请求处理和响应生成。它支持多种配置方式和视图技术,与 Spring 框架无缝集成,是构建 Java Web 应用的理想选择。

通过本教程,您应该能够理解 SpringMVC 的基本概念、核心组件和工作流程,并能够开始开发自己的 SpringMVC 应用程序。

相关推荐
用户34325962788169 小时前
Spring AI Alibaba中使用Redis Vector报错修改过程
后端
oak隔壁找我9 小时前
MyBatis和SpringBoot集成的原理详解
后端
oak隔壁找我9 小时前
SpringBoot @Import 注解详解
后端
oak隔壁找我9 小时前
Spring Bean 生命周期详解
后端
Tony Bai9 小时前
【Go 网络编程全解】06 UDP 数据报编程:速度、不可靠与应用层弥补
开发语言·网络·后端·golang·udp
半夏知半秋9 小时前
lua对象池管理工具剖析
服务器·开发语言·后端·学习·lua
卷福同学9 小时前
【AI绘画】你有多久没有打开SD了?
后端·aigc·ai编程
Moniane9 小时前
时序数据库全面重构指南
java·后端·struts