Initialer Commit
This commit is contained in:
540
docs/PRINTSERVICE_STANDALONE_DOKUMENTATION.md
Normal file
540
docs/PRINTSERVICE_STANDALONE_DOKUMENTATION.md
Normal file
@@ -0,0 +1,540 @@
|
||||
# Printservice Standalone Java 25 v2.3
|
||||
|
||||
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.3 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.3
|
||||
|
||||
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.
|
||||
Reference in New Issue
Block a user