当前位置: 移动技术网 > IT编程>开发语言>Java > java基于servlet实现文件上传功能解析

java基于servlet实现文件上传功能解析

2019年07月22日  | 移动技术网IT编程  | 我要评论
最近项目需要做一个文件上传功能,做完了分享下,顺带当做笔记。 上传功能用后台用java实现,前端主要是js的ajax实现。后台还加入定时删除临时文件。 效果如图

最近项目需要做一个文件上传功能,做完了分享下,顺带当做笔记。
上传功能用后台用java实现,前端主要是js的ajax实现。后台还加入定时删除临时文件。
效果如图

这里写图片描述

这里写图片描述

首先是上传功能的主要类,下面是代码

package util.upload;
import java.io.file;
import java.io.ioexception;
import java.text.simpledateformat;
import java.util.date;
import java.util.iterator;
import java.util.list;
import java.util.uuid;

import javax.servlet.servletexception;
import javax.servlet.http.httpservlet;
import javax.servlet.http.httpservletrequest;
import javax.servlet.http.httpservletresponse;
import javax.servlet.http.httpsession;

import org.apache.commons.fileupload.fileitem;
import org.apache.commons.fileupload.disk.diskfileitemfactory;
import org.apache.commons.fileupload.servlet.servletfileupload;

public class uploadservlet extends httpservlet {

 private static final long serialversionuid = -3100028422371321159l;
 private boolean isallowed;
 private string upfilename;
  //定义合法后缀名的数组
 private string[] allowedextname=new string[]
      {"zip","rar",//压缩文件
     "txt","doc","wps","docx","java",//文本
     "xls","xlsx",//表格
     "ppt","pptx",//幻灯片
     "pdf",//pdf
     "jpg","jpeg","bmp","gif","png"//图片
     };
 protected void doget(httpservletrequest request, httpservletresponse response) throws servletexception, ioexception {
 dopost(request, response);

 }

 protected void dopost(httpservletrequest request, httpservletresponse response) throws servletexception, ioexception {
 //设置编码格式为utf-8
 request.setcharacterencoding("utf-8");
 response.setcharacterencoding("utf-8"); 
 //获取session,保存进度和上传结果,上传开始为nok,当为ok表示上传完成
 httpsession session=request.getsession();
 session.setattribute("result", "nok");
 session.setattribute("error", "");
 string error="";
 upfilename="";
 isallowed=false;
 //给上传的文件设一个最大值,这里是不得超过100mb
 int maxsize=100*1024*1024;
 //创建工厂对象和文件上传对象
 diskfileitemfactory factory=new diskfileitemfactory();
 servletfileupload upload=new servletfileupload(factory);
 //创建上传监听器和设置监听器
 uploadlistener listener=new uploadlistener();
 session.setattribute("listener", listener);
 upload.setprogresslistener(listener); 
 //上传路径
 string path = request.getsession().getservletcontext().getrealpath("/upload");
 string requestpath = request.getsession().getservletcontext().getcontextpath()+"/upload";
 file dirfile =new file(path);   //system.out.println(request.getsession().getservletcontext().getcontextpath());
 //如果文件夹不存在则创建  
 if (!dirfile .exists() && !dirfile .isdirectory())   
 {     
  dirfile .mkdir();  
 }  
 //根据日期创建文件夹,保存到对应日期的文件夹下
 date date=new date();
 simpledateformat sdf=new simpledateformat("yyyymmdd");
 string subdirname=sdf.format(date);
 file subdirfile=new file(path+"/"+subdirname);
 if (!subdirfile .exists() && !subdirfile .isdirectory())   
 {    
   subdirfile .mkdir();  
 }  
 try { 
  //解析上传请求
  list<fileitem> items=upload.parserequest(request);  
  iterator<fileitem> itr=items.iterator();  
  while(itr.hasnext()){   
  fileitem item=(fileitem)itr.next();
  //判断是否为文件域  
  if(!item.isformfield()){   if(item.getname()!=null&&!item.getname().equals("")){
   //获取上传文件大小和文件名称
   long upfilesize=item.getsize();  
   string filename=item.getname();

   //获取文件后缀名
   string[] splitname=filename.split("\\.");
   string extname=splitname[splitname.length-1];
   //检查文件后缀名
   for(string allowed:allowedextname)
   {
    if(allowed.equalsignorecase(extname))
    {
      isallowed=true;
    }    
   }
   if(!isallowed){
     error="上传文件格式不合法!";
     break;
   }
   if(upfilesize>maxsize){
    error="您上传的文件太大了,请选择不超过100mb的文件!";
    break;
   } 
   //此时文件暂存在服务器的内存中,构造临时对象
   file tempfile=new file(makefilename(filename));

   //指定文件上传服务器的目录及文件名称
   file file=new file(path+"/"+subdirname+"/",tempfile.getname());

   item.write(file);//第一种写文件方法
   upfilename=requestpath+"/"+subdirname+"/"+tempfile.getname();
 if(upfilename.equals("")){
   error="没选择上传文件!";
 }
 system.out.println(upfilename);
   /*//构造输入流读文件 第二种写文件方法
   inputstream is=item.getinputstream();
   int length=0;
   byte[] by=new byte[1024];

   fileoutputstream fos=new fileoutputstream(file);

   while((length=is.read(by))!=-1){
    fos.write(by, 0, length);
    //thread.sleep(10);
   }
   fos.close();
   //thread.sleep(1000);*/
   }else{
   error="没选择上传文件!";
   }
  }
  }  
 } catch (exception e) {
  e.printstacktrace();
  error="上传文件出现错误:"+e.getmessage();
 }
 if(!error.equals("")){ 
   system.out.println(error);
  session.setattribute("error", error);
 }else{ 

  session.setattribute("result", "ok"); 
  session.setattribute("filename",upfilename);
 }
 }
 /**
 * 为防止文件覆盖的现象发生,要为上传文件产生一个唯一的文件名
 * @param filename 原文件名
 * @return 生成的唯一文件名
 */
 private string makefilename(string filename){

   return uuid.randomuuid().tostring() + "_" + filename;
  } 
}

