Javaweb向服务器上传文件以及从服务器下载文件的方法

先导入jar包

  点击下载

  commons-fileupload是Apache开发的一款专门用来处理上传的工具,它的作用就是可以从request对象中解析出,用户发送的请求参数和上传文件的流。

  commons-fileupload包依赖commons-io,两个包需要同时导入。

  tomcat内置的jar包只能在tomcat服务器使用。

上传文件的方法

  1、创建DiskFileItemFactory工厂类的实例

    DiskFileItemFactory dfif=new DiskFileItemFactory();//new 一个DiskFileItemFactory对象

    DiskFileItemFactory类介绍

       工厂类,用于创建ServletFileUpload,设置缓存等

       该类一般直接使用构造器直接创建实例

       方法:

         public void setSizeThreshold(int sizeThreshold)

           用于设置缓存文件的大小(默认值10kb)

         public void setRepository(File repository)

           用于设置缓存文件位置(默认系统缓存目录)

  2、获取ServletFileUpload解析器的实例

    ServletFileUpload sfu=new ServletFileUpload(dfif);//通过DiskFileItemFactory对象获取ServletFileUpload解析器实例

    ServletFileUpload类介绍

       该类用于解析request对象从而获取用户发送的请求参数(包括普通参数和文件参数)

       该类需要调用有参构造器创建实例,构造器中需要一个DiskFileItemFactory作为参数

       方法:

        public List<FileItem> parseRequest(HttpServletRequest request)

           解析request对象,获取请求参数,返回的是一个List,List中保存的是一个FileItem对象,一个对象代表一个请求参数。

         public void setFileSizeMax(long fileSizeMax)

          设置单个文件的大小限制,单位为B 如果上传文件超出限制,会在parseRequest()抛出异常FileSizeLimitExceededException。

         public void setSizeMax(long sizeMax)

          限制请求内容的总大小,单位为B 如果上传文件超出限制,会在parseRequest()抛出异常SizeLimitExceededException。

  3、获取请求参数列表

    List<FileItem> list = sfu.parseRequest(request);//用ServletFileUpload解析器对象获取参数列表,该列表包含文件参数和普通参数  

    FileItem类介绍

      该类用于封装用户发送的参数和文件,也就是用户发送来的信息将会被封装成一个FileItem对象,我们通过该对象获取请求参数或上传文件的信息。

      该类不用我们手动创建,由ServletFileItem解析request后返回。

      方法:

        String getFieldName()

          获取表单项的名字,也就是input当中的name属性的值。

        String getName();

          获取上传的文件名,普通的请求参数为null。

        String getString(String encoding);

          获取内容l 若为文件,将文件的流转换为字符串。l 若为请求参数,则获取请求参数的value。

          encoding参数需要指定一个字符集,不指定时中文会乱码,建议设置utf-8

        boolean isFormField();

          判断当前的FileItem封装的是普通请求参数,还是一个文件。如果为普通参数返回:true l 如果为文件参数返回:false

        String getContentType();

          获取上传文件的MIME类型

        long getSize();

          获取内容的大小

上传文件的例子

  jsp的代码

             <form action="${pageContext.request.contextPath }/Files"
                 method="post" enctype="multipart/form-data">
                 文件1:<input type="file" name="file1"><br>
                 <br>文件2: <input type="file" name="file2"><br>
                 <br> 文件3:<input type="file" name="file3"><br>
                 <br> 文本:<input type="text" name="text"><br>
                 <br> <input type="submit" value="上传">
             </form>    

  servlet的代码

         DiskFileItemFactory dfif = new DiskFileItemFactory();// 创建工厂类
         ServletFileUpload sfu = new ServletFileUpload(dfif);// 创建请求解析器
         sfu.setFileSizeMax(1024 * 1024 * 1);// 设置上传单个文件的的大小
         sfu.setSizeMax(1024 * 1024 * 1 * 10);// 设置上传总文件的大小
         response.setContentType("text/html;charset=utf-8");// 设置响应内容的编码
         try {
             List<FileItem> list = sfu.parseRequest(request);// 解析请求信息,获取FileItem的集合
             for (FileItem fileItem : list) {// 遍历集合
                 if (fileItem.isFormField()) {// 如果是普通的表单项
                     String fieldName = fileItem.getFieldName();// 获取参数名
                     String value = fileItem.getString("utf-8"); // 获取参数值,设置编码为utf-8防止中文乱码
                     System.out.println(fieldName + " = " + value);
                 } else {// 如果是文件表单项
                     String fileName = fileItem.getName();// 获取文件名
                     String realPath = getServletContext().getRealPath("/upload");// 获取上传路径
                     System.out.println(realPath);
                     File f = new File(realPath);// 检查upload文件夹是否存在
                     if (!f.exists()) {//如果不存在则创建
                         f.mkdir();
                     }
                     String prefix = UUID.randomUUID().toString().replace("-", "");// 为避免重名生成一个UUID作为文件名的前缀,并且将生成UUID中的-移除
                     fileItem.write(new File(realPath + "/" + prefix + "_" + fileName));// 将文件写入到服务器中
                     fileItem.delete();// 清除文件缓存
                 }
             }
         } catch (Exception e) {
             if (e instanceof SizeLimitExceededException) {
                 response.getWriter().print("上传文件的总大小不能超过10M");// 文件总大小超出限制
             } else if (e instanceof FileSizeLimitExceededException) {
                 response.getWriter().print("上传单个文件的大小不能超过1M");// 单个文件大小超出限制
             }
         }
         response.getWriter().print("上传成功");

