Files
contract-manager/client/src/main/java/com/ecep/contract/Desktop.java
songqq a1b87de7c0 feat: 添加日志配置和Logback依赖
refactor: 重构实体类equals和hashCode方法

fix: 修复WebSocketService消息发送逻辑

style: 格式化代码和优化导入

docs: 更新JacksonConfig日期序列化格式

test: 添加CompanyFilePathTableCell测试类

chore: 清理无用代码和注释
2025-09-11 19:44:28 +08:00

308 lines
11 KiB
Java
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

package com.ecep.contract;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.net.URL;
import java.util.List;
import java.util.Properties;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.Executors;
import java.util.concurrent.FutureTask;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import com.ecep.contract.controller.BaseController;
import com.ecep.contract.controller.HomeWindowController;
import com.ecep.contract.controller.OkHttpLoginController;
import com.ecep.contract.task.TaskMonitorCenter;
import com.ecep.contract.util.HibernateProxyUtils;
import com.ecep.contract.util.TextMessageHolder;
import com.ecep.contract.util.UITools;
import com.ecep.contract.vm.CurrentEmployee;
import javafx.application.Application;
import javafx.application.Platform;
import javafx.beans.property.SimpleStringProperty;
import javafx.fxml.FXMLLoader;
import javafx.scene.Node;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.scene.control.ScrollPane;
import javafx.scene.layout.VBox;
import javafx.scene.text.Text;
import javafx.stage.Stage;
import javafx.stage.StageStyle;
import lombok.Getter;
import okhttp3.Cookie;
import okhttp3.CookieJar;
import okhttp3.HttpUrl;
import okhttp3.OkHttpClient;
/**
* JavaFx 应用程序
*
* @author ecep
* Created by ecep on 2017/05/08.
*/
public class Desktop extends Application {
public static final Logger logger = LoggerFactory.getLogger(Desktop.class);
public static Desktop instance;
public static void shutdown() {
if (logger.isDebugEnabled()) {
logger.debug("shutdown");
}
if (instance != null) {
try {
instance.stop();
} catch (Throwable e) {
logger.error("shutdown error", e);
}
}
}
private ScheduledExecutorService scheduledExecutorService = null;
private final TaskMonitorCenter taskMonitorCenter = new TaskMonitorCenter();
private final SimpleStringProperty sessionId = new SimpleStringProperty("");
@Getter
private final CurrentEmployee activeEmployee = new CurrentEmployee();
@Getter
private OkHttpClient httpClient;
public void setActiveEmployeeId(int activeEmployeeId) {
activeEmployee.getId().set(activeEmployeeId);
}
public int getActiveEmployeeId() {
return activeEmployee.getId().get();
}
public String getSessionId() {
return sessionId.get();
}
public void setSessionId(String sessionId) {
this.sessionId.set(sessionId);
}
public ScheduledExecutorService getExecutorService() {
if (scheduledExecutorService == null) {
scheduledExecutorService = Executors.newScheduledThreadPool(3);
}
return scheduledExecutorService;
}
public TaskMonitorCenter getTaskMonitorCenter() {
return taskMonitorCenter;
}
@Override
public void start(Stage primaryStage) throws Exception {
if (logger.isDebugEnabled()) {
logger.debug("start");
}
if (instance != null) {
logger.error("Desktop already started");
}
instance = this;
URL resource = getClass().getResource("/ui/start_lamp.fxml");
FXMLLoader loader = new FXMLLoader(resource);
primaryStage.setTitle("CMS");
primaryStage.initStyle(StageStyle.TRANSPARENT);
Parent root = loader.load();
Scene scene = new Scene(root);
scene.getStylesheets().add("/ui/start_lamp.css");
primaryStage.setScene(scene);
primaryStage.setOnShown(e -> {
System.out.println("primaryStage#OnShown");
});
primaryStage.show();
System.out.println("Desktop.start -> primaryStage.show()");
try {
startSpringApp(primaryStage, root, loader);
} catch (Exception e) {
UITools.showExceptionAndWait("启动失败", e);
}
}
public CompletableFuture<Void> runAsync(Runnable runnable) {
return CompletableFuture.runAsync(runnable, getExecutorService());
}
private void startSpringApp(Stage primaryStage, Parent root, FXMLLoader loader) {
logger.debug("startSpringApp");
// 更新窗口标题
Node titleNode = root.lookup("#title");
if (titleNode != null) {
primaryStage.setTitle(((Text) titleNode).getText());
}
Node lookup = root.lookup("#logBox");
if (!(lookup instanceof VBox logBox)) {
throw new RuntimeException("启动界面加载失败, #logger 类型错误");
}
ScrollPane logPane = (ScrollPane) root.lookup("#logPane");
logBox.getChildren().clear();
TextMessageHolder holder = new TextMessageHolder() {
@Override
public void addTextMessage(Text text) {
Platform.runLater(() -> {
logBox.getChildren().add(text);
logPane.layout();
logPane.setVvalue(1.0);
});
}
};
holder.info("启动中,请稍后...");
runAsync(() -> {
try {
//
holder.info("读取配置文件...");
Properties properties = new Properties();
File configFile = new File("config.properties");
if (configFile.exists()) {
holder.info("读取配置文件 " + configFile.getAbsolutePath() + "...");
try (FileInputStream input = new FileInputStream(configFile)) {
properties.load(input);
holder.info("配置文件读取成功.");
} catch (IOException e) {
holder.error("读取失败:" + e.getMessage());
logger.error(e.getMessage(), e);
return;
}
} else {
logger.warn("配置文件{}不存在", configFile.getAbsolutePath());
}
HibernateProxyUtils.useProxy(false);
runAsync(() -> {
SpringApp.launch(properties, holder);
ConfigurableListableBeanFactory beanFactory = SpringApp.context.getBeanFactory();
beanFactory.registerSingleton("scheduledExecutorService", getExecutorService());
beanFactory.registerSingleton("taskMonitorCenter", taskMonitorCenter);
});
try {
initHttpClient();
OkHttpLoginController controller = new OkHttpLoginController();
controller.setHttpClient(this.httpClient);
controller.setHolder(holder);
controller.setPrimaryStage(primaryStage);
controller.setProperties(properties);
while (true) {
try {
controller.tryLogin().get();
holder.info("登录成功");
try {
while (!SpringApp.isRunning()) {
System.out.println("等待启动");
Thread.sleep(1000);
}
} catch (InterruptedException ex) {
throw new RuntimeException(ex);
}
// 必须要等待启动成功后才能关闭主场景,否则进程结束程序退出
HomeWindowController.show().thenRun(() -> Platform.runLater(primaryStage::close));
break;
} catch (Exception ex) {
holder.error(ex.getMessage());
Thread.sleep(3000);
}
}
} catch (Exception e) {
holder.error("登录失败:" + e.getMessage());
logger.error(e.getMessage(), e);
}
} catch (Exception e) {
holder.error(e.getMessage());
logger.error(e.getMessage(), e);
}
});
System.out.println("Desktop.startSpringApp.");
}
private void initHttpClient() {
this.httpClient = new OkHttpClient().newBuilder().cookieJar(new CookieJar() {
private final List<Cookie> cookies = new java.util.ArrayList<>();
@Override
public void saveFromResponse(HttpUrl url, List<Cookie> cookies) {
// 保存服务器返回的Cookie如JSESSIONID
this.cookies.addAll(cookies);
System.out.println("保存Cookie: " + cookies);
}
@Override
public List<Cookie> loadForRequest(HttpUrl url) {
// 请求时自动携带Cookie
return cookies;
}
}).build();
}
@Override
public void stop() throws Exception {
if (logger.isDebugEnabled()) {
logger.debug("stop");
}
CompletableFuture<Void> future = BaseController.shutdown();
future.orTimeout(5, TimeUnit.SECONDS);
future.exceptionally(e -> {
logger.error(e.getMessage(), e);
return null;
});
future.thenRun(() -> {
SpringApp.shutdown();
try {
shutdownExecutorService();
super.stop();
if (logger.isDebugEnabled()) {
logger.debug("stopped");
}
} catch (Exception e) {
logger.error(e.getMessage(), e);
}
});
}
private void shutdownExecutorService() {
List<Runnable> runnableList = scheduledExecutorService.shutdownNow();
for (Runnable runnable : runnableList) {
if (logger.isDebugEnabled()) {
logger.debug("shutdown runnable = {}", runnable);
}
if (runnable instanceof FutureTask<?> future) {
if (logger.isDebugEnabled()) {
logger.debug("runnable as future, isCancelled() = {}, isDone() = {}", future.isCancelled(),
future.isDone());
}
if (future.cancel(true)) {
if (logger.isDebugEnabled()) {
logger.debug("runnable as future canceled");
}
}
}
}
scheduledExecutorService.close();
}
}