# Go实战项目
# 项目结构
project/
├── cmd/
│ └── server/
│ └── main.go # 应用入口
├── internal/
│ ├── handler/ # HTTP处理器
│ ├── service/ # 业务逻辑
│ ├── repository/ # 数据访问
│ └── model/ # 数据模型
├── pkg/ # 可复用包
├── config/ # 配置文件
├── migrations/ # 数据库迁移
├── tests/ # 测试
├── go.mod
└── go.sum
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# 完整示例:RESTful API
# 主程序
// cmd/server/main.go
package main
import (
"log"
"net/http"
"yourproject/internal/handler"
"yourproject/internal/repository"
"yourproject/internal/service"
)
func main() {
// 初始化依赖
userRepo := repository.NewUserRepository()
userService := service.NewUserService(userRepo)
userHandler := handler.NewUserHandler(userService)
// 路由设置
http.HandleFunc("/api/users", userHandler.HandleUsers)
http.HandleFunc("/api/users/", userHandler.HandleUser)
log.Println("Server starting on :8080")
log.Fatal(http.ListenAndServe(":8080", nil))
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
# 数据模型
// internal/model/user.go
package model
import "time"
type User struct {
ID int `json:"id"`
Username string `json:"username"`
Email string `json:"email"`
CreatedAt time.Time `json:"created_at"`
}
1
2
3
4
5
6
7
8
9
10
11
2
3
4
5
6
7
8
9
10
11
# Repository层
// internal/repository/user_repository.go
package repository
import (
"database/sql"
"yourproject/internal/model"
)
type UserRepository interface {
Create(user *model.User) error
GetByID(id int) (*model.User, error)
GetAll() ([]*model.User, error)
Update(user *model.User) error
Delete(id int) error
}
type userRepository struct {
db *sql.DB
}
func NewUserRepository() UserRepository {
// 初始化数据库连接
db, _ := sql.Open("postgres", "connection string")
return &userRepository{db: db}
}
func (r *userRepository) Create(user *model.User) error {
query := `INSERT INTO users (username, email) VALUES ($1, $2) RETURNING id, created_at`
return r.db.QueryRow(query, user.Username, user.Email).Scan(&user.ID, &user.CreatedAt)
}
func (r *userRepository) GetByID(id int) (*model.User, error) {
user := &model.User{}
query := `SELECT id, username, email, created_at FROM users WHERE id = $1`
err := r.db.QueryRow(query, id).Scan(&user.ID, &user.Username, &user.Email, &user.CreatedAt)
if err != nil {
return nil, err
}
return user, nil
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
# Service层
// internal/service/user_service.go
package service
import (
"errors"
"yourproject/internal/model"
"yourproject/internal/repository"
)
type UserService interface {
CreateUser(username, email string) (*model.User, error)
GetUser(id int) (*model.User, error)
GetAllUsers() ([]*model.User, error)
}
type userService struct {
repo repository.UserRepository
}
func NewUserService(repo repository.UserRepository) UserService {
return &userService{repo: repo}
}
func (s *userService) CreateUser(username, email string) (*model.User, error) {
if username == "" {
return nil, errors.New("username cannot be empty")
}
if email == "" {
return nil, errors.New("email cannot be empty")
}
user := &model.User{
Username: username,
Email: email,
}
if err := s.repo.Create(user); err != nil {
return nil, err
}
return user, nil
}
func (s *userService) GetUser(id int) (*model.User, error) {
return s.repo.GetByID(id)
}
func (s *userService) GetAllUsers() ([]*model.User, error) {
return s.repo.GetAll()
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
# Handler层
// internal/handler/user_handler.go
package handler
import (
"encoding/json"
"net/http"
"strconv"
"yourproject/internal/service"
)
type UserHandler struct {
service service.UserService
}
func NewUserHandler(svc service.UserService) *UserHandler {
return &UserHandler{service: svc}
}
func (h *UserHandler) HandleUsers(w http.ResponseWriter, r *http.Request) {
switch r.Method {
case http.MethodGet:
h.getAllUsers(w, r)
case http.MethodPost:
h.createUser(w, r)
default:
http.Error(w, "Method not allowed", http.StatusMethodNotAllowed)
}
}
func (h *UserHandler) createUser(w http.ResponseWriter, r *http.Request) {
var req struct {
Username string `json:"username"`
Email string `json:"email"`
}
if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
http.Error(w, err.Error(), http.StatusBadRequest)
return
}
user, err := h.service.CreateUser(req.Username, req.Email)
if err != nil {
http.Error(w, err.Error(), http.StatusBadRequest)
return
}
w.Header().Set("Content-Type", "application/json")
w.WriteHeader(http.StatusCreated)
json.NewEncoder(w).Encode(user)
}
func (h *UserHandler) getAllUsers(w http.ResponseWriter, r *http.Request) {
users, err := h.service.GetAllUsers()
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
w.Header().Set("Content-Type", "application/json")
json.NewEncoder(w).Encode(users)
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
# 测试
// internal/service/user_service_test.go
package service
import (
"testing"
"yourproject/internal/model"
"yourproject/internal/repository"
)
type mockUserRepository struct {
users []*model.User
}
func (m *mockUserRepository) Create(user *model.User) error {
user.ID = len(m.users) + 1
m.users = append(m.users, user)
return nil
}
func (m *mockUserRepository) GetByID(id int) (*model.User, error) {
for _, user := range m.users {
if user.ID == id {
return user, nil
}
}
return nil, errors.New("user not found")
}
func TestCreateUser(t *testing.T) {
repo := &mockUserRepository{}
svc := NewUserService(repo)
user, err := svc.CreateUser("testuser", "test@example.com")
if err != nil {
t.Fatalf("Expected no error, got %v", err)
}
if user.Username != "testuser" {
t.Errorf("Expected username 'testuser', got '%s'", user.Username)
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
# 最佳实践总结
# 1. 项目结构
- 分层架构: Handler-Service-Repository
- 依赖注入: 通过接口解耦
- 包组织: internal和pkg分离
# 2. 错误处理
- 错误包装: 使用fmt.Errorf和%w
- 错误类型: 定义自定义错误类型
- 错误检查: 使用errors.Is和errors.As
# 3. 并发安全
- Mutex: 保护共享资源
- Channel: 协程间通信
- Context: 取消和超时控制
# 4. 测试
- 单元测试: 测试每个函数
- 表驱动测试: 多场景测试
- 基准测试: 性能测试
← Go进阶