精品分享:基于 SpringBoot + Vue 开发的云盘系统(含大文件断点续传剖析)

21 篇文章 4 订阅
17 篇文章 1 订阅

引言

作为开发人员,我们经常需要存储和下载文件,为了使用方便,通常都会将文件存储在云端,市面上使用率最高的云端存储莫过于百度网盘了,但使用别人的东西难免会受到各种各样的限制,必须花钱才会享受到更好的服务体验,所以很多公司和个人都会搭建自己的云盘系统来使用,一来文件捏在自己手里,更放心,更安全,二来可以根据自己的需求定制一些个性化服务。

最近公司也要做一个自己的存储服务,要求支持大文件断点续传,在线解压缩等功能,由于是内部项目,自由度相对较高,所以我在网上找了一个开源项目 - 奇文网盘,在它的基础上,修复了上传时候进度提示显示有误的 bug,同时添加了对 rar5 文件的在线解压支持,剔除了一些繁琐的功能,同时利用 JxBrowser 套壳实现了一个客户端版本。在此分享给大家,希望能够对你有所帮助,具体的源码资料可在文末获取哦。

系统展示

首页

系统首页主要对系统功能进行了描述和展示。
首页
注册

注册页面提供滑动解锁插件,在输入用户名、手机号、密码之后,点击注册就可以注册成功。
注册
登录

输入手机号和密码,滑动解锁,点击登录按钮即可登录。
登录
网盘主页

网盘主页采用左右布局,并且做了屏幕自适应,包含了网盘的主要功能模块。
网盘主页

大文件断点续传剖析

系统前端的核心代码主要位于 src\components\file\box\uploadFile\Box.vue 文件中,里面包含了大文件的断点续传等操作,我们借助了 vue-simple-upload 组件辅助实现大文件的断点续传。

系统后端的核心代码主要位于 controller 包下的 FileController 和 FiletransferController 两个类,里面包含了对文件的上传,下载以及各种操作的 api 实现。

难点主要在于超大文件的断点续传,比如刷新页面,停电等导致上传中断,再次上传该文件时可以从之前中断的位置继续上传,而不必从头开始,断点续传主要分为以下几个步骤:

  1. 前端上传文件时,获取文件 md5 值,作为文件的唯一标识,获取文件大小,根据每个切片的大小(自定义,前后台保持一致)计算总切片数目,发送 md5 和切片信息请求后台;
  2. 后端拿到 md5 值以后,查询到该文件,根据切片信息判断文件是否已经上传完毕,如果已经上传完毕,则不用重新再上传,达到极速秒传的效果,若没有上传完毕,把已经上传的切片数组返回给前台,如 [1,2,3],没有则返回空;
  3. 前端对大文件进行切片。比如一个 100M 的文件,一个分片是 5M 的话,那么这个文件可以分20次上传。
  4. 前端请求后台发送切片,跳过已经上传的切片,每个切片上传的时候需要发送切片的具体信息:如切片大小,所有切片数,总大小,当前切片大小,当前切片数以及 md5 码等
  5. 后台接收切片上传请求,保存切片的相关信息,对上传的切片进行判断,当最后一个切片上传完毕后,合并所有切片,上传完毕。

具体流程图如下:
断点续传
以上便是对大文件断点续传的简单剖析,理解原理之后,代码实现就不再是难事,感兴趣的朋友可以在文末获取相关源码资料自行研究,这里我们不过多赘述。

后端部署

系统数据库表结构无需手动初始化,启动的时候 jpa 会自动检查,生成表结构。

数据需要手动初始化一下,复制以下内容执行即可:

delete from user where userId = 1;
insert into user (userId, username, telephone, salt, password, available) values (1, 'admin', 'admin', 'admin', 'df655ad8d3229f3269fad2a8bab59b6c', 1);

