1. 程式人生 > >Bootstrap框架---krajee外掛fileinput--最好用的檔案上傳元件----單多張圖片上傳互動方式三(推薦)

Bootstrap框架---krajee外掛fileinput--最好用的檔案上傳元件----單多張圖片上傳互動方式三(推薦)

我們在前一章已經實現了 Bootstrap框架---Uploadify外掛----多張圖片上傳互動方式二 。

本章主要關注單多張圖片上傳在Bootstrap框架中的佈局和實現。

我們在之前的文章中已經在SpringMVC基礎框架的基礎上應用了BootStrap的後臺框架,在此基礎上記錄 單多張圖片上傳在Bootstrap框架中的佈局方式三和實現

基礎專案原始碼下載地址為:

我們在基礎專案中已經做好了首頁index的訪問。
現在就在index.jsp頁面和index的路由Controller上做修改,實現  單多張圖片上傳在Bootstrap框架中的佈局和實現

效果圖



Krajee的FileInput外掛介紹

介紹

外掛主頁地址是:

http://plugins.krajee.com/file-input

可以從這裡看到很多Demo的程式碼展示:

http://plugins.krajee.com/file-basic-usage-demo

這是一個增強的 HTML5 檔案輸入控制元件,是一個 Bootstrap 3.x 的擴充套件,實現檔案上傳預覽,多檔案上傳等功能:

bootstrap-fileinput是一款基於Bootstrap 3.x的html5檔案上傳外掛。該檔案上傳外掛帶有預覽圖效果,可同時選擇多個檔案。該外掛使用bootstrap CSS3樣式來製作檔案上傳介面,美觀大方。並且它提供了多國語言,你可以選擇使用中文。

該檔案上傳外掛比普通的檔案上傳外掛功能更強大,它可以對圖片、文字檔案、HTML檔案、視訊檔案、音訊檔案、flash檔案生成預覽圖。另外,它還可以基於AJAX上傳檔案,拖拽上傳檔案,檢視上傳進度,可以選擇性的預覽,新增或刪除檔案。

特點

該檔案上傳外掛的特點有:

AJAX上傳功能基於HTML5 FormData(絕大多數現代瀏覽器都支援該屬性)。在不支援該屬性的瀏覽器中會回退為普通的檔案上傳元件。使用AJAX必須設定uploadUrl屬性。

允許你新增、移除和追加檔案。新增的檔案可以生成預覽圖。
可以將檔案拖拽到指定區域來上傳檔案。
可以一個個的刪除或更新檔案,也可以同時完成這些操作。
如果showPreview屬性設定為false,或者瀏覽器不支援uploadUrl屬性,將會回退為普通的檔案上傳元件。
可以配置檔案上傳等待指示,檔案上傳成功資訊,檔案上傳出錯資訊。
在使用ajax上傳檔案時可以新增額外的表單資訊。
可以顯示檔案當前上傳的進度。
可以取消和終止當前正在上傳的任務。
檔案上傳完畢會自動重新整理預覽區域的內容。

外掛外部依賴需求


Bootstrap 3.x

最新版本的jQuery

大多數現代瀏覽器都支援HTML5(inputs和FileReader AP),CSS3和jQuery。對於IE瀏覽器,必須是IE10以上的版本。IE9及以下的版本會回退為普通的檔案上傳元件,並且不支援選擇多個檔案和HTML 5 FileReader API。

AJAX上傳需要瀏覽器支援HTML5 FormData和XHR2 (XMLHttpRequest 2)。大多數現代瀏覽器都支援FormData和XHR2。在不支援這些特性的瀏覽器中將會回退為普通的檔案上傳元件。

引用

一般情況下,我們需要引入下面兩個檔案,外掛才能正常使用:

bootstrap-fileinput/css/fileinput.min.css
bootstrap-fileinput/js/fileinput.min.js
簡單的介面效果如下所示,和眾多上傳檔案控制元件一樣,可以接受各種型別的檔案。當然,我們也可以指定具體接受的檔案型別等功能。
如果需要考慮中文化,那麼還需要引入檔案:

bootstrap-fileinput/js/fileinput_locale_zh.js

下載檔案地址:

https://github.com/kartik-v/bootstrap-fileinput

http://download.csdn.net/detail/q383965374/9879093


下載解壓後得到相關資原始檔。

