新增ws实现打印调用

This commit is contained in:
lifangliang 2025-06-24 13:48:15 +08:00
parent 3c9095bff4
commit 676c135121
3 changed files with 238 additions and 0 deletions

View File

@ -0,0 +1,22 @@
package com.goeing.printserver.main.domain.dto;
import lombok.Data;
import java.time.LocalDateTime;
@Data
public class WebSocketMessageDTO {
// 消息内容
private String payload;
// 消息时间戳
private LocalDateTime timestamp;
// 消息类型可选
private String type;
//请求id
private String requestId;
}

View File

@ -0,0 +1,213 @@
package com.goeing.printserver.main.sse;
import cn.hutool.extra.spring.SpringUtil;
import cn.hutool.json.JSONUtil;
import com.alibaba.fastjson.JSON;
import com.goeing.printserver.main.PrintController;
import com.goeing.printserver.main.domain.dto.WebSocketMessageDTO;
import com.goeing.printserver.main.domain.request.PrintRequest;
import jakarta.websocket.*;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.ApplicationArguments;
import org.springframework.boot.ApplicationRunner;
import org.springframework.stereotype.Component;
import jakarta.annotation.PreDestroy;
import javax.print.PrintService;
import java.awt.print.PrinterJob;
import java.io.IOException;
import java.net.URI;
import java.util.*;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;
@ClientEndpoint
@Component
@Slf4j
public class PrinterClient implements ApplicationRunner {
private Session session;
@Value("${print.printer.id}")
private String printerId;
@Value("${print.websocket.url}")
private String serverUri;
@Value("${print.websocket.apiKey}")
private String apiKey;
private final ScheduledExecutorService reconnectExecutor = Executors.newSingleThreadScheduledExecutor();
private final ScheduledExecutorService heartbeatExecutor = Executors.newSingleThreadScheduledExecutor();
private boolean isConnecting = false;
// 无参构造函数由Spring管理
public PrinterClient() {
// 构造函数不做连接操作在run方法中进行连接
}
@OnOpen
public void onOpen(Session session) {
this.session = session;
log.info("WebSocket连接已建立");
isConnecting = false;
}
@OnMessage
public void onMessage(String message, Session session) {
log.info("收到消息: {}", message);
try {
// 解析消息
WebSocketMessageDTO webSocketMessageDTO = JSON.parseObject(message, WebSocketMessageDTO.class);
String type = webSocketMessageDTO.getType();
if ("print".equals(type)) {
String payload = webSocketMessageDTO.getPayload();
PrintRequest printRequest = JSONUtil.toBean(payload, PrintRequest.class);
PrintController bean = SpringUtil.getBean(PrintController.class);
// 处理打印任务
log.info("收到打印任务: {}, ", printRequest);
try {
bean.print(printRequest);
log.info("打印任务完成: {}", printRequest.getFileUrl());
Map<String,String> map = new HashMap<>();
map.put("status", "success");
map.put("msg", "");
webSocketMessageDTO.setType("RESPONSE");
webSocketMessageDTO.setPayload(JSONUtil.toJsonStr(map));
session.getBasicRemote().sendText(JSONUtil.toJsonStr(webSocketMessageDTO));
} catch (Exception e) {
log.error("打印失败: {}", printRequest.getFileUrl(), e);
// 发送打印失败消息
String errorMsg = e.getMessage();
if (errorMsg == null) {
errorMsg = "未知错误";
} else {
// 转义JSON特殊字符
errorMsg = errorMsg.replace("\\", "\\\\").replace("\"", "\\\"").replace("\n", "\\n");
}
Map<String,String> map = new HashMap<>();
map.put("status", "fail");
map.put("msg", errorMsg);
webSocketMessageDTO.setType("RESPONSE");
webSocketMessageDTO.setPayload(JSONUtil.toJsonStr(map));
session.getBasicRemote().sendText(JSONUtil.toJsonStr(webSocketMessageDTO));
}
} else if ("heartbeat_ack".equals(type)) {
// 心跳响应可以记录最后一次心跳时间
log.debug("收到心跳响应");
}else if ("printerList".equals(type)) {
PrintService[] printServices = PrinterJob.lookupPrintServices();
Set<String> collect = Arrays.stream(printServices).map(PrintService::getName).collect(Collectors.toSet());
List<String> collect1 = collect.stream().sorted().collect(Collectors.toList());
webSocketMessageDTO.setType("RESPONSE");
webSocketMessageDTO.setPayload(JSONUtil.toJsonStr(collect1));
session.getBasicRemote().sendText(JSONUtil.toJsonStr(webSocketMessageDTO));
}
} catch (Exception e) {
log.error("处理消息失败", e);
}
}
@OnClose
public void onClose(Session session, CloseReason closeReason) {
log.warn("WebSocket连接关闭: {}", closeReason.getReasonPhrase());
this.session = null;
// 安排重连任务
scheduleReconnect();
}
@OnError
public void onError(Session session, Throwable throwable) {
log.error("WebSocket连接发生错误", throwable);
this.session = null;
// 安排重连任务
scheduleReconnect();
}
/**
* 连接到WebSocket服务器
*/
private void connect() {
if (isConnecting || (session != null && session.isOpen())) {
return; // 已经连接或正在连接中
}
String tempUrl = serverUri+"?printerId="+printerId+"&apiKey="+apiKey;
isConnecting = true;
try {
log.info("正在连接到WebSocket服务器: {}", tempUrl);
WebSocketContainer container = ContainerProvider.getWebSocketContainer();
// 设置连接超时时间
container.setDefaultMaxSessionIdleTimeout(60000);
container.connectToServer(this, new URI(tempUrl));
} catch (Exception e) {
log.error("连接到WebSocket服务器失败", e);
isConnecting = false;
// 连接失败安排重连
scheduleReconnect();
}
}
/**
* 启动心跳机制
*/
private void startHeartbeat() {
heartbeatExecutor.scheduleAtFixedRate(() -> {
if (session != null && session.isOpen()) {
try {
session.getBasicRemote().sendText("{\"type\":\"heartbeat\"}");
log.debug("发送心跳");
} catch (IOException e) {
log.error("发送心跳失败", e);
}
}
}, 30, 30, TimeUnit.SECONDS);
log.info("心跳机制已启动");
}
/**
* 安排重连任务
*/
private void scheduleReconnect() {
reconnectExecutor.schedule(() -> {
log.info("尝试重新连接到WebSocket服务器...");
connect();
}, 5, TimeUnit.SECONDS);
}
/**
* 关闭连接和资源
*/
@PreDestroy
public void shutdown() {
log.info("正在关闭WebSocket客户端...");
if (session != null) {
try {
session.close();
} catch (Exception e) {
log.error("关闭WebSocket连接失败", e);
}
}
reconnectExecutor.shutdownNow();
heartbeatExecutor.shutdownNow();
log.info("WebSocket客户端已关闭");
}
@Override
public void run(ApplicationArguments args) {
// 应用启动后连接到WebSocket服务器
connect();
}
}

View File

@ -1,3 +1,6 @@
spring.application.name=goeingPrintServer
server.port=9090
print.websocket.url=ws://127.0.0.1:8080/print-websocket
print.printer.id=123456
print.websocket.apiKey=519883ab-3677-ce4b-59ba-7263870d0a26