delete from role where roleId in (1, 2);
INSERT INTO `role` (`roleId`, `available`, `description`, `roleName`, `createTime`, `createUserId`, `modifyTime`, `modifyUserId`) VALUES (1, 1, '超级管理员', '超级管理员', NULL, NULL, '2021-11-10 20:46:06', NULL);
INSERT INTO `role` (`roleId`, `available`, `description`, `roleName`, `createTime`, `createUserId`, `modifyTime`, `modifyUserId`) VALUES (2, 1, '普通用户', '普通用户', NULL, NULL, NULL, NULL);

delete from sysparam where sysParamId in (1, 2, 3);
insert into sysparam (sysParamId, sysParamKey, sysParamValue, sysParamDesc) values (1, 'totalStorageSize', '10240', '总存储大小(单位M)');
insert into sysparam (sysParamId, sysParamKey, sysParamValue, sysParamDesc) values (2, 'initDataFlag', '1', '系统初始化数据标识');
insert into sysparam (sysParamId, sysParamKey, sysParamValue, sysParamDesc) values (3, 'version', '1.1.2', '当前脚本的版本号');

delete from filetype where fileTypeId in (0, 1, 2, 3, 4, 5);
INSERT INTO `filetype` (`fileTypeId`, `fileTypeName`) VALUES (0, '全部');
INSERT INTO `filetype` (`fileTypeId`, `fileTypeName`) VALUES (1, '图片');
INSERT INTO `filetype` (`fileTypeId`, `fileTypeName`) VALUES (2, '文档');
INSERT INTO `filetype` (`fileTypeId`, `fileTypeName`) VALUES (3, '视频');
INSERT INTO `filetype` (`fileTypeId`, `fileTypeName`) VALUES (4, '音乐');
INSERT INTO `filetype` (`fileTypeId`, `fileTypeName`) VALUES (5, '其他');

delete from fileextend where 1 = 1;
INSERT INTO `fileextend` (`fileExtendName`) VALUES ('bmp');
INSERT INTO `fileextend` (`fileExtendName`) VALUES ('jpg');
INSERT INTO `fileextend` (`fileExtendName`) VALUES ('png');
INSERT INTO `fileextend` (`fileExtendName`) VALUES ('tif');
INSERT INTO `fileextend` (`fileExtendName`) VALUES ('gif');
INSERT INTO `fileextend` (`fileExtendName`) VALUES ('jpeg');

INSERT INTO `fileextend` (`fileExtendName`) VALUES ('doc');
INSERT INTO `fileextend` (`fileExtendName`) VALUES ('docx');
INSERT INTO `fileextend` (`fileExtendName`) VALUES ('docm');
INSERT INTO `fileextend` (`fileExtendName`) VALUES ('dot');
INSERT INTO `fileextend` (`fileExtendName`) VALUES ('dotx');
INSERT INTO `fileextend` (`fileExtendName`) VALUES ('dotm');
INSERT INTO `fileextend` (`fileExtendName`) VALUES ('odt');
INSERT INTO `fileextend` (`fileExtendName`) VALUES ('fodt');
INSERT INTO `fileextend` (`fileExtendName`) VALUES ('ott');
INSERT INTO `fileextend` (`fileExtendName`) VALUES ('rtf');
INSERT INTO `fileextend` (`fileExtendName`) VALUES ('txt');
INSERT INTO `fileextend` (`fileExtendName`) VALUES ('html');
INSERT INTO `fileextend` (`fileExtendName`) VALUES ('htm');
INSERT INTO `fileextend` (`fileExtendName`) VALUES ('mht');
INSERT INTO `fileextend` (`fileExtendName`) VALUES ('xml');
INSERT INTO `fileextend` (`fileExtendName`) VALUES ('pdf');
INSERT INTO `fileextend` (`fileExtendName`) VALUES ('djvu');
INSERT INTO `fileextend` (`fileExtendName`) VALUES ('fb2');
INSERT INTO `fileextend` (`fileExtendName`) VALUES ('epub');
INSERT INTO `fileextend` (`fileExtendName`) VALUES ('xps');