我們在自己的專案資原始檔夾中新建目錄bootstrap-fileinput,把相關檔案放進去。如圖所示:


在index.jsp中引用檔案程式碼如下:

<link type="text/css" rel="stylesheet" href="/res/bootstrap-fileinput/css/fileinput.css" />
<script type="text/javascript" src="/res/bootstrap-fileinput/js/fileinput.js"></script>
<script type="text/javascript" src="/res/bootstrap-fileinput/js/zh.js"></script>


初始化外掛

// initialize with defaults
$("#input-id").fileinput();
 
// with plugin options
$("#input-id").fileinput({'showUpload':false, 'previewFileType':'any'});       

#input-id是檔案上傳input元素的ID識別符號(例如:type = file)。

你也可以直接通過HTML5 data屬性來初始化外掛。

<input id="input-id" type="file" class="file" data-preview-file-type="text" >        

        

或者使用封裝方法

html程式碼

<div class="row" style="height: 500px">
<input id="file-Portrait" type="file">
</div>

JS程式碼

//初始化fileinput控制元件(第一次初始化)
function initFileInput(ctrlName, uploadUrl) {    
    var control = $('#' + ctrlName); 
    control.fileinput({
        language: 'zh', //設定語言
        uploadUrl: uploadUrl, //上傳的地址
        allowedFileExtensions : ['jpg', 'png','gif'],//接收的檔案字尾
        showUpload: false, //是否顯示上傳按鈕
        showCaption: false,//是否顯示標題
        browseClass: "btn btn-primary", //按鈕樣式             
        previewFileIcon: "<i class='glyphicon glyphicon-king'></i>", 
    });
}


//初始化fileinput控制元件(第一次初始化)
initFileInput("file-Portrait", "/User/EditPortrait");


 配置引數


showCaption:是否顯示檔案的標題。預設值true。
showPreview:是否顯示檔案的預覽圖。預設值true。
showRemove:是否顯示刪除/清空按鈕。預設值true。
showUpload:是否顯示檔案上傳按鈕。預設是submit按鈕,除非指定了uploadUrl屬性。預設值true。
showCancel:是否顯示取消檔案上傳按鈕。只有在AJAX上傳執行緒中該屬性才可見可用。預設值true。
captionClass:在標題容器上額外的class。型別string。
previewClass:在預覽區域容器上的額外的class。型別string。
mainClass:新增在檔案上傳主容器。型別string。
initialDelimiter:在initialPreview屬性中用於上傳多個檔案時的分隔符。預設值:'*$$*'。
initialPreview:型別string或array。顯示的初始化預覽內容。你可以傳入一個簡單的HTML標籤用於顯示圖片、文字或檔案。如果設定一個字串,會在初始化預覽圖中顯示一個檔案。你可以在initialDelimiter屬性中設定分隔符用於顯示多個預覽圖。如果設定為陣列,初始化預覽圖中會顯示陣列中所有的檔案。
下面的CSS樣式用於顯示各種不同型別的檔案預覽圖:
image files:CSS樣式為file-preview-image
text files:CSS樣式為file-preview-text
other files:CSS樣式為file-preview-other
下面的例子是如何設定不同型別檔案的初始化預覽圖:

// for image files
initialPreview: [
    "<img src='/images/desert.jpg' class='file-preview-image' alt='Desert' title='Desert'>",
    "<img src='/images/jellyfish.jpg' class='file-preview-image' alt='Jelly Fish' title='Jelly Fish'>",
],
 
// for text files
initialPreview: "<div class='file-preview-text' title='NOTES.txt'>" +
    "This is the sample text file content upto wrapTextLength of 250 characters" +
    "<span class='wrap-indicator' onclick='$(\"#show-detailed-text\").modal(\"show\")' title='NOTES.txt'>[…]</span>" +
    "</div>"
 
// for other files    
initialPreview: "<div class='file-preview-text'>" + 
    "<h2><i class='glyphicon glyphicon-file'></i></h2>" +
    "Filename.xlsx" + "</div>"

initialPreviewCount:型別int。被新增到選擇的檔案的初始化預覽圖的數量。當overwriteInitial屬性設定為false時,該引數可以顯示正確的檔案標題。

