• 文件的上传和下载


     文件上传是Java EE开发经常遇到的,文件上传的方式有很多中方式

    本次的上传方式是基于commons-fileupload 

     1、文件上传

    Spring MVC框架的文件上传是基于commons-fileupload 组件的文件上传

    SpringMVC对原有的组建上进行进一步的封装,简化了文件上传代码的实现

    取消了不同上传组件的编程差异

    ①、基于表单的文件上传

    标签<input type="file" />就是一个输入框和一个按钮

        <form action="<%=request.getContextPath()%>/upload" method="post" enctype="multipart/form-data">
            <input type="file" name="img"><br>
            <input type="submit" value="submit">
        </form>

     对于基于表单的文件上传不要忘记使用enctype属性,并且将值设置为:multipart/form-data

     同时将表单的提交方式设置为post

    关于enctype:是指定数据表单的编码方式

    application/x-www-urlencoded:这是默认的编码方式,它只处理表单域中的value属性值

    multipart/form-data:该编码是以二进制流的方式处理表单数据,并将文件域指定文件的内容封装到请求的参数里

    text/plain:该编码方式只有当表单的action属性为mailto:URL的形式才使用,主要适用于直接通过表单发邮件的方式

    ②、MultipartFile接口

     springmvc框架中上传文件时将文件的相关信息及操作封装到MultipartFile对象中

    开发者只需要怕调用类型声明模型的一个属性即可对上传文件进行操作。

    该接口有以下的方法:

    byte[] getBytes():以字节数组的形式返回文件内容
    String getContentType():返回文件的内容类型
    boolean isEmpty():判断上传文件是否为空
    long getSize():返回文件的大小,单位字节
    InputStream getInputStream():返回一个InputStream,从中读取文件的内容
    void transferTo(File var1):将上传文件保存在目标目录下

    ③、单个文件上传

    创建好一个工程,需要使用到的两个jar是:

    同时也将该两个jar复制在tomcat的lib文件夹下,以免再开发的时候报错!!!

    再web.xml文件中可以为了防止中文乱码进行相关的设定:

    web.xml

        <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>

    上传页面的设置:

    file.jsp

    <body>
        上传文件:<br>
        <form action="<%=request.getContextPath()%>/upload" method="post" enctype="multipart/form-data">
            <input type="file" name="img"><br>
    
            <input type="submit" value="submit">
        </form>
    
    </body>

    上传成功之后的跳转页面

    show.jsp

    <body>
        success!!!
    </body>

    配置controller

    FileController.java

    @Controller
    public class FileController {
        @RequestMapping("/upload")
        public String  upLoad(MultipartFile img) throws Exception {
            //存放的路径
            String  path = "d:/images";
            //获取文件的原始名称
            String fileName = img.getOriginalFilename();
            System.out.println(fileName);
            File file = new File(path,fileName);
            //文件上传
            img.transferTo(file);
            return "show";
        }
    }

    这里说一下:如果File的使用方法掌握比较好,可以进行使用File的方法,而不需要提前把所需要的文件夹创建好!!!

    dispatcher-servlet.xml

        <mvc:annotation-driven></mvc:annotation-driven>
        <context:component-scan base-package="controller"/> 
        <!--视图解析-->
        <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver" >
            <property name="suffix" value=".jsp"/>
            <property name="prefix" value="/WEB-INF/jsp/"/>
        </bean>
      <!--文件上传 -->
        <bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
            <property name="maxUploadSize" value="104857600"/>
            <property name="maxInMemorySize" value="4096"/>
        </bean>

    这里严重需要注意:文件上的配置id是固定的,DispatcherServlert中的值会和该id进行配对!!!

    测试:

    跳转页面:

    查看本地:

    文件存放位置问题:

    由于path直接是本地的文件位置,再正常的业务中都是再服务器中,需要较多的费用,且指定文件夹的位置可能会造成不必要的后果!

    此时将项目的文件设置只能安放在指定的工程文件加下,即项目下的某个文件夹:

    修改controller

     @RequestMapping("/upload")
        public String  upLoad(MultipartFile img, HttpSession session) throws Exception {
            //存放的路径
            //String  path = "d:/images";
            String path = session.getServletContext().getRealPath("/images");
            //获取文件的原始名称
            String fileName = img.getOriginalFilename();
            System.out.println(fileName);
            File file = new File(path,fileName);
            //文件上传
            img.transferTo(file);
            return "show";
        }

    测试的结果是:

    此时用户上传的文件夹只能再本地工程的目录中!!!

    关于CommonsMultipartResolver:

    上传中文遇到乱码的问题

    上传设置文件大小问题

    ......

     配置文件中:

        <bean id="multipartResolver" class="org.springframework.web.multipart.
        commons.CommonsMultipartResolver
    "> <property name="maxUploadSize" value="104857600"/> <property name="maxInMemorySize" value="4096"/> <property name="defaultEncoding" value="utf-8"></property> </bean>

    maxInMemorySize:允许文件上传的最大尺寸

    maxUploadSize:最大的上传文件大小(字节)

    defaultEncoding:编码方式

    是否是空文件问题:

    如果没有选择文件,后台中的img不是空的!!!

    可进行打印测试!

    可进行文件大小是否为0的测试在进行业务的实现

    @RequestMapping("/upload")
        public String  upLoad(MultipartFile img, HttpSession session) throws Exception {
            String path = session.getServletContext().getRealPath("/images");
             if (img.getSize() > 0){
               //获取文件的原始名称
               String fileName = img.getOriginalFilename();
               System.out.println(fileName);
               File file = new File(path,fileName);
               //文件上传
               img.transferTo(file);
          return "show";
        }
          return "show";
    }

     指定文件类型

    开发中可以根据需要进行指定文件的类型,根据判断能否正常进行业务的实现

        @RequestMapping("/upload")
        public String  upLoad(MultipartFile img, HttpSession session) throws Exception {
            String path = session.getServletContext().getRealPath("/images");
            if (img.getSize() > 0){
               //获取文件的原始名称
               String fileName = img.getOriginalFilename();
               if (fileName.endsWith("jpg") || fileName.endsWith("txt")){
                   System.out.println(fileName);
                   File file = new File(path,fileName);
                   //文件上传
                   img.transferTo(file);
               }
           }
            return "show";
        }

     此时的实现业务都很简单

    ②、多文件上传

    再原有工程上进行多文件上传的操作

    新建前端添加页面:

    files.jsp

    上传文件:<br>
    <form action="<%=request.getContextPath()%>/uploads" method="post" enctype="multipart/form-data">
        <input type="file" name="img"><br>
        <input type="file" name="img"><br>
    
        <input type="submit" value="submit">
    </form>

    controller实现

    具体的逻辑没有进行太多的实现!!!

    @Controller
    public class FilesController {
        //上传多个文件!!
        @RequestMapping("/files")
        public String Files(){
            return "files";
        }
    
        @RequestMapping("/uploads")
        public String uploads(@RequestParam MultipartFile [] img, HttpSession session)
                throws Exception {
    
            String path = session.getServletContext().getRealPath("/images");
    
            for (MultipartFile imgs :img){
                if (imgs.getSize() > 0){
                    String fileName = imgs.getOriginalFilename();
                    File file = new File(path,fileName);
                    imgs.transferTo(file);
                }
            }
           return "show";
        }
    }

    此时值得说一下:

    上文件的name都是统一的,后台既可以得到一个数组

    再后台的参数中创建数组时,需要用@RequestParam注解进行指定,否则会报错!!!

    测试页面:

    查看本地的文件夹:

     此时的文件都已经成功的上传!!!

    2、文件下载

    ①、文件下的实现方法

    文件下载有两种方法:

    超链接下载

    程序编码进行下载

    超链接下载实现简单,但是暴露了下载文件的真是位置,并且只能下载存放在WEB应用程序所在的目录下文件

    程序编码实现的下载可以增强安全的访问机制,还可以从任意位置提供下载的数据

    利用程序实现下载需要设置两个报头:

    1、Web服务器需要告诉浏览器其所输出的类型不是普通文本文件或HTML文件,而是一个保存再本地的

    下载文件,还需要设置Content-Type的值为application/x-msdownload

    2、Web服务器希望浏览器不直接处理响应的实体内容,而是由用户选择相应的实体内容保存到一个文件

    中,还需要设置Content-Disposition报头。

    ②、文件下载过程

    前端下载页面的显示:

    showDownFiles.jsp 

    <table>
        <tr>
            <td>文件名</td>
        </tr>
        <c:forEach items="${files}" var="f">
            <tr>
                <td><a href="<%=request.getContextPath()%>/down?filename=${f}">${f}</a></td>
            </tr>
        </c:forEach>
    
    </table>

    Controller实现:

    package controller;
    
    import org.springframework.stereotype.Controller;
    import org.springframework.ui.Model;
    import org.springframework.web.bind.annotation.RequestMapping;
    import org.springframework.web.bind.annotation.RequestParam;
    
    import javax.servlet.ServletOutputStream;
    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpServletResponse;
    import javax.servlet.http.HttpSession;
    import java.io.*;
    import java.util.ArrayList;
    
    @Controller
    public class FileDownController {
    
    
    
        //显示要下载的文件
        @RequestMapping("/showDownFiles")
        public String  show(HttpSession session, HttpServletRequest request, Model model){
    
            //下载文件的位置
            String reqlpath = session.getServletContext().getRealPath("/images");
    
            File dir = new File(reqlpath);
    
            File files [] = dir.listFiles();
            //获取文件夹下的所有文件名
            ArrayList<String> filaName = new ArrayList<>();
            for (int i = 0;i<files.length;i++){
                filaName.add(files[i].getName());
            }
            model.addAttribute("files",filaName);
            return "showDownFiles";
        }
    
        @RequestMapping("/down")
        public String down(@RequestParam String filename, HttpServletRequest request,
                           HttpServletResponse response,HttpSession session){
    
            //要下载的路径
            String aFilePath = null;
            //输入流
            FileInputStream in = null;
            //输出流
            ServletOutputStream out = null;
    
            try {
                //从文件夹中获取文件
                aFilePath = session.getServletContext().getRealPath("/images");
    
                //设置文件下载使用的报头
                response.setHeader("Content-type","application/x-msdownload");
                response.setHeader("Content-Disposition","attachment;filename=" + toUTF8String(filename));
    
                //读入文件
                in = new FileInputStream(aFilePath + "\" + filename);
    
                out= response.getOutputStream();
                out.flush();
                int aRead = 0;
                byte b [] = new byte[1024];
                while ((aRead = in.read(b))!=-1 & in != null){
                    out.write(b,0,aRead);
                }
                out.flush();
                in.close();
                out.close();
    
            } catch (FileNotFoundException e) {
                e.printStackTrace();
            } catch (IOException e) {
                e.printStackTrace();
            }
    
            System.out.println("success");
            return null;
        }
    
        //下载保存文件名的字符编码转换方法
        public  String toUTF8String(String  str){
            StringBuffer sb = new StringBuffer();
    
            int len = str.length();
            for (int i=0;i<len;i++){
                //取出字符中的每个字符
                char c = str.charAt(i);
    
                if(c >=0 && c <=255){
                    sb.append(c);
                }else {
                    byte b [];
                    try {
                        b=Character.toString(c).getBytes("UTF-8");
                    } catch (UnsupportedEncodingException e) {
                        e.printStackTrace();
                        b=null;
                    }
                    for (int j = 0;j<b.length;j++){
                        int k = b[j];
                        if (k<0){
                            k&=255;
                        }
                        sb.append("%" + Integer.toHexString(k).toUpperCase());
                    }
                }
            }
            return sb.toString();
        }
    }

    测试:

    点击下载:

  • 相关阅读:
    阿里前端测试题--关于ES6中Promise函数的理解与应用
    elementUI之switch应用的坑
    vue函数同步执行遇到的问题
    阻止事件冒泡,阻止默认事件,event.stopPropagation()和event.preventDefault(),return false的区别
    关于Echarts的原生js获取DOM元素与动态加载DOM元素的冲突问题
    Linux 18.04 非root 安装re2c和ninja
    《Deep Learning of Graph Matching》论文阅读
    读书笔记《程序员的数学:概率统计》
    为什么要找特征向量?
    c++ 初始化
  • 原文地址:https://www.cnblogs.com/Mrchengs/p/10261747.html
Copyright © 2020-2023  润新知