JavaWeb文件上传与下载功能解析

在开发过程中文件的上传下载很常用。这里简单的总结一下:

1.文件上传必须满足的条件:
a、 页面表单的method必须是post 因为get传送的数据太小了
b、 页面表单的enctype必须是multipart/form-data类型的
c、 表单中提供上传输入域
代码细节: 客户端表单中:<form enctype="multipart/form-data"/>
(如果没有这个属性,则服务端读取的文件路径会因为浏览器的不同而不同)
服务端ServletInputStream is=request.getInputStream();用流的方式获取请求正文内容,进一步的解析。

2.上传文件的细节:
(1)为什么设置表单类型为:multipart/form-data.是设置这个表单传递的不是key=value值。传递的是字节码.
表单与请求的对应关系:

如上可以看出在设置表单类型为:multipart/form-data之后,在HTTP请求体中将你选择的文件初始化为二进制,如上图中的Cookie之下的一串的随机字符串下的内容。
但注意,在标识文件(即一串随机字符串)所分割出来的文件字节码中有两行特殊字符,即第一行内容文件头和一行空行。之后的第三行才是二进制的文件内容。
所以在服务端接受客户端上传的文件时,获取HTTP请求参数中的文件二进制时,要去掉前三行。

3.自己手工解析上传的txt文件:

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
/**
 * 如果一个表单的类型是post且enctype为multipart/form-date
 * 则所有数据都是以二进制的方式向服务器上传递。
 * 所以req.getParameter("xxx")永远为null。
 * 只可以通过req.getInputStream()来获取数据,获取正文的数据
 *
 * @author wangxi
 *
 */
public class UpServlet extends HttpServlet {
 public void doPost(HttpServletRequest req, HttpServletResponse resp)
   throws ServletException, IOException {
  req.setCharacterEncoding("UTF-8");
  String txt = req.getParameter("txt");//返回的是null
  System.err.println("txt is :"+txt);
  System.err.println("=========================================");
  InputStream in = req.getInputStream();
//  byte[] b= new byte[1024];
//  int len = 0;
//  while((len=in.read(b))!=-1){
//   String s = new String(b,0,len);
//   System.err.print(s);
//  }
  BufferedReader br = new BufferedReader(new InputStreamReader(in));
  String firstLine = br.readLine();//读取第一行,且第一行是分隔符号,即随机字符串
  String fileName = br.readLine();//第二行文件信息,从中截取出文件名
  fileName = fileName.substring(fileName.lastIndexOf("\\")+1);// xxxx.txt"
  fileName = fileName.substring(0,fileName.length()-1);

  br.readLine();
  br.readLine();
  String data = null;
  //获取当前项目的运行路径
  String projectPath = getServletContext().getRealPath("/up");
  PrintWriter out = new PrintWriter(projectPath+"/"+fileName);
  while((data=br.readLine())!=null){
   if(data.equals(firstLine+"--")){
    break;
   }
   out.println(data);
  }
  out.close();
 }
}

4.使用apache-fileupload处理文件上传:
框架:是指将用户经常处理的业务进行一个代码封装。让用户可以方便的调用。
目前文件上传的(框架)组件:
Apache—-fileupload -
Orialiy – COS – 2008() -
Jsp-smart-upload – 200M。
用fileupload上传文件:

需要导入第三方包:

Apache-fileupload.jar – 文件上传核心包。
    Apache-commons-io.jar – 这个包是fileupload的依赖包。同时又是一个工具包。

核心类:

DiskFileItemFactory – 设置磁盘空间,保存临时文件。只是一个具类。
    ServletFileUpload  - 文件上传的核心类,此类接收request,并解析reqeust。
    ServletfileUpload.parseRequest(requdest)  - List<FileItem>
    注:一个FileItem就是一个标识的开始:---------243243242342 到 ------------------245243523452—就是一个FileItem

第一步:导入包:

第二步:书写一个servlet完成doPost方法