initialPreviewDelimiter:型別string。用於分割初始化預覽圖內容的分割符。只有在initialPreview屬性傳入的引數是字串而不是陣列時可用。預設值是:*$$*。


initialPreviewConfig:型別:array。每一個initialPreview項的配置屬性。陣列中的每一個元素都應該是下面關鍵字組成的物件或關聯陣列:

- `caption`: _string_, the caption or filename to display for each initial preview item content.
- `width`: _string_, the CSS width of the image/content displayed.
- `url`: _string_, the URL for deleting the image/content in the initial preview via AJAX post response. This will default to `deleteUrl` if not set.
- `key`: _string|object_, the key that will be passed as data to the `url` via AJAX POST.
- `extra`: _object|function_, the extra data that will be passed as data to the initial preview delete url/AJAX server call via POST. This will default to `deleteExtraData` if not set.


下面是配置initialPreviewConfig屬性的一個例子。
// setup initial preview with data keys 
initialPreview: [
    "<img src='/images/desert.jpg' class='file-preview-image' alt='Desert' title='Desert'>",
    "<img src='/images/jellyfish.jpg' class='file-preview-image' alt='Jelly Fish' title='Jelly Fish'>",
],
// initial preview configuration
initialPreviewConfig: [
    {
        caption: 'desert.jpg', 
        width: '120px', 
        url: '/localhost/avatar/delete', 
        key: 100, 
        extra: {id: 100}
    },
    {
        caption: 'jellyfish.jpg', 
        width: '120px', 
        url: '/localhost/avatar/delete', 
        key: 101, 
        extra: function() { 
            return {id: $("#id").val()};
        },
    }
] 


注意:ajax delete操作會通過POST向伺服器傳送下面的資料:
key:在initialPreviewConfig['key']中設定的key值。
通過initialPreviewConfig['extra']或deleteExtraData格式傳入的其它作為key: value鍵值對資料。
initialPreviewShowDelete:是否為每一個由initialPreview外掛的預覽圖建立一個刪除按鈕。


previewThumbTags:型別array。預覽圖的一組標籤。它會在預覽圖生成之後動態的替換掉縮圖標籤。例如:

// change thumbnail footer template
layoutTemplates.footer = '<div class="file-thumbnail-footer">\n' +
'    <div class="file-caption-name">{caption}</div>\n' +
'    {CUSTOM_TAG_NEW}\n' +
'    {CUSTOM_TAG_INIT}\n' +
'    {actions}\n' +
'</div>';
 
// set preview template tags
previewThumbTags = {
    '{CUSTOM_TAG_NEW}': '<span class="custom-css">CUSTOM MARKUP</span>',
    '{CUSTOM_TAG_INIT}': ' '
};  

上面只是該檔案上傳外掛一部分的屬性,要檢視完整的屬性和可用方法,可以檢視:

https://github.com/kartik-v/bootstrap-fileinput/

也可以檢視 fileinput.js中的$.fn.fileinput.defaults方法,如圖:


JSP頁面

<%@ include file="./include/header.jsp"%>
<%@ taglib uri="com.data.web.view.function" prefix="cf" %>
<style>
/*uploadfive上傳外掛背景按鈕圖樣式*/
.upload-image {
    height: 200px;
    width: 200px;
    background-image: url(/res/assets/img/demoUpload.jpg);
    background-color: white;
    background-repeat: no-repeat;
    background-size: contain;
    background-origin: content-box;
    background-position: center;
    background-size: contain;
    background-origin: content-box;
}
</style>
        <div id="page-wrapper">
            <div id="page-inner">




                <div class="row">
                    <div class="col-md-12">
                        <h1 class="page-header">
                            多張(動態)圖片上傳 <small>Uploadify</small>
                        </h1>
                    </div>
                </div>
                <!-- /. ROW  -->


     <form class="form-horizontal" id="base">
                 <input type="text" value="${pic.id}" id="id" name="id" hidden/>
                <div class="form-group">
                    <label for="name" class="col-sm-2 control-label">名稱:</label>
                    <div class="col-sm-10">
                        <input type="text" class="form-control" id="name" name="name" value="${pic.name}"
                               placeholder="">
                    </div>
                </div>
                <div class="form-group ">
                    <label class="col-sm-2 control-label">描述:</label>
                    <div class="col-sm-10">
                        <textarea id="description" name="description" class="form-control"
                                  rows="8">${pic.description}</textarea>
                    </div>
                </div>
              
                <div class="form-group">
                <label class="col-sm-2 control-label">圖片上傳:</label>
                <div class="col-sm-10">
        <input id="file-0a" class="file file-loading" type="file" multiple 
           data-min-file-count="1" name="upload_file" >
                </div>
                </div>
                  <div class="form-group " id="pics">
                  </div>
                <div class="form-group">
                    <div class="col-sm-6 col-sm-offset-2">
                        <button type="button" class="btn btn-default cancel"
                                data-dismiss="modal">取消
                        </button>
                        <button type="button" class="btn btn-primary save"
                                data-loading-text="Saving...">確認
                        </button>
                    </div>
                </div>
           </form>  
                <!-- /. ROW  -->
            </div>
            <!-- /. PAGE INNER  -->
        </div>
        <!-- /. PAGE WRAPPER  -->


    


        
        




 <%@ include file="./include/footer.jsp"%>
 <link type="text/css" rel="stylesheet" href="/res/bootstrap-fileinput/css/fileinput.css" />
