Die Sourcen des DBFSample finden sich wie immer im GitHub.
Das DBFSample ist ein PoC um eine DBF Datei mit Java verarbeiten zu können.
Im Projekt haben wir einige DBF Dateien erhalten, deren Daten wir importieren/verarbeiten müssen. Das soll nicht meine Aufgabe sein, aber ich möchte für den Fall vorbereitet sein, dass ich dabei unterstützen darf.
Ich brauche also erstmal nur verstehen, was eine DBF Datei ist und wie ich grundlegend damit arbeiten kann.
Was ist eine DBF Datei
Eine DBF-Datei ist eine Standarddatenbankdatei, die von dBASE, einer Datenbankverwaltungssystemanwendung, verwendet wird. Es organisiert Daten in mehreren Datensätzen mit Feldern, die in einem Array-Datentyp gespeichert sind.
Aufgrund der frühzeitigen Einführung in der Datenbank und einer relativ einfachen Dateistruktur wurden DBF-Dateien allgemein als Standardspeicherformat für strukturierte Daten in kommerziellen Anwendungen akzeptiert.
https://datei.wiki/extension/dbf
Wie kann ich eine DBF Datei öffnen?
DBeaver
Da es sich um ein Datenbankformat handelt und ich grade das Tool DBeaver in meinen Arbeitsalltag eingeführt habe, lag es für mich nahe, die Datei mit DBeaver zu öffnen.
Dazu musste ich einen Treiber zu DBeaver hinzufügen um anschließend die Datei öffnen zu können. Ich konnte dann die Tabellenstruktur sehen, aber nicht auf die Tabelle zugreifen. Es gab eine Fehlermeldung, dass eine weitere Datei fehlen würde.
java.sql.SQLException: nl.knaw.dans.common.dbflib.CorruptedTableException: Could not find file 'C:\dev\tmp\adress.dbt' (or multiple matches for the file)
DBeaver Stack-Trace
Diese andere Datei gibt es nicht und sie ist auch nicht für den Zugriff erforderlich, wie der erfolgreiche Zugriff über die anderen Wege beweist.
Etwas ausführlicher hatte ich es im Artikel zu DBeaver geschrieben.
Excel
Excel öffnen, DBF Datei reinziehen, Daten ansehen. Fertig, so einfach kann es gehen.
Ich hatte mich allerdings durch die Bezeichnung Standarddatenbankdatei ablenken lassen, so dass ich zuerst die Wege über DBeaver und Java versucht hatte.
Java
Für den Zugriff mit Java habe ich die Bibliothek JavaDBF verwendet.
Die beiden Testklassen JavaDBFReaderTest und JavaDBFReaderWithFieldNamesTest waren schnell angepasst und eine weiter Klasse zum Auslesen aller Daten ReadItAll war dann auch problemlos möglich. Dabei ignoriere ich die Datentypen und lese einfach alles als Strings ein. Für den PoC reicht das.
DBF in PostgresDB speichern
Als Beispiel, wie ich mit den Daten weiterarbeiten kann, importiere ich sie in eine Postgres Datenbank.
Dazu lese ich zuerst die sample.dbf ein und erzeuge dann eine Tabelle sample mit allen Columns, die in sample.dbf vorhanden sind. Anschließend wird die Tabelle zeilenweise gefüllt.
Das meiste ist hardcodiert und die Spalten sind alles Text-Spalten, da ich die Datentypen aus der DBF Datei nicht auslese, aber für den PoC reicht das.
Die Sourcen des JEXIEPORTER finden sich wie immer im GitHub.
Der JEXIEPORTER ist ein PoC um Java Objekt in XML oder JSON Strings zu transformieren und aus den XML/JSON-Strings wieder Java Objekte zu transformieren. Außerdem um CSV-Dateien sowie Excel- und ODF/ODS-Dateien zu lesen und zu schreiben.
Der JEXIEPORTER führt folgende Schritte durch:
import sampledata.csv
convert data to xml
convert data to json
convert xml to objects
convert json to objects
export data as CSV to a temporary file and opens system csv-viewer
export data as xls to a temporary file and opens system xls-viewer
import temporary xlx file
Beispieldaten
Die Beispieldaten sampledata.csv habe ich auf GenerateData generieren lassen und habe dann die trennenden Komma durch Semikolon ersetzt.
Für ein Projekt musste ich ein PDF erzeugen und habe das dann mit iText umgesetzt.
Um mich in die Technik einzuarbeiten habe ich mir ein paar Bilder von Pixabay heruntergeladen, ein Projekt auf GitHub angelegt und dann schrittweise ein PDF mit Bildern erzeugt:
Vor ca. zwei Jahren durfte ich einen Impusvortrag zum Thema Redis halten. Den Inhalt der Folien kopiere ich hierher.
Durch welches Problem bin ich auf Redis gestoßen?
• Migration einer Anwendung von SAP Application Server mit drei Application Server Instanzen auf zwei Apache Tomcat Server • Session Data ging durch Wechsel der Tomcat Server verloren • Lösung: Sticky Session [im LoadBalancer] • Alternative Lösung: Persistieren den Session in der Application Datenbank • • zB in PROJECT_XYZ umgesetzt • • Problem bei der aktuellen Application: DB hat bereits Performanceprobleme • Erweiterte alternative Lösung: • • Speichern der Session Daten in einer eigenen Datenbank • • -> Fragestellung: Gibt es für so ein Scenario spezialisierte Datenbanken?
[Anmerkung aus 2023: Es gibt beim Tomcat ein Clustering/Session Replication Feature, das hatten wir aber aus Gründen nicht in Erwägung gezogen]
Was ist Redis
Der Name Redis steht für Remote Dictionary Server.
In-Memory-Datenbank • Alle Daten werden direkt im Arbeitsspeicher gespeichert • Dadurch sehr kurze Zugriffszeiten • Auch bei großen, unstrukturierten Datenmengen
Key-Value-Store • Hohe Performanz • Dank einfacher Struktur leicht skalierbar • Zu jedem Eintrag wird ein Schlüssel erstellt, über den die Informationen dann wieder aufgerufen werden können.
Redis ist über Module erweiterbar. Mitbewerber der Key-Value-Datenbanken: Amazon DynamoDB
Weitere Optionen • Inkrementelle Vergrößerung oder Verkleinerung • Lebenszeit von Werten setzen • Mit append dem hinterlegten Wert einen weiteren hinzufügen • Einträge mit rename umbenennen
Heute durfte ich einen Impusvortrag zum Thema Quarkus halten. Den Inhalt der Folien incl. Kommentare und die Notizen der Live Demo kopiere ich hierher.
Quarkus
Was ist Quarkus?
• Open-Source-Framework • Um Anwendungen für eine moderne, Cloud-native Welt zu erstellen • Kubernetes-natives Java-Framework • auf GraalVM und HotSpot zugeschnitten • aus den besten Java-Bibliotheken und -Standards entwickelt
Was ist Quarkus?
Traditionelle Java-Stacks wurden für monolithische Anwendungen mit langen Startzeiten und großem Speicherbedarf in einer Welt entwickelt, in der es noch keine Cloud, Container und Kubernetes gab. Java-Frameworks mussten sich weiterentwickeln, um den Anforderungen dieser neuen Welt gerecht zu werden.
Quarkus wurde entwickelt, um Java-Entwicklern die Möglichkeit zu geben, Anwendungen für eine moderne, Cloud-native Welt zu erstellen. Quarkus ist ein Kubernetes-natives Java-Framework, das auf GraalVM und HotSpot zugeschnitten ist und aus den besten Java-Bibliotheken und -Standards entwickelt wurde. Ziel ist es, Java zur führenden Plattform in Kubernetes- und Serverless-Umgebungen zu machen und Entwicklern ein Framework zu bieten, das eine größere Bandbreite an verteilten Anwendungsarchitekturen abdeckt.
Vollständig und absolut Open Source
https://quarkus.io/about/
Ausgewählte Features
• Live-Coding mit Dev-Modus • Microprofile-Integration für Cloud-native Anwendungen • Nutzung von Quarkus für RESTful-Anwendungen • Serverless Funktionen mit Quarkus Funqy • Integration mit Datenbanken • Performance • Erweiterungen
Live-Coding mit Dev-Modus
Eine der herausragenden Eigenschaften von Quarkus ist die Möglichkeit des Live-Codings. Mit dem Dev-Modus können Entwickler Änderungen am Code vornehmen und diese Änderungen werden sofort in der laufenden Anwendung wirksam, ohne dass ein Neustart erforderlich ist. Dies beschleunigt den Entwicklungsprozess erheblich und ermöglicht eine iterative Entwicklung in Echtzeit.
Serverless Funktionen mit Quarkus Funqy
Eine API für verschiedenen FaaS-Umgebungen wie AWS Lambda, Azure Functions, Google Cloud Functions, Knative und Knative Events (Cloud Events), daher eine sehr einfache API.
Quarkus Funqy ist Teil der serverlosen Strategie von Quarkus und zielt darauf ab, eine portable Java-API zum Schreiben von Funktionen bereitzustellen, die in verschiedenen FaaS-Umgebungen wie AWS Lambda, Azure Functions, Google Cloud Functions, Knative und Knative Events (Cloud Events) eingesetzt werden können. Es ist auch als eigenständiger Dienst nutzbar.
Da es sich bei Funqy um eine Abstraktion handelt, die mehrere verschiedene Cloud-/Funktionsanbieter und Protokolle umfasst, muss es eine sehr einfache API sein und verfügt daher möglicherweise nicht über alle Funktionen, die Sie von anderen Remoting-Abstraktionen gewohnt sind. Ein schöner Nebeneffekt ist jedoch, dass Funqy so optimiert und so klein wie möglich ist. Das bedeutet, dass Funqy zwar ein wenig an Flexibilität einbüßt, dafür aber einen Rahmen bietet, der wenig bis gar keinen Overhead hat.
Integration mit Datenbanken
Quarkus bietet Erweiterungen für verschiedene Datenbanken, wie z.B. PostgreSQL, MySQL, MongoDB und viele mehr.
Performance
Erweiterungen
Live Demo
Download
Import into Eclipse IDE
Prerequisites
Eclipse öffnen, Terminal mit Ubuntu (WSL) öffnen
Java und Maven Versionen überprüfen:
java --version
echo $JAVA_HOME
mvn --version
# bei mir wird die Maven Version nicht angezeigt, wohl aber der Pfad der Installation, über den prüfe ich die Version
ls - lisah /opt/maven
cd /mnt/c/dev/workspace/code-with-quarkus/
clear
Start Quarkus
Starte Projekt:
./mvnw compile quarkus:dev
Internal Web Browser öffnen: http://localhost:8080/ „Visit the DEV UI“ funktioniert nicht im Eclipse Browser
Return String ändern und hello-Seite neu laden -> kein Neustart notwendig!
curl http://localhost:8080/hello
# In Klasse GreetingResource ändern von:
@Produces(MediaType.TEXT_PLAIN)
# nach:
@Produces(MediaType.APPLICATION_JSON)
Änderung wird auch hier ohne Neustart übernommen, um sie zu zeigen verwende ich HTTPie statt cURL:
http http://localhost:8080/hello
Um das Hot Deployment für JUnit Tests zu zeigen gehe ich in das Terminal, mit dem ich Quarkus gestartet habe und drücke "r" für "re-run test". Der Test schlägt fehlt, da ich in GreetingResource den Rückgabestring geändert hatte. Ich passe den zu erwartenden Wert in GreetingResourceTest an und drücke dann wieder "r" im Terminal. Alle Tests sind jetzt grün. Es war kein Neustart notwendig.
Contexts and Dependency Injection (CDI)
Klasse GreetingService hinzufügen:
package org.acme;
import jakarta.enterprise.context.ApplicationScoped;
@ApplicationScoped
public class GreetingService {
private String greeting = "Hallo";
public String greeting(String name) {
return greeting + " " + name;
}
}
Die Klasse GreetingResource erweitern:
package org.acme;
import jakarta.inject.Inject;
import jakarta.ws.rs.GET;
import jakarta.ws.rs.Path;
import jakarta.ws.rs.Produces;
import jakarta.ws.rs.core.MediaType;
@Path("/hello")
public class GreetingResource {
@Inject
GreetingService service;
@GET
@Produces(MediaType.TEXT_PLAIN)
public String hello() {
return "Hello from Welt";
}
@GET
@Produces(MediaType.TEXT_PLAIN)
@Path("/greeting/{name}")
public String greeting(String name) {
return service.greeting(name);
}
}
Und wieder ohne Neustart testen:
http http://localhost:8080/hello/greeting/Welt
Configuration
Klasse GreetingService ändern:
package org.acme;
import jakarta.enterprise.context.ApplicationScoped;
@ApplicationScoped
public class GreetingService {
@ConfigProperty(name = "greeting")
private String greeting;
public String greeting(String name) {
return greeting + " " + name;
}
}
Testen:
http http://localhost:8080/hello/greeting/Welt
Der Test schlägt fehl, da die Property greeting noch nicht gesetzt wurde, was wir jetzt nachholen:
greeting=Huhu
Testen:
http http://localhost:8080/hello/greeting/Welt
Jetzt funktioniert es und es kommt "Huhu Welt" zurück.
Staged Properties: In DEV Modus möchten wir eine andere Begrüßung sehen:
greeting=Huhu
%%dev.greeting=Moin
Testen:
http http://localhost:8080/hello/greeting/Welt
Es funktioniert und es kommt "Moin Welt" zurück.
Metrics
Testen:
http http://localhost:8080/q/metrics
Fehler: Not Found
Mit Maven nachinstallieren (alternativ: Gradle oder Quarkus CLI):
Ich möchte eine lokale Oracle Datenbank mit Docker laufen lassen um so einige Sachen schnell lokal testen zu können. Hintergrund ist eine anstehende Cloud zu Cloud Migration einer bestehenden Anwendung, bei der zugleich die Oracle DB und Java aktualisiert werden wird.
Docker Image
Bei PostgreSQL war das mit der gedockerten Datenbank relativ einfach. Oracle macht es etwas schwieriger. Einfache Images, die man auf dem Docker Hub finden kann, existieren nicht. Statt dessen muss man ein GitHub Repository clonen und ein Shell Script ausführen, um ein Image zu erzeugen und in die lokale Registry zu schieben.
Frei verfügbar sind nur die Versionen Oracle Database 18c XE, 21c XE and 23c FREE. Ich entscheide mich, für die beiden Versionen 21c XE und 23c FREE das Image zu erzeugen und dann zuerst mit Version 23c FREE zu testen und ggf. später weitere Tests mit Version 21c XE machen zu können.
cd <workspace>
mkdir oracle
cd oracle
git clone https://github.com/oracle/docker-images.git
cd docker-images/OracleDatabase/SingleInstance/dockerfiles/
./buildContainerImage.sh -h
./buildContainerImage.sh -f 23.2.0
# Oracle Database container image for 'free' version 23.2.0 is ready to be extended:
#
# --> oracle/database:23.2.0-free
#
# Build completed in 608 seconds.
./buildContainerImage.sh -x 21.3.0
# Version 23.2.0 does not have Express Edition available.
Die Erzeugung des zweiten Images hat leider nicht funktioniert. Da das erste Image schon so lange gebraucht hat und ich das zweite Image nur proaktiv anlegen wollte, bin ich auch momentan nicht großartig motiviert, dem jetzt weiter nachzugehen. Version 23c FREE reicht erst einmal.
Image direkt von Oracle
Nach dieser Doku kann man das Image auch direkt aus der Oracle Registry ziehen. Zumindest für Oracle Database 23c Free – Developer Release.
Docker Container
Die Dokumentation hat einen speziellen Abschnitt für 23c FREE
Den Abschnitt auf jeden Fall gut ansehen, ich habe den Container mit folgendem Befehl erzeugt:
Die Wahl der Library fiel auf ZXing (“zebra crossing”), denn das ist die main library that supports QR codes in Java. und ich habe keine Anhaltspunkte finden können, warum ich eine andere Library nehmen sollte.
package deringo;
import java.awt.Desktop;
import java.io.IOException;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.HashMap;
import java.util.Map;
import com.google.zxing.BarcodeFormat;
import com.google.zxing.EncodeHintType;
import com.google.zxing.MultiFormatWriter;
import com.google.zxing.NotFoundException;
import com.google.zxing.WriterException;
import com.google.zxing.client.j2se.MatrixToImageWriter;
import com.google.zxing.common.BitMatrix;
import com.google.zxing.qrcode.decoder.ErrorCorrectionLevel;
public class TestMain {
public static void main(String args[]) throws WriterException, IOException, NotFoundException {
String data = "Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam";
Path path = Paths.get("./test.png");
// Encoding charset to be used
String charset = "UTF-8";
Map<EncodeHintType, ErrorCorrectionLevel> hashMap = new HashMap<EncodeHintType, ErrorCorrectionLevel>();
// generates QR code with Low level(L) error correction capability
hashMap.put(EncodeHintType.ERROR_CORRECTION, ErrorCorrectionLevel.L);
// invoking the user-defined method that creates the QR code
generateQRcode(data, path, charset, hashMap, 200, 200);// increase or decrease height and width accodingly
System.out.println("QR Code created successfully.");
Desktop.getDesktop().open(path.toFile());
}
public static void generateQRcode(String data, Path path, String charset, Map<EncodeHintType, ErrorCorrectionLevel> map, int h, int w)
throws WriterException, IOException {
BitMatrix matrix = new MultiFormatWriter().encode(new String(data.getBytes(charset), charset),
BarcodeFormat.QR_CODE, w, h);
MatrixToImageWriter.writeToPath(matrix, getExtension(path), path);
}
/**
* Own function until we have this in JDK<br>
* Finally, there is a new method Path#getExtension available right in the JDK as of Java 21:<br>
* https://stackoverflow.com/questions/3571223/how-do-i-get-the-file-extension-of-a-file-in-java/74315488#74315488
*/
public static String getExtension(Path path) {
String extension = path.getFileName().toString().substring(path.getFileName().toString().lastIndexOf('.') + 1);
return extension;
}
}
ZXing und Docx4J
Der QR Code lässt sich schön als PNG generieren. Allerdings brauche ich den QR Code in einem Word Dokument. Das Word Dokument wird mit Docx4J generiert.
package deringo;
import java.awt.Desktop;
import java.io.File;
import java.nio.file.Files;
import org.docx4j.dml.wordprocessingDrawing.Inline;
import org.docx4j.openpackaging.packages.WordprocessingMLPackage;
import org.docx4j.openpackaging.parts.WordprocessingML.BinaryPartAbstractImage;
import org.docx4j.openpackaging.parts.WordprocessingML.MainDocumentPart;
import org.docx4j.wml.Drawing;
import org.docx4j.wml.Jc;
import org.docx4j.wml.JcEnumeration;
import org.docx4j.wml.ObjectFactory;
import org.docx4j.wml.P;
import org.docx4j.wml.PPr;
import org.docx4j.wml.R;
public class TestMain {
public static void main(String[] args) throws Exception {
WordprocessingMLPackage wordPackage = WordprocessingMLPackage.createPackage();
MainDocumentPart mainDocumentPart = wordPackage.getMainDocumentPart();
mainDocumentPart.addStyledParagraphOfText("Title", "Welcome to my QR Code");
mainDocumentPart.addParagraphOfText("Welcome to my QR Code");
File image = new File("test.png" );
byte[] fileContent = Files.readAllBytes(image.toPath());
BinaryPartAbstractImage imagePart = BinaryPartAbstractImage
.createImagePart(wordPackage, fileContent);
Inline inline = imagePart.createImageInline(
"QR Code Image (filename hint)", "Alt Text", 1, 2, false);
P Imageparagraph = addImageToParagraph(inline);
mainDocumentPart.getContent().add(Imageparagraph);
File exportFile = new File("welcome.docx");
wordPackage.save(exportFile);
Desktop.getDesktop().open(exportFile);
}
private static P addImageToParagraph(Inline inline) {
ObjectFactory factory = new ObjectFactory();
P p = factory.createP();
R r = factory.createR();
p.getContent().add(r);
Drawing drawing = factory.createDrawing();
r.getContent().add(drawing);
drawing.getAnchorOrInline().add(inline);
// center image
PPr paragraphProperties = factory.createPPr();
Jc justification = factory.createJc();
justification.setVal(JcEnumeration.CENTER);
paragraphProperties.setJc(justification);
p.setPPr(paragraphProperties);
return p;
}
}
Das Ergebnis sieht brauchbar aus:
Allerdings habe ich die zuvor gespeicherte Datei verwendet. Ich möchte das aber on the fly machen, also ohne, dass ich den QR Code erst speichere und dann in das Word Dokument übernehme.
package deringo;
import java.awt.Desktop;
import java.awt.image.BufferedImage;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.util.HashMap;
import java.util.Map;
import javax.imageio.ImageIO;
import org.docx4j.dml.wordprocessingDrawing.Inline;
import org.docx4j.openpackaging.packages.WordprocessingMLPackage;
import org.docx4j.openpackaging.parts.WordprocessingML.BinaryPartAbstractImage;
import org.docx4j.openpackaging.parts.WordprocessingML.MainDocumentPart;
import org.docx4j.wml.Drawing;
import org.docx4j.wml.Jc;
import org.docx4j.wml.JcEnumeration;
import org.docx4j.wml.ObjectFactory;
import org.docx4j.wml.P;
import org.docx4j.wml.PPr;
import org.docx4j.wml.R;
import com.google.zxing.BarcodeFormat;
import com.google.zxing.EncodeHintType;
import com.google.zxing.MultiFormatWriter;
import com.google.zxing.client.j2se.MatrixToImageWriter;
import com.google.zxing.common.BitMatrix;
import com.google.zxing.qrcode.decoder.ErrorCorrectionLevel;
public class TestMain {
public static void main(String[] args) throws Exception {
WordprocessingMLPackage wordPackage = WordprocessingMLPackage.createPackage();
MainDocumentPart mainDocumentPart = wordPackage.getMainDocumentPart();
mainDocumentPart.addStyledParagraphOfText("Title", "Welcome to my QR Code");
mainDocumentPart.addParagraphOfText("Welcome to my QR Code");
BinaryPartAbstractImage imagePart = BinaryPartAbstractImage
.createImagePart(wordPackage, getQRCode());
Inline inline = imagePart.createImageInline(
"QR Code Image (filename hint)", "Alt Text", 1, 2, false);
P Imageparagraph = addImageToParagraph(inline);
mainDocumentPart.getContent().add(Imageparagraph);
File exportFile = new File("welcome.docx");
wordPackage.save(exportFile);
Desktop.getDesktop().open(exportFile);
}
private static P addImageToParagraph(Inline inline) {
ObjectFactory factory = new ObjectFactory();
P p = factory.createP();
R r = factory.createR();
p.getContent().add(r);
Drawing drawing = factory.createDrawing();
r.getContent().add(drawing);
drawing.getAnchorOrInline().add(inline);
// center image
PPr paragraphProperties = factory.createPPr();
Jc justification = factory.createJc();
justification.setVal(JcEnumeration.CENTER);
paragraphProperties.setJc(justification);
p.setPPr(paragraphProperties);
return p;
}
public static byte[] getQRCode() throws Exception {
String data = "Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam";
// Encoding charset to be used
String charset = "UTF-8";
Map<EncodeHintType, ErrorCorrectionLevel> hashMap = new HashMap<EncodeHintType, ErrorCorrectionLevel>();
// generates QR code with Low level(L) error correction capability
hashMap.put(EncodeHintType.ERROR_CORRECTION, ErrorCorrectionLevel.L);
BitMatrix matrix = new MultiFormatWriter().encode(new String(data.getBytes(charset), charset),
BarcodeFormat.QR_CODE, 200, 200);
BufferedImage bi = MatrixToImageWriter.toBufferedImage(matrix);
ByteArrayOutputStream baos = new ByteArrayOutputStream();
ImageIO.write(bi, "png", baos);
byte[] bytes = baos.toByteArray();
return bytes;
}
}
Allerdings ändert sich bei jedem Durchlauf der Initialization Vector (IV). Dadurch kann man den verschlüsselten Wert (der in dem Beispielcode nicht ausgegeben wird) nicht in einem zweiten Durchlauf wieder entschlüsseln. Das entspricht somit noch nicht dem, was ich brauche.
Mein Code
Ich möchte lediglich einen String verschlüsseln, über den QR-Code weitergeben und später soll der verschlüsselte Wert wieder entschlüsselt werden. Daher muss ich, anders als in dem Beispiel oben, Passwort, Salt und IV speichern.
Dazu brauche ich einen IV im String Format, den ich mir als erstes generieren lasse:
public static String generateIV() {
byte[] iv = new byte[16];
new SecureRandom().nextBytes(iv);
return Base64.getEncoder().encodeToString(iv);
}
Passwort, Salt und IV-String werden in den Properties gespeichert:
Damit kann ich die Methoden zum Erstellen von SecretKey und IvParameterSpec erstellen und darauf aufbauend die Methoden encrypt(String) und decrypt(String):
Spring Initializr verwenden. Als Dependencies Spring Web und OAuth2 Client hinzufügen.
Zip-File herunterladen und in das Projekt entpacken. Warten bis Maven alle Dependencies heruntergeladen hat und anschließend Oauth2Application starten.
Unter http://localhost:8080 wird eine Login-Seite angezeigt:
Add a Home Page
Hier halte ich mich an den Guide. Die WebJars kannte ich bereits, aber noch nicht deren Locator. Den muss ich mal in meinem JSF Projekt ausprobieren.
In your new project, create index.html in the src/main/resources/static folder. You should add some stylesheets and JavaScript links so the result looks like this:
None of this is necessary to demonstrate the OAuth 2.0 login features, but it’ll be nice to have a pleasant UI in the end, so you might as well start with some basic stuff in the home page.
If you start the app and load the home page, you’ll notice that the stylesheets have not been loaded. So, you need to add those as well by adding jQuery and Twitter Bootstrap:
The final dependency is the webjars "locator" which is provided as a library by the webjars site. Spring can use the locator to locate static assets in webjars without needing to know the exact versions (hence the versionless /webjars/** links in the index.html). The webjar locator is activated by default in a Spring Boot app, as long as you don’t switch off the MVC autoconfiguration.
With those changes in place, you should have a nice looking home page for your app.
Oauth2Application starten. Mir wird wieder die Login-Seite angezeigt. Ich nehme die spring-boot-starter-oauth2-client Dependency aus der pom.xml heraus, starte Oauth2Application neu und sehe eine leere Seite.
Mir ist nicht ganz klar, woran das liegt, also mache ich erstmal weiter mit dem Guide, in der Hoffnung dass es am Ende laufen wird.
Add a New GitHub App
Webhook: Active Flag deaktivieren
MÖÖÖÖÖÖP FALSCH
Ich habe oben eine GitHub App angelegt und keine OAuth App. Also nochmal von vorn:
In einem anderen Tab des Browsers war ich bereits in GitHub eingeloggt:
Wenn ich den Seitenaufruf in einem neuen privaten Browserfenster tätige, sieht die Anmeldung so aus:
In beiden Fällen wird anschließend eine leere Seite angezeigt:
Auch die index.html bleibt leer:
Also irgendwas ist da noch nicht richtig. Anscheinend hatte ich die index.html nicht richtig gespeichert, die Datei war noch leer. Also den Code hinzugefügt und gespeichert.
Anschließend funktioniert es auch:
Sehr schön, da kann der Zukunftsingo sich ja freuen, hier weiter herumzuexperimentieren, sobald wieder etwas Zeit ist.
Ein Report soll als Word Dokument (.docx) verfügbar gemacht werden.
Dazu wird zuerst eine Word Datei als Template erstellt mit Platzhaltern an den entsprechenden Stellen. Die Ersetzung einzelner Wörter ist relativ trivial, das Befüllen einer Tabelle mit n Zeilen stellte sich dann etwas kniffliger heraus. Diese Notizen und das dazugehörige Beispielprojekt dienen als Erinnerungsstütze, falls der Zukunftsingo nach dem aktuellen Projekt noch einmal etwas mit docx4j machen darf.
Word Template erstellen
Word mit einem leeren Dokument öffnen, einen Platzhalter für eine Überschrift, einen Text und eine Tabelle hinzufügen.
Die Überschriften der Tabelle sind fix und werden nicht ersetzt. Die Anzahl der Zeilen in dem Report ist dynamisch. Die Tabelle erhält keine Zeilen, diese werden später hineingeneriert.
Würde der Report eine Tabelle mit einer fixen Anzahl von Zeilen vorsehen, könnte man die ganze Tabelle in das Dokument eintragen und und später die einzelnen Werte per Wortersetzung hineingenerieren.
Die Tabelle bekommt noch einen Titel, um sie so eindeutig identifizieren zu können. Beispielsweise wenn das Dokument mehrere Tabellen enthält.
Abschließend unter dem Namen template.docx als Word-Dokument speichern, nicht als Strict Open XML-Dokument!
Projekt einrichten
Ein neues Maven Projekt anlegen.
Die Datei template.docx nach src/main/resources kopieren.
Java Klasse anlegen, die das Template läd und eine neue Zieldatei im tmpdir mit teilgeneriertem Name anlegt. Dadurch erhalten wir bei jedem Durchlauf eine neue Datei, um sie ggf. noch einmal miteinander vergleichen zu können, und das Aufräumen übernimmt das Betriebssystem für uns.
Als Dummyaction wird das Template in die Zieldatei kopiert. An dieser Stelle kommt im nächsten Schritt Docx4J ins Spiel um das Template zu befüllen.
Im letzten Schritt lassen wir uns die Zieldatei mit Word öffnen um so direkt das Ergebnis überprüfen zu können.