【SpringMVC 进阶】拦截器、文件上传、异常处理与 SSM 整合全解析

前言

SpringMVC 作为主流的 Web 开发框架,在企业级应用中占据重要地位。本文将从实际开发场景出发,详细讲解 SpringMVC 核心进阶知识点:拦截器(登录校验)、文件上传、全局异常处理器,以及 SSM(Spring+SpringMVC+MyBatis)整合全过程,附带完整代码示例,助力快速上手实战。

一、拦截器(Interceptor)

1.1 什么是拦截器?

Spring MVC 中的拦截器类似于 Servlet 中的过滤器(Filter),主要用于拦截用户请求并做自定义处理(如权限验证、登录状态校验、日志记录等)。它依赖 Web 框架,基于 Java 反射机制实现,属于 AOP 编程思想的典型应用。

1.2 自定义基础拦截器

步骤 1:创建拦截器类

实现 HandlerInterceptor 接口,重写核心方法:

java 复制代码
package com.hg.interceptor;

import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

public class CustomHandlerInterceptor implements HandlerInterceptor {
    /**
     * 控制器方法调用前执行(核心)
     * @return true:继续执行(下一个拦截器/处理器);false:中断后续操作
     */
    @Override
    public boolean preHandle(HttpServletRequest request,
                      HttpServletResponse response, Object object) throws Exception {
        System.out.println("HandlerInterceptor preHandle ....");
        return true;
    }

    /**
     * 控制器方法调用后、视图解析前执行
     * 可修改视图/模型数据(如添加全局公共数据)
     */
    @Override
    public void postHandle(HttpServletRequest request,HttpServletResponse response, 
                         Object object, ModelAndView modelAndView) throws Exception {
        System.out.println("HandlerInterceptor postHandle ....");
    }

    /**
     * 整个请求完成(视图渲染结束)后执行
     * 用于资源清理、日志记录等
     */
    @Override
    public void afterCompletion(HttpServletRequest request,
        HttpServletResponse response,Object object, Exception e) throws Exception {
        System.out.println("HandlerInterceptor afterCompletion ....");
    }
}
步骤 2:配置拦截器(springmvc.xml)
XML 复制代码
<!-- 配置拦截器 -->
<mvc:interceptors>
    <mvc:interceptor>
        <!-- 匹配所有URL -->
        <mvc:mapping path="/**"/>
        <!-- 拦截器类路径 -->
        <bean class="com.hg.interceptor.CustomHandlerInterceptor"/>
    </mvc:interceptor>
</mvc:interceptors>
步骤 3:测试

编写 Controller:

java 复制代码
@Controller
@RequestMapping("/account")
public class AccountController {
    @RequestMapping("/findAccount12")
    public String findAccount12(Model model) {
        model.addAttribute("msg", "欢迎你 springmvc");
        System.out.println("controller的方法执行了......");
        return "success";
    }
}

JSP 超链接:

html 复制代码
<a href="/account/findAccount12">拦截器测试</a>

访问链接后,控制台会依次输出 preHandle → 控制器方法 → postHandleafterCompletion

二、文件上传

2.1 添加依赖(pom.xml)

XML 复制代码
<!-- 文件上传核心依赖 -->
<dependency>
    <groupId>commons-fileupload</groupId>
    <artifactId>commons-fileupload</artifactId>
    <version>1.3.1</version>
</dependency>

2.2 配置文件上传解析器(springmvc.xml)

注意:id 必须为 multipartResolver

XML 复制代码
<bean id="multipartResolver" 
      class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
    <!-- 最大上传大小:5MB -->
    <property name="maxUploadSize" value="5242880"/>
    <!-- 编码格式 -->
    <property name="defaultEncoding" value="UTF-8"/>
</bean>

<!-- 静态资源映射(可选,用于访问上传后的文件) -->
<mvc:resources mapping="/head/**" location="/head/"/>

2.3 编写上传接口

java 复制代码
@Controller
@RequestMapping("/account")
public class AccountController {
    @RequestMapping(path="/upload")
    public String upload(HttpServletRequest request, 
                         MultipartFile head, Model model) throws IOException {
        System.out.println("springmvc方式的文件上传");
        // 1. 获取上传目录(项目部署路径下的uploads文件夹)
        String path = request.getSession().getServletContext().getRealPath("/uploads");
        // 2. 创建目录(不存在则创建)
        File fileDir = new File(path);
        if(!fileDir.exists()) fileDir.mkdirs();
        // 3. 获取文件名并上传
        String filename = head.getOriginalFilename();
        head.transferTo(new File(fileDir, filename));
        
        model.addAttribute("msg", "文件上传成功!");
        return "success";
    }
}

