目录

深入浅出SpringMVC从入门到实战指南

深入浅出SpringMVC:从入门到实战指南

深入浅出SpringMVC:从入门到实战指南

什么是SpringMVC?

SpringMVC是Spring框架的一个模块,是一个基于MVC架构的Web框架。它通过一套MVC注解让POJO成为处理请求的控制器,无需实现任何接口,提供了灵活、可配置的Web应用开发解决方案。

MVC模式回顾

MVC(Model-View-Controller)是一种软件设计模式,将应用程序分为三个核心组件:

  • Model(模型):处理业务逻辑和数据持久化
  • View(视图):负责数据展示和用户界面
  • Controller(控制器):接收用户输入,协调模型和视图

用户请求

控制器Controller

模型Model

视图View

响应返回用户

为什么选择SpringMVC?

  1. 解耦优势

    • MyBatis:解决Java代码和SQL语句之间的耦合
    • Spring:解决业务层和其他各层之间的耦合
    • SpringMVC:解决Java代码和Servlet之间的耦合
  2. 相比Servlet的优势

    • 无需为每个请求编写单独的Servlet
    • 简化参数接收过程
    • 提供灵活的请求映射机制

SpringMVC核心架构与执行流程

SpringMVC的核心是前端控制器模式,所有请求都通过一个中央Servlet(DispatcherServlet)进行分发。

ClientDispatcherServletHandlerMappingHandlerAdapterHandlerViewResolverViewHTTP请求查询处理器返回处理链请求处理器适配执行处理器方法返回ModelAndView返回ModelAndView解析视图返回View对象渲染视图返回渲染结果HTTP响应ClientDispatcherServletHandlerMappingHandlerAdapterHandlerViewResolverView

核心组件介绍

  1. DispatcherServlet:前端控制器,接收所有请求
  2. HandlerMapping:映射请求到处理器
  3. HandlerAdapter:执行处理器方法
  4. ViewResolver:解析视图名称到具体视图实现
  5. View:渲染模型数据,生成响应内容

快速搭建SpringMVC项目

1. 添加Maven依赖

<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-webmvc</artifactId>
    <version>5.3.23</version>
</dependency>

2. 配置web.xml

<servlet>
    <servlet-name>springmvc</servlet-name>
    <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
    <init-param>
        <param-name>contextConfigLocation</param-name>
        <param-value>classpath:springmvc-config.xml</param-value>
    </init-param>
    <load-on-startup>1</load-on-startup>
</servlet>

<servlet-mapping>
    <servlet-name>springmvc</servlet-name>
    <url-pattern>/</url-pattern>
</servlet-mapping>

3. 创建SpringMVC配置文件

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:context="http://www.springframework.org/schema/context"
       xmlns:mvc="http://www.springframework.org/schema/mvc"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/context
        http://www.springframework.org/schema/context/spring-context.xsd
        http://www.springframework.org/schema/mvc
        http://www.springframework.org/schema/mvc/spring-mvc.xsd">

    <!-- 开启注解扫描 -->
    <context:component-scan base-package="com.example.controller"/>
    
    <!-- 开启MVC注解驱动 -->
    <mvc:annotation-driven/>
    
    <!-- 配置视图解析器 -->
    <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
        <property name="prefix" value="/WEB-INF/views/"/>
        <property name="suffix" value=".jsp"/>
    </bean>
</beans>

4. 创建控制器

@Controller
@RequestMapping("/user")
public class UserController {

    @RequestMapping("/register")
    public String register(User user, Model model) {
        // 处理用户注册逻辑
        model.addAttribute("message", "注册成功");
        return "result";
    }
}

请求映射详解

SpringMVC使用@RequestMapping注解映射URL请求到控制器方法:

@Controller
@RequestMapping("/products") // 类级别映射
public class ProductController {
    
    @RequestMapping(value = "/list", method = RequestMethod.GET) // 方法级别映射
    public String listProducts(Model model) {
        // 获取产品列表
        return "product/list";
    }
    
    @GetMapping("/{id}") // 简化注解,等同于@RequestMapping(method=RequestMethod.GET)
    public String getProduct(@PathVariable("id") Long id, Model model) {
        // 根据ID获取产品
        return "product/detail";
    }
    
    @PostMapping("/create") // 简化注解
    public String createProduct(Product product) {
        // 创建产品
        return "redirect:/products/list";
    }
}

参数绑定机制

SpringMVC提供了强大的参数绑定功能,支持多种参数类型:

1. 基本类型绑定

@PostMapping("/login")
public String login(String username, String password) {
    // 参数名与表单字段名一致时自动绑定
    return "dashboard";
}

2. 使用@RequestParam注解

@PostMapping("/login")
public String login(
    @RequestParam("username") String name, 
    @RequestParam(value = "pwd", required = false, defaultValue = "123456") String password) {
    // 明确指定参数映射关系
    return "dashboard";
}

3. POJO对象绑定

public class User {
    private String username;
    private String password;
    private Integer age;
    // getter和setter方法
}

@PostMapping("/register")
public String register(User user) {
    // 自动将表单字段绑定到User对象的属性
    return "success";
}

4. 集合类型绑定

public class Order {
    private List<Product> products;
    private Map<String, Address> addresses;
    // getter和setter方法
}

@PostMapping("/order")
public String createOrder(Order order) {
    // 处理包含集合的复杂对象
    return "order_confirmation";
}

数据验证与错误处理

SpringMVC支持JSR-303验证规范:

