Compare commits
14
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
191c6dfce7 | ||
|
|
478f8c4549 | ||
|
|
41ad507f68 | ||
|
|
93bef5c0ea | ||
|
|
d00cf7a5c2 | ||
|
|
ae2f6366c4 | ||
|
|
cf8e27d18f | ||
|
|
5978de5534 | ||
|
|
0724f442e6 | ||
|
|
9f2a6e56ff | ||
|
|
b55b4e87a6 | ||
|
|
8a43ac80cf | ||
|
|
b3a3d7fad9 | ||
|
|
dd3f70c324 |
@@ -10,39 +10,8 @@ import org.slf4j.LoggerFactory;
|
|||||||
|
|
||||||
@SpringBootApplication
|
@SpringBootApplication
|
||||||
public class GoeingPrintServerApplication {
|
public class GoeingPrintServerApplication {
|
||||||
|
|
||||||
private static final Logger log = LoggerFactory.getLogger(GoeingPrintServerApplication.class);
|
|
||||||
|
|
||||||
public static void main(String[] args) {
|
public static void main(String[] args) {
|
||||||
// 检查是否在macOS系统上运行
|
SpringApplication.run(GoeingPrintServerApplication.class, args);
|
||||||
String osName = System.getProperty("os.name").toLowerCase();
|
|
||||||
boolean isMacOS = osName.contains("mac");
|
|
||||||
|
|
||||||
// 检查是否已经设置了java.awt.headless系统属性
|
|
||||||
String headlessProperty = System.getProperty("java.awt.headless");
|
|
||||||
|
|
||||||
// 如果是macOS并且没有明确设置headless属性,可能需要特殊处理
|
|
||||||
if (isMacOS && headlessProperty == null) {
|
|
||||||
log.info("在macOS系统上运行,检查是否需要启用无头模式");
|
|
||||||
|
|
||||||
// 检查是否支持图形界面
|
|
||||||
if (GraphicsEnvironment.isHeadless()) {
|
|
||||||
log.warn("检测到系统不支持图形界面,自动启用无头模式");
|
|
||||||
System.setProperty("java.awt.headless", "true");
|
|
||||||
System.setProperty("app.headless.mode", "true");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
ConfigurableApplicationContext context = SpringApplication.run(GoeingPrintServerApplication.class, args);
|
|
||||||
|
|
||||||
// 从配置中读取是否强制使用无头模式
|
|
||||||
Environment env = context.getEnvironment();
|
|
||||||
boolean forceHeadless = Boolean.parseBoolean(env.getProperty("app.force.headless", "false"));
|
|
||||||
|
|
||||||
if (forceHeadless) {
|
|
||||||
log.info("根据配置强制启用无头模式");
|
|
||||||
System.setProperty("java.awt.headless", "true");
|
|
||||||
System.setProperty("app.headless.mode", "true");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ import com.goeing.printserver.main.domain.request.PrintRequest;
|
|||||||
import com.goeing.printserver.main.service.PrintQueueService;
|
import com.goeing.printserver.main.service.PrintQueueService;
|
||||||
import com.goeing.printserver.main.service.PrintService;
|
import com.goeing.printserver.main.service.PrintService;
|
||||||
import com.goeing.printserver.main.utils.PdfPrinter;
|
import com.goeing.printserver.main.utils.PdfPrinter;
|
||||||
|
import com.goeing.printserver.main.ws.PrinterClient;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
import org.springframework.web.bind.annotation.*;
|
import org.springframework.web.bind.annotation.*;
|
||||||
@@ -15,13 +16,12 @@ import org.springframework.web.bind.annotation.*;
|
|||||||
// 使用完全限定名称避免与自定义PrintService接口冲突
|
// 使用完全限定名称避免与自定义PrintService接口冲突
|
||||||
import java.awt.print.PrinterJob;
|
import java.awt.print.PrinterJob;
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.time.LocalDateTime;
|
import java.time.format.DateTimeFormatter;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Set;
|
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
@RestController
|
@RestController
|
||||||
@@ -35,7 +35,10 @@ public class PrintController implements PrintService {
|
|||||||
@Autowired
|
@Autowired
|
||||||
private PrintServerConfig config;
|
private PrintServerConfig config;
|
||||||
|
|
||||||
private final String rootPath = "pdfTemp";
|
@Autowired
|
||||||
|
private PrinterClient printerClient;
|
||||||
|
|
||||||
|
private final String rootPath = System.getProperty("java.io.tmpdir") + File.separator + "goeingprint" + File.separator + "pdfTemp";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 获取所有可用打印机列表
|
* 获取所有可用打印机列表
|
||||||
@@ -104,6 +107,51 @@ public class PrintController implements PrintService {
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 清空打印队列
|
||||||
|
*
|
||||||
|
* @return 清空结果
|
||||||
|
*/
|
||||||
|
@DeleteMapping("queue/clear")
|
||||||
|
public Map<String, Object> clearQueue() {
|
||||||
|
int clearedCount = printQueueService.clearQueue();
|
||||||
|
Map<String, Object> result = new HashMap<>();
|
||||||
|
result.put("success", true);
|
||||||
|
result.put("clearedCount", clearedCount);
|
||||||
|
result.put("message", "队列已清空,共清空 " + clearedCount + " 个任务");
|
||||||
|
result.put("timestamp", System.currentTimeMillis());
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 取消单个任务
|
||||||
|
*
|
||||||
|
* @param taskId 任务ID
|
||||||
|
* @return 取消结果
|
||||||
|
*/
|
||||||
|
@DeleteMapping("queue/task/{taskId}")
|
||||||
|
public Map<String, Object> cancelTask(@PathVariable String taskId) {
|
||||||
|
Map<String, Object> result = new HashMap<>();
|
||||||
|
try {
|
||||||
|
boolean cancelled = printQueueService.cancelTask(taskId);
|
||||||
|
if (cancelled) {
|
||||||
|
result.put("success", true);
|
||||||
|
result.put("message", "任务已取消");
|
||||||
|
result.put("taskId", taskId);
|
||||||
|
} else {
|
||||||
|
result.put("success", false);
|
||||||
|
result.put("message", "未找到指定任务");
|
||||||
|
result.put("taskId", taskId);
|
||||||
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
result.put("success", false);
|
||||||
|
result.put("message", "取消任务失败: " + e.getMessage());
|
||||||
|
result.put("taskId", taskId);
|
||||||
|
}
|
||||||
|
result.put("timestamp", System.currentTimeMillis());
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 搜索打印任务
|
* 搜索打印任务
|
||||||
*
|
*
|
||||||
@@ -142,7 +190,13 @@ public class PrintController implements PrintService {
|
|||||||
taskMap.put("fileName", extractFileName(task.getFileUrl()));
|
taskMap.put("fileName", extractFileName(task.getFileUrl()));
|
||||||
taskMap.put("printer", task.getPrinter());
|
taskMap.put("printer", task.getPrinter());
|
||||||
taskMap.put("status", task.getStatus());
|
taskMap.put("status", task.getStatus());
|
||||||
taskMap.put("createTime", task.getQueuedTime());
|
// 格式化创建时间为 yyyy-MM-dd HH:mm:ss
|
||||||
|
if (task.getQueuedTime() != null) {
|
||||||
|
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
|
||||||
|
taskMap.put("createTime", task.getQueuedTime().format(formatter));
|
||||||
|
} else {
|
||||||
|
taskMap.put("createTime", "N/A");
|
||||||
|
}
|
||||||
taskMap.put("fileUrl", task.getFileUrl());
|
taskMap.put("fileUrl", task.getFileUrl());
|
||||||
return taskMap;
|
return taskMap;
|
||||||
})
|
})
|
||||||
@@ -194,6 +248,65 @@ public class PrintController implements PrintService {
|
|||||||
return settings;
|
return settings;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取打印机连接状态
|
||||||
|
*
|
||||||
|
* @return 包含各种连接状态的详细信息
|
||||||
|
*/
|
||||||
|
@GetMapping("printers/status")
|
||||||
|
public Map<String, Object> getPrintersStatus() {
|
||||||
|
Map<String, Object> status = new HashMap<>();
|
||||||
|
|
||||||
|
// Java后端服务状态
|
||||||
|
Map<String, Object> backendStatus = new HashMap<>();
|
||||||
|
backendStatus.put("status", "connected");
|
||||||
|
backendStatus.put("uptime", getUptime());
|
||||||
|
backendStatus.put("timestamp", System.currentTimeMillis());
|
||||||
|
status.put("backend", backendStatus);
|
||||||
|
|
||||||
|
// WebSocket连接状态
|
||||||
|
Map<String, Object> websocketStatus = new HashMap<>();
|
||||||
|
boolean isWebSocketConnected = printerClient.isConnected();
|
||||||
|
websocketStatus.put("status", isWebSocketConnected ? "connected" : "disconnected");
|
||||||
|
websocketStatus.put("url", config.getWebsocketUrl());
|
||||||
|
websocketStatus.put("printerId", config.getPrinterId());
|
||||||
|
if (isWebSocketConnected) {
|
||||||
|
websocketStatus.put("connectionUrl", printerClient.getCurrentConnectionUrl());
|
||||||
|
}
|
||||||
|
websocketStatus.put("timestamp", System.currentTimeMillis());
|
||||||
|
status.put("websocket", websocketStatus);
|
||||||
|
|
||||||
|
// 本地打印机状态
|
||||||
|
Map<String, Object> printersStatus = new HashMap<>();
|
||||||
|
javax.print.PrintService[] printServices = PrinterJob.lookupPrintServices();
|
||||||
|
List<Map<String, Object>> printerList = Arrays.stream(printServices)
|
||||||
|
.map(service -> {
|
||||||
|
Map<String, Object> printer = new HashMap<>();
|
||||||
|
printer.put("name", service.getName());
|
||||||
|
printer.put("status", "available"); // 简化处理,假设所有检测到的打印机都可用
|
||||||
|
printer.put("isDefault", service.getName().equals(config.getDefaultPrinter()));
|
||||||
|
return printer;
|
||||||
|
})
|
||||||
|
.sorted((a, b) -> ((String) a.get("name")).compareTo((String) b.get("name")))
|
||||||
|
.collect(Collectors.toList());
|
||||||
|
|
||||||
|
printersStatus.put("count", printerList.size());
|
||||||
|
printersStatus.put("printers", printerList);
|
||||||
|
printersStatus.put("defaultPrinter", config.getDefaultPrinter());
|
||||||
|
printersStatus.put("timestamp", System.currentTimeMillis());
|
||||||
|
status.put("localPrinters", printersStatus);
|
||||||
|
|
||||||
|
// 打印队列状态
|
||||||
|
Map<String, Object> queueStatus = new HashMap<>();
|
||||||
|
queueStatus.put("queueSize", printQueueService.getQueueSize());
|
||||||
|
queueStatus.put("maxQueueSize", printQueueService.getMaxQueueSize());
|
||||||
|
queueStatus.put("currentTask", printQueueService.getCurrentTaskInfo());
|
||||||
|
queueStatus.put("timestamp", System.currentTimeMillis());
|
||||||
|
status.put("queue", queueStatus);
|
||||||
|
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 保存系统设置
|
* 保存系统设置
|
||||||
*
|
*
|
||||||
@@ -203,18 +316,76 @@ public class PrintController implements PrintService {
|
|||||||
@PostMapping("settings")
|
@PostMapping("settings")
|
||||||
public Map<String, String> saveSystemSettings(@RequestBody Map<String, Object> settings) {
|
public Map<String, String> saveSystemSettings(@RequestBody Map<String, Object> settings) {
|
||||||
try {
|
try {
|
||||||
|
boolean needReconnect = false;
|
||||||
|
|
||||||
// 更新最大队列大小
|
// 更新最大队列大小
|
||||||
if (settings.containsKey("maxQueueSize")) {
|
if (settings.containsKey("maxQueueSize")) {
|
||||||
int maxQueueSize = (Integer) settings.get("maxQueueSize");
|
int maxQueueSize = (Integer) settings.get("maxQueueSize");
|
||||||
printQueueService.setMaxQueueSize(maxQueueSize);
|
printQueueService.setMaxQueueSize(maxQueueSize);
|
||||||
|
config.setMaxQueueSize(maxQueueSize);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 更新默认打印机
|
||||||
|
if (settings.containsKey("defaultPrinter")) {
|
||||||
|
String defaultPrinter = (String) settings.get("defaultPrinter");
|
||||||
|
config.setDefaultPrinter(defaultPrinter);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 更新通知设置
|
||||||
|
if (settings.containsKey("enableNotifications")) {
|
||||||
|
boolean enableNotifications = (Boolean) settings.get("enableNotifications");
|
||||||
|
config.setEnableNotifications(enableNotifications);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 更新自动启动设置
|
||||||
|
if (settings.containsKey("autoStart")) {
|
||||||
|
boolean autoStart = (Boolean) settings.get("autoStart");
|
||||||
|
config.setAutoStart(autoStart);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 更新WebSocket URL(需要重连)
|
||||||
|
if (settings.containsKey("websocketUrl")) {
|
||||||
|
String websocketUrl = (String) settings.get("websocketUrl");
|
||||||
|
if (!websocketUrl.equals(config.getWebsocketUrl())) {
|
||||||
|
config.setWebsocketUrl(websocketUrl);
|
||||||
|
needReconnect = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 更新打印机ID(需要重连)
|
||||||
|
if (settings.containsKey("printerId")) {
|
||||||
|
String printerId = (String) settings.get("printerId");
|
||||||
|
if (!printerId.equals(config.getPrinterId())) {
|
||||||
|
config.setPrinterId(printerId);
|
||||||
|
needReconnect = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 更新API Key(需要重连)
|
||||||
|
if (settings.containsKey("apiKey")) {
|
||||||
|
String apiKey = (String) settings.get("apiKey");
|
||||||
|
if (!apiKey.equals(config.getApiKey())) {
|
||||||
|
config.setApiKey(apiKey);
|
||||||
|
needReconnect = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 保存配置到文件
|
||||||
|
config.saveConfig();
|
||||||
|
|
||||||
|
// 如果WebSocket相关配置发生变化,触发重连
|
||||||
|
if (needReconnect) {
|
||||||
|
log.info("WebSocket配置已更改,正在重新连接...");
|
||||||
|
printerClient.reconnect();
|
||||||
|
} else {
|
||||||
|
log.info("WebSocket配置未更改,无需重连");
|
||||||
}
|
}
|
||||||
|
|
||||||
// 这里可以添加其他设置的保存逻辑
|
|
||||||
log.info("系统设置已保存: {}", settings);
|
log.info("系统设置已保存: {}", settings);
|
||||||
|
|
||||||
Map<String, String> result = new HashMap<>();
|
Map<String, String> result = new HashMap<>();
|
||||||
result.put("status", "success");
|
result.put("status", "success");
|
||||||
result.put("message", "设置保存成功");
|
result.put("message", "设置保存成功" + (needReconnect ? ",WebSocket正在重新连接" : ""));
|
||||||
return result;
|
return result;
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
log.error("保存系统设置失败", e);
|
log.error("保存系统设置失败", e);
|
||||||
@@ -225,36 +396,6 @@ public class PrintController implements PrintService {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* 获取系统日志
|
|
||||||
*
|
|
||||||
* @return 系统日志列表
|
|
||||||
*/
|
|
||||||
@GetMapping("logs")
|
|
||||||
public List<Map<String, Object>> getSystemLogs() {
|
|
||||||
// 这里返回模拟的日志数据,实际项目中可以集成日志框架
|
|
||||||
List<Map<String, Object>> logs = new ArrayList<>();
|
|
||||||
|
|
||||||
Map<String, Object> log1 = new HashMap<>();
|
|
||||||
log1.put("level", "info");
|
|
||||||
log1.put("time", LocalDateTime.now().minusHours(1).toString());
|
|
||||||
log1.put("message", "打印服务启动成功");
|
|
||||||
logs.add(log1);
|
|
||||||
|
|
||||||
Map<String, Object> log2 = new HashMap<>();
|
|
||||||
log2.put("level", "info");
|
|
||||||
log2.put("time", LocalDateTime.now().minusMinutes(30).toString());
|
|
||||||
log2.put("message", "连接到打印机: " + (config.getDefaultPrinter() != null ? config.getDefaultPrinter() : "默认打印机"));
|
|
||||||
logs.add(log2);
|
|
||||||
|
|
||||||
Map<String, Object> log3 = new HashMap<>();
|
|
||||||
log3.put("level", "info");
|
|
||||||
log3.put("time", LocalDateTime.now().minusMinutes(10).toString());
|
|
||||||
log3.put("message", "当前队列大小: " + printQueueService.getQueueSize());
|
|
||||||
logs.add(log3);
|
|
||||||
|
|
||||||
return logs;
|
|
||||||
}
|
|
||||||
|
|
||||||
@PostMapping("print")
|
@PostMapping("print")
|
||||||
public String print(@RequestBody PrintRequest request) {
|
public String print(@RequestBody PrintRequest request) {
|
||||||
@@ -304,7 +445,7 @@ public class PrintController implements PrintService {
|
|||||||
log.info("正在从以下地址下载文件: {}", fileUrl);
|
log.info("正在从以下地址下载文件: {}", fileUrl);
|
||||||
HttpUtil.downloadFile(fileUrl, filePath);
|
HttpUtil.downloadFile(fileUrl, filePath);
|
||||||
|
|
||||||
log.info("文件下载地址为:",filePath);
|
log.info("文件下载地址为:{}",filePath);
|
||||||
|
|
||||||
if (!pdfFile.exists() || pdfFile.length() == 0) {
|
if (!pdfFile.exists() || pdfFile.length() == 0) {
|
||||||
throw new RuntimeException("Downloaded file is empty or does not exist");
|
throw new RuntimeException("Downloaded file is empty or does not exist");
|
||||||
|
|||||||
@@ -0,0 +1,38 @@
|
|||||||
|
// LogbackConfig.java
|
||||||
|
package com.goeing.printserver.main.config;
|
||||||
|
|
||||||
|
import ch.qos.logback.classic.LoggerContext;
|
||||||
|
import ch.qos.logback.classic.Logger;
|
||||||
|
import com.goeing.printserver.main.utils.MemoryLogAppender;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.context.annotation.Configuration;
|
||||||
|
|
||||||
|
import jakarta.annotation.PostConstruct;
|
||||||
|
|
||||||
|
@Configuration
|
||||||
|
public class LogbackConfig {
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private MemoryLogAppender memoryLogAppender;
|
||||||
|
|
||||||
|
@PostConstruct
|
||||||
|
public void registerAppender() {
|
||||||
|
LoggerContext context = (LoggerContext) LoggerFactory.getILoggerFactory();
|
||||||
|
|
||||||
|
// 将 Spring 管理的 appender 关联到 Logback 的上下文
|
||||||
|
memoryLogAppender.setContext(context);
|
||||||
|
|
||||||
|
// / 添加 appender 到 root logger(供其它包使用)
|
||||||
|
Logger rootLogger = context.getLogger(org.slf4j.Logger.ROOT_LOGGER_NAME);
|
||||||
|
rootLogger.addAppender(memoryLogAppender);
|
||||||
|
|
||||||
|
// 同时添加到 com.goeing.printserver 包级 logger(该 logger 配置了 additivity=false)
|
||||||
|
Logger appLogger = context.getLogger("com.goeing.printserver");
|
||||||
|
appLogger.addAppender(memoryLogAppender);
|
||||||
|
|
||||||
|
// 启动 appender
|
||||||
|
memoryLogAppender.start();
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -50,6 +50,7 @@ public class PrintServerConfig {
|
|||||||
// 确定配置文件路径
|
// 确定配置文件路径
|
||||||
String userHome = System.getProperty("user.home");
|
String userHome = System.getProperty("user.home");
|
||||||
configFile = new File(userHome + File.separator + ".goeing" + File.separator + CONFIG_FILE);
|
configFile = new File(userHome + File.separator + ".goeing" + File.separator + CONFIG_FILE);
|
||||||
|
// System.out.println(configFile.getAbsolutePath());
|
||||||
|
|
||||||
// 确保目录存在
|
// 确保目录存在
|
||||||
if (!configFile.getParentFile().exists()) {
|
if (!configFile.getParentFile().exists()) {
|
||||||
@@ -78,7 +79,7 @@ public class PrintServerConfig {
|
|||||||
printerId = properties.getProperty("printerId", DEFAULT_PRINTER_ID);
|
printerId = properties.getProperty("printerId", DEFAULT_PRINTER_ID);
|
||||||
apiKey = properties.getProperty("apiKey", DEFAULT_API_KEY);
|
apiKey = properties.getProperty("apiKey", DEFAULT_API_KEY);
|
||||||
|
|
||||||
log.info("配置已加载: {}", configFile.getAbsolutePath());
|
log.info("配置已加载: {}, WebSocket URL: {}, PrinterId: {}", configFile.getAbsolutePath(), websocketUrl, printerId);
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
log.error("加载配置文件失败", e);
|
log.error("加载配置文件失败", e);
|
||||||
// 使用默认值
|
// 使用默认值
|
||||||
@@ -101,7 +102,10 @@ public class PrintServerConfig {
|
|||||||
*/
|
*/
|
||||||
public void saveConfig() {
|
public void saveConfig() {
|
||||||
try {
|
try {
|
||||||
// 更新属性
|
// 确保目录存在
|
||||||
|
configFile.getParentFile().mkdirs();
|
||||||
|
|
||||||
|
// 设置配置值
|
||||||
properties.setProperty("defaultPrinter", defaultPrinter);
|
properties.setProperty("defaultPrinter", defaultPrinter);
|
||||||
properties.setProperty("maxQueueSize", String.valueOf(maxQueueSize));
|
properties.setProperty("maxQueueSize", String.valueOf(maxQueueSize));
|
||||||
properties.setProperty("enableNotifications", String.valueOf(enableNotifications));
|
properties.setProperty("enableNotifications", String.valueOf(enableNotifications));
|
||||||
@@ -113,9 +117,10 @@ public class PrintServerConfig {
|
|||||||
|
|
||||||
// 保存到文件
|
// 保存到文件
|
||||||
try (FileOutputStream fos = new FileOutputStream(configFile)) {
|
try (FileOutputStream fos = new FileOutputStream(configFile)) {
|
||||||
properties.store(fos, "Goeing Print Server Configuration");
|
properties.store(fos, "Print Server Configuration");
|
||||||
log.info("配置已保存: {}", configFile.getAbsolutePath());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
log.info("配置已保存: {}, WebSocket URL: {}, PrinterId: {}", configFile.getAbsolutePath(), websocketUrl, printerId);
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
log.error("保存配置文件失败", e);
|
log.error("保存配置文件失败", e);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,74 @@
|
|||||||
|
package com.goeing.printserver.main.controller;
|
||||||
|
|
||||||
|
import com.goeing.printserver.main.utils.MemoryLogAppender;
|
||||||
|
import com.goeing.printserver.main.utils.MemoryLogStorage;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.web.bind.annotation.*;
|
||||||
|
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 日志控制器,提供日志相关的 API 接口
|
||||||
|
*/
|
||||||
|
@RestController
|
||||||
|
@RequestMapping("/api/logs")
|
||||||
|
@Slf4j
|
||||||
|
public class LogController {
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private MemoryLogStorage memoryLogStorage;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取系统日志
|
||||||
|
* @param limit 限制数量,默认100
|
||||||
|
* @param level 日志级别过滤,默认ALL
|
||||||
|
* @return 日志列表
|
||||||
|
*/
|
||||||
|
@GetMapping
|
||||||
|
public Map<String, Object> getLogs(
|
||||||
|
@RequestParam(defaultValue = "100") int limit,
|
||||||
|
@RequestParam(defaultValue = "ALL") String level) {
|
||||||
|
|
||||||
|
Map<String, Object> result = new HashMap<>();
|
||||||
|
|
||||||
|
try {
|
||||||
|
List<MemoryLogAppender.LogEntry> logs = memoryLogStorage.getLogs(limit, level);
|
||||||
|
result.put("success", true);
|
||||||
|
result.put("logs", logs);
|
||||||
|
result.put("total", logs.size());
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.error("获取日志失败", e);
|
||||||
|
result.put("success", false);
|
||||||
|
result.put("message", "获取日志失败: " + e.getMessage());
|
||||||
|
result.put("logs", List.of());
|
||||||
|
result.put("total", 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 清空系统日志
|
||||||
|
* @return 操作结果
|
||||||
|
*/
|
||||||
|
@DeleteMapping
|
||||||
|
public Map<String, Object> clearLogs() {
|
||||||
|
Map<String, Object> result = new HashMap<>();
|
||||||
|
|
||||||
|
try {
|
||||||
|
memoryLogStorage.clearLogs();
|
||||||
|
result.put("success", true);
|
||||||
|
result.put("message", "日志已清空");
|
||||||
|
log.info("系统日志已被清空");
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.error("清空日志失败", e);
|
||||||
|
result.put("success", false);
|
||||||
|
result.put("message", "清空日志失败: " + e.getMessage());
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -4,6 +4,7 @@ import com.goeing.printserver.main.domain.bo.PrintOption;
|
|||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
|
|
||||||
import java.time.LocalDateTime;
|
import java.time.LocalDateTime;
|
||||||
|
import java.time.format.DateTimeFormatter;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
@@ -40,16 +41,27 @@ public class PrintTask {
|
|||||||
*/
|
*/
|
||||||
public Map<String, Object> toMap() {
|
public Map<String, Object> toMap() {
|
||||||
Map<String, Object> map = new HashMap<>();
|
Map<String, Object> map = new HashMap<>();
|
||||||
|
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
|
||||||
|
|
||||||
map.put("fileUrl", fileUrl);
|
map.put("fileUrl", fileUrl);
|
||||||
map.put("printerName", printer);
|
map.put("printerName", printer);
|
||||||
map.put("status", status);
|
map.put("status", status);
|
||||||
map.put("queuedTime", queuedTime);
|
|
||||||
|
// 格式化时间字段
|
||||||
|
if (queuedTime != null) {
|
||||||
|
map.put("queuedTime", queuedTime.format(formatter));
|
||||||
|
} else {
|
||||||
|
map.put("queuedTime", "N/A");
|
||||||
|
}
|
||||||
|
|
||||||
if (startTime != null) {
|
if (startTime != null) {
|
||||||
map.put("startTime", startTime);
|
map.put("startTime", startTime.format(formatter));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (endTime != null) {
|
if (endTime != null) {
|
||||||
map.put("endTime", endTime);
|
map.put("endTime", endTime.format(formatter));
|
||||||
}
|
}
|
||||||
|
|
||||||
return map;
|
return map;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -13,12 +13,12 @@ public class PrintOption {
|
|||||||
private String size;
|
private String size;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 打印颜色模式,如"Full Color", "Monochrome"等
|
* 打印颜色模式,如"Color", "Monochrome"等
|
||||||
*/
|
*/
|
||||||
private String color;
|
private String color;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 打印面设置,如"One-Sided", "Double-Sided"等
|
* 打印面设置,如"Single-Sided", "Double-Sided"等
|
||||||
*/
|
*/
|
||||||
private String sides;
|
private String sides;
|
||||||
|
|
||||||
|
|||||||
@@ -12,6 +12,7 @@ import org.springframework.context.annotation.Lazy;
|
|||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
import java.time.format.DateTimeFormatter;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
@@ -63,6 +64,7 @@ public class PrintQueueService {
|
|||||||
* 打印任务内部类,封装打印请求和WebSocket会话
|
* 打印任务内部类,封装打印请求和WebSocket会话
|
||||||
*/
|
*/
|
||||||
private static class PrintTask {
|
private static class PrintTask {
|
||||||
|
private final String id;
|
||||||
private final PrintRequest printRequest;
|
private final PrintRequest printRequest;
|
||||||
private final WebSocketMessageDTO messageDTO;
|
private final WebSocketMessageDTO messageDTO;
|
||||||
private final Session session;
|
private final Session session;
|
||||||
@@ -72,6 +74,7 @@ public class PrintQueueService {
|
|||||||
private String status; // queued, processing, completed, failed
|
private String status; // queued, processing, completed, failed
|
||||||
|
|
||||||
public PrintTask(PrintRequest printRequest, WebSocketMessageDTO messageDTO, Session session) {
|
public PrintTask(PrintRequest printRequest, WebSocketMessageDTO messageDTO, Session session) {
|
||||||
|
this.id = "TASK_" + System.currentTimeMillis() + "_" + (int)(Math.random() * 1000);
|
||||||
this.printRequest = printRequest;
|
this.printRequest = printRequest;
|
||||||
this.messageDTO = messageDTO;
|
this.messageDTO = messageDTO;
|
||||||
this.session = session;
|
this.session = session;
|
||||||
@@ -79,6 +82,10 @@ public class PrintQueueService {
|
|||||||
this.status = "queued";
|
this.status = "queued";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public String getId() {
|
||||||
|
return id;
|
||||||
|
}
|
||||||
|
|
||||||
public PrintRequest getPrintRequest() {
|
public PrintRequest getPrintRequest() {
|
||||||
return printRequest;
|
return printRequest;
|
||||||
}
|
}
|
||||||
@@ -121,16 +128,28 @@ public class PrintQueueService {
|
|||||||
|
|
||||||
public Map<String, Object> toMap() {
|
public Map<String, Object> toMap() {
|
||||||
Map<String, Object> map = new HashMap<>();
|
Map<String, Object> map = new HashMap<>();
|
||||||
|
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
|
||||||
|
|
||||||
|
map.put("id", id);
|
||||||
map.put("fileUrl", printRequest.getFileUrl());
|
map.put("fileUrl", printRequest.getFileUrl());
|
||||||
map.put("printerName", printRequest.getPrinterName());
|
map.put("printerName", printRequest.getPrinterName());
|
||||||
map.put("status", status);
|
map.put("status", status);
|
||||||
map.put("queuedTime", queuedTime);
|
|
||||||
|
// 格式化时间字段
|
||||||
|
if (queuedTime != null) {
|
||||||
|
map.put("queuedTime", queuedTime.format(formatter));
|
||||||
|
} else {
|
||||||
|
map.put("queuedTime", "N/A");
|
||||||
|
}
|
||||||
|
|
||||||
if (startTime != null) {
|
if (startTime != null) {
|
||||||
map.put("startTime", startTime);
|
map.put("startTime", startTime.format(formatter));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (endTime != null) {
|
if (endTime != null) {
|
||||||
map.put("endTime", endTime);
|
map.put("endTime", endTime.format(formatter));
|
||||||
}
|
}
|
||||||
|
|
||||||
return map;
|
return map;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -212,6 +231,7 @@ public class PrintQueueService {
|
|||||||
|
|
||||||
try {
|
try {
|
||||||
// 执行打印
|
// 执行打印
|
||||||
|
// Thread.sleep(20000L);
|
||||||
printService.print(printRequest);
|
printService.print(printRequest);
|
||||||
log.info("打印任务完成: {}", printRequest.getFileUrl());
|
log.info("打印任务完成: {}", printRequest.getFileUrl());
|
||||||
|
|
||||||
@@ -350,6 +370,43 @@ public class PrintQueueService {
|
|||||||
return maxQueueSize;
|
return maxQueueSize;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 清空打印队列
|
||||||
|
* 注意:此操作不会影响当前正在处理的任务
|
||||||
|
*
|
||||||
|
* @return 清空的任务数量
|
||||||
|
*/
|
||||||
|
public int clearQueue() {
|
||||||
|
int clearedCount = printQueue.size();
|
||||||
|
printQueue.clear();
|
||||||
|
log.info("打印队列已清空,共清空 {} 个任务", clearedCount);
|
||||||
|
return clearedCount;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 取消指定任务
|
||||||
|
* @param taskId 任务ID
|
||||||
|
* @return 是否成功取消
|
||||||
|
*/
|
||||||
|
public boolean cancelTask(String taskId) {
|
||||||
|
// 检查当前任务
|
||||||
|
if (currentTask != null && taskId.equals(currentTask.getId())) {
|
||||||
|
log.info("取消当前正在执行的任务: {}", taskId);
|
||||||
|
currentTask.setStatus("cancelled");
|
||||||
|
currentTask = null;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 从队列中移除任务
|
||||||
|
boolean removed = printQueue.removeIf(task -> taskId.equals(task.getId()));
|
||||||
|
if (removed) {
|
||||||
|
log.info("成功从队列中取消任务: {}", taskId);
|
||||||
|
} else {
|
||||||
|
log.warn("未找到要取消的任务: {}", taskId);
|
||||||
|
}
|
||||||
|
return removed;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 获取历史服务实例
|
* 获取历史服务实例
|
||||||
*
|
*
|
||||||
|
|||||||
@@ -0,0 +1,65 @@
|
|||||||
|
package com.goeing.printserver.main.utils;
|
||||||
|
|
||||||
|
import ch.qos.logback.classic.spi.ILoggingEvent;
|
||||||
|
import ch.qos.logback.core.AppenderBase;
|
||||||
|
import lombok.Getter;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
|
import java.time.LocalDateTime;
|
||||||
|
import java.time.format.DateTimeFormatter;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 内存日志追加器,用于缓存日志到内存中
|
||||||
|
*/
|
||||||
|
@Component
|
||||||
|
public class MemoryLogAppender extends AppenderBase<ILoggingEvent> {
|
||||||
|
@Autowired
|
||||||
|
private MemoryLogStorage memoryLogStorage; // ✅ Spring 注入,全局唯一
|
||||||
|
|
||||||
|
private static final DateTimeFormatter FORMATTER =
|
||||||
|
DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss.SSS");
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void start() {
|
||||||
|
System.out.println("✅ MemoryLogAppender started with context: " + context);
|
||||||
|
super.start(); // 必须调用
|
||||||
|
}
|
||||||
|
@Override
|
||||||
|
protected void append(ILoggingEvent event) {
|
||||||
|
if (!isStarted()) return;
|
||||||
|
|
||||||
|
// 排除日志接口的请求日志,避免循环记录
|
||||||
|
String message = event.getFormattedMessage();
|
||||||
|
if (message != null) {
|
||||||
|
if (message.contains("/api/logs")||message.contains("LogController")) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
LogEntry logEntry = new LogEntry(
|
||||||
|
LocalDateTime.now().format(FORMATTER),
|
||||||
|
event.getLevel().toString(),
|
||||||
|
event.getLoggerName(),
|
||||||
|
event.getFormattedMessage()
|
||||||
|
);
|
||||||
|
memoryLogStorage.addLog(logEntry); // 写入共享存储
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 日志条目类
|
||||||
|
*/
|
||||||
|
@Getter
|
||||||
|
public static class LogEntry {
|
||||||
|
private final String timestamp;
|
||||||
|
private final String level;
|
||||||
|
private final String logger;
|
||||||
|
private final String message;
|
||||||
|
|
||||||
|
public LogEntry(String timestamp, String level, String logger, String message) {
|
||||||
|
this.timestamp = timestamp;
|
||||||
|
this.level = level;
|
||||||
|
this.logger = logger;
|
||||||
|
this.message = message;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,57 @@
|
|||||||
|
package com.goeing.printserver.main.utils;
|
||||||
|
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
|
import java.util.*;
|
||||||
|
import java.util.concurrent.ConcurrentLinkedQueue;
|
||||||
|
|
||||||
|
@Component
|
||||||
|
public class MemoryLogStorage {
|
||||||
|
|
||||||
|
private final Queue<MemoryLogAppender.LogEntry> logs = new ConcurrentLinkedQueue<>();
|
||||||
|
private static final int MAX_LOGS = 2000;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 添加日志条目,并控制最大数量
|
||||||
|
*/
|
||||||
|
public void addLog(MemoryLogAppender.LogEntry logEntry) {
|
||||||
|
logs.offer(logEntry);
|
||||||
|
// 保持最多 MAX_LOGS 条
|
||||||
|
while (logs.size() > MAX_LOGS) {
|
||||||
|
logs.poll();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取日志列表(支持过滤和分页)
|
||||||
|
*/
|
||||||
|
public List<MemoryLogAppender.LogEntry> getLogs(int limit, String level) {
|
||||||
|
List<MemoryLogAppender.LogEntry> result = new ArrayList<>();
|
||||||
|
for (MemoryLogAppender.LogEntry log : logs) {
|
||||||
|
if (level == null || "ALL".equals(level) || level.equals(log.getLevel())) {
|
||||||
|
result.add(log);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// 最新的在前
|
||||||
|
result.sort((a, b) -> b.getTimestamp().compareTo(a.getTimestamp()));
|
||||||
|
// 限制数量
|
||||||
|
if (limit > 0 && result.size() > limit) {
|
||||||
|
return result.subList(0, limit);
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 清空所有日志
|
||||||
|
*/
|
||||||
|
public void clearLogs() {
|
||||||
|
logs.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取当前日志数量(用于监控)
|
||||||
|
*/
|
||||||
|
public int size() {
|
||||||
|
return logs.size();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,9 +1,8 @@
|
|||||||
package com.goeing.printserver.main.utils;// src/main/java/com/example/printer/PdfPrinter.java
|
package com.goeing.printserver.main.utils;
|
||||||
|
|
||||||
import cn.hutool.core.util.StrUtil;
|
import cn.hutool.core.util.StrUtil;
|
||||||
import com.goeing.printserver.main.domain.bo.PrintOption;
|
import com.goeing.printserver.main.domain.bo.PrintOption;
|
||||||
import org.apache.pdfbox.pdmodel.PDDocument;
|
import org.apache.pdfbox.pdmodel.PDDocument;
|
||||||
import org.apache.pdfbox.printing.PDFPageable;
|
|
||||||
import org.apache.pdfbox.printing.Orientation;
|
import org.apache.pdfbox.printing.Orientation;
|
||||||
import org.apache.pdfbox.printing.PDFPrintable;
|
import org.apache.pdfbox.printing.PDFPrintable;
|
||||||
import org.apache.pdfbox.printing.Scaling;
|
import org.apache.pdfbox.printing.Scaling;
|
||||||
@@ -30,6 +29,10 @@ public class PdfPrinter {
|
|||||||
|
|
||||||
private static final Map<String, MediaSizeName> PAPER_SIZES = new HashMap<>();
|
private static final Map<String, MediaSizeName> PAPER_SIZES = new HashMap<>();
|
||||||
|
|
||||||
|
// 装订边距常量(英寸)
|
||||||
|
private static final double BINDING_MARGIN_LEFT = 0.5; // 左装订额外边距
|
||||||
|
private static final double BINDING_MARGIN_TOP = 0.5; // 顶装订额外边距
|
||||||
|
|
||||||
static {
|
static {
|
||||||
PAPER_SIZES.put("Letter", MediaSizeName.NA_LETTER); // 8.5" × 11"
|
PAPER_SIZES.put("Letter", MediaSizeName.NA_LETTER); // 8.5" × 11"
|
||||||
PAPER_SIZES.put("Legal", MediaSizeName.NA_LEGAL); // 8.5" × 14"
|
PAPER_SIZES.put("Legal", MediaSizeName.NA_LEGAL); // 8.5" × 14"
|
||||||
@@ -68,13 +71,44 @@ public class PdfPrinter {
|
|||||||
public static void print(String pdfPath, String printerName, PrintOption option) throws Exception {
|
public static void print(String pdfPath, String printerName, PrintOption option) throws Exception {
|
||||||
// 参数验证
|
// 参数验证
|
||||||
validatePrintParameters(pdfPath, printerName, option);
|
validatePrintParameters(pdfPath, printerName, option);
|
||||||
|
PrinterJob job = getPrintServiceByName(printerName);
|
||||||
// 加载PDF文档并执行打印
|
// 加载PDF文档并执行打印
|
||||||
PDDocument document = null;
|
PDDocument document = null;
|
||||||
try {
|
try {
|
||||||
document = PDDocument.load(new File(pdfPath));
|
document = PDDocument.load(new File(pdfPath));
|
||||||
PrinterJob job = getPrintServiceByName(printerName);
|
|
||||||
|
String color = option.getColor();
|
||||||
|
//如果是封面彩打 那么要把封面和 内容分开打印 就做两个打印任务 先打封面 再打内容
|
||||||
|
if ("Cover Letter Color Only".equals(color)) {
|
||||||
|
PDDocument cover = new PDDocument();
|
||||||
|
cover.addPage(document.getPage(0));
|
||||||
|
cover.close();
|
||||||
|
|
||||||
|
PDDocument content = new PDDocument();
|
||||||
|
for (int i = 0; i < document.getNumberOfPages(); i++) {
|
||||||
|
//第一页是封面
|
||||||
|
if (i == 0) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
content.addPage(document.getPage(i));
|
||||||
|
}
|
||||||
|
content.close();
|
||||||
|
//打印 封面和内容
|
||||||
|
option.setColor("color");
|
||||||
|
setPageStyle(cover, job, option);
|
||||||
|
option.setColor("black & white");
|
||||||
|
setPageStyle(content, job, option);
|
||||||
|
|
||||||
|
} else {
|
||||||
|
if (StrUtil.containsIgnoreCase(color,"color")){
|
||||||
|
option.setColor("color");
|
||||||
|
}
|
||||||
|
//全部打印
|
||||||
setPageStyle(document, job, option);
|
setPageStyle(document, job, option);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
} finally {
|
} finally {
|
||||||
// 确保文档被关闭
|
// 确保文档被关闭
|
||||||
if (document != null) {
|
if (document != null) {
|
||||||
@@ -182,12 +216,8 @@ public class PdfPrinter {
|
|||||||
// 设置页面方向
|
// 设置页面方向
|
||||||
Orientation pdfOrientation = getPdfOrientation(option.getOrientation());
|
Orientation pdfOrientation = getPdfOrientation(option.getOrientation());
|
||||||
|
|
||||||
// 获取纸张尺寸
|
// 设置纸张 A4 Letter等
|
||||||
String size = option.getSize() != null ? option.getSize() : "Letter";
|
Paper paper = createPaperFromOption(option);
|
||||||
double[] dimensions = getPaperDimensions(size);
|
|
||||||
|
|
||||||
// 创建自定义Paper对象
|
|
||||||
Paper paper = createPaper(dimensions[0], dimensions[1], option.getMargin());
|
|
||||||
|
|
||||||
// 创建PageFormat对象
|
// 创建PageFormat对象
|
||||||
PageFormat pageFormat = new PageFormat();
|
PageFormat pageFormat = new PageFormat();
|
||||||
@@ -204,7 +234,6 @@ public class PdfPrinter {
|
|||||||
Book book = new Book();
|
Book book = new Book();
|
||||||
|
|
||||||
// 将所有页面添加到Book中,使用相同的PageFormat
|
// 将所有页面添加到Book中,使用相同的PageFormat
|
||||||
// 根据页面方向选择适当的缩放模式
|
|
||||||
Scaling scaling;
|
Scaling scaling;
|
||||||
if (option.getSize() != null) {
|
if (option.getSize() != null) {
|
||||||
// 如果用户指定了纸张大小,使用适应页面的缩放模式
|
// 如果用户指定了纸张大小,使用适应页面的缩放模式
|
||||||
@@ -215,7 +244,7 @@ public class PdfPrinter {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 创建PDFPrintable对象,设置居中和显示页面边框
|
// 创建PDFPrintable对象,设置居中和显示页面边框
|
||||||
PDFPrintable printable = new PDFPrintable(document, scaling, false, 0, true);
|
PDFPrintable printable = new PDFPrintable(document, scaling, false, 300, true);
|
||||||
book.append(printable, pageFormat, document.getNumberOfPages());
|
book.append(printable, pageFormat, document.getNumberOfPages());
|
||||||
|
|
||||||
// 应用自定义页面设置到打印作业
|
// 应用自定义页面设置到打印作业
|
||||||
@@ -234,14 +263,13 @@ public class PdfPrinter {
|
|||||||
*/
|
*/
|
||||||
public static Paper createPaperFromOption(PrintOption option) {
|
public static Paper createPaperFromOption(PrintOption option) {
|
||||||
// 获取纸张尺寸
|
// 获取纸张尺寸
|
||||||
String size = option.getSize() != null ? option.getSize() : "Letter";
|
double[] dimensions = getPaperDimensions(option.getSize());
|
||||||
double[] dimensions = getPaperDimensions(size);
|
|
||||||
|
|
||||||
// 获取边距(默认为0.5英寸)
|
// 获取边距(默认为0.5英寸)
|
||||||
double marginInches = option.getMargin();
|
double marginInches = option.getMargin();
|
||||||
|
|
||||||
// 创建并返回Paper对象
|
// 创建并返回Paper对象,考虑装订选项
|
||||||
return createPaper(dimensions[0], dimensions[1], marginInches);
|
return createPaper(dimensions[0], dimensions[1], marginInches, option.getPosition());
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -253,10 +281,6 @@ public class PdfPrinter {
|
|||||||
private static PrintRequestAttributeSet createPrintRequestAttributeSet(PrintOption option) {
|
private static PrintRequestAttributeSet createPrintRequestAttributeSet(PrintOption option) {
|
||||||
PrintRequestAttributeSet aset = new HashPrintRequestAttributeSet();
|
PrintRequestAttributeSet aset = new HashPrintRequestAttributeSet();
|
||||||
|
|
||||||
// 设置纸张大小
|
|
||||||
String size = option.getSize() != null ? option.getSize() : "Letter";
|
|
||||||
aset.add(PAPER_SIZES.getOrDefault(size, MediaSizeName.NA_LETTER));
|
|
||||||
|
|
||||||
// 设置颜色模式
|
// 设置颜色模式
|
||||||
setColorMode(aset, option.getColor());
|
setColorMode(aset, option.getColor());
|
||||||
|
|
||||||
@@ -280,7 +304,7 @@ public class PdfPrinter {
|
|||||||
* @return PDF页面方向
|
* @return PDF页面方向
|
||||||
*/
|
*/
|
||||||
private static Orientation getPdfOrientation(String orientationStr) {
|
private static Orientation getPdfOrientation(String orientationStr) {
|
||||||
if (orientationStr != null && "ORI_LANDSCAPE".equalsIgnoreCase(orientationStr)) {
|
if ("ORI_LANDSCAPE".equalsIgnoreCase(orientationStr)) {
|
||||||
return Orientation.LANDSCAPE;
|
return Orientation.LANDSCAPE;
|
||||||
}
|
}
|
||||||
return Orientation.PORTRAIT; // 默认为纵向
|
return Orientation.PORTRAIT; // 默认为纵向
|
||||||
@@ -293,7 +317,14 @@ public class PdfPrinter {
|
|||||||
* @param color 颜色模式字符串
|
* @param color 颜色模式字符串
|
||||||
*/
|
*/
|
||||||
private static void setColorMode(PrintRequestAttributeSet aset, String color) {
|
private static void setColorMode(PrintRequestAttributeSet aset, String color) {
|
||||||
if (color != null && ("Full Color".equalsIgnoreCase(color) || "Cover Letter Color Only".equalsIgnoreCase(color))) {
|
if (color == null) {
|
||||||
|
aset.add(Chromaticity.MONOCHROME);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
String c = color.trim().toLowerCase();
|
||||||
|
|
||||||
|
if (c.equals("color")) {
|
||||||
aset.add(Chromaticity.COLOR);
|
aset.add(Chromaticity.COLOR);
|
||||||
} else {
|
} else {
|
||||||
aset.add(Chromaticity.MONOCHROME);
|
aset.add(Chromaticity.MONOCHROME);
|
||||||
@@ -307,7 +338,7 @@ public class PdfPrinter {
|
|||||||
* @param sides 打印面字符串
|
* @param sides 打印面字符串
|
||||||
*/
|
*/
|
||||||
private static void setPrintSides(PrintRequestAttributeSet aset, String sides) {
|
private static void setPrintSides(PrintRequestAttributeSet aset, String sides) {
|
||||||
if (sides != null && ("Double-Sided".equalsIgnoreCase(sides) || "Two-Sided".equalsIgnoreCase(sides))) {
|
if (("Double-Sided".equalsIgnoreCase(sides))) {
|
||||||
aset.add(Sides.TWO_SIDED_LONG_EDGE);
|
aset.add(Sides.TWO_SIDED_LONG_EDGE);
|
||||||
} else {
|
} else {
|
||||||
aset.add(Sides.ONE_SIDED);
|
aset.add(Sides.ONE_SIDED);
|
||||||
@@ -354,22 +385,52 @@ public class PdfPrinter {
|
|||||||
*
|
*
|
||||||
* @param width 纸张宽度(点)
|
* @param width 纸张宽度(点)
|
||||||
* @param height 纸张高度(点)
|
* @param height 纸张高度(点)
|
||||||
* @param marginInches 边距(英寸)
|
* @param marginInches 基础边距(英寸)
|
||||||
|
* @param bindingOption 装订选项
|
||||||
* @return 配置好的Paper对象
|
* @return 配置好的Paper对象
|
||||||
*/
|
*/
|
||||||
private static Paper createPaper(double width, double height, double marginInches) {
|
private static Paper createPaper(double width, double height, double marginInches, String bindingOption) {
|
||||||
Paper paper = new Paper();
|
Paper paper = new Paper();
|
||||||
paper.setSize(width, height);
|
paper.setSize(width, height);
|
||||||
|
|
||||||
|
// 计算各边的边距,考虑装订选项
|
||||||
|
double leftMargin = marginInches;
|
||||||
|
double topMargin = marginInches;
|
||||||
|
double rightMargin = marginInches;
|
||||||
|
double bottomMargin = marginInches;
|
||||||
|
|
||||||
|
// 根据装订选项调整边距
|
||||||
|
if (bindingOption != null) {
|
||||||
|
switch (bindingOption) {
|
||||||
|
case "Left":
|
||||||
|
leftMargin += BINDING_MARGIN_LEFT;
|
||||||
|
break;
|
||||||
|
case "Top":
|
||||||
|
topMargin += BINDING_MARGIN_TOP;
|
||||||
|
break;
|
||||||
|
case "Staple":
|
||||||
|
leftMargin += BINDING_MARGIN_LEFT;
|
||||||
|
topMargin += BINDING_MARGIN_TOP;
|
||||||
|
break;
|
||||||
|
case "None":
|
||||||
|
default:
|
||||||
|
// 不调整边距
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// 将边距从英寸转换为点
|
// 将边距从英寸转换为点
|
||||||
double marginPoints = marginInches * 72;
|
double leftMarginPoints = leftMargin * 72;
|
||||||
|
double topMarginPoints = topMargin * 72;
|
||||||
|
double rightMarginPoints = rightMargin * 72;
|
||||||
|
double bottomMarginPoints = bottomMargin * 72;
|
||||||
|
|
||||||
// 设置可打印区域
|
// 设置可打印区域
|
||||||
paper.setImageableArea(
|
paper.setImageableArea(
|
||||||
marginPoints,
|
leftMarginPoints,
|
||||||
marginPoints,
|
topMarginPoints,
|
||||||
width - 2 * marginPoints,
|
width - leftMarginPoints - rightMarginPoints,
|
||||||
height - 2 * marginPoints
|
height - topMarginPoints - bottomMarginPoints
|
||||||
);
|
);
|
||||||
|
|
||||||
return paper;
|
return paper;
|
||||||
|
|||||||
+98
-24
@@ -1,4 +1,4 @@
|
|||||||
package com.goeing.printserver.main.sse;
|
package com.goeing.printserver.main.ws;
|
||||||
|
|
||||||
import cn.hutool.json.JSONUtil;
|
import cn.hutool.json.JSONUtil;
|
||||||
import com.alibaba.fastjson.JSON;
|
import com.alibaba.fastjson.JSON;
|
||||||
@@ -21,6 +21,7 @@ import java.net.URI;
|
|||||||
import java.util.*;
|
import java.util.*;
|
||||||
import java.util.concurrent.Executors;
|
import java.util.concurrent.Executors;
|
||||||
import java.util.concurrent.ScheduledExecutorService;
|
import java.util.concurrent.ScheduledExecutorService;
|
||||||
|
import java.util.concurrent.ScheduledFuture;
|
||||||
import java.util.concurrent.TimeUnit;
|
import java.util.concurrent.TimeUnit;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
@@ -32,9 +33,12 @@ public class PrinterClient implements ApplicationRunner {
|
|||||||
private final PrintServerConfig config;
|
private final PrintServerConfig config;
|
||||||
private Session session;
|
private Session session;
|
||||||
|
|
||||||
private final ScheduledExecutorService reconnectExecutor = Executors.newSingleThreadScheduledExecutor();
|
|
||||||
private final ScheduledExecutorService heartbeatExecutor = Executors.newSingleThreadScheduledExecutor();
|
private final ScheduledExecutorService heartbeatExecutor = Executors.newSingleThreadScheduledExecutor();
|
||||||
private boolean isConnecting = false;
|
private final ScheduledExecutorService connectionMonitor = Executors.newSingleThreadScheduledExecutor();
|
||||||
|
private volatile ScheduledFuture<?> heartbeatTask;
|
||||||
|
private volatile boolean isConnecting = false;
|
||||||
|
private int reconnectAttempts = 0;
|
||||||
|
private static final int MAX_RECONNECT_ATTEMPTS = 10;
|
||||||
|
|
||||||
// 构造函数,注入PrintQueueService和PrintServerConfig
|
// 构造函数,注入PrintQueueService和PrintServerConfig
|
||||||
public PrinterClient(@Lazy PrintQueueService printQueueService, PrintServerConfig config) {
|
public PrinterClient(@Lazy PrintQueueService printQueueService, PrintServerConfig config) {
|
||||||
@@ -48,6 +52,8 @@ public class PrinterClient implements ApplicationRunner {
|
|||||||
this.session = session;
|
this.session = session;
|
||||||
log.info("WebSocket连接已建立");
|
log.info("WebSocket连接已建立");
|
||||||
isConnecting = false;
|
isConnecting = false;
|
||||||
|
reconnectAttempts = 0; // 重置重连计数
|
||||||
|
startHeartbeat();
|
||||||
}
|
}
|
||||||
|
|
||||||
@OnMessage
|
@OnMessage
|
||||||
@@ -89,10 +95,18 @@ public class PrinterClient implements ApplicationRunner {
|
|||||||
PrintService[] printServices = PrinterJob.lookupPrintServices();
|
PrintService[] printServices = PrinterJob.lookupPrintServices();
|
||||||
Set<String> collect = Arrays.stream(printServices).map(PrintService::getName).collect(Collectors.toSet());
|
Set<String> collect = Arrays.stream(printServices).map(PrintService::getName).collect(Collectors.toSet());
|
||||||
|
|
||||||
List<String> collect1 = collect.stream().sorted().collect(Collectors.toList());
|
List<String> printerList = collect.stream().sorted().collect(Collectors.toList());
|
||||||
|
|
||||||
|
// 获取设置中的默认打印机
|
||||||
|
String defaultPrinter = config.getDefaultPrinter();
|
||||||
|
|
||||||
|
// 构建响应对象
|
||||||
|
Map<String, Object> response = new HashMap<>();
|
||||||
|
response.put("printerList", printerList);
|
||||||
|
response.put("defaultPrinter", defaultPrinter);
|
||||||
|
|
||||||
webSocketMessageDTO.setType("RESPONSE");
|
webSocketMessageDTO.setType("RESPONSE");
|
||||||
webSocketMessageDTO.setPayload(JSONUtil.toJsonStr(collect1));
|
webSocketMessageDTO.setPayload(JSONUtil.toJsonStr(response));
|
||||||
session.getBasicRemote().sendText(JSONUtil.toJsonStr(webSocketMessageDTO));
|
session.getBasicRemote().sendText(JSONUtil.toJsonStr(webSocketMessageDTO));
|
||||||
} else if ("queueStatus".equals(type)) {
|
} else if ("queueStatus".equals(type)) {
|
||||||
// 返回当前打印队列状态
|
// 返回当前打印队列状态
|
||||||
@@ -125,25 +139,22 @@ public class PrinterClient implements ApplicationRunner {
|
|||||||
public void onClose(Session session, CloseReason closeReason) {
|
public void onClose(Session session, CloseReason closeReason) {
|
||||||
log.warn("WebSocket连接关闭: {}", closeReason.getReasonPhrase());
|
log.warn("WebSocket连接关闭: {}", closeReason.getReasonPhrase());
|
||||||
this.session = null;
|
this.session = null;
|
||||||
// 安排重连任务
|
// 连接监控器会自动处理重连
|
||||||
scheduleReconnect();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@OnError
|
@OnError
|
||||||
public void onError(Session session, Throwable throwable) {
|
public void onError(Session session, Throwable throwable) {
|
||||||
log.error("WebSocket连接发生错误", throwable);
|
log.error("WebSocket连接发生错误", throwable);
|
||||||
this.session = null;
|
this.session = null;
|
||||||
|
// 连接监控器会自动处理重连
|
||||||
// 安排重连任务
|
|
||||||
scheduleReconnect();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 连接到WebSocket服务器
|
* 连接到WebSocket服务器
|
||||||
*/
|
*/
|
||||||
private void connect() {
|
private void connect() {
|
||||||
if (isConnecting || (session != null && session.isOpen())) {
|
if (isConnecting) {
|
||||||
return; // 已经连接或正在连接中
|
return; // 正在连接中
|
||||||
}
|
}
|
||||||
|
|
||||||
// 从配置对象中获取最新的连接参数
|
// 从配置对象中获取最新的连接参数
|
||||||
@@ -151,6 +162,14 @@ public class PrinterClient implements ApplicationRunner {
|
|||||||
String printerId = config.getPrinterId();
|
String printerId = config.getPrinterId();
|
||||||
String apiKey = config.getApiKey();
|
String apiKey = config.getApiKey();
|
||||||
|
|
||||||
|
if (serverUri == null || serverUri.trim().isEmpty()) {
|
||||||
|
log.warn("WebSocket URL未配置,跳过连接");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 添加调试日志
|
||||||
|
log.info("当前配置 - WebSocket URL: {}, PrinterId: {}, ApiKey: {}", serverUri, printerId, apiKey);
|
||||||
|
|
||||||
String tempUrl = serverUri+"?printerId="+printerId+"&apiKey="+apiKey;
|
String tempUrl = serverUri+"?printerId="+printerId+"&apiKey="+apiKey;
|
||||||
|
|
||||||
isConnecting = true;
|
isConnecting = true;
|
||||||
@@ -162,9 +181,8 @@ public class PrinterClient implements ApplicationRunner {
|
|||||||
container.connectToServer(this, new URI(tempUrl));
|
container.connectToServer(this, new URI(tempUrl));
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
log.error("连接到WebSocket服务器失败", e);
|
log.error("连接到WebSocket服务器失败", e);
|
||||||
|
} finally {
|
||||||
isConnecting = false;
|
isConnecting = false;
|
||||||
// 连接失败,安排重连
|
|
||||||
scheduleReconnect();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -172,27 +190,63 @@ public class PrinterClient implements ApplicationRunner {
|
|||||||
* 启动心跳机制
|
* 启动心跳机制
|
||||||
*/
|
*/
|
||||||
private void startHeartbeat() {
|
private void startHeartbeat() {
|
||||||
heartbeatExecutor.scheduleAtFixedRate(() -> {
|
// 取消之前的心跳任务
|
||||||
|
if (heartbeatTask != null && !heartbeatTask.isCancelled()) {
|
||||||
|
heartbeatTask.cancel(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
heartbeatTask = heartbeatExecutor.scheduleAtFixedRate(() -> {
|
||||||
if (session != null && session.isOpen()) {
|
if (session != null && session.isOpen()) {
|
||||||
try {
|
try {
|
||||||
session.getBasicRemote().sendText("{\"type\":\"heartbeat\"}");
|
session.getBasicRemote().sendText("{\"type\":\"heartbeat\"}");
|
||||||
log.debug("发送心跳");
|
log.debug("发送心跳");
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
log.error("发送心跳失败", e);
|
log.debug("发送心跳失败", e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}, 30, 30, TimeUnit.SECONDS);
|
}, 30, 20, TimeUnit.SECONDS);
|
||||||
log.info("心跳机制已启动");
|
log.info("心跳机制已启动");
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 安排重连任务
|
* 启动连接监控
|
||||||
*/
|
*/
|
||||||
private void scheduleReconnect() {
|
private void startConnectionMonitor() {
|
||||||
reconnectExecutor.schedule(() -> {
|
connectionMonitor.scheduleWithFixedDelay(() -> {
|
||||||
log.info("尝试重新连接到WebSocket服务器...");
|
try {
|
||||||
|
checkAndReconnect();
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.error("连接监控任务执行失败", e);
|
||||||
|
}
|
||||||
|
}, 10, 20, TimeUnit.SECONDS); // 每10秒检查一次
|
||||||
|
|
||||||
|
log.info("连接监控已启动,每10秒检查一次连接状态");
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 检查连接状态并在需要时重连
|
||||||
|
*/
|
||||||
|
private void checkAndReconnect() {
|
||||||
|
if (isConnected()) {
|
||||||
|
// 连接正常,重置重连计数
|
||||||
|
reconnectAttempts = 0;
|
||||||
|
log.debug("WebSocket连接状态正常");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isConnecting) {
|
||||||
|
log.debug("正在连接中,跳过此次检查");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (reconnectAttempts >= MAX_RECONNECT_ATTEMPTS) {
|
||||||
|
log.error("重连次数已达上限({}次),停止重连", MAX_RECONNECT_ATTEMPTS);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
log.info("检测到连接断开,开始重连...(第{}次尝试)", reconnectAttempts + 1);
|
||||||
|
reconnectAttempts++;
|
||||||
connect();
|
connect();
|
||||||
}, 5, TimeUnit.SECONDS);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -201,6 +255,16 @@ public class PrinterClient implements ApplicationRunner {
|
|||||||
@PreDestroy
|
@PreDestroy
|
||||||
public void shutdown() {
|
public void shutdown() {
|
||||||
log.info("正在关闭WebSocket客户端...");
|
log.info("正在关闭WebSocket客户端...");
|
||||||
|
|
||||||
|
// 取消心跳任务
|
||||||
|
if (heartbeatTask != null && !heartbeatTask.isCancelled()) {
|
||||||
|
heartbeatTask.cancel(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 停止连接监控和心跳
|
||||||
|
connectionMonitor.shutdownNow();
|
||||||
|
heartbeatExecutor.shutdownNow();
|
||||||
|
|
||||||
if (session != null) {
|
if (session != null) {
|
||||||
try {
|
try {
|
||||||
session.close();
|
session.close();
|
||||||
@@ -208,8 +272,6 @@ public class PrinterClient implements ApplicationRunner {
|
|||||||
log.error("关闭WebSocket连接失败", e);
|
log.error("关闭WebSocket连接失败", e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
reconnectExecutor.shutdownNow();
|
|
||||||
heartbeatExecutor.shutdownNow();
|
|
||||||
log.info("WebSocket客户端已关闭");
|
log.info("WebSocket客户端已关闭");
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -218,6 +280,12 @@ public class PrinterClient implements ApplicationRunner {
|
|||||||
*/
|
*/
|
||||||
public void reconnect() {
|
public void reconnect() {
|
||||||
log.info("配置已更改,重新连接WebSocket服务器...");
|
log.info("配置已更改,重新连接WebSocket服务器...");
|
||||||
|
|
||||||
|
// 停止旧的心跳任务
|
||||||
|
if (heartbeatTask != null && !heartbeatTask.isCancelled()) {
|
||||||
|
heartbeatTask.cancel(false);
|
||||||
|
}
|
||||||
|
|
||||||
if (session != null && session.isOpen()) {
|
if (session != null && session.isOpen()) {
|
||||||
try {
|
try {
|
||||||
session.close();
|
session.close();
|
||||||
@@ -227,6 +295,10 @@ public class PrinterClient implements ApplicationRunner {
|
|||||||
}
|
}
|
||||||
session = null;
|
session = null;
|
||||||
isConnecting = false;
|
isConnecting = false;
|
||||||
|
|
||||||
|
// 重置重连计数
|
||||||
|
reconnectAttempts = 0;
|
||||||
|
|
||||||
connect();
|
connect();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -267,6 +339,8 @@ public class PrinterClient implements ApplicationRunner {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void run(ApplicationArguments args) {
|
public void run(ApplicationArguments args) {
|
||||||
|
// 启动连接监控
|
||||||
|
startConnectionMonitor();
|
||||||
// 应用启动后连接到WebSocket服务器
|
// 应用启动后连接到WebSocket服务器
|
||||||
connect();
|
connect();
|
||||||
}
|
}
|
||||||
@@ -10,7 +10,6 @@ spring.main.allow-circular-references=true
|
|||||||
|
|
||||||
# 在macOS系统上,如果遇到HeadlessException,可以设置为true强制使用无头模式
|
# 在macOS系统上,如果遇到HeadlessException,可以设置为true强制使用无头模式
|
||||||
# 或者在启动时添加JVM参数:-Djava.awt.headless=true
|
# 或者在启动时添加JVM参数:-Djava.awt.headless=true
|
||||||
app.force.headless=false
|
|
||||||
|
|
||||||
# 日志配置
|
# 日志配置
|
||||||
# 设置打印机状态面板和设置面板的日志级别为WARN,减少日志输出
|
# 设置打印机状态面板和设置面板的日志级别为WARN,减少日志输出
|
||||||
|
|||||||
@@ -0,0 +1,54 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<configuration>
|
||||||
|
<!-- 控制台输出 -->
|
||||||
|
<appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender">
|
||||||
|
<encoder>
|
||||||
|
<pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</pattern>
|
||||||
|
</encoder>
|
||||||
|
</appender>
|
||||||
|
|
||||||
|
<!-- 内存日志追加器 -->
|
||||||
|
<!-- <appender name="MEMORY" class="com.goeing.printserver.main.utils.MemoryLogAppender">-->
|
||||||
|
<!-- <!– 内存追加器不需要额外配置 –>-->
|
||||||
|
<!-- </appender>-->
|
||||||
|
|
||||||
|
<!-- 文件输出 -->
|
||||||
|
<appender name="FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
|
||||||
|
<file>${java.io.tmpdir}/goeingprint/logs/application.log</file>
|
||||||
|
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
|
||||||
|
<fileNamePattern>${java.io.tmpdir}/goeingprint/logs/application.%d{yyyy-MM-dd}.%i.log</fileNamePattern>
|
||||||
|
<timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
|
||||||
|
<maxFileSize>10MB</maxFileSize>
|
||||||
|
</timeBasedFileNamingAndTriggeringPolicy>
|
||||||
|
<maxHistory>30</maxHistory>
|
||||||
|
</rollingPolicy>
|
||||||
|
<encoder>
|
||||||
|
<pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</pattern>
|
||||||
|
</encoder>
|
||||||
|
</appender>
|
||||||
|
|
||||||
|
<!-- 根日志级别 -->
|
||||||
|
<root level="INFO">
|
||||||
|
<appender-ref ref="CONSOLE" />
|
||||||
|
<!-- <appender-ref ref="MEMORY" />-->
|
||||||
|
<appender-ref ref="FILE" />
|
||||||
|
</root>
|
||||||
|
|
||||||
|
<!-- 特定包的日志级别 -->
|
||||||
|
<logger name="com.goeing.printserver" level="DEBUG" additivity="false">
|
||||||
|
<appender-ref ref="CONSOLE" />
|
||||||
|
<!-- <appender-ref ref="MEMORY" />-->
|
||||||
|
<appender-ref ref="FILE" />
|
||||||
|
</logger>
|
||||||
|
|
||||||
|
<!-- Spring Boot 相关日志 -->
|
||||||
|
<logger name="org.springframework" level="WARN" />
|
||||||
|
<logger name="org.springframework.web" level="WARN" />
|
||||||
|
|
||||||
|
<!-- Hibernate 相关日志 -->
|
||||||
|
<logger name="org.hibernate" level="WARN" />
|
||||||
|
|
||||||
|
<!-- 网络相关日志 -->
|
||||||
|
<logger name="org.apache.http" level="WARN" />
|
||||||
|
<logger name="httpclient" level="WARN" />
|
||||||
|
</configuration>
|
||||||
Reference in New Issue
Block a user