INSERT INTO `fileextend` (`fileExtendName`) VALUES ('xls');
INSERT INTO `fileextend` (`fileExtendName`) VALUES ('xlsx');
INSERT INTO `fileextend` (`fileExtendName`) VALUES ('xlsm');
INSERT INTO `fileextend` (`fileExtendName`) VALUES ('xlt');
INSERT INTO `fileextend` (`fileExtendName`) VALUES ('xltx');
INSERT INTO `fileextend` (`fileExtendName`) VALUES ('xltm');
INSERT INTO `fileextend` (`fileExtendName`) VALUES ('ods');
INSERT INTO `fileextend` (`fileExtendName`) VALUES ('fods');
INSERT INTO `fileextend` (`fileExtendName`) VALUES ('ots');
INSERT INTO `fileextend` (`fileExtendName`) VALUES ('csv');

INSERT INTO `fileextend` (`fileExtendName`) VALUES ('pps');
INSERT INTO `fileextend` (`fileExtendName`) VALUES ('ppsx');
INSERT INTO `fileextend` (`fileExtendName`) VALUES ('ppsm');
INSERT INTO `fileextend` (`fileExtendName`) VALUES ('ppt');
INSERT INTO `fileextend` (`fileExtendName`) VALUES ('pptx');
INSERT INTO `fileextend` (`fileExtendName`) VALUES ('pptm');
INSERT INTO `fileextend` (`fileExtendName`) VALUES ('pot');
INSERT INTO `fileextend` (`fileExtendName`) VALUES ('potx');
INSERT INTO `fileextend` (`fileExtendName`) VALUES ('potm');
INSERT INTO `fileextend` (`fileExtendName`) VALUES ('odp');
INSERT INTO `fileextend` (`fileExtendName`) VALUES ('fodp');
INSERT INTO `fileextend` (`fileExtendName`) VALUES ('otp');

INSERT INTO `fileextend` (`fileExtendName`) VALUES ('hlp');
INSERT INTO `fileextend` (`fileExtendName`) VALUES ('wps');

INSERT INTO `fileextend` (`fileExtendName`) VALUES ('avi');
INSERT INTO `fileextend` (`fileExtendName`) VALUES ('mp4');
INSERT INTO `fileextend` (`fileExtendName`) VALUES ('mpg');
INSERT INTO `fileextend` (`fileExtendName`) VALUES ('mov');
INSERT INTO `fileextend` (`fileExtendName`) VALUES ('swf');
INSERT INTO `fileextend` (`fileExtendName`) VALUES ('wav');
INSERT INTO `fileextend` (`fileExtendName`) VALUES ('aif');
INSERT INTO `fileextend` (`fileExtendName`) VALUES ('au');
INSERT INTO `fileextend` (`fileExtendName`) VALUES ('mp3');
INSERT INTO `fileextend` (`fileExtendName`) VALUES ('ram');
INSERT INTO `fileextend` (`fileExtendName`) VALUES ('wma');
INSERT INTO `fileextend` (`fileExtendName`) VALUES ('mmf');
INSERT INTO `fileextend` (`fileExtendName`) VALUES ('amr');
INSERT INTO `fileextend` (`fileExtendName`) VALUES ('aac');
INSERT INTO `fileextend` (`fileExtendName`) VALUES ('flac');
INSERT INTO `fileextend` (`fileExtendName`) VALUES ('java');
INSERT INTO `fileextend` (`fileExtendName`) VALUES ('js');
INSERT INTO `fileextend` (`fileExtendName`) VALUES ('css');
INSERT INTO `fileextend` (`fileExtendName`) VALUES ('json');