<script type="text/javascript" src="/res/bootstrap-fileinput/js/fileinput.js"></script>
<script type="text/javascript" src="/res/bootstrap-fileinput/js/zh.js"></script>
<script type="text/javascript">
/**
 * jQuery form 擴充套件獲取資料
 */
$.fn.formGet = function(opts) {
opts = $.extend({}, opts);
var data = {},
  els = opts.formGroup ? this.find('[form-group="' + opts.formGroup + '"]') : this.find('[name]');
if (!els || !els.length) {
  return data;
}


var fnSetValue = (function(emptyToNull) {
  return emptyToNull ? function(obj, propertyChain, value, allowMulti) {
    value !== '' && _fnObjectSetPropertyChainValue(obj, propertyChain, value, allowMulti)
  } : _fnObjectSetPropertyChainValue
})(opts.emptyToNull);


els.each(function() {
  var $this = $(this),
    type = $this.attr('type'),
    name = $this.attr('name'), // 可能為屬性鏈
    tag = this.tagName.toLowerCase();
  if (tag == 'input') {
    if (type == 'checkbox') {
      var v = $(this).val();
      if (v == 'on' || !v) {
        fnSetValue(data, name, $(this).prop('checked'));
      } else {
        $(this).prop('checked') && fnSetValue(data, name, v, true);
      }
    } else if (type == 'radio') {
      this.checked && fnSetValue(data, name, $this.val());
    } else {
      fnSetValue(data, name, $this.val());
    }
  } else if ('|select|textarea|'.indexOf('|' + tag + '|') > -1) {
    fnSetValue(data, name, $this.val());
  } else {
    fnSetValue(data, name, $.trim($this.text()));
  }
});
return data;
};




/**  
 * 內部私有方法  
 */  
var _fnObjectGetPropertyChainValue = function(obj, propertyChain) {  
  /* 獲取屬性鏈的值 */  
  if (!obj) return;  
  if (!propertyChain) return obj;  
  var property,  
    chains = propertyChain.split('.'),  
    i = 0,  
    len = chains.length;  
  for (;  
    (property = chains[i]) && i < len - 1; i++) {  
    if (!obj[property]) return;  
    obj = obj[property];  
  }  
  return obj[property];  
},  
_fnObjectSetPropertyChainValue = function(obj, propertyChain, value, allowMulti) {  
  /* 設定屬性鏈的值 */  
  if (!obj || !propertyChain) return;  
  var property,  
    chainObj = obj,  
    chains = propertyChain.split('.'),  
    i = 0,  
    len = chains.length;  
  for (;  
    (property = chains[i]) && i < len - 1; i++) {  
    if (!chainObj[property]) {  
      chainObj[property] = {};  
    }  
    chainObj = chainObj[property];  
  }  
  // 改進版:checkbox的多選可以組合為陣列  
  if (!allowMulti || chainObj[property] === undefined) {  
    chainObj[property] = value;  
  } else {  
    var pv = chainObj[property];  
    if ($.isArray(pv)) {  
      pv.push(value);  
    } else {  
      chainObj[property] = [pv, value];  
    }  
  }  
  return obj;  
};  
  


