上传与下载的笔记 .

来源:互联网 发布:你知我知 我 杨过 编辑:程序博客网 时间:2024/06/03 00:04
 

文件的上传和下载
1.基于表单的文件上传
如果在表单中使用表单元素 <input type=“file” />,浏览器在解析表单时,会自动生成一个输入框和一个按钮,输入框可供用户填写本地文件的文件名和路径名,按钮可以让浏览器打开一个文件选择框供用户选择文件:

2.Enctype 属性
当表单需要上传文件时,需指定表单 enctype 的值为 multipart/form-data
在 form 元素的语法中,enctype 属性指定将数据发送到服务器时浏览器使用的编码类型。 
enctype 属性取值:
application/x-www-form-urlencoded:表单 enctype 属性的默认值。这种编码方案使用有限的字符集,当使用了非字母和数字时,必须用”%HH”代替(H 代表十六进制数字)。对于大容量的二进制数据或包含非 ASCII 字符的文本来说,这种编码不能满足要求。
multipart/form-data:form 设定了enctype=“multipart/form-data”属性后,表示表单以二进制传输数据

3.Commons-fileupload 组件

Commons-fileupload 组件是 Apache 开源代码组织用来处理表单文件上传的一个子项目,该组件性能优异,可以支持任意大小的文件的上传
Commons-fileupload 组件从 1.1 版本开始依赖 Apache 的另一个项目:commons-io

4.Commons-fileupload 组件上传的基本原理
FileUpload组件将页面提交的所有元素(普通form表单域,如text和文件域file)都看作一样的FileItem,这样上传页面提交的 request请求也就是一个FileItem的有序组合,FileUpload组件可以解析该request,并返回一个一个的FileItem。而对每一个FileItem,FileUpload组件可以判断出它是普通form表单域还是文件file域,从而根据不同的类型,采取不同的操作--如果是表单域,就读出其值,如果是文件域,就保存文件到服务器硬盘上或者内存中。

5.Commons-fileupload 组件API
在 Commons-fileupload 组件中,主要用到以下三个接口和类:
ServletFileUpload 负责处理上传的文件数据,并将每部分的数据封装成一到 FileItem 对象中。
DiskFileItemFactory 是创建 FileItem 对象的工厂,在这个工厂类中可以配置内存缓冲区大小和存放临时文件的目录。
ServletFileUpload 在接收上传文件数据时,会将内容保存到内存缓存区中,如果文件内容超过了 DiskFileItemFactory 指定的缓冲区的大小,那么文件将被保存到磁盘上,存储为 DiskFileItemFactory 指定目录中的临时文件。等文件数据都接收完毕后,ServletUpload 在从文件中将数据写入到上传文件目录下的文件中

6.文件的下载
情景:在一些网络系统中,需要隐藏下载文件的真实地址,或者下载的文件需要一个程序来动态的确定后在传送给客户端
方案:利用程序编码实现下载
可以增加安全访问控制,只对经过授权认证的用户提供下载
可以从任意位置提供下载的数据
利用程序实现下载需要设置 2 个报头:
Web 服务器需要告诉浏览器其所输出的内容的类型不是普通的文本文件或 HTML 文件,而是一个要保存到本地的下载文件。设置Content-Type 的值为:application/x-msdownload
Web 服务器希望浏览器不直接处理相应的实体内容,而是由用户选择将相应的实体内容保存到一个文件中,这需要设置 Content-Disposition 报头。该报头指定了接收程序处理数据内容的方式,在 HTTP 应用中只有 attachment 是标准方式,attachment 表示要求用户干预。在 attachment 后面还可以指定 filename 参数,该参数是服务器建议浏览器将实体内容保存到文件中的文件名称。在设置 Content-Dispostion 之前一定要指定 Content-Type. 
因为要下载的文件可以是各种类型的文件,所以要将文件传送给客户端,其相应内容应该被当做二进制来处理,所以应该调用                                方法返回 ServeltOutputStream 对象来向客户端写入文件内容。                       

 

基本思想: FileUpload组件将页面提交的所有元素(普通form表单域,如text和文件域file)都看作一样的FileItem,这样上传页面提交的 request请求也就是一个FileItem的有序组合,FileUpload组件可以解析该request,并返回一个一个的FileItem。而对每一个FileItem,FileUpload组件可以判断出它是普通form表单域还是文件file域,从而根据不同的类型,采取不同的操作--如果是表单域,就读出其值,如果是文件域,就保存文件到服务器硬盘上或者内存中。
步骤:
0. 创建 FileItemFactory 子类 DiskFileItemFactory 的对象
1.为了得到 ServletFileUpload 对象, 先需要得到 FileItemFactory 的一个对象, 然后调用 new ServletFileUpload(FileItemFactory fif); 方法得到 ServletFileUpload 对象
2.为了得到 FileItem 的集合, 先需要得到 ServletFileUpload 对象, 然后调用该对象的 parseRequest() 方法得到 FileItem 的 List
3.从 HttpServletRequest 对象中得到 FileItem 的集合
4. 对上述集合进行遍历:判断是表单域还是文件域

