jquery-file-upload angularjs下使用簡介

1.什麼是jquery-file-upload

jQuery File Upload是一個非常優秀的上傳組件,主要使用了XHR作爲上傳方式,並且利用了相當多的現代瀏覽器功能,所以可以實現諸如批量上傳、超大文件上傳、圖片預覽、拖拽上傳、上傳進度顯示、跨域上傳等功能。

美中不足的是jQuery File Upload的默認UI比較複雜,集成了全部功能,讓jQuery File Upload的定製變得比較繁瑣。同時jquery-file-upload官網上對angualrjs集成沒有相關的API,doc 使得jquery-file-upload在angualrjs中難度極爲複雜,網上關於相關集成的文章少之又少,故在此介紹。

 2.jquery-file-upload 與angualrJs 集成效果圖

 批量上傳

拖拽上傳

進度條


影集預覽


自動播放功能


3.相關實現

1.需要的js庫

query-file-upload 方面

預覽效果依賴blueimp 的 gallery庫 相關資源如下:


爲了預覽效果的實現還需要load-image.all.min.js和canvas-to-blob.min.js這兩個js 可以從網上下載

相關資源整合: http://pan.baidu.com/s/1slN6Jox

2.在app中引入相關js css


在app中引入相關module


3.html的編寫

<div >
    <h1>文件上傳</h1>
    <!-- The file upload form used as target for the file upload widget -->
        <div class="panel panel-default">
        <div class="panel-heading">
            <h3 class="panel-title">注意事項</h3>
        </div>
        <div class="panel-body">
            <ul>
                <li>單個圖片上傳大小限制爲<strong>999 KB</strong> (default file size is unlimited).</li>
                <li>前選擇對應格式的圖片上傳 (<strong>JPG, GIF, PNG</strong>)</li>
           </ul>
        </div>
    </div>
    <form id="fileupload"
    	 method="POST" 
    	 data-ng-controller="uploadController";
    	 enctype="multipart/form-data" 
    	 data-file-upload="options" 
    	 data-ng-class="{'fileupload-processing': processing() || loadingFiles}">
        <!-- The fileupload-buttonbar contains buttons to add/delete files and start/cancel the upload -->
        <div class="row fileupload-buttonbar">
            <div class="col-lg-5">
                <!-- The fileinput-button span is used to style the file input field as button -->
                <span class="btn btn-success fileinput-button" ng-class="{disabled: disabled}">
                    <i class="glyphicon glyphicon-plus"></i>
                    <span>添加附件</span>
                    <input type="file" name="files[]" ng-show="options.maxNumberOfFiles==1" ng-disabled="disabled">
                    <input type="file" name="files[]" multiple ng-show="!options.maxNumberOfFiles" ng-disabled="disabled">
                </span>
                <button type="button" class="btn btn-primary start" data-ng-click="submit()">
                    <i class="glyphicon glyphicon-upload"></i>
                    <span>全部開始</span>
                </button>
                <button type="button" class="btn btn-danger cancel" data-ng-click="destoryAll()">
                    <i class="glyphicon glyphicon glyphicon-trash"></i>
                    <span>全部刪除</span> 
                </button>
               
                <!-- The global file processing state -->
                <span class="fileupload-process"></span>
            </div>
            <!-- The global progress state -->
            <div class="col-lg-4 fade" data-ng-class="{in: active()}">
                <!-- The global progress bar -->
                <div class="progress progress-striped active" data-file-upload-progress="progress()"><div class="progress-bar progress-bar-success" data-ng-style="{width: num + '%'}"></div></div>
                <!-- The extended global progress state -->
                <div class="progress-extended"> </div>
            </div>
            <div class="col-lg-3">
            	 <button type="button" class="btn btn-warning" ng-click="cancelUpload()" style="float:right">
		                        <i class="glyphicon glyphicon-ban-circle"></i>
		                        <span>取消</span>
		        </button>
		    	<button type="button" class="btn btn-info" ng-click="saveUpload()" ng-disabled="saveStatus" style="float:right;margin-right:5px">
		                        <i class="glyphicon glyphicon-save"></i>
		                        <span>保存</span>
		        </button>
            </div>
        </div>
        <!-- The table listing the files available for upload/download -->
        <table class="table table-striped files ng-cloak">
            <tr data-ng-repeat="file in queue" data-ng-class="{'processing': file.$processing()}">
                <td data-ng-switch data-on="!!file.thumbnailUrl">
                    <div class="preview" data-ng-switch-when="true">
                        <a data-ng-href="{{file.url}}" title="{{file.name}}" download="{{file.name}}" data-gallery>
                        	<img data-ng-src="{{file.thumbnailUrl}}" alt="" width="80" height="80">
                        </a>
                    </div>
                    <div class="preview" data-ng-switch-default data-file-upload-preview="file"></div>
                </td>
                <td>
                    <p class="name" data-ng-switch data-on="!!file.url">
                        <span data-ng-switch-when="true" data-ng-switch data-on="!!file.thumbnailUrl">
                            <a data-ng-switch-when="true" data-ng-href="{{file.url}}" title="{{file.name}}" download="{{file.name}}" data-gallery>{{file.name}}</a>
                            <a data-ng-switch-default data-ng-href="{{file.url}}" title="{{file.name}}" download="{{file.name}}">{{file.name}}</a>
                        </span>
                        <span data-ng-switch-default>{{file.name}}</span>
                    </p>
                    <strong data-ng-show="file.error" class="error text-danger">{{file.error}}</strong>
                </td>
                <td>
                    <p class="size">{{file.size | formatFileSize}}</p>
                    <div class="progress progress-striped active fade" data-ng-class="{pending: 'in'}[file.$state()]" data-file-upload-progress="file.$progress()"><div class="progress-bar progress-bar-success" data-ng-style="{width: num + '%'}"></div></div>
                </td>
                <td style="text-align:right">
                    <button type="button" class="btn btn-primary start" data-ng-click="file.$submit()" data-ng-hide="!file.$submit || options.autoUpload || file.status" data-ng-disabled="file.$state() == 'pending' || file.$state() == 'rejected'">
                        <i class="glyphicon glyphicon-upload"></i>
                        <span>開始</span>
                    </button>
                    <button type="button" class="btn btn-warning cancel" data-ng-click="file.$cancel()" data-ng-hide="!file.$cancel || file.status">
                        <i class="glyphicon glyphicon-ban-circle"></i>
                        <span>取消</span>
                    </button>
                    <button type="button" class="btn btn-danger destroy" ng-click="destory(file)" data-ng-hide="!file.status">
                        <i class="glyphicon glyphicon-trash"></i>
                        <span>刪除</span>
                    </button>
                </td>
            </tr>
        </table>
        
    </form>
    <br>