delete from fileclassification where 1 = 1;
INSERT INTO `fileclassification` (`fileClassificationId`, `fileTypeId`, `fileExtendName`) VALUES (1, 1, 'bmp');
INSERT INTO `fileclassification` (`fileClassificationId`, `fileTypeId`, `fileExtendName`) VALUES (2, 1, 'jpg');
INSERT INTO `fileclassification` (`fileClassificationId`, `fileTypeId`, `fileExtendName`) VALUES (3, 1, 'png');
INSERT INTO `fileclassification` (`fileClassificationId`, `fileTypeId`, `fileExtendName`) VALUES (4, 1, 'tif');
INSERT INTO `fileclassification` (`fileClassificationId`, `fileTypeId`, `fileExtendName`) VALUES (5, 1, 'gif');
INSERT INTO `fileclassification` (`fileClassificationId`, `fileTypeId`, `fileExtendName`) VALUES (6, 1, 'jpeg');

INSERT INTO `fileclassification` (`fileClassificationId`, `fileTypeId`, `fileExtendName`) VALUES (7, 2, 'doc');
INSERT INTO `fileclassification` (`fileClassificationId`, `fileTypeId`, `fileExtendName`) VALUES (8, 2, 'docx');
INSERT INTO `fileclassification` (`fileClassificationId`, `fileTypeId`, `fileExtendName`) VALUES (9, 2, 'docm');
INSERT INTO `fileclassification` (`fileClassificationId`, `fileTypeId`, `fileExtendName`) VALUES (10, 2, 'dot');
INSERT INTO `fileclassification` (`fileClassificationId`, `fileTypeId`, `fileExtendName`) VALUES (11, 2, 'dotx');
INSERT INTO `fileclassification` (`fileClassificationId`, `fileTypeId`, `fileExtendName`) VALUES (12, 2, 'dotm');
INSERT INTO `fileclassification` (`fileClassificationId`, `fileTypeId`, `fileExtendName`) VALUES (13, 2, 'odt');
INSERT INTO `fileclassification` (`fileClassificationId`, `fileTypeId`, `fileExtendName`) VALUES (14, 2, 'fodt');
INSERT INTO `fileclassification` (`fileClassificationId`, `fileTypeId`, `fileExtendName`) VALUES (15, 2, 'ott');
INSERT INTO `fileclassification` (`fileClassificationId`, `fileTypeId`, `fileExtendName`) VALUES (16, 2, 'rtf');
INSERT INTO `fileclassification` (`fileClassificationId`, `fileTypeId`, `fileExtendName`) VALUES (17, 2, 'txt');
INSERT INTO `fileclassification` (`fileClassificationId`, `fileTypeId`, `fileExtendName`) VALUES (18, 2, 'html');
INSERT INTO `fileclassification` (`fileClassificationId`, `fileTypeId`, `fileExtendName`) VALUES (19, 2, 'htm');
INSERT INTO `fileclassification` (`fileClassificationId`, `fileTypeId`, `fileExtendName`) VALUES (20, 2, 'mht');
INSERT INTO `fileclassification` (`fileClassificationId`, `fileTypeId`, `fileExtendName`) VALUES (21, 2, 'xml');
INSERT INTO `fileclassification` (`fileClassificationId`, `fileTypeId`, `fileExtendName`) VALUES (22, 2, 'pdf');
INSERT INTO `fileclassification` (`fileClassificationId`, `fileTypeId`, `fileExtendName`) VALUES (23, 2, 'djvu');
INSERT INTO `fileclassification` (`fileClassificationId`, `fileTypeId`, `fileExtendName`) VALUES (24, 2, 'fb2');
INSERT INTO `fileclassification` (`fileClassificationId`, `fileTypeId`, `fileExtendName`) VALUES (25, 2, 'epub');
INSERT INTO `fileclassification` (`fileClassificationId`, `fileTypeId`, `fileExtendName`) VALUES (26, 2, 'xps');
INSERT INTO `fileclassification` (`fileClassificationId`, `fileTypeId`, `fileExtendName`) VALUES (27, 2, 'xls');
INSERT INTO `fileclassification` (`fileClassificationId`, `fileTypeId`, `fileExtendName`) VALUES (28, 2, 'xlsx');
INSERT INTO `fileclassification` (`fileClassificationId`, `fileTypeId`, `fileExtendName`) VALUES (29, 2, 'xlsm');
INSERT INTO `fileclassification` (`fileClassificationId`, `fileTypeId`, `fileExtendName`) VALUES (30, 2, 'xlt');
INSERT INTO `fileclassification` (`fileClassificationId`, `fileTypeId`, `fileExtendName`) VALUES (31, 2, 'xltx');
INSERT INTO `fileclassification` (`fileClassificationId`, `fileTypeId`, `fileExtendName`) VALUES (32, 2, 'xltm');
INSERT INTO `fileclassification` (`fileClassificationId`, `fileTypeId`, `fileExtendName`) VALUES (33, 2, 'ods');
INSERT INTO `fileclassification` (`fileClassificationId`, `fileTypeId`, `fileExtendName`) VALUES (34, 2, 'fods');
INSERT INTO `fileclassification` (`fileClassificationId`, `fileTypeId`, `fileExtendName`) VALUES (35, 2, 'ots');
INSERT INTO `fileclassification` (`fileClassificationId`, `fileTypeId`, `fileExtendName`) VALUES (36, 2, 'csv');
INSERT INTO `fileclassification` (`fileClassificationId`, `fileTypeId`, `fileExtendName`) VALUES (37, 2, 'pps');
INSERT INTO `fileclassification` (`fileClassificationId`, `fileTypeId`, `fileExtendName`) VALUES (38, 2, 'ppsx');
INSERT INTO `fileclassification` (`fileClassificationId`, `fileTypeId`, `fileExtendName`) VALUES (39, 2, 'ppsm');
INSERT INTO `fileclassification` (`fileClassificationId`, `fileTypeId`, `fileExtendName`) VALUES (40, 2, 'ppt');
INSERT INTO `fileclassification` (`fileClassificationId`, `fileTypeId`, `fileExtendName`) VALUES (41, 2, 'pptx');
INSERT INTO `fileclassification` (`fileClassificationId`, `fileTypeId`, `fileExtendName`) VALUES (42, 2, 'pptm');
INSERT INTO `fileclassification` (`fileClassificationId`, `fileTypeId`, `fileExtendName`) VALUES (43, 2, 'pot');
INSERT INTO `fileclassification` (`fileClassificationId`, `fileTypeId`, `fileExtendName`) VALUES (44, 2, 'potx');
INSERT INTO `fileclassification` (`fileClassificationId`, `fileTypeId`, `fileExtendName`) VALUES (45, 2, 'potm');
INSERT INTO `fileclassification` (`fileClassificationId`, `fileTypeId`, `fileExtendName`) VALUES (46, 2, 'odp');
INSERT INTO `fileclassification` (`fileClassificationId`, `fileTypeId`, `fileExtendName`) VALUES (47, 2, 'fodp');
INSERT INTO `fileclassification` (`fileClassificationId`, `fileTypeId`, `fileExtendName`) VALUES (48, 2, 'otp');
INSERT INTO `fileclassification` (`fileClassificationId`, `fileTypeId`, `fileExtendName`) VALUES (49, 2, 'hlp');
INSERT INTO `fileclassification` (`fileClassificationId`, `fileTypeId`, `fileExtendName`) VALUES (50, 2, 'wps');

