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 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 cookies = new java.util.ArrayList<>(); @Override public void saveFromResponse(HttpUrl url, List cookies) { // 保存服务器返回的Cookie(如JSESSIONID) this.cookies.addAll(cookies); System.out.println("保存Cookie: " + cookies); } @Override public List loadForRequest(HttpUrl url) { // 请求时自动携带Cookie return cookies; } }).build(); } @Override public void stop() throws Exception { if (logger.isDebugEnabled()) { logger.debug("stop"); } CompletableFuture 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 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(); } }