React frontend dengan backend Go/Gin/Gorm

 – Beragampengetahuan
11 mins read

React frontend dengan backend Go/Gin/Gorm – Beragampengetahuan

Proyek ReactAndGo adalah untuk membandingkan front-end Aplikasi Halaman Tunggal berbasis React dan back-end Rest berbasis Go dengan front-end Angular dan back-end Spring Boot/Java.

Tujuan dari proyek ini adalah untuk mengirimkan pemberitahuan kepada pengemudi mobil ketika harga gas turun di bawah harga target. Harga gas diimpor dari pemasok melalui pesan MQTT dan disimpan dalam database. Untuk pengembangan, disediakan dua pesan pengujian, yang dikirim ke server Apache Artemis untuk diproses dalam proyek. Server Apache Artemis dapat dijalankan sebagai gambar Docker, perintah untuk mengunduh dan menjalankan gambar dapat ditemukan di file “docker-artemis.sh”. Sebagai database, Postgresql digunakan, yang juga dapat dijalankan sebagai image Docker. Perintah-perintah ini dapat ditemukan di file “docker-postgres.sh”.

Contents

Arsitektur

Arsitektur sistem adalah sebagai berikut:

struktur sistem

Frontend React menggunakan antarmuka Rest yang disediakan oleh framework Gin untuk berkomunikasi dengan backend. Server Perpesanan Apache Artemis digunakan dalam pengembangan untuk menerima dan mengirim kembali pesan uji harga bahan bakar yang diproses menggunakan pustaka Paho-MQTT. Dalam produksi, penyedia mengirimkan pesan MQTT. Framework Gorm digunakan untuk menyimpan data di Postgresql. Tampilan push notification digunakan untuk menampilkan notifikasi dari frontend jika target harga tercapai.

Proyek sumber terbuka yang menggunakan Go memiliki lebih banyak arsitektur berbasis domain, membagi kode untuk setiap domain menjadi paket. Untuk proyek ReactAndGo, arsitektur berbasis domain digabungkan dengan arsitektur berlapis untuk menyusun kode.

pengontrol dasar

BaseController generik diperlukan untuk mengelola perutean dan keamanan aplikasi. Arsitektur dibagi menjadi domain SPBU, domain push notification dan domain pengguna aplikasi. Permintaan istirahat dan penanganan respons ada di lapisannya sendiri, yang mencakup klien Istirahat untuk impor pompa bensin. Lapisan layanan berisi logika, akses basis data, dan fungsi tambahan lainnya. Fungsionalitas independen domain seperti Cron Job, penanganan token Jwt, dan penanganan pesan diimplementasikan dalam paket terpisah dengan peran utilitas.

Notifikasi dari frontend React ke backend Go/Gin/Gorm

Proyek ReactAndGo digunakan untuk menunjukkan cara menampilkan notifikasi dengan permintaan berkala ke backend, dan cara menangani permintaan yang tersisa ke backend di pengontrol dan repositori.

Bereaksi ujung depan

Di ujung depan, pekerja khusus memulai setelah login dan mengelola notifikasi.ini initWebWorker(...) Fungsi LoginModal.tsx memulai pekerja dan memproses token:

  const initWebWorker = async (userResponse: UserResponse) => {
    let result = null;
    if (!globalWebWorkerRefState) {
      const worker = new Worker(new URL('../webpush/dedicated-worker.js', import.meta.url));
      if (!!worker) {
        worker.addEventListener('message', (event: MessageEvent) => {
          //console.log(event.data);
          if (!!event?.data?.Token && event?.data.Token?.length > 10) {
            setGlobalJwtToken(event.data.Token);
          }
        });
        worker.postMessage({ jwtToken: userResponse.Token, newNotificationUrl: `/usernotification/new/${userResponse.Uuid}` } as MsgData);
        setGlobalWebWorkerRefState(worker);
        result = worker;
      }
    } else {
      globalWebWorkerRefState.postMessage({ jwtToken: userResponse.Token, newNotificationUrl: `/usernotification/new/${userResponse.Uuid}` } as MsgData);
      result = globalWebWorkerRefState;
    }
    return result;
  };

