欢迎您访问新疆栾骏商贸有限公司,公司主营电子五金轴承产品批发业务!
全国咨询热线: 400-8878-609

新闻资讯

常见问题

SpringMVC实现文件上传与下载、拦截器、异常处理器等功能

作者:用户投稿2026-01-11 03:47:49
目录
  • 文件下载
  • 文件上传
  • 拦截器
    • 拦截器的配置
    • 多个拦截器的执行顺序
  • 异常处理器
    • 基于配置的异常处理
    • 基于注解的异常处理
  • 总结

    文件下载

    使用ResponseEntity实现下载文件的功能

    index.html

    <!DOCTYPE html>
    <html lang="en" xmlns:th="http:www.thymeleaf.org">
    <head>
        <meta charset="UTF-8">
        <title>首页</title>
    </head>
    <body>
    <a th:href="@{/testDown}" rel="external nofollow" >点击下载</a>
    </body>
    </html>
    

    控制器

    @RequestMapping("/testDown")
    public ResponseEntity<byte[]> testResponseEntity(HttpSession session) throws IOException {
        //获取ServletContext对象
        ServletContext servletContext = session.getServletContext();
    	
        //获取服务器中文件的真实路径
        String realPath = servletContext.getRealPath("/static/img/1.jpg");
    	
        //创建输入流
        InputStream is = new FileInputStream(realPath);
    	
        //创建字节数组
        byte[] bytes = new byte[is.available()];
    	
        //将流读到字节数组中
        is.read(bytes);
    	
        //创建HttpHeaders对象设置响应头信息
        MultiValueMap<String, String> headers = new HttpHeaders();
    	
        //设置要下载方式以及下载文件的名字
        headers.add("Content-Disposition", "attachment;filename=1.jpg");
    	
        //设置响应状态码
        HttpStatus statusCode = HttpStatus.OK;
    	
        //创建ResponseEntity对象
        ResponseEntity<byte[]> responseEntity = new ResponseEntity<>(bytes, headers, statusCode);
    	
        //关闭输入流
        is.close();
    	
        return responseEntity;
    }
    

    注意:如果报500错误,可能是项目中无法找到静态资源文件,需要对项目重新打包。

    文件上传

    文件上传要求form表单的请求方式必须为post,并且添加属性enctype="multipart/form-data"以二进制方式上传

    SpringMVC中将上传的文件封装到MultipartFile对象中,通过此对象可以获取文件相关信息

    上传步骤:

    添加依赖

    <!-- https://mvnrepository.com/artifact/commons-fileupload/commons-fileupload -->
    <dependency>
        <groupId>commons-fileupload</groupId>
        <artifactId>commons-fileupload</artifactId>
        <version>1.3.1</version>
    </dependency>
    

    在SpringMVC的配置文件springMVC.xml中添加配置

    <!--必须通过文件解析器的解析才能将文件转换为MultipartFile对象-->
    <!--必须设置id属性,springMVC是根据id获取,且id必须设置为multipartResolver-->
    <bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver"></bean>
    

    index.html

    <form method="post" th:action="@{/testUp}" enctype="multipart/form-data">
        <input type="file" name="photo">
        <input type="submit" value="上传">
    </form>
    

    控制器

    @RequestMapping("/testUp")
    
    //MultipartFile的形参名必须与index.html中的file标签的name一致
    public String testUp(MultipartFile photo, HttpSession session) throws IOException {
        //获取上传的文件的文件名
        String fileName = photo.getOriginalFilename();
    	
        //处理文件重名问题
        String hzName = fileName.substring(fileName.lastIndexOf("."));
        fileName = UUID.randomUUID().toString() + hzName;
    	
        //获取服务器中photo目录的路径
        ServletContext servletContext = session.getServletContext();
        String photoPath = servletContext.getRealPath("photo");
        File file = new File(photoPath);
        if(!file.exists()){
            file.mkdir();
        }
        String finalPath = photoPath + File.separator + fileName;
    	
        //实现上传功能
        photo.transferTo(new File(finalPath));
        return "success";
    }
    

    拦截器

    拦截器的配置

    SpringMVC中的拦截器用于拦截控制器方法的执行

    SpringMVC中的拦截器需要实现HandlerInterceptor接口

    HandlerInterceptor源码

    public interface HandlerInterceptor {
        default boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
            return true;
        }
    
        default void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, @Nullable ModelAndView modelAndView) throws Exception {
        }
    
        default void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, @Nullable Exception ex) throws Exception {
        }
    }
    

    HandlerInterceptor接口有三个默认方法

    • preHandle:控制器方法执行之前执行preHandle(),其boolean类型的返回值表示是否拦截或放行,返回true为放行,即调用控制器方法;返回false表示拦截,即不调用控制器方法
    • postHandle:控制器方法执行之后执行postHandle()
    • afterCompletion:处理完视图和模型数据,渲染视图完毕之后执行afterCompletion()

    控制器

    FirstInterceptor.java

    public class FirstInterceptor implements HandlerInterceptor {
        public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
            System.out.println("FirstInterceptor-->preHandle");
            return false;
        }
    
        public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
            System.out.println("FirstInterceptor-->postHandle");
        }
    
        public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
            System.out.println("FirstInterceptor-->afterCompletion");
        }
    }
    

    SpringMVC的拦截器必须在SpringMVC的配置文件中进行配置:

    方式一

        <mvc:interceptors>
            <bean class="com.gonghr.springmvc.interceptors.FirstInterceptor"></bean>
        </mvc:interceptors>
    

    输出:

    FirstInterceptor-->preHandle

    方式二

        <mvc:interceptors>
            <ref bean="firstInterceptor"></ref>
        </mvc:interceptors>
    

    注意提前开启注解扫描,并把拦截器放入Ioc容器

    输出:

    FirstInterceptor-->preHandle

    注意:以上两种配置方式都是对DispatcherServlet所处理的所有的请求进行拦截。

    方式三

        <mvc:interceptors>
            <mvc:interceptor>
                <mvc:mapping path="/**"/>  <!--拦截所有请求-->
                <mvc:exclude-mapping path="/"/>  <!--不拦截主页-->
                <ref bean="firstInterceptor"></ref>
            </mvc:interceptor>
        </mvc:interceptors>
    

    可以进入首页

    发送任意请求都会被拦截

    输出:

    FirstInterceptor-->preHandle

    以上配置方式可以通过ref或bean标签设置拦截器,通过mvc:mapping设置需要拦截的请求,通过mvc:exclude-mapping设置需要排除的请求,即不需要拦截的请求

    /**:拦截所有请求

    /*:拦截一级目录的请求

    多个拦截器的执行顺序

    第一个拦截器

    @Component
    public class FirstInterceptor implements HandlerInterceptor {
        public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
            System.out.println("FirstInterceptor-->preHandle");
            return true;
        }
    
        public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
            System.out.println("FirstInterceptor-->postHandle");
        }
    
        public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
            System.out.println("FirstInterceptor-->afterCompletion");
        }
    }
    

    第二个拦截器

    @Component
    public class SecondInterceptor implements HandlerInterceptor {
        public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
            System.out.println("SecondInterceptor-->preHandle");
            return true;
        }
    
        public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
            System.out.println("SecondInterceptor-->postHandle");
        }
    
        public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
            System.out.println("SecondInterceptor-->afterCompletion");
        }
    }
    

    两个拦截器都设置为对任意请求放行。

    输出:

    FirstInterceptor-->preHandle
    SecondInterceptor-->preHandle
    SecondInterceptor-->postHandle
    FirstInterceptor-->postHandle
    SecondInterceptor-->afterCompletion
    FirstInterceptor-->afterCompletion

    • 若每个拦截器的preHandle()都返回true

    此时多个拦截器的执行顺序和拦截器在SpringMVC的配置文件的配置顺序有关:

    preHandle()会按照配置的顺序执行,而postHandle()和afterCompletion()会按照配置的反序执行

    如果设置第一个拦截器对所有请求放行,第二个拦截器对所有请求拦截。

    第一个拦截器

    @Component
    public class FirstInterceptor implements HandlerInterceptor {
        public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
            System.out.println("FirstInterceptor-->preHandle");
            return true;
        }
    
        public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
            System.out.println("FirstInterceptor-->postHandle");
        }
    
        public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
            System.out.println("FirstInterceptor-->afterCompletion");
        }
    }
    

    第二个拦截器

    @Component
    public class SecondInterceptor implements HandlerInterceptor {
        public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
            System.out.println("SecondInterceptor-->preHandle");
            return false;
        }
    
        public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
            System.out.println("SecondInterceptor-->postHandle");
        }
    
        public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
            System.out.println("SecondInterceptor-->afterCompletion");
        }
    }
    

    输出:

    FirstInterceptor-->preHandle
    SecondInterceptor-->preHandle
    FirstInterceptor-->afterCompletion

    • 若某个拦截器的preHandle()返回了false

    preHandle()返回false和它之前的拦截器的preHandle()都会执行,postHandle()都不执行,返回false的拦截器之前的拦截器的afterCompletion()会执行

    异常处理器

    基于配置的异常处理

    SpringMVC提供了一个处理控制器方法执行过程中所出现的异常的接口:HandlerExceptionResolver

    HandlerExceptionResolver接口的实现类有:DefaultHandlerExceptionResolver和SimpleMappingExceptionResolver

    SpringMVC提供了自定义的异常处理器SimpleMappingExceptionResolver,使用方式:

    <bean class="org.springframework.web.servlet.handler.SimpleMappingExceptionResolver">
        <property name="exceptionMappings">
            <props>
            	<!--
            		properties的键表示处理器方法执行过程中出现的异常
            		properties的值表示若出现指定异常时,设置一个新的视图名称,跳转到指定页面
            	-->
                <prop key="java.lang.ArithmeticException">error</prop>
            </props>
        </property>
        <!--
        	exceptionAttribute属性设置一个属性名,将出现的异常信息在请求域中进行共享
        -->
        <property name="exceptionAttribute" value="ex"></property>
    </bean>
    

    error.html

    出现错误
    <p th:text="${ex}"></p>
    

    index.html

    <a th:href="@{/testException}">测试异常处理</a>
    

    基于注解的异常处理

    //@ControllerAdvice将当前类标识为异常处理的组件
    @ControllerAdvice
    public class ExceptionController {
    
        //@ExceptionHandler用于设置所标识方法处理的异常
        @ExceptionHandler(value = {ArithmeticException.class,NullPointerException.class})
        //ex表示当前请求处理中出现的异常对象
        public String handleArithmeticException(Exception ex, Model model){
            model.addAttribute("ex", ex);
            return "error";
        }
    
    }
    

    总结