• SpringMVC的文件上传与SpringMVC的拦截器


    SpringMVC的请求-文件上传-客户端表单实现

    文件上传客户端表单需要满足:

    表单项type=“file”
    
    表单的提交方式是post
    
    表单的enctype属性是多部分表单形式,及enctype=“multipart/form-data”
    <form action="/weather/summer" method="post" enctype="multipart/form-data">
        文件名:<input type="text" name="name"><br/>
        文件:<input type="file" name="fileName"/><br/>
        提交:<input type="submit" value="上传">
    </form>

    文件上传的原理

    1: 当form表单修改为多部分表单时,request.getParameter()将失效

    2: entype="application/x-www-form-urlencoded" 时,form表单的正文内容格式是: key=value&key=value&key=value

    3:当form表单的enctype取值为 multipart/form-data时,请求正文内容就变成多部分形式:

    单文件上传的代码实现

    我们要现在pom.xml中导入文件上传所需要的包

    commons-fileupload工具包与commons-io

    commons-fileupload封装文件上传工具类

    Common IO 是一个工具库,用来帮助开发IO功能(java io操作是开发中比较常用的技术,但是如果每次都使用原生的IO流来操作会显得比较繁琐。)

    <!--   导入文件上传的jar包坐标-->
        <dependency>
          <groupId>commons-fileupload</groupId>
          <artifactId>commons-fileupload</artifactId>
          <version>1.3.1</version>
        </dependency>
        <dependency>
          <groupId>commons-io</groupId>
          <artifactId>commons-io</artifactId>
          <version>2.5</version>
        </dependency>

    在spring.xml中配置多媒体解析器CommonsMultipartResolver

    如果你的前端使用form标签进行值的

    <!-- 定义文件上传解析器 -->
    <!--    配置文件上传解析器,-->  <!--当文件上传解析器未配置的时候,后端的方法是不能从前端的form标签中获取传递来的参数-->
    
    <bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
        <!-- 设定默认编码 -->
        <property name="defaultEncoding" value="UTF-8"></property>
        <!-- 设定文件上传的最大值为5MB,5*1024*1024 -->
        <property name="maxUploadSize" value="5242880"></property>
        <!-- 设定文件上传时写入内存的最大值,如果小于这个参数不会生成临时文件,默认为10240 -->
        <property name="maxInMemorySize" value="40960"></property>
        <!-- 上传文件的临时路径 -->
        <property name="uploadTempDir" value="fileUpload/temp"></property>
        <!-- 延迟文件解析 -->
        <property name="resolveLazily" value="true"/>

    前端程序:

    <form action="/weather/summer" method="post" enctype="multipart/form-data">
        文件名:<input type="text" name="name"><br/>
        文件:<input type="file" name="fileName"/><br/>
        提交:<input type="submit" value="上传">
    </form>

    后台程序:

    @Controller
    @RequestMapping(path = "/weather")
    public class WeatherController {
    
        @ResponseBody
        @RequestMapping(path = "Spring",method = RequestMethod.POST)
        public void quickSpring(@RequestParam(value = "name") String username, @RequestParam("uploadFile") MultipartFile file){  //当你的名字与你的前端设input的name属性值不同时获取的则是null,
                                                                        // 那是因为没有经过属性映射匹配需要对要获取的属性使用@RequestParams注解来进行映射
            System.out.println(username);   //
            System.out.println(file);
        }
    }

    单文件上传的代码实现(文件的接收与存储)

    进行前端的上传地文件存储起来

        @ResponseBody
        @RequestMapping(path = "autumn")
        public void autumn(String name,@RequestParam(value = "fileName") MultipartFile uploadFile) throws IOException {
            System.out.println(name);
            //获取上传文件的名称
            String filename = uploadFile.getOriginalFilename();
            System.out.println(filename);
            //将前端上传地文件存储起来
            uploadFile.transferTo(new File("D:\资料\test\"+filename));
    
        }

    多文件上传的代码实现1:

    前端:

    <form action="/weather/winter" method="post" enctype="multipart/form-data">
        文件名:<input type="text" name="name"><br/>
        文件:<input type="file" name="fileName"/><br/>
        文件2:<input type="file" name="fileName2"/><br/>
        提交:<input type="submit" value="上传">
    </form>

    后端:

        @ResponseBody
        @RequestMapping(path = "/winter")
        public void Winter(String name, MultipartFile fileName,MultipartFile fileName2){ // 依次获取对应的文件name
            System.out.println(name);
            System.out.println(fileName.getOriginalFilename());
            System.out.println(fileName2.getOriginalFilename());
        }

    多文件上传的代码实现2:

    多文件上传,只需要将页面修改为多个文件上传项,将方法参数MultipartFile类型修改为MultipartFile[] 然后前端传递的参数的name名必须全部相同,否则获取的内容不同无法放到后端数组中

     前端:

    首先要将传递的文件的name名全部设置为相同的,然后将前端传递的文件name与后端的文件name设置为相同的

     @ResponseBody
        @RequestMapping("autumnOne")
        public void AutumnOne(String name,MultipartFile [] fileName) throws IOException {  // 此时的文件的name也要和前端传递来的一致
            System.out.println(name);
            System.out.println(fileName.length);
            for (MultipartFile m :fileName) {
                System.out.println(m.getOriginalFilename());
                m.transferTo(new File("D:\资料\test\"+m.getOriginalFilename()));  //文件的存储
    
            }
        }

    SpringMVC的拦截器

    SpringMVC拦截器-拦截器的作用

    Spring MVC 的拦截器类似于 Servlet  开发中的过滤器 Filter,用于对处理器进行预处理和后处理。
    
    将拦截器按一定的顺序联结成一条链,这条链称为拦截器链(InterceptorChain)。在访问被拦截的方法或字段时,拦截器链中的拦截器就会按其之前定义的顺序被调用。拦截器也是AOP思想的具体实现。

    SpringMVC拦截器-interceptor和filter区别

    关于interceptor和filter的区别,如图所示:

    过滤器器可以拦截抱任何请求信息,包括静态的资源也可以拦截, 而拦截器只可以对controller中的请求方法进行拦截,不可以拦截静态资源

    SpringMVC拦截器--自定义拦截器

    自定义拦截器很简单,只有如下三步:

    ①创建拦截器类实现HandlerInterceptor接口
    
    ②配置拦截器
    
    ③测试拦截器的拦截效果

    1) Spring MVC也可以使用拦截器对请求进行拦截处理,用户可以自定义拦截器来实现特定的功能,自定义的拦截器可以实现HandlerInterceptor接口,也可以继承HandlerInterceptorAdapter 适配器类  

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

            如果程序员决定该拦截器对请求进行拦截处理后还要调用其他的拦截器,或者是业务处理器去进行处理,则返回true;如果程序员决定不需要再调用其他的组件去处理请求,则返回false

    ② postHandle()这个方法在业务处理器处理完请求后,但是DispatcherServlet 向客户端返回响应前被调用,在该方法中对用户请求request进行处理。

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

    当我们在执行方法的时候发现卡在了拦截器的preHandle方法的时候就去看下这个方法是否返回的是true,如果返回的是false则下面的一切都不执行了

    编写拦截器:

    先定义一个方法去实现HandlerInterceptor接口

    /**
     * 手动实现拦截器必须实现HandlerInterceptor接口和它的方法
     */
    public class MyInterceptor implements HandlerInterceptor {
    
        @Override
        public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
            System.out.println("我是拦截器的目标执行方法前的");
    
            return true;
        }
    
        @Override
        public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
            System.out.println("我是拦截器目标方法执行后,视图返回前的");
        }
    
        @Override
        public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
            System.out.println("拦截器的最后方法,我在所有的方法都执行完后执行");
        }
    }

    配置:在SpringMVC的配置文件中配置

    然后去springMvc.xml中配置你的拦截器

    <!--    配置拦截器-->
    <!--  将mvc的命名空间导入后配置拦截器-->
        <mvc:annotation-driven />
        <mvc:interceptors>
            <mvc:interceptor>
        <!--  对那些资源进行操作-->
                <mvc:mapping path="/**"/>
                <bean class="com.springMvc.Interceptor.MyInterceptor"/><!--指定你的拦截器的具体是谁-->
            </mvc:interceptor>
        </mvc:interceptors>

    编写测试程序测试:

    编写Controller,发请求到controller,跳转页面

    @RequestMapping("/test")
    @Controller
    public class TargetControlle {
    
        @RequestMapping("/target")
        public ModelAndView target(ModelAndView modelAndView){
            System.out.println("目标资源执行.....");
            modelAndView.addObject("name","目标资源");
            modelAndView.setViewName("target");
            return modelAndView;
        }
    
    }

    切忌在编写拦截器的时候一定要仔细查看手动实现的拦截器重写的preHandle方法是不是return  true只有返回的true才可以进行下面的流程的执行

    多个拦截器的使用:

    其实可以理解为python的装饰器,层层执行,从上到下依次执行的,

    比如有拦截器1和拦截器2就是拦截器1将拦截器2和目标方法包裹住了

    请求的流程图如下:(从上到下依次执行)

    定义拦截器1

    MyInterceptor

    /**
     * 手动实现拦截器必须实现HandlerInterceptor接口和它的方法
     */
    public class MyInterceptor implements HandlerInterceptor {
    
        @Override
        public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
            System.out.println("我是拦截器1的目标执行方法前的preHandle");
    
            return true;
        }
    
        @Override
        public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
            System.out.println("我是拦截器1的postHandle");
        }
    
        @Override
        public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
            System.out.println("拦截器1的最后方法");
        }
    }
    Interceptor

    定义拦截器2:

    public class MyInterceptorTwo implements HandlerInterceptor {
    
        @Override
        public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
            System.out.println("我是拦截器2的preHandle方法,我应该在目标方法执行前和拦截器1的preHandle方法后执行");
            return true;
        }
    
        @Override
        public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
            System.out.println("我是拦截器2的postHandle方法,我应该在目标资源执行后和方法1的postHandle方法执行前");
        }
    
        @Override
        public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
            System.out.println("我是拦截器2的afterCompletion方法我在目标方法执行后,拦截器1的postHandle方法后执行");
        }
    }
    MyInterceptorTwo

    在springMvc.xml中配置拦截器(拦截器的先后执行就是在此处配置的)

    <!--    配置拦截器-->
    <!--  将mvc的命名空间导入后配置拦截器-->
        <mvc:annotation-driven />
        <mvc:interceptors>
            <mvc:interceptor>
        <!--  对那些资源进行操作-->
                <mvc:mapping path="/**"/>
                <bean class="com.springMvc.Interceptor.MyInterceptor"/><!--指定你的拦截器的具体位置-->
            </mvc:interceptor>
        </mvc:interceptors>
    
    <!--    配置拦截器2-->
        <mvc:interceptors>
            <mvc:interceptor>
                <mvc:mapping path="/**"/>
                <bean class="com.springMvc.Interceptor.MyInterceptorTwo"/>
            </mvc:interceptor>
        </mvc:interceptors>

    目标方法

    @RequestMapping("/test")
    @Controller
    public class TargetControlle {
    
        @RequestMapping("/target")
        public ModelAndView target(ModelAndView modelAndView){
            System.out.println("目标资源执行.....");
            modelAndView.addObject("name","目标资源");
            modelAndView.setViewName("target");
            return modelAndView;
        }
    
    }

    执行的结果为;

    我是拦截器1的目标执行方法前的preHandle
    我是拦截器2的preHandle方法,我应该在目标方法执行前和拦截器1的preHandle方法后执行
    目标资源执行.....
    我是拦截器2的postHandle方法,我应该在目标资源执行后和方法1的postHandle方法执行前
    我是拦截器1的postHandle
    我是拦截器2的afterCompletion方法我在目标方法执行后,拦截器1的postHandle方法后执行
    拦截器1的最后方法

    我们可以利用拦截器的方法来进行方法的判断和资源信息展示的更改:

    拦截器1:来进行携带参数和跳转界面的判断

    /**
     * 手动实现拦截器必须实现HandlerInterceptor接口和它的方法
     */
    public class MyInterceptor implements HandlerInterceptor {
    
        @Override
        public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
            System.out.println("我是拦截器1的目标执行方法前的preHandle");
            String param = request.getParameter("username");
            if("laowang".equals(param)){  // 判断是否携带参数username,它的值是laowang
                return true; // 返回true代表放行
            }else {
                request.getRequestDispatcher("/WEB-INF/views/error.jsp").forward(request,response);
                return false;
            }
    
        }
    
        @Override
        public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
            System.out.println("我是拦截器1的postHandle");
        }
    
        @Override
        public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
            System.out.println("拦截器1的最后方法");
        }
    }

    拦截器2:利用postHandle来更改界面返回的参数

    public class MyInterceptorTwo implements HandlerInterceptor {
    
        @Override
        public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
            System.out.println("我是拦截器2的preHandle方法,我应该在目标方法执行前和拦截器1的preHandle方法后执行");
            return true; //返回true代表放行,返回false代表不放行
        }
    
        @Override
        public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
            modelAndView.addObject("name","我是拦截器2修改后的参数");
            System.out.println("我是拦截器2的postHandle方法,我应该在目标资源执行后和方法1的postHandle方法执行前");
        }
    
        @Override
        public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
            System.out.println("我是拦截器2的afterCompletion方法我在目标方法执行后,拦截器1的postHandle方法后执行");
        }
    }

    拦截器的配置

    <!--    配置拦截器-->
    <!--  将mvc的命名空间导入后配置拦截器-->
        <mvc:annotation-driven />
        <mvc:interceptors>
            <mvc:interceptor>
        <!--  对那些资源进行操作-->
                <mvc:mapping path="/**"/>
                <bean class="com.springMvc.Interceptor.MyInterceptor"/><!--指定你的拦截器的具体位置-->
            </mvc:interceptor>
        </mvc:interceptors>
    
    <!--    配置拦截器2-->
        <mvc:interceptors>
            <mvc:interceptor>
                <mvc:mapping path="/**"/>
                <bean class="com.springMvc.Interceptor.MyInterceptorTwo"/>
            </mvc:interceptor>
        </mvc:interceptors>

    结论:

    当拦截器的preHandle方法返回true则会执行目标资源,如果返回false则不执行目标资源
    
    多个拦截器情况下,配置在前的先执行,配置在后的后执行
    
    拦截器中的方法执行顺序是:preHandler-------目标资源----postHandle---- afterCompletion

     

     

  • 相关阅读:
    PAT甲级1060 Are They Equal【模拟】
    PAT甲级1131 Subway Map【dfs】【输出方案】
    PAT甲级1052 Linked List Sorting
    Dev的GridControl控件选择框的使用
    关于MongoDB数据库中文件唯一性的问题
    docker-学习笔记5-存储卷
    docker-学习笔记4-网络
    docker-学习笔记3-镜像基础
    docker-学习笔记2-基础用法
    docker-学习笔记1-基础入门
  • 原文地址:https://www.cnblogs.com/zhaoyunlong/p/14303640.html
Copyright © 2020-2023  润新知