Spring Web MVC从入门到实战

一、Spring Web MVC核心概念

Spring Web MVC是Spring框架的Web模块,基于MVC设计模式构建,通过DispatcherServlet作为前端控制器统一处理请求,实现了Web层的职责解耦。其核心优势包括:清晰的角色划分、强大的扩展性、与Spring生态的无缝集成、支持RESTful风格以及灵活的数据绑定机制。

1.1 核心组件架构

Spring MVC的核心架构包括以下关键组件:

  • DispatcherServlet:前端控制器,接收所有HTTP请求并分发到对应的处理器
  • HandlerMapping:请求映射器,根据URL路径匹配对应的控制器方法
  • HandlerAdapter:处理器适配器,支持多种类型的控制器
  • Controller:页面控制器,处理业务逻辑并返回模型数据
  • ViewResolver:视图解析器,将逻辑视图名解析为实际视图对象
  • ModelAndView:封装模型数据和视图名称的容器

1.2 请求处理流程

Spring MVC处理请求的完整流程如下:

  1. 用户发送请求到DispatcherServlet
  2. DispatcherServlet委托HandlerMapping查找处理器
  3. HandlerMapping返回HandlerExecutionChain(包含处理器和拦截器)
  4. DispatcherServlet调用HandlerAdapter适配处理器
  5. HandlerAdapter执行控制器方法并返回ModelAndView
  6. ViewResolver解析逻辑视图名得到具体视图
  7. 视图渲染并将响应返回给用户

二、开发环境搭建

2.1 Maven项目配置

创建Maven Web项目,在pom.xml中添加核心依赖:

<dependencies>
    <!-- Spring MVC核心依赖 -->
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-webmvc</artifactId>
        <version>5.3.25</version>
    </dependency>
    
    <!-- Servlet API -->
    <dependency>
        <groupId>javax.servlet</groupId>
        <artifactId>javax.servlet-api</artifactId>
        <version>4.0.1</version>
        <scope>provided</scope>
    </dependency>
    
    <!-- JSTL标签库 -->
    <dependency>
        <groupId>javax.servlet</groupId>
        <artifactId>jstl</artifactId>
        <version>1.2</version>
    </dependency>
</dependencies>

2.2 web.xml配置

配置DispatcherServlet作为前端控制器:

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

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

2.3 Spring MVC配置文件

创建spring-mvc.xml配置文件:

<?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:annotation-driven/>
    
    <!-- 静态资源处理 -->
    <mvc:default-servlet-handler/>
    
    <!-- 视图解析器 -->
    <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
        <property name="prefix" value="/WEB-INF/views/"/>
        <property name="suffix" value=".jsp"/>
    </bean>
</beans>

三、控制器开发

3.1 控制器注解

Spring MVC提供了丰富的注解来简化控制器开发:

@Controller
@RequestMapping("/user")
public class UserController {
    
    // GET请求映射
    @GetMapping("/list")
    public String listUsers(Model model) {
        List<User> users = userService.getAll();
        model.addAttribute("users", users);
        return "user/list";
    }
    
    // POST请求映射
    @PostMapping("/add")
    public String addUser(@Valid User user, BindingResult result) {
        if (result.hasErrors()) {
            return "user/form";
        }
        userService.save(user);
        return "redirect:/user/list";
    }
    
    // RESTful风格API
    @GetMapping("/{id}")
    @ResponseBody
    public ResponseEntity<User> getUserById(@PathVariable Long id) {
        User user = userService.findById(id);
        return ResponseEntity.ok(user);
    }
}

3.2 常用注解说明

  • @Controller:标识该类为控制器
  • @RestController:@Controller + @ResponseBody的组合,适用于REST API
  • @RequestMapping:映射请求路径,可指定HTTP方法
  • @GetMapping/@PostMapping:特定HTTP方法的快捷方式
  • @PathVariable:获取URL路径参数
  • @RequestParam:获取请求参数
  • @RequestBody:获取请求体中的JSON数据
  • @ResponseBody:将返回值直接作为响应体

四、数据绑定与验证

4.1 数据绑定方式

Spring MVC支持多种数据绑定方式:

@PostMapping("/register")
public String register(
    @RequestParam("username") String username,  // 获取单个参数
    @RequestParam String password,             // 参数名与方法参数名一致
    @ModelAttribute User user,                 // 绑定到POJO对象
    @RequestBody UserDTO userDTO               // 绑定JSON请求体
) {
    // 业务逻辑
    return "success";
}

4.2 数据验证

使用Bean Validation进行数据校验:

@Data
public class User {
    @NotBlank(message = "用户名不能为空")
    @Size(min = 3, max = 20, message = "用户名长度3-20位")
    private String username;
    
    @NotBlank(message = "密码不能为空")
    @Size(min = 6, max = 20, message = "密码长度6-20位")
    private String password;
    
    @Email(message = "邮箱格式不正确")
    private String email;
}

@PostMapping("/save")
public String saveUser(@Valid User user, BindingResult result) {
    if (result.hasErrors()) {
        return "user/form";
    }
    userService.save(user);
    return "redirect:/user/list";
}

五、视图技术

5.1 JSP视图

配置视图解析器后,控制器返回逻辑视图名:

@GetMapping("/detail/{id}")
public String userDetail(@PathVariable Long id, Model model) {
    User user = userService.findById(id);
    model.addAttribute("user", user);
    return "user/detail";  // 对应/WEB-INF/views/user/detail.jsp
}

5.2 Thymeleaf集成

添加Thymeleaf依赖:

<dependency>
    <groupId>org.thymeleaf</groupId>
    <artifactId>thymeleaf-spring5</artifactId>
    <version>3.0.15.RELEASE</version>
</dependency>

配置Thymeleaf视图解析器:

<bean id="templateResolver" class="org.thymeleaf.spring5.templateresolver.SpringResourceTemplateResolver">
    <property name="prefix" value="/WEB-INF/templates/"/>
    <property name="suffix" value=".html"/>
    <property name="templateMode" value="HTML5"/>
    <property name="characterEncoding" value="UTF-8"/>
</bean>

<bean id="templateEngine" class="org.thymeleaf.spring5.SpringTemplateEngine">
    <property name="templateResolver" ref="templateResolver"/>
</bean>

<bean class="org.thymeleaf.spring5.view.ThymeleafViewResolver">
    <property name="templateEngine" ref="templateEngine"/>
    <property name="characterEncoding" value="UTF-8"/>
</bean>

六、拦截器与过滤器

6.1 拦截器实现

自定义拦截器实现HandlerInterceptor接口:

public class AuthInterceptor implements HandlerInterceptor {
    
