用go开发企业级项目,给出详细的代码实现

下面以一个企业级用户管理微服务为例,展示 Go 语言开发企业级项目的核心代码实现。该服务包含用户 CRUD、认证授权、日志、配置管理、数据库交互等企业级项目常见模块,采用分层架构(API 层、服务层、数据层)设计。

项目结构(企业级标准分层)

user-service/
├── cmd/                  # 程序入口
│   └── server/
│       └── main.go       # 主函数
├── internal/             # 内部代码(不对外暴露)
│   ├── api/              # API层(处理HTTP请求)
│   │   ├── handler.go    # 处理器
│   │   └── middleware.go # 中间件(认证、日志等)
│   ├── config/           # 配置管理
│   │   └── config.go
│   ├── domain/           # 领域模型
│   │   └── user.go
│   ├── repository/       # 数据访问层
│   │   └── user_repo.go
│   └── service/          # 业务逻辑层
│       └── user_service.go
├── pkg/                  # 公共包(可复用)
│   ├── logger/           # 日志工具
│   ├── db/               # 数据库连接
│   └── auth/             # 认证工具
├── configs/              # 配置文件
│   └── config.yaml
└── go.mod

核心代码实现

1. 领域模型(internal/domain/user.go)

定义核心业务实体,与数据库表结构对应。

package domain

import "time"

// User 用户领域模型
type User struct {
    ID        uint64    `json:"id"`         // 用户ID
    Username  string    `json:"username"`   // 用户名(唯一)
    Password  string    `json:"-"`          // 密码(返回时忽略)
    Email     string    `json:"email"`      // 邮箱
    Status    int       `json:"status"`     // 状态(1-正常,0-禁用)
    CreatedAt time.Time `json:"created_at"` // 创建时间
    UpdatedAt time.Time `json:"updated_at"` // 更新时间
}

// UserRepository 数据访问接口(依赖倒置,解耦服务层与数据库)
type UserRepository interface {
    Create(user *User) error
    GetByID(id uint64) (*User, error)
    GetByUsername(username string) (*User, error)
    Update(user *User) error
    Delete(id uint64) error
}
2. 配置管理(internal/config/config.go)

企业级项目需支持多环境配置(开发 / 测试 / 生产),这里用viper解析 yaml 配置。

package config

import (
    "fmt"
    "github.com/spf13/viper"
)

// Config 应用配置
type Config struct {
    Server   ServerConfig   `mapstructure:"server"`
    Database DatabaseConfig `mapstructure:"database"`
    JWT      JWTConfig      `mapstructure:"jwt"`
}

// ServerConfig 服务配置
type ServerConfig struct {
    Port int    `mapstructure:"port"`
    Env  string `mapstructure:"env"` // 环境:dev/test/prod
}

// DatabaseConfig 数据库配置
type DatabaseConfig struct {
    DSN      string `mapstructure:"dsn"`       // 连接串
    MaxOpen  int    `mapstructure:"max_open"`  // 最大连接数
    MaxIdle  int    `mapstructure:"max_idle"`  // 最大空闲连接
    Timeout  int    `mapstructure:"timeout"`   // 超时时间(秒)
}

// JWTConfig 认证配置
type JWTConfig struct {
    Secret string `mapstructure:"secret"` // 密钥
    Expire int    `mapstructure:"expire"` // 过期时间(小时)
}

// Load 加载配置文件
func Load(path string) (*Config, error) {
    viper.SetConfigFile(path)
    viper.SetConfigType("yaml")
    if err := viper.ReadInConfig(); err != nil {
        return nil, fmt.Errorf("读取配置失败: %v", err)
    }

    var cfg Config
    if err := viper.Unmarshal(&cfg); err != nil {
        return nil, fmt.Errorf("解析配置失败: %v", err)
    }
    return &cfg, nil
}
3. 数据库连接(pkg/db/mysql.go)

企业级项目需管理数据库连接池,避免频繁创建连接。

package db

import (
    "database/sql"
    "fmt"
    "time"
    _ "github.com/go-sql-driver/mysql" // MySQL驱动
    "user-service/internal/config"
)