其中需要引入commons-fileupload-1.3.1.jar,commons-io-2.4.jar
上传过程中,我们需要实时获取上传进度等信息,引入的库里为我们添加了一个progresslistener接口,我们再写一个类实现这个接口,上面类中添加该接口

//创建工厂对象和文件上传对象
 diskfileitemfactory factory=new diskfileitemfactory();
 servletfileupload upload=new servletfileupload(factory);
 //创建上传监听器和设置监听器
 uploadlistener listener=new uploadlistener();
 session.setattribute("listener", listener);
 upload.setprogresslistener(listener);

下面是这个监听类的具体实现代码

package util.upload;

import org.apache.commons.fileupload.progresslistener;

public class uploadlistener implements progresslistener{

  private volatile long 
  bytesread = 0l,//上传的字节数
  contentlength = 0l,//总字节数
  item = 0l; 
   public uploadlistener() 
    {
      super();
    }

   @override
   public void update(long abytesread, long acontentlength, int anitem) {

    bytesread = abytesread;
     contentlength = acontentlength;
     item = anitem;
   }
   public long getbytesread() 
   {
     return bytesread;
   }
   public long getcontentlength() 
   {
     return contentlength;
   }

   public long getitem() 
   {
     return item;
   }
}

现在能获取上传进度等信息了,但还需要一个servlet返回给前端,下面实现

package util.upload;

import java.io.ioexception;
import java.io.printwriter;
import java.util.hashmap;
import java.util.map;

import javax.servlet.servletexception;
import javax.servlet.http.httpservlet;
import javax.servlet.http.httpservletrequest;
import javax.servlet.http.httpservletresponse;
import javax.servlet.http.httpsession;

import org.apache.commons.fileupload.progresslistener;

import com.google.gson.gson;
/**
 获取上传进度,上传路径,错误,上传结果等信息
 */

public class getprogressservlet extends httpservlet{

 private static final long serialversionuid = -3596466520775012991l;

 protected void doget(httpservletrequest request, httpservletresponse response) throws servletexception, ioexception {
 dopost(request, response);
 }

