diff --git a/client/pom.xml b/client/pom.xml
index d20084f..e5acc9b 100644
--- a/client/pom.xml
+++ b/client/pom.xml
@@ -6,12 +6,12 @@
com.ecep.contract
Contract-Manager
- 0.0.58-SNAPSHOT
+ 0.0.80-SNAPSHOT
com.ecep.contract
client
- 0.0.58-SNAPSHOT
+ 0.0.80-SNAPSHOT
${java.version}
@@ -22,7 +22,7 @@
com.ecep.contract
common
- 0.0.58-SNAPSHOT
+ 0.0.80-SNAPSHOT
org.springframework.boot
diff --git a/client/src/main/java/com/ecep/contract/Desktop.java b/client/src/main/java/com/ecep/contract/Desktop.java
index ec50adf..15ce1a5 100644
--- a/client/src/main/java/com/ecep/contract/Desktop.java
+++ b/client/src/main/java/com/ecep/contract/Desktop.java
@@ -17,6 +17,7 @@ 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.TextMessageHolder;
@@ -25,7 +26,7 @@ import com.ecep.contract.vm.CurrentEmployee;
import javafx.application.Application;
import javafx.application.Platform;
-import javafx.beans.property.SimpleIntegerProperty;
+import javafx.beans.property.SimpleStringProperty;
import javafx.fxml.FXMLLoader;
import javafx.scene.Node;
import javafx.scene.Parent;
@@ -36,6 +37,10 @@ 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 应用程序
@@ -63,9 +68,12 @@ public class Desktop extends Application {
private ScheduledExecutorService scheduledExecutorService = null;
private final TaskMonitorCenter taskMonitorCenter = new TaskMonitorCenter();
- private final SimpleIntegerProperty sessionId = new SimpleIntegerProperty(0);
+ 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);
@@ -75,11 +83,11 @@ public class Desktop extends Application {
return activeEmployee.getId().get();
}
- public int getSessionId() {
+ public String getSessionId() {
return sessionId.get();
}
- public void setSessionId(int sessionId) {
+ public void setSessionId(String sessionId) {
this.sessionId.set(sessionId);
}
@@ -136,7 +144,6 @@ public class Desktop extends Application {
// 更新窗口标题
Node titleNode = root.lookup("#title");
if (titleNode != null) {
-
primaryStage.setTitle(((Text) titleNode).getText());
}
@@ -187,16 +194,37 @@ public class Desktop extends Application {
});
try {
+ initHttpClient();
+
OkHttpLoginController controller = new OkHttpLoginController();
+ controller.setHttpClient(this.httpClient);
controller.setHolder(holder);
controller.setPrimaryStage(primaryStage);
controller.setProperties(properties);
- while (true) {
- controller.tryLogin();
- if (getActiveEmployeeId() > 0) {
- break;
+ // while (true) {
+ controller.tryLogin().whenComplete((v, e) -> {
+ if (e != null) {
+ holder.error("登录失败:" + e.getMessage());
+ } else {
+ 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));
}
- }
+ });
+ // if (getActiveEmployeeId() > 0) {
+ // break;
+ // }
+ // }
+
} catch (Exception e) {
holder.error("登录失败:" + e.getMessage());
logger.error(e.getMessage(), e);
@@ -210,6 +238,26 @@ public class Desktop extends Application {
}
+ 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()) {
diff --git a/client/src/main/java/com/ecep/contract/controller/HomeWindowController.java b/client/src/main/java/com/ecep/contract/controller/HomeWindowController.java
index c13b486..d8b5afa 100644
--- a/client/src/main/java/com/ecep/contract/controller/HomeWindowController.java
+++ b/client/src/main/java/com/ecep/contract/controller/HomeWindowController.java
@@ -34,6 +34,7 @@ import com.ecep.contract.util.FxmlPath;
import com.ecep.contract.util.FxmlUtils;
import com.ecep.contract.vm.CurrentEmployee;
+import javafx.application.Platform;
import javafx.concurrent.Task;
import javafx.event.ActionEvent;
import javafx.scene.Node;
@@ -46,6 +47,12 @@ import javafx.scene.layout.VBox;
import javafx.stage.Modality;
import javafx.stage.Stage;
import javafx.stage.WindowEvent;
+import okhttp3.OkHttpClient;
+import okhttp3.Request;
+import okhttp3.Response;
+import okhttp3.WebSocket;
+import okhttp3.WebSocketListener;
+import okio.ByteString;
@Lazy
@Scope("prototype")
@@ -70,6 +77,9 @@ public class HomeWindowController extends BaseController {
public Label taskMonitorLabel;
public Label employeeStatusLabel;
+ private WebSocket webSocket;
+ private String webSocketUrl = "ws://localhost:8080/ws";
+
public void initialize() {
openCompanyManagerWindow.setOnAction(event -> showInOwner(CompanyManagerWindowController.class));
openProjectManagerWindow.setOnAction(event -> showInOwner(ProjectManagerWindowController.class));
@@ -95,6 +105,7 @@ public class HomeWindowController extends BaseController {
employeeStatusLabel.textProperty().bind(Desktop.instance.getActiveEmployee().getName());
Desktop.instance.getTaskMonitorCenter().bindStatusLabel(taskMonitorLabel);
Desktop.instance.getActiveEmployee().initialize();
+ initWebSocket();
}
@EventListener
@@ -209,4 +220,64 @@ public class HomeWindowController extends BaseController {
public void onShowTaskMonitorWindowAction(ActionEvent event) {
showInOwner(TaskMonitorViewController.class);
}
+
+ private void initWebSocket() {
+
+ OkHttpClient httpClient = Desktop.instance.getHttpClient();
+
+ try {
+ // 构建WebSocket请求,包含认证信息
+ Request request = new Request.Builder()
+ .url(webSocketUrl)
+ .build();
+
+ webSocket = httpClient.newWebSocket(request, new WebSocketListener() {
+ @Override
+ public void onOpen(WebSocket webSocket, Response response) {
+ Platform.runLater(() -> {
+ setStatus("WebSocket连接已建立");
+ // 登录成功后的处理
+ System.out.println("WebSocket连接已建立");
+ });
+ }
+
+ @Override
+ public void onMessage(WebSocket webSocket, String text) {
+ // 处理收到的文本消息
+ logger.debug("收到WebSocket消息: " + text);
+ // 这里可以根据需要处理从服务器接收的数据
+ }
+
+ @Override
+ public void onMessage(WebSocket webSocket, ByteString bytes) {
+ // 处理收到的二进制消息
+ logger.debug("收到二进制WebSocket消息,长度: " + bytes.size());
+ }
+
+ @Override
+ public void onClosing(WebSocket webSocket, int code, String reason) {
+ logger.debug("WebSocket连接正在关闭: 代码=" + code + ", 原因=" + reason);
+ }
+
+ @Override
+ public void onClosed(WebSocket webSocket, int code, String reason) {
+ logger.debug("WebSocket连接已关闭: 代码=" + code + ", 原因=" + reason);
+ // 可以在这里处理重连逻辑
+ }
+
+ @Override
+ public void onFailure(WebSocket webSocket, Throwable t, Response response) {
+ logger.error("WebSocket连接失败: " + t.getMessage());
+ Platform.runLater(() -> {
+ setStatus("WebSocket连接失败: " + t.getMessage());
+ });
+ }
+ });
+ } catch (Exception e) {
+ logger.error("建立WebSocket连接失败: " + e.getMessage());
+ Platform.runLater(() -> {
+ setStatus("建立WebSocket连接失败: " + e.getMessage());
+ });
+ }
+ }
}
diff --git a/client/src/main/java/com/ecep/contract/controller/LoginWidowController.java b/client/src/main/java/com/ecep/contract/controller/LoginWidowController.java
index 002e8e6..336fa39 100644
--- a/client/src/main/java/com/ecep/contract/controller/LoginWidowController.java
+++ b/client/src/main/java/com/ecep/contract/controller/LoginWidowController.java
@@ -524,7 +524,7 @@ public class LoginWidowController implements MessageHolder {
info("请稍后...");
}
Desktop.instance.setActiveEmployeeId(employeeInfo.employeeId);
- Desktop.instance.setSessionId(employeeInfo.sessionId);
+ // Desktop.instance.setSessionId(employeeInfo.sessionId);
tryShowHomeWindow();
}
diff --git a/client/src/main/java/com/ecep/contract/controller/OkHttpLoginController.java b/client/src/main/java/com/ecep/contract/controller/OkHttpLoginController.java
index a7803bd..8121108 100644
--- a/client/src/main/java/com/ecep/contract/controller/OkHttpLoginController.java
+++ b/client/src/main/java/com/ecep/contract/controller/OkHttpLoginController.java
@@ -18,11 +18,13 @@ import org.springframework.util.StringUtils;
import com.ecep.contract.Desktop;
import com.ecep.contract.MessageHolder;
import com.ecep.contract.SpringApp;
+import com.fasterxml.jackson.databind.JsonNode;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.fasterxml.jackson.databind.node.ObjectNode;
import javafx.application.Platform;
import javafx.geometry.Insets;
import javafx.scene.Scene;
-import javafx.scene.control.Alert;
import javafx.scene.control.Button;
import javafx.scene.control.CheckBox;
import javafx.scene.control.Label;
@@ -34,16 +36,16 @@ import javafx.stage.Stage;
import lombok.Setter;
import okhttp3.Call;
import okhttp3.Callback;
-import okhttp3.FormBody;
+import okhttp3.Cookie;
+import okhttp3.CookieJar;
+import okhttp3.HttpUrl;
import okhttp3.MediaType;
import okhttp3.OkHttpClient;
-import okhttp3.FormBody;
import okhttp3.Request;
import okhttp3.RequestBody;
import okhttp3.Response;
+import okhttp3.ResponseBody;
import okhttp3.WebSocket;
-import okhttp3.WebSocketListener;
-import okio.ByteString;
public class OkHttpLoginController implements MessageHolder {
private static final Logger logger = LoggerFactory.getLogger(OkHttpLoginController.class);
@@ -55,14 +57,30 @@ public class OkHttpLoginController implements MessageHolder {
private Stage primaryStage;
@Setter
private Properties properties;
-
+ @Setter
private OkHttpClient httpClient;
private WebSocket webSocket;
private String serverUrl;
private String webSocketUrl;
public OkHttpLoginController() {
- this.httpClient = new OkHttpClient();
+ 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
@@ -79,20 +97,32 @@ public class OkHttpLoginController implements MessageHolder {
this.webSocketUrl = "ws://" + host + ":" + port + "/ws";
}
- public void tryLogin() {
+ public CompletableFuture tryLogin() {
initServerUrls();
// 检查配置文件中是否保存用户名和密码
String userName = getUserName();
String password = getPassword();
+ CompletableFuture loginFuture = new CompletableFuture<>();
+
if (StringUtils.hasText(userName) && StringUtils.hasText(password)) {
- login(userName, password);
+ login(userName, password).whenComplete((v, e) -> {
+ if (e != null) {
+ loginFuture.completeExceptionally(e);
+ } else {
+ loginFuture.complete(v);
+ }
+ });
} else {
Platform.runLater(() -> {
showLoginDialog();
+ if (!loginFuture.isDone()) {
+ loginFuture.complete(null);
+ }
});
}
+ return loginFuture;
}
private String getUserName() {
@@ -193,8 +223,19 @@ public class OkHttpLoginController implements MessageHolder {
}
// 执行登录
- login(username, password);
- stage.close();
+ login(username, password).whenComplete((v, e) -> {
+ if (e != null) {
+ Platform.runLater(() -> {
+ errorLabel.setText(e.getMessage());
+ errorLabel.setVisible(true);
+ // showError("登录失败", e.getMessage());
+ });
+ return;
+ }
+ Platform.runLater(() -> {
+ stage.close();
+ });
+ });
});
// 创建场景并设置到窗口
@@ -202,160 +243,84 @@ public class OkHttpLoginController implements MessageHolder {
stage.setScene(scene);
stage.setResizable(false);
stage.showAndWait();
+
+ System.out.println("登录窗口关闭");
}
- private void login(String username, String password) {
+ private CompletableFuture login(String username, String password) {
+ // 添加详细日志,记录服务器URL和请求准备情况
info("正在连接服务器: " + serverUrl);
+ logger.debug("login方法被调用,用户名: " + username);
+ CompletableFuture future = new CompletableFuture<>();
try {
- // 构建表单格式的登录请求
- RequestBody body = new FormBody.Builder()
- .add("username", username)
- .add("password", password)
- .build();
+ ObjectMapper objectMapper = SpringApp.getBean(ObjectMapper.class);
+ ObjectNode objectNode = objectMapper.createObjectNode();
+ objectNode.put("username", username);
+ objectNode.put("password", password);
+ objectNode.put("type", "client");
+ // 将MacIP列表转换为Map格式(MAC地址->IP地址)
+ List macIpList = getMacAndIP().join();
+ ObjectNode signNode = objectMapper.createObjectNode();
+ for (MacIP macIp : macIpList) {
+ signNode.put(macIp.mac, macIp.ip);
+ }
+ objectNode.set("sign", signNode);
+
+ // 构建JSON格式的登录请求
+ RequestBody body = RequestBody.create(objectNode.toString(), JSON);
+
+ // 构建并记录完整的请求URL
+ String loginUrl = serverUrl + "/api/login";
+ logger.debug("构建登录请求URL: " + loginUrl);
Request request = new Request.Builder()
- .url(serverUrl + "/login")
+ .url(loginUrl)
.post(body)
.build();
- httpClient.newCall(request).enqueue(new Callback() {
- @Override
- public void onFailure(Call call, IOException e) {
- Platform.runLater(() -> {
- error("登录失败: 无法连接到服务器 - " + e.getMessage());
- showError("登录失败", "无法连接到服务器,请检查网络连接或服务器配置。");
- });
- }
+ httpClient.newCall(request).enqueue(new Callback() {
+ @Override
+ public void onFailure(Call call, IOException e) {
+ future.completeExceptionally(
+ new IOException("登录失败: 无法连接到服务器,请检查网络连接或服务器配置 - " + e.getMessage(), e));
+ }
- @Override
- public void onResponse(Call call, Response response) throws IOException {
+ @Override
+ public void onResponse(Call call, Response response) throws IOException {
+ try {
if (!response.isSuccessful()) {
- Platform.runLater(() -> {
- error("登录失败: 服务器返回错误码 - " + response.code());
- showError("登录失败", "用户名或密码错误,或服务器暂时不可用。");
- });
+ future.completeExceptionally(
+ new IOException("登录失败: 服务器返回错误码 - " + response.toString()));
return;
}
+ ResponseBody body = response.body();
+ System.out.println("contentType = " + body.contentType());
+ JsonNode jsonNode = objectMapper.readTree(body.string());
- try {
- // 解析登录响应
- String responseBody = response.body().string();
- logger.debug("登录响应: " + responseBody);
-
- // 这里需要根据实际的响应格式解析数据
- // 假设响应包含employeeId和sessionId
- int employeeId = extractEmployeeId(responseBody);
- int sessionId = extractSessionId(responseBody);
-
- if (employeeId > 0 && sessionId > 0) {
- Platform.runLater(() -> {
- info("登录成功,正在建立WebSocket连接...");
- // 登录成功后建立WebSocket连接
- establishWebSocketConnection(employeeId, sessionId);
- });
- } else {
- Platform.runLater(() -> {
- error("登录失败: 无效的响应数据");
- showError("登录失败", "服务器返回无效的响应数据。");
- });
- }
- } catch (Exception e) {
- Platform.runLater(() -> {
- error("登录失败: 解析响应失败 - " + e.getMessage());
- showError("登录失败", "解析服务器响应时发生错误。");
- });
+ boolean success = jsonNode.get("success").asBoolean(false);
+ if (!success) {
+ future.completeExceptionally(
+ new IOException("登录失败: 服务器返回错误 - " + jsonNode.get("error").asText()));
+ return;
}
+ System.out.println("登录成功: " + jsonNode.toString());
+ // 登录成功后,调用新的API端点获取用户信息
+
+ Desktop.instance.setActiveEmployeeId(jsonNode.get("employeeId").asInt());
+ Desktop.instance.setSessionId(jsonNode.get("sessionId").asText());
+ future.complete(null);
+
+ } finally {
+ // 确保主响应体被关闭
+ response.close();
}
- });
- } catch (Exception e) {
- Platform.runLater(() -> {
- error("登录过程中发生错误: " + e.getMessage());
- showError("登录错误", e.getMessage());
- });
- }
- }
-
- private void establishWebSocketConnection(int employeeId, int sessionId) {
- try {
- // 构建WebSocket请求,包含认证信息
- Request request = new Request.Builder()
- .url(webSocketUrl + "?employeeId=" + employeeId + "&sessionId=" + sessionId)
- .build();
-
- webSocket = httpClient.newWebSocket(request, new WebSocketListener() {
- @Override
- public void onOpen(WebSocket webSocket, Response response) {
- Platform.runLater(() -> {
- info("WebSocket连接已建立");
- // 登录成功后的处理
- logined(employeeId, sessionId);
- });
- }
-
- @Override
- public void onMessage(WebSocket webSocket, String text) {
- // 处理收到的文本消息
- logger.debug("收到WebSocket消息: " + text);
- // 这里可以根据需要处理从服务器接收的数据
- }
-
- @Override
- public void onMessage(WebSocket webSocket, ByteString bytes) {
- // 处理收到的二进制消息
- logger.debug("收到二进制WebSocket消息,长度: " + bytes.size());
- }
-
- @Override
- public void onClosing(WebSocket webSocket, int code, String reason) {
- logger.debug("WebSocket连接正在关闭: 代码=" + code + ", 原因=" + reason);
- }
-
- @Override
- public void onClosed(WebSocket webSocket, int code, String reason) {
- logger.debug("WebSocket连接已关闭: 代码=" + code + ", 原因=" + reason);
- // 可以在这里处理重连逻辑
- }
-
- @Override
- public void onFailure(WebSocket webSocket, Throwable t, Response response) {
- logger.error("WebSocket连接失败: " + t.getMessage());
- Platform.runLater(() -> {
- error("WebSocket连接失败: " + t.getMessage());
- showError("连接错误", "与服务器的WebSocket连接失败。");
- });
}
});
} catch (Exception e) {
- logger.error("建立WebSocket连接失败: " + e.getMessage());
- Platform.runLater(() -> {
- error("建立WebSocket连接失败: " + e.getMessage());
- showError("连接错误", "无法建立与服务器的WebSocket连接。");
- });
+ future.completeExceptionally(new IOException("登录过程中发生错误: " + e.getMessage(), e));
}
- }
-
- private void logined(int employeeId, int sessionId) {
- // 设置当前登录员工信息
- Desktop.instance.setActiveEmployeeId(employeeId);
- Desktop.instance.setSessionId(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));
+ return future;
}
CompletableFuture> getMacAndIP() {
@@ -402,46 +367,6 @@ public class OkHttpLoginController implements MessageHolder {
});
}
- // 辅助方法:从响应中提取employeeId
- private int extractEmployeeId(String responseBody) {
- // 这里应该根据实际的响应格式进行解析
- // 示例:假设响应格式是 {"employeeId": 123, "sessionId": 456}
- try {
- int start = responseBody.indexOf("employeeId") + 12;
- int end = responseBody.indexOf(",", start);
- if (end == -1) {
- end = responseBody.indexOf("}", start);
- }
- return Integer.parseInt(responseBody.substring(start, end).trim());
- } catch (Exception e) {
- return -1;
- }
- }
-
- // 辅助方法:从响应中提取sessionId
- private int extractSessionId(String responseBody) {
- // 这里应该根据实际的响应格式进行解析
- try {
- int start = responseBody.indexOf("sessionId") + 11;
- int end = responseBody.indexOf(",", start);
- if (end == -1) {
- end = responseBody.indexOf("}", start);
- }
- return Integer.parseInt(responseBody.substring(start, end).trim());
- } catch (Exception e) {
- return -1;
- }
- }
-
- private void showError(String title, String message) {
- Platform.runLater(() -> {
- Alert alert = new Alert(Alert.AlertType.ERROR);
- alert.setTitle(title);
- alert.setHeaderText(null);
- alert.setContentText(message);
- alert.showAndWait();
- });
- }
// WebSocket消息发送方法
public void sendMessage(String message) {
diff --git a/client/src/main/java/com/ecep/contract/controller/SysConfWindowController.java b/client/src/main/java/com/ecep/contract/controller/SysConfWindowController.java
index 13fcb45..2a5f295 100644
--- a/client/src/main/java/com/ecep/contract/controller/SysConfWindowController.java
+++ b/client/src/main/java/com/ecep/contract/controller/SysConfWindowController.java
@@ -11,10 +11,6 @@ import org.springframework.stereotype.Component;
import com.ecep.contract.constant.CompanyCustomerConstant;
import com.ecep.contract.constant.CompanyVendorConstant;
import com.ecep.contract.constant.ContractConstant;
-import com.ecep.contract.service.CompanyCustomerFileService;
-import com.ecep.contract.service.CompanyCustomerService;
-import com.ecep.contract.service.ContractService;
-import com.ecep.contract.service.YongYouU8Service;
import com.ecep.contract.util.StringConfig;
import jakarta.annotation.PreDestroy;
diff --git a/client/src/main/java/com/ecep/contract/controller/vendor/approved_list/CompanyVendorApprovedListVendorImportTask.java b/client/src/main/java/com/ecep/contract/controller/vendor/approved_list/CompanyVendorApprovedListVendorImportTask.java
index 0a02c22..704a802 100644
--- a/client/src/main/java/com/ecep/contract/controller/vendor/approved_list/CompanyVendorApprovedListVendorImportTask.java
+++ b/client/src/main/java/com/ecep/contract/controller/vendor/approved_list/CompanyVendorApprovedListVendorImportTask.java
@@ -10,7 +10,6 @@ import java.util.function.Consumer;
import java.util.stream.Collectors;
import java.util.stream.Stream;
-import com.ecep.contract.util.ProxyUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.data.domain.Page;
@@ -35,6 +34,7 @@ import com.ecep.contract.service.CompanyVendorService;
import com.ecep.contract.service.ContractService;
import com.ecep.contract.task.Tasker;
import com.ecep.contract.util.ParamUtils;
+import com.ecep.contract.util.ProxyUtils;
import lombok.Setter;
diff --git a/client/src/main/java/com/ecep/contract/vm/CurrentEmployee.java b/client/src/main/java/com/ecep/contract/vm/CurrentEmployee.java
index 68fc1f3..e25a209 100644
--- a/client/src/main/java/com/ecep/contract/vm/CurrentEmployee.java
+++ b/client/src/main/java/com/ecep/contract/vm/CurrentEmployee.java
@@ -157,7 +157,7 @@ public class CurrentEmployee extends EmployeeViewModel {
*/
executorService.scheduleWithFixedDelay(() -> {
try {
- SpringApp.getBean(EmployeeService.class).updateActive(Desktop.instance.getSessionId());
+ // SpringApp.getBean(EmployeeService.class).updateActive(Desktop.instance.getSessionId());
} catch (Exception e) {
if (logger.isErrorEnabled()) {
logger.error("updateActive:{}", e.getMessage(), e);
diff --git a/client/src/main/resources/ui/contact.fxml b/client/src/main/resources/ui/contact.fxml
index 9d37c7e..8014eeb 100644
--- a/client/src/main/resources/ui/contact.fxml
+++ b/client/src/main/resources/ui/contact.fxml
@@ -20,7 +20,7 @@
-
+
@@ -114,3 +114,4 @@
+
diff --git a/common/pom.xml b/common/pom.xml
index d87b150..4bf415d 100644
--- a/common/pom.xml
+++ b/common/pom.xml
@@ -6,12 +6,12 @@
com.ecep.contract
Contract-Manager
- 0.0.58-SNAPSHOT
+ 0.0.80-SNAPSHOT
com.ecep.contract
common
- 0.0.58-SNAPSHOT
+ 0.0.80-SNAPSHOT
${java.version}
diff --git a/pom.xml b/pom.xml
index 304639f..77aa967 100644
--- a/pom.xml
+++ b/pom.xml
@@ -10,7 +10,7 @@
com.ecep.contract
Contract-Manager
- 0.0.58-SNAPSHOT
+ 0.0.80-SNAPSHOT
pom
server
diff --git a/server/pom.xml b/server/pom.xml
index ad9ec87..7e29a1c 100644
--- a/server/pom.xml
+++ b/server/pom.xml
@@ -6,12 +6,12 @@
com.ecep.contract
Contract-Manager
- 0.0.58-SNAPSHOT
+ 0.0.80-SNAPSHOT
com.ecep.contract
server
- 0.0.58-SNAPSHOT
+ 0.0.80-SNAPSHOT
${java.version}
@@ -22,7 +22,7 @@
com.ecep.contract
common
- 0.0.58-SNAPSHOT
+ 0.0.80-SNAPSHOT
org.springframework.boot
@@ -74,6 +74,14 @@
+
+
+
+ javax.servlet
+ javax.servlet-api
+ 4.0.1
+ provided
+
com.mysql
diff --git a/server/src/main/java/com/ecep/contract/api/controller/LoginApiController.java b/server/src/main/java/com/ecep/contract/api/controller/LoginApiController.java
new file mode 100644
index 0000000..f0b68bf
--- /dev/null
+++ b/server/src/main/java/com/ecep/contract/api/controller/LoginApiController.java
@@ -0,0 +1,159 @@
+package com.ecep.contract.api.controller;
+
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import jakarta.servlet.http.HttpServletRequest;
+import jakarta.servlet.http.HttpSession;
+
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.context.request.RequestContextHolder;
+import org.springframework.web.context.request.ServletRequestAttributes;
+import org.springframework.data.domain.Sort;
+import org.springframework.security.authentication.AuthenticationManager;
+import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
+import org.springframework.security.core.Authentication;
+import org.springframework.security.core.AuthenticationException;
+import org.springframework.security.core.context.SecurityContextHolder;
+import org.springframework.security.core.userdetails.User;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+import com.ecep.contract.ds.other.service.EmployeeAuthBindService;
+import com.ecep.contract.ds.other.service.EmployeeService;
+import com.ecep.contract.model.Employee;
+import com.ecep.contract.model.EmployeeAuthBind;
+
+import lombok.Data;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+@RestController
+@RequestMapping("/api")
+public class LoginApiController {
+ private static final Logger logger = LoggerFactory.getLogger(LoginApiController.class);
+
+ @Autowired
+ private AuthenticationManager authenticationManager;
+
+ @Autowired
+ private EmployeeService employeeService;
+ @Autowired
+ private EmployeeAuthBindService employeeAuthBindService;
+
+ /**
+ * JSON格式的登录API
+ * 使用Spring Security进行认证,返回JSON格式的响应
+ */
+ @PostMapping("/login")
+ public Map jsonLogin(@RequestBody LoginRequest loginRequest, HttpServletRequest request) {
+ // 获取HttpSession
+ HttpSession session = request.getSession();
+
+ // 添加日志记录,确认方法被调用
+ logger.debug("jsonLogin方法被调用,请求类型: {}", loginRequest.getType());
+ logger.debug("请求用户名: {}", loginRequest.getUsername());
+ logger.debug("会话ID: {}", session != null ? session.getId() : "null");
+ Map result = new HashMap<>();
+
+ try {
+ Employee employee = null;
+ if ("client".equals(loginRequest.getType())) {
+ // 根据用户名查找Employee对象
+ employee = employeeService.findByAccount(loginRequest.getUsername());
+ if (employee == null) {
+ result.put("success", false);
+ result.put("error", "用户信息不存在");
+ return result;
+ }
+ List authBinds = employeeAuthBindService.findAllByEmployee(employee, Sort.unsorted());
+ if (authBinds.isEmpty()) {
+ result.put("success", false);
+ result.put("error", "用户未绑定认证信息");
+ return result;
+ }
+
+ EmployeeAuthBind matched = null;
+ Map signMap = loginRequest.getSign();
+ if (signMap != null) {
+ for (EmployeeAuthBind authBind : authBinds) {
+ String clientIp = signMap.get(authBind.getMac());
+ if (clientIp != null && authBind.getIp().equals(clientIp)) {
+ matched = authBind;
+ break;
+ }
+ }
+ }
+ if (matched == null) {
+ result.put("success", false);
+ result.put("error", "认证信息错误");
+ return result;
+ }
+ UsernamePasswordAuthenticationToken authenticationToken = new UsernamePasswordAuthenticationToken(
+ loginRequest.getUsername(), "default123");
+
+ // 使用AuthenticationManager进行认证
+ Authentication authentication = authenticationManager.authenticate(authenticationToken);
+
+ // 设置认证结果到SecurityContext
+ SecurityContextHolder.getContext().setAuthentication(authentication);
+
+ } else {
+ // 创建认证令牌
+ UsernamePasswordAuthenticationToken authenticationToken = new UsernamePasswordAuthenticationToken(
+ loginRequest.getUsername(), loginRequest.getPassword());
+
+ // 使用AuthenticationManager进行认证
+ Authentication authentication = authenticationManager.authenticate(authenticationToken);
+
+ // 设置认证结果到SecurityContext
+ SecurityContextHolder.getContext().setAuthentication(authentication);
+
+ employee = employeeService.findByAccount(loginRequest.getUsername());
+ }
+
+ if (employee != null) {
+ // 获取当前登录用户
+ User currentUser = (User) SecurityContextHolder.getContext().getAuthentication().getPrincipal();
+ // 返回登录成功的信息
+ result.put("success", true);
+ result.put("employeeId", employee.getId());
+ result.put("sessionId", session.getId());
+ result.put("username", employee.getAccount());
+ result.put("roles", currentUser.getAuthorities());
+ result.put("message", "登录成功");
+ } else {
+ // 用户不存在
+ result.put("success", false);
+ result.put("error", "用户信息不存在");
+ }
+
+ } catch (AuthenticationException e) {
+ // 认证失败
+ result.put("success", false);
+ result.put("error", "用户名或密码错误");
+ } catch (Exception e) {
+ // 其他错误
+ result.put("success", false);
+ result.put("error", "登录过程中发生错误: " + e.getMessage());
+ }
+
+ return result;
+ }
+
+ /**
+ * 登录请求的JSON数据模型
+ */
+ @Data
+ public static class LoginRequest {
+ private String type;
+ private String username;
+ private String password;
+
+ private Map sign = new HashMap<>();
+
+ }
+}
\ No newline at end of file
diff --git a/server/src/main/java/com/ecep/contract/config/GlobalExceptionHandler.java b/server/src/main/java/com/ecep/contract/config/GlobalExceptionHandler.java
index 41bfaef..7933c83 100644
--- a/server/src/main/java/com/ecep/contract/config/GlobalExceptionHandler.java
+++ b/server/src/main/java/com/ecep/contract/config/GlobalExceptionHandler.java
@@ -15,13 +15,15 @@ import org.springframework.web.method.annotation.MethodArgumentTypeMismatchExcep
import org.springframework.web.servlet.NoHandlerFoundException;
import org.springframework.web.servlet.mvc.support.DefaultHandlerExceptionResolver;
+import java.io.PrintWriter;
+import java.io.StringWriter;
import java.util.HashMap;
import java.util.Map;
/**
* 全局异常处理器,捕获并处理所有Controller层抛出的异常,将错误信息以JSON格式返回给前端
*/
-// @RestControllerAdvice
+@RestControllerAdvice
public class GlobalExceptionHandler {
private static final Logger logger = LoggerFactory.getLogger(GlobalExceptionHandler.class);
@@ -36,9 +38,24 @@ public class GlobalExceptionHandler {
result.put("code", 500);
result.put("message", "系统内部错误:" + e.getMessage());
result.put("errorType", e.getClass().getName());
+ result.put("stackTrace", getStackTraceAsString(e));
result.put("success", false);
return new ResponseEntity<>(result, HttpStatus.INTERNAL_SERVER_ERROR);
}
+
+ /**
+ * 将异常堆栈转换为字符串
+ */
+ private String getStackTraceAsString(Throwable throwable) {
+ StringWriter sw = new StringWriter();
+ PrintWriter pw = new PrintWriter(sw);
+ try {
+ throwable.printStackTrace(pw);
+ return sw.toString();
+ } finally {
+ pw.close();
+ }
+ }
/**
* 处理运行时异常
@@ -50,6 +67,7 @@ public class GlobalExceptionHandler {
result.put("code", 500);
result.put("message", "运行时错误:" + e.getMessage());
result.put("errorType", e.getClass().getName());
+ result.put("stackTrace", getStackTraceAsString(e));
result.put("success", false);
return new ResponseEntity<>(result, HttpStatus.INTERNAL_SERVER_ERROR);
}
diff --git a/server/src/main/java/com/ecep/contract/config/SecurityConfig.java b/server/src/main/java/com/ecep/contract/config/SecurityConfig.java
index 90171de..faf38c9 100644
--- a/server/src/main/java/com/ecep/contract/config/SecurityConfig.java
+++ b/server/src/main/java/com/ecep/contract/config/SecurityConfig.java
@@ -51,8 +51,8 @@ public class SecurityConfig {
http
.authorizeHttpRequests(authorize -> authorize
.requestMatchers("/login.html", "/css/**", "/js/**", "/images/**", "/webjars/**", "/login",
- "/error")
- .permitAll() // 允许静态资源、登录页面和错误页面访问
+ "/error", "/api/login")
+ .permitAll() // 允许静态资源、登录页面、错误页面和JSON登录API访问
.anyRequest().authenticated() // 其他所有请求需要认证
)
.csrf(AbstractHttpConfigurer::disable) // 禁用CSRF保护,适合开发环境
diff --git a/server/src/main/java/com/ecep/contract/ds/other/controller/EmployeeController.java b/server/src/main/java/com/ecep/contract/ds/other/controller/EmployeeController.java
index 7a886c3..9b48230 100644
--- a/server/src/main/java/com/ecep/contract/ds/other/controller/EmployeeController.java
+++ b/server/src/main/java/com/ecep/contract/ds/other/controller/EmployeeController.java
@@ -1,6 +1,9 @@
package com.ecep.contract.ds.other.controller;
import java.util.Map;
+import java.util.HashMap;
+
+import jakarta.servlet.http.HttpSession;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
@@ -8,6 +11,7 @@ import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.data.jpa.domain.Specification;
+import org.springframework.security.core.userdetails.User;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
@@ -50,4 +54,35 @@ public class EmployeeController {
employeeService.delete(employee);
}
+ /**
+ * 获取当前登录用户的信息
+ * 包括employeeId和sessionId
+ */
+ @RequestMapping("/currentUser")
+ public Map getCurrentUser(HttpSession session) {
+ Map result = new HashMap<>();
+
+ try {
+ // 获取当前登录用户
+ User currentUser = SecurityUtils.getCurrentUser();
+ if (currentUser != null) {
+ // 根据用户名查找Employee对象
+ Employee employee = employeeService.findByName(currentUser.getUsername());
+ if (employee != null) {
+ result.put("employeeId", employee.getId());
+ result.put("sessionId", session.getId());
+ result.put("success", true);
+ return result;
+ }
+ }
+ } catch (Exception e) {
+ // 处理异常
+ }
+
+ // 如果获取失败,返回错误信息
+ result.put("success", false);
+ result.put("error", "无法获取当前用户信息");
+ return result;
+ }
+
}
diff --git a/server/src/main/java/com/ecep/contract/ds/other/repository/EmployeeAuthBindRepository.java b/server/src/main/java/com/ecep/contract/ds/other/repository/EmployeeAuthBindRepository.java
index eb7d661..7eaa007 100644
--- a/server/src/main/java/com/ecep/contract/ds/other/repository/EmployeeAuthBindRepository.java
+++ b/server/src/main/java/com/ecep/contract/ds/other/repository/EmployeeAuthBindRepository.java
@@ -4,21 +4,14 @@ import java.util.List;
import org.springframework.context.annotation.Lazy;
import org.springframework.data.domain.Sort;
-import org.springframework.data.jpa.repository.JpaRepository;
-import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
-import org.springframework.data.repository.CrudRepository;
-import org.springframework.data.repository.PagingAndSortingRepository;
import org.springframework.stereotype.Repository;
+import com.ecep.contract.ds.MyRepository;
import com.ecep.contract.model.Employee;
import com.ecep.contract.model.EmployeeAuthBind;
@Lazy
@Repository
-public interface EmployeeAuthBindRepository extends
- // JDBC interfaces
- CrudRepository, PagingAndSortingRepository,
- // JPA interfaces
- JpaRepository, JpaSpecificationExecutor {
+public interface EmployeeAuthBindRepository extends MyRepository {
List findAllByEmployee(Employee employee, Sort sort);
}