重构所有注解@CacheConfig的Service类,将IEntityService泛型从实体类改为VO类 实现实体与VO之间的转换逻辑,使用VO替代实体进行缓存以避免序列化问题 更新相关依赖组件和测试用例,确保功能完整性和系统兼容性 优化Redis缓存配置,清理旧缓存数据并验证新缓存策略有效性
310 lines
11 KiB
Java
310 lines
11 KiB
Java
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);
|
||
MyProperties myProperties = new MyProperties();
|
||
myProperties.loadFromProperties(properties);
|
||
controller.setProperties(myProperties);
|
||
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();
|
||
}
|
||
} |