 protected void dopost(httpservletrequest request, httpservletresponse response) throws servletexception, ioexception {
   request.setcharacterencoding("utf-8");
   response.setcharacterencoding("utf-8");
   uploadlistener listener= null;
   httpsession session = request.getsession();
   string error=(string) session.getattribute("error");
   string result= (string) session.getattribute("result");
   string filename=(string) session.getattribute("filename");
   printwriter out = response.getwriter();
   long bytesread = 0,contentlength = 0; 
   if (session != null)
    {
      listener = (uploadlistener)session.getattribute("listener");

      if (listener == null)
      {
        return;
      }
      else
      {        
        bytesread = listener.getbytesread();//上传的字节数
        contentlength = listener.getcontentlength();//总字节数

      }
      //自己定义的返回格式
      string rp=bytesread+","
          +contentlength+","
          +error+","
          +result+","
          +filename;

      //system.out.println(rp);
      out.print(rp);
      /*   //返回json格式数据
      map<string,object> map=new hashmap<string,object>();
      map.put("bytesread", bytesread);
      map.put("contentlength", contentlength);
      map.put("error", error);
      map.put("result", result);
      map.put("filename", filename);
      gson gson=new gson();
      string json=gson.tojson(map);
      out.print(json);*/
      out.flush();
      out.close();  
    }
 }
}

后台上传的功能代码写完了,下面实现上传的前端,首先是html

<!doctype html>
  <html>
  <head>
    <meta charset="utf-8" />
    <script type="text/javascript" src="js/upfile.js" charset="utf-8"></script>
    <link rel="stylesheet" type="text/css" href="css/upfile.css">
  </head>
  <body >
    <a href="javascript:addone()">添加</a>
    <div id="target">
      <input type="file" id="file" name="file" onchange="addfile(event)" multiple/>
    </div>
    <span id="test">0</span>
  </body> 
</html>

界面比较简单,就一个添加的a标签,负责上传的input隐藏起来
css文件主要渲染的上传进度的显示

      #file {
        display: none;
      }
      .pro{
        width:500px;
      }
      .pborder {

        position: relative;
        width: 500px; /* 宽度 */
        border: 1px solid #b1d632;
        padding: 1px;
      }

      .drawpro {
        width: 0px;
        display: block;
        position: relative;
        background: #b1d632;
        color: #333333;
        height: 20px; /* 高度 */
        line-height: 20px; /* 必须和高度一致,文本才能垂直居中 */
      }

      .pspan {
        position: absolute;
        width: 500px;
        text-align: center;
        font-weight: bold;
      }

接着是前端的重点,js文件

//显示上传信息的html
var upfile_html = '<div class="pborder"><div class="drawpro">'
    + '<span class="pspan">0%</span></div></div><span name="path"></span><img src="common/upload/images/del.png" style="float:right" width="20" height="20" name="del" onclick=abortupload(this)>';

var targetdiv_id = "target";//显示上传文件的目标div的id
var httpxml = null;//发送上传请求的xmlhttprequest对象
var httpprogress = null;//发送请求进度信息的xmlhttprequest对象
var oldfilelist = new array();//修改时保存已有附件信息的列表
var uplist = new array();//保存上传文件的列表
var f_input;//上传文件的input对象
var flag = true;//是否可以上传下一个文件标志
var uurl = "upload";//上传文件的请求url
var gurl = "getprogress";//获取上传进度信息的url
var cancelflag = 0;//取消标志
var timer, waittimer;//定时器
var nowid = 0;//正在上传文件的id
var id = 0;//队列中最后一个文件的id

/**
 * 文件对象
 */
function uploadfile(id, file) {
  this.id = id;
  this.file = file;
  this.state = 0;
  this.path = "";
}
/**
 * 初始化的方法
 */
window.onload = function init() {
  f_input = document.getelementbyid("file");
  var tdiv = document.getelementbyid(targetdiv_id);

  var oldspan = tdiv.getelementsbytagname("span");

  for ( var i = 0; i < oldspan.length; i++) {
    oldfilelist.push(oldspan[i].getattribute("name"));
  }
}

/**
 * 选择一个文件上传
 */
function addone() {
  f_input.value = null;
  f_input.click();
}

/**
 * 选中文件后将文件对象添加到队列,开始上传
 * 
 */