一个sevlet
public class RegServlet extends HttpServlet {

 protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
  try {
   //1. 通过 fileupload 组件获取用户的请求信息
   ServletContext sc = this.getServletContext();
   UserInfo user = new UserInfo();
   
    //1). 创建 FileItemFactory 实现类 DiskFileItemFactory 的对象
   DiskFileItemFactory itemFactory = new DiskFileItemFactory();
   
    //2). 设置 FileItemFactory 的两个属性值: sizeThreshold 和 repository
   itemFactory.setSizeThreshold(1024 * 500);
   
   String tempPath = sc.getRealPath("/temp/");
   File repository = new File(tempPath);
   if(!repository.exists())
    repository.mkdir();
   itemFactory.setRepository(repository);
   
    //3). 利用 FileItemFactory 对象创建 ServletFileUpload 对象
   ServletFileUpload fileUpload = new ServletFileUpload(itemFactory);
   
    //4)  设置 ServletFileUpload 的 sizeMax 属性 或则 fileSizeMax 属性 100kb
   fileUpload.setSizeMax(100 * 1024);
   
    //5)  利用  ServletFileUpload 对象解析请求获取 FileItem 的集合,
       //    若上传文件超过 100kb 可能会出现异常, 捕获该异常, 则将页面派发到 /register.jsp 给出 "上传的文件大小不能超过 100kb " 的信息, 方法结束 
   List<FileItem> items = fileUpload.parseRequest(request);
   
    //6)  对 5) 获取的集合进行遍历.
   for(FileItem item : items){
    //7) 获取 FileItem 对象的 filedName 属性值
    String filedName = item.getFieldName();
   
     //8) 检查 FileItem 对象是否为文本域, 若为文本域, 直接取出其值. 并把该值存入 UserInfo 的相应属性中.
    if(item.isFormField()){
     String value = item.getString("UTF-8");
     
     if(filedName.equals("username")){
      user.setUsername(value);
     }
     if(filedName.equals("nickname")){
      user.setNickname(value);
     }
     if(filedName.equals("email")){
      user.setEmail(value);
     }
    }else{
     //9) 若 8) 不是文本域,
     //a. 获取上传文件的扩展名, 若其扩展名不是 jpg 则将页面派发到 /register.jsp 给出 "上传的文件只能为 jpg 格式" 的信息, 方法结束 
     String fileName = item.getName();
     int index = fileName.lastIndexOf(".");
     String str = fileName.substring(index + 1);
  
     if(!"jpg".equals(str)){
      System.out.println("非法的文件类型");
      request.setAttribute("errorinfo", "非法的文件类型");
      request.getRequestDispatcher("/register.jsp")
       .forward(request, response);
      return;
     }
     
     //b. 需要对该文件进行上传操作. 上传到当前 web 应用的根目录的 pictures 目录下, 且文件名为 username.jpg
     String picPath = sc.getRealPath("/pictures/");
     File pic = new File(picPath);
     if(!pic.exists())
      pic.mkdir();
  
     System.out.println(picPath);
     
     String uploadFileName = picPath + "//" + user.getUsername() + ".jpg";
     File file = new File(uploadFileName);
     item.write(file);
     
     //c. 把 pictures/username.jpg 赋给 UserInfo 对象的 photo 属性中
     user.setPhoto("pictures/" + user.getUsername() + ".jpg");
    }
    
     
   }
   
   UserInfoDAO userDAO = new UserInfoDAO();
   userDAO.saveUserInfo(user);
   
   //2. 将页面派发到 /success.jsp 页面, 显示用户的详细信息
   request.setAttribute("userinfo", user);
   request.getRequestDispatcher("/success.jsp")
    .forward(request, response);
  } catch (FileUploadException e) {
   e.printStackTrace();
   
   if(e instanceof FileUploadBase.SizeLimitExceededException){
    System.out.println("文件体积过大!");
    request.setAttribute("errorinfo", "文件体积过大");
    request.getRequestDispatcher("/register.jsp")
     .forward(request, response);
    return;
   }
  } catch (Exception e) {
   e.printStackTrace();
  }
  
 }

}

原创粉丝点击