Spring Integration DSL vs. Custom ObjectMapper

Spring Integration nutzt eigene ObjectMapper. Möchte man aber genau diesen konfigurieren, dann kommt man nicht umhin, einen eigenen HttpMessageConverter zu konstruieren und diesen explizit in der Flow-Definition zu setzen:

    @Bean
    IntegrationFlow flow() {
        return IntegrationFlows.from("channelname")
                .handle(Http.outboundGateway("http://server/api?query")
                        .httpMethod(HttpMethod.GET)
                        .messageConverters(customMessageConverter())
                        .expectedResponseType(new ParameterizedTypeReference<CustomViewType>() {
                        })
                        .requestFactory(requestFactory)
                )
                .handle(spec -> customService.doSomething((CustomViewType) spec.getPayload()))
                .get();
    }

    private HttpMessageConverter<?> customMessageConverter() {
        return new MappingJackson2HttpMessageConverter(objectMapper());
    }

    private ObjectMapper objectMapper() {
        ObjectMapper mapper = new ObjectMapper();
        mapper.registerModule(...);
        // eigene Konfiguration hier
        return mapper;
    }

Code Week 2019

Code Week

Vom 5. bis 20. Oktober findet wieder die europaweite Code Week statt. Wie auch in den letzten Jahren wird es wieder am Eröffnungstag einen LEGO WeDo 2.0 Roboter Workshop geben – und neu: die Zauberschule Informatik!

Und da Ferien sind, wird es auch in der Bücherhalle Volksdorf noch zwei Workshops geben.

Hier die Termine anlässlich der Code Week 2019:

Zentralbibliothek am Hühnerposten:
Sa., 5. Oktober, 10 bis 13 Uhr: Zauberschule Informatik (3 Kurse á 60 Minuten)
Sa., 5. Oktober, 14 bis 17 Uhr: Lego Roboter bauen (3 Kurse á 60 Minuten)

Bücherhalle Volksdorf
Di., 8. Oktober, 10 bis 13 Uhr: Lego Roboter bauen (dreistündiger Workshop)
Di., 15. Oktober, 10 bis 13 Uhr: Lego Roboter bauen (dreistündiger Workshop)

Code Week 2016 [CC BY 4.0. Körber-Stiftung, Foto: Sandra Schink]
Spaß und Spannung bei der Auftaktveranstaltung der CodeWeek 2017 in Hamburg [CC BY 4.0. Körber-Stiftung, Foto: Sandra Schink]
Die Code Week Hamburg ludt vom 6. bis 21. Oktober 2018 Kinder und Jugendliche dazu ein, ihre Begeisterung für das Tüfteln, Hacken und Programmieren zu entdecken. [CC BY 4.0. Körber-Stiftung, Foto: Sandra Schink]
Code Week 2018 [CC BY 4.0. Körber-Stiftung, Foto: Sandra Schink]

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