下载文件的方法

  文件下载最直接的方法就是把文件直接放到服务器的目录中,(eclipse下可以用tc工具快速访问到tomcat的工作目录,具体看我另一片博客)用户直接访问该文件就可以直接下载。但是实际上这种方式并不一定好用,比如我们在服务器上直接放置一个MP3文件,然后通过浏览器访问该文件的地址,如果是IE浏览器可能就会弹出下载窗口,而如果是FireFox和Chrome则有可能直接播放。再有就是有一些文件我们是不希望用户可以直接访问到的,这是我们就要通过Servlet来完成下载功能。

  下载文件的几个关键点

    1、 服务器以一个流的形式将文件发送给浏览器。

    2、发送流的同时还需要设置几个响应头,来告诉浏览器下载的信息。

      具体响应头如下:

        Content-Type:下载文件的MIME类型,

               可以通过servletContext. getMimeType(String file)获取,

               也可以直接手动指定,

               使用response.setContentType(String type);

               响应头样式:Content-Type: audio/mpeg

        Content-Disposition:下载文件的名字,

                  主要作用是提供一个默认的用户名,

                  通过response.setHeader("Content-Disposition", disposition)设置

                  响应头样式:Content-Disposition: attachment; filename=xxx.mp3

         Content-Length: 下载文件的长度,用于设置文件的长处(不必须)

                 通过response. setContentLength(int len)设置。

                 设置后样式:Content-Length: 3140995

    3、 接下来需要以输入流的形式读入硬盘上的文件

        FileInputStream is = new FileInputStream(file);

        这个流就是我们一会要发送给浏览器的内容

    4、通过response获取一个输出流,并将文件(输入流)通过该流发送给浏览器

        获取输出流 ServletOutputStream out = response.getOutputStream();

        通过输出流向浏览器发送文件(不要忘了关闭输入流)

          byte[] b = new byte[1024];

          int len = 0;

          while((len=is.read(b))> 0){

            out.write(b, 0, len);

          }

          is.close();

下载的例子

  servlet代码  

         String realPath = getServletContext().getRealPath("/WEB-INF/download/风吹麦浪.mp3");// 获取文件真实地址
         File file = new File(realPath);// 获取file对象
         if (!file.exists()) {// 找不到目标文件
             response.getWriter().print("文件不存在");
             return;
         }
         FileInputStream fis = new FileInputStream(file);// 获取文件输入流
         String contentType = getServletContext().getMimeType(realPath);// 获取文件的MIME信息
         String filename = file.getName();// 设置下载文件的名字
         //设置编码格式,否则文件名为中文时会乱码
         String ua = request.getHeader("User-Agent");// 获取客户端信息
         if (ua.contains("Firefox")) {// 判断客户端是否为火狐
             filename = "=?utf-8?B?" + new BASE64Encoder().encode(filename.getBytes("utf-8")) + "?=";// 若为火狐使用BASE64编码
         } else {
             filename = URLEncoder.encode(filename, "utf-8");// 否则使用UTF-8
         }
         String disposition = "attachment; filename=" + filename;// 创建Content-Disposition信息
         long size = file.length();// 获取文件长度
         response.setContentType(contentType);// 设置Content-Type
         response.setHeader("Content-Disposition", disposition);// 设置Content-Disposition
         response.setContentLength((int) size);// 设置文件长度
         ServletOutputStream out = response.getOutputStream();// 通过response获取输出流,用于向浏览器输出内容
         byte[] buffer = new byte[1024];// 将文件输入流通过输出流输出
         int len = 0;
         while ((len = fis.read(buffer)) > 0) {
             out.write(buffer, 0, len);
         }
         fis.close();// 最后不要忘记关闭输入流,输出流由Tomcat自己处理,不用手动关闭

编码问题

    从服务器获取浏览器发送的非文件内容包含中文时,需要设置编码,如String value = fileItem.getString("utf-8"); // 获取参数值,设置编码为utf-8防止中文乱码,不设置则会乱码;

    从服务器向浏览器发送中文时,需要对内容进行URL编码。(其他编码问题请看另一篇博客,里边会记录我遇到过的编码问题)
      大部分浏览器使用如下方式即可解决乱码问题:URLEncoder.encode(fileName, "utf-8");但是火狐默认以Base64来解码的,所以要为火狐单独处理。
         可以使用如下代码来判断浏览器的类型,然后进行不同的编码处理
      就是上面例子中使用的方法

        //设置编码格式,否则文件名为中文时会乱码
         String ua = request.getHeader("User-Agent");// 获取客户端信息
         if (ua.contains("Firefox")) {// 判断客户端是否为火狐
             filename = "=?utf-8?B?" + new BASE64Encoder().encode(filename.getBytes("utf-8")) + "?=";// 若为火狐使用BASE64编码
         } else {
             filename = URLEncoder.encode(filename, "utf-8");// 否则使用UTF-8
         }

