記得剛入行的時候,做了一個文件上傳的功能,因為上傳時間較久,為了用戶友好性,想要添加一個實時進度條,顯示進度。奈何當時技術有限,查了許久也沒用找到解決方案,最后不了了之。
近來偶然想到這個問題,于是決定整理一下實現方式,也為和我曾經一樣碰壁的同學,提供一些思路。
1、首先我們這里實現的是一個實時的進度條,并不是一個純前端的進度條,它需要根據后端的處理進度來實時反饋進度條長度,那么必然要與后端交互。
當然這里容易陷入一個誤區,覺得與后端交互的,那么這個功能的重點一定在后端,但實際上這個功能的重點在前端。
不難想到,我們要知道實時進度,那么一定需要不斷的請求后端,得到響應反饋,前后端請求比較常用的是ajax,但除它之外,我們還有更基礎的xhr(XMLHttpRequest)。作為后端同學可能對xhr有些陌生,實際上ajax就是基于xhr實現的。
2、xhr可以讓我們在不重新加載頁面的情況下更新網頁,在頁面已經加載后從后端請求并接受數據,這樣就可以無感的讓我們后端文件的上傳進度了。
3、為了監聽文件上傳下載進度,我們主要使用到xhr的三個進度事件:
當然除上述三個事件之外,還有其他的進度事件,這不是本文的重點,大家可自行拓展學習XHR對象的進度事件
XMLHttpRequest簡介
4、基于上述三個進度事件,我們可以通過process事件持續不斷地發送請求獲取文件上傳下載的進度,load事件用于文件上傳下載完成后的處理,比如提示成功。error用于請求發送錯誤時的處理。
5、有了上述的思路之后,我們來進行實際演示。
1、創建springboot項目,引入spring web、lombok、文件上傳commons-fileupload依賴
xml復制代碼<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>commons-fileupload</groupId>
<artifactId>commons-fileupload</artifactId>
<version>1.4</version>
</dependency>
2、創建MultipartResolver的bean,用來將普通的請求封裝成擁有文件上傳功能的請求
java復制代碼@Component
public class FileUpLoadConfig {
@Bean(name="multipartResolver")
public MultipartResolver multipartResolver(){
return new CommonsMultipartResolver();
}
}
3、創建一個文件上傳接口:這里我單純做個演示,就直接在controller層中書寫了,實際生產要將上傳方法提取為工具類,在service中進行具體業務處理。
如下代碼為將文件上傳后,保存到資源文件夾下
java復制代碼@RestController
@RequestMapping("file")
public class FileController {
private final static Logger log = LoggerFactory.getLogger(FileController.class);
@PostMapping("/upload")
@ResponseBody
public ResponseEntity<String> fileUpload(@RequestParam("file") MultipartFile file) {
try {
// 獲取資源文件存放路徑,用于臨時存放生成的excel文件
String path = Objects.requireNonNull(this.getClass().getClassLoader().getResource("")).getPath();
// 文件名
String fileName = path + file.getOriginalFilename();
// 創建目標文件
File dest = new File(fileName);
// 向指定路徑寫入文件
file.transferTo(dest);
// 返回文件訪問路徑
return new ResponseEntity<>(fileName, HttpStatus.OK);
} catch (Exception e) {
e.printStackTrace();
log.info(String.format("文件上傳失敗,原因:%s",e));
return new ResponseEntity<>("文件上傳失敗", HttpStatus.INTERNAL_SERVER_ERROR);
}
}
}
4、后端接口完成后,進入我們的重點,我們來實現前端進度條
5、首先引入jQuery,我這里使用了3.6.1版本
6、實現一個上傳的頁面,這里利用了html5的progress標簽,該標簽用于實現進度條,支持兩個屬性:value和max,分別為當前進度值和最大進度值
html復制代碼<div class="modal-body form ">
<!-- 文件上傳 -->
<form id="dialogForm" class="form-horizontal">
<div class="form-group">
<label class="control-label">文件:</label>
<div >
<input type="file" name="file" id="file" onchange="upload()">
</div>
</div>
<div class="form-group">
<label class="control-label">上傳進度:</label>
<div >
<!--進度條-->
<div id="progress-body">
<progress></progress>
<div id="progress-bar">0%</div>
</div>
</div>
</div>
</form>
</div>
7、書寫進度監聽方法,即progress方法
js復制代碼 //進度條更新
function progressHandle(e) {
$('#progress-body progress').attr({
value : e.loaded,
max : e.total
});
var percent = (e.loaded / e.total * 100).toFixed(2);
$('#progress-body #progress-bar').html(percent + "%");
};
8、書寫load,error方法
js復制代碼 //上傳完成處理函數
function uploadSuccess(e) {
alert("上傳完成");
};
//上傳出錯處理函數
function uploadFail(e) {
alert("上傳失敗");
};
9、實現上傳方法upload
js復制代碼 // 文件上傳
function upload() {
var formData = new FormData();
formData.append("file", $("#file")[0].files[0]);
$.ajax({
url : "/file/upload",
type : "POST",
data : formData,
processData : false, // 告訴jQuery不要去處理發送的數據
contentType : false, // 告訴jQuery不要去設置Content-Type請求頭
success : function(data) {
console.log(data);
},
xhr : function() {
var xhr = $.ajaxSettings.xhr();
// xhr.upload專用于上傳事件監聽
if (xhr.upload) {
//處理進度條的事件
xhr.upload.addEventListener("progress", progressHandle,
false);
//加載完成的事件
xhr.addEventListener("load", uploadSuccess, false);
//加載出錯的事件
xhr.addEventListener("error", uploadFail, false);
return xhr;
}
}
});
}
10、運行項目,訪問上傳頁,我這里直接書寫在index.html中了
11、測試:如下圖所示,可以正常顯示進度
12、上傳成功后,后臺資源文件夾中也能看到對應的上傳文件,演示成功!
上述我們講解了如何實現上傳進度條功能,有了這個思路,我們再實現下載功能:
1、同樣,我們實現一個簡單的進度條頁面
html復制代碼 <!-- 文件下載 -->
<form id="dialogForm" class="form-horizontal">
<div class="form-group">
<label class="control-label">下載進度:
</label>
<div>
<!--進度條-->
<div id="progress-body">
<progress></progress>
<div id="progress-bar">0%</div>
</div>
</div>
</div>
<button type="button" onclick="download()">下載</button>
</form>
2、實現下載方法
這里我們不再采用ajax的方法,而是直接通過xhr請求,并且因為要在瀏覽器中下載該文件,所以以window.URL.revokeObjectURL方法來下載并釋放該文件。
js復制代碼 // 文件下載
function download() {
var xhr = new XMLHttpRequest();
//處理進度條的事件
xhr.addEventListener("progress", progressHandle, false);
//加載出錯的事件
xhr.addEventListener("error", uploadFail, false);
xhr.open("POST","/file/download");
//設置響應類型
xhr.responseType = 'blob';
xhr.onload = function (e) {
if (this.status === 200) {
// 截取掉'attachment;filename='
var filename = xhr.getResponseHeader("Content-disposition").slice(20);
var blob = this.response;
var a = document.createElement('a');
var url = URL.createObjectURL(blob);
a.href = url;
a.download = filename;
document.body.appendChild(a);
a.click();
window.URL.revokeObjectURL(url);
}
}
xhr.send();
}
//進度條更新
function progressHandle(e) {
$('#progress-body progress').attr({
value: e.loaded,
max: e.total
});
var percent = (e.loaded / e.total * 100).toFixed(2);
$('#progress-body #progress-bar').html(percent + "%");
};
//上傳出錯處理函數
function uploadFail(e) {
alert("下載失敗");
};
3、實現后端下載文件接口
這里與上傳文件不同的是,前端在進行文件上傳時,是可以獲取到文件的總大小的,而下載文件時因為是流式下載,前端是不知道要下載的文件一共有多少大小的。
因此也就無法估算總體的進度比例。所以我們后端接口中要通過Content-Length響應頭指定文件的總大小
我這里為了演示方便,直接下載上述上傳的文件。實際應用可更改為你自己的文件下載路徑。
java復制代碼 @PostMapping("/download")
@ResponseBody
public ResponseEntity<String> download(HttpServletResponse response) throws IOException {
// 獲取資源文件存放路徑,用于臨時存放生成的excel文件
String path = Objects.requireNonNull(this.getClass().getClassLoader().getResource("")).getPath();
File pathFile = new File(path);
File[] files = pathFile.listFiles();
if (ObjectUtils.isEmpty(files)) {
return new ResponseEntity<>("文件為空,請先上傳文件", HttpStatus.OK);
}
InputStream inputStream = null;
ServletOutputStream ouputStream = null;
try {
for (File file : files) {
if(file.isDirectory()){
continue;
}
inputStream = new FileInputStream(file);
response.setContentType("application/x-msdownload");
response.setHeader("Content-Disposition", "attachment;filename=" + URLEncoder.encode(file.getName(), "UTF-8"));
// 設置一個總長度,否則無法估算進度
response.setHeader("Content-Length",String.valueOf(file.length()));
ouputStream = response.getOutputStream();
byte b[] = new byte[1024];
int n;
while ((n = inputStream.read(b)) != -1) {
ouputStream.write(b, 0, n);
}
ouputStream.flush();
break;
}
} catch (Exception e) {
e.printStackTrace();
} finally {
if(inputStream != null){
inputStream.close();
}
if(ouputStream != null){
ouputStream.close();
}
}
return new ResponseEntity<>("文件下載成功", HttpStatus.OK);
}
4、運行項目
5、測試:文件成功下載,進度也實時顯示
以上演示源碼可在如下地址下載: https://gitee.com/wuhanxue/progress_bar_demo
以上我們就完成了文件的上傳和下載的實時進度監控,雖然這個功能的重點在前端,但是后端通過這個功能點,也能更好的理解前后端請求的交互。
最后我們拋出一個思考問題:如何實時監控后端自定義功能的執行進度?
作者:wu55555
鏈接:https://juejin.cn/post/7238886731058642999
ysq5.7.44源代碼方式
下載安裝配置
官網文檔
https://dev.mysql.com/doc/refman/5.7/en/installing-source-distribution.html
打開mysql官網網站 https://www.mysql.com/,點擊download進入下載頁面。
在下載頁面中找到mysql社區服務器版本,點擊“MySQL Community (GPL) Downloads ?”進入社區服務器版的下載頁面。
點擊社區服務器版“MySQL Community Server”
點擊存檔“Archives”,選擇操作系統,操作系統版本,找到源碼。
yum install -y gcc-c++
CMake是一個跨平臺的開源構建工具,用于構建mysql軟件。他寫CMakeLists.txt文件來描述項目的結構,用cmake生成makefile文件,共make編譯使用。
yum install cmake
cmake官網下載 https://cmake.org/download/,源碼編譯見軟件包中的readme文件。
查看cmake版本
cmake --version
一般系統自帶這個編譯工具,可以通過make --version查看版本。
需要 SSL 庫來支持加密連接、隨機數生成。
yum install openssl-devel
Boost是一個由C++社區開發和維護的開源C++庫集合,旨在擴展C++語言的功能和性能。
構建 MySQL 需要 Boost C++ 庫,必須安裝Boost 1.59.0,安裝 Boost 后,根據調用WITH_BOOST在CMake 時為選項設置的值告訴構建系統 Boost 文件的放置位置。
見以下兩個選項:
-DDOWNLOAD_BOOST=1 \
-DWITH_BOOST=/usr/local/boost
ncurses庫是一個用于創建文本用戶界面(TUI)的開發庫。
yum install ncurses-devel
如果您打算運行測試腳本,則需要 Perl。
groupadd mysql
useradd -r -g mysql -s /bin/false mysql
解壓
cd /soft
tar zxvf mysql-5.7.44.tar.gz
cd mysql-5.7.44
創建構建目錄
mkdir build
cd build
構建make編譯文件
cmake .. \
-DCMAKE_INSTALL_PREFIX=/usr/local/mysql \
-DMYSQL_DATADIR=/home/mysql \
-DSYSCONFDIR=/etc \
-DDEFAULT_CHARSET=utf8mb4 \
-DDEFAULT_COLLATION=utf8mb4_general_ci \
-DMYSQL_TCP_PORT=3306 \
-DDOWNLOAD_BOOST=1 \
-DWITH_BOOST=/usr/local/boost
說明:
-DCMAKE_INSTALL_PREFIX:配置安裝到特定路徑
-DMYSQL_DATADIR:配置數據目錄
-DSYSCONFDIR:配置選項文件的目錄
-DDEFAULT_CHARSET:配置mysql服務字符集,默認字符是latin1(cp1252西歐)字符集
-DDEFAULT_COLLATION:服務器排序規則。默認排序規則使用 latin1_swedish_ci。
-DMYSQL_TCP_PORT:服務器偵聽 TCP/IP 連接的端口號。默認值為 3306。
-DDOWNLOAD_BOOST:檢查是否有boost庫
重新構建時運行以下命令清楚歷史構建信息
make clean
rm -rf CMakeCache.txt
編譯&安裝
make
make install
groupadd mysql
useradd -r -g mysql -s /bin/false mysql
echo 'export PATH=$PATH:/usr/local/mysql/bin' >> /etc/profile
source /etc/profile
echo $PATH
切換到mysql軟件根目錄
cd /usr/local/mysql
創建mysql-files目錄
mkdir mysql-files
chown mysql:mysql mysql-files
mysql-files目錄提供了一個方便的位置來用作系統變量的值 secure_file_priv,這將導入和導出操作限制到特定目錄。
創建mysql配置文件
vi /etc/my.cnf
[mysqld]
basedir=/usr/local/mysql
datadir=/home/mysql
MySQL安裝完成后,必須初始化數據目錄。
bin/mysqld --defaults-file=/etc/my.cnf \
--initialize \
--user=mysql
--defaults-file:指定初始化時的配置文件,必須在選項的第一位。(配置文件中只能有basedir和datadir,其他選項需要在初始化后才能加入)
--initialize:初始化
--user:指定mysql軟件運行用戶
注意:初始化數據庫目錄時,除了使用--basedir、--datadir、--user選項外,不應該使用其他選項。其他選項可以在初始化完成后再my.cnf中指定,然后重啟mysql服務。意思就是說初始化數據庫目錄時最多只能使用--basedir、--datadir、--user選項。
bin/mysql_ssl_rsa_setup
bin/mysqld_safe --user=mysql &
對于使用 RPM 包安裝 MySQL 的 Linux 系統,服務器啟動和關閉是使用 systemd 而不是mysqld_safe管理的,并且 不安裝mysqld_safe 。
cd support-files/
cp mysql.server /etc/init.d/mysql
chmod +x /etc/init.d/mysql
chkconfig --add mysql
service mysql start
service mysql stop
service mysql restart
登錄mysql后運行如下命令修改密碼,登錄密碼在初始化數據目錄時有顯示。
ALTER USER 'root'@'localhost' IDENTIFIED BY 'Welcome123#';
查看默認存在的用戶
select user,host from mysql.user;
你需要在“/etc/systemd/system/”創建一個“mysql.service”的文件,告訴systemd如何管理MySQL服務。
文件內容如下:
[Unit]
Description=MySQL Server
After=network.target
[Service]
ExecStart=/usr/local/mysql/bin/mysqld_safe --user=mysql
ExecStop=/usr/local/mysql/bin/mysqladmin shutdown
User=mysql
Group=mysql
Restart=always
[Install]
WantedBy=multi-user.target
說明:
After=network.target 是systemd服務單元文件中的一個指令,它指定了服務單元所依賴的其他單元。具體來說,network.target 是一個systemd的單元,表示網絡服務已經啟動并可用。
Restart=always 意味著當服務意外退出(即非正常退出)時,systemd會自動嘗試重新啟動該服務。
WantedBy=multi-user.target 是systemd服務單元文件中的一個指令,它定義了服務的啟動級別(run level)。在systemd中,系統的啟動級別通過一個稱為 target 的單元來表示。multi-user.target 是系統的多用戶運行級別,通常用于大多數服務器環境,表示系統已經啟動到了可以提供多用戶登錄和運行多個服務的階段。WantedBy=multi-user.target 指定了MySQL服務的啟動級別,并告訴systemd在系統啟動到多用戶運行級別時啟動MySQL服務。
重新加載systemd管理器配置
創建完服務單元文件后,需要通知systemd重新加載它的配置,以便識別到新的MySQL服務單元。
systemctl daemon-reload
TML大文件上傳源代碼,HTML大文件上傳解決方案,HTML大文件上傳思路,HTML大文件上傳實例,HTML大文件分塊上傳,HTML大文件分片上傳,HTML大文件批量上傳,HTML大文件加密上傳,HTML文件夾上傳,HTML大文件多線程上傳,
隨著視頻網站和大數據應用的普及,特別是高清視頻和4K視頻應用的到來,超大文件上傳已經成為了日常的基礎應用需求。
但是在很多情況下,平臺運營方并沒有大文件上傳和斷點續傳的開發經驗,往往在網上找一些簡單的PHP或者Java程序來實現基本的上傳功能,然而在實際使用中會發現,這些基于腳本語言實現的上傳功能模塊性能很弱,一是不支持2GB以上的內容上傳;二是無法支持斷點續傳;三是效率極低,單臺服務器最多支持幾十個并發上傳連接。
當前我們要搭建一個運營級的視頻服務平臺,在嘗試了各種產品均無法滿足要求,因此最后花精力自主用C++語言實現了這一高性能上傳服務器。
而基于PHP、JAVA等技術實現的文件上傳服務天生無法支持超大文件上傳,無法逾越2GB的最大文件尺寸瓶頸;
支持4GB以上超大文件上傳,文件大小不受限制;
支持斷點續傳,斷網、關機重啟均不受影響;
對于大文件的處理,無論是用戶端還是服務端,如果一次性進行讀取發送、接收都是不可取,很容易導致內存問題。所以對于大文件上傳,采用切塊分段上傳
從上傳的效率來看,利用多線程并發上傳能夠達到最大效率。
文件上傳頁面的前端可以選擇使用一些比較好用的上傳組件,例如百度的開源組件WebUploader,這些組件基本能滿足文件上傳的一些日常所需功能,如異步上傳文件,文件夾,拖拽式上傳,黏貼上傳,上傳進度監控,文件縮略圖,甚至是大文件斷點續傳,大文件秒傳。
在web項目中上傳文件夾現在已經成為了一個主流的需求。在OA,或者企業ERP系統中都有類似的需求。上傳文件夾并且保留層級結構能夠對用戶行成很好的引導,用戶使用起來也更方便。能夠提供更高級的應用支撐。
導入項目:
導入到Eclipse:http://www.ncmem.com/doc/view.aspx?id=9da9c7c2b91b40b7b09768eeb282e647
導入到IDEA:http://www.ncmem.com/doc/view.aspx?id=9fee385dfc0742448b56679420f22162
springboot統一配置:http://www.ncmem.com/doc/view.aspx?id=7768eec9284b48e3abe08f032f554ea2
下載示例:
https://gitee.com/xproer/up6-jsp-eclipse/tree/6.5.40/
工程
NOSQL
NOSQL示例不需要任何配置,可以直接訪問測試
創建數據表
選擇對應的數據表腳本,這里以SQL為例
修改數據庫連接信息
訪問頁面進行測試
文件存儲路徑
up6/upload/年/月/日/guid/filename
相關問題:
1.javax.servlet.http.HttpServlet錯誤
2.項目無法發布到tomcat
3.md5計算完畢后卡住
4.服務器找不到config.json文件
相關參考:
文件保存位置
源碼工程文檔:https://drive.weixin.qq.com/s?k=ACoAYgezAAw1dWofra
源碼報價單:https://drive.weixin.qq.com/s?k=ACoAYgezAAwoiul8gl
OEM版報價單:https://drive.weixin.qq.com/s?k=ACoAYgezAAwuzp4W0a
產品源代碼:https://drive.weixin.qq.com/s?k=ACoAYgezAAwbdKCskc
授權生成器:https://drive.weixin.qq.com/s?k=ACoAYgezAAwTIcFph1
*請認真填寫需求信息,我們會在24小時內與您取得聯系。