/**
 * DiskFileItemFactory构造的两个参数
 * 第一个参数:sizeThreadHold - 设置缓存(内存)保存多少字节数据,默认为10K
 * 如果一个文件没有大于10K,则直接使用内存直接保存成文件就可以了。
 * 如果一个文件大于10K,就需要将文件先保存到临时目录中去。
 * 第二个参数 File 是指临时目录位置
 *
 */
public class Up2Servlet extends HttpServlet {
 public void doPost(HttpServletRequest req, HttpServletResponse resp)
   throws ServletException, IOException {
  req.setCharacterEncoding("UTf-8");
  //获取项目的路径
  String path = getServletContext().getRealPath("/up");
  //第一步声明diskfileitemfactory工厂类,用于在指的磁盘上设置一个临时目录
  DiskFileItemFactory disk =
    new DiskFileItemFactory(1024*10,new File("/home/wang/"));
  //第二步:声明ServletFileUpoload,接收上面的临时目录
  ServletFileUpload up = new ServletFileUpload(disk);
  //第三步:解析request
  try {
   List<FileItem> list = up.parseRequest(req);
   //如果就一个文件
   FileItem file = list.get(0);
   //获取文件名,带路径
   String fileName = file.getName();
   fileName = fileName.substring(fileName.lastIndexOf("\\")+1);
   //获取文件的类型
   String fileType = file.getContentType();
   //获取文件的字节码
   InputStream in = file.getInputStream();
   //声明输出字节流
   OutputStream out = new FileOutputStream(path+"/"+fileName);
   //文件copy
   byte[] b = new byte[1024];
   int len = 0;
   while((len=in.read(b))!=-1){
    out.write(b,0,len);
   }
   out.close();

   long size = file.getInputStream().available();

   //删除上传的临时文件
   file.delete();
   //显示数据
   resp.setContentType("text/html;charset=UTf-8");
   PrintWriter op = resp.getWriter();
   op.print("文件上传成功<br/>文件名:"+fileName);
   op.print("<br/>文件类型:"+fileType);
   op.print("<br/>文件大小(bytes)"+size);

  } catch (Exception e) {
   e.printStackTrace();
  }

 }

}

5.使用该框架上传多个文件:

第一步:修改页面的表单为多个input type=”file”

<form action="<c:url value='/Up3Servlet'/>" method="post" enctype="multipart/form-data">
  File1:<input type="file" name="txt"><br/>
  File2:<input type="file" name="txt"><br/>
  <input type="submit"/>
 </form>

第二步:遍历list

public class Up3Servlet extends HttpServlet {
 public void doPost(HttpServletRequest request, HttpServletResponse response)
   throws ServletException, IOException {
  request.setCharacterEncoding("UTF-8");
  String path = getServletContext().getRealPath("/up");
  //声明disk
  DiskFileItemFactory disk = new DiskFileItemFactory();
  disk.setSizeThreshold(1024*1024);
  disk.setRepository(new File("d:/a"));
  //声明解析requst的servlet
  ServletFileUpload up = new ServletFileUpload(disk);
  try{
   //解析requst
   List<FileItem> list = up.parseRequest(request);
   //声明一个list<map>封装上传的文件的数据
   List<Map<String,String>> ups = new ArrayList<Map<String,String>>();
   for(FileItem file:list){
    Map<String,String> mm = new HashMap<String, String>();
    //获取文件名
    String fileName = file.getName();
    fileName = fileName.substring(fileName.lastIndexOf("\\")+1);
    String fileType = file.getContentType();
    InputStream in = file.getInputStream();
    int size = in.available();
    //使用工具类
    FileUtils.copyInputStreamToFile(in,new File(path+"/"+fileName));
    mm.put("fileName",fileName);
    mm.put("fileType",fileType);
    mm.put("size",""+size);

    ups.add(mm);
    file.delete();
   }
   request.setAttribute("ups",ups);
   //转发
   request.getRequestDispatcher("/jsps/show.jsp").forward(request, response);

  }catch(Exception e){
   e.printStackTrace();
  }
 }
}

