E-Mail-Templates mit Thymeleaf (Teil 3 von 1)

Im dritten der bisher nur einteiligen Serie über E-Mail-Templates mit Thymeleaf zeige ich, wie sich HTML-basierte E-Mails erzeugen lassen, die vom Anwender mit seinem E-Mail-Programm der Wahl vor dem Versenden noch bearbeitet werden können (im ersten Teil wird es um die rein server-seitige Generierung von E-Mails gehen und der zweite Teil ist der Vorläufer zu diesem, bei dem es um Text-E-Mails geht).

Wunsch der Fachabteilung war es, zwei Datensätze zu vergleichen und die Unterschiede hervorzuheben. Die E-Mail sollte eine Tabelle enthalten, in dem diese Werte gegenübergestellt werden:

Vom Server vor-generierte E-Mail

Über einen mailto-Link lässt sich im body-Parameter nur Text übergeben (siehe Teil 2 dieser Reihe) und bei der Variante aus Teil 1 verschickt der Server selbst die E-Mail, ohne das der Anwender noch eingreifen könnte.

Die Lösung besteht nun darin, dass der Server eine .eml-Datei für den Download erzeugt. Die damit verknüpfte Anwendung ist das E-Mail-Programm, dass die Nachricht dann sendebereit anzeigt.

Controller-Code

    @GetMapping(path = "/{id}/vergleichen/{candidate}")
    public void mailvorlageZeitreihenVergleichen(
            @PathVariable("id") Long id,
            @PathVariable("candidate") Long candidateId,
            HttpServletResponse response
    ) throws IOException {
        Context context = new Context();
        context.setVariable("original", service.zeitreihe(id));
        context.setVariable("candidate", service.zeitreihe(candidateId));
        context.setVariable(ThymeleafEvaluationContext.THYMELEAF_EVALUATION_CONTEXT_CONTEXT_VARIABLE_NAME,
                new ThymeleafEvaluationContext(applicationContext, conversionService));
        String body = templateEngine.process("intern/zeitreihen/mailvorlageZeitreihenVergleichen", context);

        response.setContentType("text/plain");
        response.setHeader(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename=\"Negativliste_"
                + LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyyMMddHHmm")) + ".eml\"");
        BufferedWriter out = new BufferedWriter(new OutputStreamWriter(response.getOutputStream()));
        out.write(body);
        out.flush();
    }

Der Code besteht aus drei Abschnitten:

  1. Ermitteln der Daten und übertragen in den Context.
  2. Verarbeiten des Thymeleaf-Templates.
  3. Schreiben der Daten in den OutputStream der HttpServletResponse.

In den Context schreiben wir die Daten, auf die wir später im Template zugreifen wollen. Einzige Besonderheit ist hier der ThymeleafEvaluationContext. Diesen brauchen wir, damit ggf. eigene Converter genutzt werden können, z. B. für die Formatierung von Datumswerten (die Syntax mit den doppelt-geschweiften Klammern: ${{zeitraum}}).

Über den Header CONTENT_DISPOSITION teilen wir dem Browser zum einem mit, dass er die empfangenen Daten als Download anbieten soll und zum anderen legen wir hier auch den Dateinamen fest, den wir mit .eml enden lassen. Das zeigt sich dann für den Anwender wie folgt:

Download der vom Server gerenderten E-Mail-Vorlage

Das Template mit der E-Mail-Vorlage

Bei einer Spring-Boot-Anwendung liegt das Template in der Datei src/main/resources/templates/intern/zeitreihen/mailvorlageZeitreihenVergleichen.html und sieht so aus:

To:
Subject: Zeitreihen-Vergleich: <th:block th:text="${original.bilanzkreis}"></th:block> vs. <th:block th:text="${candidate.bilanzkreis}"></th:block>
X-Unsent: 1
Content-Type: text/html

<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
  <meta charset="UTF-8">
  <title>E-Mail-Vorlage: Zeitreihen vergleichen</title>
  <style>
    body {...} 
    th {...}
    .abweichung {
      color: red !important;
      font-weight: bold !important;
    }
  </style>
</head>
<body>
  <table>
    <thead>
    <tr>
      <th></th>
      <th>Originale Zeitreihe</th>
      <th>Vergleichs-Zeitreihe</th>
    </tr>
    </thead>
    <tbody>
    <tr>
      <th>Bilanzkreis</th>
      <td th:text="${original.bilanzkreis}"></td>
      <td th:text="${candidate.bilanzkreis}" th:classappend="${original.bilanzkreis != candidate.bilanzkreis} ? 'abweichung' : ''"></td>
    </tr>
    <tr>
      <th>Lieferant</th>
      <td th:text="${original.lieferantName}"></td>
      <td th:text="${candidate.lieferantName}" th:classappend="${original.lieferantName != candidate.lieferantName} ? 'abweichung' : ''"></td>
    </tr>