2.4 前端上传表单

java 复制代码
<form action="/account/upload" method="post" enctype="multipart/form-data">
    文件: <input type="file" name="head"/>
    <input type="submit" value="提交"/>
</form>

关键:表单必须设置 enctype="multipart/form-data",否则无法上传二进制文件。

三、全局异常处理器

3.1 异常处理思路

系统中 DAO、Service、Controller 层的异常统一向上抛出,最终由 SpringMVC 前端控制器交给自定义异常处理器处理,避免直接暴露错误信息到页面,提升用户体验。

3.2 自定义异常处理器

java 复制代码
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.HandlerExceptionResolver;
import org.springframework.web.servlet.ModelAndView;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

@Component // 交给Spring容器管理
public class CustomExceptionResolver implements HandlerExceptionResolver {
    @Override
    public ModelAndView resolveException(HttpServletRequest request,
                                         HttpServletResponse response, 
                                         Object handler, Exception ex) {
        // 1. 创建ModelAndView对象
        ModelAndView mv = new ModelAndView();
        // 2. 封装异常信息
        mv.addObject("message", "系统异常:" + ex.toString());
        // 3. 设置错误页面
        mv.setViewName("error");
        return mv;
    }
}

3.3 测试

java 复制代码
@Controller
@RequestMapping("/account")
public class AccountController {
    @RequestMapping("/findAccount14")
    public String findAccount14(Model model) {
        // 模拟算术异常
        int i = 10 / 0;
        model.addAttribute("msg", "欢迎你 springmvc");
        return "success";
    }
}

JSP 超链接:

html 复制代码
<a href="/account/findAccount14">异常处理器测试</a>

四、SSM 整合(Spring+SpringMVC+MyBatis)

4.1 环境准备

1. 建库建表
sql 复制代码
CREATE TABLE `account` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `name` varchar(20) DEFAULT NULL,
  `money` double DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
