[玩转GoLang] 5分钟整合Gin / Gorm框架入门

方法 / 步骤

一: Gin框架

1.1 : 环境 & 项目配置

1, GoLand创建项目

  • 创建main.go
bash 复制代码
package main

import (
    "github.com/gin-gonic/gin"
)

func main() {
    r := gin.Default()

    r.GET("/", func(c *gin.Context) {
        c.JSON(200, gin.H{
            "message": "Hello, Gin!",
        })
    })

    r.Run(":8080") // 启动服务,监听 8080 端口
}
  • 创建go.mod文件

2, 初始化Gin项目

bash 复制代码
go mod tidy
go get -u github.com/gin-gonic/gin
# 或者在go.mod 文件中添加下面依赖
require github.com/gin-gonic/gin v1.9.0

3, 编译配置

bash 复制代码
# 更改输出目录为 xxxx/target

# 工具实参 去除编译相关
-ldflags="-s -w"

1.2 路由 & 出入参

go 复制代码
// 基本路由
r := gin.Default()
r.GET("/ping", func(c *gin.Context) {
    c.JSON(200, gin.H{"message": "pong"})
})

// 路由分组 (getUsers)
api := r.Group("/api")
{
    api.GET("/users", getUsers)
    api.POST("/users", createUser)
}




r.Run(":8080")


// 绑定入参
type User struct {
    Name string `json:"name"`
    Age  int    `json:"age"`
}

r.POST("/user", func(c *gin.Context){
    var u User
    if err := c.ShouldBindJSON(&u); err != nil {
        c.JSON(400, gin.H{"error": err.Error()})
        return
    }
    c.JSON(200, gin.H{"status": "ok", "user": u})
})
// 获取 URL 参数
r.GET("/user/:id", func(c *gin.Context){
    id := c.Param("id")
    c.JSON(200, gin.H{"id": id})
})

Gin Context

Gin 的 Context 特性(相比 Java 更轻量)

  • Gin 的 Context 集成了请求、响应、JSON、参数、Header 等
  • 无需额外注入 HttpServletRequest / Response
go 复制代码
r.GET("/info", func(c *gin.Context){
    path := c.Request.URL.Path
    header := c.GetHeader("User-Agent")
    c.JSON(200, gin.H{"path": path, "ua": header})
})

1.3 Gin + Go 并发入门(相比 Java 线程更轻量)

  • Go 原生 goroutine + Gin Context 可以轻松实现并发处理
  • 对比 Java 线程,goroutine 占用资源极少
go 复制代码
r.GET("/async", func(c *gin.Context){
	// 创建协程function
    go func(ctx *gin.Context){
        time.Sleep(2 * time.Second)
        fmt.Println("Async processing done")
    }(c.Copy()) // 必须使用 Copy() 避免 Context 并发问题

    c.JSON(200, gin.H{"status": "processing"})
})

通过上面可以看出我们的端口号都是在代码里面写死的8080, 实际在生产中这么写死很不优雅的,所以下面就用另外一种优雅的方式来实现:

1.4 环境变量管理:godotenv

  • go.mod文件中 添加相关依赖
go 复制代码
require (
	github.com/gin-gonic/gin v1.10.1
	// godotenv环境变量依赖
	github.com/joho/godotenv v1.5.1
)
  • .env 文件内容
bash 复制代码
KEY=value
DB_USER=root
DB_PASS=123456
PORT=9999
  • 更改main.go中的 端口号使用配置里面进行加载
go 复制代码
package main

import (
	"fmt"
	"github.com/gin-gonic/gin"
	"github.com/joho/godotenv"
	"log"
	"os"
	"time"
)

type Users struct {
	Name string `json:"name"`
	Age  int    `json:"age"`
}

func main() {

	// 1. 使用godotenv加载 .env 文件 (如果不配置gin的默认端口号是8080)
	err := godotenv.Load()
	if err != nil {
		log.Println("No .env file found, using system environment variables")
	}
	r := gin.Default()
	port := os.Getenv("PORT")
	r.Run(":" + port)

	r.GET("/", func(c *gin.Context) {
		c.JSON(200, gin.H{
			"message": "Hello, Gin!",
		})
	})

	api := r.Group("/api")
	{
		api.GET("/users", getUsers)
		api.POST("/users", createUser)
	}

	// Gin 并发处理入门
	r.GET("/async", func(c *gin.Context) {
		go func(ctx *gin.Context) {
			time.Sleep(2 * time.Second)
			fmt.Println("Async processing done")
		}(c.Copy()) // 必须使用 Copy() 避免 Context 并发问题

		c.JSON(200, gin.H{"status": "processing"})
	})
	// 启动服务,监听 8080 端口
	//r.Run(":8080")
}

