Web_文件的上传-FileUpload

来源:互联网 发布:赣州富云软件 编辑:程序博客网 时间:2024/05/29 16:43

一.Tip:上传文件的处理细节http://blog.sina.com.cn/s/blog_3eb047df0100ow34.html

1.中文文件乱码问题
文件名中文乱码问题,可调用ServletUpLoadersetHeaderEncoding方法,或者设置request的setCharacterEncoding属性

普通字段的乱码
  1.手工转换
  2.FileItem.getString("UTF-8");获得名称的时候传一个字符集
 上传文件的乱码: ServletFileUpload.setHeaderEncoding("UTF-8");


2.临时文件的删除问题
由于文件大小超出DiskFileItemFactory.setSizeThreshold方法设置的内存缓冲区的大小时,Commons-fileupload组件将使用临时文件保存上传数据,因此在程序结束时,务必调用FileItem.delete方法删除临时文件。

在处理完每一个item之后,要记得调用item.delete方法,删除临时文件
Delete方法的调用必须位于流关闭之后,否则会出现文件占用,而导致删除失败的情况。


3.文件存放位置
为保证服务器安全,上传文件应保存在应用程序的WEB-INF目录下,或者不受WEB服务器管理的目录。
为防止多用户上传相同文件名的文件,而导致文件覆盖的情况发生,文件上传程序应保证上传文件具有唯一文件名。
为防止单个目录下文件过多,影响文件读写速度,处理上传文件的程序应根据可能的文件上传总量,选择合适的目录结构生成算法,将上传文件分散存储。

 

4.如何处理空文件上传
 在处理item时,判断item的getName方法返回的是不是"",如果为空,则代表客户机没有上传文件

 

5.限制上传文件的最大值
 限制单个的最大值:upload.setFileSizeMax(1024*1024);   FileUploadBase.FileSizeLimitExceededException
 限制多个的最大值:upload.setSizeMax(1024*1024*5);  FileUploadBase.SizeLimitExceededException

 

6.为防止多用户上传相同文件名的文件,而导致文件覆盖的情况发生,文件上传程序应保证上传文件具有唯一文件名。
 public String generateFilename(String filename){
  return UUID.randomUUID().toString() + "_" + filename;  //83743_9834834_9u34_9834-1.avi
 }

 

7.为避免在一个目录保存多个文件,影响文件读取的性能,应把文件打散到多个目录存储
 public String generateFilepath(String uploadpath,String filename){  //upload
  
  int hashcode = filename.hashCode();
  int dir1 = hashcode&0xf;
  int dir2 = (hashcode>>4)&0xf;
  //  http://  c:\\
  String savepath = uploadpath + "\" + dir1 + "\" + dir2;
  File file = new File(savepath);
  if(!file.exists()){
   file.mkdirs();
  }
  return savepath;
 }

 

8.限制上传文件的类型
 得到上传文件的后缀名,判断是否合法,如果不合法,则抛异常提醒用户


9.ProgressListener显示上传进度
ProgressListener progressListener = new ProgressListener() {
 public void update(long pBytesRead, long pContentLength, int pItems) {

 System.out.println("到现在为止,  " + pBytesRead + " 字节已上传,总大小为 "
     + pContentLength);
 }
};
upload.setProgressListener(progressListener);
以KB为单位显示上传进度
long temp = -1;   //temp注意设置为类变量
long ctemp = pBytesRead /1024;
if (mBytes == ctemp) 
 return;
temp = mBytes;

 

10.做出动态上传效果

 

实例

public class UploadServlet4 extends HttpServlet {