// InitMySQL 初始化MySQL连接池
func InitMySQL(cfg config.DatabaseConfig) (*sql.DB, error) {
    db, err := sql.Open("mysql", cfg.DSN)
    if err != nil {
        return nil, fmt.Errorf("连接数据库失败: %v", err)
    }

    // 配置连接池
    db.SetMaxOpenConns(cfg.MaxOpen)
    db.SetMaxIdleConns(cfg.MaxIdle)
    db.SetConnMaxLifetime(time.Duration(cfg.Timeout) * time.Second)

    // 测试连接
    if err := db.Ping(); err != nil {
        return nil, fmt.Errorf("测试连接失败: %v", err)
    }
    return db, nil
}
4. 数据访问层(internal/repository/user_repo.go)

实现数据库交互,依赖sql.DB,遵循领域模型定义的接口。

package repository

import (
    "database/sql"
    "fmt"
    "user-service/internal/domain"
)

// UserRepository 数据库实现
type UserRepository struct {
    db *sql.DB // 注入数据库连接
}

// NewUserRepository 创建实例
func NewUserRepository(db *sql.DB) *UserRepository {
    return &UserRepository{db: db}
}

// Create 创建用户
func (r *UserRepository) Create(user *domain.User) error {
    sqlStr := `INSERT INTO users (username, password, email, status, created_at, updated_at) 
               VALUES (?, ?, ?, ?, ?, ?)`
    result, err := r.db.Exec(sqlStr, 
        user.Username, user.Password, user.Email, user.Status,
        user.CreatedAt, user.UpdatedAt,
    )
    if err != nil {
        return fmt.Errorf("插入用户失败: %v", err)
    }
    // 获取自增ID
    id, err := result.LastInsertId()
    if err != nil {
        return err
    }
    user.ID = uint64(id)
    return nil
}

// GetByID 按ID查询
func (r *UserRepository) GetByID(id uint64) (*domain.User, error) {
    sqlStr := `SELECT id, username, password, email, status, created_at, updated_at 
               FROM users WHERE id = ?`
    row := r.db.QueryRow(sqlStr, id)
    
    var user domain.User
    err := row.Scan(
        &user.ID, &user.Username, &user.Password, &user.Email,
        &user.Status, &user.CreatedAt, &user.UpdatedAt,
    )
    if err == sql.ErrNoRows {
        return nil, nil // 无数据返回nil
    }
    if err != nil {
        return nil, fmt.Errorf("查询用户失败: %v", err)
    }
    return &user, nil
}

// 其他方法(GetByUsername/Update/Delete)实现类似...
5. 业务逻辑层(internal/service/user_service.go)

处理核心业务逻辑(如密码加密、数据校验),依赖领域接口(解耦数据库)。

package service

import (
    "errors"
    "time"
    "golang.org/x/crypto/bcrypt" // 密码加密
    "user-service/internal/domain"
    "user-service/pkg/auth"
)

// UserService 用户服务
type UserService struct {
    repo   domain.UserRepository // 依赖接口,而非具体实现
    jwtCfg auth.JWTConfig        // JWT配置
}

// NewUserService 创建实例
func NewUserService(repo domain.UserRepository, jwtCfg auth.JWTConfig) *UserService {
    return &UserService{repo: repo, jwtCfg: jwtCfg}
}

// Register 用户注册
func (s *UserService) Register(username, password, email string) (*domain.User, error) {
    // 1. 校验用户名是否已存在
    exist, err := s.repo.GetByUsername(username)
    if err != nil {
        return nil, err
    }
    if exist != nil {
        return nil, errors.New("用户名已存在")
    }

    // 2. 密码加密(企业级项目必须加密存储)
    hashPwd, err := bcrypt.GenerateFromPassword([]byte(password), bcrypt.DefaultCost)
    if err != nil {
        return nil, errors.New("密码加密失败")
    }

    // 3. 创建用户
    now := time.Now()
    user := &domain.User{
        Username:  username,
        Password:  string(hashPwd),
        Email:     email,
        Status:    1, // 默认为正常状态
        CreatedAt: now,
        UpdatedAt: now,
    }
    if err := s.repo.Create(user); err != nil {
        return nil, err
    }
    return user, nil
}

