Membuat Crud Di Golang Dengan Konsep MVC
Bahasa Pemrgaman Go (Atau Biasa Disebut Golang), merupakan sebuah bahasa pemrograman open source yang dikembangkan oleh google (2009). Dan pemrograman Golang biasa digunakan untuk pengembangan Web dan jaringan.
Konsep MVC (Model,View,Controller), sebuah cara untuk memisahkan data, tampilan dan proses.
1. Buat Folder Project
Konsep MVC (Model,View,Controller), sebuah cara untuk memisahkan data, tampilan dan proses.
1. Buat Folder Project
$ mkdir mvcCrud
2. Buat Struktur Folder MVC
mvcCrud |_app/ |_db/ |_http/ |_template/
3. Membuat Model CRUD
Buat Folder models Di Folder db & Folder Person di models dan buat file Person.go di folder Person
$ mkdir models && cd models && mkdir Person && touch Person.go
Person.go
package Person import ( "fmt" "crudMvc/db/conn" "html/template" ) type Orang struct { Id int Nama string Alamat string } func GetallData() []Orang { db,err := conn.Connect() if err != nil { fmt.Println("Error Koneksi", err) return nil } rows,errquer := db.Query("SELECT * FROM person") if errquer != nil { fmt.Println("Query Gagal",errquer) return nil } defer rows.Close() defer db.Close() var results []Orang for rows.Next(){ var each Orang var erreach = rows.Scan(&each.Id,&each.Nama,&each.Alamat) if erreach != nil{ fmt.Println(erreach.Error()) return nil } results = append(results,each) } return results } func InsertData(nama string, alamat string) bool { db,err := conn.Connect() if err != nil { fmt.Println("Gagal Koneksi ===>",err) return false } getNama := template.HTMLEscapeString(nama) getAlamat := template.HTMLEscapeString(alamat) rows,errquer := db.Exec("INSERT INTO person (nama,alamat) VALUES(?,?)",getNama,getAlamat) defer db.Close() if errquer != nil{ fmt.Println("Gagal Insert",errquer) return false }else{ fmt.Println(rows) return true } } func CekData(id string) bool { db,err := conn.Connect() if err != nil { fmt.Println("Error Koneksi", err) return false } removeChar := template.HTMLEscapeString(id) fmt.Println(removeChar) var result Orang defer db.Close() rows := db.QueryRow("SELECT * FROM person WHERE id=?",removeChar).Scan(&result.Id,&result.Nama,&result.Alamat) if rows != nil{ fmt.Println("Failed Query",rows) return false }else{ return true } } func DeleteData(id string) bool { db,err := conn.Connect() if err != nil { fmt.Println("Error Koneksi", err) return false } removeChar := template.HTMLEscapeString(id) fmt.Println(removeChar) defer db.Close() result, err := db.Exec("DELETE FROM person WHERE id = ?", removeChar) rowsAffected, err := result.RowsAffected() if err != nil { fmt.Println("Failed Query :",err) return false }else{ fmt.Println("Success Query :",rowsAffected) return true } } func UpdateData(id string,nama string,alamat string) bool { db,err := conn.Connect() if err != nil { fmt.Println("Error Koneksi", err) return false } id_s := template.HTMLEscapeString(id) nama_s := template.HTMLEscapeString(nama) alamat_s := template.HTMLEscapeString(alamat) defer db.Close() result, err := db.Exec("UPDATE person SET nama = ?, alamat = ? WHERE id = ?", nama_s,alamat_s,id_s) rowsAffected, err := result.RowsAffected() if err != nil { fmt.Println("Failed Query :",err) return false }else{ fmt.Println("Success Query :",rowsAffected) return true } }
3. Membuat Connection Ke Mysql
# Disini Saya Menggunakan Database Mysql
* Kembali Ke Direktori awal project tadi mvcCrud
$ go get github.com/go-sql-driver/mysql
* Setelah menginstal libbary nya Buat Folder conn di db dan file conn.go di dalam folder conn
conn.go
package conn import ( "database/sql" _ "github.com/go-sql-driver/mysql" ) func Connect() (*sql.DB, error){ db, err := sql.Open("mysql", "root:@/mvc_crud") if err != nil { panic(err) return nil,err } return db,nil }
4. Membuat Database dengan nama mvc_crud
* Buat table person
+--------+-------------+------+-----+---------+----------------+ | Field | Type | Null | Key | Default | Extra | +--------+-------------+------+-----+---------+----------------+ | id | int(11) | NO | PRI | NULL | auto_increment | | nama | varchar(50) | NO | | NULL | | | alamat | text | NO | | NULL | | +--------+-------------+------+-----+---------+----------------+
5. Pada Folder template Buat file index.html
index.html
<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <meta name="viewport" content="width=device-width, initial-scale=1"> <title>{{.title}}</title> </head> <style> @import url('https://fonts.googleapis.com/css2?family=Montserrat:wght@400;600;800&display=swap'); body { background-color: #ccd7e8; } table { border-collapse: collapse; background-color: white; overflow: hidden; width: 600px; border-radius: 10px; } th, td { font-family:'Motnserrat',sans-serif; text-align: left; font-size: 12px; padding: 10px; } th { background-color: #7691ab; color: white; } .btn-hapus, .btn-edit { padding: 10px 20px; background-color: #4CAF50; /* Hijau untuk Hapus */ color: white; border: none; border-radius: 4px; cursor: pointer; } .btn-save, .btn-cancel { padding: 10px 20px; background-color: #4CAF50; /* Hijau untuk Hapus */ color: white; border: none; border-radius: 4px; cursor: pointer; } .btn-edit { background-color: #2196F3; /* Biru untuk Edit */ } .btn-cancel{ background-color:#2196F3 ; } .modal { display: none; /* Hidden by default */ position: fixed; /* Stay in place */ z-index: 1; /* Sit on top */ left: 0; top: 0; width: 100%; /* Full width */ height: 100%; /* Full height */ overflow: auto; /* Enable scroll if needed */ background-color: rgba(0,0,0,0.4); /* Black w/ opacity */ } .modal-content { background-color: #fefefe; margin: 15% auto; /* 15% from the top and centered */ padding: 20px; border: 1px solid #888; width: 50%; } .close { position: absolute; top: 0; right: 25px; font-size: 35px; font-weight: bold; color: #000; cursor: pointer; } </style> <body> <table style="margin-left:25%;"> <tr> <form method="POST"> <td><input autocomplete="off" required placeholder="Nama" style="border-radius: 5px; height:40px;" type="text" name="nama"></td> <td><input autocomplete="off" required placeholder="Alamat" style="border-radius: 5px; height:40px;" type="text" name="alamat"></td> <td> <button type="submit" class="btn-edit">Tambah Data</button> </td> </form> </tr> </table> <br> <table style="margin-left: 25%;"> <tr> <th>Id</th> <th>Nama</th> <th>Alamat</th> <th>Action</th> </tr> {{range .result}} <tr> <td>{{.Id}}</td> <td>{{.Nama}}</td> <td>{{.Alamat}}</td> <td> <button class="btn-hapus" idData="{{.Id}}" namaData="{{.Nama}}" onclick="HapusRequest('{{.Id}}')">Hapus</button> <button class="btn-edit" type="submit" onclick="EditRequest('{{.Id}}')" id="btnEdit{{.Id}}" idData="{{.Id}}" alamatData="{{.Alamat}}" namaData="{{.Nama}}"> Edit</button> </td> </tr> {{end}} </table> <br> <table style="margin-left:25%; display: none;" id="showEdit"> <tr> <form id="formUpdate" method="POST"> <td><input autocomplete="off" placeholder="nama" id="inputNama" style="border-radius: 5px; height:40px;" type="text" name="nama"></td> <td><input autocomplete="off" placeholder="alamat" id="inputAlamat" style="border-radius: 5px; height:40px;" type="text" name="alamat"> <input type="hidden" name="id" id="inputId"></td> <td> <button class="btn-save" id="saveUpdate">Save</button> <button class="btn-cancel" type="button" id="cancelBtn" style="background-color: red;">Cancel</button> </td> </form> </tr> </table> <script> const HapusRequest = async(id) => { const url = `http://${window.location.host}/delete/${id}` const resp = await fetch(url) if (resp.status == 200) { window.location.href = `http://${window.location.host}` }else{ window.location.href = `http://${window.location.host}` } } const EditRequest = async(id) => { const showEdit = document.getElementById(`btnEdit${id}`) showEdit.addEventListener('click',() => { console.log(22) const tampilEdit = document.getElementById("showEdit") tampilEdit.style.display = "block" showEdit.style.display = "none" const namaInput = document.getElementById("inputNama") const alamatInput = document.getElementById("inputAlamat") const idInput = document.getElementById("inputId") namaInput.setAttribute("value",showEdit.getAttribute("namaData")) alamatInput.setAttribute("value",showEdit.getAttribute("alamatData")) idInput.setAttribute("value",showEdit.getAttribute("idData")) const btnCancel = document.getElementById("cancelBtn") btnCancel.addEventListener("click",()=>{ tampilEdit.style.display = "none" showEdit.style.display="block" }) const saveBtn = document.getElementById("saveUpdate") let forms = document.getElementById('formUpdate') forms.action = "/update/" saveBtn.addEventListener("onclick",()=>{ forms.submit() }) }) } </script> </body> </html>
6. Membuat Controller
- Buat Folder DeleteControl lalu DeleteControl.go buat di dalam folder DeleteControl
- Buat Folder ReadControl lalu ReadControl.go buat di dalam folder ReadControl
- Buat Folder UpdateControl lalu UpdateControl.go buat di dalam folder UpdateControl
* Buat Ini Di Dalam http/controller/
DeleteControl.go
DeleteControl.go
package DeleteControl import( "fmt" "net/http" "crudMvc/db/models/Person" "encoding/json" ) type Message struct{ Pesan string Status int } func ControllerDelete(w http.ResponseWriter, r *http.Request){ if r.Method == "GET"{ var resp Message params := r.URL.Path[8:] if len(params) == 0 { http.Redirect(w,r,"/",http.StatusSeeOther) }else{ result := Person.CekData(params) if result{ resultDelete := Person.DeleteData(params) fmt.Println(resultDelete) resp.Status = 200 resp.Pesan = "Sukses Hapus" w.Header().Set("Content-Type", "application/json") w.WriteHeader(http.StatusOK) respJson,_ := json.Marshal(resp) w.Write(respJson) }else{ resp.Status = 400 resp.Pesan = "Bad Request" w.Header().Set("Content-Type", "application/json") w.WriteHeader(http.StatusBadRequest) respJson,_ := json.Marshal(resp) w.Write(respJson) } } }else{ } }
ReadControl.go
package ReadControl import ( "fmt" "net/http" "html/template" "crudMvc/db/models/Person" ) type D map[string]interface{} func ControllerRead(w http.ResponseWriter,r *http.Request){ fmt.Println(r.Method) if r.Method == "GET"{ var data = D { "title":"Halaman Read", "result":Person.GetallData(), } t,err := template.ParseFiles("template/index.html") if err!= nil { fmt.Println("Ada Error =>",err)} t.ExecuteTemplate(w,"index.html",data) }else if r.Method == "POST"{ result := Person.InsertData(r.FormValue("nama"),r.FormValue("alamat")) if result{ fmt.Println(result) http.Redirect(w,r,"/",http.StatusSeeOther) } }else{ } }
UpdateControl.go
package UpdateControl import( "fmt" "net/http" "crudMvc/db/models/Person" ) func UpdateController(w http.ResponseWriter, r *http.Request){ fmt.Println("update") fmt.Println(r.Method) if r.Method == "POST"{ result := Person.UpdateData(r.FormValue("id"),r.FormValue("nama"),r.FormValue("alamat")) if result { http.Redirect(w,r,"/",http.StatusSeeOther) }else{ http.Redirect(w,r,"/",http.StatusSeeOther) } }else{ http.Redirect(w,r,"/",http.StatusSeeOther) } }
7. Membuat Routing
*buat file main.go di dalam folder app/
main.go
package main import ( "fmt" "net/http" "log" "crudMvc/http/controller/ReadControl" "crudMvc/http/controller/DeleteControl" "crudMvc/http/controller/UpdateControl" ) func main(){ fmt.Println("Listening Port 8000") http.HandleFunc("/",ReadControl.ControllerRead) http.HandleFunc("/delete/",DeleteControl.ControllerDelete) http.HandleFunc("/update/",UpdateControl.UpdateController) log.Fatal(http.ListenAndServe(":8000",nil)) }
*** Pada File go.mod pastikan module crudMvc***
8. Running Project
$ go run app/main.go
Hasil Dari Project Di Atas
Create & Read
Update
Delete
Penjelasan Singkat
- Di sini saya memisahkan folder proses, tampilan dan data
- folder proses saya taro di dalm folder http/controller
- tampilan saya hanya menggunakan satu, karena saya menggunakan javascript untuk beberapa menghandle request. dan saya simpan di folder template
- data/model saya simpan pada folder db
- folder app/ digunakan untuk mengatur endpoint atau routing dan file utama yang akan di jalankan
- go.dev
- wikipedia.org
- novalagung.com
- stackoverflow.com