function addfile(evt) {
  var f = f_input.files[0];
  if (f != undefined) {
    var uf = new uploadfile(id, f);
    uplist.push(uf);
    var div = document.createelement("div");
    div.setattribute("id", "pro" + (id));
    div.setattribute("class", "pro");
    div.innerhtml = upfile_html;
    var targetdiv = document.getelementbyid(targetdiv_id);
    targetdiv.appendchild(div);
    div.getelementsbytagname("span")[1].innerhtml = "文件名:"
        + uplist[id].file.name;
    waittimer = setinterval("upload()", 1000);
    id++;
  }
}
/**
 * 将队列中的文件上传
 */
function upload() {

  if (flag == true) {

    if (uplist.length > 0) {

      var uf;
      for ( var i = 0; i < uplist.length; i++) {
        if (uplist[i].state == 0) {
          uf = uplist[i];
          uplist[i].state = 1;
          break;
        }
      }

      if (uf != undefined & uf != null) {
        flag = false;
        if (window.xmlhttprequest) {
          httpup = new xmlhttprequest();
        } else if (window.activexobject) {
          httpup = new activexobject("microsoft.xmlhttp");
        }
        var formdata = new formdata();
        formdata.append("file", uf.file);
        httpup.open("post", uurl, true);
       httpup.upload.addeventlistener('progress', uploadprogress, false);
        httpup.send(formdata);
        nowid = uf.id;
        timer = setinterval("getp()", 50);
      }
    }
  }
}

/**
 * 获取上传进度等信息
 */
function getp() {
  if (window.xmlhttprequest) {
    httpprogress = new xmlhttprequest();
  } else if (window.activexobject) {
    httpprogress = new activexobject("microsoft.xmlhttp");
  }
  httpprogress.onreadystatechange = onprogress;
  httpprogress.open("post", gurl, true);
  httpprogress.setrequestheader("content-type",
      "application/x-www-form-urlencoded");
  httpprogress.send("×tamp=" + (new date()).gettime());
}

/**
 * 处理返回的上传信息,显示到界面
 */
function onprogress() {
  if (httpprogress.readystate == 4 && httpprogress.status == 200) {
    result = httpprogress.responsetext;
    var result = result.replace(/(^\s*)|(\s*$)/g, "");
    var res = result.split(",");
    var now = parseint(res[0]);
    var all = parseint(res[1]);
    var err = res[2];
    var state = res[3];
    var path = res[4];
    var per = (now / all * 100).tofixed(2);
    var prodiv = document.getelementbyid("pro" + nowid);

    if (prodiv != null & prodiv != undefined) {
      if (err != "" & err != null & err.length > 0) {
        window.clearinterval(timer);
        if (cancelflag == 1) {
          err = "上传终止";
          cancelflag = 0;
        }
        prodiv.getelementsbytagname("div")[0].style.display = "none";
        prodiv.getelementsbytagname("span")[1].innerhtml = err;
        httpup.abort();
        flag = true;
        uplist[nowid].state = 3;
        return;
      }
      if (state == "ok") {
        prodiv.getelementsbytagname("div")[0].style.display = "none";
        var tmpf = uplist[nowid].file;
        prodiv.getelementsbytagname("span")[1].innerhtml = "文件名:"
            + tmpf.name;
        window.clearinterval(timer);
        flag = true;
        uplist[nowid].state = 2;
        uplist[nowid].path = path;
        return;
      }
      prodiv.getelementsbytagname("div")[1].style.width = per * 5 + "px";
      prodiv.getelementsbytagname("span")[0].innerhtml = per + "%";

    }
  }
}

/**
 * 取消上传的方法
 */
function abortupload(obj) {
  var idstr = obj.parentnode.id;
  var id = idstr.slice(3);
  if (uplist[id].state == 1) {
    httpup.abort();
    flag = true;
    cancelflag = 1;
  } else {
    uplist[id].state = 3;
  }
  document.getelementbyid(idstr).remove();

}
/**
 * 获取上传文件的路径
 * @returns 格式化后字符串
 */