...

Das Template beginnt mit den Steuer-Header für die E-Mail. Ein Empfänger (To:) ist hier weggelassen und muss vom Anwender in seinem Mail-Programm ergänzt werden. Das X-Unsent sorgt dafür, dass das Mail-Programm weiß, dass die E-Mail noch nicht versendet wurde (BTW: Ich habe das Ganze nur mit Outlook ausprobiert). Schließlich teilen wir dem E-Mail-Programm noch mit, das der Inhalt (Body) HTML ist und nach der Leerzeile kommt auch schon der Body. Hier kann wie gewohnt die Thymleaf-Syntax verwendet werden (das klappt auch in den Header-Zeilen wie beim Betreff (Subject) zu sehen ist).

Code Week 2018

Zur Auftaktveranstaltung der Code Week 2018 kamen wieder viele interessierte Kinder und Jugendliche in die Zentralbibliothek am Hühnerposten. Unter dem Dach der Kids4IT habe ich wie letztes Jahr wieder die LEGO Education WeDo 2.0 Sets mitgebracht und insgesamt sieben 45-minütige Mini-Workshops mit bis zu 10 Kindern durchgeführt.

Die Presse und Medien war auch wieder vertreten und haben zum Teil noch am gleichen Tag berichtet:

NDR Hamburg Journal: https://www.ndr.de/fernsehen/sendungen/hamburg_journal/Code-Week-Fit-fuer-die-digitale-Zukunft-,hamj72798.html

Hamburg 1: https://www.hamburg1.de/nachrichten/37592/Auftaktveranstaltung_der_Coding_Wochen.html

Sat.1 Regional: 
https://www.sat1regional.de/auftakt-der-code-week-2018-in-hamburg/

Quelle: Screenshot aus dem Beitrag des NDR Hamburg Journal

Quelle: Screenshot aus dem Beitrag von Hamburg 1

Quelle: Screenshot aus dem Beitrag von Sat.1 Regional

Code Week 2018 – Schnupperkurse LEGO WeDo

Vom 6. bis 21. Oktober findet die europaweite Code Week start. Auch in Hamburg gibt es wieder viele spannende Workshops. Zur Auftaktveranstaltung der Hamburger Code Week in der Zentralbibliothek am Hühnerposten sind auch die kleinen LEGO Education WeDo 2.0 Roboter wieder im Einsatz. Eine vorherige Anmeldung ist nicht erfordlich, es liegen jedoch am Tag der Veranstaltung Listen aus, in die sich interessierte Kids eintragen mögen. Der Schnupperworkshop findet laufend in der Zeit von 11 bis 17 Uhr statt.

Und weil Ferien sind, gibt es schon mal vorweg ebenfalls einen Schnupperworkshop in der Bücherhalle Hamburg Volksdorf. Und zwar am 2. Oktober in der Zeit von 14 bis 17 Uhr. Eine Anmeldung ist auch hier diesmal nicht erforderlich.

Auf beiden Veranstaltungen wird der Forschungsroboter „Milo“ gebaut und mit ein App auf einem Tablet programmiert.

LEGO Roboter bauen in der Bücherhalle Volksdorf

Am 12. Mai gibt es wieder einen kostenlosen Kurs „LEGO Roboter bauen“ in der Bücherhalle Volksdorf. Mithilfe des Konstruktionsbausatzes LEGO Education WeDo 2.0 baut ihr kleine LEGO Roboter und programmiert diese in einer graphischen Programmiersprache auf einem Tablet-Computer.

Anmeldungen für Kinder zwischen 8 und 10 Jahren in der Bücherhalle Volksdorf, Eulenkrugstraße 55-57, 22359 Hamburg.

Milo spielt „Alle meine Entchen“

Wer sagt denn, das „Milo“, der freundliche Roboter aus dem LEGO Education WeDo 2.0 Set nicht auch Musik machen kann?

Mithilfe des von LEGO bereitgestellten SDK lässt sich der Piezo-Player im SmartHub ansprechen und so zum Beispiel dazu bringen, das Kinderlied Alle meine Entchen abzuspielen.

Jeden Tag etwas dazu lernen: Versehentliche Abhängigkeiten erkennen und verhindern (Maven Enforcer Plugin)