//初始化外掛
$("#file-0a").fileinput({
uploadUrl : "/upload",//上傳檔案的url--對應後臺的接收controller
language: 'zh', //設定語言
allowedFileExtensions : [ 'jpg', 'png', 'gif' ],
overwriteInitial : false,
dropZoneEnabled: false,//禁用dropZone區域,選擇圖片後才顯示預覽區域(推薦)
//showPreview: false,//隱藏dropZone和預覽區
//showBrowse: false,//隱藏選擇框的選擇按鈕
//showUpload: false,//隱藏選擇框的上傳按鈕
//showCaption: false,//隱藏選擇欄的input
//captionClass:'col-sm-10',//在標題容器上額外的class
//previewClass:'col-sm-10',//在預覽容器上額外的class
//mainClass:'col-sm-10',//新增在檔案上傳主容器額外的class
maxFileSize : 2000,//上傳檔案最大的尺寸
maxFilesNum : 3,//上傳最大的檔案數量
initialCaption: "請上傳圖片",//文字框初始話value
//allowedFileTypes: ['image', 'video', 'flash'],
slugCallback : function(filename) {
return filename.replace('(', '_').replace(']', '_');
}
});




//上傳成功後回撥函式
$('#file-0a').on('fileuploaded', function(event, data, previewId, index) {
debugger;
var form = data.form, files = data.files, extra = data.extra,
response = data.response, reader = data.reader;
console.log(response);//打印出返回的json
console.log("${hostname}"+response.result);//打印出路徑
$("#pics").append('<input type="hidden" class="imagePaths" name="imagePaths_'+index+'.filePath"  value="'+"${hostname}"+response.result+'">'); 


});






  
    $(document).ready(function () {
        /*END-儲存表單-END*/
        $('button.save').on('click', function () {
            debugger;
            var data = $('#base').formGet();
            var imagePaths = new Array();
            var length=$('.imagePaths').length;
           for(var i=0;i<length;i++){
           var index=eval('data.imagePaths_'+i);
            imagePaths.push(index);
            }
            data.imagePaths=imagePaths;
            $.ajax({
                type: "POST",
                url: "/pic/save",
                contentType: "application/json",
                data: JSON.stringify(data),
                success: function (result) {
                    console.log(result);
                    if (!result.code) 
                    {
                        alert(result.data);
                    } else {
                        alert(result.msg);
                    }
                },
                error: function (result) {
                    alert("出錯了,請稍後重試");
                }
            });
        });
    });


</script>




</body>


</html>


返回資訊輔助實體類

AjaxResult.java

package com.test.util;

import org.springframework.data.annotation.Transient;

/**
 * AjaxResult
 * 
 * 標準化的ajax響應, 取代之前直接返回結果的方式。
 * 
 */
public class AjaxResult {

	@Transient
	public static final int CODE_SUCCESS = 1;
	@Transient
	public static final int CODE_FAILURE = 0;
	@Transient
	public static final AjaxResult RESULT_ERROR = new AjaxResult(
			CODE_FAILURE, "執行出錯了", null);
	@Transient
	public static final AjaxResult RESULT_SUCCESS = new AjaxResult(
			CODE_SUCCESS, null, null);
	@Transient
	public static final AjaxResult RESULT_INVAILD_PARAMETER = new AjaxResult(
			CODE_FAILURE, "引數格式不正確", null);

	private int code = CODE_FAILURE;
	private String error;
	private Object result;

	public static AjaxResult resultError(String error) {
		return new AjaxResult(CODE_FAILURE, error, null);
	}

	public static AjaxResult resultSuccess(Object result) {
		return new AjaxResult(CODE_SUCCESS, null, result);
	}

	/**
	 * @param code
	 * @param error
	 * @param result
	 */
	public AjaxResult(int code, String error, Object result) {
		super();
		this.code = code;
		this.error = error;
		this.result = result;
	}

	/**
	 * @return the code
	 */
	public int getCode() {
		return code;
	}

	/**
	 * @param code
	 *            the code to set
	 */
	public void setCode(int code) {
		this.code = code;
	}

	/**
	 * @return the error
	 */
	public String getError() {
		return error;
	}

	/**
	 * @param error
	 *            the error to set
	 */
	public void setError(String error) {
		this.error = error;
	}

	/**
	 * @return the result
	 */
	public Object getResult() {
		return result;
	}

