2024年3月12日18:04:19

master
zm 2024-03-12 18:04:31 +08:00
parent f6c3670b93
commit b45c73b364
5 changed files with 564 additions and 50 deletions

View File

@ -486,6 +486,12 @@
<artifactId>rsyntaxtextarea</artifactId>
<version>3.3.4</version>
</dependency>
<dependency>
<groupId>org.apache.tika</groupId>
<artifactId>tika-core</artifactId>
<version>1.27</version> <!-- 请检查并使用最新版本 -->
</dependency>
</dependencies>
<build>

View File

@ -2,18 +2,23 @@ package com.zhangmeng.tools.controller;
import cn.hutool.crypto.digest.DigestUtil;
import com.zhangmeng.tools.utils.AlertUtils;
import com.zhangmeng.tools.utils.EncryptUtils;
import com.zhangmeng.tools.utils.ImagePath;
import com.zhangmeng.tools.utils.MinioUtils;
import com.zhangmeng.tools.dto.BucketFile;
import com.zhangmeng.tools.utils.*;
import io.minio.messages.Bucket;
import javafx.beans.value.ChangeListener;
import javafx.beans.value.ObservableValue;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.fxml.FXML;
import javafx.scene.control.Button;
import javafx.scene.control.TextField;
import javafx.scene.Scene;
import javafx.scene.control.*;
import javafx.scene.control.cell.PropertyValueFactory;
import javafx.scene.image.Image;
import javafx.scene.image.ImageView;
import javafx.stage.DirectoryChooser;
import javafx.stage.FileChooser;
import javafx.stage.Stage;
import javafx.scene.text.Text;
import javafx.stage.*;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.io.FileUtils;
import org.apache.commons.io.FilenameUtils;
@ -21,6 +26,10 @@ import org.apache.commons.io.FilenameUtils;
import java.io.File;
import java.io.IOException;
import java.nio.file.Files;
import java.util.Arrays;
import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors;
/**
*
@ -41,9 +50,6 @@ public class MinioUploadController {
@FXML
public TextField secretKey;
@FXML
public TextField bucket;
@FXML
public ImageView iv;
@ -56,9 +62,140 @@ public class MinioUploadController {
@FXML
public TextField file_path;
@FXML
public ComboBox<String> backet_list;
private final ObservableList<String> backet_item_list = FXCollections.observableArrayList();
private final ObservableList<BucketFile> list = FXCollections.observableArrayList();
@FXML
public TableView<BucketFile> tableview;
@FXML
public TableColumn<BucketFile,String> file_name;
@FXML
public TableColumn<BucketFile,Number> file_size;
@FXML
public TableColumn<BucketFile,String> file_url;
@FXML
public TableColumn<BucketFile,String> file_bucket;
@FXML
public Button reload_config;
@FXML
public Button delete_bucket;
@FXML
public Button create_bucket;
@FXML
public TextField create_bucket_name;
public void reload(String bucketName){
if (bucketName == null){
return;
}
List<BucketFile> bucketFiles = MinioUtils.getFileList(bucketName);
if (bucketFiles.size()>0){
list.clear();
list.addAll(bucketFiles);
}
}
public void init_bucket_list(){
backet_item_list.clear();
//获取所有储存桶
List<Bucket> buckets = MinioUtils.getAllBuckets();
if (buckets.size()>0){
for (Bucket bucket : buckets) {
backet_item_list.add(bucket.name());
}
}
}
public void init_minio_config(){
//默认值
endpoint.setText("http://192.168.1.254:9000");
accessKey.setText("minioadmin");
secretKey.setText("minioadmin");
MinioUtils.objectMap.put("endpoint",endpoint.getText());
MinioUtils.objectMap.put("accessKey",accessKey.getText());
MinioUtils.objectMap.put("secretKey",secretKey.getText());
}
public void reload_minio_config(){
}
@FXML
public void initialize() {
init_minio_config();
this.backet_list.setItems(backet_item_list);
backet_list.getSelectionModel().selectedItemProperty().addListener(new ChangeListener<String>() {
@Override
public void changed(ObservableValue<? extends String> observable, String oldValue, String newValue) {
if (newValue != null){
reload(newValue);
}
}
});
init_bucket_list();
tableview.setItems(list);
file_name.setCellValueFactory(new PropertyValueFactory<BucketFile,String>("fileName"));
file_size.setCellValueFactory(new PropertyValueFactory<BucketFile,Number>("size"));
file_url.setCellValueFactory(new PropertyValueFactory<BucketFile,String>("url"));
file_bucket.setCellValueFactory(new PropertyValueFactory<BucketFile,String>("bucketName"));
file_name.prefWidthProperty().bind(tableview.widthProperty().divide(tableview.getColumns().size()));
file_size.prefWidthProperty().bind(tableview.widthProperty().divide(tableview.getColumns().size()));
file_url.prefWidthProperty().bind(tableview.widthProperty().divide(tableview.getColumns().size()));
file_bucket.prefWidthProperty().bind(tableview.widthProperty().divide(tableview.getColumns().size()));
// 创建上下文菜单
final ContextMenu contextMenu = new ContextMenu();
MenuItem cat = new MenuItem("查看");
MenuItem copy_url = new MenuItem("复制url");
MenuItem menuItem = new MenuItem("删除");
menuItem.setOnAction(event -> {
list.remove(tableview.getSelectionModel().getSelectedItem());
});
contextMenu.getItems().add(cat);
cat.setOnAction(event -> {
BucketFile selectedItem = tableview.getSelectionModel().getSelectedItem();
iv.setImage(new Image(selectedItem.getUrl()));
});
contextMenu.getItems().add(copy_url);
copy_url.setOnAction(event -> {
ClipboardUtils.setString(tableview.getSelectionModel().getSelectedItem().getUrl());
});
contextMenu.getItems().add(menuItem);
// 添加事件监听器来处理上下文菜单的显示
tableview.setOnContextMenuRequested(event -> {
// 只有当表格有选中项时才显示上下文菜单
if (!tableview.getSelectionModel().isEmpty()) {
contextMenu.show(tableview, event.getScreenX(), event.getScreenY());
}
});
tableview.getSelectionModel().selectedItemProperty().addListener(new ChangeListener<BucketFile>() {
@Override
public void changed(ObservableValue<? extends BucketFile> observable, BucketFile oldValue, BucketFile newValue) {
if (newValue != null) {
System.out.println(newValue.getFileName());
}
}
});
file_choose.setText(null);
ImageView iv = new ImageView(new Image(ImagePath.path(ImagePath.ImagePathType.IMAGE_FILE)));
iv.setPreserveRatio(true);
@ -66,11 +203,6 @@ public class MinioUploadController {
file_choose.setGraphic(iv);
file_choose.setOnAction(event -> choose_file());
//默认值
endpoint.setText("http://192.168.1.14:9000");
accessKey.setText("minioadmin");
secretKey.setText("minioadmin");
bucket.setText("mediafiles");
upload.setOnAction(event -> {
@ -89,19 +221,62 @@ public class MinioUploadController {
return;
}
if (bucket.getText().length() == 0) {
AlertUtils.alert_warning("bucket不能为空!");
if (backet_list.getSelectionModel().getSelectedItem() == null) {
AlertUtils.alert_warning("请选择bucket再试!");
return;
}
File file = new File(file_path.getText());
String extension = FilenameUtils.getExtension(file.getName());
if (extension.equals("jpg") || extension.equals("png")) {
images_upload();
// String extension = FilenameUtils.getExtension(file.getName());
// if (extension.equals("jpg") || extension.equals("png")) {
// images_upload();
// }
// if (extension.equals("mp4") || extension.equals("avi")) {
// videos_upload();
// }
MinioUtils.upload_file(file,backet_list.getSelectionModel().getSelectedItem());
reload(backet_list.getSelectionModel().getSelectedItem());
});
reload_config.setOnAction(event -> {
});
create_bucket.setOnAction(event -> {
if (create_bucket_name.getText().length() == 0) {
AlertUtils.alert_warning("bucket的名称不能为空!");
return;
}
if (extension.equals("mp4") || extension.equals("avi")) {
videos_upload();
MinioUtils.createBucket(create_bucket_name.getText());
init_bucket_list();
});
delete_bucket.setOnAction(event -> {
// 用户点击了确定按钮
if (backet_list.getSelectionModel().getSelectedItem() == null){
MinioUtils.warning_msg("请选择将要删除的bucket在试!");
return;
}
Alert alert = new Alert(Alert.AlertType.CONFIRMATION);
alert.initModality(Modality.APPLICATION_MODAL);
alert.setTitle("确认");
alert.setHeaderText("你确定要继续吗?");
alert.setContentText("这将执行一个操作。");
Optional<ButtonType> result = alert.showAndWait();
result.ifPresent(response -> {
if (response == ButtonType.OK) {
//清空
List<BucketFile> fileList = MinioUtils.getFileList(backet_list.getSelectionModel().getSelectedItem());
List<String> del_list = fileList.stream().map(BucketFile::getFileName).collect(Collectors.toList());
MinioUtils.removeFiles(backet_list.getSelectionModel().getSelectedItem(), del_list);
MinioUtils.removeBucket(backet_list.getSelectionModel().getSelectedItem());
AlertUtils.alert_msg("删除成功!");
init_bucket_list();
} else {
}
});
});
}
@ -116,14 +291,14 @@ public class MinioUploadController {
// process the chunk
String fileMd5 = DigestUtil.md5Hex(chunk);
//判断分块是否存在
if (!MinioUtils.checkChunk(fileMd5, i, bucket.getText())) {
if (!MinioUtils.checkChunk(fileMd5, i, backet_list.getSelectionModel().getSelectedItem())) {
//得到分块文件的目录路径
String chunkFileFolderPath = MinioUtils.getChunkFileFolderPath(fileMd5);
//得到分块文件的路径
String chunkFilePath = chunkFileFolderPath + i;
try {
//将文件存储至minIO
MinioUtils.addMediaFilesToMinIO(chunk, bucket.getText(), chunkFilePath, "application/octet-stream");
MinioUtils.addMediaFilesToMinIO(chunk, backet_list.getSelectionModel().getSelectedItem(), chunkFilePath, "application/octet-stream");
} catch (Exception ex) {
ex.printStackTrace();
}
@ -136,7 +311,7 @@ public class MinioUploadController {
try {
//上传文件到minIO
MinioUtils.addMediaFilesToMinIO(filereader.getFile().getAbsolutePath(), bucket.getText(), mergeFilePath);
MinioUtils.addMediaFilesToMinIO(filereader.getFile().getAbsolutePath(), backet_list.getSelectionModel().getSelectedItem(), mergeFilePath);
log.debug("合并文件上传MinIO完成{}", filereader.getFile().getAbsolutePath());
} catch (Exception e) {
e.printStackTrace();
@ -156,7 +331,7 @@ public class MinioUploadController {
String md5Hex = DigestUtil.md5Hex(bytes);
String contentType = Files.probeContentType(file.toPath());
String extension = FilenameUtils.getExtension(file.getName());
MinioUtils.addMediaFilesToMinIO(bytes, bucket.getText(), md5Hex + "." + extension, contentType);
MinioUtils.addMediaFilesToMinIO(bytes, backet_list.getSelectionModel().getSelectedItem(), md5Hex + "." + extension, contentType);
} catch (IOException e) {
e.printStackTrace();
}

View File

@ -0,0 +1,68 @@
package com.zhangmeng.tools.dto;
/**
* @author zhangmeng
* @version 1.0
* @date 2024-03-07 16:31
*/
public class BucketFile {
private String bucketName;
private String fileName;
private boolean isDir;
private Long size;
private String url;
public BucketFile() {
}
public BucketFile(String bucketName, String fileName, boolean isDir, Long size, String url) {
this.bucketName = bucketName;
this.fileName = fileName;
this.isDir = isDir;
this.size = size;
this.url = url;
}
public String getBucketName() {
return bucketName;
}
public void setBucketName(String bucketName) {
this.bucketName = bucketName;
}
public String getFileName() {
return fileName;
}
public void setFileName(String fileName) {
this.fileName = fileName;
}
public boolean isDir() {
return isDir;
}
public void setDir(boolean dir) {
isDir = dir;
}
public Long getSize() {
return size;
}
public void setSize(Long size) {
this.size = size;
}
public String getUrl() {
return url;
}
public void setUrl(String url) {
this.url = url;
}
}

