添加ftp 服务 2023年3月11日15:59:44
parent
387252e3d0
commit
7b0be2127a
|
|
@ -140,6 +140,10 @@
|
||||||
|
|
||||||

|

|
||||||
|
|
||||||
|
#### 8.2 ftp 服务工具
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
## 2. 开源项目总览
|
## 2. 开源项目总览
|
||||||
|
|
||||||
| 项目名称 |地址|
|
| 项目名称 |地址|
|
||||||
|
|
|
||||||
6
pom.xml
6
pom.xml
|
|
@ -276,6 +276,12 @@
|
||||||
<artifactId>javax.mail</artifactId>
|
<artifactId>javax.mail</artifactId>
|
||||||
<version>1.6.2</version>
|
<version>1.6.2</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.apache.ftpserver</groupId>
|
||||||
|
<artifactId>ftpserver-core</artifactId>
|
||||||
|
<version>1.1.1</version>
|
||||||
|
</dependency>
|
||||||
</dependencies>
|
</dependencies>
|
||||||
|
|
||||||
<build>
|
<build>
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,30 @@
|
||||||
package com.zhangmeng.tools.controller;
|
package com.zhangmeng.tools.controller;
|
||||||
|
|
||||||
|
import com.zhangmeng.tools.server.SimpleFtpServer;
|
||||||
|
import com.zhangmeng.tools.utils.AlertUtils;
|
||||||
|
import com.zhangmeng.tools.utils.ImagePath;
|
||||||
|
import javafx.beans.property.SimpleObjectProperty;
|
||||||
|
import javafx.collections.FXCollections;
|
||||||
|
import javafx.collections.ObservableList;
|
||||||
|
import javafx.fxml.FXML;
|
||||||
|
import javafx.geometry.Pos;
|
||||||
|
import javafx.scene.control.*;
|
||||||
|
import javafx.scene.image.Image;
|
||||||
|
import javafx.scene.image.ImageView;
|
||||||
|
import javafx.scene.layout.HBox;
|
||||||
|
import javafx.scene.paint.Paint;
|
||||||
|
import javafx.scene.text.Text;
|
||||||
|
import javafx.stage.DirectoryChooser;
|
||||||
|
import javafx.stage.Stage;
|
||||||
|
import javafx.util.Callback;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.apache.ftpserver.ftplet.Authority;
|
||||||
|
import org.apache.ftpserver.usermanager.impl.BaseUser;
|
||||||
|
import org.apache.ftpserver.usermanager.impl.WritePermission;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author : 芊芊墨客
|
* @author : 芊芊墨客
|
||||||
|
|
@ -10,5 +34,205 @@ import lombok.extern.slf4j.Slf4j;
|
||||||
@Slf4j
|
@Slf4j
|
||||||
public class FtpServerController {
|
public class FtpServerController {
|
||||||
|
|
||||||
|
public enum Status{
|
||||||
|
init("未启动"),
|
||||||
|
start("已启动"),
|
||||||
|
stop("已停止"),
|
||||||
|
;
|
||||||
|
|
||||||
|
private String desc;
|
||||||
|
|
||||||
|
Status(String desc) {
|
||||||
|
this.desc = desc;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getDesc() {
|
||||||
|
return desc;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setDesc(String desc) {
|
||||||
|
this.desc = desc;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@FXML
|
||||||
|
public Button server_start;
|
||||||
|
|
||||||
|
@FXML
|
||||||
|
public Button server_stop;
|
||||||
|
|
||||||
|
@FXML
|
||||||
|
public TextField user_name;
|
||||||
|
|
||||||
|
@FXML
|
||||||
|
public PasswordField password;
|
||||||
|
|
||||||
|
@FXML
|
||||||
|
public TextField resoureces_dir;
|
||||||
|
|
||||||
|
@FXML
|
||||||
|
public Text server_status;
|
||||||
|
|
||||||
|
@FXML
|
||||||
|
private Button add_user;
|
||||||
|
|
||||||
|
@FXML
|
||||||
|
private ListView<Data> server_list;
|
||||||
|
|
||||||
|
@FXML
|
||||||
|
private Button choose_file_dir;
|
||||||
|
|
||||||
|
private ObservableList<Data> list = FXCollections.observableArrayList();
|
||||||
|
private SimpleObjectProperty<Status> server_status_info = new SimpleObjectProperty<>();
|
||||||
|
|
||||||
|
private SimpleFtpServer simpleFtpServer = null;
|
||||||
|
|
||||||
|
@FXML
|
||||||
|
public void initialize() {
|
||||||
|
|
||||||
|
initStatus();
|
||||||
|
server_list.setPlaceholder(new Label("暂无服务信息!"));
|
||||||
|
server_list.setItems(list);
|
||||||
|
server_list.setCellFactory(new Callback<>() {
|
||||||
|
@Override
|
||||||
|
public ListCell<Data> call(ListView<Data> param) {
|
||||||
|
return new ListCell<>() {
|
||||||
|
@Override
|
||||||
|
protected void updateItem(Data data, boolean b) {
|
||||||
|
super.updateItem(data, b);
|
||||||
|
if (!b) {
|
||||||
|
HBox hBox = new HBox();
|
||||||
|
hBox.setAlignment(Pos.CENTER);
|
||||||
|
hBox.getChildren().add(new Label("username:" + data.username + ",password:" + data.password + ",rootDir:" + data.rootDir));
|
||||||
|
this.setGraphic(hBox);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
});
|
||||||
|
server_list.setFixedCellSize(40);
|
||||||
|
add_user.setOnAction(event -> {
|
||||||
|
if (user_name.getText().length() == 0 ){
|
||||||
|
AlertUtils.alert_warning("用户名不能为空!");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (password.getText().length() == 0 ){
|
||||||
|
AlertUtils.alert_warning("密码不能为空!");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (resoureces_dir.getText().length() == 0 ){
|
||||||
|
AlertUtils.alert_warning("资源文件夹不能为空!");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
Data data = new Data();
|
||||||
|
data.setUsername(user_name.getText());
|
||||||
|
data.setPassword(password.getText());
|
||||||
|
data.setRootDir(resoureces_dir.getText());
|
||||||
|
|
||||||
|
list.add(data);
|
||||||
|
|
||||||
|
//清楚输入框
|
||||||
|
user_name.setText(null);
|
||||||
|
password.setText(null);
|
||||||
|
resoureces_dir.setText(null);
|
||||||
|
});
|
||||||
|
|
||||||
|
server_start.setOnAction(event -> {
|
||||||
|
|
||||||
|
simpleFtpServer = SimpleFtpServer.create();
|
||||||
|
|
||||||
|
for (Data item : server_list.getItems()) {
|
||||||
|
BaseUser user = new BaseUser();
|
||||||
|
List<Authority> list = new ArrayList<>();
|
||||||
|
list.add(new WritePermission());
|
||||||
|
user.setAuthorities(list);
|
||||||
|
user.setName(item.username);
|
||||||
|
user.setPassword(item.password);
|
||||||
|
user.setHomeDirectory(item.rootDir);
|
||||||
|
simpleFtpServer.addUser(user);
|
||||||
|
}
|
||||||
|
simpleFtpServer.start();
|
||||||
|
startStatus();
|
||||||
|
});
|
||||||
|
|
||||||
|
server_stop.setOnAction(event -> {
|
||||||
|
simpleFtpServer.stop();
|
||||||
|
stopStatus();
|
||||||
|
});
|
||||||
|
|
||||||
|
choose_file_dir.setText(null);
|
||||||
|
ImageView iv = new ImageView(new Image(ImagePath.path(ImagePath.ImagePathType.IMAGE_FILE)));
|
||||||
|
iv.setPreserveRatio(true);
|
||||||
|
iv.setFitWidth(18);
|
||||||
|
choose_file_dir.setGraphic(iv);
|
||||||
|
choose_file_dir.setOnAction(event -> {
|
||||||
|
Stage stage = new Stage();
|
||||||
|
DirectoryChooser dc = new DirectoryChooser();
|
||||||
|
dc.setTitle("文件夹选择器");
|
||||||
|
File file = dc.showDialog(stage);
|
||||||
|
if (file == null){
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
resoureces_dir.setText(file.getPath());
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private void stopStatus(){
|
||||||
|
server_status.setFill(Paint.valueOf("#ccffccff"));
|
||||||
|
server_status.setText(Status.stop.desc);
|
||||||
|
server_status_info.set(Status.stop);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void startStatus(){
|
||||||
|
server_status.setFill(Paint.valueOf("#ccffccff"));
|
||||||
|
server_status.setText(Status.start.desc);
|
||||||
|
server_status_info.set(Status.start);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void initStatus(){
|
||||||
|
server_status.setFill(Paint.valueOf("#ccffccff"));
|
||||||
|
server_status.setText(Status.init.desc);
|
||||||
|
server_status_info.set(Status.init);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class Data{
|
||||||
|
|
||||||
|
private String username;
|
||||||
|
private String password;
|
||||||
|
private String rootDir;
|
||||||
|
|
||||||
|
public Data() {
|
||||||
|
}
|
||||||
|
|
||||||
|
public Data(String username, String password, String rootDir) {
|
||||||
|
this.username = username;
|
||||||
|
this.password = password;
|
||||||
|
this.rootDir = rootDir;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getUsername() {
|
||||||
|
return username;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setUsername(String username) {
|
||||||
|
this.username = username;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getPassword() {
|
||||||
|
return password;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setPassword(String password) {
|
||||||
|
this.password = password;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getRootDir() {
|
||||||
|
return rootDir;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setRootDir(String rootDir) {
|
||||||
|
this.rootDir = rootDir;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,229 @@
|
||||||
|
package com.zhangmeng.tools.server;
|
||||||
|
|
||||||
|
import cn.hutool.core.lang.Assert;
|
||||||
|
import cn.hutool.core.net.NetUtil;
|
||||||
|
import cn.hutool.extra.ftp.FtpException;
|
||||||
|
import org.apache.ftpserver.ConnectionConfig;
|
||||||
|
import org.apache.ftpserver.FtpServer;
|
||||||
|
import org.apache.ftpserver.FtpServerFactory;
|
||||||
|
import org.apache.ftpserver.ftplet.Authority;
|
||||||
|
import org.apache.ftpserver.ftplet.Ftplet;
|
||||||
|
import org.apache.ftpserver.ftplet.User;
|
||||||
|
import org.apache.ftpserver.ftplet.UserManager;
|
||||||
|
import org.apache.ftpserver.listener.ListenerFactory;
|
||||||
|
import org.apache.ftpserver.ssl.SslConfiguration;
|
||||||
|
import org.apache.ftpserver.ssl.SslConfigurationFactory;
|
||||||
|
import org.apache.ftpserver.usermanager.PropertiesUserManagerFactory;
|
||||||
|
import org.apache.ftpserver.usermanager.impl.BaseUser;
|
||||||
|
import org.apache.ftpserver.usermanager.impl.WritePermission;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author : 芊芊墨客
|
||||||
|
* @version : 1.0
|
||||||
|
* @date : 2023-03-11 15:05
|
||||||
|
*/
|
||||||
|
public class SimpleFtpServer {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 创建FTP服务器,调用{@link SimpleFtpServer#start()}启动即可
|
||||||
|
*
|
||||||
|
* @return SimpleFtpServer
|
||||||
|
*/
|
||||||
|
public static SimpleFtpServer create() {
|
||||||
|
return new SimpleFtpServer();
|
||||||
|
}
|
||||||
|
|
||||||
|
FtpServerFactory serverFactory;
|
||||||
|
ListenerFactory listenerFactory;
|
||||||
|
FtpServer ftpServer;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 构造
|
||||||
|
*/
|
||||||
|
public SimpleFtpServer() {
|
||||||
|
serverFactory = new FtpServerFactory();
|
||||||
|
listenerFactory = new ListenerFactory();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取 {@link FtpServerFactory},用于设置FTP服务器相关信息
|
||||||
|
*
|
||||||
|
* @return {@link FtpServerFactory}
|
||||||
|
*/
|
||||||
|
public FtpServerFactory getServerFactory() {
|
||||||
|
return this.serverFactory;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 设置连接相关配置,使用ConnectionConfigFactory创建{@link ConnectionConfig}对象
|
||||||
|
*
|
||||||
|
* @param connectionConfig 连接配置
|
||||||
|
* @return this
|
||||||
|
*/
|
||||||
|
public SimpleFtpServer setConnectionConfig(ConnectionConfig connectionConfig) {
|
||||||
|
this.serverFactory.setConnectionConfig(connectionConfig);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取{@link ListenerFactory},用于设置端口、用户、SSL等信息
|
||||||
|
*
|
||||||
|
* @return {@link ListenerFactory}
|
||||||
|
*/
|
||||||
|
public ListenerFactory getListenerFactory() {
|
||||||
|
return this.listenerFactory;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 自定义默认端口,如果不设置,使用默认端口:21
|
||||||
|
*
|
||||||
|
* @param port 端口
|
||||||
|
* @return this
|
||||||
|
*/
|
||||||
|
public SimpleFtpServer setPort(int port) {
|
||||||
|
Assert.isTrue(NetUtil.isValidPort(port), "Invalid port!");
|
||||||
|
this.listenerFactory.setPort(port);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取用户管理器,用于新增、查找和删除用户信息
|
||||||
|
*
|
||||||
|
* @return 用户管理器
|
||||||
|
*/
|
||||||
|
public UserManager getUserManager() {
|
||||||
|
return this.serverFactory.getUserManager();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 增加FTP用户
|
||||||
|
*
|
||||||
|
* @param user FTP用户信息
|
||||||
|
* @return this
|
||||||
|
*/
|
||||||
|
public SimpleFtpServer addUser(User user) {
|
||||||
|
try {
|
||||||
|
getUserManager().save(user);
|
||||||
|
} catch (org.apache.ftpserver.ftplet.FtpException e) {
|
||||||
|
throw new FtpException(e);
|
||||||
|
}
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 添加匿名用户
|
||||||
|
*
|
||||||
|
* @param homePath 用户路径,匿名用户对此路径有读写权限
|
||||||
|
* @return this
|
||||||
|
*/
|
||||||
|
public SimpleFtpServer addAnonymous(String homePath) {
|
||||||
|
BaseUser user = new BaseUser();
|
||||||
|
user.setName("anonymous");
|
||||||
|
user.setHomeDirectory(homePath);
|
||||||
|
List<Authority> authorities = new ArrayList<>();
|
||||||
|
// 添加用户读写权限
|
||||||
|
authorities.add(new WritePermission());
|
||||||
|
user.setAuthorities(authorities);
|
||||||
|
return addUser(user);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 删除用户
|
||||||
|
*
|
||||||
|
* @param userName 用户名
|
||||||
|
* @return this
|
||||||
|
*/
|
||||||
|
public SimpleFtpServer delUser(String userName) {
|
||||||
|
try {
|
||||||
|
getUserManager().delete(userName);
|
||||||
|
} catch (org.apache.ftpserver.ftplet.FtpException e) {
|
||||||
|
throw new FtpException(e);
|
||||||
|
}
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 使用SSL安全连接,可以使用SslConfigurationFactory创建{@link SslConfiguration}
|
||||||
|
*
|
||||||
|
* @param ssl {@link SslConfiguration}
|
||||||
|
* @return this
|
||||||
|
*/
|
||||||
|
public SimpleFtpServer setSsl(SslConfiguration ssl) {
|
||||||
|
this.listenerFactory.setSslConfiguration(ssl);
|
||||||
|
listenerFactory.setImplicitSsl(true);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 使用SSL安全连接
|
||||||
|
*
|
||||||
|
* @param keystoreFile 密钥文件
|
||||||
|
* @param password 密钥文件密码
|
||||||
|
* @return this
|
||||||
|
*/
|
||||||
|
public SimpleFtpServer setSsl(File keystoreFile, String password) {
|
||||||
|
SslConfigurationFactory sslFactory = new SslConfigurationFactory();
|
||||||
|
sslFactory.setKeystoreFile(keystoreFile);
|
||||||
|
sslFactory.setKeystorePassword(password);
|
||||||
|
return setSsl(sslFactory.createSslConfiguration());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 自定义用户管理器,一般用于使用配置文件配置用户信息
|
||||||
|
*
|
||||||
|
* @param userManager {@link UserManager}
|
||||||
|
* @return this
|
||||||
|
*/
|
||||||
|
public SimpleFtpServer setUserManager(UserManager userManager) {
|
||||||
|
this.serverFactory.setUserManager(userManager);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 自定义用户信息配置文件,此方法会重置用户管理器
|
||||||
|
*
|
||||||
|
* @param propertiesFile 配置文件
|
||||||
|
* @return this
|
||||||
|
*/
|
||||||
|
public SimpleFtpServer setUsersConfig(File propertiesFile) {
|
||||||
|
final PropertiesUserManagerFactory userManagerFactory = new PropertiesUserManagerFactory();
|
||||||
|
userManagerFactory.setFile(propertiesFile);
|
||||||
|
return this.setUserManager(userManagerFactory.createUserManager());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 增加FTP动作行为监听处理器,通过实现{@link Ftplet},可以对用户的行为监听并执行相应动作
|
||||||
|
*
|
||||||
|
* @param name 名称
|
||||||
|
* @param ftplet {@link Ftplet},用户自定义监听规则
|
||||||
|
* @return this
|
||||||
|
*/
|
||||||
|
public SimpleFtpServer addFtplet(String name, Ftplet ftplet) {
|
||||||
|
this.serverFactory.getFtplets().put(name, ftplet);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 启动FTP服务,阻塞当前线程
|
||||||
|
*/
|
||||||
|
public void start() {
|
||||||
|
// 一个Listener对应一个监听端口
|
||||||
|
// 可以创建多个监听,此处默认只监听一个
|
||||||
|
serverFactory.addListener("default", listenerFactory.createListener());
|
||||||
|
try {
|
||||||
|
ftpServer = serverFactory.createServer();
|
||||||
|
ftpServer.start();
|
||||||
|
} catch (org.apache.ftpserver.ftplet.FtpException e) {
|
||||||
|
throw new FtpException(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void stop() {
|
||||||
|
ftpServer.stop();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -1,6 +1,28 @@
|
||||||
<?xml version="1.0" encoding="UTF-8"?>
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
|
||||||
|
<?import javafx.scene.control.Button?>
|
||||||
|
<?import javafx.scene.control.Label?>
|
||||||
|
<?import javafx.scene.control.ListView?>
|
||||||
|
<?import javafx.scene.control.PasswordField?>
|
||||||
|
<?import javafx.scene.control.TextField?>
|
||||||
<?import javafx.scene.layout.AnchorPane?>
|
<?import javafx.scene.layout.AnchorPane?>
|
||||||
|
<?import javafx.scene.text.Text?>
|
||||||
|
|
||||||
|
<AnchorPane prefHeight="649.0" prefWidth="1200.0" xmlns="http://javafx.com/javafx/19" xmlns:fx="http://javafx.com/fxml/1" fx:controller="com.zhangmeng.tools.controller.FtpServerController">
|
||||||
<AnchorPane fx:controller="com.zhangmeng.tools.controller.FtpServerController" prefHeight="649.0" prefWidth="1200.0" xmlns="http://javafx.com/javafx/19" xmlns:fx="http://javafx.com/fxml/1" />
|
<children>
|
||||||
|
<Label layoutX="78.0" layoutY="98.0" text="用户名:" />
|
||||||
|
<Label layoutX="84.0" layoutY="154.0" text="密码:" />
|
||||||
|
<Button fx:id="server_start" layoutX="443.0" layoutY="400.0" mnemonicParsing="false" text="启动ftp服务" AnchorPane.bottomAnchor="224.0" />
|
||||||
|
<Button fx:id="server_stop" layoutX="614.0" layoutY="400.0" mnemonicParsing="false" text="停止服务" AnchorPane.bottomAnchor="224.0" />
|
||||||
|
<TextField fx:id="user_name" layoutX="131.0" layoutY="94.0" prefHeight="25.0" prefWidth="331.0" />
|
||||||
|
<PasswordField fx:id="password" layoutX="131.0" layoutY="150.0" prefHeight="25.0" prefWidth="331.0" />
|
||||||
|
<ListView fx:id="server_list" layoutX="629.0" layoutY="94.0" prefHeight="224.0" prefWidth="501.0" AnchorPane.bottomAnchor="331.0" AnchorPane.leftAnchor="629.0" AnchorPane.rightAnchor="70.0" AnchorPane.topAnchor="94.0" />
|
||||||
|
<Label layoutX="563.0" layoutY="98.0" text="服务列表:" />
|
||||||
|
<Label layoutX="59.0" layoutY="212.0" text="资源目录:" />
|
||||||
|
<TextField fx:id="resoureces_dir" layoutX="131.0" layoutY="208.0" prefHeight="25.0" prefWidth="331.0" />
|
||||||
|
<Button fx:id="add_user" layoutX="258.0" layoutY="287.0" mnemonicParsing="false" text="添加" />
|
||||||
|
<Label layoutX="82.0" layoutY="404.0" text="服务状态:" AnchorPane.bottomAnchor="228.0" />
|
||||||
|
<Text fx:id="server_status" layoutX="155.0" layoutY="417.0" strokeType="OUTSIDE" strokeWidth="0.0" text="服务状态" AnchorPane.bottomAnchor="228.0" />
|
||||||
|
<Button fx:id="choose_file_dir" layoutX="477.0" layoutY="208.0" mnemonicParsing="false" text="选择文件夹" />
|
||||||
|
</children>
|
||||||
|
</AnchorPane>
|
||||||
|
|
|
||||||
Binary file not shown.
|
After Width: | Height: | Size: 125 KiB |
Loading…
Reference in New Issue