	/**
	 * @param result
	 *            the result to set
	 */
	public void setResult(Object result) {
		this.result = result;
	}
}


JSONResult.java

package com.test.util;

/**
 * JSONResult
 * 標準化的JSON響應
 * 
 * <pre>
 * {@link JSONResult#success(Object)}
 * {@link JSONResult#error(String)}
 * </pre>
 * 
 * 
 */
public class JSONResult {

	/**
	 * 成功的程式碼
	 */
	public static final int			CODE_SUCCESS			= 0;

	/**
	 * 錯誤的程式碼,可根據錯誤型別進行詳細分類
	 */
	public static final int			CODE_ERROR				= -1;

	/**
	 * 空白的成功響應
	 */
	public static final JSONResult	RESULT_SUCCESS_NO_DATA	= new JSONResult(CODE_SUCCESS, null, null);

	private int						code;
	private String					msg;
	private Object					data;

	/**
	 * 建立一個成功的響應
	 * 
	 * @param data
	 * @return
	 */
	public static JSONResult success(Object data) {
		return new JSONResult(CODE_SUCCESS, null, data);
	}

	/**
	 * 建立一個錯誤的響應
	 * 
	 * @param msg
	 * @return
	 */
	public static JSONResult error(String msg) {
		return new JSONResult(CODE_ERROR, msg, null);
	}

	/**
	 * @param code
	 * @param msg
	 * @param data
	 */
	public JSONResult(int code, String msg, Object data) {
		this.code = code;
		this.setMsg(msg);
		this.data = data;
	}

	public int getCode() {
		return code;
	}

	public JSONResult setCode(int code) {
		this.code = code;
		return this;
	}

	public Object getData() {
		return data;
	}

	public JSONResult setData(Object data) {
		this.data = data;
		return this;
	}

	public String getMsg() {
		return msg;
	}

	public JSONResult setMsg(String msg) {
		this.msg = msg;
		return this;
	}

}


Pic.java

package com.test.domain.entity;


import java.util.List;

public class Pic {
private String id;
private String name;
private String description;
private List<Image> imagePaths; // 圖片
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getDescription() {
return description;
}
public void setDescription(String description) {
this.description = description;
}
public List<Image> getImagePaths() {
return imagePaths;
}
public void setImagePaths(List<Image> imagePaths) {
this.imagePaths = imagePaths;
}



}





Image.java

package com.test.domain.entity;

/**
 * 圖片 Image
 */
public class Image {

    private String title; //名稱
    private String description; //描述
    private String filePath; //檔案地址

    public String getTitle() {
        return title;
    }

    public void setTitle(String title) {
        this.title = title;
    }

    public String getDescription() {
        return description;
    }

    public void setDescription(String description) {
        this.description = description;
    }

    public String getFilePath() {
        return filePath;
    }

    public void setFilePath(String filePath) {
        this.filePath = filePath;
    }

    public Image() {
    }

    /**
     * @param title
     * @param filePath
     */
    public Image(String title, String filePath) {
        this.title = title;
        this.filePath = filePath;
    }
}


頁面路由控制器

IndexController.java

package com.test.web.controller;


import java.io.IOException;


import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;


import com.test.domain.entity.Pic;
import com.test.util.JSONResult;


/**
 * IndexController
 * 
 * 
 */
@Controller
public class IndexController {


@RequestMapping("/")
public String index(Model model) throws IOException {
          model.addAttribute("hostname", "http://127.0.0.1:8080/");
return "/index";
}



@RequestMapping("/pic/save")
@ResponseBody
public JSONResult saveMigrateLine(@RequestBody Pic pic) {
//儲存pic記錄
//int result = save(pic);
int result =1;
return result > 0 ? JSONResult.success("儲存成功")
:JSONResult.error("儲存失敗!");
}
}



檔案上傳接收控制器

UploadController.java

package com.test.web.controller;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;

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

import org.apache.commons.fileupload.FileItem;
import org.apache.commons.fileupload.FileUploadException;
import org.apache.commons.fileupload.disk.DiskFileItemFactory;
import org.apache.commons.fileupload.servlet.ServletFileUpload;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;

import com.test.util.AjaxResult;

/**
 * 通用的上傳(儲存到本地伺服器)
 * 
 */
@Controller
public class UploadController {