Das Enforcer-Plugin von Maven kann sicherstellen, dass bestimmte Abhängigkeiten zu anderen Bibliotheken (jars) nicht in der finalen auszuliefernden Datei landen, zum Beispiel Bibliotheken, die nur für automatisierte Tests benötigt werden.

Beispiel für eine Konfiguration des Plugins:

<plugin>
  <groupId>org.apache.maven.plugins</groupId>
  <artifactId>maven-enforcer-plugin</artifactId>
  <executions>
    <execution>
      <id>enforce-banned-dependencies</id>
      <goals>
        <goal>enforce</goal>
      </goals>
      <configuration>
        <rules>
          <bannedDependencies>
            <excludes>
              <exclude>junit:*:*:*:compile</exclude>
              <exclude>org.hamcrest:*:*:*:compile</exclude>
              <exclude>org.mockito:*:*:*:compile</exclude>
              <exclude>*:JUnitParams:*:*:compile</exclude>
              <exclude>*:hamcrest-date:*:*:compile</exclude>
              <exclude>*:*:*:test-jar:compile</exclude>
              <exclude>*:snh-commons-test:*:*:compile</exclude>
            </excludes>
          </bannedDependencies>
        </rules>
        <fail>true</fail>
      </configuration>
    </execution>
  </executions>
</plugin>

Diese Konfiguration stellt sicher, dass die gängigen Test-Bibliotheken nicht im produktiven Code verwendet werden.

 

„Milo“ hat Nachwuchs bekommen

Verkleinertes Modell des LEGO-WeDo Roboters "Milo"

Mini-Milo

Hallo!

Darf ich mich vorstellen: Ich bin „Mini-Milo“ der Sohn von meinem Papa „Milo“ (der berühmt-beliebte Roboter aus dem LEGO WeDo 2.0 Set). Ich erkunde gerade die Welt und hab auch schon eine ganz schöne Blume gefunden…

Ich bestehe schon aus 31 handverlesenen LEGO-Steinen und werde bestimmt noch wachsen. Wenn ich groß bin, möchte ich auch so ein toller Roboter wie mein Papa sein!

Unit-Testing: Exceptions testen [Java 8 Update]

In meinem Beitrag Unit-Testing: Exceptions testen habe ich gezeigt, wie sich Exceptions mit JUnit testen lassen, ohne dabei die Teststruktur verändern zu müssen (Arrange-Act-Assert; Given-When-Then) oder zusätzliche Bibliotheken verwenden zu müssen:

@Test
public void methodThrowsException() {
   IllegalArgumentException ex = foo(someIllegalArgument);
   assertThat(ex.getMessage(), is("foobarfoo"));
}

private Exception foo(FooBarFoo fooBarFoo) {
   try {
      subjectUnderTest.foo(someIllegalArgument);
      return null;
   } catch (IllegalArgumentException ex) {
      return ex;
   }
}

Dank Java 8 und Lambdas lässt sich der Code vereinfachen:

@Test
public void methodThrowsException() {
   Exception ex = tryCall(() -> subjectUnderTest.foo(someIllegalArgument));
   assertThat(ex.getMessage(), is("foobarfoo"));
}

private Exception tryCall(Callable<?> callable) {
   try {
      callable.call();
      return null;
   } catch (Exception ex) {
      return ex;
   }
}

Die Vereinfachung besteht nun darin, dass die Methode tryCall in eine Hilfsklasse ausgelagert werden kann – sie ist jetzt unabhängig vom konkreten Testfall.

Veröffentlicht unter Blog | Verschlagwortet mit

LEGO WeDo 2.0: Praxisbericht

Nach den Sommerferien werde ich an der Grundschule meiner Tochter einen Nachmittagskurs „LEGO Roboter bauen“ anbieten. Als Generalprobe habe ich heute mit den Kindern aus der Klasse meiner Tochter dies in drei Gruppen zu je 8 Schülerinnen und Schüler ausprobiert; Dauer jeweils ca. 90 Minuten.

IMG_20160718_120534298Gebaut und programmiert haben wir das Model zum Thema „Zugkraft und Reibung“ aus dem LEGO Education WeDo 2.0 Set. Jeweils zwei Kinder haben mit einem Set und einem Tablet gearbeit. Es war das erste Mal, das ich mit Kindern zusammengearbeitet habe und es hat allen Beteiligten sehr viel Spaß gemacht – allein, Hochleistungssport ist wahrscheinlich weniger anstregend 😉 Meine detailliert ausgearbeitete Planung und Vorbereitung konnte ich jedoch schon nach 30 Sekunden über den Haufen werfen und musste mich ersteinmal in der Situation pausenlos quaselnder Kinder zurecht finden. Auch das war ein Grund für diese Generalprobe. Wichtige Lehre: Immer einen Plan B bereit haben – zum Glück hatte ich noch ein Ersatzset und einmal das fertig aufgebaute Model. Die Kids sind schon tottraurig, wenn ihr Roboter nicht funktioniert, weil sie das falsche Zahnrad eingesetzt haben.

