Wicket 6 – Spaß mit IResource?

Hallo zusammen,

öfter höre ich in meinen Workshops und Vorträgen die Frage, wozu man eine IResource braucht.Da muss ich nicht lange überlegen.

Nehmen wir als Beispiel folgendes Requirement – wir möchten ein QR-Code dynamisch innerhalb unserer Anwendung generieren und zur Anzeige bringen.

Funktioniert über ein Servlet – prinzipiell – hiermit verlassen wir aber die Wicket-Welt und begehen einen Technologiebruch, der nicht notwendig ist. Es geht einfacher, und zwar mit IResource.

Zunächst erzeugen wir uns einen neuen Maven-Archetype.

[code]

mvn archetype:generate -DarchetypeGroupId=org.apache.wicket -DarchetypeArtifactId=wicket-archetype-quickstart -DarchetypeVersion=6.3.0 -DgroupId=de.effectivetrainings -DartifactId=wicket-6-resources -DarchetypeRepository=https://repository.apache.org/ -DinteractiveMode=false

[/code]

In der pom.xml konfigurieren wir uns noch eine Abhängigkeit auf IText, eine recht nette Bibliothek zum generieren von Barcodes aller Art.

[code language=”xml”]

com.itextpdf
itextpdf
5.2.0

[/code]

Wir schreiben uns zunächst einen einfachen Barcode-Generator. Das ist nichts anderes als die IText Standard-API und deswegen gehe ich nicht näher darauf ein.

[code language=”java”]

/**
* @author martin@effectivetrainings.de
*         Date: 29.11.12
*         Time: 21:42
*/
public class BarCodeGenerator {

public BufferedImage generate(String code)  {
BarcodeQRCode qrCode = new BarcodeQRCode(code,300,300, new HashMap<EncodeHintType, Object>());
java.awt.Image image = qrCode.createAwtImage(Color.BLACK,Color.WHITE);
return toBufferedImage(image);
}

public byte[] asRawBytes(String code){
ByteArrayOutputStream bout = new ByteArrayOutputStream();
try {
ImageIO.write(generate(code), "png",bout);
return bout.toByteArray();
} catch (Exception e) {
//here you should throw some kind of exception
return new byte[0];
}
}

private BufferedImage toBufferedImage(java.awt.Image image){
BufferedImage bi = new BufferedImage(image.getWidth(null),image.getHeight(null),BufferedImage.TYPE_INT_RGB);
Graphics bg = bi.getGraphics();
bg.drawImage(image, 0, 0, null);
bg.dispose();
return bi;

}

[/code]

Zum Beweis, dass das Ganze funktioniert schreiben wir uns einen sehr einfachen Test. Achtung, dieser Test schreibt eine Testdatei in euer /tmp Verzeichnis. Das ist kein echter Unit-Test, sondern nur ein Smoke-Test um zu prüfen, ob die Generierung tut.

[code language=”java”]public class BarCodeGeneratorTest {

@Test
public void testGenerateQRCode() throws Exception{
byte[] raw = new BarCodeGenerator().asRawBytes("http://www.effectivetrainings.de");
File outputfile = new File("/tmp/wicket-6-resource-example.png");
FileOutputStream fout = new FileOutputStream(outputfile);
fout.write(raw);

}
}

[/code]

Der Test macht genau, was wir erwarten würden und generiert in /tmp/ folgende Datei, die mit
jedem aktuellen Smartphone gescannt werden kann.
Ok, damit ist schon viel geschafft, wie aber bringen wir dieses “Bild” jetzt in unserer Webanwendung zur Anzeige.

Der langweilige  Weg wäre, hierfür ein Servlet zu schreiben und dieses Bild direkt in die Response zu rendern. Viel besser ist, das Ganze in eine IResource zu verpacken.

Da dies ein Standard-Use-Case ist, bringt Wicket hier natürlich schon etwas fertiges mit. Wir erzeugen uns einfach folgene Klasse:

[code language=”java”]

public class QRResource extends DynamicImageResource {
@Override
protected byte[] getImageData(Attributes attributes) {
return new byte[0];
}
}

[/code]

Die Klasse DynamicImageResource macht genau das, was wir brauchen und bietet schon eine Methode “getImageData” die zufälligerweise bereits ein byte-array erwartet. Die Implementierung sieht dann so aus:

[code language=”java”]

public class QRResource extends DynamicImageResource {

private BarCodeGenerator generator;

public QRResource(){
generator = new BarCodeGenerator();
}

@Override
protected byte[] getImageData(Attributes attributes) {
return generator.asRawBytes("woher kriegen wir den Code?");
}

public static ResourceReference asReference(){
return new ResourceReference("qr"){

@Override
public IResource getResource() {
return new QRResource();
}
};
}
}

[/code]

Die Frage ist nur, woher wir jetzt den Code bekommen, den wir eigentlich in das Bild kodieren möchten. Jetzt endlich kommt Wicket-6 so richtig in Fahrt, denn seid 1.5 kann man Resourcen mounten. Was bedeutet mounten? Die Resource bekommt eine feste URL. Außerdem kann ich Requests an diese Resource schicken kann – Und Requests beinhalten Parameter.

Die Resource mounten machen analog beispielsweise WebPages  in der Application-Klasse.

[code language=”java”]

/**
* @see org.apache.wicket.Application#init()
*/
@Override
public void init()
{
super.init();
mountResource("/qr/${code}", QRResource.asReference());

// add your configuration here
}

[/code]

Die mountResource-Methode erwartet nicht direkt eine Resource sondern eine ResourceReference, deren Erzeugung wir gleich mit in die QRResource und die Methode “asReference” verpackt haben.

Das Schöne ist tatsächlich, dass wir mit dem dynamischen Pfad alles haben, was wir brauchen um unsere Webanwendung um dynamische QR-Codes zu erweitern.

Was noch fehlt ist das Auslesen des Parameters in der Resource, noch fehlt uns der eigentliche Text, den wir in den QRCode kodieren möchten.

Die Methode getImageData bekommt als Parameter eine Klasse vom Type “Attributes”. Attributes bietet folgende Methoden.

Wunderschön, wir sehen, wir bekommen direkt Zugriff auf die allseits beliebten PageParameter.

Bauen wir das Ganze in unsere Anwendung ein. Wir löschen einfach alles, was wir nicht brauchen und enden mit einer leeren Page und einem minimalistischen Markup.

[code language=”java”]
public class HomePage extends WebPage {
private static final long serialVersionUID = 1L;

public HomePage(final PageParameters parameters) {
super(parameters);
}
}

[/code]
[code language=”html”]

<img alt="" src="/qr/effectivetrainings.de" />

[/code]

Wir haben nicht mal eine “wicket:id”:). Starten wir das Ganze mit der beigefügten Start-Klasse sieht man folgendes.

effective trainings url

Alle Sourcen finden Sich wie immer in meinem Wicket-6-Playground-Repo.

War dieser Blogeintrag für Sie interessant? Evtl. kann ich noch mehr für Sie tun.

Effective Trainings Wicket Workshop

Effective Trainings & Consulting - Martin Dilger



Hat Ihnen dieser Blog-Eintrag gefallen? Ich stelle in diesem Blog Informationen über Tools, Frameworks und Werkzeuge zur Verfügung, die mich produktiver machen. Vielleicht kann ich auch Ihnen helfen, produktiver zu werden.


Ich unterstütze Sie als freier Mitarbeiter bei der Entwicklung von Software-Projekten, Agiler Arbeit sowie Schulungen / Fortbildungen.


Jeden Tag ein bisschen produktiver - ab heute