From 9e9ab1628d90a439426dafccda769551e1b79abf Mon Sep 17 00:00:00 2001 From: Teena Steger Date: Wed, 12 Nov 2025 10:06:19 +0100 Subject: [PATCH] 07: Demos und Labor --- web/06/demos/00-values.go | 19 ------ web/06/demos/01-variables.go | 23 -------- web/06/demos/02-constants.go | 21 ------- web/06/demos/03-for.go | 32 ---------- web/06/demos/04-if-else.go | 28 --------- web/06/demos/05-switch.go | 49 --------------- web/06/demos/06-arrays.go | 38 ------------ web/06/demos/07-pointers.go | 24 -------- web/06/demos/08-slices.go | 58 ------------------ web/06/demos/09-maps.go | 42 ------------- web/06/demos/11-functions.go | 36 ----------- web/06/demos/helloworld.go | 7 --- web/07/demos/00_method_receiver.go | 26 ++++++++ web/07/demos/01_helloworld_http.go | 17 ++++++ web/07/demos/02_responsewriter_http.go | 19 ++++++ web/07/demos/03_get_request_http.go | 36 +++++++++++ web/07/demos/04_post_request_http.go | 47 +++++++++++++++ web/07/demos/post_form.html | 22 +++++++ web/07/demos/taskmanager/go.mod | 3 + web/07/demos/taskmanager/main.go | 82 ++++++++++++++++++++++++++ web/07/demos/taskmanager/task.go | 60 +++++++++++++++++++ web/07/demos/taskmanager/tasks.json | 19 ++++++ web/07/labor/07_aufgaben.md | 80 +++++++++++++++++++++++++ 23 files changed, 411 insertions(+), 377 deletions(-) delete mode 100644 web/06/demos/00-values.go delete mode 100644 web/06/demos/01-variables.go delete mode 100644 web/06/demos/02-constants.go delete mode 100644 web/06/demos/03-for.go delete mode 100644 web/06/demos/04-if-else.go delete mode 100644 web/06/demos/05-switch.go delete mode 100644 web/06/demos/06-arrays.go delete mode 100644 web/06/demos/07-pointers.go delete mode 100644 web/06/demos/08-slices.go delete mode 100644 web/06/demos/09-maps.go delete mode 100644 web/06/demos/11-functions.go delete mode 100644 web/06/demos/helloworld.go create mode 100644 web/07/demos/00_method_receiver.go create mode 100644 web/07/demos/01_helloworld_http.go create mode 100644 web/07/demos/02_responsewriter_http.go create mode 100644 web/07/demos/03_get_request_http.go create mode 100644 web/07/demos/04_post_request_http.go create mode 100644 web/07/demos/post_form.html create mode 100644 web/07/demos/taskmanager/go.mod create mode 100644 web/07/demos/taskmanager/main.go create mode 100644 web/07/demos/taskmanager/task.go create mode 100644 web/07/demos/taskmanager/tasks.json create mode 100644 web/07/labor/07_aufgaben.md diff --git a/web/06/demos/00-values.go b/web/06/demos/00-values.go deleted file mode 100644 index d1af72e..0000000 --- a/web/06/demos/00-values.go +++ /dev/null @@ -1,19 +0,0 @@ -package main - -import "fmt" - -func main() { - - //Strings - fmt.Println("go" + "lang") - - //Integers - fmt.Println("1+1 =", 1+1) - //Floats - fmt.Println("7.0/3.0 =", 7.0/3.0) - - //Boolean - fmt.Println(true && false) - fmt.Println(true || false) - fmt.Println(!true) -} diff --git a/web/06/demos/01-variables.go b/web/06/demos/01-variables.go deleted file mode 100644 index ec75eb6..0000000 --- a/web/06/demos/01-variables.go +++ /dev/null @@ -1,23 +0,0 @@ -package main - -import "fmt" - -var z = "initial" - -func main() { - - var a = "initial" - fmt.Println(a) - - var b, c int = 1, 2 - fmt.Println(b, c) - - var d = true - fmt.Println(d) - - var e int - fmt.Println(e) - - f := "apple" - fmt.Println(f) -} diff --git a/web/06/demos/02-constants.go b/web/06/demos/02-constants.go deleted file mode 100644 index c030546..0000000 --- a/web/06/demos/02-constants.go +++ /dev/null @@ -1,21 +0,0 @@ -package main - -import ( - "fmt" - "math" -) - -const s string = "constant" - -func main() { - fmt.Println(s) - - const n = 500000000 - - const d = 3e20 / n - fmt.Println(d) - - fmt.Println(int64(d)) - - fmt.Println(math.Sin(n)) -} \ No newline at end of file diff --git a/web/06/demos/03-for.go b/web/06/demos/03-for.go deleted file mode 100644 index 912b6c3..0000000 --- a/web/06/demos/03-for.go +++ /dev/null @@ -1,32 +0,0 @@ -package main - -import "fmt" - -func main() { - - i := 1 - for i <= 3 { - fmt.Println(i) - i = i + 1 - } - - for j := 0; j < 3; j++ { - fmt.Println(j) - } - - for i := range 3 { - fmt.Println("range", i) - } - - for { - fmt.Println("loop") - break - } - - for n := range 6 { - if n%2 == 0 { - continue - } - fmt.Println(n) - } -} diff --git a/web/06/demos/04-if-else.go b/web/06/demos/04-if-else.go deleted file mode 100644 index c4e8f89..0000000 --- a/web/06/demos/04-if-else.go +++ /dev/null @@ -1,28 +0,0 @@ -package main - -import "fmt" - -func main() { - - if 7%2 == 0 { - fmt.Println("7 is even") - } else { - fmt.Println("7 is odd") - } - - if 8%4 == 0 { - fmt.Println("8 is divisible by 4") - } - - if 8%2 == 0 || 7%2 == 0 { - fmt.Println("either 8 or 7 are even") - } - - if num := 9; num < 0 { - fmt.Println(num, "is negative") - } else if num < 10 { - fmt.Println(num, "has 1 digit") - } else { - fmt.Println(num, "has multiple digits") - } -} diff --git a/web/06/demos/05-switch.go b/web/06/demos/05-switch.go deleted file mode 100644 index 545f1a6..0000000 --- a/web/06/demos/05-switch.go +++ /dev/null @@ -1,49 +0,0 @@ -package main - -import ( - "fmt" - "time" -) - -func main() { - - i := 2 - fmt.Print("Write ", i, " as ") - switch i { - case 1: - fmt.Println("one") - case 2: - fmt.Println("two") - case 3: - fmt.Println("three") - } - - switch time.Now().Weekday() { - case time.Saturday, time.Sunday: - fmt.Println("It's the weekend") - default: - fmt.Println("It's a weekday") - } - - t := time.Now() - switch { - case t.Hour() < 12: - fmt.Println("It's before noon") - default: - fmt.Println("It's after noon") - } - - whatAmI := func(i interface{}) { - switch t := i.(type) { - case bool: - fmt.Println("I'm a bool") - case int: - fmt.Println("I'm an int") - default: - fmt.Printf("Don't know type %T\n", t) - } - } - whatAmI(true) - whatAmI(1) - whatAmI("hey") -} diff --git a/web/06/demos/06-arrays.go b/web/06/demos/06-arrays.go deleted file mode 100644 index 0db8314..0000000 --- a/web/06/demos/06-arrays.go +++ /dev/null @@ -1,38 +0,0 @@ -package main - -import "fmt" - -func main() { - - var a [5]int - fmt.Println("emp:", a) - - a[4] = 100 - fmt.Println("set:", a) - fmt.Println("get:", a[4]) - - fmt.Println("len:", len(a)) - - b := [5]int{1, 2, 3, 4, 5} - fmt.Println("dcl:", b) - - b = [...]int{1, 2, 3, 4, 5} - fmt.Println("dcl:", b) - - b = [...]int{100, 3: 400, 500} - fmt.Println("idx:", b) - - var twoD [2][3]int - for i := 0; i < 2; i++ { - for j := 0; j < 3; j++ { - twoD[i][j] = i + j - } - } - fmt.Println("2d: ", twoD) - - twoD = [2][3]int{ - {1, 2, 3}, - {1, 2, 3}, - } - fmt.Println("2d: ", twoD) -} diff --git a/web/06/demos/07-pointers.go b/web/06/demos/07-pointers.go deleted file mode 100644 index e5f95f6..0000000 --- a/web/06/demos/07-pointers.go +++ /dev/null @@ -1,24 +0,0 @@ -package main - -import "fmt" - -func zeroval(ival int) { - ival = 0 -} - -func zeroptr(iptr *int) { - *iptr = 0 -} - -func main() { - i := 1 - fmt.Println("initial:", i) - - zeroval(i) - fmt.Println("zeroval:", i) - - zeroptr(&i) - fmt.Println("zeroptr:", i) - - fmt.Println("pointer:", &i) -} diff --git a/web/06/demos/08-slices.go b/web/06/demos/08-slices.go deleted file mode 100644 index 8400528..0000000 --- a/web/06/demos/08-slices.go +++ /dev/null @@ -1,58 +0,0 @@ -package main - -import ( - "fmt" - "slices" -) - -func main() { - - var s []string - fmt.Println("uninit:", s, s == nil, len(s) == 0) - - s = make([]string, 3) - fmt.Println("emp:", s, "len:", len(s), "cap:", cap(s)) - - s[0] = "a" - s[1] = "b" - s[2] = "c" - fmt.Println("set:", s) - fmt.Println("get:", s[2]) - - fmt.Println("len:", len(s)) - - s = append(s, "d") - s = append(s, "e", "f") - fmt.Println("apd:", s) - - c := make([]string, len(s)) - copy(c, s) - fmt.Println("cpy:", c) - - l := s[2:5] - fmt.Println("sl1:", l) - - l = s[:5] - fmt.Println("sl2:", l) - - l = s[2:] - fmt.Println("sl3:", l) - - t := []string{"g", "h", "i"} - fmt.Println("dcl:", t) - - t2 := []string{"g", "h", "i"} - if slices.Equal(t, t2) { - fmt.Println("t == t2") - } - - twoD := make([][]int, 3) - for i := 0; i < 3; i++ { - innerLen := i + 1 - twoD[i] = make([]int, innerLen) - for j := 0; j < innerLen; j++ { - twoD[i][j] = i + j - } - } - fmt.Println("2d: ", twoD) -} diff --git a/web/06/demos/09-maps.go b/web/06/demos/09-maps.go deleted file mode 100644 index 5918528..0000000 --- a/web/06/demos/09-maps.go +++ /dev/null @@ -1,42 +0,0 @@ -package main - -import ( - "fmt" - "maps" -) - -func main() { - - m := make(map[string]int) - - m["k1"] = 7 - m["k2"] = 13 - - fmt.Println("map:", m) - - v1 := m["k1"] - fmt.Println("v1:", v1) - - v3 := m["k3"] - fmt.Println("v3:", v3) - - fmt.Println("len:", len(m)) - - // delete(m, "k2") - // fmt.Println("map:", m) - - // clear(m) - // fmt.Println("map:", m) - - wert, prs := m["k2"] - fmt.Println("prs:", prs) - fmt.Println("wert:", wert) - - n := map[string]int{"foo": 1, "bar": 2} - fmt.Println("map:", n) - - n2 := map[string]int{"foo": 1, "bar": 2} - if maps.Equal(n, n2) { - fmt.Println("n == n2") - } -} diff --git a/web/06/demos/11-functions.go b/web/06/demos/11-functions.go deleted file mode 100644 index 4f51b2d..0000000 --- a/web/06/demos/11-functions.go +++ /dev/null @@ -1,36 +0,0 @@ -package main - -import "fmt" - -func plus(a int, b int) int { - return a + b -} - -func plusPlus(a, b, c int) int { - return a + b + c -} - -func plusNamed(a, b int) (result int) { - result = a + b - return -} - -func plusDescription(a int, b int) (int, string) { - result := a + b - return result, fmt.Sprintf("%d+%d = %d", a, b, result) -} - -func main() { - - res := plus(1, 2) - fmt.Println("1+2 =", res) - - res = plusPlus(1, 2, 3) - fmt.Println("1+2+3 =", res) - - res = plusNamed(1, 2) - fmt.Println("1+2 =", res) - - _, desc := plusDescription(1, 2) - fmt.Println(desc) -} diff --git a/web/06/demos/helloworld.go b/web/06/demos/helloworld.go deleted file mode 100644 index c048119..0000000 --- a/web/06/demos/helloworld.go +++ /dev/null @@ -1,7 +0,0 @@ -package main - -import "fmt" - -func main() { - fmt.Println("hello world") -} diff --git a/web/07/demos/00_method_receiver.go b/web/07/demos/00_method_receiver.go new file mode 100644 index 0000000..00f8020 --- /dev/null +++ b/web/07/demos/00_method_receiver.go @@ -0,0 +1,26 @@ +package main + +import "fmt" + +type Person struct { + Name string + Age int +} + +// Wert-Receiver: arbeitet auf einer Kopie +func (p Person) Greet() { + fmt.Println("Hallo,", p.Name) +} + +// Zeiger-Receiver: kann das Original ändern +func (p *Person) Birthday() { + p.Age++ +} + +func main() { + a := Person{Name: "Karl", Age: 30} + + a.Greet() // Ausgabe: Hallo, Karl + a.Birthday() // Alter wird erhöht + fmt.Println(a.Age) // Ausgabe: 31 +} diff --git a/web/07/demos/01_helloworld_http.go b/web/07/demos/01_helloworld_http.go new file mode 100644 index 0000000..e6eae8a --- /dev/null +++ b/web/07/demos/01_helloworld_http.go @@ -0,0 +1,17 @@ +package main + +import ( + "fmt" + "net/http" +) + +type helloHandler int + +func (hello helloHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) { + fmt.Fprintf(w, "Hello World %d!", hello) +} + +func main() { + var world helloHandler + http.ListenAndServe("localhost:8080", world) +} diff --git a/web/07/demos/02_responsewriter_http.go b/web/07/demos/02_responsewriter_http.go new file mode 100644 index 0000000..da73765 --- /dev/null +++ b/web/07/demos/02_responsewriter_http.go @@ -0,0 +1,19 @@ +package main + +import ( + "net/http" +) + +type respExampleHandler int + +func (hello respExampleHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) { + w.Header().Set("my-http-header", "Ein beliebiger Text") + w.Header().Set("Content-Type", "text/html; charset=utf-8") + w.WriteHeader(http.StatusFound) + w.Write([]byte("

Dies ist eine HTML-Überschrift

")) +} + +func main() { + var r respExampleHandler + http.ListenAndServe("localhost:8080", r) +} diff --git a/web/07/demos/03_get_request_http.go b/web/07/demos/03_get_request_http.go new file mode 100644 index 0000000..5462ffd --- /dev/null +++ b/web/07/demos/03_get_request_http.go @@ -0,0 +1,36 @@ +package main + +import ( + "fmt" + "net/http" +) + +type reqExampleHandler int + +func (hello reqExampleHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) { + + if r.Method != http.MethodGet { + http.Error(w, "Only GET requests are allowed", http.StatusMethodNotAllowed) + return + } + + fmt.Println("Method:", r.Method) + fmt.Println("URL:", r.URL.String()) + fmt.Println("Host:", r.Host) + fmt.Println("Accept-Header", r.Header.Get("Accept")) + + queryParams := r.URL.Query() + fmt.Println("Query Parameters:") + for key, values := range queryParams { + for _, value := range values { + fmt.Printf(" %s = %s\n", key, value) + } + } + + w.Write([]byte("

GET: http.Request-Beispiel

")) +} + +func main() { + var r reqExampleHandler + http.ListenAndServe("localhost:8080", r) +} diff --git a/web/07/demos/04_post_request_http.go b/web/07/demos/04_post_request_http.go new file mode 100644 index 0000000..b311cf6 --- /dev/null +++ b/web/07/demos/04_post_request_http.go @@ -0,0 +1,47 @@ +package main + +import ( + "fmt" + "net/http" +) + +type formExampleHandler int + +func (formHandler formExampleHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) { + + if r.Method != http.MethodPost { + http.Error(w, "Only POST requests are allowed", http.StatusMethodNotAllowed) + return + } + + // Formulardaten parsen und Überprüfen, ob ungültige Formulardaten gesendet wurde + if err := r.ParseForm(); err != nil { + http.Error(w, "Fehler beim Parsen des Formulars", http.StatusBadRequest) + return + } + + // Überprüfen, ob leeres Formular gesendet wurde + if len(r.PostForm) == 0 { + http.Error(w, "Kein POST-Formular gesendet", http.StatusBadRequest) + return + } + + // Zugriff auf PostForm-Daten + // string mit Wert des Feldes "name" + name := r.PostForm.Get("name") + // []string mit allen ausgewählten Werten der Checkbox "hobby" + hobbies := r.PostForm["hobby"] + + // Ausgabe der Werte + fmt.Fprintf(w, "Name: %s\n", name) + fmt.Fprintf(w, "Hobbies:\n") + for _, h := range hobbies { + fmt.Fprintf(w, "- %s\n", h) + } + +} + +func main() { + var r formExampleHandler + http.ListenAndServe("localhost:8080", r) +} diff --git a/web/07/demos/post_form.html b/web/07/demos/post_form.html new file mode 100644 index 0000000..0c7c328 --- /dev/null +++ b/web/07/demos/post_form.html @@ -0,0 +1,22 @@ + + + + + + Einfaches Formular für Backend + + + +
+ + +

Hobbies: + + + +

+ +
+ + + \ No newline at end of file diff --git a/web/07/demos/taskmanager/go.mod b/web/07/demos/taskmanager/go.mod new file mode 100644 index 0000000..ac8c0df --- /dev/null +++ b/web/07/demos/taskmanager/go.mod @@ -0,0 +1,3 @@ +module taskmanager + +go 1.24.5 diff --git a/web/07/demos/taskmanager/main.go b/web/07/demos/taskmanager/main.go new file mode 100644 index 0000000..668daf3 --- /dev/null +++ b/web/07/demos/taskmanager/main.go @@ -0,0 +1,82 @@ +package main + +import ( + "fmt" + "os" + "strconv" +) + +func main() { + // Frage: Was macht dieser Teil genau? + if len(os.Args) < 2 { + fmt.Println("Usage: add | list | done ") + return + } + + // Lädt alle Tasks aus JSON-Datei in eine Liste + // Gibt eine leere Liste zurück, falls die JSON-Datei noch nicht existiert + // Gibt Fehlermeldung vom Typ error zurück, falls etwas schief gelaufen ist + tasklist, err := LoadTasks("tasks.json") + + // TODO: Fehlerbehandlung + if err != nil { + fmt.Println("Fehler beim Laden der JSON-Datei: " + err.Error()) + } + + // Je nach Kommandozeilenargument wird: + // - Task neu erstellt und zur Liste hinzugefügt (auch in JSON-Datei) + // - Alle Tasks aus der Liste ausgegeben inkl. Status ("✓" für done, sonst " ") + // - Task als done markiert und Ergebnis ausgegeben + switch os.Args[1] { + case "add": + // TODO: Prüfen, ob 3. Kommandozeilenargument für Title vorliegt + if len(os.Args) < 3 { + fmt.Println("Geben Sie einen Titel ein.") + return + } + + // TODO: Task zur Liste hinzufügen + tasklist.Add(os.Args[2]) + + // TODO: Liste in JSON-Datei speichern + tasklist.Save("tasks.json") + + // Ergebnis ausgeben + fmt.Println("Task added.") + + case "list": + // TODO: Durch alle Tasks der Liste iterieren + for _, task := range tasklist.Tasks { + // TODO: Task-Status bestimmen und inklusive ID und Title ausgeben + status := " " + if task.Done { + status = "✓" + } + fmt.Printf("[%s] %d: %s\n", status, task.ID, task.Title) + + } + + case "done": + // TODO: Prüfen, ob 3. Kommandozeilenargument für ID vorliegen + if len(os.Args) < 3 { + fmt.Println("Geben Sie eine ID ein.") + return + } + + // TODO: Prüfen, ob ID vom Typ integer, sonst Fehlermeldung und Abbruch + // Tipp: strconv.Atoi(string) + id, err := strconv.Atoi(os.Args[2]) + if err != nil { + fmt.Println("Falsche Eingabe der ID") + return + } + // TODO: Task auf done setzen + tasklist.Complete(id) + + // TODO: Taskliste in JSON-Datei speichern + tasklist.Save("tasks.json") + + // Ergebnis ausgeben + fmt.Println("Task marked as done.") + } +} diff --git a/web/07/demos/taskmanager/task.go b/web/07/demos/taskmanager/task.go new file mode 100644 index 0000000..6816c96 --- /dev/null +++ b/web/07/demos/taskmanager/task.go @@ -0,0 +1,60 @@ +package main + +import ( + "encoding/json" + "os" +) + +// TODO: Task repräsentiert eine einzelne To-Do-Aufgabe mit ID, Titel und Status. +// Tipp: struct verwenden +type Task struct { + ID int `json:"id"` + Title string `json:"title"` + Done bool `json:"done"` +} + +// TODO: TaskList enthält eine Liste von Aufgaben (Tasks). +type TaskList struct { + Tasks []Task `json:"tasks"` +} + +// TODO: Fügt einen neuen Task mit übergebenen Titel in die Liste ein. +// Die neue ID entspricht der Anzahl der Elemente in der Liste. (ok, weil keine Tasks gelöscht werden) +func (tl *TaskList) Add(title string) { + id := len(tl.Tasks) + 1 + newTask := Task{ID: id, Title: title, Done: false} + tl.Tasks = append(tl.Tasks, newTask) +} + +// TODO: Setzt vorhandenen Task mit übergebener ID auf den Status done. +// Annahme: Wir wissen nicht, wie ID erstellt wird. +func (tl *TaskList) Complete(id int) { + for i := range tl.Tasks { + if tl.Tasks[i].ID == id { + tl.Tasks[i].Done = true + } + } +} + +// Liste wird im JSON-Format in einer Datei mit übergebenen Dateinamen gespeichert +func (tl *TaskList) Save(filename string) error { + data, err := json.MarshalIndent(tl, "", " ") + if err != nil { + return err + } + return os.WriteFile(filename, data, 0644) +} + +// TODO: Lädt eine Liste von Tasks aus einer JSON-Datei (Dateiname als Parameter übergeben) +// Falls die Datei noch nicht existiert, wird eine leere Liste (neu) zurückgegeben +// Tipp 1: Einlesen einer Datei: os.ReadFile(filename) +// Tipp 2: JSON-Daten in TaskList-Struktur umwandeln: json.Unmarshal(data, &tl) +func LoadTasks(filename string) (*TaskList, error) { + data, err := os.ReadFile(filename) + if err != nil { + return &TaskList{}, nil + } + var tl TaskList + jsonErr := json.Unmarshal(data, &tl) + return &tl, jsonErr +} diff --git a/web/07/demos/taskmanager/tasks.json b/web/07/demos/taskmanager/tasks.json new file mode 100644 index 0000000..63b6e7b --- /dev/null +++ b/web/07/demos/taskmanager/tasks.json @@ -0,0 +1,19 @@ +{ + "tasks": [ + { + "id": 1, + "title": "Vorlesung besuchen", + "done": false + }, + { + "id": 2, + "title": "Go by Example durcharbeiten", + "done": true + }, + { + "id": 3, + "title": "Webserver lokal installieren", + "done": false + } + ] +} \ No newline at end of file diff --git a/web/07/labor/07_aufgaben.md b/web/07/labor/07_aufgaben.md new file mode 100644 index 0000000..2588311 --- /dev/null +++ b/web/07/labor/07_aufgaben.md @@ -0,0 +1,80 @@ +# Übungsblatt 07 + +## 1. Go-Übung: Grundlagen + +_Keine Abgabe erforderlich_ + +**Aufgabenstellung**: Machen Sie sich mit den Grundlagen der Programmiersprache vertraut. + +#### Arbeitsschritte + +1. Besuchen Sie die Webseite [Go by Example](https://gobyexample.com): **Go by Example** ist eine Einführung in Go anhand kommentierter Beispielprogramme. +2. Arbeiten Sie die Liste der Beispiele nacheinander durch. Folgende Themen werden (mindestens) empfohlen: + - Hello World + - Values + - Variables + - For + - If/Else + - Switch + - Arrays + - Slices + - Maps + - Functions + - Multiple Return Values + - Closures + - Range over Built-in Types + - Pointers + - Structs + - Methods + - Interfaces + - Enums + - Errors + +## 2. Go-Übung: Kommandozeilenprogramm + +**Aufgabenstellung**: Entwickeln Sie ein Kommandozeilenprogramm in Go, mit dem Nutzer:innen ihre persönliche Büchersammlung verwalten können. + +_Tipp: Schauen Sie sich vorher das Demo-Programm "taskmanager" an._ + +#### Arbeitsschritte + +Implementieren Sie ein Programm mit folgenden Funktionen: + +1. **Buch hinzufügen** + ```bash + go run main.go add "Titel" "Autor" + ``` + → Fügt ein neues Buch zur Sammlung hinzu. + +2. **Bücher auflisten** + ```bash + go run main.go list + ``` + → Zeigt alle Bücher mit ID, Titel, Autor und Lesestatus. + +3. **Buch als gelesen markieren** + ```bash + go run main.go read + ``` + → Markiert das Buch mit der angegebenen ID als gelesen. + +4. **Persistenz** + - Die Bücher sollen in einer Datei `books.json` gespeichert und beim Programmstart wieder geladen werden. + - Verwenden Sie dafür das `encoding/json`-Paket und `os.ReadFile` / `os.WriteFile`. + +### Hinweise + +- Verwenden Sie `struct` für die Buch- und Bibliotheksdaten. +- Arbeiten Sie mit `slice` zur Verwaltung der Bücherliste. +- Nutzen Sie Methoden zur Kapselung von Logik (z. B. `Add`, `MarkRead`, `Save`). +- Behandeln Sie Fehler sinnvoll und benutzerfreundlich. +- Strukturieren Sie Ihr Projekt in mindestens zwei Dateien (`main.go`, `book.go`). + +## 3. Go-Übung: Formulardaten empfangen + +**Aufgabenstellung**: Erstellen Sie ein Webserver-Programm in Go, das den HTTP-Endpunkt `/registrierung` bereitstellt. + +- Der Endpunkt nimmt die Formulardaten der Workshop-Anmeldung aus Übungsblatt 04 entgegen und gibt sie als Response zurück. +- Nutzen Sie dazu gerne die zuvor von Ihnen in Übungsblatt 05 definierte SWAGGER-Schnittstelle. +- Es sollen nur `POST`-Request erlaubt sein. Falls eine andere Methode verwendet wurde, soll der Status-Code 405 (Method not allowed) zurückgegeben werden. +- Testen Sie Ihren Endpunkt mit Ihrem HTML-Formular.