public class User {
    @NotBlank(message = "用户名不能为空")
    @Size(min = 3, max = 20, message = "用户名长度必须在3-20之间")
    private String username;
    
    @NotBlank(message = "密码不能为空")
    @Size(min = 6, message = "密码长度不能少于6位")
    private String password;
    // getter和setter方法
}

@PostMapping("/register")
public String register(@Valid User user, BindingResult result) {
    if (result.hasErrors()) {
        return "register_form"; // 返回表单页面显示错误信息
    }
    // 处理注册逻辑
    return "success";
}

拦截器与AOP编程

SpringMVC拦截器类似于过滤器,但更加强大和灵活:

public class AuthInterceptor implements HandlerInterceptor {
    
    @Override
    public boolean preHandle(HttpServletRequest request, 
                           HttpServletResponse response, 
                           Object handler) throws Exception {
        // 在处理器执行前调用
        HttpSession session = request.getSession();
        if (session.getAttribute("user") == null) {
            response.sendRedirect("/login");
            return false; // 中断执行链
        }
        return true; // 继续执行
    }
    
    @Override
    public void postHandle(HttpServletRequest request, 
                          HttpServletResponse response, 
                          Object handler, 
                          ModelAndView modelAndView) throws Exception {
        // 在处理器执行后、视图渲染前调用
    }
    
    @Override
    public void afterCompletion(HttpServletRequest request, 
                               HttpServletResponse response, 
                               Object handler, 
                               Exception ex) throws Exception {
        // 在整个请求完成后调用
    }
}

配置拦截器:

<mvc:interceptors>
    <mvc:interceptor>
        <mvc:mapping path="/secure/**"/>
        <bean class="com.example.interceptor.AuthInterceptor"/>
    </mvc:interceptor>
</mvc:interceptors>

RESTful API开发

SpringMVC非常适合开发RESTful风格的API:

@RestController // 组合了@Controller和@ResponseBody
@RequestMapping("/api/users")
public class UserApiController {
    
    @Autowired
    private UserService userService;
    
    @GetMapping
    public ResponseEntity<List<User>> getAllUsers() {
        List<User> users = userService.findAll();
        return ResponseEntity.ok(users);
    }
    
    @GetMapping("/{id}")
    public ResponseEntity<User> getUserById(@PathVariable Long id) {
        User user = userService.findById(id);
        return ResponseEntity.ok(user);
    }
    
    @PostMapping
    public ResponseEntity<User> createUser(@RequestBody User user) {
        User savedUser = userService.save(user);
        return ResponseEntity.created(URI.create("/api/users/" + savedUser.getId()))
                           .body(savedUser);
    }
    
    @PutMapping("/{id}")
    public ResponseEntity<User> updateUser(@PathVariable Long id, @RequestBody User user) {
        User updatedUser = userService.update(id, user);
        return ResponseEntity.ok(updatedUser);
    }
    
    @DeleteMapping("/{id}")
    public ResponseEntity<Void> deleteUser(@PathVariable Long id) {
        userService.delete(id);
        return ResponseEntity.noContent().build();
    }
}

文件上传处理

SpringMVC简化了文件上传的处理:

@PostMapping("/upload")
public String handleFileUpload(@RequestParam("file") MultipartFile file) {
    if (!file.isEmpty()) {
        try {
            byte[] bytes = file.getBytes();
            // 保存文件
            Path path = Paths.get("uploads/" + file.getOriginalFilename());
            Files.write(path, bytes);
            return "redirect:/success";
        } catch (IOException e) {
            return "redirect:/error";
        }
    }
    return "redirect:/empty";
}

配置MultipartResolver:

<bean id="multipartResolver" 
      class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
    <property name="maxUploadSize" value="10485760"/> <!-- 10MB -->
</bean>

异常处理机制

SpringMVC提供了统一的异常处理机制:

@ControllerAdvice // 全局异常处理
public class GlobalExceptionHandler {
    
    @ExceptionHandler(UserNotFoundException.class)
    public ResponseEntity<ErrorResponse> handleUserNotFound(UserNotFoundException ex) {
        ErrorResponse error = new ErrorResponse("USER_NOT_FOUND", ex.getMessage());
        return ResponseEntity.status(HttpStatus.NOT_FOUND).body(error);
    }
    
    @ExceptionHandler(Exception.class)
    public ResponseEntity<ErrorResponse> handleGeneralException(Exception ex) {
        ErrorResponse error = new ErrorResponse("INTERNAL_ERROR", "系统内部错误");
        return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(error);
    }
}

性能优化建议

  1. 合理使用拦截器:避免在拦截器中执行耗时操作
  2. 视图解析优化:使用模板引擎缓存编译结果
  3. 静态资源处理:配置<mvc:resources>避免静态资源经过DispatcherServlet
  4. 异步处理:使用@AsyncCallable/DeferredResult提高并发处理能力
  5. 合理设计控制器:保持控制器简洁,将业务逻辑委托给Service层

总结

SpringMVC作为一个成熟、强大的Web框架,通过简洁的注解配置和灵活的扩展机制,极大地简化了Java Web开发。无论是传统的页面渲染应用还是现代化的RESTful API,SpringMVC都能提供优秀的解决方案。

掌握SpringMVC的核心概念和最佳实践,将帮助你构建出结构清晰、易于维护的高质量Web应用程序。随着Spring Boot的普及,SpringMVC的使用变得更加简单,但其核心原理和设计思想仍然保持不变。

希望本文能帮助你深入理解SpringMVC,并在实际项目中灵活运用这些知识!