// Login 用户登录(返回JWT令牌)
func (s *UserService) Login(username, password string) (string, error) {
    // 1. 查询用户
    user, err := s.repo.GetByUsername(username)
    if err != nil {
        return "", err
    }
    if user == nil {
        return "", errors.New("用户名或密码错误")
    }

    // 2. 校验密码
    if err := bcrypt.CompareHashAndPassword([]byte(user.Password), []byte(password)); err != nil {
        return "", errors.New("用户名或密码错误")
    }

    // 3. 生成JWT令牌
    token, err := auth.GenerateToken(user.ID, s.jwtCfg.Secret, s.jwtCfg.Expire)
    if err != nil {
        return "", errors.New("生成令牌失败")
    }
    return token, nil
}

// 其他方法(GetUser/UpdateUser/DeleteUser)实现类似...
6. API 层(HTTP 处理器与中间件)
处理器(internal/api/handler.go)

处理 HTTP 请求,调用服务层,返回 JSON 响应。

package api

import (
    "encoding/json"
    "net/http"
    "strconv"
    "user-service/internal/domain"
    "user-service/internal/service"
)

// UserHandler API处理器
type UserHandler struct {
    userService *service.UserService
}

// NewUserHandler 创建实例
func NewUserHandler(userService *service.UserService) *UserHandler {
    return &UserHandler{userService: userService}
}

// RegisterHandler 注册接口
func (h *UserHandler) RegisterHandler(w http.ResponseWriter, r *http.Request) {
    // 1. 解析请求体
    var req struct {
        Username string `json:"username"`
        Password string `json:"password"`
        Email    string `json:"email"`
    }
    if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
        http.Error(w, "请求格式错误", http.StatusBadRequest)
        return
    }

    // 2. 调用服务层
    user, err := h.userService.Register(req.Username, req.Password, req.Email)
    if err != nil {
        http.Error(w, err.Error(), http.StatusInternalServerError)
        return
    }

    // 3. 返回响应
    w.Header().Set("Content-Type", "application/json")
    json.NewEncoder(w).Encode(map[string]interface{}{
        "code": 0,
        "msg":  "注册成功",
        "data": user,
    })
}

// LoginHandler 登录接口
func (h *UserHandler) LoginHandler(w http.ResponseWriter, r *http.Request) {
    // 类似注册逻辑:解析请求 -> 调用服务层 -> 返回令牌
    // ...
}

// GetUserHandler 查询用户接口(需要认证)
func (h *UserHandler) GetUserHandler(w http.ResponseWriter, r *http.Request) {
    // 从URL获取用户ID
    idStr := r.PathValue("id") // Go 1.22+支持PathValue
    id, err := strconv.ParseUint(idStr, 10, 64)
    if err != nil {
        http.Error(w, "无效的用户ID", http.StatusBadRequest)
        return
    }

    // 调用服务层查询
    user, err := h.userService.GetUser(id)
    if err != nil {
        http.Error(w, err.Error(), http.StatusInternalServerError)
        return
    }
    if user == nil {
        http.Error(w, "用户不存在", http.StatusNotFound)
        return
    }

    // 返回用户信息
    w.Header().Set("Content-Type", "application/json")
    json.NewEncoder(w).Encode(map[string]interface{}{
        "code": 0,
        "data": user,
    })
}
中间件(认证 + 日志,internal/api/middleware.go)
package api

import (
    "log"
    "net/http"
    "time"
    "user-service/pkg/auth"
)

// AuthMiddleware 认证中间件(验证JWT令牌)
func AuthMiddleware(secret string) func(http.Handler) http.Handler {
    return func(next http.Handler) http.Handler {
        return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
            // 从Header获取令牌
            tokenStr := r.Header.Get("Authorization")
            if tokenStr == "" {
                http.Error(w, "未提供令牌", http.StatusUnauthorized)
                return
            }

            // 验证令牌
            _, err := auth.ValidateToken(tokenStr, secret)
            if err != nil {
                http.Error(w, "无效的令牌", http.StatusUnauthorized)
                return
            }

            // 验证通过,继续处理请求
            next.ServeHTTP(w, r)
        })
    }
}