    @Override
    public boolean preHandle(HttpServletRequest request, 
                           HttpServletResponse response, 
                           Object handler) throws Exception {
        // 前置处理,返回true放行,false拦截
        String token = request.getHeader("Authorization");
        if (token == null || !token.startsWith("Bearer ")) {
            response.sendError(HttpStatus.UNAUTHORIZED.value(), "未授权");
            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 {
        // 最终处理,请求完成后执行
    }
}

6.2 拦截器配置

在Spring配置文件中注册拦截器:

<mvc:interceptors>
    <mvc:interceptor>
        <mvc:mapping path="/api/**"/>
        <mvc:exclude-mapping path="/api/auth/**"/>
        <bean class="com.example.interceptor.AuthInterceptor"/>
    </mvc:interceptor>
</mvc:interceptors>

6.3 过滤器与拦截器区别

特性 过滤器(Filter) 拦截器(Interceptor)
归属 Servlet规范 Spring MVC框架
作用范围 所有请求 仅Spring MVC请求
执行时机 请求前/响应后 控制器方法前后
依赖容器 依赖Servlet容器 不依赖Servlet容器
访问能力 不能访问Spring Bean 可以访问Spring Bean

七、异常处理

7.1 全局异常处理器

使用@ControllerAdvice实现全局异常处理:

@ControllerAdvice
public class GlobalExceptionHandler {
    
    // 处理参数校验异常
    @ExceptionHandler(MethodArgumentNotValidException.class)
    @ResponseStatus(HttpStatus.BAD_REQUEST)
    public ResponseEntity<ErrorResponse> handleValidationException(
        MethodArgumentNotValidException ex) {
        
        List<String> errors = ex.getBindingResult()
            .getFieldErrors()
            .stream()
            .map(error -> error.getField() + ": " + error.getDefaultMessage())
            .collect(Collectors.toList());
        
        ErrorResponse response = new ErrorResponse(
            "VALIDATION_FAILED", 
            "参数校验失败", 
            errors
        );
        return ResponseEntity.badRequest().body(response);
    }
    
    // 处理业务异常
    @ExceptionHandler(BusinessException.class)
    public ResponseEntity<ErrorResponse> handleBusinessException(BusinessException ex) {
        ErrorResponse response = new ErrorResponse(
            ex.getCode(), 
            ex.getMessage()
        );
        return ResponseEntity.status(ex.getStatus()).body(response);
    }
    
    // 处理其他异常
    @ExceptionHandler(Exception.class)
    @ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
    public ResponseEntity<ErrorResponse> handleException(Exception ex) {
        ErrorResponse response = new ErrorResponse(
            "INTERNAL_ERROR", 
            "系统内部错误"
        );
        return ResponseEntity.internalServerError().body(response);
    }
}

7.2 自定义异常

定义业务异常类:

public class BusinessException extends RuntimeException {
    private final int code;
    private final HttpStatus status;
    
    public BusinessException(int code, String message) {
        super(message);
        this.code = code;
        this.status = HttpStatus.BAD_REQUEST;
    }
    
    public BusinessException(int code, String message, HttpStatus status) {
        super(message);
        this.code = code;
        this.status = status;
    }
    
    // getter方法
}

八、RESTful API开发

8.1 RESTful设计原则

  • 资源标识:使用URI标识资源,如/users/{id}
  • HTTP方法:GET获取、POST创建、PUT更新、DELETE删除
  • 状态码:使用合适的HTTP状态码表示请求结果
  • 无状态:每个请求包含足够信息,不依赖会话状态

8.2 RESTful控制器

@RestController
@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);
    }
    
    // 根据ID获取用户
    @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.setId(id);
        User updatedUser = userService.update(user);
        return ResponseEntity.ok(updatedUser);
    }
    
    // 删除用户
    @DeleteMapping("/{id}")
    public ResponseEntity<Void> deleteUser(@PathVariable Long id) {
        userService.deleteById(id);
        return ResponseEntity.noContent().build();
    }
}

九、文件上传与下载

9.1 文件上传

配置MultipartResolver:

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

控制器处理文件上传:

@PostMapping("/upload")
public String uploadFile(@RequestParam("file") MultipartFile file) {
    if (file.isEmpty()) {
        return "redirect:/upload?error=文件为空";
    }
    
    try {
        // 获取文件名
        String fileName = file.getOriginalFilename();
        // 保存文件
        file.transferTo(new File("/uploads/" + fileName));
        return "redirect:/upload?success=上传成功";
    } catch (IOException e) {
        return "redirect:/upload?error=上传失败";
    }
}

9.2 文件下载

@GetMapping("/download/{fileName}")
public ResponseEntity<Resource> downloadFile(@PathVariable String fileName) {
    try {
        // 加载文件
        Resource resource = new FileSystemResource("/uploads/" + fileName);
        
        // 设置响应头
        HttpHeaders headers = new HttpHeaders();
        headers.add(HttpHeaders.CONTENT_DISPOSITION, 
                   "attachment; filename=\"" + fileName + "\"");
        headers.add(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_OCTET_STREAM_VALUE);
        
        return ResponseEntity.ok()
                .headers(headers)
                .contentLength(resource.contentLength())
                .body(resource);
    } catch (Exception e) {
        return ResponseEntity.notFound().build();
    }
}

十、性能优化

10.1 启动优化

  • 减少Bean数量:使用@Lazy进行懒加载
  • 缩小包扫描范围:精确指定@ComponentScan的basePackage
  • 开启预加载:使用spring-context-indexer加速启动

10.2 响应优化

  • 启用缓存:使用@Cacheable缓存热点数据
  • 异步处理:使用@Async处理耗时操作
  • 连接池优化:配置数据库连接池参数
  • 静态资源缓存:配置Cache-Control响应头

10.3 数据库优化

  • 读写分离:主从数据库架构
  • 分库分表:大数据量场景
  • 索引优化:合理设计数据库索引
  • 批量操作:使用batchUpdate减少事务提交次数