 public void doGet(HttpServletRequest request, HttpServletResponse response)
   throws ServletException, IOException {
  
  //request.setCharacterEncoding("UTF-8");这个解决不了上传文件的乱码问题
  List exts = Arrays.asList("jpg","bmp"); //创建一个集合,封装限制上传文件类型数据
  try{
   //1.创建工厂
   DiskFileItemFactory factory = new DiskFileItemFactory();
   //设置缓冲文件夹路径
   factory.setRepository(new File(this.getServletContext().getRealPath("/temp")));
   
   //2.得到解析器
   ServletFileUpload upload = new ServletFileUpload(factory);
   //设置解析器的字符集
   upload.setHeaderEncoding("UTF-8");
   //设置单个上传文件最大容量
   upload.setFileSizeMax(1024*1024);
   //设置多个上传文件最大容量
   upload.setSizeMax(1024*1024*5);
   //设置监听器,创建一个接口,实现接口方法,从监听器中获得:上传文件的当前上传字节pBytesRead,上传文件总大小pContentLength,正在处理的上传对象pItems
   upload.setProgressListener(new ProgressListener(){
    public void update(long pBytesRead, long pContentLength, int pItems) {
     System.out.println("当前处理的是" + pItems + "上传文件,文件大小是: " + pContentLength + ",当前已上传:" + pBytesRead + "字节");
    }
   });
   
   //3.用解析器解析request,得到代表每一个输入项的fileitem对象
   List<FileItem> list = upload.parseRequest(request);
   
   //4.迭代集合,获取每一个fileitem的数据
   for(FileItem item : list){
    if(item.isFormField()){
     //代表当前获取的普通输入项的数据
     String inputName = item.getFieldName();  //username
     String inputValue = item.getString("UTF-8"); //在获得上传数据时通过参数直接给字符集相当于下面代码
     //inputValue = new String(inputValue.getBytes("iso8859-1"),"UTF-8");
     System.out.println(inputName + "=" + inputValue);
    }else{  //代表当前获取的item封装的是上传文件的数据
     //获得上传文件的文件路径
     String filename = item.getName();  //""
     //判断上传文件路径为空的情况
     if(filename.trim().equals("")){
      continue;
     }
     //根据上传文件名获得文件类型,判断exts集合中是否允许该类型上传,如果不支持,抛一个自定义异常
     String ext = filename.substring(filename.lastIndexOf(".")+1);
     if(!exts.contains(ext)){  //集合的是否包含方法
      throw new ExtException();
     }
     //如果支持,获得文件名
     filename = filename.substring(filename.lastIndexOf("\")+1);  //""
     
     //获得上传对象的输入流读取文件输出到指定位置
     InputStream in = item.getInputStream();
     int len = 0;
     byte buffer[] = new byte[1024];
     //输出路径
     String uploadpath = this.getServletContext().getRealPath("/WEB-INF/upload");
     //传入文件名返回一个随即生成带ID的唯一保存文件名
     String saveFilename = generateFilename(filename);
     //传入输出路径和保存文件名,根据hash算法创建目录,返回一个用于将传入文件打散保存的保存路径
     String savePath = generateFilepath(uploadpath, saveFilename);
     //创建输出流到指定保存地址
     FileOutputStream out = new FileOutputStream(savePath + "\" + saveFilename);
     while((len=in.read(buffer))>0){
      out.write(buffer, 0, len);
     }
     
     in.close();
     out.close();
     item.delete();  //删除item对应的临时文件
     
    }
   }
   request.setAttribute("message", "上传成功!!");
  }catch (FileUploadBase.FileSizeLimitExceededException e) {
   request.setAttribute("message", "上传文件不能超过1M");
  }catch (FileUploadBase.SizeLimitExceededException e) {
   request.setAttribute("message", "上传文件的大小加起来不能超过5M");
  }catch (ExtException e) {
   request.setAttribute("message", "上传文件只能是jpg,bmp");
  }catch (Exception e) {
   e.printStackTrace();
   request.setAttribute("message", "由于未知错误上传失败!!");
  }
  request.getRequestDispatcher("/message.jsp").forward(request, response);
 }

 public void doPost(HttpServletRequest request, HttpServletResponse response)
   throws ServletException, IOException {
  doGet(request, response);
 }

 //需要的更具类方法,本应该写在工具类中,这里为了方便直接写在servlet里


 //根据传入的文件名生成一个带ID的唯一的文件名返回
 public String generateFilename(String filename){
  return UUID.randomUUID().toString() + "_" + filename;  //83743_9834834_9u34_9834-1.avi
 }


 //获得打散保存路径方法
 public String generateFilepath(String uploadpath,String filename){  //upload
  //根据传进来的文件名算出hash值
  int hashcode = filename.hashCode();
  //获得hash值的后4位的int数作为1级保存目录
  int dir1 = hashcode&0xf;
  //将hash值右移4位,也就是获取5到8位,作为2级保存目录
  int dir2 = (hashcode>>4)&0xf;
  //  http://  c:\\  根据级目录组合成一个为文件保存的目录
  String savepath = uploadpath + "\" + dir1 + "\" + dir2;
  //创建文件流,将保存地址传入,如果不存在则创建其所有目录,最后返回该目录地址
  File file = new File(savepath);
  if(!file.exists()){
   file.mkdirs();
  }
  return savepath;
 }

}

 

JSP编写动态上传效果

<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
  <head>
    <title>动态上传</title>
   
    <script type="text/javascript">
     function add(){
      
      var input = document.create_rElement("input");
      input.type = "file";
      input.name = "file";
      
      var btn = document.create_rElement("input");
      btn.type = "button";
      btn.value = "删除";
      btn.onclick = function del(){

    <!--获得这个节点的父节点的父节点,删除其孩子节点(这个节点的父节点),这样就删除了整个DIV-->
       this.parentNode.parentNode.removeChild(this.parentNode);
      }
      
      var div = document.create_rElement("div");
      div.a(input);
      div.a(btn);
      
      document.getElementByIdx_x("files").a(div);
     }
    </script>
  </head>
 
  <body>
   
    <form action="${pageContext.request.contextPath }/servlet/UploadServlet4" method="post" enctype="multipart/form-data">
     <table>
      <tr>
       <td>上传用户:</td>
       <td>
        <input type="text" name="username">
       </td>
      </tr>
      
      <tr>
       <td></td>
       <td>
        <input type="button" value="添加文件" onclick="add()">
       </td>
      </tr>
      
      <tr>
       <td></td>
       <td>
        <div id="files">
        
        </div>
       </td>
      </tr>
      <tr>
       <td></td>
       <td>
        <input type="submit" value="上传">
       </td>
      </tr>
     </table>
    </form>
   
  </body>
</html>

0 0
原创粉丝点击