Frontend React menggunakan perpustakaan Recoil untuk manajemen status dan memeriksa apakah globalWebWorkerRefState ada.Jika tidak, pekerja masuk dedicated-worker.js Buat dan buat pendengar acara untuk token Jwt. Token Jwt disimpan dalam status Recoil untuk semua permintaan istirahat.Kemudian postMessage(...) Metode pekerja dipanggil untuk memulai permintaan notifikasi.Para pekerja kemudian disimpan di globalWebWorkerRefState Kemudian pekerja kembali.

Worker dikembangkan dalam file dedicated-worker.ts. Memerlukan pekerja sebagai file .js. Untuk mendapatkan bantuan dari Typescript, pekerja mengembangkan di Typescript, yang kemudian menjadi Javascript di Playground TypeScript. Ini menghemat banyak waktu saya.ini refreshToken(...) Fungsi pekerja menyegarkan token Jwt:

interface UserResponse {
  Token?: string
  Message?: string
}

let jwtToken = '';
let tokenIntervalRef: ReturnType<typeof setInterval>;
const refreshToken = (myToken: string) => {
  if (!!tokenIntervalRef) {
    clearInterval(tokenIntervalRef);
  }
  jwtToken = myToken;
  if (!!jwtToken && jwtToken.length > 10) {
    tokenIntervalRef = setInterval(() => {
      const requestOptions = {
        method: 'GET',
        headers: { 'Content-Type': 'application/json', 'Authorization': `Bearer ${jwtToken}` },
      };
      fetch('/appuser/refreshtoken', requestOptions).then(response => response.json() as UserResponse)
        .then(result => {
        if ((!result.Message && !!result.Token && result.Token.length > 10)) {
          //console.log('Token refreshed.');
          jwtToken = result.Token;
          /* eslint-disable-next-line no-restricted-globals */
          self.postMessage(result);
        } else {
          jwtToken = '';
          clearInterval(tokenIntervalRef);
        }
      });
    }, 45000);
  }
}

ini refreshToken(...) Fungsi pertama memeriksa apakah interval token lain telah dimulai dan menghentikannya. Kemudian alokasikan dan periksa tokennya. Jika pemeriksaan berhasil, interval baru akan mulai menyegarkan token setiap 45 detik.ini requestOptions dibuat dengan token Authorization bidang tajuk.Kemudian ambil token baru menggunakan fetch(...) , dan periksa responsnya, atur token, dan posting ke EventListener di LoginModal.tsx.Jika tidak ada token Jwt yang diterima, interval dihentikan, dan jwtToken Setel ke string kosong.

Eventlistener pekerja menerima pesan token dan memprosesnya sebagai berikut:

interface MsgData {
  jwtToken: string;
  newNotificationUrl: string;
}

let notificationIntervalRef: ReturnType<typeof setInterval>;
/* eslint-disable-next-line no-restricted-globals */
self.addEventListener('message', (event: MessageEvent) => {
  const msgData = event.data as MsgData;
  refreshToken(msgData.jwtToken);  
  if (!!notificationIntervalRef) {
    clearInterval(notificationIntervalRef);
  }
  notificationIntervalRef = setInterval(() => {
    if (!jwtToken) {
      clearInterval(notificationIntervalRef);
    }
    const requestOptions = {
      method: 'GET',
      headers: { 'Content-Type': 'application/json', 'Authorization': `Bearer ${jwtToken}` },
    };
    /* eslint-disable-next-line no-restricted-globals */
    self.fetch(msgData.newNotificationUrl, requestOptions).then(result => result.json()).then(resultJson => {
      if (!!resultJson && resultJson?.length > 0) {
        /* eslint-disable-next-line no-restricted-globals */
        self.postMessage(resultJson);
        //Notification
        //console.log(Notification.permission);
        if (Notification.permission === 'granted') { 
          if(resultJson?.length > 0 && resultJson[0]?.Message?.length > 1 && resultJson[0]?.Title?.length > 1) {            
            for(let value of resultJson) {
            new Notification(value?.Title, {body: value?.Message});
            }
          }                
        }
      }
    });
  }, 60000);
});

