feat: 实现基于JSON的登录API和安全认证
refactor: 重构登录逻辑和会话管理 fix: 修复会话ID类型和WebSocket连接问题 build: 更新项目版本号和添加Servlet API依赖 style: 清理无用导入和注释代码
This commit is contained in:
@@ -6,12 +6,12 @@
|
|||||||
<parent>
|
<parent>
|
||||||
<groupId>com.ecep.contract</groupId>
|
<groupId>com.ecep.contract</groupId>
|
||||||
<artifactId>Contract-Manager</artifactId>
|
<artifactId>Contract-Manager</artifactId>
|
||||||
<version>0.0.58-SNAPSHOT</version>
|
<version>0.0.80-SNAPSHOT</version>
|
||||||
</parent>
|
</parent>
|
||||||
|
|
||||||
<groupId>com.ecep.contract</groupId>
|
<groupId>com.ecep.contract</groupId>
|
||||||
<artifactId>client</artifactId>
|
<artifactId>client</artifactId>
|
||||||
<version>0.0.58-SNAPSHOT</version>
|
<version>0.0.80-SNAPSHOT</version>
|
||||||
|
|
||||||
<properties>
|
<properties>
|
||||||
<maven.compiler.source>${java.version}</maven.compiler.source>
|
<maven.compiler.source>${java.version}</maven.compiler.source>
|
||||||
@@ -22,7 +22,7 @@
|
|||||||
<dependency>
|
<dependency>
|
||||||
<groupId>com.ecep.contract</groupId>
|
<groupId>com.ecep.contract</groupId>
|
||||||
<artifactId>common</artifactId>
|
<artifactId>common</artifactId>
|
||||||
<version>0.0.58-SNAPSHOT</version>
|
<version>0.0.80-SNAPSHOT</version>
|
||||||
<exclusions>
|
<exclusions>
|
||||||
<exclusion>
|
<exclusion>
|
||||||
<groupId>org.springframework.boot</groupId>
|
<groupId>org.springframework.boot</groupId>
|
||||||
|
|||||||
@@ -17,6 +17,7 @@ import org.slf4j.LoggerFactory;
|
|||||||
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
|
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
|
||||||
|
|
||||||
import com.ecep.contract.controller.BaseController;
|
import com.ecep.contract.controller.BaseController;
|
||||||
|
import com.ecep.contract.controller.HomeWindowController;
|
||||||
import com.ecep.contract.controller.OkHttpLoginController;
|
import com.ecep.contract.controller.OkHttpLoginController;
|
||||||
import com.ecep.contract.task.TaskMonitorCenter;
|
import com.ecep.contract.task.TaskMonitorCenter;
|
||||||
import com.ecep.contract.util.TextMessageHolder;
|
import com.ecep.contract.util.TextMessageHolder;
|
||||||
@@ -25,7 +26,7 @@ import com.ecep.contract.vm.CurrentEmployee;
|
|||||||
|
|
||||||
import javafx.application.Application;
|
import javafx.application.Application;
|
||||||
import javafx.application.Platform;
|
import javafx.application.Platform;
|
||||||
import javafx.beans.property.SimpleIntegerProperty;
|
import javafx.beans.property.SimpleStringProperty;
|
||||||
import javafx.fxml.FXMLLoader;
|
import javafx.fxml.FXMLLoader;
|
||||||
import javafx.scene.Node;
|
import javafx.scene.Node;
|
||||||
import javafx.scene.Parent;
|
import javafx.scene.Parent;
|
||||||
@@ -36,6 +37,10 @@ import javafx.scene.text.Text;
|
|||||||
import javafx.stage.Stage;
|
import javafx.stage.Stage;
|
||||||
import javafx.stage.StageStyle;
|
import javafx.stage.StageStyle;
|
||||||
import lombok.Getter;
|
import lombok.Getter;
|
||||||
|
import okhttp3.Cookie;
|
||||||
|
import okhttp3.CookieJar;
|
||||||
|
import okhttp3.HttpUrl;
|
||||||
|
import okhttp3.OkHttpClient;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* JavaFx 应用程序
|
* JavaFx 应用程序
|
||||||
@@ -63,9 +68,12 @@ public class Desktop extends Application {
|
|||||||
private ScheduledExecutorService scheduledExecutorService = null;
|
private ScheduledExecutorService scheduledExecutorService = null;
|
||||||
private final TaskMonitorCenter taskMonitorCenter = new TaskMonitorCenter();
|
private final TaskMonitorCenter taskMonitorCenter = new TaskMonitorCenter();
|
||||||
|
|
||||||
private final SimpleIntegerProperty sessionId = new SimpleIntegerProperty(0);
|
private final SimpleStringProperty sessionId = new SimpleStringProperty("");
|
||||||
@Getter
|
@Getter
|
||||||
private final CurrentEmployee activeEmployee = new CurrentEmployee();
|
private final CurrentEmployee activeEmployee = new CurrentEmployee();
|
||||||
|
@Getter
|
||||||
|
private OkHttpClient httpClient;
|
||||||
|
|
||||||
|
|
||||||
public void setActiveEmployeeId(int activeEmployeeId) {
|
public void setActiveEmployeeId(int activeEmployeeId) {
|
||||||
activeEmployee.getId().set(activeEmployeeId);
|
activeEmployee.getId().set(activeEmployeeId);
|
||||||
@@ -75,11 +83,11 @@ public class Desktop extends Application {
|
|||||||
return activeEmployee.getId().get();
|
return activeEmployee.getId().get();
|
||||||
}
|
}
|
||||||
|
|
||||||
public int getSessionId() {
|
public String getSessionId() {
|
||||||
return sessionId.get();
|
return sessionId.get();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setSessionId(int sessionId) {
|
public void setSessionId(String sessionId) {
|
||||||
this.sessionId.set(sessionId);
|
this.sessionId.set(sessionId);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -136,7 +144,6 @@ public class Desktop extends Application {
|
|||||||
// 更新窗口标题
|
// 更新窗口标题
|
||||||
Node titleNode = root.lookup("#title");
|
Node titleNode = root.lookup("#title");
|
||||||
if (titleNode != null) {
|
if (titleNode != null) {
|
||||||
|
|
||||||
primaryStage.setTitle(((Text) titleNode).getText());
|
primaryStage.setTitle(((Text) titleNode).getText());
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -187,16 +194,37 @@ public class Desktop extends Application {
|
|||||||
});
|
});
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
initHttpClient();
|
||||||
|
|
||||||
OkHttpLoginController controller = new OkHttpLoginController();
|
OkHttpLoginController controller = new OkHttpLoginController();
|
||||||
|
controller.setHttpClient(this.httpClient);
|
||||||
controller.setHolder(holder);
|
controller.setHolder(holder);
|
||||||
controller.setPrimaryStage(primaryStage);
|
controller.setPrimaryStage(primaryStage);
|
||||||
controller.setProperties(properties);
|
controller.setProperties(properties);
|
||||||
while (true) {
|
// while (true) {
|
||||||
controller.tryLogin();
|
controller.tryLogin().whenComplete((v, e) -> {
|
||||||
if (getActiveEmployeeId() > 0) {
|
if (e != null) {
|
||||||
break;
|
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) {
|
} catch (Exception e) {
|
||||||
holder.error("登录失败:" + e.getMessage());
|
holder.error("登录失败:" + e.getMessage());
|
||||||
logger.error(e.getMessage(), e);
|
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<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
|
@Override
|
||||||
public void stop() throws Exception {
|
public void stop() throws Exception {
|
||||||
if (logger.isDebugEnabled()) {
|
if (logger.isDebugEnabled()) {
|
||||||
|
|||||||
@@ -34,6 +34,7 @@ import com.ecep.contract.util.FxmlPath;
|
|||||||
import com.ecep.contract.util.FxmlUtils;
|
import com.ecep.contract.util.FxmlUtils;
|
||||||
import com.ecep.contract.vm.CurrentEmployee;
|
import com.ecep.contract.vm.CurrentEmployee;
|
||||||
|
|
||||||
|
import javafx.application.Platform;
|
||||||
import javafx.concurrent.Task;
|
import javafx.concurrent.Task;
|
||||||
import javafx.event.ActionEvent;
|
import javafx.event.ActionEvent;
|
||||||
import javafx.scene.Node;
|
import javafx.scene.Node;
|
||||||
@@ -46,6 +47,12 @@ import javafx.scene.layout.VBox;
|
|||||||
import javafx.stage.Modality;
|
import javafx.stage.Modality;
|
||||||
import javafx.stage.Stage;
|
import javafx.stage.Stage;
|
||||||
import javafx.stage.WindowEvent;
|
import javafx.stage.WindowEvent;
|
||||||
|
import okhttp3.OkHttpClient;
|
||||||
|
import okhttp3.Request;
|
||||||
|
import okhttp3.Response;
|
||||||
|
import okhttp3.WebSocket;
|
||||||
|
import okhttp3.WebSocketListener;
|
||||||
|
import okio.ByteString;
|
||||||
|
|
||||||
@Lazy
|
@Lazy
|
||||||
@Scope("prototype")
|
@Scope("prototype")
|
||||||
@@ -70,6 +77,9 @@ public class HomeWindowController extends BaseController {
|
|||||||
public Label taskMonitorLabel;
|
public Label taskMonitorLabel;
|
||||||
public Label employeeStatusLabel;
|
public Label employeeStatusLabel;
|
||||||
|
|
||||||
|
private WebSocket webSocket;
|
||||||
|
private String webSocketUrl = "ws://localhost:8080/ws";
|
||||||
|
|
||||||
public void initialize() {
|
public void initialize() {
|
||||||
openCompanyManagerWindow.setOnAction(event -> showInOwner(CompanyManagerWindowController.class));
|
openCompanyManagerWindow.setOnAction(event -> showInOwner(CompanyManagerWindowController.class));
|
||||||
openProjectManagerWindow.setOnAction(event -> showInOwner(ProjectManagerWindowController.class));
|
openProjectManagerWindow.setOnAction(event -> showInOwner(ProjectManagerWindowController.class));
|
||||||
@@ -95,6 +105,7 @@ public class HomeWindowController extends BaseController {
|
|||||||
employeeStatusLabel.textProperty().bind(Desktop.instance.getActiveEmployee().getName());
|
employeeStatusLabel.textProperty().bind(Desktop.instance.getActiveEmployee().getName());
|
||||||
Desktop.instance.getTaskMonitorCenter().bindStatusLabel(taskMonitorLabel);
|
Desktop.instance.getTaskMonitorCenter().bindStatusLabel(taskMonitorLabel);
|
||||||
Desktop.instance.getActiveEmployee().initialize();
|
Desktop.instance.getActiveEmployee().initialize();
|
||||||
|
initWebSocket();
|
||||||
}
|
}
|
||||||
|
|
||||||
@EventListener
|
@EventListener
|
||||||
@@ -209,4 +220,64 @@ public class HomeWindowController extends BaseController {
|
|||||||
public void onShowTaskMonitorWindowAction(ActionEvent event) {
|
public void onShowTaskMonitorWindowAction(ActionEvent event) {
|
||||||
showInOwner(TaskMonitorViewController.class);
|
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());
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -524,7 +524,7 @@ public class LoginWidowController implements MessageHolder {
|
|||||||
info("请稍后...");
|
info("请稍后...");
|
||||||
}
|
}
|
||||||
Desktop.instance.setActiveEmployeeId(employeeInfo.employeeId);
|
Desktop.instance.setActiveEmployeeId(employeeInfo.employeeId);
|
||||||
Desktop.instance.setSessionId(employeeInfo.sessionId);
|
// Desktop.instance.setSessionId(employeeInfo.sessionId);
|
||||||
tryShowHomeWindow();
|
tryShowHomeWindow();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -18,11 +18,13 @@ import org.springframework.util.StringUtils;
|
|||||||
import com.ecep.contract.Desktop;
|
import com.ecep.contract.Desktop;
|
||||||
import com.ecep.contract.MessageHolder;
|
import com.ecep.contract.MessageHolder;
|
||||||
import com.ecep.contract.SpringApp;
|
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.application.Platform;
|
||||||
import javafx.geometry.Insets;
|
import javafx.geometry.Insets;
|
||||||
import javafx.scene.Scene;
|
import javafx.scene.Scene;
|
||||||
import javafx.scene.control.Alert;
|
|
||||||
import javafx.scene.control.Button;
|
import javafx.scene.control.Button;
|
||||||
import javafx.scene.control.CheckBox;
|
import javafx.scene.control.CheckBox;
|
||||||
import javafx.scene.control.Label;
|
import javafx.scene.control.Label;
|
||||||
@@ -34,16 +36,16 @@ import javafx.stage.Stage;
|
|||||||
import lombok.Setter;
|
import lombok.Setter;
|
||||||
import okhttp3.Call;
|
import okhttp3.Call;
|
||||||
import okhttp3.Callback;
|
import okhttp3.Callback;
|
||||||
import okhttp3.FormBody;
|
import okhttp3.Cookie;
|
||||||
|
import okhttp3.CookieJar;
|
||||||
|
import okhttp3.HttpUrl;
|
||||||
import okhttp3.MediaType;
|
import okhttp3.MediaType;
|
||||||
import okhttp3.OkHttpClient;
|
import okhttp3.OkHttpClient;
|
||||||
import okhttp3.FormBody;
|
|
||||||
import okhttp3.Request;
|
import okhttp3.Request;
|
||||||
import okhttp3.RequestBody;
|
import okhttp3.RequestBody;
|
||||||
import okhttp3.Response;
|
import okhttp3.Response;
|
||||||
|
import okhttp3.ResponseBody;
|
||||||
import okhttp3.WebSocket;
|
import okhttp3.WebSocket;
|
||||||
import okhttp3.WebSocketListener;
|
|
||||||
import okio.ByteString;
|
|
||||||
|
|
||||||
public class OkHttpLoginController implements MessageHolder {
|
public class OkHttpLoginController implements MessageHolder {
|
||||||
private static final Logger logger = LoggerFactory.getLogger(OkHttpLoginController.class);
|
private static final Logger logger = LoggerFactory.getLogger(OkHttpLoginController.class);
|
||||||
@@ -55,14 +57,30 @@ public class OkHttpLoginController implements MessageHolder {
|
|||||||
private Stage primaryStage;
|
private Stage primaryStage;
|
||||||
@Setter
|
@Setter
|
||||||
private Properties properties;
|
private Properties properties;
|
||||||
|
@Setter
|
||||||
private OkHttpClient httpClient;
|
private OkHttpClient httpClient;
|
||||||
private WebSocket webSocket;
|
private WebSocket webSocket;
|
||||||
private String serverUrl;
|
private String serverUrl;
|
||||||
private String webSocketUrl;
|
private String webSocketUrl;
|
||||||
|
|
||||||
public OkHttpLoginController() {
|
public OkHttpLoginController() {
|
||||||
this.httpClient = new OkHttpClient();
|
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
|
@Override
|
||||||
@@ -79,20 +97,32 @@ public class OkHttpLoginController implements MessageHolder {
|
|||||||
this.webSocketUrl = "ws://" + host + ":" + port + "/ws";
|
this.webSocketUrl = "ws://" + host + ":" + port + "/ws";
|
||||||
}
|
}
|
||||||
|
|
||||||
public void tryLogin() {
|
public CompletableFuture<Void> tryLogin() {
|
||||||
initServerUrls();
|
initServerUrls();
|
||||||
|
|
||||||
// 检查配置文件中是否保存用户名和密码
|
// 检查配置文件中是否保存用户名和密码
|
||||||
String userName = getUserName();
|
String userName = getUserName();
|
||||||
String password = getPassword();
|
String password = getPassword();
|
||||||
|
|
||||||
|
CompletableFuture<Void> loginFuture = new CompletableFuture<>();
|
||||||
|
|
||||||
if (StringUtils.hasText(userName) && StringUtils.hasText(password)) {
|
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 {
|
} else {
|
||||||
Platform.runLater(() -> {
|
Platform.runLater(() -> {
|
||||||
showLoginDialog();
|
showLoginDialog();
|
||||||
|
if (!loginFuture.isDone()) {
|
||||||
|
loginFuture.complete(null);
|
||||||
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
return loginFuture;
|
||||||
}
|
}
|
||||||
|
|
||||||
private String getUserName() {
|
private String getUserName() {
|
||||||
@@ -193,169 +223,104 @@ public class OkHttpLoginController implements MessageHolder {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 执行登录
|
// 执行登录
|
||||||
login(username, password);
|
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();
|
stage.close();
|
||||||
});
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
// 创建场景并设置到窗口
|
// 创建场景并设置到窗口
|
||||||
Scene scene = new Scene(borderPane, 400, 280);
|
Scene scene = new Scene(borderPane, 400, 280);
|
||||||
stage.setScene(scene);
|
stage.setScene(scene);
|
||||||
stage.setResizable(false);
|
stage.setResizable(false);
|
||||||
stage.showAndWait();
|
stage.showAndWait();
|
||||||
|
|
||||||
|
System.out.println("登录窗口关闭");
|
||||||
}
|
}
|
||||||
|
|
||||||
private void login(String username, String password) {
|
private CompletableFuture<Void> login(String username, String password) {
|
||||||
|
// 添加详细日志,记录服务器URL和请求准备情况
|
||||||
info("正在连接服务器: " + serverUrl);
|
info("正在连接服务器: " + serverUrl);
|
||||||
|
logger.debug("login方法被调用,用户名: " + username);
|
||||||
|
CompletableFuture<Void> future = new CompletableFuture<>();
|
||||||
|
|
||||||
try {
|
try {
|
||||||
// 构建表单格式的登录请求
|
ObjectMapper objectMapper = SpringApp.getBean(ObjectMapper.class);
|
||||||
RequestBody body = new FormBody.Builder()
|
ObjectNode objectNode = objectMapper.createObjectNode();
|
||||||
.add("username", username)
|
objectNode.put("username", username);
|
||||||
.add("password", password)
|
objectNode.put("password", password);
|
||||||
.build();
|
objectNode.put("type", "client");
|
||||||
|
|
||||||
|
// 将MacIP列表转换为Map<String, String>格式(MAC地址->IP地址)
|
||||||
|
List<MacIP> 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()
|
Request request = new Request.Builder()
|
||||||
.url(serverUrl + "/login")
|
.url(loginUrl)
|
||||||
.post(body)
|
.post(body)
|
||||||
.build();
|
.build();
|
||||||
|
|
||||||
httpClient.newCall(request).enqueue(new Callback() {
|
httpClient.newCall(request).enqueue(new Callback() {
|
||||||
@Override
|
@Override
|
||||||
public void onFailure(Call call, IOException e) {
|
public void onFailure(Call call, IOException e) {
|
||||||
Platform.runLater(() -> {
|
future.completeExceptionally(
|
||||||
error("登录失败: 无法连接到服务器 - " + e.getMessage());
|
new IOException("登录失败: 无法连接到服务器,请检查网络连接或服务器配置 - " + e.getMessage(), e));
|
||||||
showError("登录失败", "无法连接到服务器,请检查网络连接或服务器配置。");
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onResponse(Call call, Response response) throws IOException {
|
public void onResponse(Call call, Response response) throws IOException {
|
||||||
|
try {
|
||||||
if (!response.isSuccessful()) {
|
if (!response.isSuccessful()) {
|
||||||
Platform.runLater(() -> {
|
future.completeExceptionally(
|
||||||
error("登录失败: 服务器返回错误码 - " + response.code());
|
new IOException("登录失败: 服务器返回错误码 - " + response.toString()));
|
||||||
showError("登录失败", "用户名或密码错误,或服务器暂时不可用。");
|
|
||||||
});
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
ResponseBody body = response.body();
|
||||||
|
System.out.println("contentType = " + body.contentType());
|
||||||
|
JsonNode jsonNode = objectMapper.readTree(body.string());
|
||||||
|
|
||||||
try {
|
boolean success = jsonNode.get("success").asBoolean(false);
|
||||||
// 解析登录响应
|
if (!success) {
|
||||||
String responseBody = response.body().string();
|
future.completeExceptionally(
|
||||||
logger.debug("登录响应: " + responseBody);
|
new IOException("登录失败: 服务器返回错误 - " + jsonNode.get("error").asText()));
|
||||||
|
return;
|
||||||
// 这里需要根据实际的响应格式解析数据
|
|
||||||
// 假设响应包含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) {
|
System.out.println("登录成功: " + jsonNode.toString());
|
||||||
Platform.runLater(() -> {
|
// 登录成功后,调用新的API端点获取用户信息
|
||||||
error("登录失败: 解析响应失败 - " + e.getMessage());
|
|
||||||
showError("登录失败", "解析服务器响应时发生错误。");
|
Desktop.instance.setActiveEmployeeId(jsonNode.get("employeeId").asInt());
|
||||||
});
|
Desktop.instance.setSessionId(jsonNode.get("sessionId").asText());
|
||||||
|
future.complete(null);
|
||||||
|
|
||||||
|
} finally {
|
||||||
|
// 确保主响应体被关闭
|
||||||
|
response.close();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
Platform.runLater(() -> {
|
future.completeExceptionally(new IOException("登录过程中发生错误: " + e.getMessage(), e));
|
||||||
error("登录过程中发生错误: " + e.getMessage());
|
|
||||||
showError("登录错误", e.getMessage());
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
}
|
return future;
|
||||||
|
|
||||||
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连接。");
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
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));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
CompletableFuture<List<MacIP>> getMacAndIP() {
|
CompletableFuture<List<MacIP>> 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消息发送方法
|
// WebSocket消息发送方法
|
||||||
public void sendMessage(String message) {
|
public void sendMessage(String message) {
|
||||||
|
|||||||
@@ -11,10 +11,6 @@ import org.springframework.stereotype.Component;
|
|||||||
import com.ecep.contract.constant.CompanyCustomerConstant;
|
import com.ecep.contract.constant.CompanyCustomerConstant;
|
||||||
import com.ecep.contract.constant.CompanyVendorConstant;
|
import com.ecep.contract.constant.CompanyVendorConstant;
|
||||||
import com.ecep.contract.constant.ContractConstant;
|
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 com.ecep.contract.util.StringConfig;
|
||||||
|
|
||||||
import jakarta.annotation.PreDestroy;
|
import jakarta.annotation.PreDestroy;
|
||||||
|
|||||||
@@ -10,7 +10,6 @@ import java.util.function.Consumer;
|
|||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
import java.util.stream.Stream;
|
import java.util.stream.Stream;
|
||||||
|
|
||||||
import com.ecep.contract.util.ProxyUtils;
|
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
import org.springframework.data.domain.Page;
|
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.service.ContractService;
|
||||||
import com.ecep.contract.task.Tasker;
|
import com.ecep.contract.task.Tasker;
|
||||||
import com.ecep.contract.util.ParamUtils;
|
import com.ecep.contract.util.ParamUtils;
|
||||||
|
import com.ecep.contract.util.ProxyUtils;
|
||||||
|
|
||||||
import lombok.Setter;
|
import lombok.Setter;
|
||||||
|
|
||||||
|
|||||||
@@ -157,7 +157,7 @@ public class CurrentEmployee extends EmployeeViewModel {
|
|||||||
*/
|
*/
|
||||||
executorService.scheduleWithFixedDelay(() -> {
|
executorService.scheduleWithFixedDelay(() -> {
|
||||||
try {
|
try {
|
||||||
SpringApp.getBean(EmployeeService.class).updateActive(Desktop.instance.getSessionId());
|
// SpringApp.getBean(EmployeeService.class).updateActive(Desktop.instance.getSessionId());
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
if (logger.isErrorEnabled()) {
|
if (logger.isErrorEnabled()) {
|
||||||
logger.error("updateActive:{}", e.getMessage(), e);
|
logger.error("updateActive:{}", e.getMessage(), e);
|
||||||
|
|||||||
@@ -20,7 +20,7 @@
|
|||||||
<?import javafx.scene.paint.Color?>
|
<?import javafx.scene.paint.Color?>
|
||||||
<?import javafx.scene.text.Font?>
|
<?import javafx.scene.text.Font?>
|
||||||
|
|
||||||
<BorderPane fx:id="root" maxHeight="900" maxWidth="1024" minHeight="300" minWidth="200" prefHeight="600.0" prefWidth="800.0" xmlns="http://javafx.com/javafx/22" xmlns:fx="http://javafx.com/fxml/1" fx:controller="com.ecep.contract.manager.ds.company.controller.contact.CompanyContactWindowController">
|
<BorderPane fx:id="root" maxHeight="900" maxWidth="1024" minHeight="300" minWidth="200" prefHeight="600.0" prefWidth="800.0" xmlns="http://javafx.com/javafx/22" xmlns:fx="http://javafx.com/fxml/1" fx:controller="com.ecep.contract.ds.company.controller.contact.CompanyContactWindowController">
|
||||||
<center>
|
<center>
|
||||||
<TabPane fx:id="tabPane" tabClosingPolicy="UNAVAILABLE" tabMaxWidth="100.0" tabMinWidth="40.0">
|
<TabPane fx:id="tabPane" tabClosingPolicy="UNAVAILABLE" tabMaxWidth="100.0" tabMinWidth="40.0">
|
||||||
<tabs>
|
<tabs>
|
||||||
@@ -114,3 +114,4 @@
|
|||||||
</HBox>
|
</HBox>
|
||||||
</bottom>
|
</bottom>
|
||||||
</BorderPane>
|
</BorderPane>
|
||||||
|
|
||||||
|
|||||||
@@ -6,12 +6,12 @@
|
|||||||
<parent>
|
<parent>
|
||||||
<groupId>com.ecep.contract</groupId>
|
<groupId>com.ecep.contract</groupId>
|
||||||
<artifactId>Contract-Manager</artifactId>
|
<artifactId>Contract-Manager</artifactId>
|
||||||
<version>0.0.58-SNAPSHOT</version>
|
<version>0.0.80-SNAPSHOT</version>
|
||||||
</parent>
|
</parent>
|
||||||
|
|
||||||
<groupId>com.ecep.contract</groupId>
|
<groupId>com.ecep.contract</groupId>
|
||||||
<artifactId>common</artifactId>
|
<artifactId>common</artifactId>
|
||||||
<version>0.0.58-SNAPSHOT</version>
|
<version>0.0.80-SNAPSHOT</version>
|
||||||
|
|
||||||
<properties>
|
<properties>
|
||||||
<maven.compiler.source>${java.version}</maven.compiler.source>
|
<maven.compiler.source>${java.version}</maven.compiler.source>
|
||||||
|
|||||||
2
pom.xml
2
pom.xml
@@ -10,7 +10,7 @@
|
|||||||
</parent>
|
</parent>
|
||||||
<groupId>com.ecep.contract</groupId>
|
<groupId>com.ecep.contract</groupId>
|
||||||
<artifactId>Contract-Manager</artifactId>
|
<artifactId>Contract-Manager</artifactId>
|
||||||
<version>0.0.58-SNAPSHOT</version>
|
<version>0.0.80-SNAPSHOT</version>
|
||||||
<packaging>pom</packaging>
|
<packaging>pom</packaging>
|
||||||
<modules>
|
<modules>
|
||||||
<module>server</module>
|
<module>server</module>
|
||||||
|
|||||||
@@ -6,12 +6,12 @@
|
|||||||
<parent>
|
<parent>
|
||||||
<groupId>com.ecep.contract</groupId>
|
<groupId>com.ecep.contract</groupId>
|
||||||
<artifactId>Contract-Manager</artifactId>
|
<artifactId>Contract-Manager</artifactId>
|
||||||
<version>0.0.58-SNAPSHOT</version>
|
<version>0.0.80-SNAPSHOT</version>
|
||||||
</parent>
|
</parent>
|
||||||
|
|
||||||
<groupId>com.ecep.contract</groupId>
|
<groupId>com.ecep.contract</groupId>
|
||||||
<artifactId>server</artifactId>
|
<artifactId>server</artifactId>
|
||||||
<version>0.0.58-SNAPSHOT</version>
|
<version>0.0.80-SNAPSHOT</version>
|
||||||
|
|
||||||
<properties>
|
<properties>
|
||||||
<maven.compiler.source>${java.version}</maven.compiler.source>
|
<maven.compiler.source>${java.version}</maven.compiler.source>
|
||||||
@@ -22,7 +22,7 @@
|
|||||||
<dependency>
|
<dependency>
|
||||||
<groupId>com.ecep.contract</groupId>
|
<groupId>com.ecep.contract</groupId>
|
||||||
<artifactId>common</artifactId>
|
<artifactId>common</artifactId>
|
||||||
<version>0.0.58-SNAPSHOT</version>
|
<version>0.0.80-SNAPSHOT</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.springframework.boot</groupId>
|
<groupId>org.springframework.boot</groupId>
|
||||||
@@ -75,6 +75,14 @@
|
|||||||
<!-- <scope>provided</scope> -->
|
<!-- <scope>provided</scope> -->
|
||||||
<!-- </dependency> -->
|
<!-- </dependency> -->
|
||||||
|
|
||||||
|
<!-- Servlet API -->
|
||||||
|
<dependency>
|
||||||
|
<groupId>javax.servlet</groupId>
|
||||||
|
<artifactId>javax.servlet-api</artifactId>
|
||||||
|
<version>4.0.1</version>
|
||||||
|
<scope>provided</scope>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>com.mysql</groupId>
|
<groupId>com.mysql</groupId>
|
||||||
<artifactId>mysql-connector-j</artifactId>
|
<artifactId>mysql-connector-j</artifactId>
|
||||||
|
|||||||
@@ -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<String, Object> 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<String, Object> 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<EmployeeAuthBind> authBinds = employeeAuthBindService.findAllByEmployee(employee, Sort.unsorted());
|
||||||
|
if (authBinds.isEmpty()) {
|
||||||
|
result.put("success", false);
|
||||||
|
result.put("error", "用户未绑定认证信息");
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
EmployeeAuthBind matched = null;
|
||||||
|
Map<String, String> 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<String, String> sign = new HashMap<>();
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -15,13 +15,15 @@ import org.springframework.web.method.annotation.MethodArgumentTypeMismatchExcep
|
|||||||
import org.springframework.web.servlet.NoHandlerFoundException;
|
import org.springframework.web.servlet.NoHandlerFoundException;
|
||||||
import org.springframework.web.servlet.mvc.support.DefaultHandlerExceptionResolver;
|
import org.springframework.web.servlet.mvc.support.DefaultHandlerExceptionResolver;
|
||||||
|
|
||||||
|
import java.io.PrintWriter;
|
||||||
|
import java.io.StringWriter;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 全局异常处理器,捕获并处理所有Controller层抛出的异常,将错误信息以JSON格式返回给前端
|
* 全局异常处理器,捕获并处理所有Controller层抛出的异常,将错误信息以JSON格式返回给前端
|
||||||
*/
|
*/
|
||||||
// @RestControllerAdvice
|
@RestControllerAdvice
|
||||||
public class GlobalExceptionHandler {
|
public class GlobalExceptionHandler {
|
||||||
|
|
||||||
private static final Logger logger = LoggerFactory.getLogger(GlobalExceptionHandler.class);
|
private static final Logger logger = LoggerFactory.getLogger(GlobalExceptionHandler.class);
|
||||||
@@ -36,10 +38,25 @@ public class GlobalExceptionHandler {
|
|||||||
result.put("code", 500);
|
result.put("code", 500);
|
||||||
result.put("message", "系统内部错误:" + e.getMessage());
|
result.put("message", "系统内部错误:" + e.getMessage());
|
||||||
result.put("errorType", e.getClass().getName());
|
result.put("errorType", e.getClass().getName());
|
||||||
|
result.put("stackTrace", getStackTraceAsString(e));
|
||||||
result.put("success", false);
|
result.put("success", false);
|
||||||
return new ResponseEntity<>(result, HttpStatus.INTERNAL_SERVER_ERROR);
|
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("code", 500);
|
||||||
result.put("message", "运行时错误:" + e.getMessage());
|
result.put("message", "运行时错误:" + e.getMessage());
|
||||||
result.put("errorType", e.getClass().getName());
|
result.put("errorType", e.getClass().getName());
|
||||||
|
result.put("stackTrace", getStackTraceAsString(e));
|
||||||
result.put("success", false);
|
result.put("success", false);
|
||||||
return new ResponseEntity<>(result, HttpStatus.INTERNAL_SERVER_ERROR);
|
return new ResponseEntity<>(result, HttpStatus.INTERNAL_SERVER_ERROR);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -51,8 +51,8 @@ public class SecurityConfig {
|
|||||||
http
|
http
|
||||||
.authorizeHttpRequests(authorize -> authorize
|
.authorizeHttpRequests(authorize -> authorize
|
||||||
.requestMatchers("/login.html", "/css/**", "/js/**", "/images/**", "/webjars/**", "/login",
|
.requestMatchers("/login.html", "/css/**", "/js/**", "/images/**", "/webjars/**", "/login",
|
||||||
"/error")
|
"/error", "/api/login")
|
||||||
.permitAll() // 允许静态资源、登录页面和错误页面访问
|
.permitAll() // 允许静态资源、登录页面、错误页面和JSON登录API访问
|
||||||
.anyRequest().authenticated() // 其他所有请求需要认证
|
.anyRequest().authenticated() // 其他所有请求需要认证
|
||||||
)
|
)
|
||||||
.csrf(AbstractHttpConfigurer::disable) // 禁用CSRF保护,适合开发环境
|
.csrf(AbstractHttpConfigurer::disable) // 禁用CSRF保护,适合开发环境
|
||||||
|
|||||||
@@ -1,6 +1,9 @@
|
|||||||
package com.ecep.contract.ds.other.controller;
|
package com.ecep.contract.ds.other.controller;
|
||||||
|
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
import java.util.HashMap;
|
||||||
|
|
||||||
|
import jakarta.servlet.http.HttpSession;
|
||||||
|
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
import org.springframework.data.domain.Page;
|
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.Pageable;
|
||||||
import org.springframework.data.domain.Sort;
|
import org.springframework.data.domain.Sort;
|
||||||
import org.springframework.data.jpa.domain.Specification;
|
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.RequestMapping;
|
||||||
import org.springframework.web.bind.annotation.RequestParam;
|
import org.springframework.web.bind.annotation.RequestParam;
|
||||||
import org.springframework.web.bind.annotation.RestController;
|
import org.springframework.web.bind.annotation.RestController;
|
||||||
@@ -50,4 +54,35 @@ public class EmployeeController {
|
|||||||
employeeService.delete(employee);
|
employeeService.delete(employee);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取当前登录用户的信息
|
||||||
|
* 包括employeeId和sessionId
|
||||||
|
*/
|
||||||
|
@RequestMapping("/currentUser")
|
||||||
|
public Map<String, Object> getCurrentUser(HttpSession session) {
|
||||||
|
Map<String, Object> 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;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,21 +4,14 @@ import java.util.List;
|
|||||||
|
|
||||||
import org.springframework.context.annotation.Lazy;
|
import org.springframework.context.annotation.Lazy;
|
||||||
import org.springframework.data.domain.Sort;
|
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 org.springframework.stereotype.Repository;
|
||||||
|
|
||||||
|
import com.ecep.contract.ds.MyRepository;
|
||||||
import com.ecep.contract.model.Employee;
|
import com.ecep.contract.model.Employee;
|
||||||
import com.ecep.contract.model.EmployeeAuthBind;
|
import com.ecep.contract.model.EmployeeAuthBind;
|
||||||
|
|
||||||
@Lazy
|
@Lazy
|
||||||
@Repository
|
@Repository
|
||||||
public interface EmployeeAuthBindRepository extends
|
public interface EmployeeAuthBindRepository extends MyRepository<EmployeeAuthBind, Integer> {
|
||||||
// JDBC interfaces
|
|
||||||
CrudRepository<EmployeeAuthBind, Integer>, PagingAndSortingRepository<EmployeeAuthBind, Integer>,
|
|
||||||
// JPA interfaces
|
|
||||||
JpaRepository<EmployeeAuthBind, Integer>, JpaSpecificationExecutor<EmployeeAuthBind> {
|
|
||||||
List<EmployeeAuthBind> findAllByEmployee(Employee employee, Sort sort);
|
List<EmployeeAuthBind> findAllByEmployee(Employee employee, Sort sort);
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user