</div>
<!-- The blueimp Gallery widget -->
<div id="blueimp-gallery" class="blueimp-gallery blueimp-gallery-controls" data-filter=":even">
    <div class="slides"></div>
    <h3 class="title"></h3>
    <a class="prev">‹</a>
    <a class="next">›</a>
    <a class="close">×</a>
    <a class="play-pause"></a>
    <ol class="indicator"></ol>
</div>

4.controller的編寫

var page=angular.module('upload.view',[]);

page.config(['$httpProvider', 'fileUploadProvider',
         function ($httpProvider, fileUploadProvider) {
             delete $httpProvider.defaults.headers.common['X-Requested-With'];
             fileUploadProvider.defaults.redirect = window.location.href.replace(
                 /\/[^\/]*$/,
                 '/cors/result.html?%s'
             );
             angular.extend(fileUploadProvider.defaults, {
                     disableImageResize: /Android(?!.*Chrome)|Opera/.test(window.navigator.userAgent),
                     maxFileSize: 999000,
                     acceptFileTypes: /(\.|\/)(gif|jpe?g|png)$/i,
                     maxNumberOfFiles :10    
             });
         }
     ]);
    page.controller('uploadController', [ '$scope', '$rootScope', '$http', 'RoleService', '$state', '$stateParams',
        '$window', function($scope, $rootScope, $http, RoleService, $state, $stateParams, $window) {
            var url =  '/servlet/UploadServlet';
            $scope.options = {
                url : url,
                dataType : 'json',
                autoUpload : false,
                acceptFileTypes : /(\.|\/)(gif|jpe?g|png)$/i,
                previewCrop : true,
                maxNumberOfFiles :1
            };
            $scope.queue=[];
            $scope.fileList=[];
            $scope.saveStatus=true;
            
            $scope.$on('fileuploadadd', function(event, data) {
                if($scope.options.maxNumberOfFiles==1){
                    $scope.queue=[];
                }
            });
            
            $scope.$on('fileuploaddone', function(event, data) {
                if(data.result.length==1){
                     var uploadSuccessName=data.result[0].name;
                     var uploadSuccessFileName=data.result[0].fileName;
                     var uploadSuccessStatus=data.result[0].status;
                     var uploadSuccessFileId=data.result[0].fileId;
                    for(var i=0;i<$scope.queue.length;i++){
                      if($scope.queue[i].name==uploadSuccessName){
                          $scope.queue[i].url="/servlet/DownLoadServlet?f="+uploadSuccessFileName;
                          $scope.queue[i].thumbnailUrl="/servlet/DownLoadServlet?f="+uploadSuccessFileName;   
                          $scope.queue[i].status=uploadSuccessStatus;   
                          $scope.queue[i].fileId=uploadSuccessFileId;
                          $scope.saveStatus=false;
                      }
                    }
                }
                for(var i=0;i<$scope.queue.length;i++){
                    if($scope.queue[i].status==1){
                        $scope.saveStatus=false;
                    }else{
                        $scope.saveStatus=true;
                        break;
                    }
                  }
            });
            
            $scope.destoryAll=function(){
                $scope.clear($scope.queue);
                
            }     
            
            $scope.saveUpload=function(){
                $scope.fileList=[];
                for(var i=0;i<$scope.queue.length;i++){
                    if($scope.queue[i].status){
                        $scope.fileList.push($scope.queue[i]);
                    }
                }
                $scope.closeThisDialog($scope.fileList);
            }
            
            $scope.cancelUpload=function(){
                $scope.closeThisDialog();
            }
     
            $scope.destory=function(file){
                $scope.clear(file);
            }
  }]);