// LogMiddleware 日志中间件(记录请求信息)
func LogMiddleware(next http.Handler) http.Handler {
    return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
        start := time.Now()
        // 记录请求方法、路径、耗时
        defer func() {
            log.Printf(
                "method: %s, path: %s, duration: %v",
                r.Method, r.URL.Path, time.Since(start),
            )
        }()
        next.ServeHTTP(w, r)
    })
}
7. 主程序入口(cmd/server/main.go)

组装所有组件,启动服务。

package main

import (
    "log"
    "net/http"
    "user-service/internal/api"
    "user-service/internal/config"
    "user-service/internal/repository"
    "user-service/internal/service"
    "user-service/pkg/db"
)

func main() {
    // 1. 加载配置
    cfg, err := config.Load("configs/config.yaml")
    if err != nil {
        log.Fatalf("加载配置失败: %v", err)
    }

    // 2. 初始化数据库连接
    mysqlDB, err := db.InitMySQL(cfg.Database)
    if err != nil {
        log.Fatalf("初始化数据库失败: %v", err)
    }
    defer mysqlDB.Close()

    // 3. 初始化依赖(依赖注入,解耦组件)
    userRepo := repository.NewUserRepository(mysqlDB)
    userService := service.NewUserService(userRepo, cfg.JWT)
    userHandler := api.NewUserHandler(userService)

    // 4. 注册路由
    mux := http.NewServeMux()
    // 公开接口(无需认证)
    mux.HandleFunc("POST /register", userHandler.RegisterHandler)
    mux.HandleFunc("POST /login", userHandler.LoginHandler)
    // 需认证的接口(应用认证中间件)
    authMux := api.AuthMiddleware(cfg.JWT.Secret)(mux)
    mux.Handle("GET /users/{id}", authMux)

    // 5. 应用日志中间件
    server := &http.Server{
        Addr:    ":" + strconv.Itoa(cfg.Server.Port),
        Handler: api.LogMiddleware(mux),
    }

    // 6. 启动服务
    log.Printf("服务启动,端口: %d,环境: %s", cfg.Server.Port, cfg.Server.Env)
    if err := server.ListenAndServe(); err != nil {
        log.Fatalf("服务启动失败: %v", err)
    }
}

企业级特性说明

  1. 分层架构:API 层(处理 HTTP)→ 服务层(业务逻辑)→ 数据层(数据库交互),职责清晰,便于维护。
  2. 依赖注入:通过接口解耦各层

go集成微服务框架生态重新实现

下面基于Go 微服务生态主流框架(如 Gin 作为 HTTP 框架、GORM 作为 ORM、Consul 服务注册发现、Jaeger 链路追踪、zap 日志),重新实现企业级用户管理微服务,使其更贴近生产环境的微服务架构。

项目结构(微服务标准架构)

user-service/
├── cmd/                  # 程序入口
│   └── server/
│       └── main.go       # 主函数(初始化框架、注册服务)
├── internal/             # 内部代码
│   ├── api/              # API层(Gin路由+控制器)
│   │   ├── handler/      # 控制器
│   │   │   └── user.go
│   │   └── router/       # 路由注册
│   │       └── router.go
│   ├── config/           # 配置(viper)
│   │   └── config.go
│   ├── domain/           # 领域模型
│   │   └── user.go
│   ├── repository/       # 数据访问层(GORM)
│   │   └── user.go
│   ├── service/          # 业务层
│   │   └── user.go
│   └── middleware/       # 微服务中间件(认证、追踪、日志)
│       ├── auth.go
│       ├── logger.go
│       └── tracer.go
├── pkg/                  # 公共工具
│   ├── registry/         # 服务注册(Consul)
│   ├── trace/            # 链路追踪(Jaeger)
│   └── auth/             # JWT工具
├── configs/              # 配置文件
│   └── config.yaml
└── go.mod

核心依赖(go.mod 关键部分)

require (
    github.com/gin-gonic/gin v1.9.1        // HTTP框架
    gorm.io/gorm v1.25.3                   // ORM框架
    gorm.io/driver/mysql v1.5.2            // MySQL驱动
    github.com/hashicorp/consul/api v1.20.0 // 服务注册发现
    go.opentelemetry.io/otel v1.19.0       // 链路追踪
    go.uber.org/zap v1.26.0                // 日志框架
    github.com/spf13/viper v1.18.2         // 配置管理
    golang.org/x/crypto v0.17.0            // 密码加密
)

