SpringMVC系列十一: 文件上传与自定义拦截器

文章目录

上一讲, 我们学习的是 SpringMVC系列十: 中文乱码处理与JSON处理

现在打开springmvc项目

SpringMVC文件上传

基本介绍

1.Spring MVC 为文件上传提供了直接的支持, 这种支持是通过即插即用的 MultipartResolver 实现的. SpringJakata Commons FileUpload 技术实现了一个 MultipartResolver 实现类: CommonsMultipartResolver

2.SpringMVC 上下文中默认没有装配 Multipartresolver , 因此默认情况下不能处理文件的上传工作, 如果想使用 Spring 的文件上传功能, 需现在上下文中配置 MultipartResolver

需求分析 / 图解

应用实例-代码实现

1.引入springmvc 文件上传需要的jarspingmvc上传文件需要的jar

2.在web路径下创建fileUpload.jsp

html 复制代码
<body>
<h1>文件上传的演示</h1>
<form action="?" method="post" enctype="multipart/form-data">
    文件介绍:<input type="text" name="introduce"/><br/>
    选择文件:<input type="file" name="file"/><br/>
    <input type="submit" value="上传文件"/>
</form>
</body>

3.配置文件过滤器, 在web.xml中, 使用Spring 提供的, 前面已经配置过了 传送

4.配置文件上传解析器, 在springDispatcherServlet-servlet.xml , 简单看一下CommonsMultipartResolver源码

xml 复制代码
<!--配置文件上传需要的bean-->
<bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver"></bean>

5.在com.zzw.web.fileupload下新建FileUploadHandler.java

java 复制代码
 * @author 赵志伟
 * @version 1.0
 * 处理文件上传的handler
 */
@SuppressWarnings({"all"})
@Controller
public class FileUploadHandler {

    //编写方法, 处理文件上传的请求
    @RequestMapping(value = "/fileUpload")
    public String fileUpload(@RequestParam(value = "file") MultipartFile file,
                             HttpServletRequest request, String introduce) throws IOException {
        //接收到提交的文件名
        String originalFilename = file.getOriginalFilename();
        System.out.println("你上传的文件名=" + originalFilename);
        System.out.println("文件的介绍=" + introduce);
        //得到要把上传的文件保存到哪个路径[全路径: 包括文件名]
        String fileFullPath =
                request.getServletContext().getRealPath("/img/" + originalFilename);
        //创建文件
        File saveToFile = new File(fileFullPath);
        //将上传的文件, 转存到saveToFile
        file.transferTo(saveToFile);
        return "success";
    }
}