还有一种简单但还不理解的方式,亲测可用
     向将字符串用gbk进行解码,然后在使用iso8859-1进行编码
          

 filename = new String(filename.getBytes("gbk"),"iso8859-1");

SpringMVC上传文件

  Spring MVC 上下文中默认没有为文件上传提供直接的支持,因此默认情况下不能处理文件的上传工作,如果想使用 Spring 的文件上传功能,需现在上下文中配置 CommonsMultipartResovler:

  1、与上面一样同样需要导入jar包

  2、在SpringMVC配置文件中配置CommonsMultipartResovler    

         <!-- 配置CommonsMultipartResolver -->
         <bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
             <property name="defaultEncoding" value="utf-8"></property>
             <!-- 以字节为单位 -->
             <property name="maxUploadSize" value="1024000"></property>
         </bean>

  3、表单:POST请求,file类型,enctype="multipart/form-data"

    表单:    

         <form action="${pageContext.request.contextPath }/fileUpload"
         method="post" enctype="multipart/form-data">
         text:<input type="text" name="text"><br> <br> 文件:<input
             type="file" name="file"><br> <br> <input
             type="submit" value="上传">
        </form>    

    controller:    

     @RequestMapping(value = "/fileUpload")
     public String fileUpload(HttpServletRequest request, @RequestParam(value = "text", required = false) String text,
             @RequestParam("file") CommonsMultipartFile file) throws Exception {

         String realPath = request.getServletContext().getRealPath("/upload");//获取真实路径
         //System.out.println(realPath);
         File file1 = new File(realPath);//创建文件夹
         if (!file1.exists()) {
             file1.mkdir();
         }
         OutputStream out = null;
         InputStream in = null;//文件输入输出流
         String prefix = UUID.randomUUID().toString();//生成唯一UUID
         String fileName = prefix + "_" + file.getOriginalFilename();
         System.out.println(fileName);
         out = new FileOutputStream(new File(realPath + "\\" + fileName));
         in = file.getInputStream();
         // IOUtils.copy(in, out);//导入的jar自带的工具类,复制文件,下面是自己写的复制方法
         int readIndex = 0;
         int copyBytes = 0;
         byte[] buffer = new byte[1024];
         while ((readIndex = in.read(buffer)) > 0) {
             out.write(buffer, 0, readIndex);
             copyBytes += readIndex;
         }
         System.out.println("共复制了:" + copyBytes + "字节");
         if (out != null)
             out.close();
         if (in != null)
             in.close();//关闭流
         return "success";
     }

SpringMVC文件下载  

     @RequestMapping(value = "/goFileDownload")//转到下载页面,将文件名显示在页面上
     public ModelAndView goFileDownload(HttpServletRequest request) throws Exception {
         ModelAndView mv = new ModelAndView();
         String path = request.getServletContext().getRealPath("/upload/");
         System.out.println(path);
         File file = new File(path);//获取目录
         File[] files = file.listFiles();
         List<String> fileName = new ArrayList<>();
         for (int i = 0; i < files.length; i++)//获取文件名list
             if (files[i].isFile())
                 fileName.add(files[i].getName());
         mv.setViewName("download");
         mv.addObject("files", fileName);
         return mv;
     }
     @RequestMapping(value = "/fileDownload/{fileName:.+}")//接受文件名参数并下载对应文件,Spring下只需将返回值设置为ResponseEntity<byte[]>即可实现
     public ResponseEntity<byte[]> fileDownload(HttpServletRequest request,
             @PathVariable(value = "fileName") String fileName) throws Exception {
         //System.out.println(fileName);
         String path = request.getServletContext().getRealPath("/upload/" + fileName);//获取文件的真实路径
         //System.out.println(path);
         File file = new File(path);//创建文件对象,准备获取内容
         InputStream in = new FileInputStream(file);
         byte[] body = new byte[in.available()];
         in.read(body);
         if (in != null)
             in.close();
         HttpHeaders headers = new HttpHeaders();//设置响应头
         fileName = new String(fileName.getBytes("gbk"), "iso8859-1");//防止中文文件名乱码,但是我去掉也能正常下载,可能是我的文件名是接收的原因
         headers.add("Content-Disposition", "attachment;filename=" + fileName);
         HttpStatus statusCode = HttpStatus.OK;//http状态码,此时为200      参考一篇博客
         //System.out.println(statusCode);
         ResponseEntity<byte[]> response = new ResponseEntity<byte[]>(body, headers, statusCode);//设置返回值
         return response;
     }

  

  

上一篇:WEB前端第十五课——CSS动画A


下一篇:asp.net 反射reflection(原理读元数据,3种加载方法,反射的几种调用方法,反射在MVC,ORM中的应用)