function getfileliststr() {

  var str = "";
  if (oldfilelist.length > 0) {
    for ( var i = 0; i < oldfilelist.length; i++) {
      if (oldfilelist[i] != null & oldfilelist[i] != ""
          & oldfilelist[i] != undefined) {
        str = str + oldfilelist[i] + ",";
      }

    }
  }
  for ( var i = 0; i < uplist.length; i++) {
    var f = uplist[i];
    if (f.state == 2) {
      str = str + f.path + ",";
    }
  }
  return str;
}
/**
 * 移除修改时已有的旧附件
 * 
 */
function removeold(btn) {
  var num = btn.getattribute("name");
  oldfilelist[num - 1] = null;
  btn.parentnode.remove();
}
  function uploadprogress(e) {
        if (e.lengthcomputable) {
          var ibytesuploaded = e.loaded;
          var ibytestotal = e.total;
          document.getelementbyid("test").innerhtml=ibytesuploaded+"/"+ibytestotal;
        }
      }

使用ajax发送上传文件,获取上传进度,结果等信息。
使用的html5的file api,所以必须ie9以上的才可以兼容,火狐还有个问题,ajax请求不立即返回,直到所有ajax请求都发送完了,才都返回同一个结果,这就导致上传进度不显示。不过上传进度信息也可以使用html5的file api获取,其中加了一点代码,页面下面test的div里的数值就是在前端获取到的进度。

上传的都实现完了,接着是处理上传后的临时文件,因为使用的uuid命名文件,所以文件会生成很多,没用的需要定时处理。使用servletcontextlistener:
在 servlet api 中有一个 servletcontextlistener 接口,它能够监听 servletcontext 对象的生命周期,实际上就是监听 web 应用的生命周期。

当servlet 容器启动或终止web 应用时,会触发servletcontextevent 事件,该事件由servletcontextlistener 来处理。在 servletcontextlistener 接口中定义了处理servletcontextevent 事件的两个方法。
利用其特性,实现定时删除临时文件的功能,代码如下:

package util.upload;

import java.io.ioexception;
import java.io.inputstream;
import java.util.date;
import java.util.properties;
import java.util.timer;
import java.util.timertask;

import javax.servlet.servletcontext;
import javax.servlet.servletcontextevent;
import javax.servlet.servletcontextlistener;

/** 
 * 时间监听器 
 *  
 * 
 */ 
public class tempfilelistener implements servletcontextlistener { 
  private timer timer; 
  private systemtasktest systemtask; 
  private static string every_time_run; 
  static { 
    properties prop = new properties(); 
    inputstream instrem = tempfilemanager.class.getclassloader() 
        .getresourceasstream("tempfile.properties"); 
    try { 
      prop.load(instrem); 
      system.out.println(instrem);
      every_time_run = prop.getproperty("every_time_run"); 

    } catch (ioexception e) { 
      e.printstacktrace(); 
    } finally { 
      try { 
        instrem.close(); 
      } catch (ioexception e) { 
        e.printstacktrace(); 
      } 
    } 
  } 

  // 监听器初始方法 
  public void contextinitialized(servletcontextevent sce) { 

    timer = new timer(); 
    systemtask = new systemtasktest(sce.getservletcontext() 
        .getrealpath("/"), sce.getservletcontext()); 
    try { 
      system.out.println("定时器已启动");
      // 监听器获取网站的根目录 
      string path = sce.getservletcontext().getrealpath("/"); 
      long time = long.parselong(every_time_run) * 1000;// 循环执行的时间 
      system.out.println("time" + time);  
      // 第一个参数是要运行的代码,第二个参数是从什么时候开始运行,第三个参数是每隔多久在运行一次。重复执行 
      timer.schedule(systemtask, 10000, time); 
      system.out.println("已经添加任务调度表");
    } catch (exception e) { 
      e.printstacktrace();
    } 
  } 

  public void contextdestroyed(servletcontextevent sce) { 
    try { 
      timer.cancel(); 
    } catch (exception e) { 
    } 
  } 
} 

/** 
 * 时间任务器 
 * 
 */ 
class systemtasktest extends timertask { 
  private servletcontext context; 
  private string path; 
  public systemtasktest(string path, servletcontext context) { 
    this.path = path; 
    this.context = context; 
  } 