2. 核心依赖(pom.xml)
XML 复制代码
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>com.hg</groupId>
    <artifactId>ssm</artifactId>
    <version>1.0-SNAPSHOT</version>
    <packaging>war</packaging>

    <properties>
        <spring.version>5.2.8.RELEASE</spring.version>
        <slf4j.version>1.6.6</slf4j.version>
        <log4j.version>1.2.12</log4j.version>
        <mysql.version>8.0.29</mysql.version>
        <mybatis.version>3.4.5</mybatis.version>
        <druid.version>1.1.0</druid.version>
    </properties>
    
    <dependencies>
        <!-- Spring核心 -->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context</artifactId>
            <version>${spring.version}</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-tx</artifactId>
            <version>${spring.version}</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-jdbc</artifactId>
            <version>${spring.version}</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-webmvc</artifactId>
            <version>${spring.version}</version>
        </dependency>
        
        <!-- MyBatis + 整合包 -->
        <dependency>
            <groupId>org.mybatis</groupId>
            <artifactId>mybatis</artifactId>
            <version>${mybatis.version}</version>
        </dependency>
        <dependency>
            <groupId>org.mybatis</groupId>
            <artifactId>mybatis-spring</artifactId>
            <version>1.3.0</version>
        </dependency>
        
        <!-- 数据库 -->
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>${mysql.version}</version>
        </dependency>
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>druid</artifactId>
            <version>${druid.version}</version>
        </dependency>
        
        <!-- Web相关 -->
        <dependency>
            <groupId>javax.servlet</groupId>
            <artifactId>servlet-api</artifactId>
            <version>2.5</version>
            <scope>provided</scope>
        </dependency>
        <dependency>
            <groupId>jstl</groupId>
            <artifactId>jstl</artifactId>
            <version>1.2</version>
        </dependency>
        
        <!-- 日志 -->
        <dependency>
            <groupId>org.slf4j</groupId>
            <artifactId>slf4j-log4j12</artifactId>
            <version>${slf4j.version}</version>
        </dependency>
    </dependencies>
    
    <build>
        <!-- Tomcat插件 -->
        <plugins>
            <plugin>
                <groupId>org.apache.tomcat.maven</groupId>
                <artifactId>tomcat7-maven-plugin</artifactId>
                <version>2.2</version>
                <configuration>
                    <port>8080</port>
                    <path>/</path>
                </configuration>
            </plugin>
        </plugins>
        
        <!-- 资源扫描(MyBatis映射文件) -->
        <resources>
            <resource>
                <directory>src/main/java</directory>
                <includes>
                    <include>**/*.xml</include>
                </includes>
            </resource>
            <resource>
                <directory>src/main/resources</directory>
            </resource>
        </resources>
    </build>
</project>

4.2 核心配置文件

1. 数据库配置(db.properties)
XML 复制代码
jdbc.driver=com.mysql.cj.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/ssm?useSSL=false&serverTimezone=Asia/Shanghai&characterEncoding=UTF-8
jdbc.username=root
jdbc.password=1111
2. Spring DAO 层配置(applicationContext-dao.xml)
XML 复制代码
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:context="http://www.springframework.org/schema/context"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       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">
    <!-- 加载数据库配置文件 -->
    <context:property-placeholder location="classpath:db.properties"/>
    
    <!-- 德鲁伊连接池 -->
    <bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource" destroy-method="close">
        <property name="url" value="${jdbc.url}"/>
        <property name="username" value="${jdbc.username}"/>
        <property name="password" value="${jdbc.password}"/>
        <property name="driverClassName" value="${jdbc.driver}"/>
        <property name="maxActive" value="10"/>
        <property name="minIdle" value="5"/>
    </bean>
    
    <!-- SqlSessionFactory配置 -->
    <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
        <property name="dataSource" ref="dataSource"/>
        <!-- 实体类别名扫描 -->
        <property name="typeAliasesPackage" value="com.hg.pojo"/>
    </bean>
    
    <!-- Mapper接口扫描 -->
    <bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
        <property name="basePackage" value="com.hg.mapper"/>
        <property name="sqlSessionFactoryBeanName" value="sqlSessionFactory"/>
    </bean>
</beans>
3. 事务配置(applicationContext-tx.xml)
XML 复制代码
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:tx="http://www.springframework.org/schema/tx"
       xmlns:aop="http://www.springframework.org/schema/aop"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
       http://www.springframework.org/schema/beans/spring-beans.xsd
       http://www.springframework.org/schema/tx
       http://www.springframework.org/schema/tx/spring-tx.xsd
       http://www.springframework.org/schema/aop
       https://www.springframework.org/schema/aop/spring-aop.xsd">
    <!-- 事务管理器 -->
    <bean id="transactionManager"
          class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
        <property name="dataSource" ref="dataSource"/>
    </bean>
    
    <!-- 事务通知 -->
    <tx:advice id="txAdvice" transaction-manager="transactionManager">
        <tx:attributes>
            <tx:method name="insert*" propagation="REQUIRED"/>
            <tx:method name="delete*" propagation="REQUIRED"/>
            <tx:method name="update*" propagation="REQUIRED"/>
            <tx:method name="select*" propagation="SUPPORTS" read-only="true"/>
        </tx:attributes>
    </tx:advice>
    
    <!-- 切面配置 -->
    <aop:config>
        <aop:advisor advice-ref="txAdvice"
                     pointcut="execution(* com.hg.service.*.*(..))"/>
    </aop:config>
</beans>
4. Service 层配置(applicationContext-service.xml)
XML 复制代码
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:context="http://www.springframework.org/schema/context"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       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">
    <!-- 扫描Service包 -->
    <context:component-scan base-package="com.hg.service"/>
</beans>
5. SpringMVC 配置(springmvc.xml)
XML 复制代码
<?xml version="1.0" encoding="UTF-8"?>
<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="http://www.springframework.org/schema/beans
       http://www.springframework.org/schema/beans/spring-beans.xsd
       http://www.springframework.org/schema/mvc
       http://www.springframework.org/schema/mvc/spring-mvc.xsd
       http://www.springframework.org/schema/context
       http://www.springframework.org/schema/context/spring-context.xsd">
    <!-- 扫描Controller -->
    <context:component-scan base-package="com.hg.controller"/>
    
    <!-- 视图解析器 -->
    <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
        <property name="prefix" value="/WEB-INF/pages/"/>
        <property name="suffix" value=".jsp"/>
    </bean>
    
    <!-- 开启MVC注解驱动 -->
    <mvc:annotation-driven/>
</beans>
6. Web 配置(web.xml)
XML 复制代码
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
         version="4.0">
    <!-- Spring容器加载 -->
    <context-param>
        <param-name>contextConfigLocation</param-name>
        <param-value>classpath:applicationContext-*.xml</param-value>
    </context-param>
    <listener>
        <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
    </listener>
    
    <!-- 解决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>
    </filter>
    <filter-mapping>
        <filter-name>CharacterEncodingFilter</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping>
    
    <!-- SpringMVC前端控制器 -->
    <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.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>
</web-app>

4.3 业务代码编写

1. 实体类(Account.java)
java 复制代码
package com.hg.pojo;

public class Account {
    private Integer id;
    private String name;
    private Double money;

    // getter/setter/toString 省略
}
2. Mapper 接口 + 映射文件

AccountMapper.java:

java 复制代码
package com.hg.mapper;

import com.hg.pojo.Account;
import java.util.List;

public interface AccountMapper {
    List<Account> selectAccount();
}

AccountMapper.xml:

XML 复制代码
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
        PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.hg.mapper.AccountMapper">
    <select id="selectAccount" resultType="Account">
        select * from account
    </select>
</mapper>
3. Service 层

AccountService.java:

java 复制代码
package com.hg.service;

import com.hg.pojo.Account;
import java.util.List;

public interface AccountService {
    List<Account> selectAccount();
}

AccountServiceImpl.java:

java 复制代码
package com.hg.service.impl;

import com.hg.mapper.AccountMapper;
import com.hg.pojo.Account;
import com.hg.service.AccountService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.List;

@Service
public class AccountServiceImpl implements AccountService {
    @Autowired
    private AccountMapper accountMapper;

    @Override
    public List<Account> selectAccount() {
        return accountMapper.selectAccount();
    }
}
4. Controller 层
java 复制代码
package com.hg.controller;

import com.hg.pojo.Account;
import com.hg.service.AccountService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;

import java.util.List;

@Controller
@RequestMapping("/account")
public class AccountController {
    @Autowired
    private AccountService accountService;

    @RequestMapping("/selectAccount")
    public String selectAccount(Model model){
        List<Account> list = accountService.selectAccount();
        model.addAttribute("list", list);
        return "select_account";
    }
}
5. 前端页面(select_account.jsp)
java 复制代码
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<html>
<head>
    <title>账户列表</title>
</head>
<body>
<h2>查询所有账户</h2>
<table width="30%" border="1" cellspacing="0" cellpadding="0">
    <tr>
        <th>id</th>
        <th>name</th>
        <th>money</th>
    </tr>
    <c:forEach var="account" items="${list}">
        <tr>
            <td>${account.id}</td>
            <td>${account.name}</td>
            <td>${account.money}</td>
        </tr>
    </c:forEach>
</table>
</body>
</html>

4.4 测试

启动 Tomcat,访问 http://localhost:8080/account/selectAccount,即可看到数据库中的账户列表。

五、拓展作业(实战强化)

  1. 基于登录拦截器实现完整的 "登录 - 注册" 流程;
  2. 结合文件上传功能,实现用户头像上传并关联到账户信息;
  3. 为 SSM 整合项目添加全局异常处理,捕获数据库 / 业务异常;
  4. 优化登录拦截器,排除登录 / 注册接口(避免死循环);
  5. 为 Account 表添加create_time(开户日期)字段,实现日期的新增 / 查询。

总结

本文从 SpringMVC 核心进阶特性入手,逐步讲解了拦截器、文件上传、异常处理器的实现逻辑,并完整梳理了 SSM 整合的全流程。这些知识点是企业级 Web 开发的核心,掌握后可快速搭建规范的 Java Web 项目。建议结合作业动手实践,加深对知识点的理解与运用。

相关推荐
無限進步D12 小时前
Java 运行原理
java·开发语言·入门
難釋懷12 小时前
安装Canal
java
是苏浙12 小时前
JDK17新增特性
java·开发语言
不光头强12 小时前
spring cloud知识总结
后端·spring·spring cloud
GetcharZp15 小时前
告别 Python 依赖!用 LangChainGo 打造高性能大模型应用,Go 程序员必看!
后端
阿里加多15 小时前
第 4 章:Go 线程模型——GMP 深度解析
java·开发语言·后端·golang
likerhood15 小时前
java中`==`和`.equals()`区别
java·开发语言·python
小小李程序员16 小时前
Langchain4j工具调用获取不到ThreadLocal
java·后端·ai