核心代码实现

1. 配置管理(internal/config/config.go)

集成微服务必要配置(服务注册、链路追踪、数据库等):

package config

import (
    "fmt"
    "github.com/spf13/viper"
)

// Config 微服务配置
type Config struct {
    Server   ServerConfig   `mapstructure:"server"`
    MySQL    MySQLConfig    `mapstructure:"mysql"`
    JWT      JWTConfig      `mapstructure:"jwt"`
    Consul   ConsulConfig   `mapstructure:"consul"`   // 服务注册
    Jaeger   JaegerConfig   `mapstructure:"jaeger"`   // 链路追踪
    LogLevel string         `mapstructure:"log_level"` // 日志级别
}

// ServerConfig 服务基础配置
type ServerConfig struct {
    Name string `mapstructure:"name"` // 服务名(user-service)
    Host string `mapstructure:"host"` // 服务IP
    Port int    `mapstructure:"port"` // 服务端口
}

// MySQLConfig 数据库配置
type MySQLConfig struct {
    DSN      string `mapstructure:"dsn"`
    MaxOpen  int    `mapstructure:"max_open"`
    MaxIdle  int    `mapstructure:"max_idle"`
}

// JWTConfig 认证配置
type JWTConfig struct {
    Secret string `mapstructure:"secret"`
    Expire int64  `mapstructure:"expire"` // 过期时间(秒)
}

// ConsulConfig 服务注册配置
type ConsulConfig struct {
    Address string `mapstructure:"address"` // Consul地址(如127.0.0.1:8500)
    TTL     int    `mapstructure:"ttl"`     // 健康检查间隔(秒)
}

// JaegerConfig 链路追踪配置
type JaegerConfig struct {
    Endpoint string `mapstructure:"endpoint"` // Jaeger收集器地址
}

// Load 加载配置
func Load(path string) (*Config, error) {
    viper.SetConfigFile(path)
    if err := viper.ReadInConfig(); err != nil {
        return nil, fmt.Errorf("读取配置失败: %w", err)
    }
    var cfg Config
    if err := viper.Unmarshal(&cfg); err != nil {
        return nil, fmt.Errorf("解析配置失败: %w", err)
    }
    return &cfg, nil
}
2. 领域模型(internal/domain/user.go)

结合 GORM 标签定义数据库映射:

package domain

import (
    "time"
    "gorm.io/gorm"
)

// User 用户模型(与数据库表映射)
type User struct {
    ID        uint64         `gorm:"primaryKey;autoIncrement" json:"id"`
    Username  string         `gorm:"size:50;uniqueIndex;not null" json:"username"` // 唯一索引
    Password  string         `gorm:"size:100;not null" json:"-"`                  // 密码加密存储
    Email     string         `gorm:"size:100;uniqueIndex" json:"email"`            // 邮箱唯一
    Status    int            `gorm:"type:int;default:1" json:"status"`             // 1-正常,0-禁用
    CreatedAt time.Time      `json:"created_at"`
    UpdatedAt time.Time      `json:"updated_at"`
    DeletedAt gorm.DeletedAt `gorm:"index" json:"-"` // 软删除
}
3. 数据访问层(internal/repository/user.go)

基于 GORM 实现数据库操作:

package repository

import (
    "context"
    "user-service/internal/domain"
    "gorm.io/gorm"
)

// UserRepository 数据访问接口
type UserRepository interface {
    Create(ctx context.Context, user *domain.User) error
    GetByID(ctx context.Context, id uint64) (*domain.User, error)
    GetByUsername(ctx context.Context, username string) (*domain.User, error)
    Update(ctx context.Context, user *domain.User) error
}

// userRepository GORM实现
type userRepository struct {
    db *gorm.DB
}

func NewUserRepository(db *gorm.DB) UserRepository {
    return &userRepository{db: db}
}

// Create 创建用户
func (r *userRepository) Create(ctx context.Context, user *domain.User) error {
    return r.db.WithContext(ctx).Create(user).Error
}

// GetByUsername 按用户名查询
func (r *userRepository) GetByUsername(ctx context.Context, username string) (*domain.User, error) {
    var user domain.User
    err := r.db.WithContext(ctx).Where("username = ?", username).First(&user).Error
    if err != nil {
        if err == gorm.ErrRecordNotFound {
            return nil, nil // 无数据返回nil
        }
        return nil, err
    }
    return &user, nil
}