INSERT INTO `fileclassification` (`fileClassificationId`, `fileTypeId`, `fileExtendName`) VALUES (51, 2, 'java');
INSERT INTO `fileclassification` (`fileClassificationId`, `fileTypeId`, `fileExtendName`) VALUES (52, 2, 'js');
INSERT INTO `fileclassification` (`fileClassificationId`, `fileTypeId`, `fileExtendName`) VALUES (53, 2, 'css');
INSERT INTO `fileclassification` (`fileClassificationId`, `fileTypeId`, `fileExtendName`) VALUES (54, 2, 'json');


INSERT INTO `fileclassification` (`fileClassificationId`, `fileTypeId`, `fileExtendName`) VALUES (55, 3, 'avi');
INSERT INTO `fileclassification` (`fileClassificationId`, `fileTypeId`, `fileExtendName`) VALUES (56, 3, 'mp4');
INSERT INTO `fileclassification` (`fileClassificationId`, `fileTypeId`, `fileExtendName`) VALUES (57, 3, 'mpg');
INSERT INTO `fileclassification` (`fileClassificationId`, `fileTypeId`, `fileExtendName`) VALUES (58, 3, 'mov');
INSERT INTO `fileclassification` (`fileClassificationId`, `fileTypeId`, `fileExtendName`) VALUES (59, 3, 'swf');