十一、实战项目:用户管理系统

11.1 项目结构

src/main/java/
├── com.example
│   ├── config/          # 配置类
│   ├── controller/       # 控制器层
│   ├── service/          # 服务层
│   ├── repository/       # 数据访问层
│   ├── model/           # 实体类
│   ├── dto/             # 数据传输对象
│   ├── exception/       # 异常类
│   └── interceptor/     # 拦截器
src/main/resources/
├── application.yml      # 配置文件
├── static/             # 静态资源
└── templates/           # 模板文件

11.2 核心功能实现

用户控制器

@RestController
@RequestMapping("/api/users")
public class UserController {
    
    @Autowired
    private UserService userService;
    
    @GetMapping
    public ResponseEntity<PageResult<User>> getUsers(
            @RequestParam(defaultValue = "1") int page,
            @RequestParam(defaultValue = "10") int size) {
        Page<User> userPage = userService.findAll(page, size);
        return ResponseEntity.ok(PageResult.of(userPage));
    }
    
    @PostMapping
    public ResponseEntity<User> createUser(@Valid @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, 
                                         @Valid @RequestBody User user) {
        user.setId(id);
        User updatedUser = userService.update(user);
        return ResponseEntity.ok(updatedUser);
    }
    
    @DeleteMapping("/{id}")
    public ResponseEntity<Void> deleteUser(@PathVariable Long id) {
        userService.deleteById(id);
        return ResponseEntity.noContent().build();
    }
}

全局异常处理

@ControllerAdvice
public class GlobalExceptionHandler {
    
    @ExceptionHandler(MethodArgumentNotValidException.class)
    public ResponseEntity<ErrorResponse> handleValidationException(
            MethodArgumentNotValidException ex) {
        List<String> errors = ex.getBindingResult()
                .getFieldErrors()
                .stream()
                .map(error -> error.getField() + ": " + error.getDefaultMessage())
                .collect(Collectors.toList());
        
        ErrorResponse response = new ErrorResponse(
                "VALIDATION_FAILED", 
                "参数校验失败", 
                errors
        );
        return ResponseEntity.badRequest().body(response);
    }
    
    @ExceptionHandler(ResourceNotFoundException.class)
    public ResponseEntity<ErrorResponse> handleResourceNotFound(
            ResourceNotFoundException ex) {
        ErrorResponse response = new ErrorResponse(
                "NOT_FOUND", 
                ex.getMessage()
        );
        return ResponseEntity.status(HttpStatus.NOT_FOUND).body(response);
    }
}

十二、总结

Spring Web MVC作为企业级Java Web开发的首选框架,通过本文的系统学习,您已经掌握了从基础概念到实战项目的完整知识体系。关键要点包括:

  1. 核心架构:理解DispatcherServlet、HandlerMapping、HandlerAdapter等核心组件的工作原理
  2. 控制器开发:熟练掌握@Controller、@RequestMapping等注解的使用
  3. 数据绑定:掌握@RequestParam、@RequestBody、@PathVariable等参数绑定方式
  4. 异常处理:使用@ControllerAdvice实现全局异常统一处理
  5. RESTful API:遵循RESTful设计原则开发规范的API接口
  6. 性能优化:掌握启动优化、响应优化、数据库优化等技巧

通过实际项目实践,您可以将理论知识转化为实际开发能力,构建出高性能、可维护的企业级Web应用。

 

版权声明:本文为JienDa博主的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
若内容若侵犯到您的权益,请发送邮件至:platform_service@jienda.com我们将第一时间处理!
所有资源仅限于参考和学习,版权归JienDa作者所有,更多请访问JienDa首页。

给TA赞助
共{{data.count}}人
人已赞助
后端

Web虚拟卡销售店铺实现方案

2025-12-19 21:44:16

后端

PHP+MYSQL+HTML实现在线购物商城,基于php的电商系统,电子商务网站,零食购物商城

2025-12-19 21:54:50

0 条回复 A文章作者 M管理员
    暂无讨论,说说你的看法吧
个人中心
购物车
优惠劵
今日签到
有新私信 私信列表
搜索