View File

@ -1,19 +1,30 @@
package com.zhangmeng.tools.utils;
import io.minio.GetObjectArgs;
import io.minio.MinioClient;
import io.minio.PutObjectArgs;
import io.minio.UploadObjectArgs;
import com.zhangmeng.tools.dto.BucketFile;
import io.minio.*;
import io.minio.errors.*;
import io.minio.http.Method;
import io.minio.messages.Bucket;
import io.minio.messages.DeleteObject;
import io.minio.messages.Item;
import javafx.application.Platform;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.codec.digest.DigestUtils;
import org.apache.commons.io.FilenameUtils;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.tika.Tika;
import java.io.*;
import java.nio.ByteBuffer;
import java.nio.channels.FileChannel;
import java.nio.file.Path;
import java.nio.file.StandardOpenOption;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.util.*;
import java.util.stream.Collectors;
@Slf4j
public class MinioUtils {
@ -25,6 +36,35 @@ public class MinioUtils {
}
}
public static Map<String,Object> objectMap = new HashMap<>();
public static MinioClient getDefault() {
if (minioClient == null) {
Object endpoint = objectMap.get("endpoint");
Object accessKey = objectMap.get("accessKey");
Object secretKey = objectMap.get("secretKey");
if (endpoint == null ){
Platform.runLater(()->{
AlertUtils.alert_warning("配置文件endpoint 为空");
});
return null;
}
if (accessKey == null ){
Platform.runLater(()->{
AlertUtils.alert_warning("配置文件accessKey 为空");
});
return null;
}
if (secretKey == null ){
Platform.runLater(()->{
AlertUtils.alert_warning("配置文件secretKey 为空");
});
return null;
}
minioClient = MinioClient.builder().endpoint(endpoint.toString()).credentials(accessKey.toString(), secretKey.toString()).build();
}
return minioClient;
}
public static String getFilePathByMd5(String fileMd5, String fileExt) {
return fileMd5.substring(0, 1) + "/" + fileMd5.substring(1, 2) + "/" + fileMd5 + "/" + fileMd5 + fileExt;
@ -56,6 +96,66 @@ public class MinioUtils {
return false;
}
public static List<Item> getAllObjectsByPrefix(String bucketName,
String prefix,
boolean recursive) {
List<Item> list = new ArrayList<>();
Iterable<Result<Item>> objectsIterator = getDefault().listObjects(
ListObjectsArgs.builder().bucket(bucketName).prefix(prefix).recursive(recursive).build());
if (objectsIterator != null) {
for (Result<Item> o : objectsIterator) {
Item item = null;
try {
item = o.get();
} catch (ErrorResponseException | InsufficientDataException | InternalException | InvalidKeyException | InvalidResponseException | IOException | NoSuchAlgorithmException | ServerException | XmlParserException e) {
e.printStackTrace();
}
list.add(item);
}
}
return list;
}
public static List<BucketFile> getFileList(String bucketName) {
List<Item> itemList = getAllObjectsByPrefix(bucketName, null, true);
List<BucketFile> list = new ArrayList<>();
if (itemList.size() > 0 ){
list = itemList.stream().map(i -> {
BucketFile bucketFile = new BucketFile();
bucketFile.setBucketName(bucketName);
bucketFile.setDir(i.isDir());
bucketFile.setFileName(i.objectName());
bucketFile.setSize(i.size());
//获取url
String presignedObjectUrl = getPresignedObjectUrl(bucketName, i.objectName());
bucketFile.setUrl(presignedObjectUrl);
return bucketFile;
}).collect(Collectors.toList());
}
return list;
}
/**
*
*
* @param bucketName
* @param objectName
* @return url
*/
public static String getPresignedObjectUrl(String bucketName, String objectName) {
GetPresignedObjectUrlArgs args = GetPresignedObjectUrlArgs.builder()
.bucket(bucketName)
.object(objectName)
.method(Method.GET).build();
try {
return getDefault().getPresignedObjectUrl(args);
} catch (ErrorResponseException | InsufficientDataException | InternalException | InvalidKeyException | InvalidResponseException | IOException | NoSuchAlgorithmException | XmlParserException | ServerException e) {
e.printStackTrace();
}
return null;
}
public static class FileChunkReader implements AutoCloseable {
private final FileChannel channel;
@ -293,7 +393,159 @@ public class MinioUtils {
}
public static void main(String[] args) {
test("G:\\FXGL基础入门教程 Java游戏引擎教程_1简介与游戏演示\\1-1 简介与游戏演示-1080P 高清-AVC.mp4");
/**
* Bucket
*
* @return
*/
public static List<Bucket> getAllBuckets() {
try {
return getDefault().listBuckets();
} catch (ErrorResponseException | InsufficientDataException | InternalException | InvalidKeyException | InvalidResponseException | IOException | NoSuchAlgorithmException | ServerException | XmlParserException e) {
e.printStackTrace();
}
return null;
}
public static void upload_file(File file,String bucketName){
//文件名
String fileName = file.getName();
String newFileName = System.currentTimeMillis() + "." + StringUtils.substringAfterLast(fileName, ".");
String contentType = getContentType(file);
if (bucketName == null){
AlertUtils.alert_warning("上传的bucket不能为空!");
return;
}
uploadFile(bucketName, file, newFileName, contentType);
AlertUtils.alert_msg("文件上传成功");
}
/**
* 使MultipartFile
*
* @param bucketName
* @param file
* @param objectName
* @param contentType
* @return
*/
public static ObjectWriteResponse uploadFile(String bucketName, File file, String objectName, String contentType) {
FileInputStream inputStream = null;
try {
inputStream = new FileInputStream(file);
return minioClient.putObject(
PutObjectArgs.builder()
.bucket(bucketName)
.object(objectName)
.contentType(contentType)
.stream(inputStream,inputStream.available(), -1)
.build());
} catch (IOException | ServerException | InsufficientDataException | XmlParserException | InternalException | InvalidResponseException | InvalidKeyException | NoSuchAlgorithmException | ErrorResponseException e) {
e.printStackTrace();
} finally {
if (inputStream != null){
try {
inputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
return null;
}
public static String getContentType(File file){
Tika tika = new Tika();
try {
return tika.detect(file);
} catch (IOException e) {
e.printStackTrace();
}
return null;
}
/**
* SpringBootBucket
* Bucket
*
* @param bucketName
*/
@SneakyThrows(Exception.class)
public static void createBucket(String bucketName) {
if (!bucketExists(bucketName)) {
getDefault().makeBucket(MakeBucketArgs.builder().bucket(bucketName).build());
success_msg(bucketName + "创建成功!");
}else {
warning_msg(bucketName + "已存在");
}
}
public static void warning_msg(String msg){
Platform.runLater(()->{
AlertUtils.alert_warning(msg );
});
}
public static void success_msg(String msg){
Platform.runLater(()->{
AlertUtils.alert_msg(msg);
});
}
/**
* Buckettruefalse
*
* @param bucketName
* @return
*/
@SneakyThrows(Exception.class)
public static boolean bucketExists(String bucketName) {
return getDefault().bucketExists(BucketExistsArgs.builder().bucket(bucketName).build());
}
/**
* bucketNameBuckettrue false
*
* @param bucketName
* @throws Exception
*/
@SneakyThrows(Exception.class)
public static void removeBucket(String bucketName) {
getDefault().removeBucket(RemoveBucketArgs.builder().bucket(bucketName).build());
}
/**
*
*
* @param bucketName
* @param objectName
*/
@SneakyThrows(Exception.class)
public static void removeFile(String bucketName, String objectName) {
minioClient.removeObject(
RemoveObjectArgs.builder()
.bucket(bucketName)
.object(objectName)
.build());
}
/**
*
*
* @param bucketName
* @param keys
* @return
*/
public static void removeFiles(String bucketName, List<String> keys) {
List<DeleteObject> objects = new LinkedList<>();
keys.forEach(s -> {
objects.add(new DeleteObject(s));
try {
removeFile(bucketName, s);
} catch (Exception e) {
log.error("[Minio工具类]>>>> 批量删除文件,异常:", e);
}
});
}
}

View File

@ -1,32 +1,45 @@
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.scene.control.Button?>
<?import javafx.scene.control.ComboBox?>
<?import javafx.scene.control.Label?>
<?import javafx.scene.control.ProgressBar?>
<?import javafx.scene.control.TableColumn?>
<?import javafx.scene.control.TableView?>
<?import javafx.scene.control.TextField?>
<?import javafx.scene.image.ImageView?>
<?import javafx.scene.layout.AnchorPane?>
<AnchorPane prefHeight="649.0" prefWidth="1200.0" style="-fx-background-color: 1px;" xmlns="http://javafx.com/javafx/19" xmlns:fx="http://javafx.com/fxml/1" fx:controller="com.zhangmeng.tools.controller.MinioUploadController">
<children>
<Label layoutX="265.0" layoutY="72.0" text="endpoint:" />
<TextField fx:id="endpoint" layoutX="344.0" layoutY="68.0" prefHeight="25.0" prefWidth="612.0" />
<TextField fx:id="accessKey" layoutX="344.0" layoutY="125.0" prefHeight="25.0" prefWidth="612.0" />
<TextField fx:id="secretKey" layoutX="344.0" layoutY="181.0" prefHeight="25.0" prefWidth="612.0" />
<Label layoutX="263.0" layoutY="129.0" text="accessKey:" />
<Label layoutX="264.0" layoutY="185.0" text="secretKey:" />
<Label layoutX="278.0" layoutY="242.0" text="bucket:" />
<TextField fx:id="bucket" layoutX="344.0" layoutY="238.0" prefHeight="25.0" prefWidth="612.0" />
<Label layoutX="284.0" layoutY="308.0" text="文件:" />
<AnchorPane layoutX="344.0" layoutY="317.0" prefHeight="153.0" prefWidth="227.0" style="-fx-border-color: gray;-fx-border-width: 1px">
<Label layoutX="45.0" layoutY="39.0" text="endpoint:" />
<TextField fx:id="endpoint" layoutX="112.0" layoutY="34.0" prefHeight="25.0" prefWidth="169.0" />
<TextField fx:id="accessKey" layoutX="387.0" layoutY="34.0" prefHeight="25.0" prefWidth="169.0" />
<TextField fx:id="secretKey" layoutX="633.0" layoutY="34.0" prefHeight="25.0" prefWidth="169.0" />
<Label layoutX="311.0" layoutY="39.0" text="accessKey:" />
<Label layoutX="571.0" layoutY="39.0" text="secretKey:" />
<Label layoutX="833.0" layoutY="39.0" text="bucket:" />
<Label layoutX="45.0" layoutY="97.0" text="文件:" />
<AnchorPane layoutX="112.0" layoutY="97.0" prefHeight="153.0" prefWidth="227.0" style="-fx-border-color: gray;-fx-border-width: 1px">
<children>
<ImageView fx:id="iv" fitHeight="153.0" fitWidth="227.0" pickOnBounds="true" preserveRatio="true" AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="0.0" />
</children>
</AnchorPane>
<Button fx:id="file_choose" layoutX="623.0" layoutY="382.0" mnemonicParsing="false" text="文件选择" />
<Button fx:id="upload" layoutX="752.0" layoutY="382.0" mnemonicParsing="false" text="上传" />
<ProgressBar layoutX="263.0" layoutY="539.0" prefHeight="7.0" prefWidth="746.0" progress="0.0" />
<Label layoutX="209.0" layoutY="534.0" text="进度:" />
<TextField fx:id="file_path" layoutX="623.0" layoutY="317.0" prefHeight="25.0" prefWidth="331.0" />
<Button fx:id="file_choose" layoutX="725.0" layoutY="101.0" mnemonicParsing="false" text="文件选择" />
<Button fx:id="upload" layoutX="814.0" layoutY="101.0" mnemonicParsing="false" text="上传" />
<TextField fx:id="file_path" layoutX="376.0" layoutY="100.0" prefHeight="25.0" prefWidth="331.0" />
<TableView fx:id="tableview" layoutX="27.0" layoutY="270.0" prefHeight="200.0" prefWidth="200.0" AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="270.0">
<columns>
<TableColumn fx:id="file_bucket" prefWidth="300.0" text="bucket名称" />
<TableColumn fx:id="file_name" prefWidth="270.0" text="文件名称" />
<TableColumn fx:id="file_size" prefWidth="133.0" text="文件大小" />
<TableColumn fx:id="file_url" prefWidth="496.0" text="文件url" />
</columns>
</TableView>
<ComboBox fx:id="backet_list" layoutX="905.0" layoutY="35.0" prefWidth="150.0" />
<Button fx:id="reload_config" layoutX="886.0" layoutY="101.0" mnemonicParsing="false" text="重新加载配置文件" />
<Button fx:id="create_bucket" layoutX="725.0" layoutY="163.0" mnemonicParsing="false" text="创建bucket" />
<TextField fx:id="create_bucket_name" layoutX="512.0" layoutY="163.0" prefHeight="23.0" prefWidth="191.0" />
<Label layoutX="376.0" layoutY="167.0" text="将要创建的bucket名称" />
<Button fx:id="delete_bucket" layoutX="1073.0" layoutY="35.0" mnemonicParsing="false" text="删除所选bucket" />
</children>
</AnchorPane>