  /** 
   * 把要定时执行的任务就在run中 
   */ 
  public void run() {  
    tempfilemanager etf;   
    try { 

      system.out.println("开始执行任务!");
      // 需要执行的代码 
      system.out.println(new date().tolocalestring()); 

      etf = new tempfilemanager(path); 
      etf.run();    

      system.out.println("指定任务执行完成!");
    } catch (exception e) { 
      e.printstacktrace(); 
    } 
  } 
} 

上面只是监听器,负责定时调用删除临时文件的方法,具体实现是下面的类

package util.upload;

import java.io.file;
import java.io.ioexception;
import java.io.inputstream;
import java.util.date;
import java.util.properties;


/** 
 * 删除服务器上的文件 
 * 
 */ 

public class tempfilemanager implements runnable { 
  private string path;//路径 

  private static string retention_time = "1440";// 文件保存的时间 一天单位分
  static { 
    properties prop = new properties(); 
    inputstream instrem = tempfilemanager.class.getclassloader() 
        .getresourceasstream("execl.properties"); 
    try { 
      prop.load(instrem); 
      retention_time = prop.getproperty("file_retention_time"); 

    } catch (ioexception e) { 
      e.printstacktrace(); 
    } finally { 
      try { 
        instrem.close(); 
      } catch (ioexception e) { 
        e.printstacktrace(); 
      } 
    } 
  } 
  /** 
   * 构造函数。初始化参数 
   * @param path 
   */ 
  public tempfilemanager(string path) { 
    this.path = path; 

  } 
  /** 
   * 把线程要执行的代码放在run()中 
   */ 
  public void run() { 
    system.out.println("文件管理开始========="); 
    path = path + "upload"; 
    system.out.println("文件管理路径===" + path); 
    file file = new file(path); 
    deletefiles(file); 
  } 

  /** 
   * 批量删除文件 
   *  
   * @param folder 
   */ 
  public void deletefiles(file folder) { 
  if(folder.isdirectory()){

    file[] files = folder.listfiles();
    if(files.length<=0){
      if(!folder.getabsolutepath().equalsignorecase(path)){
      if(candeletefile(folder)){
        if (folder.delete()) { 
          system.out.println("文件夹" + folder.getname() + "删除成功!"); 
        } else { 
          system.out.println("文件夹" + folder.getname() 
              + "删除失败!此文件夹内的文件可能正在被使用"); 
        } 
      }
      }
    }
    for (int i = 0; i < files.length; i++) { 

      if(files[i].isdirectory())
      {
      deletefiles(files[i]);
      }else{
        deletefile(files[i]); 
      }

    } 
  }
  } 

  /** 
   * 删除文件 
   *  
   * @param file 
   */ 
  private void deletefile(file file) { 
    try { 
      if (file.isfile()) { 
        // 删除符合条件的文件 
        if (candeletefile(file)) { 
          if (file.delete()) { 
            system.out.println("文件" + file.getname() + "删除成功!"); 
          } else { 
            system.out.println("文件" + file.getname() 
                + "删除失败!此文件可能正在被使用"); 
          } 
        } else { 

        } 
      } else { 
        system.out.println("没有可以删除的文件了"); 
      } 

    } catch (exception e) { 
      system.out.println("删除文件失败========"); 
      e.printstacktrace(); 
    } 
  } 

  /** 
   * 判断文件是否能够被删除 
   */ 
  private boolean candeletefile(file file) { 
    date filedate = getfiledate(file); 
    date date = new date(); 
    long time = (date.gettime() - filedate.gettime()) / 1000 / 60 
        - integer.parseint(retention_time);// 当前时间与文件间隔的分钟 
//    system.out.println("time=="+time);
    if (time > 0) { 
      return true; 
    } else { 
      return false; 
    } 

  } 

  /** 
   * 获取文件最后的修改时间 
   *  
   * @param file 
   * @return 
   */ 
  private date getfiledate(file file) { 
    long modifiedtime = file.lastmodified(); 
    date d = new date(modifiedtime); 
    return d; 
  } 

} 

判断文件是否超时,超时就自动删除,并且能自动删除文件夹。

以上就是本文的全部内容,希望对大家学习java程序设计有所帮助。

如您对本文有疑问或者有任何想说的,请点击进行留言回复,万千网友为您解惑!

相关文章:

验证码:
移动技术网