// 其他方法(GetByID/Update)实现类似...
4. 业务逻辑层(internal/service/user.go)

结合微服务上下文(链路追踪、日志):

package service

import (
    "context"
    "errors"
    "time"
    "user-service/internal/domain"
    "user-service/internal/repository"
    "user-service/pkg/auth"
    "golang.org/x/crypto/bcrypt"
)

// UserService 业务服务接口
type UserService interface {
    Register(ctx context.Context, username, password, email string) (*domain.User, error)
    Login(ctx context.Context, username, password string) (string, error)
    GetUser(ctx context.Context, id uint64) (*domain.User, error)
}

// userService 实现
type userService struct {
    repo   repository.UserRepository
    jwtSec string
    jwtExp int64
}

func NewUserService(repo repository.UserRepository, jwtSec string, jwtExp int64) UserService {
    return &userService{
        repo:   repo,
        jwtSec: jwtSec,
        jwtExp: jwtExp,
    }
}

// Register 注册业务逻辑
func (s *userService) Register(ctx context.Context, username, password, email string) (*domain.User, error) {
    // 1. 检查用户名是否存在
    exist, err := s.repo.GetByUsername(ctx, username)
    if err != nil {
        return nil, err
    }
    if exist != nil {
        return nil, errors.New("用户名已存在")
    }

    // 2. 密码加密
    hashPwd, err := bcrypt.GenerateFromPassword([]byte(password), bcrypt.DefaultCost)
    if err != nil {
        return nil, errors.New("密码加密失败")
    }

    // 3. 创建用户
    user := &domain.User{
        Username:  username,
        Password:  string(hashPwd),
        Email:     email,
        CreatedAt: time.Now(),
        UpdatedAt: time.Now(),
    }
    if err := s.repo.Create(ctx, user); err != nil {
        return nil, err
    }
    return user, nil
}

// Login 登录业务逻辑(生成JWT)
func (s *userService) Login(ctx context.Context, username, password string) (string, error) {
    user, err := s.repo.GetByUsername(ctx, username)
    if err != nil {
        return "", err
    }
    if user == nil {
        return "", errors.New("用户名或密码错误")
    }

    // 校验密码
    if err := bcrypt.CompareHashAndPassword([]byte(user.Password), []byte(password)); err != nil {
        return "", errors.New("用户名或密码错误")
    }

    // 生成JWT令牌(包含用户ID)
    token, err := auth.GenerateToken(user.ID, s.jwtSec, s.jwtExp)
    if err != nil {
        return "", errors.New("生成令牌失败")
    }
    return token, nil
}

// 其他方法(GetUser)实现类似...
5. API 层(控制器 + 路由)
控制器(internal/api/handler/user.go)

基于 Gin 处理 HTTP 请求:

package handler

import (
    "net/http"
    "strconv"
    "user-service/internal/service"
    "github.com/gin-gonic/gin"
)

// UserHandler 控制器
type UserHandler struct {
    userService service.UserService
}

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

// Register 注册接口
func (h *UserHandler) Register(c *gin.Context) {
    var req struct {
        Username string `json:"username" binding:"required,min=3,max=20"`
        Password string `json:"password" binding:"required,min=6"`
        Email    string `json:"email" binding:"required,email"`
    }
    // 参数校验
    if err := c.ShouldBindJSON(&req); err != nil {
        c.JSON(http.StatusBadRequest, gin.H{"code": 400, "msg": err.Error()})
        return
    }

    // 调用业务层
    user, err := h.userService.Register(c.Request.Context(), req.Username, req.Password, req.Email)
    if err != nil {
        c.JSON(http.StatusInternalServerError, gin.H{"code": 500, "msg": err.Error()})
        return
    }

    c.JSON(http.StatusOK, gin.H{
        "code": 0,
        "msg":  "注册成功",
        "data": user,
    })
}