INSERT INTO `fileclassification` (`fileClassificationId`, `fileTypeId`, `fileExtendName`) VALUES (60, 4, 'wav');
INSERT INTO `fileclassification` (`fileClassificationId`, `fileTypeId`, `fileExtendName`) VALUES (61, 4, 'aif');
INSERT INTO `fileclassification` (`fileClassificationId`, `fileTypeId`, `fileExtendName`) VALUES (62, 4, 'au');
INSERT INTO `fileclassification` (`fileClassificationId`, `fileTypeId`, `fileExtendName`) VALUES (63, 4, 'mp3');
INSERT INTO `fileclassification` (`fileClassificationId`, `fileTypeId`, `fileExtendName`) VALUES (64, 4, 'ram');
INSERT INTO `fileclassification` (`fileClassificationId`, `fileTypeId`, `fileExtendName`) VALUES (65, 4, 'wma');
INSERT INTO `fileclassification` (`fileClassificationId`, `fileTypeId`, `fileExtendName`) VALUES (66, 4, 'mmf');
INSERT INTO `fileclassification` (`fileClassificationId`, `fileTypeId`, `fileExtendName`) VALUES (67, 4, 'amr');
INSERT INTO `fileclassification` (`fileClassificationId`, `fileTypeId`, `fileExtendName`) VALUES (68, 4, 'aac');
INSERT INTO `fileclassification` (`fileClassificationId`, `fileTypeId`, `fileExtendName`) VALUES (69, 4, 'flac');

系统开发环境 dev 使用 h2 数据库,方便开发调试,项目启动成功后访问 http://localhost:8080/h2-concole 便可以对数据库进行管理维护;正式环境 prod 使用 mysql 数据库,通过修改 application.properties 中的 spring.profiles.active 实现环境切换。

部署也很简单,把项目打成 jar 包丢到服务器执行 java -jar xxx.jar 即可。

前端部署

前端执行 npm run serve 可以在开发环境调试运行,生产环境需要执行 npm run build 打包,打包后根目录下会生成文件夹 dist,我们这里选择使用 nginx 进行反向代理,将 dist 文件夹下的文件放置于 nginx/html 目录下,并配置 nginx/conf/nginx.conf,具体配置如下:

http {
 include       mime.types;
 default_type  application/octet-stream;

 #log_format  main  '$remote_addr - $remote_user [$time_local] "$request" '
 #                  '$status $body_bytes_sent "$http_referer" '
 #                  '"$http_user_agent" "$http_x_forwarded_for"';

 #access_log  logs/access.log  main;

 sendfile        on;
 #tcp_nopush     on;

 #keepalive_timeout  0;
 keepalive_timeout  65;

 #gzip  on;
 tcp_nopush on;
 tcp_nodelay on;
 types_hash_max_size 2048;
 client_max_body_size 2048m;
 client_header_buffer_size 512k;
 large_client_header_buffers 4 512k;
 server {
        listen       80;
		server_name localhost;   

        location /{
            root   html;
            index  index.html index.htm;
			try_files	$uri $uri/ /index.html; 
        }

		location /api/{
			#proxy_set_hearder host                $host;
			#proxy_set_header X-forwarded-for $proxy_add_x_forwarded_for;
			#proxy_set_header X-real-ip           $remote_addr;

			# 配置此处用于获取客户端的真实IP
			proxy_set_header Host $http_host;
			proxy_set_header X-Real-IP $remote_addr;
			proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
			proxy_set_header X-Forwarded-Proto $scheme;
			proxy_pass	http://localhost:8080/;
		}

        error_page   500 502 503 504  /50x.html;
        location = /50x.html {
            root   html;
        }
    }
}

nginx 配置完毕重启,访问 http://localhost 便可以成功访问:
浏览器访问

套壳实现客户端

作为一个网盘应用,自然不能少了客户端,相信在平时的开发中我们也不时会遇到客户要求使用客户端的场景,我的客户在之前的项目中就提过此类的需求,但我相信做 java 开发的大部分都是 web 开发,对于桌面应用的开发基本都不擅长,那么问题来了,怎么用最小的成本把当前的 web 应用转化为桌面应用并且可以保证平台兼容性呢,当时我的客户就要求能在 windows,mac,linux 和国产麒麟系统上运行,可以说是很变态了,我当时寻求解决方案也花了好一阵时间。

我试过前台的 electron,JavaFx 等,实现效果都不理想,最后终于发现了一款兼容性极好,实现效果良好的客户端套壳神器:JxBrower,JxBrower 的功能十分强大,他是使用 Java 开发,内置了 chrome 的内核,并且可以对 js 和 Java 程序进行桥接,实现两者之间的交互,同时也可以监听浏览器中常见的事件,定制自己的个性化业务需求,唯一美中不足的,它是付费插件,想要试用的朋友可以去官网申请试用 license,可以免费使用 30 天,也可以在公众号直接联系我哦。

此项目我正是利用 JxBrower 实现了网盘客户端,代码如下:

package com.btzh;

import com.teamdev.jxbrowser.browser.Browser;
import com.teamdev.jxbrowser.browser.callback.StartDownloadCallback;
import com.teamdev.jxbrowser.download.Download;
import com.teamdev.jxbrowser.download.DownloadTarget;
import com.teamdev.jxbrowser.download.event.DownloadUpdated;
import com.teamdev.jxbrowser.engine.Engine;
import com.teamdev.jxbrowser.engine.EngineOptions;
import com.teamdev.jxbrowser.view.swing.BrowserView;

import javax.swing.*;
import java.awt.*;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.io.File;
import java.nio.file.Paths;

import static com.teamdev.jxbrowser.engine.RenderingMode.HARDWARE_ACCELERATED;


/**
 * @author zrx
 */
public class Main {

