博客地址:https://ainyi.com/76
日常,工作
在這里總結一下上傳吧(是以前做過的練習,就匯總到個人博客吧)
java ssm 框架實現文件上傳
實現:單文件上傳、多文件上傳(單選和多選),並且用 ajax 異步刷新,在當前界面顯示上傳的文件
后端
首先 springmvc 的配置文件要配置上傳文件解析器:
<!-- 配置文件解析器 -->
<bean id="multipartResolver"
class="org.springframework.web.multipart.commons.CommonsMultipartResolver"
p:defaultEncoding="utf-8">
<property name="uploadTempDir" value="/temp"></property>
<property name="maxUploadSize">
<value>209715200</value><!-- 200MB -->
</property>
<property name="maxInMemorySize">
<value>4096</value><!-- 4KB大小讀寫 -->
</property>
</bean>
其次在 pom.xml 中要配置上傳文件的依賴
<dependency>
<groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>
<version>2.4</version>
</dependency>
<dependency>
<groupId>commons-fileupload</groupId>
<artifactId>commons-fileupload</artifactId>
<version>1.3.1</version>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
<version>3.3.2</version>
</dependency>
單文件上傳
/**
* 單文件上傳
* @param file
* @param request
* @return
* @throws IllegalStateException
* @throws IOException
* @throws JSONException
*/
public static String simUpload(MultipartFile file, HttpServletRequest request)
throws IllegalStateException, IOException, JSONException{
if(!file.isEmpty()){
String path = request.getSession().getServletContext().getRealPath("/upload");
//定義文件
File parent = new File(path);
if(!parent.exists()) parent.mkdirs();
HashMap<String, Object> map = new HashMap<String,Object>();
String oldName = file.getOriginalFilename();
long size = file.getSize();
//使用TmFileUtil文件上傳工具獲取文件的各種信息
//優化文件大小
String sizeString = TmFileUtil.countFileSize(size);
//獲取文件后綴名
String ext = TmFileUtil.getExtNoPoint(oldName);
//隨機重命名,10位時間字符串
String newFileName = TmFileUtil.generateFileName(oldName, 10, "yyyyMMddHHmmss");
String url = "upload/"+newFileName;
//文件傳輸,parent文件
file.transferTo(new File(parent, newFileName));
map.put("oldname",oldName);//文件原名稱
map.put("ext",ext);
map.put("size",sizeString);
map.put("name",newFileName);//文件新名稱
map.put("url",url);
//以json方式輸出到頁面
return JSONUtil.serialize(map);
}else{
return null;
}
}
多文件上傳(整合了單選文件和多選文件的兩種)
/**
* 多文件上傳
* @param files
* @param request
* @return
* @throws IllegalStateException
* @throws IOException
* @throws JSONException
*/
public static List<HashMap<String, Object>> mutlUpload(MultipartFile[] files, HttpServletRequest request)
throws IllegalStateException, IOException, JSONException{
if(files.length > 0){
String path = request.getSession().getServletContext().getRealPath("/upload");
//定義文件
File parent = new File(path);
if(!parent.exists()) parent.mkdirs();
//創建這個集合保存所有文件的信息
List<HashMap<String, Object>> listMap = new ArrayList<HashMap<String, Object>>();
//循環多次上傳多個文件
for (MultipartFile file : files) {
//創建map對象保存每一個文件的信息
HashMap<String, Object> map = new HashMap<String,Object>();
String oldName = file.getOriginalFilename();
long size = file.getSize();
//使用TmFileUtil文件上傳工具獲取文件的各種信息
//優化文件大小
String sizeString = TmFileUtil.countFileSize(size);
//獲取文件后綴名
String ext = TmFileUtil.getExtNoPoint(oldName);
//隨機重命名,10位時間字符串
String newFileName = TmFileUtil.generateFileName(oldName, 10, "yyyyMMddHHmmss");
String url = "upload/"+newFileName;
//文件傳輸,parent文件
file.transferTo(new File(parent, newFileName));
map.put("oldname",oldName);//文件原名稱
map.put("ext",ext);
map.put("size",sizeString);
map.put("name",newFileName);//文件新名稱
map.put("url",url);
listMap.add(map);
}
//以json方式輸出到頁面
return listMap;
}else{
return null;
}
}
前端
前端代碼:
文件多選,實際上在
<input type="file"
name="fileupmulti"
accept="image/jpeg,image/png"
onchange="mutiFiles(this)"
multiple/>
多加了一個 multiple 屬性
onchange 事件代碼
// 單文件上傳
function uploadFile(obj){
// 創建一個 FormData 對象,用一些鍵值對來模擬一系列表單控件
// 即把 form 中所有表單元素的 name 與 value 組裝成一個 queryString
let form = new FormData();
let fileObj = obj.files[0];
form.append('doc',fileObj);
// ajax 代碼...
}
// 多文件上傳(多選)
function mutiFiles(obj){
let form = new FormData();
let fileObj = obj.files;
let length = fileObj.length;
// 將 fileObj 轉換成數組
// let filese = Array.from(fileObj);
for(let i = 0; i < length; i++){
form.append('doc', fileObj[i]);
}
// ajax 代碼...
}
// 多文件上傳(單選:一個一個選擇文件,最后點擊提交按鈕觸發的方法)
function multipartone(){
let file1 = $('.fileupon11').get(0).files[0];
let file2 = $('.fileupon12').get(0).files[0];
let file3 = $('.fileupon13').get(0).files[0];
//如果都是空,則直接退出
isEmpty(file1) && isEmpty(file2) && isEmpty(file3) return;
let form = new FormData();
//用同一個名字,注入到controller層的參數數組
form.append('doc', file1);
form.append('doc', file2);
form.append('doc', file3);
// ajax 代碼...
}
要想在當前界面顯示上傳的文件,而不跳轉,就利用 ajax 異步請求
不過需要注意的是,我這里使用 FormData() 儲存文件對象, ajax 要配上這幾個參數才可實現文件上傳:
$.ajax({
type: "post",
data: form, // FormData()對象
url: basePath+"/upload/mutl",
contentType: false, // 必須false才會自動加上正確的Content-Type
processData: false, // 必須false才會避開 jQuery 對 formdata 的默認處理, XMLHttpRequest會對 formdata 進行正確的處理
success: function(data){
// TODO
}
})
controller 層調用
package com.krry.controller;
import java.io.IOException;
import java.util.HashMap;
import java.util.List;
import javax.servlet.http.HttpServletRequest;
import org.apache.struts2.json.JSONException;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.multipart.MultipartFile;
import com.krry.util.UploadUtil;
/**
* 文件上傳類
* KrryUploadController
* @author krry
* @version 1.0.0
*
*/
@Controller
@RequestMapping("/upload")
public class KrryUploadController {
/**
* 單文件上傳
* @param file
* @param request
* @return
* @throws IllegalStateException
* @throws IOException
* @throws JSONException
*/
@ResponseBody
@RequestMapping(value = "/file")
public String krryupload(@RequestParam("doc") MultipartFile file, HttpServletRequest request) throws IllegalStateException, IOException, JSONException{
//調用工具類完成上傳,返回相關數據到頁面
return UploadUtil.simUpload(file, request);
}
/**
* 多文件上傳
* @param file
* @param request
* @return
* @throws IllegalStateException
* @throws IOException
* @throws JSONException
*/
// 這里的MultipartFile[] file表示前端頁面上傳過來的多個文件,file對應頁面中多個file類型的input標簽的name,但框架只會將一個文件封裝進一個MultipartFile對象,
// 並不會將多個文件封裝進一個MultipartFile[]數組,直接使用會報[Lorg.springframework.web.multipart.MultipartFile;.<init>()錯誤,
// 所以需要用@RequestParam校正參數(參數名與MultipartFile對象名一致),當然也可以這么寫:@RequestParam("file") MultipartFile[] files。
@ResponseBody
@RequestMapping(value = "/mutl")
public List<HashMap<String, Object>> krryuploadMutl(@RequestParam("doc") MultipartFile[] file, HttpServletRequest request) throws IllegalStateException, IOException, JSONException{
//調用工具類完成上傳,返回相關數據到頁面
return UploadUtil.mutlUpload(file, request);
}
}
進度條
要顯示上傳進度條,我這里采用原生 ajax 方法
function uploadFile(obj) {
// ...
// 一些獲取上傳對象的相關代碼
// 創建一個 ajax 對象
var xhr = new XMLHttpRequest();
// 規定請求的類型、URL 以及是否異步處理請求。true為異步
// 請求是異步的。因為要實時獲取到上傳的進度,則請求需是異步的,如果是同步的話,會直到請求完成才能獲取到響應
xhr.open("post", basePath+"/upload/file", true);
// 上傳成功進入的回調函數
xhr.onreadystatechange = function(){
if(xhr.readyState==4 && xhr.status==200){ // 狀態 4 和 200 代表和服務器端交互成功
// 獲取上傳成功的返回數據
var data = xhr.responseText.trim();
jdata = eval("("+data+")");
krry_uploadsuccess(jdata);
}
};
// 監聽文件上傳的進度
xhr.upload.addEventListener("progress", progressFunction, false);
// 發送http請求:將請求發送到服務器,與后台交互
xhr.send(form);
}
// 上傳進度的回調函數
function progressFunction(event) {
let prograssbarDom = document.getElementById("prograssbar");
let fileRea = document.getElementById("fileRea");
if (prograssbarDom && event.lengthComputable) {
let percent = event.loaded / event.total; //文件上傳進度百分比
let p = Math.floor(percent*100);
prograssbarDom.style.width = p+"%";
fileRea.innerHTML = p+"%";
}
}
附上優化文件大小的代碼:
/**
* 將文件的字節數轉換成文件的大小
* com.krry.uitl
* 方法名:format
* @author krry
* @param size
* @return String
* @exception
* @since 1.0.0
*/
public static String format(long size){
float fsize = size;
String fileSizeString;
if (fsize < 1024) {
fileSizeString = String.format("%.2f", fsize) + "B"; //2f表示保留兩位小數
} else if (fsize < 1048576) {
fileSizeString = String.format("%.2f", fsize/1024) + "KB";
} else if (fsize < 1073741824) {
fileSizeString = String.format("%.2f", fsize/1024/1024) + "MB";
} else if (fsize < 1024 * 1024 * 1024) {
fileSizeString = String.format("%.2f", fsize/1024/1024/1024) + "GB";
} else {
fileSizeString = "0B";
}
return fileSizeString;
}
博客地址:https://ainyi.com/76