6.回填``fileUpload.jspaction`

html 复制代码
<form action="<%=request.getServletContext()%>/fileUpload" method="post" enctype="multipart/form-data">

7.完成测试[页面方式], 看文件是否成功上传 http://localhost:8088/springmvc/fileUpload.jsp

简单地debug一下transferTo()


8.完成测试[postman方式]


自定义拦截器

什么是拦截器

●说明

1.Spring MVC 也可以使用拦截器对请求进行拦截处理, 用户可以自定义拦截器来实现特定的功能.

2.自定义的拦截器必须实现HandlerInterceptor接口

●自定义拦截器的三个方法

1.preHandle(): 这个方法在业务处理器处理请求之前被调用, 在该方法中对用户请求 request 进行处理.

2.postHandler(): 这个方法在目标方法处理完请求后执行

3.afterCompletion(): 这个方法在完全处理完请求后被调用, 可以在该方法中进行一些资源清理的操作.

自定义拦截器执行流程分析图

●自定义拦截器执行流程说明

1.如果 preHandle 方法, 返回 false , 则不再执行目标方法, 可以在此指定返回页面

2.postHandle 在目标方法被执行后执行, 可以在方法中访问到目标方法返回的 ModelAndView 对象

3.若 preHandle 返回 true , 则 afterCompletion 方法, 在渲染视图之后被执行

4.若 preHandle 返回 false , 则 afterCompletion 方法不会被调用

5.在配置拦截器时, 可以指定该拦截器对哪些请求生效, 哪些请求不生效

自定义拦截器应用实例

快速入门

●应用实例需求

完成一个自定义拦截器, 学习一下如何配置拦截器和拦截器的运行流程

●应用实例-代码实现

1.com.zzw.web.interceptor包下新建MyInterceptor01.java

java 复制代码
@Component
public class MyInterceptor01 implements HandlerInterceptor {

    /**
     * 解读
     * 1. preHandle() 在目标方法执行前被执行
     * 2. 如果preHandle() 返回false, 不再执行目标方法
     * 3. 该方法可以获取到request, response, handler
     * 4. 这里根据业务, 可以进行拦截, 并指定跳转到哪个页面
     *
     * @param request  current HTTP request
     * @param response current HTTP response
     * @param handler  chosen handler to execute, for type and/or instance evaluation
     * @return
     * @throws Exception
     */
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        System.out.println("--MyInterceptor01-- preHandle() 被执行...");
        return true;
    }


    /**
     * 解读
     * 1. 在目标方法执行后, 会执行postHandle
     * 2. 该方法可以获取到 目标方法, 返回的ModelAndView
     *
     * @param request      current HTTP request
     * @param response     current HTTP response
     * @param handler      the handler (or {@link HandlerMethod}) that started asynchronous
     *                     execution, for type and/or instance examination
     * @param modelAndView the {@code ModelAndView} that the handler returned
     *                     (can also be {@code null})
     * @throws Exception
     */
    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
        System.out.println("--MyInterceptor01-- postHandle()被执行...");

    }

    /**
     * 解读
     * 1. afterCompletion() 在视图渲染后被执行, 这里可以进行资源清理工作
     * 2.
     *
     * @param request  current HTTP request
     * @param response current HTTP response
     * @param handler  the handler (or {@link HandlerMethod}) that started asynchronous
     *                 execution, for type and/or instance examination
     * @param ex       any exception thrown on handler execution, if any; this does not
     *                 include exceptions that have been handled through an exception resolver
     * @throws Exception
     */
    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
        System.out.println("--MyInterceptor01-- afterCompletion()被执行...");

    }
}

2.在springDispatcherServlet-servlet.xml 配置拦截器

注意: 拦截器是由spring管理的 ; 过滤器是由web.xml管理的

xml 复制代码
<!--配置自定义拦截器-spring配置文件-->
<mvc:interceptors>
    <!--
    解读
    1. 第一种配置方式
    2. 使用ref 引用到对应的拦截器myInterceptor01
    3. 这种方式, 会拦截所有的目标方法
    -->
    <ref bean="myInterceptor01"/>
</mvc:interceptors>

<!--加入两个常规配置-->
<!--支持SpringMVC的高级功能, 比如JSR303校验, 映射动态请求-->
<mvc:annotation-driven></mvc:annotation-driven>
<!--将springmvc不能处理的请求, 交给tomcat处理, 比如css, js-->
<mvc:default-servlet-handler/>

3.在com.zzw.ewb.interceptor包 下新建FurnHandler.java

java 复制代码
@Controller
public class FurnHandler {

    @RequestMapping(value = "/hi")
    public String hi() {
        System.out.println("--FurnHandler-- hi()...");
        return "success";
    }

    @RequestMapping(value = "/hello")
    public String hello() {
        System.out.println("--FurnHandler-- hello()...");
        return "success";
    }
}

4.web路径下创建interceptor.jsp

html 复制代码
<head>
    <title>测试自定义拦截器</title>
</head>
<body>
<h1>测试自定义拦截器</h1>
<a href="<%=request.getContextPath()%>/hi">测试自定义拦截器-hi</a><br/><br/>
<a href="<%=request.getContextPath()%>>/hello">测试自定义拦截器-hello</a>
</body>

5.测试

浏览器测试 http://localhost:8088/springmvc/interceptor.jsp


--MyInterceptor01-- preHandle() 被执行...
--FurnHandler-- hi()...
--MyInterceptor01-- postHandle()被执行...
--MyInterceptor01-- afterCompletion()被执行...

--MyInterceptor01-- preHandle() 被执行...
--FurnHandler-- hello()...
--MyInterceptor01-- postHandle()被执行...
--MyInterceptor01-- afterCompletion()被执行...

postman测试


--MyInterceptor01-- preHandle() 被执行...
--FurnHandler-- hi()...
--MyInterceptor01-- postHandle()被执行...
--MyInterceptor01-- afterCompletion()被执行...

--MyInterceptor01-- preHandle() 被执行...
--FurnHandler-- hello()...
--MyInterceptor01-- postHandle()被执行...
--MyInterceptor01-- afterCompletion()被执行...

注意事项和细节

1.默认配置是将所有的目标方法都进行拦截, 也可以指定拦截目标方法, 比如只拦截hi

xml 复制代码
<!--配置自定义拦截器-spring配置文件-->
<mvc:interceptors>
    <!--
    解读
    1. 第二种配置方式
    2. mvc:mapping path="/hi" 指定要拦截的路径
    3. ref bean="myInterceptor01" 指定对哪个拦截器进行配置
    -->
    <mvc:interceptor>
        <mvc:mapping path="/hi"/>
        <ref bean="myInterceptor01"/>
    </mvc:interceptor>
</mvc:interceptors>

2.mvc:mapping 支持通配符, 同时指定不对哪些目标方法进行拦截

xml 复制代码
<!--配置自定义拦截器-spring配置文件-->
<mvc:interceptors>
    <!--解读
    1. 第三种配置方式
    2. mvc:mapping path="/h*" 通配符方式 表示拦截 /h 打头的路径
    3. mvc:exclude-mapping path="/hello" /hello不拦截
    4. ref bean="myInterceptor01" 指定对哪个拦截器配置
    -->
    <mvc:interceptor>
        <mvc:mapping path="/h*"/>
        <mvc:exclude-mapping path="/hello"/>
        <ref bean="myInterceptor01"/>
    </mvc:interceptor>
</mvc:interceptors>

FurnHandler添加方法

java 复制代码
@RequestMapping(value = "/ok")
public String ok() {
    System.out.println("--FurnHandler-- ok()...");
    return "success";
}

interceptor.jsp添加标签

html 复制代码
<a href="<%=request.getContextPath()%>/ok">测试自定义拦截器-ok</a>

3.拦截器需要配置才生效, 不配置是不生效的.

4.如果preHandler() 方法返回了false , 就不会执行目标方法(前提是你的目标方法被拦截了), 程序员可以在这里根据业务需要指定跳转页面.

Debug执行流程

1.prehandle()

2.目标方法

3.postHandle()

视图解析

一直点下一步

4.render()

5.afterCompletion()

解释一下model数据怎么来的? 用 postman 再走一圈

get请求

post请求

断点打到 preHandle

目标方法

postHandle

render

afterCompletion

多个拦截器

多个拦截器执行流程示意图

应用实例1

代码实现

1.com.zzw.web.interceptor.MyInterceptor02

java 复制代码
@Component
public class MyInterceptor02 implements HandlerInterceptor {

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response,
                             Object handler) throws Exception {
        System.out.println("--MyInterceptor02-- preHandle() 被执行...");
        return true;
    }

    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response,
                           Object handler, ModelAndView modelAndView) throws Exception {
        System.out.println("--MyInterceptor02-- postHandle()被执行...");
    }

    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response,
                                Object handler, Exception ex) throws Exception {
        System.out.println("--MyInterceptor02-- afterCompletion()被执行...");
    }
}

2.配置springDispathcerServlet-servlet.xml

xml 复制代码
<mvc:interceptors>
    <mvc:interceptor>
        <mvc:mapping path="/h*"/>
        <mvc:exclude-mapping path="/hello"/>
        <ref bean="myInterceptor01"/>
    </mvc:interceptor>

    <!--解读
    1.配置的第二个拦截器
    2.多个拦截器在执行时, 是按照顺序执行的
    -->
    <mvc:interceptor>
        <mvc:mapping path="/h*"/>
        <ref bean="myInterceptor02"/>
    </mvc:interceptor>
</mvc:interceptors>

3.测试
--MyInterceptor01-- preHandle() 被执行...
--MyInterceptor02-- preHandle() 被执行...
--FurnHandler-- hi()...
--MyInterceptor02-- postHandle()被执行...
--MyInterceptor01-- postHandle()被执行...
--MyInterceptor02-- afterCompletion()被执行...
--MyInterceptor01-- afterCompletion()被执行...

注意事项和细节

1.如果第1 个拦截器的preHandle()返回false , 后面都不执行

2.如果第2 个拦截器的preHandle()返回false , 就直接执行第1 个拦截器的afterCompletion() 方法, 如果拦截器更多, 规则类似.

3.说明: 前面说的规则, 目标方法被拦截是前提

应用实例2

1.需求: 如果用户提交的数据有禁用词(比如 病毒). 则, 在第1个拦截器就返回, 不执行目标方法, 功能效果如图

2.web路径/WEB-INF/pages/warning.jsp

html 复制代码
<head>
    <title>警告</title>
</head>
<body>
<h1>不要乱讲话</h1>
</body>

3.修改MyInterceptor01

java 复制代码
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response,
                         Object handler) throws Exception {
    System.out.println("--MyInterceptor01-- preHandle() 被执行...");
    //获取到用户提交的关键字
    String keyword = request.getParameter("keyword");
    if ("病毒".equals(keyword)) {
        //请求转发到warning.jsp
        //这里是原生的请求转发, 不是springmvc里的
        request.getRequestDispatcher("/WEB-INF/pages/warning.jsp").forward(request, response);
        return false;
    }
    System.out.println("得到keyword=" + keyword);
    return true;
}

3.postman测试

--MyInterceptor01-- preHandle() 被执行...
得到keyword=赵志伟
--MyInterceptor02-- preHandle() 被执行...
--FurnHandler-- hi()...
--MyInterceptor02-- postHandle()被执行...
--MyInterceptor01-- postHandle()被执行...
--MyInterceptor02-- afterCompletion()被执行...
--MyInterceptor01-- afterCompletion()被执行...

再次测试

--MyInterceptor01-- preHandle() 被执行...

作业布置

1.把前面我们学过的SpringMVC 文件上传, 自定义拦截器和相关代码和案例, 自己写一遍. 一定要自己写一遍, 否则没有印象, 理解不会深入

2.简述SpringMVC 自定义拦截器工作流程, 并画出示意图

3.debug 自定义拦截器源码, 加深理解(不用每一条语句都debug), 重点是梳理流程.

下一讲, 我们学习 SpringMVC系列十一: 文件上传与自定义拦截器

相关推荐
天使day3 分钟前
Maven
java·maven
汇匠源5 分钟前
共享无人系统,从出行到生活全面覆盖
java·生活
小灰灰要减肥1 小时前
装饰者模式
java
张铁铁是个小胖子1 小时前
MyBatis学习
java·学习·mybatis
Yan.love2 小时前
开发场景中Java 集合的最佳选择
java·数据结构·链表
椰椰椰耶2 小时前
【文档搜索引擎】搜索模块的完整实现
java·搜索引擎
大G哥2 小时前
java提高正则处理效率
java·开发语言
智慧老师2 小时前
Spring基础分析13-Spring Security框架
java·后端·spring
lxyzcm2 小时前
C++23新特性解析:[[assume]]属性
java·c++·spring boot·c++23
V+zmm101343 小时前
基于微信小程序的乡村政务服务系统springboot+论文源码调试讲解
java·微信小程序·小程序·毕业设计·ssm