ini addEventListener(...) pengolahan metode MessageEvent pesan dengan MsgData. ini jwtToken dari MsgData untuk memulai refreshToken(...) Fungsi. Kemudian periksa untuk melihat apakah interval notifikasi telah dimulai, dan jika ya, hentikan. Kemudian buat interval baru untuk memeriksa harga gas kecocokan target baru setiap 60 detik.ini jwtToken dicentang, dan menghentikan interval jika pemeriksaan gagal.Kemudian requestOptions dibuat menggunakan token Jwt Authorization bidang tajuk.Kemudian fetch(...) Digunakan untuk mengambil pembaruan harga gas baru yang cocok. Kemudian periksa JSON yang dihasilkan dan kirimkan kembali ke EventListener di LoginModal.tsx.Dan Notification.permission Pengguna dimintai izin untuk mengirim pemberitahuan, dan granted Menandakan bahwa dia setuju.Periksa data notifikasi dan kirim notifikasi new Notification(...).

belakang

Untuk menangani permintaan front-end, backend Go menggunakan framework Gin. Kerangka kerja Gin menyediakan fungsionalitas yang diperlukan untuk menangani permintaan Istirahat, seperti router, konteks (hal terkait URL), dukungan TLS, dan penanganan JSON. Perutean didefinisikan di basecontroller.go:

func Start(embeddedFiles fs.FS) {
	router := gin.Default()
        ...
	router.GET("/usernotification/new/:useruuid", token.CheckToken, getNewUserNotifications)
        ...
	router.GET("/usernotification/current/:useruuid", token.CheckToken, getCurrentUserNotifications)
	router.StaticFS("/public", http.FS(embeddedFiles))
	router.NoRoute(func(c *gin.Context) { c.Redirect(http.StatusTemporaryRedirect, "/public") })
	absolutePathKeyFile := strings.TrimSpace(os.Getenv("ABSOLUTE_PATH_KEY_FILE"))
	absolutePathCertFile := strings.TrimSpace(os.Getenv("ABSOLUTE_PATH_CERT_FILE"))
	myPort := strings.TrimSpace(os.Getenv("PORT"))
	if len(absolutePathCertFile) < 2 || len(absolutePathKeyFile) < 2 || len(myPort) < 2 {
		router.Run() // listen and serve on 0.0.0.0:3000
	} else {
		log.Fatal(router.RunTLS(":"+myPort, absolutePathCertFile, absolutePathKeyFile))
	}
}

ini Start File yang disematkan diperoleh oleh fungsi /public Direktori yang berisi file frontend statis. Bank:

router.GET("/usernotification/new/:useruuid", token.CheckToken, getNewUserNotifications)

membuat rute /usernotification/new/:useruuid Dan useruuid sebagai parameter.ini CheckToken Pemrosesan fungsi dalam file token.go Jwt Token memeriksa.ini getNewUserNotifications Fungsi di uncontroller.go menangani permintaan.

ini getNewUserNotifications(...) Fungsi:

func getNewUserNotifications(c *gin.Context) {
	userUuid := c.Param("useruuid")
	myNotifications := notification.LoadNotifications(userUuid, true)
	c.JSON(http.StatusOK, mapToUnResponses(myNotifications))
}

...

func mapToUnResponses(myNotifications []unmodel.UserNotification) []unbody.UnResponse {
   var unResponses []unbody.UnResponse
   for _, myNotification := range myNotifications {
      unResponse := unbody.UnResponse{
         Timestamp: myNotification.Timestamp, UserUuid: myNotification.UserUuid, Title: myNotification.Title, 
            Message: myNotification.Message, DataJson: myNotification.DataJson,
      }
      unResponses = append(unResponses, unResponse)
   }
   return unResponses
}

ini getNewUserNotifications(…) Fungsi menggunakan konteks Gin untuk mendapatkan parameter jalur useruuid lalu telepon LoadNotifications(…) Fungsi repositori.Ternyata begitu UserNotifications Dan mapToUnResponses(…) fungsi, yang hanya mengirimkan data yang dibutuhkan oleh front end. Konteks Gin digunakan untuk mengembalikan status HTTP OK dan marshal UserNotifications ke JSON.

Fungsi LoadNotifications(...) Di file unrepo.go, dan gunakan framework Gorm untuk memuat notifikasi dari database:

func LoadNotifications(userUuid string, newNotifications bool) []unmodel.UserNotification {
   var userNotifications []unmodel.UserNotification
   if newNotifications {
     database.DB.Transaction(func(tx *gorm.DB) error {
        tx.Where("user_uuid = ? and notification_send = ?", userUuid, !newNotifications)
           .Order("timestamp desc").Find(&userNotifications)
	for _, userNotification := range userNotifications {
	   userNotification.NotificationSend = true
	   tx.Save(&userNotification)
	}
	return nil
     })
   } else {
      database.DB.Transaction(func(tx *gorm.DB) error {
         tx.Where("user_uuid = ?", userUuid).Order("timestamp desc").Find(&userNotifications)
         var myUserNotifications []unmodel.UserNotification
         for index, userNotification := range userNotifications {
            if index < 10 {
	       myUserNotifications = append(myUserNotifications, userNotification)
	       continue
  	    }
	    tx.Delete(&userNotification)
          }
          userNotifications = myUserNotifications
          return nil
      })
    }
    return userNotifications
}

ini LoadNotifications(...) Fungsi memeriksa apakah hanya pemberitahuan baru yang diminta.Kemudian buat transaksi database, dan buat yang baru UserNotifications File pengguna untuk (notification.go) dipilih, yang terbaru terlebih dahulu.ini send bendera disetel ke true untuk menandainya sebagai tidak lagi baru, dan UserNotifications disimpan ke database. Kemudian tutup transaksi, dan kembalikan notifikasi.

Jika pemberitahuan saat ini diminta, transaksi basis data dibuka, dan UserNotifications pengguna dipilih, yang terbaru diurutkan terlebih dahulu.10 notifikasi pertama pengguna ditambahkan myUserNotification irisan, yang lain dihapus dari database. Kemudian transaksi ditutup dan notifikasi kembali.

Kesimpulannya

Ini adalah frontend React pertama saya, dan saya membagikan pengalaman saya dalam mengembangkan frontend ini. React adalah library yang jauh lebih kecil daripada Angular Framework dan membutuhkan lebih banyak library tambahan seperti Recoil untuk manajemen status. Fungsi seperti interval disertakan dalam pustaka Angular RxJs. React memiliki fitur yang jauh lebih sedikit dan membutuhkan lebih banyak library tambahan untuk mencapai hasil yang sama. Angular lebih cocok untuk kasus penggunaan di mana ujung depan membutuhkan lebih dari fungsionalitas dasar. Keuntungan dari React adalah ujung depannya sederhana. Frontend React yang tumbuh ke ukuran sedang akan membutuhkan lebih banyak pekerjaan desain dan arsitektur untuk menyaingi solusi Angular, dan mungkin membutuhkan lebih banyak upaya selama pengembangan karena desainnya yang kurang beropini.

Kesan saya: React adalah pesawat layang-layang yang harus Anda rakit sendiri. Angular datar di luar kotak.

Backend Go/Gin/Gorm berfungsi dengan baik. Bahasa Go jauh lebih sederhana dan lebih cepat dibaca daripada Java. Go dapat dipelajari dalam waktu yang relatif singkat dan memiliki pengetikan yang ketat serta konsep multithreading yang coba ditambahkan oleh Project Loom ke Java. Kerangka Gin menyediakan fungsionalitas yang diperlukan untuk mengembangkan pengontrol dan dapat dibandingkan dengan kerangka Spring Boot dalam hal fungsionalitas dan kemudahan pengembangan. Framework Gorm menyediakan fungsionalitas yang diperlukan untuk mengembangkan akses database dan mengelola repositori, dan dapat dibandingkan dengan framework Spring Boot dalam hal fungsionalitas dan kemudahan pengembangan.

Nilai jual Go adalah konsumsi memori yang rendah dan startup yang cepat, karena dapat dikompilasi ke binari dan tidak memerlukan mesin virtual. Baik Go dan Java memiliki pengumpulan sampah. Java dapat mengejar Project Graal dalam waktu startup, tetapi sampel sedang hingga besar harus disediakan terlebih dahulu dan konsumsi memori diprofilkan. Keputusan dapat didasarkan pada keterampilan pengembang, jumlah memori yang disimpan, dan masa depan yang diharapkan dari Project Graal.

rencana pengembangan website



metode pengembangan website

jelaskan beberapa rencana untuk pengembangan website, proses pengembangan website, kekuatan dan kelemahan bisnis pengembangan website
, jasa pengembangan website, tahap pengembangan website, biaya pengembangan website

#React #frontend #dengan #backend #GoGinGorm

Tinggalkan Balasan

Alamat email Anda tidak akan dipublikasikan. Ruas yang wajib ditandai *