diff --git a/asciidocs/android-1.adoc b/asciidocs/android-1.adoc new file mode 100644 index 0000000..ae96678 --- /dev/null +++ b/asciidocs/android-1.adoc @@ -0,0 +1,359 @@ += Android - Course - 1 - Introduction +ifndef::imagesdir[:imagesdir: images] +:icons: font +:source-highlighter: highlight.js +:experimental: +:sectnums: +:toc: +ifdef::backend-html5[] + +// https://fontawesome.com/v4.7.0/icons/ +icon:file-text-o[link=https://raw.githubusercontent.com/UnterrainerInformatik/documents/main/asciidocs/{docname}.adoc] ‏ ‏ ‎ +icon:github-square[link=https://github.com/UnterrainerInformatik/documents] ‏ ‏ ‎ +endif::backend-html5[] + +link:https://htl.unterrainer.info/index.html[BACK to Index] + +link:https://htl.unterrainer.info/android.html[BACK to Android - Course] + +== Grundlagen Android-Entwicklung + +image:android-1-0.png[align="center",width="100%"] + +=== Was ist Android? +- OS- und Programmierplattform von Google für mobile Geräte entwickelt. +- Basiert auf Linux-Kernel und Java + +image:android-1-1.png[align="center",width="100%"] + +=== Warum Android? +- Populärste Plattform für mobile Apps +- Einfach zu entwickelnde Apps +- Viele Verteilungsmöglichkeiten + +=== Wie funktioniert Android? +image:android-1-2.png[align="center",width="50%"] + +. Deine Apps leben hier zusammen mit den System-Apps (E-Mail, SMS, ...) +. UI Komponenten, Ressourcen-Management, Lifecycle-Management. Stellt native Bibliotheken für die App zur Verfügung. +. Jede App läuft in ihrer eigenen Instanz der Android Runtime. +. Stellt Hardware-Abstraktionen zur Verfügung. Jede App hat Zugriff auf die Hardware, aber nur über die API. +. Foundation. Kümmert sich um threading, low-level memory management, etc... + +== Android Studio IDE +Installation unter: link:https://developer.android.com/studio/install[https://developer.android.com/studio/install] + +==== +IMPORTANT: Hausübung: +Installieren und auf die neueste Version updaten. +==== + +== Kotlin Grundzüge +=== Kotlin +image:android-1-3.png[align="center",width="100%"] + +Seit 2019 ist Kotlin die bevorzugte Programmiersprache für Android-Apps bei Google +Seitdem ist die Sprache sehr populär geworden + +=== Java vs. Kotlin +==== Null Safety +|=== +|Java |Kotlin + +a|Jedes Objekt ist null by default +[java] +---- +public Integer number; +---- + +a|Kein Objekt kann null werden +[source,kotlin] +---- +val number: Int +---- +...außer man gibt es so an: +[source,kotlin] +---- +val number: Int? = null +---- +|=== + +==== Extension Functions +|=== +|Java |Kotlin + +a|Ohne Erweiterung (z.B. Project Lombok) nicht verfügbar. (Ev. noch über Vererbung... Aber nicht jedes zu erweiternde Projekt gehört auch euch.) + +a|Standardmäßig in die Sprache eingebaut. Einfach den Funktionsnamen in jedem beliebigen File mit dem jeweiligen Klassennamen prefixen. +[source,kotlin] +---- +fun String.removeFirstLastChar(): String = this.substring(1, this.length - 1) + +fun main(args: Array) { + val myString= "Hello Everyone" + val result = myString.removeFirstLastChar() + println("First character is: $result") +} +---- +|=== + +==== Code +|=== +|Java |Kotlin +a|* Eher ausführlich (getter, setter). +* Gibts schon länger als so manches modernes Sprachkonstrukt (z.B. async). +a|* Sehr kompakt. +* Weniger Lines Of Code. + +=> Besser zu erstellen, lesen und zu warten. +|=== + +==== Coroutines +|=== +|Java |Kotlin + +a|Background Threads. (z.B.: ExecutorService) + +a|* Eigener Threadpool +* In Sprache fix eingebaut + +[source,kotlin] +---- +fun main() = runBlocking { // this: CoroutineScope + launch { // launch a new coroutine and continue + delay(1000L) // non-blocking delay for 1 second + println("World!") // print after delay + } + println("Hello") // main coroutine continues +} +---- + +Output: +Hello +World! + +|=== + +==== Data Classes +|=== +|Java |Kotlin + +a|* Händisch (viel Code oder generiert) +* Durch Verwendung von Project Lombok + +a|* Ein eingebautes Sprachkonstrukt +* Getter, Setter, HashCode(), Equals(), toString()... werden automatisch implementiert. +|=== + +==== Smart Casts +|=== +|Java |Kotlin + +a|Entwickler muss die Typen überprüfen und angeben. +a|* Casting Checks werden automatisch durchgeführt (smart casts feature). +* Redundante Checks werden entfernt. +|=== + +==== No Checked Exceptions +|=== +|Java |Kotlin + +a|Es gibt checked Exceptions. + +(Meiner Meinung nach ist das eine gute Sache) +a|Es gibt keine checked Exceptions. + +(Meiner Meinung nach eine schlechte Sache, weil ... nun ... exception handling ist wichtig und sollte nicht optional sein.) +|=== + +==== Higher-Order Funcs und Lambdas +|=== +|Java |Kotlin + +a|In abgespeckter Form verfügbar oder mit alten Sprachkonstrukten nachgebaut. +a|Inherent in Sprache enthalten. + +[source,kotlin] +---- +max(strings, { a, b -> a.length < b.length }) + +/** +The function max is a higher-order function, +as it takes a function value as its second argument. +This second argument is an expression that is itself a function, +called a function literal, +which is equivalent to the following named function: +**/ + +fun compare(a: String, b: String): Boolean = a.length < b.length +---- +|=== + + +=== Übung +Spielwiese unter: link:https://play.kotlinlang.org/koans/overview[https://play.kotlinlang.org/koans/overview] + +==== +IMPORTANT: Hausübung: Alle Aufgaben auf dieser Seite links durchmachen. +Android-Studio herunterladen: https://developer.android.com/studio/releases +==== + +== Komponenten einer Android-App + +=== AndroidManifest.xml +Jedes Android-App-Projekt muss dieses File im Root des Projekt-Source-Sets enthalten. +Es enthält wichtige Informationen über die App für: + +- Build Tools +- The Android Operating System +- Google Play + +Ist eine XML-Datei, die die Struktur der App beschreibt. Ist XML, damit sie leichter von Menschen gelesen und ohne Editor geändert werden kann. +Wird beim Kompilieren in ein binäres Format übersetzt (wegen Geschwindigkeit). + +Es enthält Informationen über die Applikation: + +* functions +* services +* broadcast receivers +* content producers +* components +* The apps permissions +* The apps rights (permissions, die andere Apps brauchen werden, damit sie von eurer App Daten bekommen können.) + +=== Application Components +image:android-1-4.png[align="center",width="80%"] + +image:android-1-5.png[align="center",width="100%"] + +* Fragments + +Teile einer Maske, die innerhalb einer Activity verwendet werden können. + +* Views und ViewGroups + +Views sind GUI-Elemente. ViewGroups sind Container für Views. + +* Layouts + +XML Files, die die Struktur der Activities, Fragments und ViewGroups beschreiben. + +* Resources + +Images, Strings, UI Layouts... + +* Manifest + +Explained above. + +== Meine erste Android-App +Erstmal Android Studio herunterladen und installieren, falls dies nicht schon erfolgt ist. https://developer.android.com/studio/releases + +== Jetpack Compose + +Modernes UI Toolkit für Android-Entwicklung. +Reactive Programming Model. +Verwendet Kotlin Sprachkonstrukte. +Vollständig deklarativ wie flutter, Swift UI oder React Native (sag ihm WAS du willst, nicht WIE du es willst). + +...beschreibt die UI als Funktion, die Daten in eine UI-Hierarchie transformiert +...wenn sich die Daten ändern, ruft das Framework diese Funktionen automatisch auf und aktualisiert so die UI + +image:android-1-7.png[align="center",width="100%"] + +=== Mein erster Knopf in Jetpack-Compose +image:android-1-6.png[align="center",width="80%"] + +==== Neues Projekt anlegen + +In der Android Studio IDE, ist ein Projekt-Template eine Android-App, die alle notwendigen Teile hat, um eine Applikation zu erstellen. +Es hilft dir, ein neues Projekt einzurichten. + +Schritt für Schritt werden wir unsere erste Android-App erstellen und sie auf dem Emulator starten: + +1. Android Studio starten, indem du auf das Android Studio Icon in deinem Dock oder wo auch immer du Android Studio gespeichert hast, klickst. + +2. Wenn Android Studio startet, klicke auf "Start a new Android Studio project" am Welcome-Screen. +Alternativ kannst Du auch auf File und dann New Project klicken. + +3. Klicke auf "Empty Activity" und klicke dann auf Next. (Compose ist inzwischen Standard) + +image:android-1-8.png[align="center",width="100%"] + +Wenn der leere Compose Activity Screen geladen hat, wirst Du Felder sehen, wie 'Name', 'Package name', 'Save location', 'Language', und 'Minimum SDK'. +Für dieses Kapitel nennen wir unser Projekt 'Android Community' und lassen die anderen Einstellung in Ruhe. +Die Sprache ist per Voreinstellung auf Kotlin. +Minimum SDK ist API 21: Android 5.0 (Lollipop). Das ist die minimale Version von Android, auf der unsere App laufen können wird. +In diesem Fall wird unser Projekt auf ca. 98.8% aller Android-Geräte laufen können. +Die Einstellungen im Bild unten, wie der Name und das Package, sind nur Beispiele. Du kannst Deine eigenen Werte eingeben oder es einfach so lassen, wie es voreingestellt ist. + +image:android-1-9.png[align="center",width="100%"] + +Jetzt auf 'Finish' klicken. + +Jetzt kannst Du Dich ein wenig in den Packages umsehen. Dir wird auffallen, dass es eine 'MainActivity' Klasse gibt, die von 'Activity' ableitet. +Darin gibt es eine fun (Function) 'onCreate', die eine Methode in 'ComponentActivity' überlädt. + +Du wirst auch eine Funktion 'setContent' sehen, die den Inhalt einer Composable Funktion setzt. +Sie nimmt einen Lambda-Ausdruck, die die Elemente enthält, die angezeigt werden sollen. In unserem Fall enthält er das Theme unserer Applikation. + +In der 'Greeting' Funktion werden wir jetzt unsere eigene Grußformel "Hello, Android +Community" einsetzen und das Programm ausführen (run). + +[source,kotlin] +---- +class MainActivity : ComponentActivity() { + override fun onCreate(savedInstanceState:Bundle?) { + super.onCreate(savedInstanceState) + setContent { + AndroidCommunityTheme { + Surface( + modifier = Modifier.fillMaxSize(), + color = MaterialTheme.colors.background + ) { + Greeting("Hello, Android Community") + } + } + } + } +} +---- + + + +== Android Project Structure +image:android-1-10.png[align="center",width="50%"] +Das ist das Projekt-Root-Verzeichnis. Es enthält alle Dateien, die für das Projekt wichtig sind. + +=== Manifest Ordner +Der Manifest-Ordner ist die Quelle der Wahrheit für die Android-App; er enthält AndroidManifest.xml. +Klicke auf AndroidManifest.xml, um es zu öffnen und Dir den Inhalt anzusehen. + +image:android-1-11.png[align="center",width="100%"] +Das Java-Verzeichnis enthält alle Kotlin- (.kt) und Java-Dateien (.java), die wir erstellen, wenn wir unsere Android-Apps erstellen. +Beispielsweise, im nächsten Bild, haben wir ein Package mit (androidTest) und (test), und hier fügen wir unsere Tests hinzu. +Klicke einfach einmal alle Verzeichnisse durch um deren Inhalt zu sehen. + +image:android-1-12.png[align="center",width="100%"] +Im AndroidTest-Verzeichnis haben wir unsere UI-Tests, und im Test-Verzeichnis haben wir unsere Unit-Tests. +Unit-Tests testen kleine Teile unseres Codes, um sicherzustellen, dass das gewünschte Verhalten wie erwartet ist. +Test-Driven Development (TDD) ist während der App-Entwicklung hervorragend und wertvoll. +Einige Unternehmen folgen dieser Regel, andere nicht. Aber grundsätzlich ist es eine gute Praxis, den Code immer zu testen. + +Das res-Verzeichnis enthält XML-Layouts, UI-Strings, drawable-Images und Mipmap-Icons. +Auf der anderen Seite enthält das values-Verzeichnis viele nützliche XML-Dateien wie Dimensionen, Farben und Themes. +Klicke auf das res-Verzeichnis, um Dich mit dem vertraut zu machen, was dort ist, da wir es im nächsten Kapitel verwenden werden. + +image:android-1-13.png[align="center",width="100%"] +Zuletzt, im Gradle-Scripts Verzeichnis, haben wir die build-Konfiguration, die die beschreiben auf welche Art unser Projekt gebaut werden soll für unser Projekt enthalten. +Es ist in Module aufgeteilt und die Einträge in der obersten Datei gelten für alle Module. + +Ein Modul ist eine Sammlung von Source-Dateien und Build-Einstellungen, die es Dir ermöglichen, Dein Projekt in verschiedene Einheiten mit bestimmten Zwecken zu unterteilen. + +== Deine App mit Gradlew laufen lassen + +Zuerst mal die installierte Gradle-Version checken mit ./gradlew (GradleWrapper). + +Mit ./gradlew clean und ./gradlew build kannst Du Dein Projekt bauen. + +Ansonsten kannst Du auch einfach auf den grünen Pfeil in der IDE klicken. \ No newline at end of file diff --git a/asciidocs/android-2.adoc b/asciidocs/android-2.adoc new file mode 100644 index 0000000..4bea53b --- /dev/null +++ b/asciidocs/android-2.adoc @@ -0,0 +1,448 @@ += Android - Course - 2 - Jetpack Compose +ifndef::imagesdir[:imagesdir: images] +:icons: font +:source-highlighter: highlight.js +:experimental: +:sectnums: +:toc: +ifdef::backend-html5[] + +// https://fontawesome.com/v4.7.0/icons/ +icon:file-text-o[link=https://raw.githubusercontent.com/UnterrainerInformatik/documents/main/asciidocs/{docname}.adoc] ‏ ‏ ‎ +icon:github-square[link=https://github.com/UnterrainerInformatik/documents] ‏ ‏ ‎ +endif::backend-html5[] + +link:https://htl.unterrainer.info/index.html[BACK to Index] + +link:https://htl.unterrainer.info/android.html[BACK to Android - Course] + +== Android Views mit Jetpack Compose +image:android-2-0.png[align="center",width="100%"] + +=== Einleitung +Das wichtigste Element bei Android-Apps ist natürlich die GUI. +Früher hat man die GUI mit Java-Code entwickelt und mit XML-Dateien konfiguriert (imperativ). + +Seit ein paar Jahren ist man allerdings dazu übergegangen, diese mit Kotlin-Code unter Verwendung der deklarativen Library Jetpack Compose zu entwickeln (deklarativ). + +=== Programm +Geht nach Kapitel 1 vor, um ein neues Projekt zu erstellen. +Das Projekt sollte "Compose Basics" heißen und wir werden die Vorschau-Funktion verwenden, um die UI-Elemente zu betrachten. + +. In unserem Projekt, mach ein neues Package und nenne es `components`. +Hier werden wir alle Komponenten hinzufügen, die wir erstellen. + +. Erstelle ein Kotlin File und nenne es `UiComponents.kt`. +Innerhalb von UIComponent, erstelle eine composable Funktion, nenne sie `EditTextExample()` und rufe die `OutlinedTextField()` Funktion auf. +Dabei wirst Du aufgefordert, den erforderlichen Import zu importieren, der androidx.Compose.material.OutlinedTextField ist: ++ +[source,kotlin] +---- +@Composable +fun EditTextExample() { +OutlinedTextField() +} +---- ++ +. Wenn man sich die Signatur von OutlineTextField() genauer ansieht, bemerkt man neben der @Composable-Annotation, dass sie eine Menge Parameter hat, die alle optional sind und mit einem Default-Wert versehen sind. +Auf diese Weise können Sie die Felder parametrisieren und an Ihre Bedürfnisse anpassen. ++ +image:android-2-1.png[align="center",width="100%"] ++ +. Für dieses Beispiel werden wir nicht viel mit DU machen, die wir erstellen. Wir wollen nur zeigen wie man sie grundsätzlich erstellt. +. Jetzt, damit wir unsere Methode für unsere Zwecke anpassen können, können wir die Parameter, die wir nicht benötigen, weglassen und nur die verwenden, die wir benötigen. +Wir werden die folgenden Parameter verwenden: +`Text`, `Color` und `Modifier`, um es zu dekorieren. +Dem Modifier können wir eine Liste von Modifier-Objekten übergeben, die wir verwenden möchten. So setzen wir zum Beispiel `fillMaxWidth()`, um die Breite des Textfelds auf die maximale Breite zu setzen. +Wenn wir `fill()` aufrufen, wird das Textfeld voll gefüllt. Wir setzen `padding(top)` auf `16.dp`, was zusätzlichen Platz entlang jeder Kante des Inhalts in dp anwendet. Es hat auch einen Wert, der der Wert ist, der im OutlinedTextField eingegeben werden soll, und ein onValueChange-Lambda, das auf die Eingabeänderung hört. ++ +==== +IMPORTANT: Hausübung: +Installieren und auf die neueste Version updaten. +==== ++ +. Wir weisen unserem `OutlinedText` auch Randfarben zu, wenn er fokussiert und nicht fokussiert ist, um verschiedene Zustände darzustellen. Wenn Sie also mit der Eingabe beginnen, ändert sich die Boxfarbe zu Blau, wie im Code angegeben: ++ +[source,kotlin] +---- +@Composable +fun EditTextExample() { + OutlinedTextField( + value = "", + onValueChange = {}, + label = { Text(stringResource(id = R.string.sample)) }, + modifier = Modifier + .fillMaxWidth() + .padding(top = 16.dp), + colors = OutlinedTextFieldDefaults.colors( + focusedBorderColor = Color.Blue, + unfocusedBorderColor = Color.Black, + ) + ) +} +---- ++ +Importiere alle notwendigen Libraries und definiere R.string.sample mit einem beliebigen Wert. +. Wir haben auch einen anderen Typ von `TextField`, der nicht umrandet ist. Wenn Sie die Eingabeparameter von `OutlinedTextField` vergleichen, werden Sie feststellen, dass sie ziemlich ähnlich sind: ++ +[source,kotlin] +---- +@Composable +fun NotOutlinedEditTextExample() { + TextField( + value = "", + onValueChange = {}, + label = { Text(stringResource(id = R.string.sample)) }, + modifier = Modifier + .fillMaxWidth() + .padding(top = 16.dp), + colors = OutlinedTextFieldDefaults.colors( + focusedBorderColor = Color.Blue, + unfocusedBorderColor = Color.Black, + ) + ) +} +---- ++ +. Sie können die Anwendung ausführen, indem Sie die Compose-Funktionen innerhalb der `@Preview`-Compose-Funktion hinzufügen. In unserem Beispiel können wir `UIElementPreview()` in der gleichen Klasse erstellen, was eine Vorschau-Funktion ist, um unsere Benutzeroberfläche anzuzeigen. In der nächsten Abbildung ist die obere Ansicht ein `OutlinedTextField`, während die zweite ein normales `TextField` ist. ++ +[source,kotlin] +---- +@Preview(showBackground = true) +@Composable +fun UiElementPreview() { + MyApplicationTheme { + Column(Modifier.padding(start = 5.dp, end = 5.dp)) { + EditTextExample() + NotOutlinedEditTextExample() + ButtonWithIcon() + } + } +} +---- ++ +Die `Column` sagt Compose, dass die Elemente in der Spalte angeordnet werden sollen. Wenn Sie die Anwendung ausführen, sollte das Ergebnis etwas Ähnliches wie in der nächsten Abbildung sein. ++ +image:android-2-2.png[align="center",width="30%"] ++ +. Jetzt schauen wir uns Beispiele für Schaltflächen an. Wir werden verschiedene Möglichkeiten betrachten, Schaltflächen mit unterschiedlichen Formen zu erstellen. Wenn Sie mit der Maus über der Button()-Compose-Funktion schweben, sehen Sie, welche Eingabe sie akzeptiert, wie in der nächsten Abbildung dargestellt. ++ +image:android-2-3.png[align="center"] ++ +In unserem zweiten Beispiel werden wir versuchen, eine Schaltfläche mit einem Symbol darauf zu erstellen. Darüber hinaus werden wir Text hinzufügen, was entscheidend ist, wenn Schaltflächen erstellt werden, da wir den Benutzern angeben müssen, welche Aktion die Schaltfläche ausführt oder was passieren wird, wenn sie darauf geklickt wird. +. Gehen Sie also voran und erstellen Sie eine Compose-Funktion in der gleichen Kotlin-Datei und nennen Sie sie `ButtonWithIcon()`. Importieren Sie dann die `Button()`-Compose-Funktion. +. Innerhalb dieser Funktion müssen Sie ein `Icon()` mit `painterResource`-Eingabe, einer `contentDescription`, einem `Modifier` und `tint` importieren. Wir benötigen auch `Text()`, der unserer Schaltfläche einen Namen gibt. In unserem Beispiel werden wir `tint` nicht verwenden: ++ +[source,kotlin] +---- +@Composable +fun ButtonWithIcon() { + Button(onClick = {}) { + Icon( + painterResource(id = R.drawable.shopping_cart_24px), + contentDescription = stringResource(id = R.string.shop), + modifier = Modifier.size(20.dp) + ) + Text(text = stringResource(id = R.string.buy), Modifier.padding(start = 10.dp)) + } +} +---- ++ +Damit dieser Code einwandfrei funktioniert müssen sie das Icon zuerst herunterladen (https://fonts.google.com/icons?icon.platform=android, ein Icon suchen, auf den Tab 'Android' klicken und dann auf 'Download' klicken) und dann über den `Resource-Manager` im `Android-Studio` als `drawable` importieren (`+` und `Import drawables`). Dort bekommt es auch automatisch einen Namen und einen Eintrag in den Resourcen, über den wir das Bild ansprechen können. In meinem Beispiel ist dies `shopping_cart_24px`, bei Ihnen kann der Name aber durchaus anders sein (kommt auf das gewählte Icon an). +Alternativ können Sie sich so ein File hier herunterladen https://github.com/UnterrainerInformatik/lectures/blob/main/android/chapter1/shopping_cart-24px.xml. +Danach noch das importierte XML-File anklicken und checken, ob alle Attribute richtig gesetzt sind (in meinem Fall war `tint` auf einen Farbwert gesetzt, den ich nicht im Resource-File hatte). +Weiters müssen Sie noch die Strings `R.string.shop` und `R.string.buy` in den Resourcen anlegen (für Quick-Action mit Maus über den Fehler fahren, `Create string value resource`). ++ +. Erstellen Sie eine neue Compose-Funktion und nennen Sie sie `CornerCutShapeButton()`. In diesem Beispiel werden wir versuchen, eine Schaltfläche mit abgeschnittenen Ecken zu erstellen: ++ +[source,kotlin] +---- +@Composable +fun CornerCutShapeButton() { + Button(onClick = {}, shape = CutCornerShape(10)) { + Text(text = stringResource(id = R.string.cornerButton)) + } +} +---- ++ +. Erstellen Sie eine neue Compose-Funktion und nennen Sie sie `RoundCornerShapeButton()`. In diesem Beispiel werden wir versuchen, eine Schaltfläche mit abgerundeten Ecken zu erstellen: ++ +[source,kotlin] +---- +@Composable +fun RoundCornerShapeButton() { + Button(onClick = {}, shape = RoundedCornerShape(10.dp)) { + Text(text = stringResource(id = R.string.rounded)) + } +} +---- ++ +. Erstellen Sie eine neue Compose-Funktion und nennen Sie sie `ElevatedButtonExample()`. In diesem Beispiel werden wir versuchen, eine Schaltfläche mit Erhebung zu erstellen: ++ +[source,kotlin] +---- +@Composable +fun ElevatedButtonExample() { + Button( + onClick = {}, + elevation = ButtonDefaults.buttonElevation( + defaultElevation = 8.dp, + pressedElevation = 10.dp, + disabledElevation = 0.dp + ) + ) { + Text(text = stringResource(id = R.string.elevated)) + } +} +---- ++ +. Nachdem Sie die Anwendung gestartet haben, sollte ein Bild ähnlich wie in der nächsten Abbildung erscheinen. Die erste Schaltfläche nach dem TextField ist `ButtonWithIcon()`, die zweite ist `CornerCutShapeButton()`, die dritte ist `RoundCornerShapeButton()`, und schließlich haben wir `ElevatedButtonExample()`. ++ +image:android-2-4.png[align="center",width="30%"] ++ +. Schauen wir uns nun ein letztes Beispiel an, da wir im Laufe des Buchs verschiedene Ansichten und Stile verwenden und dabei mehr lernen werden. Lassen Sie uns jetzt eine Bildansicht betrachten; die `Image()`-Compose-Funktion akzeptiert mehrere Eingaben, wie in der nächsten Abbildung dargestellt. ++ +image:android-2-5.png[align="center"] ++ +. In unserem Beispiel wird die `Image()` nur einen `painter` haben, der nicht null sein kann, was bedeutet, dass Sie ein Bild für diese Compose-Funktion bereitstellen müssen, eine Inhaltsbeschreibung für die Barrierefreiheit und einen Modifier: ++ +[source,kotlin] +---- +@Composable +fun ImageViewExample() { + Image( + painterResource(id = R.drawable.android_logo), + contentDescription = stringResource(id = R.string.image), + modifier = Modifier.size(200.dp) + ) +} +---- ++ +Das Bild gehört wieder über den Resource-Manager importiert (Download hier, falls Sie kein eigenes finden: https://github.com/UnterrainerInformatik/lectures/blob/main/android/chapter1/android-logo.png) und die `contentDescription` wieder als String gesetzt. ++ +. Sie können auch versuchen, mit anderen Dingen zu experimentieren, wie zum Beispiel das Hinzufügen von `RadioButton()`- und `CheckBox()`-Elementen und deren Anpassung. +Wenn Sie Ihre Anwendung ausführen, sollte das Ergebnis etwas Ähnliches wie in der nächsten Abbildung sein. ++ +image:android-2-6.png[align="center",width="30%"] ++ +Ihre `@Preview`-Funktion sollte jetzt so aussehen: ++ +[source,kotlin] +---- +@Preview(showBackground = true) +@Composable +fun UiElementPreview() { + MyApplicationTheme { + Column(Modifier.padding(start = 5.dp, end = 5.dp)) { + EditTextExample() + NotOutlinedEditTextExample() + + ButtonWithIcon() + CornerCutShapeButton() + RoundCornerShapeButton() + ElevatedButtonExample() + + ImageViewExample() + } + } +} +---- + +=== Funktionsweise + +Jede Compose-Funktion ist mit der `@Composable`-Annotation versehen. Diese Annotation teilt dem Compose-Compiler mit, dass der bereitgestellte Compiler dazu bestimmt ist, die bereitgestellten Daten in eine Benutzeroberfläche umzuwandeln. Es ist auch wichtig zu beachten, dass der Name jeder Compose-Funktion ein Nomen sein muss und kein Verb oder Adjektiv sein darf. Google stellt diese Richtlinien bereit. +Jede von Ihnen erstellte Compose-Funktion kann Parameter akzeptieren, die es der App-Logik ermöglichen, Ihre Benutzeroberfläche zu beschreiben oder zu ändern. + +Wir erwähnen den Compose-Compiler, was bedeutet, dass dieser Compiler irgendein spezielles Programm ist, das den von uns geschriebenen Code analysiert und ihn in etwas übersetzt, das der Computer verstehen kann – oder Maschinensprache. + +In `Icon()` gibt `painterResouce` das Symbol an, das wir der Schaltfläche hinzufügen werden. `contentDescription` hilft bei der Barrierefreiheit, und der `modifier` wird verwendet, um unser Symbol zu dekorieren. + +Wir können die erstellten UI-Elemente vorab anzeigen, indem wir die @Preview-Annotation hinzufügen und `showBackground = true` setzen: + +[source,kotlin] +---- +@Preview(showBackground = true) +---- ++ +`@Preview` ist sehr mächtig und wir werden uns die richtige Verwendung in späteren Kapiteln genauer ansehen. + + +== Scrollable List mit Jetpack Compose +image:android-2-7.png[align="center"] + +=== Einleitung +Beim Erstellen von Android-Anwendungen sind wir uns alle einig, dass Sie wissen müssen, wie Sie eine `RecyclerView` erstellen, um Ihre Daten anzuzeigen. Mit unserer neuen, modernen Art, Android-Anwendungen zu erstellen, können wir `LazyColumn` verwenden, was sich ähnlich verhält. + +In diesem Rezept werden wir uns Zeilen, Spalten und `LazyColumn` ansehen und eine scrollbare Liste mit unseren Dummy-Daten erstellen. +Zusätzlich werden wir dabei auch etwas Kotlin lernen. + +Wir werden das Projekt Compose Basics weiterhin verwenden, um eine scrollbare Liste zu erstellen. Daher müssen Sie die vorherige Anleitung abgeschlossen haben, um zu beginnen. + +=== Programm +. Lassen Sie uns jetzt unsere erste scrollbare Liste erstellen. Zuerst brauchen wir jedoch Dummy-Daten, die in unserer Liste angezeigt werden sollen. Erstellen Sie daher ein Paket namens `favoritecity`, in dem unser scrollbares Beispiel leben wird. +. Innerhalb des Pakets `favoritecity` erstellen Sie eine neue Datenklasse und nennen Sie sie `City`; dies wird unsere Dummy-Datenquelle sein - `data class City()`. +. Modellieren wir unsere City-Datenklasse. Stellen Sie sicher, dass Sie die erforderlichen Imports hinzufügen, sobald Sie die annotierten Werte hinzugefügt haben: ++ +[source,kotlin] +---- +data class City( + val id: Int, + @StringRes val nameResourceId: Int, + @DrawableRes val imageResourceId: Int +) +---- ++ +. Jetzt müssen wir in unseren Dummy-Daten eine Kotlin-Klasse erstellen und diese Klasse `CityDataSource` nennen. In dieser Klasse werden wir eine Funktion namens `loadCities()` erstellen, die unsere Liste von `List` zurückgibt, die wir in unserer scrollbaren Liste anzeigen werden. ++ +[source,kotlin] +---- +class CityDataSource { + fun loadCities(): List { + return listOf( + City(1, R.string.spain, R.drawable.spain), + City(2, R.string.new_york, R.drawable.newyork), + City(3, R.string.tokyo, R.drawable.tokyo), + City(4, R.string.switzerland, R.drawable.switzerland), + City(5, R.string.singapore, R.drawable.singapore), + City(6, R.string.paris, R.drawable.paris), + ) + } +} +---- ++ +. Jetzt haben wir unsere Dummy-Daten, und es ist Zeit, diese in unserer scrollbaren Liste anzuzeigen. Erstellen Sie eine neue Kotlin-Datei in unserem `components`-Paket und nennen Sie sie `CityComponents`. In `CityComponents` erstellen wir unsere `@Preview`-Funktion: ++ +[source,kotlin] +---- +@Preview(showBackground = true) +@Composable +private fun CityCardPreview() { + CityApp() +} +---- ++ +. Innerhalb unserer `@Preview`-Funktion haben wir eine weitere Compose-Funktion, `CityApp()`; innerhalb dieser Funktion rufen wir unsere `CityList`-Compose-Funktion auf, die die Liste als Parameter hat. In dieser Compose-Funktion rufen wir außerdem `LazyColumn` auf, und items wird `CityCard(cities)` sein. Weitere Erläuterungen zu `LazyColumn` und items finden Sie im Abschnitt "Funktionsweise": ++ +[source,kotlin] +---- +@Composable +fun CityList(cityList: List) { + LazyColumn { + items(cityList) { cities -> + CityCard(cities) + } + } +} +---- ++ +. Schließlich erstellen wir unsere `CityCard(city)`-Compose-Funktion: ++ +[source,kotlin] +---- +@Composable +fun CityCard(city: City) { + Card(modifier = Modifier.padding(10.dp), + elevation = 4.dp) { + Column { + Image( + painter = painterResource(city.imageResourceId), + contentDescription = stringResource(city.nameResourceId), + modifier = Modifier + .fillMaxWidth() + .height(154.dp), + contentScale = ContentScale.Crop + ) + Text( + text = LocalContext.current.getString(city.nameResourceId), + modifier = Modifier.padding(16.dp), + style = MaterialTheme.typography.h5 + ) + } + } +} +---- ++ +Wenn Sie die `CityCardPreview`-Komponierfunktion ausführen, sollte eine scrollbare Liste erstellt werden, wie in der nächsten Abbildung zu sehen ist. +image:android-2-7.png[align="center"] + +=== Funktionsweise +In Kotlin gibt es zwei Arten von Listen: unveränderliche (`immutable`) und veränderliche (`mutable`). Unveränderliche Listen sind Listen mit Elementen, die nicht geändert werden können (es werden Kopien zurückgegeben und nicht die eigentliche Liste), während veränderliche Listen Elemente enthalten, die in der Liste modifiziert werden können. Um eine Liste zu definieren, können wir sagen, dass eine Liste eine generische, geordnete Sammlung von Elementen ist, und diese Elemente können in Form von Ganzzahlen, Zeichenketten, Bildern usw. vorliegen, was größtenteils vom Typ der Daten abhängt, die unsere Listen enthalten sollen. + +Zum Beispiel haben wir in unserem Beispiel eine Zeichenkette und ein Bild, die unsere Lieblingsstädte anhand ihres Namens und Bildes identifizieren. + +In unserer `City`-Datenklasse verwenden wir `@StringRes` und `@DrawableRes`, um dies direkt aus den `res`-Ordnern für Drawable und String einfach abzurufen, und sie repräsentieren auch die `ID` für die Bilder und Zeichenketten. + +Wir haben `CityList` erstellt und sie mit der `composable`-Funktion annotiert und die Liste der Stadtobjekte als Parameter in der Funktion deklariert. Eine scrollbare Liste in Jetpack Compose wird mit `LazyColumn` erstellt. Der Hauptunterschied zwischen `LazyColumn` und `Column` besteht darin, dass bei Verwendung von `Column` nur kleine Elemente angezeigt werden können, da Compose alle Elemente auf einmal lädt. + +Zusätzlich kann eine Spalte nur feste komponierbare Funktionen enthalten, während `LazyColumn`, wie der Name schon sagt, den Inhalt bei Bedarf und auf Abruf lädt, was es gut für das Laden weiterer Elemente bei Bedarf macht. Außerdem verfügt `LazyColumn` über eine eingebaute Scrollfähigkeit, was die Arbeit für Entwickler erleichtert. + +Wir haben auch eine komposable Funktion, `CityCard`, erstellt, in der wir das `Card()`-Element aus Compose importieren. Eine Karte enthält Inhalte und Aktionen zu einem einzelnen Objekt. In unserem Beispiel hat unsere Karte zum Beispiel ein Bild und den Namen der Stadt. Das `Card()`-Element in Compose hat die folgenden Eingaben in seinen Parametern: + +[source, kotlin] +---- +@Composable +fun Card( + modifier: Modifier = Modifier, + shape: Shape = MaterialTheme.shapes.medium, + backgroundColor: Color = MaterialTheme.colors.surface, + contentColor: Color = contentColorFor(backgroundColor), + border: BorderStroke? = null, + elevation: Dp = 1.dp, + content: @Composable () -> Unit +) +---- + +Das bedeutet, dass Sie Ihre Karte leicht nach Ihren Wünschen modellieren können. Unsere Karte hat zum Beispiel `Padding` und `Elevation`, und der Bereich enthält eine Spalte. In dieser Spalte haben wir ein Bild und Text, der dazu dient, das Bild näher zu beschreiben und mehr Kontext zu bieten. + + +== Tab-Layout mit View Pager + +=== Einleitung +In Android ist es Usus zwischen verschiedenen Inhalten zu 'sliden'. Dies trifft zum Beispiel bei Carousels oder bei Tabs zu. +Hier werden wir einen `Pager` bauen, der zwischen einzelnen Seiten horizontal hin- und herwechseln kann. Er hat einen `State`, der die Seite bestimmt, die dann angezeigt wird. Die Seite wird mittels einer Farbe symbolisiert. +Sie können im vorherigen Programm weiter machen. + +=== Programm +1. Fügen sie folgende Zeilen zur `build.gradle(Module:app)` +[source, gradle] +---- +implementation("com.google.accompanist:accompanist-pager:0.32.0") + implementation("com.google.accompanist:accompanist-pager-indicators:0.32.0") +---- +Accompanist ist von JetPack und bietet einige nützliche Komponenten, die wir verwenden können. + +2. Im gleichen Projekt + +=== Funktionsweise + +== Animationen + +=== Einleitung + +=== Programm + +=== Funktionsweise + +== Accessibility + +=== Einleitung + +=== Programm + +=== Funktionsweise + +== Declarative Graphics + +=== Einleitung + +=== Programm + +=== Funktionsweise + +== Grundlagen Android-Entwicklung + +=== Einleitung + +=== Programm + +=== Funktionsweise diff --git a/asciidocs/android-3.adoc b/asciidocs/android-3.adoc new file mode 100644 index 0000000..a64dc63 --- /dev/null +++ b/asciidocs/android-3.adoc @@ -0,0 +1,145 @@ += Android - Course - 1 - Lifecycles & ViewModel +ifndef::imagesdir[:imagesdir: images] +:icons: font +:experimental: +:sectnums: +:toc: +ifdef::backend-html5[] + +// https://fontawesome.com/v4.7.0/icons/ +icon:file-text-o[link=https://raw.githubusercontent.com/UnterrainerInformatik/documents/main/asciidocs/{docname}.adoc] ‏ ‏ ‎ +icon:github-square[link=https://github.com/UnterrainerInformatik/documents] ‏ ‏ ‎ +endif::backend-html5[] + +link:https://htl.unterrainer.info/index.html[BACK to Index] + +link:https://htl.unterrainer.info/android.html[BACK to Android - Course] + +== UI-Controllers + +In Android gibt es 2 Arten von UI-Controllern: + * Activities + * Fragments + +Änderungen am Android-System führen im Allgemeinen dazu, dass UI-Controller zerstört und wieder neu erstellt werden +Man hat im allgemeinen keinen Einfluss auf diese Vorgänge... Das passiert einfach bei: + +* User Aktionen +** Rotation +** Zurück-Button +** ... +* System Events +** Konfigurationsänderungen +** Zu wenig Speicher +** ... + +==== +WARNING: Handys raus, App starten und dann rotieren, pausieren, App switchen, etc... Was glaubt ihr passiert hier wohl mit den Applikationen im Hintergund und warum kommen die zum Beispiel beim Switchen wieder zurück an genau die richtige Stelle? + +Daten sollten daher NICHT direkt in Activities oder Fragments gespeichert werden! +Diese wären dann nämlich einfach weg. +==== + +=== Activities +* Android Applikationen bestehen aus Activities +* Diese konzentrieren sich auf eine einzelne Handlung eines Users (deswegen "Activity") + +image:android-3-1.png[align="center",width="70%"] + +=== Fragments +* Fragments sind wiederverwendbare UI-Elemente +* Sie sind Teile von Activities + +image:android-3-2.png[align="center",width="80%"] + +== Lifecycles +* Unterschiedliche Elemente in Android können unterschiedliche Lifecycles haben. +* Diese bestimmen die Events, die automatisch vom System ausgelöst werden. +* Das System kann damit die Lebensdauer von Elementen verwalten. + +*Beispiel:* +Benötige eine Applikation mit höherer Priorität mehr Speicher, werden pausierte Activities einfach gelöscht. + +Dabei verliert man das jeweilige Element natürlich. + +*Man ist selbst dafür verantwortlich, dass die Daten dieses Prozedere überleben und das Element später wieder aufgebaut werden kann.* + +=== Activity Lifecycle +image:android-3-3.png[align="center",width="50%"] + +=== Fragment Lifecycle +image:android-3-4.png[align="center",width="50%"] + +=== Daten Persistieren +Es gibt die Methoden: + +* onSaveInstanceState() +* onRestoreInstanceState() + +Diese werden automatisch aufgerufen, wenn das System die Daten speichern oder wiederherstellen will. +Das ist für kleinere Datenmengen gedacht und funktioniert auch ganz gut. + +Für große Datenmengen oder Daten, die schwierig zu serialisieren sind, ist das aber weniger geeignet. +Außerdem gibt es noch asynchrone Aufrufe, die noch laufen können, obwohl diese Methoden schon aufgerufen wurden und der UI-Controller gerade zerstört wurde. +Dafür brauchen wir dann doch eine andere Lösung. + +Ohne System wird das ganze ziemlich schnell unübersichtlich. + +== ViewModel +* Teil der Android Architektur +* Speichert und managed UI-Daten unter Berücksichtigung des Activity-Lifecycles +* Wird bei Konfigurationsänderungen NICHT zerstört! +* Erlaubt dadurch der Applikation Konfigurationsänderungen zu überstehen + +Im ViewModel werden auch externe Datenquellen angebunden (Datenbank, Webservices...) + +image:android-3-5.png[align="center",width="50%"] + +=== ViewModel Lifecycle +image:android-3-6.png[align="center",width="50%"] + +... Das ViewModel wird erst zerstört, wenn die Applikation komplett beendet wird. + +==== +WARNING: Ihr verwendet das ViewModel mit `remember()` oder `mutableStateOf()`. +==== + +=== Shared Viewmodel +Ein gängiges Problem ist, dass sich zwei Fragments Daten teilen müssen. + +* Das erste selektiert zum Beispiel ein List-Item (z.B. ein Land) +* Das zweite zeigt Daten zum vom ersten ausgewählten Item an (z.B. das Bundesland) + +Hier ist ein ViewModel sehr hilfreich, auf das beide Fragments Zugriff haben. + +== LiveData +* LiveData ist ein Observable Datenhalter +* Wird von Android bereitgestellt +* Wird von ViewModels verwendet, um Daten zu speichern +* Wird von Activities und Fragments verwendet, um auf Daten zu reagieren + +=== Observer Pattern +* ViewModels sollten nichts vom View wissen +* Der View trägt sich beim LiveData im ViewModel ein, damit er updates bekommt +* Der View kann Methoden im ViewModel aufrufen, falls ein Benutzer eine Aktion ausführt + +image:android-3-7.png[align="center",width="50%"] + +=== Livecycle-Awareness +* Schickt nur Updates an aktive Abonnenten (STARTED oder RESUMED) +* Beim Abonnieren wird ein LifeCylce-Objekt übergeben +* Wenn dieses Objekt auf DESTROYED wechselt, wird das Abonnement automatisch entfernt + +image:android-3-8.png[align="center",width="50%"] + +=== Vorteile +* UI zeigt sicher immer den Data-State an +* Keine Mem-Leaks +* Keine Crashes wegen gestoppter Activities +* Kein manuelles Lifecycle-Handling +* Immer Up-To-Date (auch nach Aufwachen, Config-Änderungen, ...) +* Resourcen teilen (singleton LiveData) + +==== +WARNING: Ihr verwendet LiveData mit `observeAsState()` oder `observe()`. +==== diff --git a/asciidocs/android.adoc b/asciidocs/android.adoc new file mode 100644 index 0000000..8940644 --- /dev/null +++ b/asciidocs/android.adoc @@ -0,0 +1,46 @@ += Android - Course +ifndef::imagesdir[:imagesdir: images] +:icons: font +:source-highlighter: highlight.js +:experimental: +:sectnums: +:toc: +ifdef::backend-html5[] + +// https://fontawesome.com/v4.7.0/icons/ +icon:file-text-o[link=https://raw.githubusercontent.com/UnterrainerInformatik/documents/main/asciidocs/{docname}.adoc] ‏ ‏ ‎ +icon:github-square[link=https://github.com/UnterrainerInformatik/documents] ‏ ‏ ‎ +endif::backend-html5[] + +link:https://htl.unterrainer.info/index.html[BACK to Index] + +== Einführung +link:https://htl.unterrainer.info/android-1.html[Android - 1 - Introduction] + +* Grundlagen Android-Entwicklung +* Android Studio IDE +* Kotlin Grundzüge +* Komponenten einer Android-App +* Mein erster Knopf in Jetpack-Compose +* Android Project Structure +* Deine App mit Gradlew laufen lassen + +== Jetpack Compose +link:https://htl.unterrainer.info/android-2.html[Android - 2 - Jetpack Compose] + +* Android Views mit Jetpack Compose +* Scrollable List mit Jetpack Compose +* Tab-Layout mit View Pager +* Animationen +* Accessibility +* Declarative Graphics + +== Lifecycles & ViewModel +link:https://htl.unterrainer.info/android-3.html[Android - 3 - Lifecycles & ViewModel] + +* UI-Controllers +* Lifecycles +* ViewModel + +== Android - 4 +link:https://htl.unterrainer.info/android-4.html[Android - 4 - ] diff --git a/asciidocs/images/android-1-0.png b/asciidocs/images/android-1-0.png new file mode 100644 index 0000000..1aa4521 Binary files /dev/null and b/asciidocs/images/android-1-0.png differ diff --git a/asciidocs/images/android-1-1.png b/asciidocs/images/android-1-1.png new file mode 100644 index 0000000..1b3505a Binary files /dev/null and b/asciidocs/images/android-1-1.png differ diff --git a/asciidocs/images/android-1-10.png b/asciidocs/images/android-1-10.png new file mode 100644 index 0000000..cedc33e Binary files /dev/null and b/asciidocs/images/android-1-10.png differ diff --git a/asciidocs/images/android-1-11.png b/asciidocs/images/android-1-11.png new file mode 100644 index 0000000..2c4e960 Binary files /dev/null and b/asciidocs/images/android-1-11.png differ diff --git a/asciidocs/images/android-1-12.png b/asciidocs/images/android-1-12.png new file mode 100644 index 0000000..cfee7c2 Binary files /dev/null and b/asciidocs/images/android-1-12.png differ diff --git a/asciidocs/images/android-1-13.png b/asciidocs/images/android-1-13.png new file mode 100644 index 0000000..83fed68 Binary files /dev/null and b/asciidocs/images/android-1-13.png differ diff --git a/asciidocs/images/android-1-2.png b/asciidocs/images/android-1-2.png new file mode 100644 index 0000000..cac2387 Binary files /dev/null and b/asciidocs/images/android-1-2.png differ diff --git a/asciidocs/images/android-1-3.png b/asciidocs/images/android-1-3.png new file mode 100644 index 0000000..c0fd448 Binary files /dev/null and b/asciidocs/images/android-1-3.png differ diff --git a/asciidocs/images/android-1-4.png b/asciidocs/images/android-1-4.png new file mode 100644 index 0000000..069710e Binary files /dev/null and b/asciidocs/images/android-1-4.png differ diff --git a/asciidocs/images/android-1-5.png b/asciidocs/images/android-1-5.png new file mode 100644 index 0000000..e7bcf15 Binary files /dev/null and b/asciidocs/images/android-1-5.png differ diff --git a/asciidocs/images/android-1-6.png b/asciidocs/images/android-1-6.png new file mode 100644 index 0000000..6412769 Binary files /dev/null and b/asciidocs/images/android-1-6.png differ diff --git a/asciidocs/images/android-1-7.png b/asciidocs/images/android-1-7.png new file mode 100644 index 0000000..da3dbea Binary files /dev/null and b/asciidocs/images/android-1-7.png differ diff --git a/asciidocs/images/android-1-8.png b/asciidocs/images/android-1-8.png new file mode 100644 index 0000000..0552327 Binary files /dev/null and b/asciidocs/images/android-1-8.png differ diff --git a/asciidocs/images/android-1-9.png b/asciidocs/images/android-1-9.png new file mode 100644 index 0000000..b7fcea7 Binary files /dev/null and b/asciidocs/images/android-1-9.png differ diff --git a/asciidocs/images/android-2-0.png b/asciidocs/images/android-2-0.png new file mode 100644 index 0000000..3bec21b Binary files /dev/null and b/asciidocs/images/android-2-0.png differ diff --git a/asciidocs/images/android-2-1.png b/asciidocs/images/android-2-1.png new file mode 100644 index 0000000..b9f31d0 Binary files /dev/null and b/asciidocs/images/android-2-1.png differ diff --git a/asciidocs/images/android-2-2.png b/asciidocs/images/android-2-2.png new file mode 100644 index 0000000..69bd69c Binary files /dev/null and b/asciidocs/images/android-2-2.png differ diff --git a/asciidocs/images/android-2-3.png b/asciidocs/images/android-2-3.png new file mode 100644 index 0000000..c8e3784 Binary files /dev/null and b/asciidocs/images/android-2-3.png differ diff --git a/asciidocs/images/android-2-4.png b/asciidocs/images/android-2-4.png new file mode 100644 index 0000000..8d137be Binary files /dev/null and b/asciidocs/images/android-2-4.png differ diff --git a/asciidocs/images/android-2-5.png b/asciidocs/images/android-2-5.png new file mode 100644 index 0000000..9a582eb Binary files /dev/null and b/asciidocs/images/android-2-5.png differ diff --git a/asciidocs/images/android-2-6.png b/asciidocs/images/android-2-6.png new file mode 100644 index 0000000..ac24298 Binary files /dev/null and b/asciidocs/images/android-2-6.png differ diff --git a/asciidocs/images/android-2-7.png b/asciidocs/images/android-2-7.png new file mode 100644 index 0000000..9aed687 Binary files /dev/null and b/asciidocs/images/android-2-7.png differ diff --git a/asciidocs/images/android-3-1.png b/asciidocs/images/android-3-1.png new file mode 100644 index 0000000..39ddbdc Binary files /dev/null and b/asciidocs/images/android-3-1.png differ diff --git a/asciidocs/images/android-3-2.png b/asciidocs/images/android-3-2.png new file mode 100644 index 0000000..d51a147 Binary files /dev/null and b/asciidocs/images/android-3-2.png differ diff --git a/asciidocs/images/android-3-3.png b/asciidocs/images/android-3-3.png new file mode 100644 index 0000000..1b1b907 Binary files /dev/null and b/asciidocs/images/android-3-3.png differ diff --git a/asciidocs/images/android-3-4.png b/asciidocs/images/android-3-4.png new file mode 100644 index 0000000..38b7333 Binary files /dev/null and b/asciidocs/images/android-3-4.png differ diff --git a/asciidocs/images/android-3-5.png b/asciidocs/images/android-3-5.png new file mode 100644 index 0000000..7289970 Binary files /dev/null and b/asciidocs/images/android-3-5.png differ diff --git a/asciidocs/images/android-3-6.png b/asciidocs/images/android-3-6.png new file mode 100644 index 0000000..38dcb13 Binary files /dev/null and b/asciidocs/images/android-3-6.png differ diff --git a/asciidocs/images/android-3-7.png b/asciidocs/images/android-3-7.png new file mode 100644 index 0000000..71dcdc8 Binary files /dev/null and b/asciidocs/images/android-3-7.png differ diff --git a/asciidocs/images/android-3-8.png b/asciidocs/images/android-3-8.png new file mode 100644 index 0000000..379b65f Binary files /dev/null and b/asciidocs/images/android-3-8.png differ diff --git a/asciidocs/images/distributed-systems-0.png b/asciidocs/images/distributed-systems-0.png new file mode 100644 index 0000000..8eced46 Binary files /dev/null and b/asciidocs/images/distributed-systems-0.png differ diff --git a/asciidocs/images/distributed-systems-1.png b/asciidocs/images/distributed-systems-1.png new file mode 100644 index 0000000..115c34f Binary files /dev/null and b/asciidocs/images/distributed-systems-1.png differ diff --git a/asciidocs/images/jwt-0.png b/asciidocs/images/jwt-0.png new file mode 100644 index 0000000..96f5a39 Binary files /dev/null and b/asciidocs/images/jwt-0.png differ diff --git a/asciidocs/images/jwt-1.png b/asciidocs/images/jwt-1.png new file mode 100644 index 0000000..c007231 Binary files /dev/null and b/asciidocs/images/jwt-1.png differ diff --git a/asciidocs/images/jwt-2.png b/asciidocs/images/jwt-2.png new file mode 100644 index 0000000..ce21cd2 Binary files /dev/null and b/asciidocs/images/jwt-2.png differ diff --git a/asciidocs/images/jwt-3.png b/asciidocs/images/jwt-3.png new file mode 100644 index 0000000..71ff3fe Binary files /dev/null and b/asciidocs/images/jwt-3.png differ diff --git a/asciidocs/images/jwt-4.png b/asciidocs/images/jwt-4.png new file mode 100644 index 0000000..5fb733d Binary files /dev/null and b/asciidocs/images/jwt-4.png differ diff --git a/asciidocs/images/package-layer-feature-0.png b/asciidocs/images/package-layer-feature-0.png new file mode 100644 index 0000000..9a41973 Binary files /dev/null and b/asciidocs/images/package-layer-feature-0.png differ diff --git a/asciidocs/images/package-layer-feature-1.png b/asciidocs/images/package-layer-feature-1.png new file mode 100644 index 0000000..3af248a Binary files /dev/null and b/asciidocs/images/package-layer-feature-1.png differ diff --git a/asciidocs/images/package-layer-feature-2.png b/asciidocs/images/package-layer-feature-2.png new file mode 100644 index 0000000..73ed7b7 Binary files /dev/null and b/asciidocs/images/package-layer-feature-2.png differ diff --git a/asciidocs/index.adoc b/asciidocs/index.adoc index da889c0..b0448e2 100644 --- a/asciidocs/index.adoc +++ b/asciidocs/index.adoc @@ -8,7 +8,32 @@ ifndef::imagesdir[:imagesdir: images] ifdef::backend-html5[] // https://fontawesome.com/v4.7.0/icons/ +icon:file-text-o[link=https://raw.githubusercontent.com/UnterrainerInformatik/lectures/main/asciidocs/{docname}.adoc] ‏ ‏ ‎ +icon:github-square[link=https://github.com/UnterrainerInformatik/lectures] ‏ ‏ ‎ endif::backend-html5[] -== Some Page -link:https://yourserver/somePage.html[Android - Course] +== Android - Course +link:https://htl.unterrainer.info/android.html[Android - Course] + +== JWT - Lecture +link:https://htl.unterrainer.info/jwt.html[JWT - Lecture] + +=== JWT - Group Puzzle +link:https://htl.unterrainer.info/jwt-group-puzzle.html[JWT - Group Puzzle] + +== Package by Layer vs. Package by Feature +link:https://htl.unterrainer.info/package-by-layer-feature.html[Package by Layer vs. Package by Feature] + +== TESTING + +link:https://htl.unterrainer.info/Lernstrecke.md[Lernstrecke] + +=== Testing MD Files + +==== On GitHub (external link) +link:https://htl.unterrainer.info/convert?url=https://raw.githubusercontent.com/UnterrainerInformatik/java-http-server/master/README.md[README.md] + +==== On this site (internal link) +link:https://htl.unterrainer.info/md/Test-MD-File.md[direct call: Test-MD-File.md] + +link:https://htl.unterrainer.info/convert?url=https://htl.unterrainer.info/md/Test-MD-File.md[convert call: Test-MD-File.md] diff --git a/asciidocs/iuml/distributed-system-1.iuml b/asciidocs/iuml/distributed-system-1.iuml new file mode 100644 index 0000000..571e3c1 --- /dev/null +++ b/asciidocs/iuml/distributed-system-1.iuml @@ -0,0 +1,71 @@ +@startuml + + database "Database" as database2 + component "Client 2" as client2 + component "Client 3" as client3 + component "Client 4" as client4 + component "Server 4" as server4 + + client2 --> server4 + client3 --> server4 + client4 --> server4 + server4 --> database2 + + component "Client 5" as client5 + component "Client 6" as client6 + component "Client 7" as client7 + component "Server 5" as server5 + component "Server 6" as server6 + component "Server 7" as server7 + database "Database" as database3 + + client5 --> server5 + client5 --> server6 + client5 --> server7 + client6 --> server5 + client6 --> server6 + client6 --> server7 + client7 --> server5 + client7 --> server6 + client7 --> server7 + server5 --> database3 + server6 --> database3 + server7 --> database3 + + @enduml + + client --> server1 + client --> server2 + client --> server3 + server1 --> database1 + server2 --> database1 + server3 --> database1 + + component "Client 2" as client2 + component "Client 3" as client3 + component "Client 4" as client4 + component "Server 4" as server4 + + client2 --> server4 + client3 --> server4 + client4 --> server4 + server4 --> database2 +} + +@enduml +package "Distributed Systems" { + component "Client" as client + component "Server 1" as server1 + component "Server 2" as server2 + component "Server 3" as server3 + database "Database" as database + + client --> server1 + client --> server2 + client --> server3 + server1 --> database1 + server2 --> database1 + server3 --> database1 +} + +@enduml diff --git a/asciidocs/iuml/distributed-system-2.iuml b/asciidocs/iuml/distributed-system-2.iuml new file mode 100644 index 0000000..85d7f16 --- /dev/null +++ b/asciidocs/iuml/distributed-system-2.iuml @@ -0,0 +1,28 @@ +@startuml + +component "Peer A" +component "Peer B" +component "Peer C" + +component "Peer D" +component "Peer E" +component "Peer J" +component "Peer K" +component "Peer L" +component "Peer M" + +"Peer A" -- "Peer B" +"Peer A" -- "Peer C" +"Peer B" -- "Peer C" +"Peer D" -- "Peer E" +"Peer E" -- "Peer K" +"Peer L" -- "Peer M" +"Peer A" -- "Peer D" +"Peer C" -- "Peer E" +"Peer D" -- "Peer K" +"Peer J" -- "Peer L" +"Peer C" -- "Peer D" +"Peer B" -- "Peer E" +"Peer J" -- "Peer M" + +@enduml diff --git a/asciidocs/jwt-group-puzzle-text-1.adoc b/asciidocs/jwt-group-puzzle-text-1.adoc new file mode 100644 index 0000000..e948596 --- /dev/null +++ b/asciidocs/jwt-group-puzzle-text-1.adoc @@ -0,0 +1,39 @@ += JWT - Group Puzzle - Text 1 +ifndef::imagesdir[:imagesdir: images] +:icons: font +:source-highlighter: highlight.js +:experimental: +:sectnums: +:toc: +ifdef::backend-html5[] + +// https://fontawesome.com/v4.7.0/icons/ +icon:file-text-o[link=https://raw.githubusercontent.com/UnterrainerInformatik/documents/main/asciidocs/{docname}.adoc] ‏ ‏ ‎ +icon:github-square[link=https://github.com/UnterrainerInformatik/documents] ‏ ‏ ‎ +endif::backend-html5[] + +link:https://htl.unterrainer.info/index.html[BACK to Index] + +link:https://htl.unterrainer.info/jwt-group-puzzle.html[BACK to Group Puzzle] + +== Text 1 - JWTs - Sinn und Aufbau + +Texte lesen (Englisch): + +==== +https://jwt.io/introduction + +What is JSON Web Token? +==== + +==== +https://jwt.io/introduction + +When should you use JSON Web Tokens? +==== + +==== +https://jwt.io/introduction + +What is the JSON Web Token structure? +==== diff --git a/asciidocs/jwt-group-puzzle-text-2.adoc b/asciidocs/jwt-group-puzzle-text-2.adoc new file mode 100644 index 0000000..8860484 --- /dev/null +++ b/asciidocs/jwt-group-puzzle-text-2.adoc @@ -0,0 +1,39 @@ += JWT - Group Puzzle - Text 2 +ifndef::imagesdir[:imagesdir: images] +:icons: font +:source-highlighter: highlight.js +:experimental: +:sectnums: +:toc: +ifdef::backend-html5[] + +// https://fontawesome.com/v4.7.0/icons/ +icon:file-text-o[link=https://raw.githubusercontent.com/UnterrainerInformatik/documents/main/asciidocs/{docname}.adoc] ‏ ‏ ‎ +icon:github-square[link=https://github.com/UnterrainerInformatik/documents] ‏ ‏ ‎ +endif::backend-html5[] + +link:https://htl.unterrainer.info/index.html[BACK to Index] + +link:https://htl.unterrainer.info/jwt-group-puzzle.html[BACK to Group Puzzle] + +== Text 2 - OAuth2 + +Texte lesen (Deutsch): + +==== +https://de.wikipedia.org/wiki/OAuth + +Hauptüberschrift mit Beschreibung +==== + +==== +https://de.wikipedia.org/wiki/OAuth + +Geschichte +==== + +==== +https://de.wikipedia.org/wiki/OAuth + +Rollen +==== diff --git a/asciidocs/jwt-group-puzzle-text-3.adoc b/asciidocs/jwt-group-puzzle-text-3.adoc new file mode 100644 index 0000000..e05bbae --- /dev/null +++ b/asciidocs/jwt-group-puzzle-text-3.adoc @@ -0,0 +1,45 @@ += JWT - Group Puzzle - Text 3 +ifndef::imagesdir[:imagesdir: images] +:icons: font +:source-highlighter: highlight.js +:experimental: +:sectnums: +:toc: +ifdef::backend-html5[] + +// https://fontawesome.com/v4.7.0/icons/ +icon:file-text-o[link=https://raw.githubusercontent.com/UnterrainerInformatik/documents/main/asciidocs/{docname}.adoc] ‏ ‏ ‎ +icon:github-square[link=https://github.com/UnterrainerInformatik/documents] ‏ ‏ ‎ +endif::backend-html5[] + +link:https://htl.unterrainer.info/index.html[BACK to Index] + +link:https://htl.unterrainer.info/jwt-group-puzzle.html[BACK to Group Puzzle] + +== Text 3 - OpenID Connect (OIDC) - Keycloak + +Texte lesen (Englisch & Deutsch): + +==== +https://de.wikipedia.org/wiki/OpenID_Connect + +Alles (ist kurz) +==== + +==== +https://en.wikipedia.org/wiki/Keycloak + +Alles (ist kurz) +==== + +==== +https://www.keycloak.org/ + +Überblick +==== + +==== +https://www.intension.de/infoblog/was-ist-keycloak/ + +Alles (auch kurz; guter Überblick) +==== diff --git a/asciidocs/jwt-group-puzzle-text-4.adoc b/asciidocs/jwt-group-puzzle-text-4.adoc new file mode 100644 index 0000000..8a9c1c9 --- /dev/null +++ b/asciidocs/jwt-group-puzzle-text-4.adoc @@ -0,0 +1,39 @@ += JWT - Group Puzzle - Text 4 +ifndef::imagesdir[:imagesdir: images] +:icons: font +:source-highlighter: highlight.js +:experimental: +:sectnums: +:toc: +ifdef::backend-html5[] + +// https://fontawesome.com/v4.7.0/icons/ +icon:file-text-o[link=https://raw.githubusercontent.com/UnterrainerInformatik/documents/main/asciidocs/{docname}.adoc] ‏ ‏ ‎ +icon:github-square[link=https://github.com/UnterrainerInformatik/documents] ‏ ‏ ‎ +endif::backend-html5[] + +link:https://htl.unterrainer.info/index.html[BACK to Index] + +link:https://htl.unterrainer.info/jwt-group-puzzle.html[BACK to Group Puzzle] + +== Text 4 - Access-Token - Refresh-Token + +Texte lesen (Englisch): + +==== +https://auth0.com/blog/refresh-tokens-what-are-they-and-when-to-use-them/ + +What Is A Token? +==== + +==== +https://auth0.com/blog/refresh-tokens-what-are-they-and-when-to-use-them/ + +Token types +==== + +==== +https://auth0.com/blog/refresh-tokens-what-are-they-and-when-to-use-them/ + +When to use Refresh Tokens? +==== diff --git a/asciidocs/jwt-group-puzzle.adoc b/asciidocs/jwt-group-puzzle.adoc new file mode 100644 index 0000000..8040e7d --- /dev/null +++ b/asciidocs/jwt-group-puzzle.adoc @@ -0,0 +1,125 @@ += JWT - Group Puzzle +ifndef::imagesdir[:imagesdir: images] +:icons: font +:source-highlighter: highlight.js +:experimental: +:sectnums: +:toc: +ifdef::backend-html5[] + +// https://fontawesome.com/v4.7.0/icons/ +icon:file-text-o[link=https://raw.githubusercontent.com/UnterrainerInformatik/documents/main/asciidocs/{docname}.adoc] ‏ ‏ ‎ +icon:github-square[link=https://github.com/UnterrainerInformatik/documents] ‏ ‏ ‎ +endif::backend-html5[] + +link:https://htl.unterrainer.info/index.html[BACK to Index] + +link:https://htl.unterrainer.info/jwt.html[BACK to JWT] + +== Vorwissen +* Was ist ein verteiltes System? + +== Ablauf +[cols="10,1",options="header"] +|=== +|Ablauf inkl. methodisch-didaktische Hinweise Lehr-/Lernmittel | Dauer +|Einleitungsvortrag zum Abgleich des Vorwissens Frontalunterricht | 20 +|Erklärung des Gruppenpuzzles Frontalunterricht | 10 +|Gruppenpuzzle - THINK-Phase | 20 +|Gruppenpuzzle - SQUARE-Phase | 40 +|Gruppenpuzzle - SHARE-Phase | 40 +|Nachbesprechung Fragerunde 20 +|=== + +== Arbeitsauftrag + +Methode: Gruppenpuzzle mit Stafettenpräsentation + +=== Fachliche Lernziele + +[cols="10,2,2,2"] +|=== +|Ich weiß um die Grundzüge von JWTs und kann sie erklären. | voll erreicht | überwiegend erreicht | nicht überwiegend erreicht +|Ich kenne verschiedene Verwendungsmöglichkeiten von JWTs. | voll erreicht | überwiegend erreicht | nicht überwiegend erreicht +|Ich kann den Aufbau eines JWTs schildern. | voll erreicht | überwiegend erreicht | nicht überwiegend erreicht +|Ich kann schildern, wie eine Benutzerrolle in einem JWT transportiert wird. | voll erreicht | überwiegend erreicht | nicht überwiegend erreicht +|Ich verstehe die Vorteile von JWTs in Verbindung mit OAuth2 und OpenIDConnect. | voll erreicht | überwiegend erreicht | nicht überwiegend erreicht +|Ich weiß, was ein Authentication-Server im Bereich OAuth2 macht. | voll erreicht | überwiegend erreicht | nicht überwiegend erreicht +|Ich kenne die Funktion und Funktionsweise eines Access-Tokens. | voll erreicht | überwiegend erreicht | nicht überwiegend erreicht +|Ich kenne die Funktion und Funktionsweise eines Refresh-Tokens. | voll erreicht | überwiegend erreicht | nicht überwiegend erreicht +|=== + +=== Soziale Lernziele + +|=== +|Texte erfassen können +|Zeitpläne einhalten können +|Zuhören können +|Angemessene Lautstärke einhalten können +|Beim Thema bleiben können. +|=== + +=== Methodisch-didaktische Hinweise + +==== Einzelarbeit (20 Minuten) THINK-Phase +Sie erhalten einen Text mit Links (Unterrichtsmaterialien), der sich mit einem Thema auseinandersetzt. Lesen Sie sich bitte den Text aufmerksam durch und fassen Sie die wesentlichen Inhalte in Einzelarbeit stichwortartig zusammen. + +==== Expertenphase (40 Minuten) SQUARE-Phase +Sie bilden nun mit allen anderen Teilnehmer/innen, die denselben Text gelesen haben, eine Arbeitsgruppe (Expertengruppe für dieses eine Thema). +Ihre Aufgabe ist es, sich über diesen Text auszutauschen und Ihre Erkenntnisse zu vergleichen. Einigen Sie sich auf die wesentlichen Aussagen, die Sie den anderen Teilnehmer/innen mitteilen möchten. Anschließend erstellen Sie ein digitales Lernplakat (oder ein anderes digitales Präsentationsmedium), das als Grundlage für eine spätere Präsentation dieser Inhalte dienen soll. Jeder/Jede von Ihnen wird dieses Thema präsentieren müssen. + +==== Stafettenpräsentation (je Thema 10 Minuten) SHARE-Phase +Sie werden in neue Gruppen eingetailt, in denen von jedem Thema mindestens eine Expertin / ein Experte vertreten ist. + +==== Diskussion (20 Minuten) +Wir diskutieren gemeinsam in der Klasse über den Ausgang, die Aufgabe und die benutzte Methodik. + +== Texte +==== +link:https://htl.unterrainer.info/jwt-group-puzzle-text-1.html[Text Gruppe 1] + +link:https://htl.unterrainer.info/jwt-group-puzzle-text-2.html[Text Gruppe 2] + +link:https://htl.unterrainer.info/jwt-group-puzzle-text-3.html[Text Gruppe 3] + +link:https://htl.unterrainer.info/jwt-group-puzzle-text-4.html[Text Gruppe 4] +==== + +== Kompetenzen +[cols="10,1",options="header"] +|=== +|Kompetenzen | Stufe + +|Architekturen erklären und beschreiben | B +|Synchronisationsmethoden | B +|Softwarearchitektur verteilter Systeme | B +|Web Development Stack, Socktes | D +|Auth, Webservices, REST | C +|=== + +[cols="10,1",options="header"] +|=== +|Soziale, personelle und Methoden-Kompetenzen | Stufe + +|Gruppenarbeit (Gruppenpuzzle) | C +|Erklären vor Klassenkollegen | C +|=== + +=== Legende +[cols="1,10",options="header"] +|=== +|Stufe | Beschreibung +|A | wiedergeben Lernende können die Inhalte wiedergeben +|B | verstehen Lernende verstehen die Thematik bzw. können diese benennen +|C | anwenden Lernende können Aufgaben anhand von AB oder Aufträgen erfüllen +|D | analysieren Lernende geben eigene Informationen an andere weiter +|E | entwickeln Fallbeispiele, Projekte - Lernende arbeiten selbstständig ohne Vorgabe +|=== + +== Quellen +* https://jwt.io +* https://jwt.io/introduction +* https://jwt.io/#debugger-io +* https://quarkus.io/guides/security-jwt +* https://developer.okta.com/docs/guides/implement-grant-type/authcode/main/ +* https://auth0.com/blog/refresh-tokens-what-are-they-and-when-to-use-them/ diff --git a/asciidocs/jwt.adoc b/asciidocs/jwt.adoc new file mode 100644 index 0000000..71b5a82 --- /dev/null +++ b/asciidocs/jwt.adoc @@ -0,0 +1,211 @@ += JWT (JSON Web Token) und OAuth2 +ifndef::imagesdir[:imagesdir: images] +:icons: font +:source-highlighter: highlight.js +:experimental: +:sectnums: +:toc: +ifdef::backend-html5[] + +// https://fontawesome.com/v4.7.0/icons/ +icon:file-text-o[link=https://raw.githubusercontent.com/UnterrainerInformatik/documents/main/asciidocs/{docname}.adoc] ‏ ‏ ‎ +icon:github-square[link=https://github.com/UnterrainerInformatik/documents] ‏ ‏ ‎ +endif::backend-html5[] + +link:https://htl.unterrainer.info/index.html[BACK to Index] + +== Vorwissen +* Was ist ein verteiltes System? + +Zusammenschluss unabhängiger Computer, die sich für den Benutzer als ein einziges System präsentieren. + +image:distributed-systems-0.png[align="center",width="40%"] + +image:distributed-systems-1.png[align="center",width="80%"] + +* Warum müssen in verteilten Systemen Nachrichten übertragen werden? +** Kommunikation +** Koordination +** Konsistenz +** Fehlertoleranz +** Skalierbarkeit +** Transparenz + +* Asymmetrische Verschlüsselung (public-private key-pair) +** Public- Private Key Pair + +* OAuth2 (basic) +** OAuth2 ist ein offenes Protokoll, das es ermöglicht, in einer standardisierten Weise den Zugriff auf Webdienste zu delegieren, ohne dass der Benutzer seine Zugangsdaten weitergeben muss. + +* OpenIDConnect (basic) +** OpenID Connect (OIDC) ist ein Identitätsauthentifizierungsprotokoll, das eine Erweiterung der offenen Autorisierung (OAuth) 2.0 darstellt, um den Prozess der Authentifizierung und Autorisierung von Benutzern zu standardisieren, wenn sie sich anmelden, um auf digitale Dienste zuzugreifen. + +== Lernziele +* JWT +** Was sind JWTs? +** Wie sieht ein JWT aus? +** Welche Probleme lösen sie? +** Wie funktioniert das Signieren? + +* OAuth2 / OpenID Connect (OIDC) +** Wie wird ein JWT bei OAuth-Authorization verwendet? +** Was ist ein Access-Token? +*** Wozu braucht man ihn? +*** Wie wird er verwendet? +** Was ist ein Refresh-Token? +*** Wozu braucht man ihn? +*** Wie wird er verwendet? + +== Sinn von JWT +* Sichere Übertragung von Informationen über JSON +** *Datenübertragung* +*** Sichere Übertragung von Daten +** *Authorisation* +*** Wenn ein Benutzer eingeloggt ist, enthält von da an jeder Request einen JWT (bearer-token). Dieser enthält die Identität des Benutzers (Identity - Wer bin ich?) und dessen Rechte (Claims - Anrechte). + +=== Was heißt Sicher? +* *Integrität* ++ +Ist das die Nachricht von meinem Gegenüber, oder wurde diese abgefangen und verändert? ++ +-> signieren (Header + Payload) + +* *Geheimhaltung* ++ +Niemand, außer dem Empfänger, soll die Übertragung lesen können. ++ +-> verschlüsseln (gesamten Token) ++ +Ist nicht die Norm. Normalerweise wird nur signiert. Wenn ihr verschlüsseln wollt, müsst ihr euch selber darum kümmern. + +==== +WARNING: Hier link:https://htl.unterrainer.info/jwt-group-puzzle.html[JWT - Group Puzzle] beginnen, oder mit normalen Vortrag hier weitermachen. +==== + +== Aufbau und Inhalt eines JWT +* *Identity (Identität)* +** Benutzerdaten +*** Name +*** Email +*** … + +* *Claims (Anrechte)* +** Zum Beispiel das Recht… +*** … in der UI … +**** … eine gewisse Aktion ausführen zu dürfen +**** … einen Bildschirm zu sehen +**** … eine detailliertere Ansicht zu haben +**** … +*** … im Backend… +**** … einen Datensatz abzufragen +**** … einen Datensatz zu ändern +**** … einen Datensatz zu löschen +**** … + +=== Struktur +* Header +** Welcher Signaturalgorithmus wird verwendet? +** Typ des Tokens (meistens 'JWT') +** *Base64Url encoded* + +* Inhalt (Payload) +** Anrechte (Claims) +** *Base64Url encoded* +* Signatur ++ + Verschlüsselungsalgorithmus( + base64UrlEncode(header) + "." + + base64UrlEncode(payload), + secret + ) ++ +In der Form: xxxxx.yyyyy.zzzzz ++ +Siehe: link:https://jwt.io/#debugger-io[] + +image:jwt-0.png[align="center",width="60%"] + +== Typische Verwendung + +=== OAuth2 + +image:jwt-1.png[align="center",width="80%"] + +1. Die Anwendung oder der Client fordert beim Autorisierungsserver eine Berechtigung an. Dies erfolgt über einen der verschiedenen Autorisierungsabläufe. Beispielsweise durchläuft eine typische OpenID Connect-konforme Webanwendung den /oauth/authorize-Endpunkt mit dem 'authorization code flow'. +2. Wenn die Berechtigung erteilt wird, gibt der Autorisierungsserver ein Zugriffstoken an die Anwendung zurück. +3. Die Anwendung verwendet das Zugriffstoken, um auf eine geschützte Ressource (wie eine API) zuzugreifen. + +Während dieser Kommunikation wird der Inhalt des Tokens immer wieder lesbar über verschiedene Ressourcen hinweg übertragen. + +==== +IMPORTANT: NIEMALS Geheimnisse in einen unverschlüsselten Token packen! +==== + +==== OpenID Connect (OIDC) +https://de.wikipedia.org/wiki/OpenID_Connect + +* OpenID Connect (OIDC) ist ein Identitätsauthentifizierungsprotokoll, das eine Erweiterung der offenen Autorisierung (OAuth) 2.0 darstellt, um den Prozess der Authentifizierung und Autorisierung von Benutzern zu standardisieren, wenn sie sich anmelden, um auf digitale Dienste zuzugreifen. + +* Erweiterung von OAuth2 +* Wird gerne bei der Authentifizierung bei REST-Schnittstellen verwendet + § Verwendet auch laut Spezifikation selbst REST-Schnittstellen und JSON-Datenformat +* De-Fakto-Standard + +==== Keycloak +https://en.wikipedia.org/wiki/Keycloak +https://www.keycloak.org/ +https://www.intension.de/infoblog/was-ist-keycloak/ + +* Open Source +* Implementierung von OpenID Connect und OAuth2 und SAML +** LDAP, OAuth, SAML +* Auf Java-Basis +* Identity Access Management (IAM) System +* On premise oder in Cloud +* SAML - Im Java-Code mit Annotationen sagen, wer wo was darf +** Muss ja auch im Code irgendwo definiert sein +** Alt, aber immer noch OK +* Single-Sign-On (SSO) Provider + +==== +WARNING: ÜBUNG: link:https://quarkus.io/guides/security-jwt[] + + + Wenn wir uns nochmal die Claims (Anrechte) ins Gedächtnis rufen, dann gibt es GUI- und Server-bezogene. + Wir bekommen jetzt am Server einen Bearer-Token im Authorization-Header und können den mit einer Library überprüfen (Signatur testen). + Dann können wir am Backend Zugriff basierend auf diesen Claims zulassen oder nicht. + Irgendwie müssen wir das dem Backend sagen (diese Rolle darf auf diesen Endpoint POST machen)… + Das machen wir mit SmallryeJWT-Annotations. +==== + +== Authorization Code Flow +link:https://developer.okta.com/docs/guides/implement-grant-type/authcode/main/[] + +image:jwt-2.png[align="center",width="90%"] + +1. Ihre Anwendung (App) fordert einen Autorisierungscode vom Autorisierungsserver (Okta) an. +2. Okta präsentiert eine Authentifizierungsaufforderung (die Okta-Anmeldeseite) im Browser des Benutzers. +3. Der Benutzer authentifiziert sich beim Autorisierungsserver und erteilt seine Zustimmung. +4. Der Browser erhält nach der Benutzerauthentifizierung einen Autorisierungscode vom Autorisierungsserver (Okta). Der Autorisierungscode wird an Ihre App übergeben. +5. Ihre App sendet diesen Code und das Client-Geheimnis an Okta. Siehe Austausch des Codes gegen Tokens. +6. Okta gibt Zugriffs- und ID-Tokens zurück, sowie optional einen Aktualisierungstoken. +7. Ihre App kann diese Tokens jetzt verwenden, um im Namen des Benutzers den Ressourcenserver (zum Beispiel eine API) aufzurufen. +8. Der Ressourcenserver überprüft das Token, bevor er auf die Anfrage antwortet. Siehe Zugriffstoken validieren. + +== Access Token / Refresh Token +link:https://auth0.com/blog/refresh-tokens-what-are-they-and-when-to-use-them/[] + +=== Access Token +image:jwt-3.png[align="center",width="50%"] + +Hat traditionell eine sehr kurze Ablauffrist! +Dadurch müssen die Clients sehr häufig am Authorization-Server einen neuen Access-Token abholen (aber eben nicht bei JEDEM Request). +Wenn ich jetzt einen User sperren will (löschen oder die Rechte (Rollen) verändern), dann dauert es maximal genau diese Expires-Zeit, bis der Client einen neuen Token mit den neuen Rechten (oder keinen Token mehr) bekommt und damit diese Änderungen in Kraft treten. + +=== Refresh Token + +Verhindert, dass Du immer wieder Dein Passwort am Google-OAuth-Authorization Server eingeben musst. +Client muss trotzdem zum Authorization-Server. +Falls Änderungen in der Berechtigung waren, werden diese im neuen Access-Token mitgegeben. +Wenn der User gelöscht wurde, bekommt er auch mit dem Refresh-Token keinen neuen Access-Token mehr. + +image:jwt-4.png[align="center",width="80%"] \ No newline at end of file diff --git a/asciidocs/package-by-layer-feature.adoc b/asciidocs/package-by-layer-feature.adoc new file mode 100644 index 0000000..ae619d8 --- /dev/null +++ b/asciidocs/package-by-layer-feature.adoc @@ -0,0 +1,48 @@ += Android - Course +ifndef::imagesdir[:imagesdir: images] +:icons: font +:source-highlighter: highlight.js +:experimental: +:sectnums: +:toc: +ifdef::backend-html5[] + +// https://fontawesome.com/v4.7.0/icons/ +icon:file-text-o[link=https://raw.githubusercontent.com/UnterrainerInformatik/documents/main/asciidocs/{docname}.adoc] ‏ ‏ ‎ +icon:github-square[link=https://github.com/UnterrainerInformatik/documents] ‏ ‏ ‎ +endif::backend-html5[] + +link:https://htl.unterrainer.info/index.html[BACK to Index] + +== Package by Layer vs. Package by Feature +link:https://medium.com/sahibinden-technology/package-by-layer-vs-package-by-feature-7e89cde2ae3a[] + +Wenn wir ein Projekt erstellen und uns überlegen wie wir die Packages aufteilen, haben wir folgende Möglichkeiten. + +image:package-layer-feature-0.png[align="center",width="50%"] + +Die linke Option heißt 'Package by Layer' und die rechte Option 'Package by Feature'. + +=== Package by Layer +...würde im Projekt-Explorer wie folgt aussehen. + +image:package-layer-feature-1.png[align="center",width="40%"] + +Hier werden die Packages (Ebenen) nach Layer vergeben. +Alle JPAs sind in einem Package, sowie auch alle Entities oder Repositories, etc... + +Für kleinere Projekte zu empfehlen. + +=== Package by Feature + +image:package-layer-feature-2.png[align="center",width="40%"] + +Hier werden die Packages (Ebenen) nach Features ausgerichtet. +Wir haben zum Beispiel die REST-Schnittstelle 'accounting', die sich komplett in einem eigenen Package befindet. + +Vorteil davon ist, dass dies schon eine Vorstufe zur Zerteilung zu Microservices ist. So eingeteilte Projekte können damit besser zerlegt werden. + +Die Kapselung ist hier besser, da die Klassen teilweise auf package-private gesetzt werden können und somit nur innerhalb des Packages sichtbar sind. +Im Falle des 'Package by Layer' wären die Klassen alle public und somit von überall sichtbar. + +Wird als Refactoring für mittlere Projekte empfohlen. diff --git a/md/Dune 2.md b/md/Dune 2.md new file mode 100644 index 0000000..ffbea38 --- /dev/null +++ b/md/Dune 2.md @@ -0,0 +1,13 @@ +War ein toller Film. + +Maturafrage 1 + + +>[!note] Prüfungsfrage +>Sie sind SWE in einer Firma.... + + +[!note] +> This is a Callout! + +[[LinkTest-MD-File]] + +[[md/assets/test]] +[[md/test|test]] +https://unterrainer.info +[testlink](https://unterrainer.info) + +* list 1 +* list 2 + * list 2.1 + * list 2.2 +* list 3 + +> test +> * he +> * sfe +> * efwef + + + + + + + + + + + +
+>[!tip]- collabsable +>Hi there! +>I'm some code... +test
testtest
+ +Das ist ein Text +* Weil er gut ist +```java +public void schas(int i){} +``` + +```plantuml +[hansi] +[Mama] +[Günter] +[Gerald] +hansi -> Mama +Mama -> Günter +Gerald -> Mama +Günter -> Gerald +``` + +[[Neue Idee]] +[[Dune 2]] + +>[!success]- Extremely long title so that it will break. fwosiu efwuorh gwurhg aeuhbwauerh awueh buea hbihaweiubv e... Just to see where the chevron will be :) +>blah + +## Überblick + +> [!info]- Präsentation +>Hier findet Ihr den gesamten Stoff als Präsentation. +>https://htl.unterrainer.info/jwt.html +>* test +>* test + +>[!info]- JWT vs. Cookies (kurz) +>https://www.youtube.com/watch?v=UBUNrFtufWo + +>[!info]- JWT vs. Cookies (länger) +>https://www.youtube.com/watch?v=o9hT7v0OLJc + +>[!info]- JWT (detailliert) +>https://www.youtube.com/watch?v=P2CPd9ynFLg + +>[!note]- Access Tokens / Refresh Tokens +>[https://www.youtube.com/watch?v=LowJMwa7LCU](https://www.youtube.com/watch?v=LowJMwa7LCU) +## Grundkompetenzen + +>[!warning]- Stoff können +>Hier einen Test eintragen. +## CheckPoint + +>[!success]- GENÜGEND +>Das musst Du können, damit Du diese Strecke positiv abschließen kannst: +> +>**JWT** +>* Was sind JWTs? +>* Wie sieht ein JWT aus? +>* Welche Probleme lösen sie? +>* Wie funktioniert das Signieren? +> +>**OAuth2 / OpenID Connect (OIDC)** +>* Wie wird ein JWT bei OAuth-Authorization verwendet? +>* Was ist ein **Access-Token**? +> * Wozu braucht man ihn? +>* Was ist ein **Refresh-Token**? +> * Wozu braucht man ihn? + +>[!tip]- JWT +>Um eine bessere Note zu erreichen, solltest Du noch folgendes erledigen: +> +>**JWT** +>* Beispiel programmieren +>https://quarkus.io/guides/security-jwt + +>[!tip]- OAuth2 +>Um eine bessere Note zu erreichen, solltest Du noch folgendes erledigen: +> +>**OAuth2 / OpenID Connect (OIDC)** +>* Access-Token - Wie funktioniert er? +>* Refresh-Token - Wie funktioniert er? +## Vertiefungen + +>[!Quote]- Vertiefendes Beispiel +>Hier ein vertiefendes Beispiel angeben. +## Reflexion + +>[!Example]- Reflexion +>Eine reflexive Übung angeben. + +end + + + +```plantuml +@startmindmap + +*[#OrangeRed] Referatsthemen + + + +**[#LightBlue] P1 Netzwerktechnologien + + +**[#LightBlue] P2 Netzwerkdienste + + +**[#LightBlue]:P3 Netzwerkmanagement & +Netzwerksicherheit; + + +**[#DodgerBlue] J4 Enterprise Architekturen + +***[#LightGreen]:Testing +(Balog Danijel); +****[#LightGoldenRodYellow] Frontend +*****_ Selenium +******_:Beispiel mit Selenium +& Java; +*****_ Graphene +****[#LightGoldenRodYellow] Backend +*****_ JPA +******_:JavaSE-JUnit Client, +der Korrektheit eines +Datenmodells prüft; +*****_ REST loadtesting mit Galing +*****_ Cucumber +*****_ REST API testing mit Karate +*****_ RESTasured +*****_ Testcontainers +****[#LightGoldenRodYellow] Theorie + +***[#LightGreen]:CDI +(Schwarz Markus); +****[#LightGoldenRodYellow] Konzepte +*****_ @Inject vs. @EJB +*****_ Events +******_ Synchronous +******_ Asynchronous +*****_ Decorators +*****_ Interceptors +****[#LightGoldenRodYellow] Implementierungen +*****_ ArC (Quarkus) +*****_ Seam +*****_ Weld + +***[#LightGreen]:JDBC +(Habibovic Sandin); +****[#LightGoldenRodYellow] Historie +****[#LightGoldenRodYellow] Anwendungsbeispiel +****[#LightGoldenRodYellow] Abgrenzung JPQL / JPA + +***[#LightGreen]:Security +(Dürk Valentin); +****[#LightGoldenRodYellow] OpenID Connect (KeyCloak) +*****_ Codebeispiel +*****_ Two-Factor Authentication +****[#LightGoldenRodYellow] Methods of Authentication +*****_ Basic Auth +*****_ Bearer / Webtoken +*****_ OAuth2 +*****_:ContainerAuthentication, +ServletFilter; +****[#LightGoldenRodYellow] Probleme bei Security +*****_ SSH +*****_ CORS +*****_ Reverse Proxy (Traefik) + +***[#LightGreen]:Zugriff auf Datenbanken +Peric Antonio; +****[#LightGoldenRodYellow] RDB vs. noSQL +****[#LightGoldenRodYellow] Kafka +****[#LightGoldenRodYellow] Reactive vs. imperative +****[#LightGoldenRodYellow] JPA +*****_ Concurrency (@Version) +*****_:Codebeispiel mit Tests, um +Concurrency zu zeigen; +*****_ Frameworks +******_ Hibernate +******_ Eclipselink +******_ Panache + +***[#LightGreen]:Electron +(Servan Amel); + +***[#LawnGreen] RMI + +***[#LightGreen]:JavaFX +(Zellinger David); + +***[#LightGreen]:JakartaEE AppServers +(Lau William); +****[#LightGoldenRodYellow] Wildfly +****[#LightGoldenRodYellow] Payara +****[#LightGoldenRodYellow] OpenLiberty +****[#LightGoldenRodYellow] TomEE + +***[#LightGreen]:JakartaEE MicroProfile +(Siegl Maximilian); +****[#LightGoldenRodYellow] Health Checks +****[#LightGoldenRodYellow] openAPI +****[#LightGoldenRodYellow] openTracing +****[#LightGoldenRodYellow] metrics +****[#LightGoldenRodYellow] Fault-tolerance +*****_ Resiliance4j +*****_ Circuit Breaker + +***[#LightGreen]:Reactive vs. imperative +(Lehner Jakob); +****[#LightGoldenRodYellow] Codebeispiel mit Quarkus +*****_ einfaches Beispiel +******_ imperativ programmiert +******_ reactive programmiert +****[#LightGoldenRodYellow] Publisher-Subsriber-Pattern + + +**[#DodgerBlue] J5 Webapplikationen + +***[#LightGreen]:Java Webtechnologien +(Hinterleitner Felix); +****[#LightGoldenRodYellow] Servlets +*****_ Codebeispiel +****[#LightGoldenRodYellow] Java Server Pages (JSP) +*****_ Codebeispiel +*****_ JSTL +*****_ Schleifen +*****_ embedded Java code +*****_ EL +****[#LightGoldenRodYellow] Java Server Faces (JSF) +*****_ Codebeispiel +*****_ Primefaces +*****_:Mojarra +(Referenzimplementierung); +*****_ Bean validation +****[#LightGoldenRodYellow] Qute (nur für Quarkus) +*****_ Codebeispiel + +***[#LightGreen]:Flutter / Firebase / Serverless +(Edalatkhah Seyyed Arsham); +****[#LightGoldenRodYellow] Theorie +*****_ Serverless +*****_:Abgrenzung zu anderen +Technologien; + +***[#LightGreen]:Angular Clients +(Wilflingseder Florian); +****[#LightGoldenRodYellow] Codebeispiel +*****_ Datenbank +*****_ CRUD-Funktionalität +*****_:Daten in Tabellenform ++ lazy loading; +****[#LightGoldenRodYellow] Authentifizierung bei KeyCloak +****[#LightGoldenRodYellow] Aufbau einer Angular-App +****[#LightGoldenRodYellow] Konzepte von Angular + +***[#LightGreen]:Datenformate +(Bhuiyan Romeo); +****[#LightGoldenRodYellow] Anwendung +*****_ Validierung +******_ der Struktur +******_ des Inhaltes +*****_ Navigation +****[#LightGoldenRodYellow] Ausprägungen +*****_ XML +*****_ JSON +*****_ YAML +*****_ TOML +****[#LightGoldenRodYellow] Libraries +*****_ GSON +*****_ Jackson +*****_ JSON-B +*****_ JSON-P + +***[#LightGreen]:Client-Server Kommunkikation +(Wunder Mattias); +****[#LightGoldenRodYellow] SOAP +*****_ WSDL +****[#LightGoldenRodYellow] REST +*****_ Jersey +*****_ RESTeasy +****[#LightGoldenRodYellow] gRPC +****[#LightGoldenRodYellow] Websockets +****[#LightGoldenRodYellow] SSE +****[#LightGoldenRodYellow] graphQL +****[#LightGoldenRodYellow] Webhooks + +***[#LightGreen]:JavaScript & Frameworks +(Hausleitner Martin); +****[#LightGoldenRodYellow] Angular +****[#LightGoldenRodYellow] React +****[#LightGoldenRodYellow] VueJS +****[#LightGoldenRodYellow] Components +*****_ Typescript vs. JavaScript +*****_ Templating (lit-html) + + +**[#DodgerBlue]:J6 Client-Server Architekturen +& Mobile Computing; + +***[#LightGreen]:Android +(Imsirovic Benjamin); +****[#LightGoldenRodYellow] Fragments +****[#LightGoldenRodYellow] Provider +****[#LightGoldenRodYellow] Services +****[#LightGoldenRodYellow] Database +****[#LightGoldenRodYellow] Sicherheit in neueren Versionsn +****[#LightGoldenRodYellow] Jetpack Compose + +***[#LawnGreen] JavaFX +****[#LightGoldenRodYellow] Codebeispiel +*****_:JavaFX Client mit Verbindung +zu Quarkus REST-Backend; + +***[#LightGreen]:Docker +(Jahn Kevin); +****[#LightGoldenRodYellow] Docker +*****_:Pushen von images +in Docker Registry; +****[#LightGoldenRodYellow] Docker-compose +*****_ MySQL +*****_ Wildfly +*****_ NodeJs / nginx +****[#LightGoldenRodYellow] Docker Swarm & Kubernetes + +***[#LightGreen]:Kubernetes +(Paukner Zeno); +****[#LightGoldenRodYellow] Minikube +****[#LightGoldenRodYellow] LeoCloud +****[#LightGoldenRodYellow] jib, s2i, ... + + +**[#DodgerBlue]:J7 Systemnahe & +hardwarenahe Programmierung; + +***[#LightGreen]:Messaging +Kuvac Antonio; +****[#LightGoldenRodYellow] MQTT +*****_ Publisher-Subscriber Pattern +*****_ Mosquitto +*****_ Abgrenzung zu openHAB +*****_ Simulation +*****_ use in a Quarkus App +****[#LightGoldenRodYellow] Kafka +****[#LightGoldenRodYellow] JMS + +***[#LightGreen]:Environment variables +(Schned Fabian); +****[#LightGoldenRodYellow] Beispiele +*****_ JAVA_HOME +*****_ MVN_HOME +****[#LightGoldenRodYellow] Bedeutung in CI/CD +*****_ docker-compose +*****_ Java + +***[#LightGreen]:ShellScripts +(Rausch-Schott Simon); +****[#LightGoldenRodYellow] Bedeutung in CI/CD +*****_ Deployment +*****_ docker-compose + +***[#LawnGreen] AMQP +****[#LightGoldenRodYellow] RabbitMQ + +***[#LightGreen]:openHAB +(Kern Philip); +****[#LightGoldenRodYellow] Überblick +****[#LightGoldenRodYellow] Use-cases +****[#LightGoldenRodYellow] Abgrenzung zu MQTT + +***[#LawnGreen] Raspberry +****[#LightGoldenRodYellow] openHAB + +***[#LightGreen]:IoT +(Lasinger Christoph); +****[#LightGoldenRodYellow] Arduino IDE +****[#LightGoldenRodYellow] platformIO +*****_ Atom +****[#LightGoldenRodYellow] Sensoren +****[#LightGoldenRodYellow] Aktoren +****[#LightGoldenRodYellow] I2C +****[#LightGoldenRodYellow] ESP8266 +****[#LightGoldenRodYellow] ESP32 + +***[#LawnGreen] ChatBots +****[#LightGoldenRodYellow] lauffähiges Codebeispiel + +@endmindmap +``` \ No newline at end of file diff --git a/md/presentations/test-presentation.md b/md/presentations/CI-CD.md similarity index 100% rename from md/presentations/test-presentation.md rename to md/presentations/CI-CD.md diff --git a/md/presentations/test/test/Untitled.md b/md/presentations/test/test/Untitled.md new file mode 100644 index 0000000..19111bc --- /dev/null +++ b/md/presentations/test/test/Untitled.md @@ -0,0 +1 @@ +@@@ admin \ No newline at end of file diff --git a/md/test-fileperms-4bhif-5bhif-2ahif.md b/md/test-fileperms-4bhif-5bhif-2ahif.md deleted file mode 100644 index bbd1ba0..0000000 --- a/md/test-fileperms-4bhif-5bhif-2ahif.md +++ /dev/null @@ -1,3 +0,0 @@ -@@@ 4bhif, 5bhif, 4ahif - -Special visibility \ No newline at end of file diff --git a/md/test-md-file.md b/md/test-md-file.md index b1822a2..bf49cc9 100644 --- a/md/test-md-file.md +++ b/md/test-md-file.md @@ -1,38 +1,7 @@ -[[test-presentation]] -[[test-lernstrecke]] -[[test-fileperms-teachers]] -[[test-fileperms-4bhif-5bhif-2ahif]] -[[test-exam-practice-question]] +[[Lernstrecke]] ## Caption This is a sample text... -## Tests for inline-permissions -@@@ teacher -Only visible to the teachers. -@@@ -@@@ 4bhif -Only visible to 4bhif and teachers. -@@@ -@@@ admin -Admins only!!! -@@@ -@@@4bhif,5bhif, 4ahif -Special visibility -@@@ - -## Test PlantUML -```plantuml -[hansi] -[Mama] -[Günter] -[Gerald] -hansi -> Mama -Mama -> Günter -Gerald -> Mama -Günter -> Gerald -``` - -## Test Code Tags ```java public class TestClass { private int myInt; @@ -44,7 +13,6 @@ public class TestClass { } ``` -## Test Callouts > [!Note] > test @@ -55,10 +23,6 @@ public class TestClass { >Alternate heading. >Fully customizable. ->[!success]- Extremely long title so that it will break. fwosiu efwuorh gwurhg aeuhbwauerh awueh buea hbihaweiubv e... Just to see where the chevron will be :) ->blah -> - >[!error]- collapsable >You don't see this. lorem ipsum sdf uihweiufh iwruh glaiweruh gvöwau ervu aweöoruvheaöiou rfhgvaöwuregväou aweäviouha öweurihgviöuaewrhgvouwahe obvuh aäoüewuhfrb äoawure hbväoueah fövobuh aweourfhbv äoaweurb höoauewrhöboiuhea, diff --git a/md/test-fileperms-teachers.md b/md/test-teachers-only.md similarity index 100% rename from md/test-fileperms-teachers.md rename to md/test-teachers-only.md diff --git a/md/test.md b/md/test.md new file mode 100644 index 0000000..187829d --- /dev/null +++ b/md/test.md @@ -0,0 +1,441 @@ +@@@ teacher + +Test einer Lernstrecke: + +@@@ teacher +Only visible to the teachers. +@@@ +@@@ 4bhif +Only visible to 4bhif and teachers. +@@@ +@@@ admin +Admins only!!! +@@@ +@@@4bhif,5bhif, 4ahif +Special visibility +@@@ + +[[test-teachers-only]] +[[test-4bhif-etc]] + +>[!note] +> This is a Callout! + +[[LinkTest-MD-File]] + +[[md/assets/test]] +[[md/test|test]] +https://unterrainer.info +[testlink](https://unterrainer.info) + +* list 1 +* list 2 + * list 2.1 + * list 2.2 +* list 3 + +> test +> * he +> * sfe +> * efwef + + + + + + + + + + + +
+>[!tip]- collabsable +>Hi there! +>I'm some code... +test
testtest
+ +Das ist ein Text +* Weil er gut ist +```java +public void schas(int i){} +``` + +```plantuml +[hansi] +[Mama] +[Günter] +[Gerald] +hansi -> Mama +Mama -> Günter +Gerald -> Mama +Günter -> Gerald +``` + +[[Neue Idee]] +[[Dune 2]] + +>[!success]- Extremely long title so that it will break. fwosiu efwuorh gwurhg aeuhbwauerh awueh buea hbihaweiubv e... Just to see where the chevron will be :) +>blah + +## Überblick + +> [!info]- Präsentation +>Hier findet Ihr den gesamten Stoff als Präsentation. +>https://htl.unterrainer.info/jwt.html +>* test +>* test + +>[!info]- JWT vs. Cookies (kurz) +>https://www.youtube.com/watch?v=UBUNrFtufWo + +>[!info]- JWT vs. Cookies (länger) +>https://www.youtube.com/watch?v=o9hT7v0OLJc + +>[!info]- JWT (detailliert) +>https://www.youtube.com/watch?v=P2CPd9ynFLg + +>[!note]- Access Tokens / Refresh Tokens +>[https://www.youtube.com/watch?v=LowJMwa7LCU](https://www.youtube.com/watch?v=LowJMwa7LCU) +## Grundkompetenzen + +>[!warning]- Stoff können +>Hier einen Test eintragen. +## CheckPoint + +>[!success]- GENÜGEND +>Das musst Du können, damit Du diese Strecke positiv abschließen kannst: +> +>**JWT** +>* Was sind JWTs? +>* Wie sieht ein JWT aus? +>* Welche Probleme lösen sie? +>* Wie funktioniert das Signieren? +> +>**OAuth2 / OpenID Connect (OIDC)** +>* Wie wird ein JWT bei OAuth-Authorization verwendet? +>* Was ist ein **Access-Token**? +> * Wozu braucht man ihn? +>* Was ist ein **Refresh-Token**? +> * Wozu braucht man ihn? + +>[!tip]- JWT +>Um eine bessere Note zu erreichen, solltest Du noch folgendes erledigen: +> +>**JWT** +>* Beispiel programmieren +>https://quarkus.io/guides/security-jwt + +>[!tip]- OAuth2 +>Um eine bessere Note zu erreichen, solltest Du noch folgendes erledigen: +> +>**OAuth2 / OpenID Connect (OIDC)** +>* Access-Token - Wie funktioniert er? +>* Refresh-Token - Wie funktioniert er? +## Vertiefungen + +>[!Quote]- Vertiefendes Beispiel +>Hier ein vertiefendes Beispiel angeben. +## Reflexion + +>[!Example]- Reflexion +>Eine reflexive Übung angeben. + +end + + + +```plantuml +@startmindmap + +*[#OrangeRed] Referatsthemen + + + +**[#LightBlue] P1 Netzwerktechnologien + + +**[#LightBlue] P2 Netzwerkdienste + + +**[#LightBlue]:P3 Netzwerkmanagement & +Netzwerksicherheit; + + +**[#DodgerBlue] J4 Enterprise Architekturen + +***[#LightGreen]:Testing +(Balog Danijel); +****[#LightGoldenRodYellow] Frontend +*****_ Selenium +******_:Beispiel mit Selenium +& Java; +*****_ Graphene +****[#LightGoldenRodYellow] Backend +*****_ JPA +******_:JavaSE-JUnit Client, +der Korrektheit eines +Datenmodells prüft; +*****_ REST loadtesting mit Galing +*****_ Cucumber +*****_ REST API testing mit Karate +*****_ RESTasured +*****_ Testcontainers +****[#LightGoldenRodYellow] Theorie + +***[#LightGreen]:CDI +(Schwarz Markus); +****[#LightGoldenRodYellow] Konzepte +*****_ @Inject vs. @EJB +*****_ Events +******_ Synchronous +******_ Asynchronous +*****_ Decorators +*****_ Interceptors +****[#LightGoldenRodYellow] Implementierungen +*****_ ArC (Quarkus) +*****_ Seam +*****_ Weld + +***[#LightGreen]:JDBC +(Habibovic Sandin); +****[#LightGoldenRodYellow] Historie +****[#LightGoldenRodYellow] Anwendungsbeispiel +****[#LightGoldenRodYellow] Abgrenzung JPQL / JPA + +***[#LightGreen]:Security +(Dürk Valentin); +****[#LightGoldenRodYellow] OpenID Connect (KeyCloak) +*****_ Codebeispiel +*****_ Two-Factor Authentication +****[#LightGoldenRodYellow] Methods of Authentication +*****_ Basic Auth +*****_ Bearer / Webtoken +*****_ OAuth2 +*****_:ContainerAuthentication, +ServletFilter; +****[#LightGoldenRodYellow] Probleme bei Security +*****_ SSH +*****_ CORS +*****_ Reverse Proxy (Traefik) + +***[#LightGreen]:Zugriff auf Datenbanken +Peric Antonio; +****[#LightGoldenRodYellow] RDB vs. noSQL +****[#LightGoldenRodYellow] Kafka +****[#LightGoldenRodYellow] Reactive vs. imperative +****[#LightGoldenRodYellow] JPA +*****_ Concurrency (@Version) +*****_:Codebeispiel mit Tests, um +Concurrency zu zeigen; +*****_ Frameworks +******_ Hibernate +******_ Eclipselink +******_ Panache + +***[#LightGreen]:Electron +(Servan Amel); + +***[#LawnGreen] RMI + +***[#LightGreen]:JavaFX +(Zellinger David); + +***[#LightGreen]:JakartaEE AppServers +(Lau William); +****[#LightGoldenRodYellow] Wildfly +****[#LightGoldenRodYellow] Payara +****[#LightGoldenRodYellow] OpenLiberty +****[#LightGoldenRodYellow] TomEE + +***[#LightGreen]:JakartaEE MicroProfile +(Siegl Maximilian); +****[#LightGoldenRodYellow] Health Checks +****[#LightGoldenRodYellow] openAPI +****[#LightGoldenRodYellow] openTracing +****[#LightGoldenRodYellow] metrics +****[#LightGoldenRodYellow] Fault-tolerance +*****_ Resiliance4j +*****_ Circuit Breaker + +***[#LightGreen]:Reactive vs. imperative +(Lehner Jakob); +****[#LightGoldenRodYellow] Codebeispiel mit Quarkus +*****_ einfaches Beispiel +******_ imperativ programmiert +******_ reactive programmiert +****[#LightGoldenRodYellow] Publisher-Subsriber-Pattern + + +**[#DodgerBlue] J5 Webapplikationen + +***[#LightGreen]:Java Webtechnologien +(Hinterleitner Felix); +****[#LightGoldenRodYellow] Servlets +*****_ Codebeispiel +****[#LightGoldenRodYellow] Java Server Pages (JSP) +*****_ Codebeispiel +*****_ JSTL +*****_ Schleifen +*****_ embedded Java code +*****_ EL +****[#LightGoldenRodYellow] Java Server Faces (JSF) +*****_ Codebeispiel +*****_ Primefaces +*****_:Mojarra +(Referenzimplementierung); +*****_ Bean validation +****[#LightGoldenRodYellow] Qute (nur für Quarkus) +*****_ Codebeispiel + +***[#LightGreen]:Flutter / Firebase / Serverless +(Edalatkhah Seyyed Arsham); +****[#LightGoldenRodYellow] Theorie +*****_ Serverless +*****_:Abgrenzung zu anderen +Technologien; + +***[#LightGreen]:Angular Clients +(Wilflingseder Florian); +****[#LightGoldenRodYellow] Codebeispiel +*****_ Datenbank +*****_ CRUD-Funktionalität +*****_:Daten in Tabellenform ++ lazy loading; +****[#LightGoldenRodYellow] Authentifizierung bei KeyCloak +****[#LightGoldenRodYellow] Aufbau einer Angular-App +****[#LightGoldenRodYellow] Konzepte von Angular + +***[#LightGreen]:Datenformate +(Bhuiyan Romeo); +****[#LightGoldenRodYellow] Anwendung +*****_ Validierung +******_ der Struktur +******_ des Inhaltes +*****_ Navigation +****[#LightGoldenRodYellow] Ausprägungen +*****_ XML +*****_ JSON +*****_ YAML +*****_ TOML +****[#LightGoldenRodYellow] Libraries +*****_ GSON +*****_ Jackson +*****_ JSON-B +*****_ JSON-P + +***[#LightGreen]:Client-Server Kommunkikation +(Wunder Mattias); +****[#LightGoldenRodYellow] SOAP +*****_ WSDL +****[#LightGoldenRodYellow] REST +*****_ Jersey +*****_ RESTeasy +****[#LightGoldenRodYellow] gRPC +****[#LightGoldenRodYellow] Websockets +****[#LightGoldenRodYellow] SSE +****[#LightGoldenRodYellow] graphQL +****[#LightGoldenRodYellow] Webhooks + +***[#LightGreen]:JavaScript & Frameworks +(Hausleitner Martin); +****[#LightGoldenRodYellow] Angular +****[#LightGoldenRodYellow] React +****[#LightGoldenRodYellow] VueJS +****[#LightGoldenRodYellow] Components +*****_ Typescript vs. JavaScript +*****_ Templating (lit-html) + + +**[#DodgerBlue]:J6 Client-Server Architekturen +& Mobile Computing; + +***[#LightGreen]:Android +(Imsirovic Benjamin); +****[#LightGoldenRodYellow] Fragments +****[#LightGoldenRodYellow] Provider +****[#LightGoldenRodYellow] Services +****[#LightGoldenRodYellow] Database +****[#LightGoldenRodYellow] Sicherheit in neueren Versionsn +****[#LightGoldenRodYellow] Jetpack Compose + +***[#LawnGreen] JavaFX +****[#LightGoldenRodYellow] Codebeispiel +*****_:JavaFX Client mit Verbindung +zu Quarkus REST-Backend; + +***[#LightGreen]:Docker +(Jahn Kevin); +****[#LightGoldenRodYellow] Docker +*****_:Pushen von images +in Docker Registry; +****[#LightGoldenRodYellow] Docker-compose +*****_ MySQL +*****_ Wildfly +*****_ NodeJs / nginx +****[#LightGoldenRodYellow] Docker Swarm & Kubernetes + +***[#LightGreen]:Kubernetes +(Paukner Zeno); +****[#LightGoldenRodYellow] Minikube +****[#LightGoldenRodYellow] LeoCloud +****[#LightGoldenRodYellow] jib, s2i, ... + + +**[#DodgerBlue]:J7 Systemnahe & +hardwarenahe Programmierung; + +***[#LightGreen]:Messaging +Kuvac Antonio; +****[#LightGoldenRodYellow] MQTT +*****_ Publisher-Subscriber Pattern +*****_ Mosquitto +*****_ Abgrenzung zu openHAB +*****_ Simulation +*****_ use in a Quarkus App +****[#LightGoldenRodYellow] Kafka +****[#LightGoldenRodYellow] JMS + +***[#LightGreen]:Environment variables +(Schned Fabian); +****[#LightGoldenRodYellow] Beispiele +*****_ JAVA_HOME +*****_ MVN_HOME +****[#LightGoldenRodYellow] Bedeutung in CI/CD +*****_ docker-compose +*****_ Java + +***[#LightGreen]:ShellScripts +(Rausch-Schott Simon); +****[#LightGoldenRodYellow] Bedeutung in CI/CD +*****_ Deployment +*****_ docker-compose + +***[#LawnGreen] AMQP +****[#LightGoldenRodYellow] RabbitMQ + +***[#LightGreen]:openHAB +(Kern Philip); +****[#LightGoldenRodYellow] Überblick +****[#LightGoldenRodYellow] Use-cases +****[#LightGoldenRodYellow] Abgrenzung zu MQTT + +***[#LawnGreen] Raspberry +****[#LightGoldenRodYellow] openHAB + +***[#LightGreen]:IoT +(Lasinger Christoph); +****[#LightGoldenRodYellow] Arduino IDE +****[#LightGoldenRodYellow] platformIO +*****_ Atom +****[#LightGoldenRodYellow] Sensoren +****[#LightGoldenRodYellow] Aktoren +****[#LightGoldenRodYellow] I2C +****[#LightGoldenRodYellow] ESP8266 +****[#LightGoldenRodYellow] ESP32 + +***[#LawnGreen] ChatBots +****[#LightGoldenRodYellow] lauffähiges Codebeispiel + +@endmindmap +``` \ No newline at end of file