GoLang 后端入门

简单 (非技术框架) 实现的 Go 后端

~~众所周知,~~后端的开发一般是面向接口的开发,也可以说是 CRUD 工程师,本文章将使用 Go 描述从数据库读出数据,然后返回 JSON 数据

数据库

例子为从 MySQL 数据库的分类表,读出分类的名称与 ID,数据库的结构如下

DROP TABLE IF EXISTS categories ;
CREATE TABLE categories (
    id INT AUTO_INCREMENT PRIMARY KEY,
    name VARCHAR(255) NOT NULL,
    description VARCHAR(255)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;

项目结构

本例子的项目结构如下

project/
├── database/       // 数据库包
│   └── database.go // 数据库连接
├── handler/        // 处理器包
│   └── category.go // 分类相关接口
├── model/          // 数据模型包
│   ├── category.go // 分类表模型
│   └── response.go // 响应数据模型
├── router/         // 路由包
│   └── router.go   // 路由配置
├── utils           // 工具包
│   └── response.go // 统一响应
├── main.go         // 程序入口

接下来将分目录说明

database

该包是管理与数据库的连接

// database.go
package database

import (
    "database/sql"
    "fmt"
    "log"

    _ "github.com/go-sql-driver/mysql"
)

var DB *sql.DB

func InitDB() {
    var err error

    dsn := "username:password@tcp(address:3306)/name?charset=utf8"
    DB, err = sql.Open("mysql", dsn)
    if err != nil {
        log.Fatalf("Failed to open database: %v", err)
    }

    // Test Connect
    err = DB.Ping()
    if err != nil {
        log.Fatalf("Failed to ping database: %v", err)
    }

    fmt.Println("Successfully connected Database!")
}

handler

这个包是对于特定处理的逻辑 (类似于三层架构的 service),其中数据库处理还可以分层 (类似于 Mapper),但这只是一个简单的示例,就酱子啦~

// category.go
package handler

import (
    "net/http"
    "project/database"
    "project/model"
    "project/utils"
)

func GetCategories(w http.ResponseWriter, r *http.Request) {
    // Select Database
    rows, err := database.DB.Query("select id,name from categories")
    if err != nil {
        http.Error(w, "Failed to query Categories", http.StatusInternalServerError)
        return
    }
    defer rows.Close()

    // analyze data
    var categories []model.Category
    for rows.Next() {
        var category model.Category
        err = rows.Scan(&category.Id, &category.Name)
        if err != nil {
            utils.JSONResponse(w, http.StatusInternalServerError, "Failed to analyze Categories", nil)
            //http.Error(w, "Failed to analyze Categories", http.StatusInternalServerError)
            return
        }
        categories = append(categories, category)
    }

    // return JSON
    //w.Header().Set("Content-Type", "application/json")
    //json.NewEncoder(w).Encode(categories)
    utils.JSONResponse(w, http.StatusOK, "", categories)
}

注释掉的内容为不适用统一响应接口,直接返回 JSON 的情况

model

这里的数据模型一般可以分为三个,从前端接收到的、数据库的以及返回给前端的,由于这只是一个简单的示例,所以我并没有细分

// category.go
package model

type Category struct {
    Id          int    `json:"id"`
    Name        string `json:"name"`
    Description string `json:"description"`
}

响应的数据模型为

package model

type Response struct {
    Code int         `json:"code"`
    Msg  string      `json:"msf"`
    Data interface{} `json:"data"`
}

router

该包管理路由,即访问了什么路径要指定相应的处理逻辑 (类似于三层架构的 controller)

// router.go
package router

import (
    "github.com/gorilla/mux"
    "project/handler"
)

func InitRouter() *mux.Router {
    router := mux.NewRouter()
    router.HandleFunc("/categories", handler.GetCategories).Methods("GET")
    return router
}

utils

该包为工具类,用于定义可以通用的工具

// response.go
package utils

import (
    "encoding/json"
    "log"
    "net/http"
    "project/model"
)

func JSONResponse(w http.ResponseWriter, code int, message string, data interface{}) {
    w.Header().Set("Content-Type", "application/json; charset=utf-8")
    w.WriteHeader(http.StatusOK)
    err := json.NewEncoder(w).Encode(model.Response{Code: code, Msg: message, Data: data})
    if err != nil {
        log.Fatal(err)
        return
    }
}

main

程序的入口

// main.go
package main

import (
    "log"
    "net/http"
    "project/database"
    "project/router"
)

func main() {
    // init Database
    database.InitDB()

    // Init Router
    r := router.InitRouter()

    // start
    log.Println("Starting server on port 8848")
    log.Fatal(http.ListenAndServe(":8848", r))
}

运行 go run main.go,程序将监听 8848 端口

This post is licensed under CC BY-NC-SA 4.0 by the author.
最后更新于 2025-01-28 21:30 +0900