10BC0 实现下载插件进度对话框 · llyJava/xJavaFxTool@418dd1a · GitHub
[go: up one dir, main page]

Skip to content

Commit 418dd1a

Browse files
committed
实现下载插件进度对话框
1 parent 5faebfb commit 418dd1a

File tree

5 files changed

+174
-22
lines changed

5 files changed

+174
-22
lines changed

src/main/java/com/xwintop/xJavaFxTool/controller/IndexController.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55

66
import com.xwintop.xJavaFxTool.controller.index.PluginManageController;
77
import com.xwintop.xJavaFxTool.model.ToolFxmlLoaderConfiguration;
8+
import com.xwintop.xJavaFxTool.plugin.PluginManager;
89
import com.xwintop.xJavaFxTool.services.IndexService;
910
import com.xwintop.xJavaFxTool.services.index.PluginManageService;
1011
import com.xwintop.xJavaFxTool.services.index.SystemSettingService;
@@ -275,6 +276,7 @@ private void pluginManageAction() throws Exception {
275276
try {
276277
XJavaFxSystemUtil.addJarClass(jarFile);
277278
this.addToolMenu(jarFile);
279+
PluginManager.getInstance().loadLocalPlugins();
278280
} catch (Exception e) {
279281
log.error("加载工具出错:", e);
280282
}

src/main/java/com/xwintop/xJavaFxTool/controller/index/PluginManageController.java

Lines changed: 17 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -6,24 +6,29 @@
66
import com.xwintop.xJavaFxTool.view.index.PluginManageView;
77
import com.xwintop.xcore.util.javafx.JavaFxViewUtil;
88
import com.xwintop.xcore.util.javafx.TooltipUtil;
9+
import java.io.File;
10+
import java.net.URL;
11+
import java.util.Map;
12+
import java.util.ResourceBundle;
13+
import java.util.function.Consumer;
914
import javafx.collections.FXCollections;
1015
import javafx.collections.ObservableList;
1116
import javafx.collections.transformation.FilteredList;
1217
import javafx.event.ActionEvent;
1318
import javafx.fxml.FXML;
1419
import javafx.fxml.FXMLLoader;
15-
import javafx.scene.control.*;
20+
import javafx.scene.control.Button;
21+
import javafx.scene.control.ContentDisplay;
22+
import javafx.scene.control.ContextMenu;
23+
import javafx.scene.control.MenuItem;
24+
import javafx.scene.control.TableCell;
25+
import javafx.scene.control.TableColumn;
26+
import javafx.stage.Window;
1627
import javafx.util.Callback;
1728
import lombok.Getter;
1829
import lombok.Setter;
1930
import lombok.extern.slf4j.Slf4j;
2031

21-
import java.io.File;
22-
import java.net.URL;
23-
import java.util.Map;
24-
import java.util.ResourceBundle;
25-
import java.util.function.Consumer;
26-
2732
/**
2833
* @ClassName: PluginManageController
2934
* @Description: 插件管理
@@ -55,6 +60,10 @@ public void initialize(URL location, ResourceBundle resources) {
5560
initService();
5661
}
5762

63+
public Window getWindow() {
64+
return this.pluginDataTableView.getScene().getWindow();
65+
}
66+
5867
public void setOnPluginDownloaded(Consumer<File> onPluginDownloaded) {
5968
this.pluginManageService.setOnPluginDownloaded(onPluginDownloaded);
6069
}
@@ -95,6 +104,7 @@ protected void updateItem(String item, boolean empty) {
95104
downloadButton.setText("已下载");
96105
downloadButton.setDisable(true);
97106
pluginDataTableView.refresh();
107+
PluginManager.getInstance().saveToFile();
98108
TooltipUtil.showToast("插件 " + dataRow.get("nameTableColumn") + " 下载完成");
99109
} catch (Exception e) {
100110
log.error("下载插件失败:", e);

src/main/java/com/xwintop/xJavaFxTool/plugin/PluginManager.java

Lines changed: 125 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,9 @@
44
import com.alibaba.fastjson.JSON;
55
import com.xwintop.xJavaFxTool.model.PluginJarInfo;
66
import java.io.File;
7+
import java.io.FileOutputStream;
78
import java.io.IOException;
9+
import java.io.InputStream;
810
import java.nio.charset.Charset;
911
import java.nio.charset.StandardCharsets;
1012
import java.nio.file.Files;
@@ -15,8 +17,21 @@
1517
import java.util.List;
1618
import java.util.Objects;
1719
import java.util.concurrent.CompletableFuture;
20+
import java.util.function.BiConsumer;
1821
import java.util.function.Consumer;
1922
import lombok.extern.slf4j.Slf4j;
23+
import okhttp3.Interceptor;
24+
import okhttp3.MediaType;
25+
import okhttp3.OkHttpClient;
26+
import okhttp3.Request.Builder;
27+
import okhttp3.Response;
28+
import okhttp3.ResponseBody;
29+
import okio.Buffer;
30+
import okio.BufferedSource;
31+
import okio.ForwardingSource;
32+
import okio.Okio;
33+
import okio.Source;
34+
import org.apache.commons.io.IOUtils;
2035

2136
@Slf4j
2237
public class PluginManager {
@@ -40,6 +55,9 @@ public static PluginManager getInstance() {
4055

4156
private final String localPluginsPath;
4257

58+
private final OkHttpClient pluginDownloader =
59+
new OkHttpClient.Builder().addInterceptor(new DownloadProgressInterceptor()).build();
60+
4361
private final List<PluginJarInfo> pluginList = new ArrayList<>(); // 插件列表
4462

4563
public PluginManager(String localPluginsPath) {
@@ -163,14 +181,44 @@ public File downloadPlugin(PluginJarInfo pluginJarInfo) throws IOException {
163181
return file;
164182
}
165183

184+
public File downloadPlugin(
185+
PluginJarInfo pluginJarInfo, BiConsumer<Long, Long> onProgressUpdate
186+
) throws IOException {
187+
188+
PluginJarInfo plugin = getPlugin(pluginJarInfo.getJarName());
189+
if (plugin == null) {
190+
throw new IllegalStateException("没有找到插件 " + pluginJarInfo.getJarName());
191+
}
192+
193+
File file = pluginJarInfo.getFile();
194+
this.currentProgressListener =
195+
(bytesRead, contentLength, done) -> onProgressUpdate.accept(contentLength, bytesRead);
196+
197+
try (
198+
Response response = pluginDownloader
199+
.newCall(new Builder().url(pluginJarInfo.getDownloadUrl()).build())
200+
.execute();
201+
InputStream inputStream = response.body().byteStream();
202+
FileOutputStream outputStream = new FileOutputStream(file)
203+
) {
204+
IOUtils.copy(inputStream, outputStream);
205+
}
206+
207+
plugin.setIsDownload(true);
208+
plugin.setIsEnable(true);
209+
plugin.setLocalVersionNumber(plugin.getVersionNumber());
210+
return file;
211+
}
212+
166213
////////////////////////////////////////////////////////////// 保存配置
167214

168215
public void saveToFile() throws IOException {
169216
String json = JSON.toJSONString(this.pluginList, true);
170-
Files.write(
171-
Paths.get(this.localPluginsPath),
172-
json.getBytes(DEFAULT_CHARSET)
173-
);
217+
Path path = Paths.get(this.localPluginsPath);
218+
if (!Files.exists(path)) {
219+
Files.createFile(path);
220+
}
221+
Files.write(path, json.getBytes(DEFAULT_CHARSET));
174222
}
175223

176224
public void saveToFileQuietly() {
@@ -180,4 +228,77 @@ public void saveToFileQuietly() {
180228
log.error("", e);
181229
}
182230
}
231+
232+
////////////////////////////////////////////////////////////// 下载进度
233+
234+
private ProgressListener currentProgressListener;
235+
236+
private class DownloadProgressInterceptor implements Interceptor {
237+
238+
@Override
239+
public Response intercept(Chain chain) throws IOException {
240+
Response originalResponse = chain.proceed(chain.request());
241+
return originalResponse.newBuilder()
242+
.body(new ProgressResponseBody(originalResponse.body(),
243+
(bytesRead, contentLength, done) -> {
244+
if (currentProgressListener != null) {
245+
currentProgressListener.update(bytesRead, contentLength, done);
246+
}
247+
}
248+
))
249+
.build();
250+
}
251+
}
252+
253+
private static class ProgressResponseBody extends ResponseBody {
254+
255+
private final ResponseBody responseBody;
256+
257+
private final ProgressListener progressListener;
258+
259+
private BufferedSource bufferedSource;
260+
261+
ProgressResponseBody(ResponseBody responseBody, ProgressListener progressListener) {
262+
this.responseBody = responseBody;
263+
this.progressListener = progressListener;
264+
}
265+
266+
@Override
267+
public MediaType contentType() {
268+
return responseBody.contentType();
269+
}
270+
271+
@Override
272+
public long contentLength() {
273+
return responseBody.contentLength();
274+
}
275+
276+
@Override
277+
public BufferedSource source() {
278+
if (bufferedSource == null) {
279+
bufferedSource = Okio.buffer(source(responseBody.source()));
280+
}
281+
return bufferedSource;
282+
}
283+
284+
private Source source(Source source) {
285+
return new ForwardingSource(source) {
286+
long totalBytesRead = 0L;
287+
288+
@Override
289+
public long read(Buffer sink, long byteCount) throws IOException {
290+
long bytesRead = super.read(sink, byteCount);
291+
// read() returns the number of bytes read, or -1 if this source is exhausted.
292+
totalBytesRead += bytesRead != -1 ? bytesRead : 0;
293+
progressListener.update(totalBytesRead, responseBody.contentLength(), bytesRead == -1);
294+
return bytesRead;
295+
}
296+
};
297+
}
298+
}
299+
300+
interface ProgressListener {
301+
302+
void update(long bytesRead, long contentLength, boolean done);
303+
}
183304
}

src/main/java/com/xwintop/xJavaFxTool/services/IndexService.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -105,6 +105,7 @@ public void addContent(String title, String fxmlPath, String resourceBundleName,
105105
PluginJarInfo pluginJarInfo = PluginManager.getInstance().getPluginByFxmlPath(fxmlPath);
106106
if (pluginJarInfo == null) {
107107
FxAlerts.error("打开失败", "没有找到指定的插件");
108+
return;
108109
}
109110

110111
if (indexController.getSingleWindowBootCheckBox().isSelected()) {

src/main/java/com/xwintop/xJavaFxTool/services/index/PluginManageService.java

Lines changed: 29 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,21 @@
11
package com.xwintop.xJavaFxTool.services.index;
22

3+
import static org.apache.commons.lang3.StringUtils.substringBeforeLast;
4+
5+
import com.xwintop.xJavaFxTool.AppException;
36
import com.xwintop.xJavaFxTool.controller.index.PluginManageController;
47
import com.xwintop.xJavaFxTool.model.PluginJarInfo;
58
import com.xwintop.xJavaFxTool.plugin.PluginManager;
6-
import lombok.Getter;
7-
import lombok.Setter;
8-
import lombok.extern.slf4j.Slf4j;
9-
import org.apache.commons.lang3.StringUtils;
10-
9+
import com.xwintop.xcore.javafx.dialog.FxProgressDialog;
10+
import com.xwintop.xcore.javafx.dialog.ProgressTask;
1111
import java.io.File;
1212
import java.util.HashMap;
1313
import java.util.Map;
1414
import java.util.function.Consumer;
15-
16-
import static org.apache.commons.lang3.StringUtils.substringBeforeLast;
15+
import lombok.Getter;
16+
import lombok.Setter;
17+
import lombok.extern.slf4j.Slf4j;
18+
import org.apache.commons.lang3.StringUtils;
1719

1820
/**
1921
* 插件管理
@@ -81,10 +83,26 @@ public void downloadPluginJar(Map<String, String> dataRow) throws Exception {
8183
pluginJarInfo.setIsDownload(true);
8284
pluginJarInfo.setIsEnable(true);
8385

84-
File file = pluginManager.downloadPlugin(pluginJarInfo);
85-
if (onPluginDownloaded != null) {
86-
onPluginDownloaded.accept(file);
87-
}
86+
ProgressTask progressTask = new ProgressTask() {
87+
@Override
88+
protected void execute() throws Exception {
89+
File file = pluginManager.downloadPlugin(
90+
pluginJarInfo, (total, current) -> updateProgress(current, total)
91+
);
92+
93+
if (onPluginDownloaded != null) {
94+
onPluginDownloaded.accept(file);
95+
}
96+
}
97+
};
98+
99+
progressTask.setOnCancelled(event -> {
100+
throw new AppException("下载被取消。");
101+
});
102+
103+
FxProgressDialog
104+
.create(pluginManageController.getWindow(), progressTask, "正在下载插件 " + pluginJarInfo.getName() + "...")
105+
.showAndWait();
88106
}
89107

90108
public void setIsEnableTableColumn(Integer index) {

0 commit comments

Comments
 (0)
0