如上就是上传文件的常用做法。现在我们在来看看fileupload的其他查用API.

判断一个fileItem是否是file(type=file)对象或是text(type=text|checkbox|radio)对象:
boolean isFormField() 如果是text|checkbox|radio|select这个值就是true.

6.处理带说明信息的图片

public class UpDescServlet extends HttpServlet {
 public void doPost(HttpServletRequest request, HttpServletResponse response)
   throws ServletException, IOException {
  request.setCharacterEncoding("UTF-8");//可以获取中文的文件名
  String path = getServletContext().getRealPath("/up");
  DiskFileItemFactory disk =
    new DiskFileItemFactory();
  disk.setRepository(new File("d:/a"));
  try{
   ServletFileUpload up =
     new ServletFileUpload(disk);
   List<FileItem> list = up.parseRequest(request);
   for(FileItem file:list){
    //第一步:判断是否是普通的表单项
    if(file.isFormField()){
     String fileName = file.getFieldName();//<input type="text" name="desc">=desc
     String value = file.getString("UTF-8");//默认以ISO方式读取数据
     System.err.println(fileName+"="+value);
    }else{//说明是一个文件
     String fileName = file.getName();
     fileName = fileName.substring(fileName.lastIndexOf("\\")+1);
     file.write(new File(path+"/"+fileName));
     System.err.println("文件名是:"+fileName);
     System.err.println("文件大小是:"+file.getSize());
     file.delete();
    }
   }
  }catch(Exception e){
   e.printStackTrace();
  }
 }

}

7.文件上传的性能提升
在解析request获取FileItem的集合的时候,使用:

FileItemIterator it= up.getItemIterator(request);

比使用

List<FileItem> list = up.parseRequest(request);

性能上要好的多。
示例代码:

public class FastServlet extends HttpServlet {

 public void doPost(HttpServletRequest request, HttpServletResponse response)
   throws ServletException, IOException {
  request.setCharacterEncoding("UTF-8");
  String path = getServletContext().getRealPath("/up");
  DiskFileItemFactory disk =
    new DiskFileItemFactory();
  disk.setRepository(new File("d:/a"));
  try{
   ServletFileUpload up = new ServletFileUpload(disk);
   //以下是迭代器模式
   FileItemIterator it= up.getItemIterator(request);
   while(it.hasNext()){
    FileItemStream item = it.next();
    String fileName = item.getName();
    fileName=fileName.substring(fileName.lastIndexOf("\\")+1);
    InputStream in = item.openStream();
    FileUtils.copyInputStreamToFile(in,new File(path+"/"+fileName));
   }
  }catch(Exception e){
   e.printStackTrace();
  }

 }

}

8.文件的下载
既可以是get也可以是post。

public void doPost(HttpServletRequest req, HttpServletResponse resp)
   throws ServletException, IOException {
  req.setCharacterEncoding("UTF-8");
  String name = req.getParameter("name");
  //第一步:设置响应的类型
  resp.setContentType("application/force-download");
  //第二读取文件
  String path = getServletContext().getRealPath("/up/"+name);
  InputStream in = new FileInputStream(path);
  //设置响应头
  //对文件名进行url编码
  name = URLEncoder.encode(name, "UTF-8");
  resp.setHeader("Content-Disposition","attachment;filename="+name);
  resp.setContentLength(in.available());

  //第三步:开始文件copy
  OutputStream out = resp.getOutputStream();
  byte[] b = new byte[1024];
  int len = 0;
  while((len=in.read(b))!=-1){
   out.write(b,0,len);
  }
  out.close();
  in.close();
 }

在使用J2EE流行框架时

使用框架内部封装好的来完成上传下载更为简单:

Struts2完成上传.

在使用Struts2进行开发时,导入的jar包不难发现存在 commons-fileupload-1.3.1.jar 包。通过上面的学习我们已经可以使用它进行文件的上传下载了。但Struts2在进行了进一步的封装。

view