Große Probleme haben auch die eingesetzten Tablets bereitet, die des öfteren die Bluetooth-Verbindung zum SmartHub verloren. Hier half nur ein deaktivieren von Bluetooth und anschließendes reaktivieren. Überhaupt hatten die Kinder hier große Schwierigkeiten, die Verbindung überhaupt aufzubauen, auch wenn ich den SmartHubs vorher folgende Namen gegeben hatte:

  • Ada Lovelace
  • Charles Babbagge
  • Konrad Zuse
  • Christiane Floyd
  • Isaac Asimov

Die LEGO-Kästen und SmartHubs haben ebenfalls diesen Namen bekommen. Dies hat sich als sehr hilfreich erwiesen.

Die Tablets

Zurück zu den Tablets: Zum Einsatz kam fünf Mal das Acer Iconia Tab 10 (Modell 2016, A3-A40). Dieses Tablet würde ich derzeit aus folgenden Gründen für den Einsatz mit LEGO Education WeDo 2.0 nicht weiterempfehlen:

  • Häufige Abbrüche der Bluetooth-Verbindung
  • Keine Möglichkeit, Nutzerkonten einzurichten (trotz Android 6.0 Marshmallow)
  • Akkulaufzeit zu kurz
  • zu laute Lautsprecher

Letzteres ist deshalb negativ, weil die Kids ganz schnell die Videos in der zugehörigen App von LEGO gefunden haben.

Für das Tablet von Acer hatte ich mich entschieden, da es ein vielversprechendes Preis-/Leistungsverhältnis hatte (200 €; Tablets und LEGO Sets habe ich übrigens selbst gekauft und der Schule gespendet) und ein Markenname mir mehr Zuverlässigkeit versprach, als z. B. ein Tablet von Aldi. Tatsächlich hinterlässt mein Medion P10356 jedoch ein wesentlich stabilieren Eindruck, insbesondere bei der Bluetooth-Anbindung. Folgendes scheint mir hier ein guter Praxistest zu sein: Die LEGO App erlaubt es, bis zu drei SmartHubs mit einem Tablet zu verbinden. Für das Tablet von Medion absolut kein Problem, für das Tablet von Acer – Pustekuchen.

Was ich vorher hätte nachlesen können, aber bei Android 6.0 Marshmallow nicht erwartet hatte, war die fehlende Möglichkeit, auf den Tablets lokale Benutzerkonten einzurichten. Dadurch wollte ich verhindern, dass die Kids die Einstellungen verändern oder andere Apps starten. Tatsächlich haben die Kinder das gar nicht erst versucht. Und wenn doch, dann hätte die von mir auf allen Tablets installierte App „AppLock“ das hoffentlich verhindert.

Vor dem Einsatz hatte ich alle Tablets voll aufgeladen und ausgeschaltet. Ein Tablet hat die 3x 90 Minuten nicht überstanden. Auch hier hat sich der Plan B – ein komplettes LEGO Set und Tablet als Ersatz – als Rettung in der Not erwiesen.

Die LEGO App

Meine Befürchtungen, dass die Kinder bei der Bedienung des Tablets und der WeDo 2.0 App von LEGO (Full Version) Schwierigkeiten bekommen würden – ich hielt die Pfeil-Schaltflächen für zu klein – hat sich im großen und ganzen als unbegründet erwiesen. Tablets lassen sich mit dem Finger wirklich kinderleicht bedienen. Doch im Detail.

Das erste, was negativ ist, ist das Einführungsvideo auf der Startseite. Es nimmt den halben Bildschirm ein und die Kids haben natürlich sofort drauf geklickt – tschüss Aufmerksamkeit, denn alle Videos sprechen die Kinder an und bringt sie zum Lachen.

Das Blättern durch die Baueinleitung gestaltet sich problemlos und in den ca. 30 Minuten, die die Kinder für den Aufbau des Modells benötigt haben, herschte angenehme Ruhe, ja manchmal sogar richtige Stille. Wer baut und Teile raussucht, da haben sich die Kinder prima selbst organisiert; eine Hilfestellung in Baumeister und Materialmanager, wie es die Lehrerhandreichungen von LEGO empfehlen, waren gar nicht notwendig. Jungen-Teams waren deutlich schneller fertig als die Mädchen oder gemischte Teams (hier sind dann die vielen Videos dann aber doch wieder ein guter Lückenfüller; andere bauen aus den verbleibenden LEGO Bausteinen teils erstaunlich tolle Konstrukte (Hund, Tech-Mech)).

