Files
Printservice-REST/docs/PRINTSERVICE_STANDALONE_DOKUMENTATION_v2.5.md

671 lines
17 KiB
Markdown

# Printservice Standalone Java 25 v2.5
Eigenständiger Druckservice ohne GlassFish/Payara. Die Anwendung läuft als normale Java-Applikation oder über WinSW als Windows-Dienst und stellt ein Webfrontend plus REST-API bereit.
## Funktionen
- eigener HTTP-Server aus dem JDK
- Webfrontend unter `http://localhost:8080/`
- REST-API unter `http://localhost:8080/api`
- Drucker-Aliase für `WINDOWS_SPOOLER` und `RAW_TCP`
- Windows-/LocalSystem-Assistent für Dienstbetrieb
- HTML-Vorlagen mit Online-Editor
- HTML-Tabellen über `{{#each:items}} ... {{/each}}`
- HTML -> PDF -> Druck
- PDF als Vorlage mit Koordinatenfeldern (`PDF_TEMPLATE`)
- PDF-Tabellen aus JSON-Arrays
- ZPL/EPL/Text RAW-Druck
- DOCX-Vorlagen rendern und herunterladen
- DOCX -> PDF -> Druck optional über `DOCX4J_FO` ohne LibreOffice
- Barcode, QR-Code, DataMatrix und weitere ZXing-Formate
- optionale Authentifizierung: wenn deaktiviert, kann jeder per REST drucken
- Benutzer-/Tokenverwaltung im Webfrontend
- persistente Druckjob-Historie / Druckwarteschlange für Redruck
- Filterung der Druckhistorie nach User, Status, Drucker und Vorlage
- Admin-Vollansicht der Warteschlange mit `full=true`
- produktionsnahe Vorlagenstruktur unter `templates/<templateName>/...`
## Zielplattform
- Java 25
- Maven 3.9 oder neuer empfohlen
- Windows, Linux oder macOS
- Windows-Dienstbetrieb über WinSW
## Build
```bash
mvn clean package
```
Ergebnis:
```text
target/printservice-standalone.jar
```
## Start als Konsole
Windows:
```cmd
java -Dprintservice.config.dir=C:\printservice -jar target\printservice-standalone.jar --host=0.0.0.0 --port=8080
```
Linux:
```bash
java -Dprintservice.config.dir=/opt/printservice -jar target/printservice-standalone.jar --host=0.0.0.0 --port=8080
```
Danach:
```text
http://localhost:8080/
http://localhost:8080/api/diagnostics/system
```
## Konfigurationsstruktur
Empfohlen unter Windows:
```text
C:\printservice
├── auth.json
├── printers.json
├── queue
│ └── print-jobs.json
├── templates
│ └── <templateName>
│ ├── template.json
│ ├── document.*
│ ├── fields.json
│ ├── sample-data.json
│ └── print-request.json
├── spool
├── archive
├── preview
└── logs
```
Ohne `-Dprintservice.config.dir` nutzt die Anwendung:
```text
%USERPROFILE%\.printservice
```
## Windows-Service mit WinSW
```powershell
mvn clean package
.\scripts\install-service.ps1 -InstallDir C:\printservice-app -ConfigDir C:\printservice -Port 8080
```
Danach `WinSW-x64.exe` als `C:\printservice-app\printservice.exe` ablegen und starten:
```powershell
cd C:\printservice-app
.\printservice.exe install
.\printservice.exe start
.\printservice.exe status
```
## Authentifizierung
Standardmäßig ist Auth deaktiviert. Dann kann jeder, der `/api/print` erreicht, drucken. Das ist für Tests praktisch, aber produktiv nur in geschlossenen Netzen sinnvoll.
```json
{
"enabled": false,
"protectPrint": true,
"protectRenderedDownload": true,
"protectPreview": false,
"protectAdmin": false,
"headerName": "X-Printservice-Token",
"tokens": []
}
```
### Empfohlener Ablauf im Webfrontend
1. Webfrontend öffnen.
2. Bereich **Authentifizierung, Benutzer und Token**.
3. Erst einen Admin-User anlegen, Scope `ALL`.
4. Token kopieren und sicher speichern.
5. Danach Auth aktivieren.
6. Optional `protectAdmin` aktivieren.
7. Für Maschinen/Clients eigene User mit Scope `PRINT` anlegen.
Token werden serverseitig nur als SHA-256-Hash gespeichert. Das Klartext-Token wird nur einmal bei der Erstellung zurückgegeben.
### REST: Benutzer/Token anlegen
```bash
curl -X POST http://localhost:8080/api/auth/users \
-H "Content-Type: application/json" \
-d @src/main/resources/examples/rest-create-auth-user-request.json
```
Beispiel:
```json
{
"userName": "line01",
"displayName": "Linie 01",
"tokenName": "line01-print-token",
"enabled": true,
"scopes": ["PRINT", "PREVIEW"]
}
```
Antwort enthält das Token einmalig:
```json
{
"userName": "line01",
"tokenName": "line01-print-token",
"token": "NUR_EINMAL_SICHTBAR"
}
```
### REST: Auth einschalten
```bash
curl -X PUT http://localhost:8080/api/auth/config \
-H "Content-Type: application/json" \
-H "X-Printservice-Token: ADMIN_TOKEN" \
-d @src/main/resources/examples/rest-update-auth-config-enabled-request.json
```
### REST: Drucken mit Token
```bash
curl -X POST http://localhost:8080/api/print \
-H "Content-Type: application/json" \
-H "X-Printservice-Token: YOUR_PRINT_TOKEN" \
-d @src/main/resources/examples/rest-print-raw-tcp-zpl-request.json
```
Alternativ:
```text
Authorization: Bearer YOUR_PRINT_TOKEN
```
## Druckwarteschlange / Druckhistorie / Redruck
Jeder echte Druckjob wird unter `queue/print-jobs.json` gespeichert. Gespeichert werden u. a. Job-ID, Benutzer, Drucker, Vorlage, Render-Modus, Status und der Original-PrintRequest. Dadurch kann der Job später erneut gedruckt werden.
### Eigene Jobs abrufen
```bash
curl "http://localhost:8080/api/queue?limit=100" \
-H "X-Printservice-Token: YOUR_PRINT_TOKEN"
```
Wenn Auth aktiv ist, sieht ein normaler Benutzer nur seine eigenen Jobs.
### Vollständige Liste abrufen
```bash
curl "http://localhost:8080/api/queue?full=true&limit=500" \
-H "X-Printservice-Token: YOUR_ADMIN_TOKEN"
```
`full=true` benötigt Scope `ADMIN` oder `ALL`.
### Nach User/Status/Vorlage filtern
```bash
curl "http://localhost:8080/api/queue?full=true&user=line01&status=SUBMITTED&templateName=serial_label_zpl" \
-H "X-Printservice-Token: YOUR_ADMIN_TOKEN"
```
### Einzelnen Job abrufen
```bash
curl http://localhost:8080/api/queue/JOB_ID \
-H "X-Printservice-Token: YOUR_PRINT_TOKEN"
```
### Redruck
```bash
curl -X POST http://localhost:8080/api/queue/JOB_ID/reprint \
-H "Content-Type: application/json" \
-H "X-Printservice-Token: YOUR_PRINT_TOKEN" \
-d @src/main/resources/examples/rest-reprint-request.json
```
Beispiel:
```json
{
"copies": 1,
"printerAlias": "LABEL_LINE_01",
"dataOverride": {
"reprintReason": "Etikett beschädigt"
}
}
```
Ohne `printerAlias` und ohne `dataOverride` wird der Originaljob unverändert erneut gesendet.
## Druckerarten
### WINDOWS_SPOOLER
Für PDF, HTML->PDF, PDF_TEMPLATE und normale Office-/A4-Drucker.
```json
{
"alias": "OFFICE_A4",
"type": "WINDOWS_SPOOLER",
"systemName": "HP_LaserJet_A4",
"description": "A4 Drucker über Windows Spooler"
}
```
### RAW_TCP
Für schnelle Etikettendrucker mit ZPL/EPL/ESC-POS/PCL.
```json
{
"alias": "LABEL_LINE_01",
"type": "RAW_TCP",
"host": "192.168.10.50",
"port": 9100,
"language": "ZPL",
"description": "Zebra Etikettendrucker direkt per TCP"
}
```
## REST-Endpunkte
```text
GET /api/diagnostics/system
GET /api/printers/diagnostics
GET /api/printers/scan
GET /api/printers
POST /api/printers
DELETE /api/printers/{alias}
GET /api/templates/storage
GET /api/templates
GET /api/templates/{name}
POST /api/templates
PUT /api/templates/{name}
DELETE /api/templates/{name}
GET /api/barcodes/formats
GET /api/auth/status
GET /api/auth/me
GET /api/auth/users
POST /api/auth/users
DELETE /api/auth/users/{idOrUserName}
GET /api/auth/config
PUT /api/auth/config
POST /api/auth/reload
POST /api/print/preview
POST /api/print/preview/html
POST /api/print/rendered
POST /api/print
GET /api/docx/converters
POST /api/docx/validate
GET /api/queue
GET /api/queue/{jobId}
POST /api/queue/{jobId}/reprint
```
## Render-Modi
| Modus | Bedeutung |
|---|---|
| `AUTO` | Modus wird anhand des Vorlagentyps ermittelt |
| `RAW` | Text/ZPL/EPL direkt ausgeben |
| `PDF` | HTML nach PDF rendern |
| `PDF_TEMPLATE` | PDF-Vorlage mit Koordinatenfeldern befüllen |
| `DOCX` | DOCX befüllen und als DOCX bereitstellen |
## Barcode-Platzhalter in HTML/ZPL
```html
<img src="{{barcode:CODE_128:serialNumber:360x90}}">
<img src="{{qr:serialNumber}}">
<img src="{{data_matrix:serialNumber:120x120}}">
```
ZPL direkt:
```zpl
^FO40,145^BCN,80,Y,N,N^FD{{serialNumber}}^FS
^FO40,260^BQN,2,6^FDLA,{{serialNumber}}^FS
```
## HTML-Tabelle
```html
<table>
<tbody>
{{#each:items}}
<tr>
<td>{{text:pos}}</td>
<td>{{text:partNumber}}</td>
<td>{{text:description}}</td>
<td>{{text:quantity}}</td>
<td><img src="{{barcode:CODE_128:serialNumber:360x90}}"></td>
</tr>
{{/each}}
</tbody>
</table>
```
## PDF_TEMPLATE-Tabelle
```json
{
"name": "positionsTable",
"type": "TABLE",
"source": "items",
"page": 1,
"x": 18,
"y": 78,
"width": 174,
"height": 125,
"rowHeight": 13,
"headerHeight": 8,
"maxRows": 9,
"overflow": "CUT",
"fontSize": 7,
"border": true,
"columns": [
{ "title": "Pos.", "field": "pos", "width": 12, "align": "CENTER" },
{ "title": "Artikel", "field": "partNumber", "width": 29 },
{ "title": "Barcode", "type": "BARCODE", "barcodeType": "CODE_128", "field": "serialNumber", "width": 39 }
]
}
```
## DOCX -> PDF -> Druck ohne LibreOffice: DOCX4J_FO
Ab v2.5 gibt es zusätzlich zum externen LibreOffice-Weg den Java-only-Konverter:
```json
{
"renderMode": "DOCX",
"docxConverter": "DOCX4J_FO"
}
```
Ablauf:
```text
DOCX-Vorlage
-> Platzhalter/Barcode/QR im DOCX füllen
-> docx4j-export-fo wandelt DOCX nach XSL-FO
-> Apache FOP erzeugt PDF
-> PDFBox druckt das PDF
```
Vorteile:
- keine LibreOffice-Installation notwendig
- läuft komplett in der Java-Anwendung
- gut für einfache DOCX-Vorlagen mit Text, einfachen Tabellen, Bildern und Kopf-/Fußzeilen
- geeignet als optionaler, serverinterner Konverter
Grenzen:
- Layouttreue ist nicht so hoch wie bei Word/LibreOffice
- komplexe Word-Layouts, Shapes, Textfelder, SmartArt, exakte Seitenumbrüche und komplizierte Tabellen müssen pro Vorlage geprüft werden
- für Produktionsdruck ist `PDF_TEMPLATE` oder `HTML -> PDF` weiterhin robuster und meist schneller
### Konverterstatus abrufen
```bash
curl http://localhost:8080/api/docx/converters
```
### DOCX4J_FO mit einer Vorlage validieren
```bash
curl -X POST "http://localhost:8080/api/docx/validate?converter=DOCX4J_FO" \
-H "Content-Type: application/json" \
-H "X-Printservice-Token: YOUR_TOKEN" \
-d @src/main/resources/examples/rest-validate-docx4j-fo-request.json
```
Beispielrequest:
```json
{
"printerAlias": "OFFICE_A4",
"templateName": "serienbegleitschein_docx",
"renderMode": "DOCX",
"docxConverter": "DOCX4J_FO",
"includeRenderedBase64": true,
"data": {
"serialNumber": "SNR000001",
"partNumber": "A123456",
"workorderNumber": "WO-100200"
}
}
```
Die Validierung prüft technisch, ob DOCX -> PDF erfolgreich erzeugt werden kann. Die Layout-Qualität muss anschließend visuell anhand des erzeugten PDFs geprüft werden.
### DOCX mit DOCX4J_FO drucken
```bash
curl -X POST http://localhost:8080/api/print \
-H "Content-Type: application/json" \
-H "X-Printservice-Token: YOUR_TOKEN" \
-d @src/main/resources/examples/rest-print-docx4j-fo-request.json
```
```json
{
"printerAlias": "OFFICE_A4",
"templateName": "serienbegleitschein_docx",
"renderMode": "DOCX",
"docxConverter": "DOCX4J_FO",
"copies": 1,
"pdfDpi": 300,
"data": {
"serialNumber": "SNR000001",
"partNumber": "A123456",
"workorderNumber": "WO-100200"
}
}
```
Empfehlung: `DOCX4J_FO` als optionale Alternative einbauen, aber pro Vorlage in der Druckfreigabe validieren. Für feste Formulare bleibt `PDF_TEMPLATE`; für dynamische Tabellen bleibt `HTML -> PDF`; für Etiketten bleibt `RAW_TCP/ZPL` die erste Wahl.
## Produktionsempfehlungen
- `RAW_TCP` für ZPL/EPL-Etikettendrucker verwenden.
- `PDF_TEMPLATE` für feste A4-Formulare verwenden.
- `HTML -> PDF` für flexible Tabellenformulare verwenden.
- Authentifizierung mindestens für `/api/print` aktivieren.
- Admin-Funktionen nach Initialeinrichtung schützen.
- Für Maschinen/Stationen separate Tokens mit eigenem User verwenden.
- `C:\printservice` regelmäßig sichern, besonders `templates`, `printers.json`, `auth.json` und `queue/print-jobs.json`.
## HTML→PDF: robuste XHTML-Normalisierung ab v2.5
Der HTML→PDF-Druckpfad normalisiert HTML-Vorlagen jetzt vor dem PDF-Renderer automatisch zu XHTML. Hintergrund: `openhtmltopdf` ist deutlich strenger als ein Browser. Normales Browser-HTML wie `<br>`, `<img>`, fehlende `</td>` oder ein UTF-8-BOM vor `<html>` kann sonst mit einem XML-Fehler abbrechen, zum Beispiel:
```text
Markup im Dokument vor dem Root-Element muss ordnungsgemäß formatiert sein.
```
Der Service führt deshalb vor dem Rendern aus:
```text
HTML-Vorlage + JSON-Daten
→ Platzhalter und Tabellenblöcke rendern
→ BOM/ungültige Steuerzeichen entfernen
→ HTML-Fragmente bei Bedarf in <html><body>...</body></html> einbetten
→ Browser-HTML mit jsoup zu XHTML normalisieren
→ openhtmltopdf → PDF
→ Druck oder Download
```
Zusätzlich gibt es einen Validierungsendpunkt:
```http
POST /api/html/validate
```
Beispiel:
```bash
curl -X POST http://localhost:8080/api/html/validate \
-H "Content-Type: application/json" \
-H "X-Printservice-Token: YOUR_TOKEN" \
-d @src/main/resources/examples/rest-validate-html-pdf-request.json
```
Eine erfolgreiche Antwort enthält unter anderem:
```json
{
"ok": true,
"templateName": "lieferschein_html_table",
"renderMode": "PDF",
"message": "HTML was rendered and normalized to XHTML successfully. It can be passed to openhtmltopdf."
}
```
Wenn die Vorlage versehentlich JSON oder PDF-Inhalt enthält, gibt der Service nun eine verständlichere Fehlermeldung aus, statt nur den SAX/XML-Fehler des Renderers weiterzugeben.
## v2.5: Lieferschein-Demos und HTML->PDF Fehlerbehebung
### HTML->PDF Fehler "Markup im Dokument vor dem Root-Element"
Der HTML->PDF Pfad normalisiert HTML jetzt vor dem openhtmltopdf Renderer. Dadurch werden typische Ursachen abgefangen: UTF-8 BOM, HTML-Fragmente ohne Root-Element, nicht XML-konforme Tags wie `<br>`, `<hr>` oder `<img>` ohne schließenden Slash.
Validierung vor dem Druck:
```bash
curl -X POST http://localhost:8080/api/html/validate \
-H "Content-Type: application/json" \
-H "X-Printservice-Token: YOUR_TOKEN" \
-d @src/main/resources/examples/rest-validate-html-pdf-request.json
```
### Einfache PDF-Lieferscheinvorlage
```text
config-example/templates/lieferschein_pdf_simple/
├── template.json
├── document.pdf
├── fields.json
├── sample-data.json
└── print-request.json
```
### DOCX-Lieferscheinvorlage
```text
config-example/templates/lieferschein_docx/
├── template.json
├── document.docx
├── sample-data.json
├── print-request.json
└── validate-request.json
```
Barcode-/QR-Platzhalter in DOCX müssen alleine in einem Absatz stehen:
```text
{{barcode:CODE_128:serialNumber:360x90}}
{{qr:serialNumber}}
```
Für Druck ohne LibreOffice verwendet das Beispiel `docxConverter=DOCX4J_FO`. Jede DOCX-Vorlage sollte vor produktiver Nutzung validiert werden.
## v2.5: Uebersichtlicher Windows-Assistent und Queue-Datenschutz
### Windows-/Drucker-Assistent im Webfrontend
Der Bereich **A. Gefundene Windows-Spooler-/CUPS-Drucker** ist jetzt als breite, scrollbar lesbare Liste umgesetzt. Die Bereiche **B. RAW_TCP fuer ZPL/EPL** und **C. Windows-Kommandos** wurden in eigene Modal-Dialoge verschoben. Dadurch bleiben lange Windows-Druckernamen lesbar und der Anwender wird Schritt fuer Schritt gefuehrt:
1. Diagnose laden.
2. Liste A pruefen und bei Bedarf einen Spooler-/CUPS-Drucker als `WINDOWS_SPOOLER` uebernehmen.
3. Fuer Zebra/Sato/CAB/Etikettendrucker den Button **B. RAW_TCP fuer ZPL/EPL** nutzen.
4. Fuer Windows-Serverinstallation den Button **C. Windows-Kommandos** oeffnen.
### Druckwarteschlange leeren
Die Druckwarteschlange des Printservice ist eine eigene JSON-basierte Historie unter:
```text
<configDir>/queue/print-jobs.json
```
Sie ist nicht die Windows-Spooler-Warteschlange. Manuell komplett leeren:
```bash
curl -X DELETE http://localhost:8080/api/queue \
-H "X-Printservice-Token: YOUR_ADMIN_TOKEN"
```
Nur Jobs aelter als X Tage loeschen:
```bash
curl -X POST "http://localhost:8080/api/queue/cleanup?olderThanDays=30" \
-H "Content-Type: application/json" \
-H "X-Printservice-Token: YOUR_ADMIN_TOKEN" \
-d "{}"
```
### Queue aus Datenschutzgruenden deaktivieren
Wenn keine Druckhistorie gespeichert werden soll, kann die Queue deaktiviert werden. Drucken funktioniert weiter, aber Jobs werden nicht gespeichert und Redruck ist nicht moeglich.
```json
{
"enabled": false,
"storeRequestsForReprint": false,
"autoCleanupEnabled": false,
"retentionDays": 0,
"maxStoredJobs": 0
}
```
Speichern per REST:
```bash
curl -X PUT http://localhost:8080/api/queue/settings \
-H "Content-Type: application/json" \
-H "X-Printservice-Token: YOUR_ADMIN_TOKEN" \
-d @src/main/resources/examples/rest-disable-queue-for-privacy-request.json
```
### Queue aktiv, aber ohne Originalrequest
Fuer eine reduzierte Historie kann die Queue aktiv bleiben, ohne den kompletten Druckrequest zu speichern. Dann bleiben Metadaten wie Zeit, User, Drucker, Vorlage und Status erhalten, aber kein Redruck aus der Historie.
```json
{
"enabled": true,
"storeRequestsForReprint": false,
"autoCleanupEnabled": true,
"retentionDays": 14,
"maxStoredJobs": 1000
}
```
### Queue-Einstellungen abrufen
```bash
curl -X GET http://localhost:8080/api/queue/settings \
-H "X-Printservice-Token: YOUR_ADMIN_TOKEN"
```
### Queue-Einstellungen speichern
```bash
curl -X PUT http://localhost:8080/api/queue/settings \
-H "Content-Type: application/json" \
-H "X-Printservice-Token: YOUR_ADMIN_TOKEN" \
-d @src/main/resources/examples/rest-update-queue-settings-request.json
```