<form action="fileUpload.action" method="post" enctype="multipart/form-data">
   
  username: <input type="text" name="username"><br>
  file: <input type="file" name="file"><br>

  <input type="submit" value="submit">
 </form>

Controller

public class FileUploadAction extends ActionSupport
{
 private String username;

   //注意,file并不是指前端jsp上传过来的文件本身,而是文件上传过来存放在临时文件夹下面的文件
 private File file;

 //提交过来的file的名字
 //struts会自动截取上次文件的名字注入给该属性
 private String fileFileName;
 //getter和setter此时为了节约篇幅省掉
  @Override
 public String execute() throws Exception
 {
 //保存上传文件的路径
  String root = ServletActionContext.getServletContext().getRealPath("/upload");
  //获取临时文件输入流
  InputStream is = new FileInputStream(file);
  //输出文件
  OutputStream os = new FileOutputStream(new File(root, fileFileName));
  //打印出上传的文件的文件名
  System.out.println("fileFileName: " + fileFileName);
    // 因为file是存放在临时文件夹的文件,我们可以将其文件名和文件路径打印出来,看和之前的fileFileName是否相同
  System.out.println("file: " + file.getName());
  System.out.println("file: " + file.getPath());

  byte[] buffer = new byte[1024];
  int length = 0;

  while(-1 != (length = is.read(buffer, 0, buffer.length)))
  {
   os.write(buffer);
  }

  os.close();
  is.close();

  return SUCCESS;
 }
}

首先我们要清楚一点,这里的file并不是真正指代jsp上传过来的文件,当文件上传过来时,struts2首先会寻找struts.multipart.saveDir(这个是在default.properties里面有)这个name所指定的存放位置(默认是空),我们可以在我们项目的struts2中来指定这个临时文件存放位置。

<constant name="struts.multipart.saveDir" value="/repository"/>

如果没有设置struts.multipart.saveDir,那么将默认使用javax.servlet.context.tempdir指定的地址,javax.servlet.context.tempdir的值是由服务器来确定的,例如:假如我的web工程的context是abc,服务器使用Tomcat,那么savePath就应该是%TOMCAT_HOME%/work/Catalina/localhost/abc_,临时文件的名称类似于upload__1a156008_1373a8615dd__8000_00000001.tmp,每次上传的临时文件名可能不同,但是大致是这种样式。而且如果是使用Eclipse中的Servers里面配置Tomcat并启动的话,那么上面地址中的%TOMCAT_HOME%将不会是系统中的实际Tomcat根目录,而会是Eclipse给它指定的地址,例如我本地的地址是这样的:/home/wang/EclipseJavaCode/.metadata/.plugins/org.eclipse.wst.server.core/tmp0/work/Catalina/localhost/abc/upload__1a156008_1373a8615dd__8000_00000001.tmp。

Struts2完成下载.

struts2的文件下载更简单,就是定义一个输入流,然后将文件写到输入流里面就行,关键配置还是在struts.xml这个配置文件里配置:

public class FileDownloadAction extends ActionSupport
{
 //要下载文件在服务器上的路径
 private String path;
 //要下载文件的文件名
 private String downloadFileName;
 //写入getter和setter
 public InputStream getDownloadFile()
 {
  return ServletActionContext.getServletContext().getResourceAsStream(path);
 }

 @Override
 public String execute() throws Exception
 {
 //当前action默认在valuestack的栈顶
  setDownloadFileName(xxx);
  return SUCCESS;
 }
}

action只是定义了一个输入流downloadFile,然后为其提供getter方法就行,接下来我们看看struts.xml的配置文件:

 <action name="fileDownload" class="com.struts2.FileDownloadAction">
    <result name="download" type="stream">
  <param name="contentDisposition">attachment;fileName="${downloadFileName}"</param>
  <param name="inputName">downloadFile</param>
   </result>
 </action>