Komplizieter war dagegen das Programmieren, vor allem, weil die Kinder was anderes als das vorgegebene Programm programmieren wollten. Die eingblendete Tablettastatur hat dann auch die größten Schwierigkeiten verursacht. Der 3-2-1-Countdown hat sich dabei als echter Zeitfresser und Fruststifter erwiesen.

Die größte Herausforderung war, wie schon oben erwähnt, das Herstellen der Bluetooth-Verbindung. Tipp: Die Verbindung erst aufbauen lassen, wenn das Programm fertig ist (zum Ausprobieren, was einzelne Programmblöcke tun, dafür ist in 90 Minuten keine Zeit).

Experimentieren

Eigentlich sollten die Kinder noch ein wenig experimentieren und herausfinden, wie der Roboter mehr Reifen ziehen kann oder sich auf unterschiedlichen Untegründen verhält (ich hatte eine Holzplatte mit, auf der Teile mit Filz und mit einer dünnen Plexiglasscheibe beklemmt waren), aber das sich der Roboter bewegt, hat schon viel zur Begeisterung beigetragen. Die ständigen Abbrüche der Bluetooth-Verbindungen sind jedoch als Frustfaktor nicht zu unterschätzen – oder ein Roboter, der vom Tisch fällt und dann in seine Einzelteile zerfällt…

Erstaunlicherweise bewegen sich einige Modell schneller als andere. Ob da an leicht anderen Aufbauten lag, konnte ich in der Kürze der Zeit nicht herausfinden.

Abbau

Da ich dreimal hinter einander den Exkurs angeboten hatte, musste die Modelle auch wieder auseinander gebaut werden. Dies Durchzusetzen ist fast ein Ding der Unmöglichkeit („Kann ich den nicht mit nach Hause nehmen?“ oder „Robbi hat mir doch gar nichts getan.“) klappt dann aber doch, wobei ich den Kinder die Tablets aus der Hand nehmen musste.

Leider landen die Bauteile nur selten in den Fächern, in die sie hingehören. Hier ist ausreichend Zeit einzuplanen und die Sets nachzusortieren oder fehlende Teile zu identifizieren (meistens haben sie sich dann in einem anderen Kasten wiedergefunden).

Ein Bauteil scheint jetzt aber dennoch dauerhaft verlustig zu sein. Hier werde ich das Ersatzteileseit von LEGO mal ordern und prüfen, ob LEGO da den richtigen Riecher hat, welche Teile am häufigsten verloren gehen.

Auch hier gilt Plan-B: Ein Set als schnell verfügbares Ersatzteillager ist unabdingbar.

Fazit

Kinder und Veranstalter hatten unglaublich viel Spaß und ich freue mich schon auf den Kurs nach den Sommerferien.

Vielen Dank, liebe Kinder der 2c, dass ihr so toll mitgemacht habt!

P.S.:
Dieser Bericht wird noch durch Bilder und Videos ergänzt.

LEGO WeDo 2.0 – Das Vogelnest (Bird’s Nest)

Seit Januar haben Vater und Tochter ein gemeinsames Hobby: LEGO WeDo 2.0, der kleine Bruder von LEGO Mindstorms. Nachdem wir schon die Forschungssonde Milo, den Zugkraft-Käfer und andere Modelle nachgebaut haben, haben wir uns ein wenig auf Youtube nach weiteren Modellen umgesehen.

Die Macher von RoboCAMP haben in ihrem Video das Vogelnest (Bird’s Nest) auf WeDo 2.0 „upgegradet“. Das Video ist detailliert genug, um das Modell nachzubauen:

Vogelnest

Ich hab‘ das mal zum Anlaß genommen und eine Bauanleitung mit dem LEGO Digital Designer erstellt (dem allerdings der Smarthub und die Motoren und Sensoren von WeDo 2.0 fehlen).

Und so sieht das zugehörige Programm aus, das mit der zugehörigen Android App erstellt wird:

Programm

Das Programm wartet nach dem Start darauf, dass sich etwas dem Bewegungssensor nähert. Dann wird der Motor eingeschaltet und läuft so lange, bis sich das Objekt (der Eltervogel) wieder entfernt. Dies wiederholt sich in einer Endlosschleife.