Write Repositories and Projections

This commit is contained in:
Marcel Schwarz 2020-06-10 23:48:23 +02:00
parent 38db18a492
commit 88bc4517fe

View File

@ -96,7 +96,31 @@
Der eingehende Request geht wieder durch die Filterkette und wenn er an dem Filter in Listing \ref{code:jwt-authorization} ankommt, wird der User extrahiert und später im Security Manager als Autorisation für diesen Request gesetzt. Wichtig ist hier, dass keine weitere Prüfung auf die Existenz des Users durchgeführt wird, auch das Password wird nicht nochmal abgefragt. Der Grund hierfür ist, wenn es den User nicht geben würde, wie käme er dann an das Token? Der eingehende Request geht wieder durch die Filterkette und wenn er an dem Filter in Listing \ref{code:jwt-authorization} ankommt, wird der User extrahiert und später im Security Manager als Autorisation für diesen Request gesetzt. Wichtig ist hier, dass keine weitere Prüfung auf die Existenz des Users durchgeführt wird, auch das Password wird nicht nochmal abgefragt. Der Grund hierfür ist, wenn es den User nicht geben würde, wie käme er dann an das Token?
\subsection{Repositories} \subsection{Repositories}
Nachdem der Nutzer authentifiziert ist, bekommt er Zugriff auf alle REST-Repositories. Für jede Ressource, die oben im ER-Modell definiert ist gibt es ein entsprechendes Repository. Dieses wird größtenteils automatisch vom Classpath Scan von Spring automatisch implementiert. Die basis CRUD Operationen werden für jedes angelegte Repository komplett ohne zutun implementiert. Ein solches Repository ist beispielsweise das der Location.
\lstinputlisting[language=Java,firstline=8,caption=LocationRepository,label=code:location-repository]{../backend/src/main/java/de/hft/geotime/repositories/LocationRepository.java}
Das einzige was dort getan werden muss, ist die Angabe des Typs, der hier behandelt wird, hier Location, und der Datentyp des Primärschlüssels, hier ein Long. Die Bedeutung der Klasse "PagingAndSortingRepository" wird in einem späteren Kapitel genauer erläutert. Um den Link der Ressource anzupassen werden die Parameter in der "RepositoryRestRessource" Annotation genutzt. Der Pfad geht immer vom Rootpfad der Applikation aus.
Werden nun noch weitere Funktionalitäten in den Repositories benötigt können diese entweder selbst implementiert werden, oder durch gut ausgewählte Funktionsdefinitionen im Interface der Ressource deklariert werden. Spring kann die Implementierung dann aus dem Namen und den Parametern der Funktion ableiten. Als unser Maximalbeispiel dient hier das RecordRepository.
\lstinputlisting[language=Java,linerange={14-27,38-41,47-54},caption=RecordRepository,label=code:record-repository]{../backend/src/main/java/de/hft/geotime/repositories/RecordRepository.java}
In diesem Repository befinden sich diverse verschiedene Methoden wie Datenoperationen definiert werden können, ohne dass sie aktiv implementiert werden müssen. Es beginnt mit der funktion "findAllByStartdateBetween". Dieser Name kann direkt als Java Hibernate Statement interpretiert werden und nimmt als Parameter zwei Datumsangaben entgegen und eine Page. Die zwei Datumsangaben werden aus dem Schlüsselwort "Between" abgeleitet. Damit es sich aber um echt vergleichbare Daten handelt, müssen diese nach einem bestimmten Schema geparsed werden. Dieses Schema ist in der "DateTimeFormat" Annotation angegeben. Als Rückgabe liefert diese Funktion dann eine Menge aller Einträge zwischen diesen Daten.
Die nächste Funktion funktioniert nun ähnlich, nur dass dort über Eigenschaften mehrerer verlinkter Objekte gegangen werden kann. "findAllBy" ist wieder das selbe wie oben und zeigt an, dass eine Liste von Ergebnissen zurückgeliefert wird, aber "Account\_User\_Username" bedeutet nun folgendes: "Gehe zum Account des Records, dann zum User dieses Accounts und von diesem User dann den Username". Der gefundene Username wird dann mit dem Parameter der Funktion verglichen und die Ergebnisse entsprechend gefiltert. Weiter zeigt das "And" eine Verkettung eines weiteren Ausdrucks an. So können auch relativ komplexe Abfragen automatisch implementiert werden.
Reicht allerdings die obige Syntax nicht mehr aus, kann auch direkt eine Hibernate Abfrage über die "@Query" Annotation angegeben werden. Der Name der Funktion ist dann nicht mehr relevant für die Implementation, sondern nur noch für den Pfad unter dem die Funktion später zu erreichen ist. Die Query an der "today" Funktion bietet nun die Möglichkeit alle Einträge in der Records Tabelle für den aktuell anfragenden User zu bestimmen. Zusätzlich wird der Zeitraum noch auf den aktuellen Tag eingeschränkt, daher ergab sich auch der passende Name "today" für die Funktion. Der Nutzer wird automatisch über die "principal" Variable in der Abfrage eingefügt. Der Pricipal wird gesetzt, sobald der Authentication Filter den User erfolgreich eingeloggt hat. Weiter wird der aktuelle Tag über die Datenbankvariable "current\_date" abgefragt.
Zuletzt kann auch nach Standard SQL Werten wie "null" oder "not null" gefragt werden. Zu sehen ist dies in der zuletzt dargestellten Funktion.
Die Datei ist nicht vollständig abgedruckt, sondern nur Ausschnittsweise um die Grundkonzepte zu erläutern.
\subsection{Projections} \subsection{Projections}
Projections bieten nun noch weitere Möglichkeiten, Daten vor der Rückgabe noch zu transformieren und gegebenenfalls mit Zusatzdaten anzureichern. Eine Projektion ist ebenfalls durch ein Interface definiert und bring vor allem dann Vorteile wenn mehrere Ressourcen gebündelt angefragt werden müssen, um Beispielsweise eine Übersicht zu erstellen.
\lstinputlisting[language=Java,firstline=9,caption=RecordOverviewProjection,label=code:record-repository]{../backend/src/main/java/de/hft/geotime/entities/projections/RecordOverviewProjection.java}
Die "RecordOverviewProjection" reichert eine normale "Record" Ressource noch zusätzlich mit dem Username und den Accountnamen an. Dadurch muss nicht für jeden Record erneut einzeln der Accountname nachgeschlagen werden. Zudem wird noch ein, bei jeder Anfrage neu berechnetes, zusätzliches Feld angefügt. Die Dauer des Records in Minuten.
\section{Endpoints} \section{Endpoints}
\subsection{HAL und Paging} \subsection{HAL und Paging}
\section{Probleme und Lösungen} \section{Probleme und Lösungen}