// 该function没有返回值,gin框架返回的json使用context进行包装返回
func createUser(context *gin.Context) {
	fmt.Println("this is createUser")
	newUser := Users{Name: "alice", Age: 12}
	//todo 进行创建用户的业务处理
	context.JSON(200, gin.H{"success": true, "data": newUser})
}

func getUsers(context *gin.Context) {
	newUser := Users{Name: "alice", Age: 12}
	context.JSON(200, gin.H{"success": true, "data": newUser})
	fmt.Println("this is getUsers")
}

二: GORM框架集成

GORM介绍

复制代码
•	GitHub: https://github.com/go-gorm/gorm
•	特点:
•	功能全:CRUD、事务、关联、钩子、分页、软删除
•	链式 API,支持自定义 SQL
•	支持 MySQL、PostgreSQL、SQLite、SQL Server 等
•	适用场景: 企业级项目、快速开发、需要自动 CRUD
•	用户量: GitHub Star ~33k+,社区活跃,文档丰富

相对于其他ORM框架

1️⃣ 前置条件 & 项目结构设计

复制代码
•	已安装 Go(推荐 Go 1.20+)
•	已安装 MySQL 或 SQLite(方便本地测试)
•	已安装 GoLand 或 VSCode(任选)
bash 复制代码
gin-gorm-demo/
├── main.go                # 程序入口
├── config/                # 配置文件
│   └── config.go
├── model/                 # 数据模型(类似 entity)
│   └── user.go
├── dao/                   # 数据访问层(类似 mapper/repository)
│   └── user_dao.go
├── service/               # 业务逻辑层
│   └── user_service.go
├── router/                # 路由配置
│   └── router.go
├── handler/               # 控制器层(类似 controller)
│   └── user_handler.go
├── .env                   # 环境配置
└── go.mod
  • 初始化项目
bash 复制代码
# 新建目录
mkdir gin-gorm-demo && cd gin-gorm-demo

# 初始化 Go 模块
go mod init gin-gorm-demo

# 安装依赖
go get -u github.com/gin-gonic/gin
go get -u gorm.io/gorm
go get -u gorm.io/driver/mysql

# 可选:本地快速调试
go get -u gorm.io/driver/sqlite   
  • MySQL 初始化SQL
sql 复制代码
-- 初始化表
CREATE TABLE `users`
(
    `id`    BIGINT UNSIGNED AUTO_INCREMENT,
    `name`  VARCHAR(100),
    `email` VARCHAR(255),
    PRIMARY KEY (`id`),
    UNIQUE INDEX `idx_users_email` (`email`)
);

2️⃣ .env 文件

(用于本地调试和生产环境切换,借助 godotenv 读取)

bash 复制代码
APP_PORT=8080
DB_DRIVER=mysql
DB_DSN=root:password@tcp(127.0.0.1:3306)/testdb?charset=utf8mb4&parseTime=True&loc=Local

3️⃣ config/config.go

go 复制代码
package config

import (
	"log"
	"os"

	"github.com/joho/godotenv"
)

type Config struct {
	AppPort string
	DBDriver string
	DBDsn    string
}

var Cfg Config

func InitConfig() {
	_ = godotenv.Load() // 读取 .env 文件

	Cfg = Config{
		AppPort: getEnv("APP_PORT", "8080"),
		DBDriver: getEnv("DB_DRIVER", "sqlite"),
		DBDsn:    getEnv("DB_DSN", "test.db"),
	}
}

func getEnv(key, defaultVal string) string {
	if value, exists := os.LookupEnv(key); exists {
		return value
	}
	return defaultVal
}

4️⃣ model/user.go

go 复制代码
package model

type User struct {
	ID    uint   `gorm:"primaryKey"`
	Name  string `gorm:"size:100"`
	Email string `gorm:"uniqueIndex"`
}

5️⃣ dao/user_dao.go

go 复制代码
package dao

import (
	"gin-gorm-demo/model"

	"gorm.io/gorm"
)

type UserDao struct {
	DB *gorm.DB
}

func NewUserDao(db *gorm.DB) *UserDao {
	return &UserDao{DB: db}
}

func (d *UserDao) Create(user *model.User) error {
	return d.DB.Create(user).Error
}

func (d *UserDao) FindAll() ([]model.User, error) {
	var users []model.User
	err := d.DB.Find(&users).Error
	return users, err
}

func (d *UserDao) FindByID(id string) (*model.User, error) {
	var user model.User
	err := d.DB.First(&user, id).Error
	return &user, err
}

6️⃣ service/user_service.go

go 复制代码
package service

import (
	"gin-gorm-demo/dao"
	"gin-gorm-demo/model"
)