struts.xml配置文件有几个地方我们要注意,首先是result的类型,type一定要定义成stream类型_,告诉action这是文件下载的result,result元素里面一般还有param子元素,这个是用来设定文件下载时的参数,inputName这个属性就是得到action中的文件输入流,名字一定要和action中的输入流属性名字相同,然后就是contentDisposition属性,这个属性一般用来指定我们希望通过怎么样的方式来处理下载的文件,如果值是attachment,则会弹出一个下载框,让用户选择是否下载,如果不设定这个值,那么浏览器会首先查看自己能否打开下载的文件,如果能,就会直接打开所下载的文件,(这当然不是我们所需要的),另外一个值就是filename这个就是文件在下载时所提示的文件下载名字。在配置完这些信息后,我们就能过实现文件的下载功能了。

SpringMVC完成上传:

view于struts2示例中的完全一样。此出不在写出。

Controller:

@Controller
@RequestMapping(value="fileOperate")
public class FileOperateAction {
 @RequestMapping(value="upload")
 public String upload(HttpServletRequest request,@RequestParam("file") MultipartFile photoFile){
 //上传文件保存的路径
  String dir = request.getSession().getServletContext().getRealPath("/")+"upload";
  //原始的文件名
  String fileName = photoFile.getOriginalFilename();      //获取文件扩展名
  String extName = fileName.substring(fileName.lastIndexOf("."));
 //防止文件名冲突,把名字小小修改一下
 fileName = fileName.substring(0,fileName.lastIndexOf(".")) + System.nanoTime() + extName;
  FileUtils.writeByteArrayToFile(new File(dir,fileName),photoFile.getBytes());
  return "success";
 }
 }