	public static void main(String[] args) {
		Engine engine = Engine.newInstance(EngineOptions.newBuilder(HARDWARE_ACCELERATED)
				.licenseKey("自己申请的试用license")
				.build());
		// Create a Browser instance.
		Browser browser = engine.newBrowser();
		SwingUtilities.invokeLater(() -> {
			JFrame frame = new JFrame("螺旋云盘");
			frame.setIconImage(Toolkit.getDefaultToolkit().getImage(Main.class.getResource(
					"/com/btzh/pan.png")));
			frame.addWindowListener(new WindowAdapter() {
				@Override
				public void windowClosing(WindowEvent e) {
					// Shutdown Chromium and release allocated resources.
					System.exit(0);
					//engine.close();
				}
			});
			// Create and embed Swing BrowserView component to display web content.
			frame.add(BrowserView.newInstance(browser));
			frame.setSize(1280, 800);
			frame.setLocationRelativeTo(null);
			frame.setVisible(true);
			// Load the required web page.
			browser.navigation().loadUrl("http://localhost");
			//zrx 监听浏览器下载
			browser.set(StartDownloadCallback.class, (params, tell) -> {
				Download download = params.download();
				// Download target details.ddd
				DownloadTarget downloadTarget = download.target();
				String suggestedFileName = downloadTarget.suggestedFileName();
				//System.out.println(downloadTarget.url());
				String processName = suggestedFileName.length() > 10 ? suggestedFileName.substring(0, 10) + "..." : suggestedFileName;

				//选择文件夹
				JFileChooser jfc = new JFileChooser();
				jfc.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY);
				int flg = jfc.showDialog(new JLabel(), "选择");
				// 如果选择了
				if (flg == JFileChooser.APPROVE_OPTION) {
					ProgressDialog dlgMain = new ProgressDialog(100, frame);
					//监听下载
					download.on(DownloadUpdated.class, event -> {
						// Print download progress in percents.
						event.progress().ifPresent(progress -> {
									dlgMain.setVisible(true);
									JProgressBar progressBar = dlgMain.getProgressBar();
									progressBar.setValue((int) progress.value());
									progressBar.setString(processName + ":" + progress.value() + "%");
									if ((int) progress.value() == 100) {
										dlgMain.dispose();
									}
								}
						);
						/*long currentSpeed = event.currentSpeed();
						long totalBytes = event.totalBytes();
						long receivedBytes = event.receivedBytes();*/
					});
					File file = jfc.getSelectedFile();
					// Tell the engine to download and save the file.
					tell.download(Paths.get(file.getAbsolutePath(), suggestedFileName));
				}
			});
		});
	}
}

如上,核心代码便是 browser.navigation().loadUrl(“http://localhost”),除此之外,在这里我监听了浏览器的下载事件,实现了一个简单的进度条下载提示,默认下载的时候没有提示,不大友好。

整体套壳实现效果(上传和下载)如下:
网盘
下载

结语

通过本文,我们在分享云盘系统的同时着重讲解了大文件断点续传的相关知识,捋顺了其中的主要流程,这也是云盘系统的核心功能之一,然后我们也借此了解了 JxBrower 套壳,之后如果有客户端开发的场景都可以作为解决方案备用。希望通过本文能让你有所收获,有所感悟。

想要获取本文所有源码资料的朋友可以关注公众号螺旋编程极客发送云盘获取,期待你的关注,我们下次再见!

  • 5
    点赞
  • 42
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
高校实验室管理系统一个基于springbootvue系统,主要用于管理高校实验室的设备、资源和实验项目。系统将实验室分为不同的类别,如化学实验室、物理实验室和生物实验室,每个实验室都有其特定的设备和资源。 该系统设计了用户管理、设备管理、实验项目管理和资源预约等功能模块。用户可以通过系统注册账号并进行登录,不同类型的用户拥有不同的权限,如管理员可以对实验室设备和资源进行管理,教师可以发布实验项目,学生可以预约实验室资源等。 在设备管理模块中,管理员可以添加、修改和删除实验室的设备信息,包括设备名称、型号、数量和状态等。在实验项目管理模块中,教师可以发布实验项目的信息,包括实验名称、内容、时间等,学生可以浏览实验项目并进行预约。 资源预约模块是系统的核心功能之一,学生可以根据自己的需求预约实验室资源,并在预约时段内使用。管理员可以对预约情况进行审核和管理,保障资源的合理利用。 系统采用了前后端分离的开发架构,前端使用vue框架进行开发,实现了用户友好的界面和交互体验。后端采用springboot框架开发,实现了业务逻辑和数据管理。系统的数据库采用MySQL进行存储,保证了数据的安全性和稳定性。 总的来说,基于springbootvue的高校实验室管理系统设计与开发充分考虑了实验室资源的合理管理和利用,为高校师生提供了便利的实验设备和资源管理平台。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值