refactor(service): 修改IEntityService泛型为VO类型并优化缓存策略
重构所有注解@CacheConfig的Service类,将IEntityService泛型从实体类改为VO类 实现实体与VO之间的转换逻辑,使用VO替代实体进行缓存以避免序列化问题 更新相关依赖组件和测试用例,确保功能完整性和系统兼容性 优化Redis缓存配置,清理旧缓存数据并验证新缓存策略有效性
This commit is contained in:
@@ -2,11 +2,14 @@ package com.ecep.contract;
|
||||
|
||||
import javafx.application.Application;
|
||||
|
||||
import java.io.File;
|
||||
|
||||
/**
|
||||
* Created by Administrator on 2017/4/16.
|
||||
*/
|
||||
public class ClientV2 {
|
||||
public static void main(String[] args) {
|
||||
System.out.println("当前目录 = " + new File(".").getAbsolutePath());
|
||||
Application.launch(Desktop.class, args);
|
||||
}
|
||||
|
||||
|
||||
@@ -203,7 +203,9 @@ public class Desktop extends Application {
|
||||
controller.setHttpClient(this.httpClient);
|
||||
controller.setHolder(holder);
|
||||
controller.setPrimaryStage(primaryStage);
|
||||
controller.setProperties(properties);
|
||||
MyProperties myProperties = new MyProperties();
|
||||
myProperties.loadFromProperties(properties);
|
||||
controller.setProperties(myProperties);
|
||||
while (true) {
|
||||
try {
|
||||
controller.tryLogin().get();
|
||||
|
||||
@@ -1,22 +1,192 @@
|
||||
package com.ecep.contract;
|
||||
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.FileOutputStream;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.Paths;
|
||||
import java.util.Properties;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.factory.InitializingBean;
|
||||
import org.springframework.stereotype.Component;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
import java.io.File;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.Paths;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
|
||||
/**
|
||||
* 应用程序配置类,用于管理系统配置信息
|
||||
*/
|
||||
@Component
|
||||
@ConfigurationProperties(prefix = "my")
|
||||
public class MyProperties {
|
||||
public class MyProperties implements InitializingBean {
|
||||
private static final Logger logger = LoggerFactory.getLogger(MyProperties.class);
|
||||
private static final String FILE_NAME = "config.properties";
|
||||
|
||||
@Getter
|
||||
@Setter
|
||||
private String downloadsPath;
|
||||
|
||||
@Getter
|
||||
@Setter
|
||||
private String serverHost;
|
||||
|
||||
@Getter
|
||||
@Setter
|
||||
private String serverPort;
|
||||
|
||||
@Getter
|
||||
@Setter
|
||||
private String userName;
|
||||
|
||||
@Getter
|
||||
@Setter
|
||||
private String password;
|
||||
|
||||
@Getter
|
||||
@Setter
|
||||
private boolean rememberPassword;
|
||||
|
||||
@Override
|
||||
public void afterPropertiesSet() throws Exception {
|
||||
// 初始化时加载配置文件
|
||||
try {
|
||||
loadFromFile();
|
||||
} catch (Exception e) {
|
||||
logger.warn("初始化配置文件失败: {}", e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 从文件加载配置
|
||||
*/
|
||||
public void loadFromFile() {
|
||||
File configFile = new File(FILE_NAME);
|
||||
if (!configFile.exists()) {
|
||||
logger.debug("配置文件不存在: {}", configFile.getPath());
|
||||
return;
|
||||
}
|
||||
|
||||
try (FileInputStream input = new FileInputStream(configFile)) {
|
||||
Properties properties = new Properties();
|
||||
properties.load(input);
|
||||
loadFromProperties(properties);
|
||||
logger.debug("成功从配置文件加载配置: {}", configFile.getPath());
|
||||
} catch (Exception e) {
|
||||
logger.error("加载配置文件失败: {}", configFile.getPath(), e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置Properties对象并加载配置
|
||||
* 用于从外部设置配置项
|
||||
*
|
||||
* @param properties 配置对象
|
||||
*/
|
||||
public void setProperties(Properties properties) {
|
||||
this.loadFromProperties(properties);
|
||||
}
|
||||
|
||||
/**
|
||||
* 从Properties对象加载配置
|
||||
* 用于从config.properties文件中读取配置项
|
||||
*
|
||||
* @param properties 配置对象
|
||||
*/
|
||||
public void loadFromProperties(Properties properties) {
|
||||
if (properties == null) {
|
||||
logger.warn("Properties对象为空,无法加载配置");
|
||||
return;
|
||||
}
|
||||
|
||||
// 加载下载路径配置
|
||||
String downloadsPath = properties.getProperty("my.downloadsPath");
|
||||
if (StringUtils.hasText(downloadsPath)) {
|
||||
this.setDownloadsPath(downloadsPath);
|
||||
logger.debug("从配置文件加载下载路径: {}", downloadsPath);
|
||||
}
|
||||
|
||||
// 加载服务器配置
|
||||
String serverHost = properties.getProperty("server.host", "127.0.0.1");
|
||||
if (StringUtils.hasText(serverHost)) {
|
||||
this.setServerHost(serverHost);
|
||||
logger.debug("从配置文件加载服务器地址: {}", serverHost);
|
||||
}
|
||||
|
||||
String serverPort = properties.getProperty("server.port", "8080");
|
||||
if (StringUtils.hasText(serverPort)) {
|
||||
this.setServerPort(serverPort);
|
||||
logger.debug("从配置文件加载服务器端口: {}", serverPort);
|
||||
}
|
||||
|
||||
// 加载用户凭证配置
|
||||
String userName = properties.getProperty("user.name");
|
||||
if (StringUtils.hasText(userName)) {
|
||||
this.setUserName(userName);
|
||||
logger.debug("从配置文件加载用户名");
|
||||
}
|
||||
|
||||
// 只有在记住密码的情况下才加载密码
|
||||
String rememberPasswordStr = properties.getProperty("user.rememberPassword");
|
||||
boolean rememberPassword = "true".equals(rememberPasswordStr);
|
||||
this.setRememberPassword(rememberPassword);
|
||||
|
||||
if (rememberPassword) {
|
||||
String password = properties.getProperty("user.password");
|
||||
if (StringUtils.hasText(password)) {
|
||||
this.setPassword(password);
|
||||
logger.debug("从配置文件加载密码");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 将配置保存到Properties对象
|
||||
* 用于将配置项保存到config.properties文件
|
||||
*
|
||||
* @param properties 配置对象
|
||||
*/
|
||||
public void saveToProperties(Properties properties) {
|
||||
if (properties == null) {
|
||||
logger.warn("Properties对象为空,无法保存配置");
|
||||
return;
|
||||
}
|
||||
|
||||
// 保存下载路径配置
|
||||
if (StringUtils.hasText(getDownloadsPath())) {
|
||||
properties.setProperty("my.downloadsPath", getDownloadsPath());
|
||||
logger.debug("保存下载路径到配置文件: {}", getDownloadsPath());
|
||||
}
|
||||
|
||||
// 保存服务器配置
|
||||
if (StringUtils.hasText(getServerHost())) {
|
||||
properties.setProperty("server.host", getServerHost());
|
||||
logger.debug("保存服务器地址到配置文件: {}", getServerHost());
|
||||
}
|
||||
|
||||
if (StringUtils.hasText(getServerPort())) {
|
||||
properties.setProperty("server.port", getServerPort());
|
||||
logger.debug("保存服务器端口到配置文件: {}", getServerPort());
|
||||
}
|
||||
|
||||
// 保存用户凭证配置
|
||||
if (StringUtils.hasText(getUserName())) {
|
||||
properties.setProperty("user.name", getUserName());
|
||||
logger.debug("保存用户名为配置文件");
|
||||
}
|
||||
|
||||
properties.setProperty("user.rememberPassword", String.valueOf(isRememberPassword()));
|
||||
|
||||
// 只有在记住密码的情况下才保存密码
|
||||
if (isRememberPassword() && StringUtils.hasText(getPassword())) {
|
||||
properties.setProperty("user.password", getPassword());
|
||||
logger.debug("保存密码到配置文件");
|
||||
} else if (properties.containsKey("user.password")) {
|
||||
// 如果不记住密码,删除已存在的密码配置
|
||||
properties.remove("user.password");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 尝试返回当前用户的下载文件夹
|
||||
@@ -24,7 +194,13 @@ public class MyProperties {
|
||||
public File getDownloadDirectory() {
|
||||
String downloadsPath = getDownloadsPath();
|
||||
if (StringUtils.hasText(downloadsPath)) {
|
||||
return new File(downloadsPath);
|
||||
// 确保目录存在
|
||||
File dir = new File(downloadsPath);
|
||||
if (!dir.exists()) {
|
||||
boolean created = dir.mkdirs();
|
||||
logger.debug("创建下载目录: {}, 结果: {}", downloadsPath, created);
|
||||
}
|
||||
return dir;
|
||||
}
|
||||
|
||||
// 没有配置下载目录时,尝试使用默认设置
|
||||
@@ -32,4 +208,29 @@ public class MyProperties {
|
||||
Path path = Paths.get(home, "Downloads");
|
||||
return path.toFile();
|
||||
}
|
||||
|
||||
/**
|
||||
* 保存配置到文件
|
||||
*/
|
||||
public void save() {
|
||||
File configFile = new File(FILE_NAME);
|
||||
try (FileOutputStream output = new FileOutputStream(configFile)) {
|
||||
Properties properties = new Properties();
|
||||
|
||||
// 如果文件已存在,先读取现有配置,避免覆盖其他配置
|
||||
if (configFile.exists()) {
|
||||
try (FileInputStream input = new FileInputStream(configFile)) {
|
||||
properties.load(input);
|
||||
}
|
||||
}
|
||||
|
||||
// 保存当前配置
|
||||
saveToProperties(properties);
|
||||
properties.store(output, "Contract Manager 应用程序配置");
|
||||
logger.debug("成功保存配置到文件: {}", configFile.getPath());
|
||||
} catch (Exception e) {
|
||||
logger.error("保存配置到文件失败: {}", configFile.getPath(), e);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -98,6 +98,17 @@ public class SpringApp {
|
||||
context = application.run();
|
||||
logger.debug("SpringApp.launch application.run().");
|
||||
Duration between = Duration.between(startup.getBufferedTimeline().getStartTime(), Instant.now());
|
||||
|
||||
// 初始化MyProperties,从properties加载配置
|
||||
try {
|
||||
MyProperties myProperties = context.getBean(MyProperties.class);
|
||||
myProperties.loadFromProperties(properties);
|
||||
holder.info("MyProperties配置加载完成");
|
||||
} catch (Exception e) {
|
||||
logger.error("加载MyProperties配置失败", e);
|
||||
holder.error("加载MyProperties配置失败: " + e.getMessage());
|
||||
}
|
||||
|
||||
holder.info("应用程序环境加载完成... " + between);
|
||||
});
|
||||
CompletableFuture.runAsync(() -> {
|
||||
|
||||
@@ -118,10 +118,24 @@ public class WebSocketClientService {
|
||||
String errorMsg = node.get(WebSocketConstant.MESSAGE_FIELD_NAME).asText();
|
||||
logger.error("收到错误消息: 错误码={}, 错误信息={}", errorCode, errorMsg);
|
||||
if (errorCode == WebSocketConstant.ERROR_CODE_UNAUTHORIZED) {
|
||||
|
||||
// 调用所有的 callbacks 和 session 失败并且移除
|
||||
callbacks.keySet().stream().toList().forEach(key -> callbacks.remove(key).completeExceptionally(new Exception("未授权")));
|
||||
sessions.values().stream().toList().forEach(session -> {
|
||||
session.updateMessage(java.util.logging.Level.SEVERE, "未授权");
|
||||
session.close();
|
||||
});
|
||||
isActive = false;
|
||||
webSocket.close(1000, "");
|
||||
WebSocketClientService.this.webSocket = null;
|
||||
|
||||
// 处理未授权错误,重新登录
|
||||
OkHttpLoginController controller = new OkHttpLoginController();
|
||||
controller.setProperties(SpringApp.getBean(MyProperties.class));
|
||||
controller.tryLogin();
|
||||
// 需要把窗口顶置
|
||||
isActive = true;
|
||||
scheduleReconnect();
|
||||
}
|
||||
return;
|
||||
}
|
||||
@@ -164,8 +178,8 @@ public class WebSocketClientService {
|
||||
};
|
||||
|
||||
private void onCallbackMessage(CompletableFuture<JsonNode> future, JsonNode node) {
|
||||
if (node.has(WebSocketConstant.SUCCESS_FIELD_VALUE)) {
|
||||
if (!node.get(WebSocketConstant.SUCCESS_FIELD_VALUE).asBoolean()) {
|
||||
if (node.has(WebSocketConstant.SUCCESS_FIELD_NAME)) {
|
||||
if (!node.get(WebSocketConstant.SUCCESS_FIELD_NAME).asBoolean()) {
|
||||
future.completeExceptionally(
|
||||
new RuntimeException(
|
||||
"请求失败:来自服务器的消息=" + node.get(WebSocketConstant.MESSAGE_FIELD_NAME).asText()));
|
||||
@@ -204,7 +218,7 @@ public class WebSocketClientService {
|
||||
String json = objectMapper.writeValueAsString(msg);
|
||||
callbacks.put(msg.getMessageId(), future);
|
||||
if (webSocket.send(json)) {
|
||||
logger.debug("send message success:{}", json);
|
||||
logger.debug("send json success:{}", json);
|
||||
} else {
|
||||
if (isActive) {
|
||||
future.completeExceptionally(new RuntimeException("Failed to send WebSocket message"));
|
||||
|
||||
@@ -116,6 +116,7 @@ public class HomeWindowController extends BaseController {
|
||||
|
||||
@EventListener
|
||||
public void onCurrentEmployeeInitialed(CurrentEmployeeInitialedEvent event) {
|
||||
System.out.println("event = " + event);
|
||||
CurrentEmployee currentEmployee = event.getEmployee();
|
||||
if (currentEmployee.isSystemAdministrator()) {
|
||||
if (logger.isInfoEnabled()) {
|
||||
|
||||
@@ -1,544 +0,0 @@
|
||||
package com.ecep.contract.controller;
|
||||
|
||||
import java.io.FileOutputStream;
|
||||
import java.net.Inet4Address;
|
||||
import java.net.InetAddress;
|
||||
import java.net.NetworkInterface;
|
||||
import java.net.SocketException;
|
||||
import java.sql.Connection;
|
||||
import java.sql.PreparedStatement;
|
||||
import java.sql.ResultSet;
|
||||
import java.sql.SQLException;
|
||||
import java.sql.Statement;
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Enumeration;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.NoSuchElementException;
|
||||
import java.util.Objects;
|
||||
import java.util.Properties;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.logging.Level;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
import com.ecep.contract.Desktop;
|
||||
import com.ecep.contract.MessageHolder;
|
||||
import com.ecep.contract.SpringApp;
|
||||
|
||||
import javafx.application.Platform;
|
||||
import javafx.beans.property.SimpleBooleanProperty;
|
||||
import javafx.beans.property.SimpleStringProperty;
|
||||
import javafx.event.EventHandler;
|
||||
import javafx.geometry.Insets;
|
||||
import javafx.scene.Scene;
|
||||
import javafx.scene.control.Button;
|
||||
import javafx.scene.control.CheckBox;
|
||||
import javafx.scene.control.Label;
|
||||
import javafx.scene.control.ListView;
|
||||
import javafx.scene.control.PasswordField;
|
||||
import javafx.scene.control.TextField;
|
||||
import javafx.scene.input.MouseEvent;
|
||||
import javafx.scene.layout.BorderPane;
|
||||
import javafx.scene.layout.GridPane;
|
||||
import javafx.stage.Stage;
|
||||
import lombok.Setter;
|
||||
|
||||
public class LoginWidowController implements MessageHolder {
|
||||
private static final Logger logger = LoggerFactory.getLogger(LoginWidowController.class);
|
||||
@Setter
|
||||
MessageHolder holder;
|
||||
@Setter
|
||||
Stage primaryStage;
|
||||
@Setter
|
||||
Properties properties;
|
||||
|
||||
@Override
|
||||
public void addMessage(Level level, String message) {
|
||||
holder.addMessage(level, message);
|
||||
}
|
||||
|
||||
private void storeProperties() {
|
||||
try (FileOutputStream fos = new FileOutputStream("config.properties")) {
|
||||
// 保存到文件
|
||||
properties.store(fos, "Updated config.properties");
|
||||
info("配置文件已更新!");
|
||||
} catch (java.io.IOException e) {
|
||||
error("保存配置文件失败:" + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
String getHost() {
|
||||
return properties.getProperty("server.host");
|
||||
}
|
||||
|
||||
public void tryLogin() {
|
||||
// CompletableFuture<ButtonType> future = new CompletableFuture<>();
|
||||
// 检查配置文件中是否保存用户名和密码
|
||||
String userName = getUserName();
|
||||
if (StringUtils.hasText(userName)) {
|
||||
try {
|
||||
EmployeeInfo employeeInfo = tryToConnect(userName, getPassword());
|
||||
if (employeeInfo.errorCode < 0) {
|
||||
error("登录失败:错误代码=" + employeeInfo.errorCode);
|
||||
} else {
|
||||
logined(employeeInfo);
|
||||
}
|
||||
} catch (SQLException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
} else {
|
||||
showUserNameLoginDialog(null);
|
||||
}
|
||||
}
|
||||
|
||||
private String getPassword() {
|
||||
// TODO Auto-generated method stub
|
||||
throw new UnsupportedOperationException("Unimplemented method 'getPassword'");
|
||||
}
|
||||
|
||||
private String getUserName() {
|
||||
// TODO Auto-generated method stub
|
||||
throw new UnsupportedOperationException("Unimplemented method 'getUserName'");
|
||||
}
|
||||
|
||||
CompletableFuture<List<LoginWidowController.MacIP>> getMacAndIP() {
|
||||
return CompletableFuture.supplyAsync(() -> {
|
||||
// mac ip
|
||||
List<LoginWidowController.MacIP> list = new ArrayList<>();
|
||||
try {
|
||||
Enumeration<NetworkInterface> interfaces = NetworkInterface.getNetworkInterfaces();
|
||||
while (interfaces.hasMoreElements()) {
|
||||
NetworkInterface anInterface = interfaces.nextElement();
|
||||
if (anInterface.isLoopback()) {
|
||||
continue;
|
||||
}
|
||||
byte[] hardwareAddress = anInterface.getHardwareAddress();
|
||||
if (hardwareAddress == null) {
|
||||
continue;
|
||||
}
|
||||
Enumeration<InetAddress> inetAddresses = anInterface.getInetAddresses();
|
||||
if (!inetAddresses.hasMoreElements()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// -分割16进制表示法
|
||||
StringBuilder sb = new StringBuilder();
|
||||
for (int i = 0; i < hardwareAddress.length; i++) {
|
||||
sb.append(
|
||||
String.format("%02X%s", hardwareAddress[i], i < hardwareAddress.length - 1 ? "-" : ""));
|
||||
}
|
||||
|
||||
while (inetAddresses.hasMoreElements()) {
|
||||
InetAddress inetAddress = inetAddresses.nextElement();
|
||||
if (inetAddress instanceof Inet4Address) {
|
||||
list.add(new LoginWidowController.MacIP(sb.toString(), inetAddress.getHostAddress()));
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (SocketException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
return list;
|
||||
});
|
||||
}
|
||||
|
||||
private EmployeeInfo tryToConnect(String userName, String password) throws SQLException {
|
||||
String host = getHost();
|
||||
String port = getPort();
|
||||
String database = getDatabase();
|
||||
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("try to connect db server host:{},port:{},database:{},user:{},pwd:{}", host, port, database,
|
||||
userName, "*");
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private String getDatabase() {
|
||||
// TODO Auto-generated method stub
|
||||
throw new UnsupportedOperationException("Unimplemented method 'getDatabase'");
|
||||
}
|
||||
|
||||
private String getPort() {
|
||||
// TODO Auto-generated method stub
|
||||
throw new UnsupportedOperationException("Unimplemented method 'getPort'");
|
||||
}
|
||||
|
||||
private void createSession(Connection connection, EmployeeInfo employeeInfo) {
|
||||
employeeInfo.sessionId = addHistory(connection, employeeInfo.employeeId, employeeInfo.binds.getFirst());
|
||||
}
|
||||
|
||||
private int addHistory(Connection connection, int employeeId, MacIP macIP) {
|
||||
try {
|
||||
String sql = "INSERT INTO EMPLOYEE_LOGIN_HISTORY (IP, MAC, DT, EMPLOYEE_ID) VALUES (?, ?, ?, ?)";
|
||||
try (PreparedStatement ps = connection.prepareStatement(sql, Statement.RETURN_GENERATED_KEYS)) {
|
||||
ps.setString(1, macIP.ip);
|
||||
ps.setString(2, macIP.mac);
|
||||
ps.setObject(3, LocalDateTime.now()); // 根据数据库字段类型调整
|
||||
ps.setInt(4, employeeId);
|
||||
ps.executeUpdate();
|
||||
// 返回 新的主键值
|
||||
ResultSet generatedKeys = ps.getGeneratedKeys();
|
||||
if (generatedKeys.next()) {
|
||||
return generatedKeys.getInt(1);
|
||||
}
|
||||
}
|
||||
} catch (SQLException e) {
|
||||
holder.error("申请新会话编号失败");
|
||||
logger.error("unable insert EMPLOYEE_LOGIN_HISTORY, ", e);
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
static class MacIP {
|
||||
String ip;
|
||||
String mac;
|
||||
|
||||
public MacIP(String mac, String ip) {
|
||||
this.mac = mac;
|
||||
this.ip = ip;
|
||||
}
|
||||
}
|
||||
|
||||
static class EmployeeInfo {
|
||||
Integer employeeId;
|
||||
List<MacIP> binds = new ArrayList<>();
|
||||
SimpleStringProperty name = new SimpleStringProperty();
|
||||
SimpleBooleanProperty active = new SimpleBooleanProperty();
|
||||
int sessionId;
|
||||
int errorCode = 0;
|
||||
|
||||
public EmployeeInfo(Integer employeeId) {
|
||||
this.employeeId = employeeId;
|
||||
}
|
||||
|
||||
public static EmployeeInfo error(int code) {
|
||||
EmployeeInfo employeeInfo = new EmployeeInfo(null);
|
||||
employeeInfo.errorCode = code;
|
||||
return employeeInfo;
|
||||
}
|
||||
|
||||
public void addBind(MacIP macIP) {
|
||||
binds.add(macIP);
|
||||
}
|
||||
}
|
||||
|
||||
private CompletableFuture<EmployeeInfo> tryLoginWithEmployeeBind(Connection connection,
|
||||
CompletableFuture<List<MacIP>> macAndIP) {
|
||||
CompletableFuture<EmployeeInfo> future = new CompletableFuture<>();
|
||||
macAndIP.thenAccept(macIPS -> {
|
||||
if (macIPS.isEmpty()) {
|
||||
future.complete(EmployeeInfo.error(-1));
|
||||
return;
|
||||
}
|
||||
|
||||
HashMap<Integer, EmployeeInfo> employeeMap = new HashMap<>();
|
||||
for (MacIP macIP : macIPS) {
|
||||
for (Integer employeeId : findAllBindEmployee(connection, macIP)) {
|
||||
employeeMap.computeIfAbsent(employeeId, k -> new EmployeeInfo(employeeId)).addBind(macIP);
|
||||
}
|
||||
}
|
||||
|
||||
if (employeeMap.isEmpty()) {
|
||||
error("本机未绑定登录信息,请联系管理员更新.");
|
||||
// 当前计算机的信息,如用户名,计算机名等
|
||||
String username = System.getProperty("user.name");
|
||||
String computerName = System.getenv("COMPUTERNAME");
|
||||
for (MacIP macIP : macIPS) {
|
||||
if (macIP.ip.equals("127.0.0.1")) {
|
||||
continue;
|
||||
}
|
||||
registerComputer(username, computerName, connection, macIP);
|
||||
}
|
||||
future.complete(EmployeeInfo.error(-2));
|
||||
return;
|
||||
}
|
||||
|
||||
if (employeeMap.size() == 1) {
|
||||
// 直接登录
|
||||
EmployeeInfo employeeInfo = employeeMap.values().stream().findFirst().get();
|
||||
// issue #1 登录成功后没有更新员工信息
|
||||
fill(connection, employeeInfo);
|
||||
future.complete(employeeInfo);
|
||||
} else {
|
||||
List<EmployeeInfo> list = employeeMap.values().stream().toList();
|
||||
// 选择登录
|
||||
Platform.runLater(() -> {
|
||||
EmployeeInfo info = showEmployeeSelectDialog(list);
|
||||
future.complete(Objects.requireNonNullElseGet(info, () -> EmployeeInfo.error(-3)));
|
||||
});
|
||||
for (EmployeeInfo info : list) {
|
||||
fill(connection, info);
|
||||
}
|
||||
}
|
||||
});
|
||||
return future;
|
||||
}
|
||||
|
||||
private EmployeeInfo showEmployeeSelectDialog(List<EmployeeInfo> list) {
|
||||
Stage stage = new Stage();
|
||||
stage.initOwner(primaryStage);
|
||||
stage.setTitle("请选择账户登录系统");
|
||||
stage.setWidth(360);
|
||||
stage.setHeight(280);
|
||||
|
||||
Label label = new Label("您的主机关联了以下账户,请选择一个登录");
|
||||
label.setPadding(new Insets(10, 0, 10, 10));
|
||||
ListView<Label> listView = new ListView<>();
|
||||
|
||||
EventHandler<MouseEvent> eventHandler = event -> {
|
||||
if (event.getClickCount() == 2) {
|
||||
// listView.getSelectionModel().select(cb);
|
||||
stage.close();
|
||||
}
|
||||
};
|
||||
for (EmployeeInfo employeeInfo : list) {
|
||||
Label cb = new Label();
|
||||
cb.setUserData(employeeInfo);
|
||||
cb.textProperty().bind(employeeInfo.name);
|
||||
cb.setPadding(new Insets(5));
|
||||
cb.setOnMouseClicked(eventHandler);
|
||||
listView.getItems().add(cb);
|
||||
}
|
||||
|
||||
// 创建 BorderPane 并设置边距
|
||||
BorderPane borderPane = new BorderPane();
|
||||
borderPane.setPadding(new Insets(10));
|
||||
borderPane.setTop(label);
|
||||
borderPane.setCenter(listView);
|
||||
|
||||
Button bottom = new Button("确定");
|
||||
bottom.setDefaultButton(true);
|
||||
bottom.setOnAction(event -> {
|
||||
Label selectedItem = listView.getSelectionModel().getSelectedItem();
|
||||
if (selectedItem == null) {
|
||||
// 没选中,退出继续选择
|
||||
return;
|
||||
}
|
||||
stage.close();
|
||||
});
|
||||
BorderPane.setAlignment(bottom, javafx.geometry.Pos.CENTER);
|
||||
|
||||
borderPane.setBottom(bottom);
|
||||
stage.setScene(new Scene(borderPane));
|
||||
stage.setOnCloseRequest(event -> {
|
||||
Label selectedItem = listView.getSelectionModel().getSelectedItem();
|
||||
if (selectedItem == null) {
|
||||
// 关闭时,如何没有做选择,不关闭窗口
|
||||
event.consume();
|
||||
}
|
||||
});
|
||||
|
||||
stage.showAndWait();
|
||||
|
||||
Label selectedItem = listView.getSelectionModel().getSelectedItem();
|
||||
if (selectedItem == null) {
|
||||
throw new NoSuchElementException("请选择工号登录系统");
|
||||
}
|
||||
|
||||
return (EmployeeInfo) selectedItem.getUserData();
|
||||
}
|
||||
|
||||
private void fill(Connection connection, EmployeeInfo info) {
|
||||
try {
|
||||
ResultSet rs = connection.createStatement()
|
||||
.executeQuery("SELECT * FROM EMPLOYEE where ID = " + info.employeeId);
|
||||
if (rs.next()) {
|
||||
String name = rs.getString("NAME");
|
||||
boolean isActive = rs.getBoolean("IS_ACTIVE");
|
||||
Platform.runLater(() -> {
|
||||
info.name.set(name);
|
||||
info.active.set(isActive);
|
||||
});
|
||||
}
|
||||
} catch (SQLException e) {
|
||||
logger.error("查询{}失败", info.employeeId, e);
|
||||
}
|
||||
}
|
||||
|
||||
private void registerComputer(String username, String computerName, Connection connection, MacIP macIP) {
|
||||
info("正在注册本机信息(MAC:" + macIP.mac + ", IP:" + macIP.ip + ")...");
|
||||
String sql = "INSERT INTO EMPLOYEE_AUTH_BIND (IP,MAC,DESCRIPTION)VALUES(?,?,?)";
|
||||
try (PreparedStatement stmt = connection.prepareStatement(sql)) {
|
||||
stmt.setString(1, macIP.ip);
|
||||
stmt.setString(2, macIP.mac);
|
||||
// 当前计算机的信息,如用户名,计算机名等
|
||||
stmt.setString(3, username + "," + computerName);
|
||||
if (stmt.execute()) {
|
||||
info("注册成功");
|
||||
}
|
||||
} catch (SQLException e) {
|
||||
error(String.format("注册失败,请联系管理员或重启应用!MAC: %s, IP: %s", macIP.mac, macIP.ip));
|
||||
logger.error("注册失败 mac:{}, ip:{}", macIP.mac, macIP.ip, e);
|
||||
}
|
||||
}
|
||||
|
||||
List<Integer> findAllBindEmployee(Connection connection, MacIP macIP) {
|
||||
List<Integer> list = new ArrayList<>();
|
||||
// 优化后代码
|
||||
String sql = "SELECT * FROM EMPLOYEE_AUTH_BIND WHERE IP = ? AND MAC = ?";
|
||||
try (PreparedStatement stmt = connection.prepareStatement(sql)) {
|
||||
stmt.setString(1, macIP.ip);
|
||||
stmt.setString(2, macIP.mac);
|
||||
try (ResultSet rs = stmt.executeQuery()) {
|
||||
while (rs.next()) {
|
||||
int id = rs.getInt("EMPLOYEE_ID");
|
||||
if (id > 0) {
|
||||
list.add(id);
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (SQLException e) {
|
||||
throw new RuntimeException(
|
||||
String.format("查询本机绑定信息异常,请联系管理员或重启应用!MAC: %s, IP: %s", macIP.mac, macIP.ip),
|
||||
e);
|
||||
}
|
||||
return list;
|
||||
}
|
||||
|
||||
private void showUserNameLoginDialog(Exception exception) {
|
||||
Stage stage = new Stage();
|
||||
stage.initOwner(primaryStage);
|
||||
stage.setTitle("登录");
|
||||
|
||||
// 创建 BorderPane 并设置边距
|
||||
BorderPane borderPane = new BorderPane();
|
||||
borderPane.setPadding(new Insets(10));
|
||||
|
||||
// 创建布局
|
||||
GridPane grid = new GridPane();
|
||||
grid.setHgap(10);
|
||||
grid.setVgap(10);
|
||||
// 为整个 GridPane 设置外边距
|
||||
// GridPane.setMargin(grid, new Insets(10));
|
||||
|
||||
// 账户输入框
|
||||
Label userLabel = new Label("账户:");
|
||||
TextField userField = new TextField();
|
||||
{
|
||||
String username = getUserName();
|
||||
if (StringUtils.hasText(username)) {
|
||||
userField.setText(username);
|
||||
}
|
||||
grid.add(userLabel, 0, 0);
|
||||
grid.add(userField, 1, 0);
|
||||
}
|
||||
|
||||
// 密码输入框
|
||||
Label passwordLabel = new Label("密码:");
|
||||
PasswordField passwordField = new PasswordField();
|
||||
{
|
||||
String password = getPassword();
|
||||
if (StringUtils.hasText(password)) {
|
||||
passwordField.setText(password);
|
||||
}
|
||||
grid.add(passwordLabel, 0, 1);
|
||||
grid.add(passwordField, 1, 1);
|
||||
}
|
||||
|
||||
// 记住密码复选框
|
||||
CheckBox rememberCheckBox = new CheckBox("记住账户密码");
|
||||
{
|
||||
String property = properties.getProperty("username_password.remember", "false");
|
||||
if (Boolean.parseBoolean(property)) {
|
||||
rememberCheckBox.setSelected(true);
|
||||
}
|
||||
}
|
||||
grid.add(rememberCheckBox, 1, 2);
|
||||
|
||||
// 错误消息提示
|
||||
Label exceptionLabel = new Label();
|
||||
grid.add(exceptionLabel, 0, 3);
|
||||
exceptionLabel.setWrapText(true);
|
||||
GridPane.setColumnSpan(exceptionLabel, 2);
|
||||
if (exception == null) {
|
||||
exceptionLabel.setVisible(false);
|
||||
} else {
|
||||
exceptionLabel.setText(exception.getMessage());
|
||||
exceptionLabel.setVisible(true);
|
||||
}
|
||||
|
||||
borderPane.setCenter(grid);
|
||||
|
||||
// 登录按钮
|
||||
Button loginButton = new Button("登录");
|
||||
loginButton.setDefaultButton(true);
|
||||
borderPane.setBottom(loginButton);
|
||||
BorderPane.setAlignment(loginButton, javafx.geometry.Pos.CENTER);
|
||||
|
||||
// 登录按钮点击事件
|
||||
loginButton.setOnAction(event -> {
|
||||
String username = userField.getText();
|
||||
String password = passwordField.getText();
|
||||
boolean remember = rememberCheckBox.isSelected();
|
||||
|
||||
// 尝试连接数据库
|
||||
exceptionLabel.setText("");
|
||||
exceptionLabel.setVisible(false);
|
||||
try {
|
||||
EmployeeInfo employeeInfo = tryToConnect(username, password);
|
||||
if (employeeInfo.errorCode < 0) {
|
||||
exceptionLabel.setText("登录失败:错误代码=" + employeeInfo.errorCode);
|
||||
exceptionLabel.setVisible(true);
|
||||
} else {
|
||||
logined(employeeInfo);
|
||||
}
|
||||
} catch (SQLException ex) {
|
||||
//
|
||||
exceptionLabel.setText("数据库错误:" + ex.getMessage());
|
||||
exceptionLabel.setVisible(true);
|
||||
return;
|
||||
}
|
||||
|
||||
properties.setProperty("db.server.username", username);
|
||||
properties.setProperty("db.server.password", password);
|
||||
properties.setProperty("username_password.remember", Boolean.toString(remember));
|
||||
|
||||
// 如果勾选了“记住密码”,则更新配置文件
|
||||
if (remember) {
|
||||
CompletableFuture.runAsync(() -> {
|
||||
storeProperties();
|
||||
});
|
||||
}
|
||||
|
||||
// 关闭登录窗口
|
||||
stage.close();
|
||||
});
|
||||
|
||||
// 创建场景并设置到窗口
|
||||
Scene scene = new Scene(borderPane, 400, 260);
|
||||
stage.setScene(scene);
|
||||
// stage.setAlwaysOnTop(true);
|
||||
stage.setResizable(false);
|
||||
stage.showAndWait();
|
||||
}
|
||||
|
||||
private void logined(EmployeeInfo employeeInfo) {
|
||||
info("欢迎 " + employeeInfo.name.get());
|
||||
if (!SpringApp.isRunning()) {
|
||||
info("请稍后...");
|
||||
}
|
||||
Desktop.instance.setActiveEmployeeId(employeeInfo.employeeId);
|
||||
// Desktop.instance.setSessionId(employeeInfo.sessionId);
|
||||
tryShowHomeWindow();
|
||||
}
|
||||
|
||||
void tryShowHomeWindow() {
|
||||
try {
|
||||
while (!SpringApp.isRunning()) {
|
||||
System.out.println("等待启动");
|
||||
Thread.sleep(1000);
|
||||
}
|
||||
} catch (InterruptedException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
|
||||
// 必须要等待启动成功后才能关闭主场景,否则进程结束程序退出
|
||||
HomeWindowController.show().thenRun(() -> Platform.runLater(primaryStage::close));
|
||||
}
|
||||
}
|
||||
@@ -11,12 +11,14 @@ import java.util.Properties;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.logging.Level;
|
||||
|
||||
import javafx.beans.property.SimpleStringProperty;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
import com.ecep.contract.Desktop;
|
||||
import com.ecep.contract.MessageHolder;
|
||||
import com.ecep.contract.MyProperties;
|
||||
import com.ecep.contract.SpringApp;
|
||||
import com.fasterxml.jackson.databind.JsonNode;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
@@ -56,11 +58,11 @@ public class OkHttpLoginController implements MessageHolder {
|
||||
@Setter
|
||||
private Stage primaryStage;
|
||||
@Setter
|
||||
private Properties properties;
|
||||
private MyProperties properties;
|
||||
@Setter
|
||||
private OkHttpClient httpClient;
|
||||
private WebSocket webSocket;
|
||||
private String serverUrl;
|
||||
private SimpleStringProperty serverUrl = new SimpleStringProperty();
|
||||
private String webSocketUrl;
|
||||
|
||||
public OkHttpLoginController() {
|
||||
@@ -91,9 +93,9 @@ public class OkHttpLoginController implements MessageHolder {
|
||||
}
|
||||
|
||||
private void initServerUrls() {
|
||||
String host = properties.getProperty("server.host", "localhost");
|
||||
String port = properties.getProperty("server.port", "8080");
|
||||
this.serverUrl = "http://" + host + ":" + port;
|
||||
String host = properties.getServerHost();
|
||||
String port = properties.getServerPort();
|
||||
serverUrl.set("http://" + host + ":" + port);
|
||||
this.webSocketUrl = "ws://" + host + ":" + port + "/ws";
|
||||
}
|
||||
|
||||
@@ -117,11 +119,11 @@ public class OkHttpLoginController implements MessageHolder {
|
||||
}
|
||||
|
||||
private String getUserName() {
|
||||
return properties.getProperty("user.name", "");
|
||||
return properties.getUserName();
|
||||
}
|
||||
|
||||
private String getPassword() {
|
||||
return properties.getProperty("user.password", "");
|
||||
return properties.getPassword();
|
||||
}
|
||||
|
||||
private void showLoginDialog() {
|
||||
@@ -138,6 +140,14 @@ public class OkHttpLoginController implements MessageHolder {
|
||||
grid.setHgap(10);
|
||||
grid.setVgap(15);
|
||||
|
||||
Label hostLabel = new Label("服务器:");
|
||||
TextField hostField = new TextField();
|
||||
{
|
||||
hostField.textProperty().bindBidirectional(serverUrl);
|
||||
grid.add(hostLabel, 0, 0);
|
||||
grid.add(hostField, 1, 0);
|
||||
}
|
||||
|
||||
// 账户输入框
|
||||
Label userLabel = new Label("用户名:");
|
||||
TextField userField = new TextField();
|
||||
@@ -146,8 +156,8 @@ public class OkHttpLoginController implements MessageHolder {
|
||||
if (StringUtils.hasText(username)) {
|
||||
userField.setText(username);
|
||||
}
|
||||
grid.add(userLabel, 0, 0);
|
||||
grid.add(userField, 1, 0);
|
||||
grid.add(userLabel, 0, 1);
|
||||
grid.add(userField, 1, 1);
|
||||
}
|
||||
|
||||
// 密码输入框
|
||||
@@ -158,25 +168,25 @@ public class OkHttpLoginController implements MessageHolder {
|
||||
if (StringUtils.hasText(password)) {
|
||||
passwordField.setText(password);
|
||||
}
|
||||
grid.add(passwordLabel, 0, 1);
|
||||
grid.add(passwordField, 1, 1);
|
||||
grid.add(passwordLabel, 0, 2);
|
||||
grid.add(passwordField, 1, 2);
|
||||
}
|
||||
|
||||
// 记住密码复选框
|
||||
CheckBox rememberCheckBox = new CheckBox("记住密码");
|
||||
{
|
||||
String property = properties.getProperty("remember.password", "false");
|
||||
if (Boolean.parseBoolean(property)) {
|
||||
boolean remember = properties.isRememberPassword();
|
||||
if (remember) {
|
||||
rememberCheckBox.setSelected(true);
|
||||
}
|
||||
}
|
||||
grid.add(rememberCheckBox, 1, 2);
|
||||
grid.add(rememberCheckBox, 1, 3);
|
||||
|
||||
// 错误消息提示
|
||||
Label errorLabel = new Label();
|
||||
errorLabel.setStyle("-fx-text-fill: red;");
|
||||
errorLabel.setVisible(false);
|
||||
grid.add(errorLabel, 0, 3);
|
||||
grid.add(errorLabel, 0, 4);
|
||||
GridPane.setColumnSpan(errorLabel, 2);
|
||||
|
||||
borderPane.setCenter(grid);
|
||||
@@ -204,14 +214,16 @@ public class OkHttpLoginController implements MessageHolder {
|
||||
errorLabel.setVisible(false);
|
||||
|
||||
// 保存配置
|
||||
properties.setProperty("user.name", username);
|
||||
if (remember) {
|
||||
properties.setProperty("user.password", password);
|
||||
properties.setProperty("remember.password", "true");
|
||||
properties.setUserName(username);
|
||||
properties.setPassword(password);
|
||||
properties.setRememberPassword(true);
|
||||
} else {
|
||||
properties.setProperty("user.password", "");
|
||||
properties.setProperty("remember.password", "false");
|
||||
properties.setUserName(username);
|
||||
properties.setPassword("");
|
||||
properties.setRememberPassword(false);
|
||||
}
|
||||
properties.save();
|
||||
|
||||
// 执行登录
|
||||
login(username, password).whenComplete((v, e) -> {
|
||||
@@ -240,8 +252,8 @@ public class OkHttpLoginController implements MessageHolder {
|
||||
|
||||
private CompletableFuture<Void> login(String username, String password) {
|
||||
// 添加详细日志,记录服务器URL和请求准备情况
|
||||
info("正在连接服务器: " + serverUrl);
|
||||
logger.debug("login方法被调用,用户名: " + username);
|
||||
info("正在连接服务器: " + serverUrl.get());
|
||||
logger.debug("用户名: {}", username);
|
||||
CompletableFuture<Void> future = new CompletableFuture<>();
|
||||
|
||||
try {
|
||||
@@ -268,7 +280,7 @@ public class OkHttpLoginController implements MessageHolder {
|
||||
RequestBody body = RequestBody.create(objectNode.toString(), JSON);
|
||||
|
||||
// 构建并记录完整的请求URL
|
||||
String loginUrl = serverUrl + "/api/login";
|
||||
String loginUrl = serverUrl.get() + "/api/login";
|
||||
logger.debug("构建登录请求URL: " + loginUrl);
|
||||
Request request = new Request.Builder()
|
||||
.url(loginUrl)
|
||||
|
||||
@@ -336,13 +336,13 @@ public class ProjectCostTabSkinItems
|
||||
grossProfitMarginColumn.setEditable(false);
|
||||
|
||||
creatorColumn.setCellValueFactory(param -> param.getValue().getCreatorId());
|
||||
creatorColumn.setCellFactory(cell -> new EmployeeTableCell<>(getEmployeeService()));
|
||||
creatorColumn.setCellFactory(EmployeeTableCell.forTableColumn(getEmployeeService()));
|
||||
updaterColumn.setCellValueFactory(param -> param.getValue().getUpdaterId());
|
||||
updaterColumn.setCellFactory(cell -> new EmployeeTableCell<>(getEmployeeService()));
|
||||
updaterColumn.setCellFactory(EmployeeTableCell.forTableColumn(getEmployeeService()));
|
||||
createDateColumn.setCellValueFactory(param -> param.getValue().getCreateDate());
|
||||
createDateColumn.setCellFactory(param -> new LocalDateTimeTableCell<>());
|
||||
createDateColumn.setCellFactory(LocalDateTimeTableCell.forTableColumn());
|
||||
updateDateColumn.setCellValueFactory(param -> param.getValue().getUpdateDate());
|
||||
updateDateColumn.setCellFactory(param -> new LocalDateTimeTableCell<>());
|
||||
updateDateColumn.setCellFactory(LocalDateTimeTableCell.forTableColumn());
|
||||
remarkColumn.setCellValueFactory(param -> param.getValue().getRemark());
|
||||
remarkColumn.setCellFactory(TextFieldTableCell.forTableColumn());
|
||||
remarkColumn.setOnEditCommit(event -> {
|
||||
|
||||
@@ -28,6 +28,7 @@ import javafx.scene.control.MenuItem;
|
||||
import javafx.scene.control.Tab;
|
||||
import javafx.scene.control.TableColumn;
|
||||
import javafx.scene.control.cell.TextFieldTableCell;
|
||||
import javafx.util.StringConverter;
|
||||
import javafx.util.converter.CurrencyStringConverter;
|
||||
import javafx.util.converter.NumberStringConverter;
|
||||
import lombok.Setter;
|
||||
@@ -99,12 +100,24 @@ public class ContractTabSkinItemsV2
|
||||
CurrencyStringConverter currencyStringConverter = new CurrencyStringConverter(numberInstance);
|
||||
|
||||
idColumn.setCellValueFactory(param -> param.getValue().getId());
|
||||
|
||||
titleColumn.setCellValueFactory(param -> param.getValue().getTitle());
|
||||
specificationColumn.setCellValueFactory(param -> param.getValue().getSpecification());
|
||||
unitColumn.setCellValueFactory(param -> param.getValue().getUnit());
|
||||
|
||||
inventoryColumn.setCellValueFactory(param -> param.getValue().getInventory());
|
||||
inventoryColumn.setCellFactory(InventoryTableCell.forTableColumn(getInventoryService()));
|
||||
inventoryColumn.setCellFactory(
|
||||
InventoryTableCell.forTableColumn(getInventoryService(), new StringConverter<InventoryVo>() {
|
||||
@Override
|
||||
public String toString(InventoryVo object) {
|
||||
return object != null ? object.getCode() : "";
|
||||
}
|
||||
|
||||
@Override
|
||||
public InventoryVo fromString(String string) {
|
||||
return getInventoryService().findByCode(string);
|
||||
}
|
||||
}));
|
||||
|
||||
exclusiveTaxPriceColumn.setCellValueFactory(param -> param.getValue().getExclusiveTaxPrice());
|
||||
exclusiveTaxPriceColumn.setCellFactory(TextFieldTableCell.forTableColumn(currencyStringConverter));
|
||||
|
||||
@@ -7,6 +7,7 @@ import com.ecep.contract.vo.InventoryCatalogVo;
|
||||
import com.ecep.contract.vo.InventoryVo;
|
||||
|
||||
import javafx.util.Callback;
|
||||
import javafx.util.StringConverter;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
@NoArgsConstructor
|
||||
@@ -21,6 +22,23 @@ public class InventoryTableCell<V> extends AsyncUpdateTableCell<V, Integer, Inve
|
||||
InventoryService inventoryService) {
|
||||
return param -> new InventoryTableCell<>(inventoryService);
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建单元格工厂,支持自定义StringConverter
|
||||
*
|
||||
* @param inventoryService 库存服务
|
||||
* @param converter 字符串转换器
|
||||
* @return 单元格工厂
|
||||
*/
|
||||
public static <V> Callback<javafx.scene.control.TableColumn<V, Integer>, javafx.scene.control.TableCell<V, Integer>> forTableColumn(
|
||||
InventoryService inventoryService, StringConverter<InventoryVo> converter) {
|
||||
return param -> new InventoryTableCell<>(inventoryService) {
|
||||
@Override
|
||||
public String format(InventoryVo entity) {
|
||||
return converter.toString(entity);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
private InventoryCatalogService inventoryCatalogService;
|
||||
|
||||
|
||||
@@ -3,6 +3,10 @@ package com.ecep.contract.controller.table.cell;
|
||||
import java.time.LocalDateTime;
|
||||
import java.time.format.DateTimeFormatter;
|
||||
|
||||
import javafx.scene.control.TableCell;
|
||||
import javafx.scene.control.TableColumn;
|
||||
import javafx.util.Callback;
|
||||
|
||||
import com.ecep.contract.MyDateTimeUtils;
|
||||
|
||||
/**
|
||||
@@ -11,6 +15,40 @@ import com.ecep.contract.MyDateTimeUtils;
|
||||
public class LocalDateTimeTableCell<T>
|
||||
extends javafx.scene.control.TableCell<T, java.time.LocalDateTime> {
|
||||
|
||||
/**
|
||||
* 静态工厂方法,创建TableCell的回调工厂
|
||||
*
|
||||
* @param <T> 表格数据类型
|
||||
* @return TableCell的回调工厂
|
||||
*/
|
||||
public static <T> Callback<TableColumn<T, LocalDateTime>, TableCell<T, LocalDateTime>> forTableColumn() {
|
||||
return column -> new LocalDateTimeTableCell<>();
|
||||
}
|
||||
|
||||
/**
|
||||
* 静态工厂方法,使用指定格式创建TableCell的回调工厂
|
||||
*
|
||||
* @param <T> 表格数据类型
|
||||
* @param format 日期时间格式
|
||||
* @return TableCell的回调工厂
|
||||
*/
|
||||
public static <T> Callback<TableColumn<T, LocalDateTime>, TableCell<T, LocalDateTime>> forTableColumn(
|
||||
String format) {
|
||||
return column -> new LocalDateTimeTableCell<>(format);
|
||||
}
|
||||
|
||||
/**
|
||||
* 静态工厂方法,使用指定的DateTimeFormatter创建TableCell的回调工厂
|
||||
*
|
||||
* @param <T> 表格数据类型
|
||||
* @param formatter DateTimeFormatter对象
|
||||
* @return TableCell的回调工厂
|
||||
*/
|
||||
public static <T> Callback<TableColumn<T, LocalDateTime>, TableCell<T, LocalDateTime>> forTableColumn(
|
||||
DateTimeFormatter formatter) {
|
||||
return column -> new LocalDateTimeTableCell<>(formatter);
|
||||
}
|
||||
|
||||
private final DateTimeFormatter formatter;
|
||||
|
||||
public LocalDateTimeTableCell(DateTimeFormatter formatter) {
|
||||
@@ -34,4 +72,5 @@ public class LocalDateTimeTableCell<T>
|
||||
setText(item.format(formatter));
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -113,12 +113,7 @@ public class QueryService<T extends IdentityEntity, TV extends IdentityViewModel
|
||||
}
|
||||
|
||||
public CompletableFuture<JsonNode> async(String method, Object... params) {
|
||||
return webSocketService.invoke(getBeanName(), method, params).handle((response, ex) -> {
|
||||
if (ex != null) {
|
||||
throw new RuntimeException("远程方法+" + method + "+调用失败", ex);
|
||||
}
|
||||
return response;
|
||||
});
|
||||
return webSocketService.invoke(getBeanName(), method, params);
|
||||
}
|
||||
|
||||
public CompletableFuture<T> asyncFindById(Integer id) {
|
||||
@@ -137,7 +132,7 @@ public class QueryService<T extends IdentityEntity, TV extends IdentityViewModel
|
||||
return asyncFindById(id).get();
|
||||
} catch (Exception e) {
|
||||
logger.error("查询实体失败 #{}", id, e);
|
||||
throw new RuntimeException("查询实体失败", e);
|
||||
throw new RuntimeException("查询实体失败 #" + id, e);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,18 +1,32 @@
|
||||
package com.ecep.contract.task;
|
||||
|
||||
import com.ecep.contract.MessageHolder;
|
||||
import com.ecep.contract.WebSocketClientTasker;
|
||||
import com.ecep.contract.vo.ContractVo;
|
||||
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
|
||||
public class ContractVerifyTasker extends Tasker<Object> {
|
||||
public class ContractVerifyTasker extends Tasker<Object> implements WebSocketClientTasker {
|
||||
@Setter
|
||||
private ContractVo contract;
|
||||
@Getter
|
||||
@Setter
|
||||
boolean passed = false;
|
||||
|
||||
@Override
|
||||
public String getTaskName() {
|
||||
return getClass().getSimpleName();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateProgress(long current, long total) {
|
||||
super.updateProgress(current, total);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Object execute(MessageHolder holder) throws Exception {
|
||||
// TODO Auto-generated method stub
|
||||
throw new UnsupportedOperationException("Unimplemented method 'execute'");
|
||||
return callRemoteTask(holder, getLocale(), contract.getId());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -3,8 +3,8 @@ package com.ecep.contract.vm;
|
||||
import com.ecep.contract.Desktop;
|
||||
import com.ecep.contract.MyDateTimeUtils;
|
||||
import com.ecep.contract.SpringApp;
|
||||
import com.ecep.contract.WebSocketClientService;
|
||||
import com.ecep.contract.controller.CurrentEmployeeInitialedEvent;
|
||||
import com.ecep.contract.model.EmployeeRole;
|
||||
import com.ecep.contract.service.EmployeeService;
|
||||
import com.ecep.contract.vo.EmployeeRoleVo;
|
||||
import com.ecep.contract.vo.EmployeeVo;
|
||||
@@ -138,11 +138,34 @@ public class CurrentEmployee extends EmployeeViewModel {
|
||||
* 3. 更新当前用户的信息
|
||||
* 4. 更新当前用户的角色
|
||||
*/
|
||||
executorService.submit(() -> {
|
||||
// issue #1 sss 2020-07-05
|
||||
// issue #1 sss 2020-07-05
|
||||
Thread.ofVirtual().start(() -> {
|
||||
|
||||
while (getId().get() <= 0) {
|
||||
try {
|
||||
Thread.sleep(5000);
|
||||
} catch (InterruptedException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
int activeEmployeeId = getId().get();
|
||||
if (activeEmployeeId <= 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
EmployeeService employeeService = SpringApp.getBean(EmployeeService.class);
|
||||
EmployeeVo employee = employeeService.findById(getId().get());
|
||||
List<EmployeeRoleVo> roles = employeeService.getRolesByEmployeeId(getId().get());
|
||||
WebSocketClientService webSocketService = SpringApp.getBean(WebSocketClientService.class);
|
||||
while (!webSocketService.getOnlineProperty().get()) {
|
||||
try {
|
||||
logger.debug("waiting for websocket online...");
|
||||
Thread.sleep(2000);
|
||||
} catch (InterruptedException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
EmployeeVo employee = employeeService.findById(activeEmployeeId);
|
||||
List<EmployeeRoleVo> roles = employeeService.getRolesByEmployeeId(activeEmployeeId);
|
||||
Platform.runLater(() -> {
|
||||
update(employee);
|
||||
rolesProperty().setAll(roles);
|
||||
@@ -151,9 +174,9 @@ public class CurrentEmployee extends EmployeeViewModel {
|
||||
future.complete(null);
|
||||
});
|
||||
});
|
||||
/**
|
||||
* 定时更新用户活动状态
|
||||
*/
|
||||
|
||||
|
||||
// 定时更新用户活动状态
|
||||
executorService.scheduleWithFixedDelay(() -> {
|
||||
try {
|
||||
// SpringApp.getBean(EmployeeService.class).updateActive(Desktop.instance.getSessionId());
|
||||
|
||||
Reference in New Issue
Block a user