    private final Logger logger = LoggerFactory.getLogger(getClass().getName());

    /**
     * 上傳到伺服器,檔名稱隨機生成(基本可以保證不重複)
     * 
     * @param request
     * @param response
     * @return AjaxResult 儲存的檔案的相對路徑
     * @throws IOException 
     */
    @RequestMapping("/upload")
    @ResponseBody
    public AjaxResult upload(HttpServletRequest request, HttpServletResponse response) throws IOException {
        try {
        	String filePath="/uploadfile";
        	//獲取檔案儲存路徑  (虛擬目錄對映為本機伺服器的實際目錄)
            String path = request.getSession().getServletContext().getRealPath(filePath); 
        	//如果儲存在ROOT裡,重新發包後靜態資源會丟失,所以儲存在ROOT包的上級路徑webapp中
            path=path.replace("ROOT\\", "");
            String fileNameResult ="";
            // 判斷enctype屬性是否為multipart/form-data  
            boolean isMultipart = ServletFileUpload.isMultipartContent(request);  
            if (!isMultipart)  
                throw new IllegalArgumentException(  
                        "上傳內容不是有效的multipart/form-data型別.");  
      
            // Create a factory for disk-based file items  
            DiskFileItemFactory factory = new DiskFileItemFactory();  
      
            // Create a new file upload handler  
            ServletFileUpload upload = new ServletFileUpload(factory);  
            // Parse the request  
            List<?> items = upload.parseRequest(request);  
      
            Iterator iter = items.iterator();  
            while (iter.hasNext()) {  
                FileItem item = (FileItem) iter.next();  
      
                if (item.isFormField()) {  
                    // 如果是普通表單欄位  
                    String name = item.getFieldName();  
                    String value = item.getString();  
                    // ...  
                } else {  
                    // 如果是檔案欄位  
                    String fieldName = item.getFieldName();  
                    String fileName = item.getName();  
                    String contentType = item.getContentType();  
                    boolean isInMemory = item.isInMemory();  
                    long sizeInBytes = item.getSize();  
                    String fileExt = fileName.substring(fileName.lastIndexOf('.'));
                    String fileNameNew =getFileNameNew()+fileExt;
                    fileNameResult=fileNameNew;
                    //儲存到本地
                        InputStream uploadedStream = item.getInputStream();  
                        savePic(path,uploadedStream,fileNameNew);
                        uploadedStream.close();  
                }  
            }  
            
            return AjaxResult.resultSuccess(filePath+"/"+fileNameResult);
        } catch (FileUploadException e) {
            logger.warn(e.getMessage(), e);
            return AjaxResult.resultError(e.getMessage());
        }
    }
    
    private void savePic(String path,InputStream inputStream, String fileName) {
    	 
        OutputStream os = null;
        try {
          // 2、儲存到臨時檔案
          // 1K的資料緩衝
          byte[] bs = new byte[1024];
          // 讀取到的資料長度
          int len;
          // 輸出的檔案流儲存到本地檔案
     
          File tempFile = new File(path);
          if (!tempFile.exists()) {
            tempFile.mkdirs();
            //如果圖片是儲存在ROOT專案外,首次建立目錄,tomcat載入需要時間,所以需要延遲10秒
            Thread.sleep(10000);
          }
          os = new FileOutputStream(tempFile.getPath() + File.separator + fileName);
          // 開始讀取
          while ((len = inputStream.read(bs)) != -1) {
            os.write(bs, 0, len);
          }
     
        } catch (IOException e) {
          e.printStackTrace();
        } catch (Exception e) {
          e.printStackTrace();
        } finally {
          // 完畢,關閉所有連結
          try {
            os.close();
            inputStream.close();
          } catch (IOException e) {
            e.printStackTrace();
          }
        }
      }

    private String getFileNameNew() {
        SimpleDateFormat fmt = new SimpleDateFormat("yyyyMMddHHmmssSSS");
        return fmt.format(new Date());
      }

}


目前上傳的檔案是接收後儲存到本地伺服器中,如果要上傳到遠端伺服器或者七牛雲等,只需要修改UploadController.java即可。

這裡只給出了 uploadify 上傳圖片的案例。 但其實 這個DEMO也可以用於上傳 zip等檔案。 只需要稍微調整jsp頁面把圖片顯示去掉即可。