type UserService struct {
	UserDao *dao.UserDao
}

func NewUserService(userDao *dao.UserDao) *UserService {
	return &UserService{UserDao: userDao}
}

func (s *UserService) CreateUser(user *model.User) error {
	return s.UserDao.Create(user)
}

func (s *UserService) GetUsers() ([]model.User, error) {
	return s.UserDao.FindAll()
}

func (s *UserService) GetUserByID(id string) (*model.User, error) {
	return s.UserDao.FindByID(id)
}

7️⃣ handler/user_handler.go

go 复制代码
package handler

import (
	"gin-gorm-demo/model"
	"gin-gorm-demo/service"
	"net/http"

	"github.com/gin-gonic/gin"
)

type UserHandler struct {
	UserService *service.UserService
}

func NewUserHandler(userService *service.UserService) *UserHandler {
	return &UserHandler{UserService: userService}
}

func (h *UserHandler) CreateUser(c *gin.Context) {
	var user model.User
	if err := c.ShouldBindJSON(&user); err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
		return
	}
	if err := h.UserService.CreateUser(&user); err != nil {
		c.JSON(http.StatusInternalServerError, gin.H{"error": "保存失败"})
		return
	}
	c.JSON(http.StatusOK, user)
}

func (h *UserHandler) GetUsers(c *gin.Context) {
	users, err := h.UserService.GetUsers()
	if err != nil {
		c.JSON(http.StatusInternalServerError, gin.H{"error": "查询失败"})
		return
	}
	c.JSON(http.StatusOK, users)
}

func (h *UserHandler) GetUserByID(c *gin.Context) {
	id := c.Param("id")
	user, err := h.UserService.GetUserByID(id)
	if err != nil {
		c.JSON(http.StatusNotFound, gin.H{"error": "用户不存在"})
		return
	}
	c.JSON(http.StatusOK, user)
}

8️⃣ router/router.go

go 复制代码
package router

import (
	"gin-gorm-demo/handler"

	"github.com/gin-gonic/gin"
)

func SetupRouter(userHandler *handler.UserHandler) *gin.Engine {
	r := gin.Default()

	r.POST("/users", userHandler.CreateUser)
	r.GET("/users", userHandler.GetUsers)
	r.GET("/users/:id", userHandler.GetUserByID)

	return r
}

9️⃣ main.go

go 复制代码
package main

import (
	"fmt"
	"gin-gorm-demo/config"
	"gin-gorm-demo/dao"
	"gin-gorm-demo/handler"
	"gin-gorm-demo/model"
	"gin-gorm-demo/router"
	"gin-gorm-demo/service"
	"log"

	"gorm.io/driver/mysql"
	"gorm.io/driver/sqlite"
	"gorm.io/gorm"
)

func initDB() *gorm.DB {
	var db *gorm.DB
	var err error

	if config.Cfg.DBDriver == "mysql" {
		db, err = gorm.Open(mysql.Open(config.Cfg.DBDsn), &gorm.Config{})
	} else {
		db, err = gorm.Open(sqlite.Open(config.Cfg.DBDsn), &gorm.Config{})
	}
	if err != nil {
		log.Fatal("数据库连接失败:", err)
	}

	// 自动建表
	db.AutoMigrate(&model.User{})
	return db
}

func main() {
	// 初始化配置
	config.InitConfig()

	// 初始化数据库
	db := initDB()

	// 初始化分层对象
	userDao := dao.NewUserDao(db)
	userService := service.NewUserService(userDao)
	userHandler := handler.NewUserHandler(userService)

	// 路由
	r := router.SetupRouter(userHandler)

	// 启动服务
	addr := fmt.Sprintf(":%s", config.Cfg.AppPort)
	r.Run(addr)
}

打包运行

相关源码链接

📚 参考资料 & 致谢

相关推荐
锐策3 小时前
Lua 核心知识点详解
开发语言·lua
kyle~3 小时前
C/C++---动态内存管理(new delete)
c语言·开发语言·c++
落日沉溺于海4 小时前
React From表单使用Formik和yup进行校验
开发语言·前端·javascript
鲸屿1954 小时前
python之socket网络编程
开发语言·网络·python
没有梦想的咸鱼185-1037-16635 小时前
基于R语言机器学习方法在生态经济学领域中的实践技术应用
开发语言·机器学习·数据分析·r语言
向上的车轮5 小时前
基于go语言的云原生TodoList Demo 项目,验证云原生核心特性
开发语言·云原生·golang
The Chosen One9855 小时前
C++ : AVL树-详解
开发语言·c++
PH_modest5 小时前
【Qt跬步积累】—— 初识Qt
开发语言·qt
怀旧,6 小时前
【C++】18. 红⿊树实现
开发语言·c++