客戶端方面代碼就此完成  下面是server端的代碼

UploadServlet

   protected void doPost(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException{
        // 得到上傳文件的保存目錄,將上傳的文件存放於WEB-INF目錄下,不允許外界直接訪問,保證上傳文件的安全
        String savePath = this.getServletContext().getRealPath("/WEB-INF/upload");
        File file = new File(savePath);
        // 判斷上傳文件的保存目錄是否存在
        if (!file.exists() && !file.isDirectory()) {
            System.out.println(savePath + "目錄不存在,需要創建");
            // 創建目錄
            file.mkdirs();
        }
        List<FileMeta> files = new LinkedList<FileMeta>();
        // 1. 使用Apache的FileUpload上傳文件
        files.addAll(MultipartRequestHandler.getInstance().uploadByApacheFileUpload(request, savePath));
        // Remove some files
        while (files.size() > 20) {
            files.remove(0);
        }
        // 2.設置響應類型的JSON
        response.setContentType("application/json");
        // 3. 轉換 List<FileMeta> 爲 JSON 格式
        ObjectMapper mapper = new ObjectMapper();
        // 4. 發送結果到客戶端
        mapper.writeValue(response.getOutputStream(), files);

    }
MultipartRequestHandler
 public  List<FileMeta> uploadByApacheFileUpload(HttpServletRequest request,String savePath) throws IOException, ServletException{
        List<FileMeta> files = new LinkedList<FileMeta>();
        // 1. 檢查要求有多文件內容
        boolean isMultipart = ServletFileUpload.isMultipartContent(request);
        FileMeta temp = null;
        // 2. If yes (it has multipart "files")
        if(isMultipart){
          // 2.1 Apache的FileUpload類實例化
          DiskFileItemFactory factory = new DiskFileItemFactory();
          factory.setSizeThreshold(1024*100);//設置緩衝區的大小爲100KB,如果不指定,那麼緩衝區的大小默認是10KB
          ServletFileUpload upload = new ServletFileUpload(factory);
          upload.setHeaderEncoding("UTF-8"); 
          //設置上傳單個文件的大小的最大值,目前是設置爲1024*1024*5字節,也就是5MB
          upload.setFileSizeMax(1024*1024*5);
          //設置上傳文件總量的最大值,最大值=同時上傳的多個文件的大小的最大值的和,目前設置爲100MB
          upload.setSizeMax(1024*1024*100);
          // 2.2 解析請求
          try {
            // 2.3 得到所有上傳FileItem
            List<FileItem> items = upload.parseRequest(request);
            // 2.4 遍歷每一個FileItem
            for(FileItem item:items){
              // 2.5 如果FileItem不是文件類型 
                if (item.isFormField()) { 
                    
                } else {
                    // 2.7 創建filemeta對象
                    temp = new FileMeta();
                    temp.setContent(item.getInputStream());
                    temp.setFileType(item.getContentType());
                    temp.setSize(item.getSize()/1024+ "Kb");
                    saveFile(temp,item,savePath);
                    temp.setStatus("1");
                    String fileId=saveAttachment(temp);  //保存到數據庫
                    temp.setFileId(fileId);
                    files.add(temp);
               }   
             }
          } catch (FileUploadException e) {
              e.printStackTrace();
          }
        }
        return files;
      }
      
      private  void saveFile(FileMeta temp,FileItem item,String savePath){
          String filename=item.getName();
          //注意:不同的瀏覽器提交的文件名是不一樣的,有些瀏覽器提交上來的文件名是帶有路徑的,如:  c:\a\b\1.txt,
          //而有些只是單純的文件名,如:1.txt
          filename = filename.substring(filename.lastIndexOf("\\")+1);
          temp.setName(filename);
          //得到上傳文件的擴展名
//        String fileExtName = filename.substring(filename.lastIndexOf(".")+1);
          //得到文件保存的名稱 UUID
          String saveFilename=makeFileName(filename);
          temp.setFileName(saveFilename);
          //得到文件的保存目錄  hash打散
          String realSavePath = makePath(saveFilename, savePath);
          try {
              //獲取item中的上傳文件的輸入流
              InputStream in = item.getInputStream();
              //創建一個文件輸出流
              FileOutputStream out = new FileOutputStream(realSavePath + "\\" + saveFilename);
              //創建一個緩衝區
              byte buffer[] = new byte[1024];
              //判斷輸入流中的數據是否已經讀完的標識
              int len = 0;
              //循環將輸入流讀入到緩衝區當中,(len=in.read(buffer))>0就表示in裏面還有數據
              while((len=in.read(buffer))>0){
                 //使用FileOutputStream輸出流將緩衝區的數據寫入到指定的目錄(savePath + "\\" + filename)當中
                 out.write(buffer, 0, len);
              }
              //關閉輸入流  關閉輸出流  刪除處理文件上傳時生成的臨時文件
              in.close();
              out.flush();
              out.close();
              item.delete();
            } catch (Exception e) {
                temp.setError("上傳失敗,文件類型錯誤/超過上傳大小限制");
                e.printStackTrace();
            } 
      }
     
      private String saveAttachment(FileMeta temp){
         Attachment attachment=new Attachment();
         attachment.setAttachmentId(temp.getFileName());
         attachment.setName(temp.getName());
         attachment.setFileType(temp.getFileType());
         attachment.setSize(temp.getSize());
         String id=attachmentService.saveAttachment(attachment);
         return id;
      }
    /**
     * @Method: makeFileName
     * @Description: 生成上傳文件的文件名,文件名以:uuid+"_"+文件的原始名稱
     */
    private static String makeFileName(String filename) { // 2.jpg
        // 爲防止文件覆蓋的現象發生,要爲上傳文件產生一個唯一的文件名
        return UUID.randomUUID().toString() + "_" + filename;
    }

    /**
     * 爲防止一個目錄下面出現太多文件,要使用hash算法打散存儲
     */
    private static String makePath(String filename, String savePath) {
        // 得到文件名的hashCode的值,得到的就是filename這個字符串對象在內存中的地址
        int hashcode = filename.hashCode();
        int dir1 = hashcode & 0xf; // 0--15
        int dir2 = (hashcode & 0xf0) >> 4; // 0-15
        // 構造新的保存目錄
        String dir = savePath + "\\" + dir1 + "\\" + dir2; // upload\2\3 upload\3\5
        // File既可以代表文件也可以代表目錄
        File file = new File(dir);
        // 如果目錄不存在
        if (!file.exists()) {
            // 創建目錄
            file.mkdirs();
        }
        return dir;
    }
FileMeta
@JsonIgnoreProperties({"content"})
public class FileMeta {
    
    private String fileName;
    private String fileType;
    private String size;
    private String thumbnailUrl;
    private String url;
    private String name;
    private String error;
    private String status;
    private InputStream content;
    private String fileId;

    public String getFileId() {
        return fileId;
    }

    public void setFileId(String fileId) {
        this.fileId = fileId;
    }

    public String getFileName() {
        return fileName;
    }

    public void setFileName(String fileName) {
        this.fileName = fileName;
    }

    public String getFileType() {
        return fileType;
    }

    public void setFileType(String fileType) {
        this.fileType = fileType;
    }

    public InputStream getContent() {
        return content;
    }

    public void setContent(InputStream content) {
        this.content = content;
    }

    public String getSize() {
        return size;
    }

    public void setSize(String size) {
        this.size = size;
    }

    public String getThumbnailUrl() {
        return thumbnailUrl;
    }

    public void setThumbnailUrl(String thumbnailUrl) {
        this.thumbnailUrl = thumbnailUrl;
    }

    public String getUrl() {
        return url;
    }

    public void setUrl(String url) {
        this.url = url;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getError() {
        return error;
    }

    public void setError(String error) {
        this.error = error;
    }

    public String getStatus() {
        return status;
    }

    public void setStatus(String status) {
        this.status = status;
    }

原理:上傳成功後服務器需向客戶端返回上傳成功的files 方便jquery-file-upload進行解析 以此判斷上傳狀態 進行下載 預覽等後續操作

文件下載Servlet

package com.apusic.justice.wx.util;

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.net.URLEncoder;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

/**
 * 下載文件Servlet
 * 
 * @author zhaoyang
 * 
 */

public class DownLoadServlet extends HttpServlet {

    private static final long serialVersionUID = 1L;

    public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        // 得到要下載的文件名
        request.setCharacterEncoding("UTF-8");
        String fileName = request.getParameter("f"); // 23239283-92489-QQ圖片.jpg
        // 上傳的文件都是保存在/WEB-INF/upload目錄下的子目錄當中
        String fileSaveRootPath = this.getServletContext().getRealPath("/WEB-INF/upload");
        // 通過文件名找出文件的所在目錄
        String path = findFileSavePathByFileName(fileName, fileSaveRootPath);
        // 得到要下載的文件
        File file = new File(path + "\\" + fileName);
        // 如果文件不存在
        if (!file.exists()) {
            return;
        }
        // 處理文件名
        String realname = fileName.substring(fileName.indexOf("_") + 1);
        // 設置響應頭,控制瀏覽器下載該文件
        response.setHeader("content-disposition", "attachment;filename=" + URLEncoder.encode(realname, "UTF-8"));
        // 讀取要下載的文件,保存到文件輸入流
        FileInputStream in = new FileInputStream(path + "\\" + fileName);
        // 創建輸出流
        OutputStream out = response.getOutputStream();
        // 創建緩衝區
        byte buffer[] = new byte[1024];
        int len = 0;
        // 循環將輸入流中的內容讀取到緩衝區當中
        while ((len = in.read(buffer)) > 0) {
            // 輸出緩衝區的內容到瀏覽器,實現文件下載
            out.write(buffer, 0, len);
        }
        // 關閉文件輸入流
        in.close();
        // 關閉輸出流
        out.close();
    }

    /**
     * @Method: findFileSavePathByFileName
     * @Description: 通過文件名和存儲上傳文件根目錄找出要下載的文件的所在路徑
     */
    public String findFileSavePathByFileName(String filename, String saveRootPath) {
        int hashcode = filename.hashCode();
        int dir1 = hashcode & 0xf; // 0--15
        int dir2 = (hashcode & 0xf0) >> 4; // 0-15
        String dir = saveRootPath + "\\" + dir1 + "\\" + dir2; // upload\2\3 upload\3\5
        File file = new File(dir);
        if (!file.exists()) {
            // 創建目錄
            file.mkdirs();
        }
        return dir;
    }

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

web.xml

<servlet>
     <servlet-name>UploadServlet</servlet-name>
     <servlet-class>com.a_1.a_1.wx.util.UploadServlet</servlet-class>
 	</servlet>
	 <servlet-mapping>
	     <servlet-name>UploadServlet</servlet-name>
	     <url-pattern>/servlet/UploadServlet</url-pattern>
	 </servlet-mapping>   
	  
	<servlet>
	     <servlet-name>DownLoadServlet</servlet-name>
	     <servlet-class>com.a_1.a_1.wx.util.DownLoadServlet</servlet-class>
 	</servlet>
	 <servlet-mapping>
	     <servlet-name>DownLoadServlet</servlet-name>
	     <url-pattern>/servlet/DownLoadServlet</url-pattern>
	 </servlet-mapping> 


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章