国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁 > 編程 > Java > 正文

java基于servlet實現文件上傳功能解析

2019-11-26 14:18:13
字體:
來源:轉載
供稿:網友

最近項目需要做一個文件上傳功能,做完了分享下,順帶當做筆記。
上傳功能用后臺用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"http://圖片     }; 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("http://.");   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文件

//顯示上傳信息的htmlvar 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的IDvar 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";//上傳文件的請求urlvar gurl = "getProgress";//獲取上傳進度信息的urlvar cancelFlag = 0;//取消標志var timer, waittimer;//定時器var nowID = 0;//正在上傳文件的idvar 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("&timeStamp=" + (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程序設計有所幫助。

發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
主站蜘蛛池模板: 安阳县| 曲水县| 双江| 广南县| 黎川县| 彭山县| 奇台县| 玉田县| 手机| 木兰县| 青浦区| 酉阳| 乐山市| 余江县| 武义县| 宁陕县| 新干县| 祁东县| 榆社县| 盘锦市| 安乡县| 鹿泉市| 临武县| 澄江县| 吴桥县| 古田县| 桂阳县| 宁远县| 渑池县| 乐昌市| 彭山县| 汝阳县| 建阳市| 利辛县| 安吉县| 丰宁| 小金县| 彰化市| 南乐县| 岑溪市| 故城县|