SpringMVC完成下载:

 @RequestMapping("/download")
 public String download(String fileName, HttpServletRequest request,
   HttpServletResponse response) {
  response.setCharacterEncoding("utf-8");
  response.setContentType("multipart/form-data");
  response.setHeader("Content-Disposition", "attachment;fileName="
    + fileName);
  try {
   InputStream inputStream = new FileInputStream(new File(文件的路径);

   OutputStream os = response.getOutputStream();
   byte[] b = new byte[2048];
   int length;
   while ((length = inputStream.read(b)) > 0) {
    os.write(b, 0, length);
   }

    // 这里主要关闭。
   os.close();

   inputStream.close();
  } catch (FileNotFoundException e) {
   e.printStackTrace();
  } catch (IOException e) {
   e.printStackTrace();
  }
   // 返回值要注意,要不然就出现下面这句错误!
   //java+getOutputStream() has already been called for this response
  return null;
 }

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持我们。

(0)

相关推荐

  • JavaWeb中struts2实现文件上传下载功能实例解析

    在做B/S系统时,通常会涉及到上传文件和下载文件,在没接struts2框架之前,我们都是使用apache下面的commons子项目的FileUpload组件来进行文件的上传,但是那样做的话,代码看起来比较繁琐,而且不灵活,在学习了struts2后,struts2为文件上传下载提供了更好的实现机制,在这里我分别就单文件上传和多文件上传的源代码进行一下讲解,这里需要导入文件下载上传的两个jar文件,一个是commons-fileupload-1.2.2.jar,另一个是commons-io-2.0.

  • javaweb 实现文件下载的方法及实例代码

    javaweb 实现文件下载 不要再说用<a>标签下载了,这个会把文件打开而不是下载 例如: <a href="E:\MyDesktop\37fecd65330184de67d419a8d02e7081.jpg">下载</a> 如果我这样写,浏览器就会把图片直接打开,除非是一个浏览器打不开的文件 所以我们还是要用到java本身的文件读写来进行文件的下载 <a href="downloadFile?filename=<s:prop

  • JavaWeb实现文件上传下载功能实例解析

    在Web应用系统开发中,文件上传和下载功能是非常常用的功能,今天来讲一下JavaWeb中的文件上传和下载功能的实现. 对于文件上传,浏览器在上传的过程中是将文件以流的形式提交到服务器端的,如果直接使用Servlet获取上传文件的输入流然后再解析里面的请求参数是比较麻烦,所以一般选择采用apache的开源工具common-fileupload这个文件上传组件.这个common-fileupload上传组件的jar包可以去apache官网上面下载,也可以在struts的lib文件夹下面找到,stru

  • JavaWeb实现文件上传与下载实例详解

    在Web应用程序开发中,文件上传与下载功能是非常常用的功能,下面通过本文给大家介绍JavaWeb实现文件上传与下载实例详解. 对于文件上传,浏览器在上传的过程中是将文件以流的形式提交到服务器端的,如果直接使用Servlet获取上传文件的输入流然后再解析里面的请求参数是比较麻烦,所以一般选择采用apache的开源工具common-fileupload这个文件上传组件.这个common-fileupload上传组件的jar包可以去apache官网上面下载,common-fileupload是依赖于c

  • JavaWeb实现文件上传下载功能实例详解

    在Web应用系统开发中,文件上传和下载功能是非常常用的功能,今天来讲一下JavaWeb中的文件上传和下载功能的实现. 文件上传概述 1.文件上传的作用 例如网络硬盘!就是用来上传下载文件的. 在智联招聘上填写一个完整的简历还需要上传照片呢. 2.文件上传对页面的要求 上传文件的要求比较多,需要记一下: 必须使用表单,而不能是超链接 表单的method必须是POST,而不能是GET 表单的enctype必须是multipart/form-data 在表单中添加file表单字段,即<input ty

  • javaweb文件打包批量下载代码

    本文实例为大家分享了javaweb文件打包批量下载,供大家参考,具体内容如下 // 批量下载未批改作业 @RequestMapping(value = "/downloadAllHomework", method = RequestMethod.GET) public void downloadAllHomework(HttpSession httpSession, HttpServletRequest request, HttpServletResponse response, St

  • javaweb实现文件上传示例代码

    本文实例为大家分享了javaweb文件下载的具体实现代码,供大家参考,具体内容如下 文件上传示例 注意:jsp页面编码为"UTF-8" 文件上传的必要条件 1.form表单,必须为POST方式提交 2.enctype="multipart/form-data" 3.必须有<input type="file" /> 前端jsp页面 <%@ page language="java" import="ja

  • JavaWeb实现文件上传与下载的方法

    文件上传概述 实现web开发中的文件上传功能,需完成如下二步操作: 在web页面中添加上传输入项 在servlet中读取上传文件的数据,并保存到本地硬盘中. 如何在web页面中添加上传输入项? <input type="file">标签用于在web页面中添加文件上传输入项,设置文件上传输入项时须注意: 1.必须要设置input输入项的name属性,否则浏览器将不会发送上传文件的数据. 2.必须把form的enctype属值设为multipart/form-data.设置该值

  • JavaWeb导出Excel文件并弹出下载框

    一.引言 在Java Web开发中经常涉及到报表,最近做的项目中需要实现将数据库中的数据显示为表格,并且实现导出为Excel文件的功能. 二.相关jar包 使用POI可以很好的解决Excel的导入和导出的问题,POI下载地址: poi-3.6-20091214.jar 三.关键代码 首先导入上述jar包. 在生成excel时一般数据源形式为一个List,下面把生成Excel格式的代码贴出来: /** * 以下为生成Excel操作 */ // 1.创建一个workbook,对应一个Excel文件

  • JavaWeb文件上传下载实例讲解(酷炫的文件上传技术)

    一.课程概述 在Web应用系统开发中,文件上传功能是非常常用的功能,今天来主要讲讲JavaWeb中的文件上传功能的相关技术实现,并且随着互联网技术的飞速发展,用户对网站的体验要求越来越高,在文件上传功能的技术上也出现许多创新点,例如异步上传文件,拖拽式上传,黏贴上传,上传进度监控,文件缩略图,大文件断点续传,大文件秒传等等. 本课程需要的基础知识: 了解基本的Http协议内容 基本IO流操作技术 Servlet基础知识 javascript/jQuery技术基础知识 二.文件上传的基础 对于文件

随机推荐