Menu

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

$ 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
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



Download Project Here

Daftar Pustaka

  • go.dev
  • wikipedia.org
  • novalagung.com
  • stackoverflow.com