// Login 登录接口
func (h *UserHandler) Login(c *gin.Context) {
    var req struct {
        Username string `json:"username" binding:"required"`
        Password string `json:"password" binding:"required"`
    }
    if err := c.ShouldBindJSON(&req); err != nil {
        c.JSON(http.StatusBadRequest, gin.H{"code": 400, "msg": err.Error()})
        return
    }

    token, err := h.userService.Login(c.Request.Context(), req.Username, req.Password)
    if err != nil {
        c.JSON(http.StatusInternalServerError, gin.H{"code": 500, "msg": err.Error()})
        return
    }

    c.JSON(http.StatusOK, gin.H{
        "code": 0,
        "msg":  "登录成功",
        "data": gin.H{"token": token},
    })
}

// GetUser 查询用户接口(需认证)
func (h *UserHandler) GetUser(c *gin.Context) {
    idStr := c.Param("id")
    id, err := strconv.ParseUint(idStr, 10, 64)
    if err != nil {
        c.JSON(http.StatusBadRequest, gin.H{"code": 400, "msg": "无效的用户ID"})
        return
    }

    user, err := h.userService.GetUser(c.Request.Context(), id)
    if err != nil {
        c.JSON(http.StatusInternalServerError, gin.H{"code": 500, "msg": err.Error()})
        return
    }
    if user == nil {
        c.JSON(http.StatusNotFound, gin.H{"code": 404, "msg": "用户不存在"})
        return
    }

    c.JSON(http.StatusOK, gin.H{
        "code": 0,
        "data": user,
    })
}
路由注册(internal/api/router/router.go)
package router

import (
    "user-service/internal/api/handler"
    "user-service/internal/middleware"
    "github.com/gin-gonic/gin"
)

// InitRouter 初始化路由
func InitRouter(
    userHandler *handler.UserHandler,
    authMiddleware gin.HandlerFunc,
    logMiddleware gin.HandlerFunc,
    traceMiddleware gin.HandlerFunc,
) *gin.Engine {
    r := gin.Default()

    // 全局中间件:日志、链路追踪
    r.Use(logMiddleware, traceMiddleware)

    // 公开路由(无需认证)
    public := r.Group("/api/v1")
    {
        public.POST("/register", userHandler.Register)
        public.POST("/login", userHandler.Login)
    }

    // 需认证的路由
    private := r.Group("/api/v1")
    private.Use(authMiddleware) // 应用认证中间件
    {
        private.GET("/users/:id", userHandler.GetUser)
    }

    return r
}
6. 微服务中间件
认证中间件(internal/middleware/auth.go)
package middleware

import (
    "net/http"
    "strings"
    "user-service/pkg/auth"
    "github.com/gin-gonic/gin"
)

// AuthMiddleware JWT认证中间件
func AuthMiddleware(secret string) gin.HandlerFunc {
    return func(c *gin.Context) {
        // 从Header获取令牌(格式:Bearer <token>)
        authHeader := c.GetHeader("Authorization")
        if authHeader == "" {
            c.JSON(http.StatusUnauthorized, gin.H{"code": 401, "msg": "未提供令牌"})
            c.Abort()
            return
        }

        parts := strings.Split(authHeader, " ")
        if len(parts) != 2 || parts[0] != "Bearer" {
            c.JSON(http.StatusUnauthorized, gin.H{"code": 401, "msg": "令牌格式错误"})
            c.Abort()
            return
        }

        // 验证令牌
        _, err := auth.ValidateToken(parts[1], secret)
        if err != nil {
            c.JSON(http.StatusUnauthorized, gin.H{"code": 401, "msg": "令牌无效或已过期"})
            c.Abort()
            return
        }

        c.Next()
    }
}
日志中间件(internal/middleware/logger.go)

基于 zap 实现结构化日志:

package middleware

import (
    "time"
    "user-service/pkg/logger"
    "github.com/gin-gonic/gin"
    "go.uber.org/zap"
)

// LogMiddleware 日志中间件
func LogMiddleware() gin.HandlerFunc {
    return func(c *gin.Context) {
        start := time.Now()
        // 处理请求
        c.Next()
        // 记录日志
        logger.Info(
            "request completed",
            zap.String("method", c.Request.Method),
            zap.String("path", c.Request.URL.Path),
            zap.Int("status", c.Writer.Status()),
            zap.Duration("duration", time.Since(start)),
Logo

Agent 垂直技术社区,欢迎活跃、内容共建。

更多推荐