# service-framework-go **Repository Path**: cryptolab/service-framework-go ## Basic Information - **Project Name**: service-framework-go - **Description**: No description available - **Primary Language**: Unknown - **License**: MIT - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 0 - **Created**: 2024-12-04 - **Last Updated**: 2024-12-04 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README # mara service 基础模板 ## 环境依赖 1. golang 1.20+ 2. mysql 5.7+ 3. redis 6.0+ ## 数据库 ### 创建数据库 `sql/root.sql` ```sql DROP DATABASE IF EXISTS `db_mara_base`; CREATE DATABASE `db_mara_base` DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci; DROP USER IF EXISTS `user_mara_base`; CREATE USER `user_mara_base`@`%` IDENTIFIED BY '$ENV::mysql_user_password'; GRANT ALL ON `db_mara_base`.* TO `user_mara_base`@`%`; ``` ### 添加表 `sql/ddl.sql` **Task 待办事项表** - 关联 `user` 表:`user_id` - 关联 `category` 表:`category_id` ```sql CREATE TABLE `task` ( `id` int(11) unsigned NOT NULL AUTO_INCREMENT, `user_id` int(11) unsigned NOT NULL COMMENT '用户ID', `category_id` int(11) unsigned NOT NULL COMMENT '分类ID', `title` varchar(255) NOT NULL COMMENT '任务标题', `content` varchar(255) NOT NULL COMMENT '任务内容', `status` tinyint(3) unsigned NOT NULL DEFAULT '0' COMMENT '0: 未完成, 1: 已完成', `due_at` bigint(20) NOT NULL COMMENT '截止时间', `finished_at` bigint(20) DEFAULT NULL COMMENT '完成时间', `created_at` bigint(20) NOT NULL, `updated_at` bigint(20) NOT NULL, `is_deleted` tinyint(3) unsigned NOT NULL DEFAULT '0' COMMENT '0: 未删除, 1: 已删除', PRIMARY KEY (`id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4; ``` **User 用户表** ```sql CREATE TABLE `user` ( `id` int(11) unsigned NOT NULL AUTO_INCREMENT, `username` varchar(255) NOT NULL COMMENT '用户名', `password` varchar(255) NOT NULL COMMENT '密码', `fullname` varchar(255) NOT NULL COMMENT '姓名', `email` varchar(255) NOT NULL COMMENT '邮箱', `phone` varchar(255) NOT NULL COMMENT '手机号', `status` tinyint(3) unsigned NOT NULL DEFAULT '0' COMMENT '状态 0:未验证 1:正常 2:禁用', `created_at` bigint(20) NOT NULL, `updated_at` bigint(20) NOT NULL, `is_deleted` tinyint(3) unsigned NOT NULL DEFAULT '0' COMMENT '0: 未删除, 1: 已删除', PRIMARY KEY (`id`), UNIQUE KEY `username` (`username`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4; ``` **Category 分类表** ```sql CREATE TABLE `category` ( `id` int(11) unsigned NOT NULL AUTO_INCREMENT, `title` varchar(255) NOT NULL DEFAULT '' COMMENT '分类名称', `description` varchar(255) NOT NULL DEFAULT '' COMMENT '分类描述', `created_at` bigint(20) NOT NULL COMMENT '创建时间', `updated_at` bigint(20) NOT NULL COMMENT '更新时间', `is_deleted` tinyint(3) unsigned NOT NULL DEFAULT '0' COMMENT '0: 未删除, 1: 已删除', PRIMARY KEY (`id`), UNIQUE KEY `title` (`title`) ) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8mb4 COMMENT='分类表'; ``` ### 添加测试数据 `sql/dml.sql` ```sql INSERT INTO `category` (`id`, `title`, `description`, `created_at`, `updated_at`, `is_deleted`) VALUES (1, '学习', '学习', 1674457673, 1674457673, 0); INSERT INTO `user` (`id`, `username`, `password`, `fullname`, `email`, `phone`, `status`, `created_at`, `updated_at`, `is_deleted`) VALUES (1, 'admin', 'admin', '管理员', 'admin@example.com', '1234567890', 1, 1674457673, 1674457673, 0); INSERT INTO `task` (`id`, `user_id`, `category_id`, `title`, `content`, `status`, `due_at`, `finished_at`, `created_at`, `updated_at`, `is_deleted`) VALUES (1, 1, 1, '学习', '学习', 0, 1674457673, NULL, 1674457673, 1674457673, 0); ``` ### 运行sql脚本 **前提条件** 1. 确保mysql容器已经启动,且名称为 `sec-mysql` 2. 确保 `$HOME/.mara/security.json` 文件存在 ```bash ./scripts/runsql.sh ./sql/root.sql ./scripts/runsql.sh ./sql/ddl.sql ./scripts/runsql.sh ./sql/dml.sql ``` ### 生成自动化CRUD代码 ```bash ./scripts/gormgen.sh db_mara_base ``` ## `POST /task/list` 根据条件返回任务列表 ### services `internal/services/task/service_list.go` **定义查询参数** ```go type SearchData struct { // 分页参数 Page int `json:"page"` PageSize int `json:"page_size"` // 查询参数 Title *string `json:"title"` // 任务名称 Status *string `json:"status"` // 任务状态 CategoryId *int32 `json:"category_id"` // 任务分类 UserId *int32 `json:"user_id"` // 任务负责人 DueAt *int32 `json:"due_at"` // 任务截止时间 } ``` **定义返回参数** ```go type TaskItem struct { Id int32 `json:"id"` Title string `json:"title"` Content string `json:"content"` Status int32 `json:"status"` DutAt int32 `json:"dut_at"` CategoryId int32 `json:"category_id"` CategoryName string `json:"category_name"` UserId int32 `json:"user_id"` Username string `json:"username"` Fullname string `json:"fullname"` CreatedAt int32 `json:"created_at"` UpdatedAt int32 `json:"updated_at"` } ``` **创建函数** 函数签名 ```go func (s *service) List(ctx core.Context, searchData *SearchData) (total int64, list []*TaskItem, err error) ``` 查询 ```go db := s.db.GetDbR().WithContext(ctx.RequestContext()). Table("task t"). Select("t.*, u.username, u.fullname, c.title as category_title"). Joins("LEFT JOIN user u ON t.user_id = u.id"). Joins("LEFT JOIN category c ON t.category_id = c.id") // 字符串模糊查询 if searchData.Title != nil { db = db.Where(mysql.LikePredicate, "%"+*searchData.Title+"%") } if searchData.Status != nil { db = db.Where(mysql.EqualPredicate, *searchData.Status) } if searchData.UserId != nil { db = db.Where(mysql.EqualPredicate, *searchData.UserId) } if searchData.CategoryId != nil { db = db.Where(mysql.EqualPredicate, *searchData.CategoryId) } // 时间类型 if searchData.DueAt != nil { db = db.Where(mysql.SmallerThanOrEqualPredicate, *searchData.DueAt) } ``` 查询总数 ```go err = db.Count(&total).Error if err != nil { return } ``` 查询分页数据 ```go // order db = db.Order("t.created_at DESC") // 分页 db = db.Limit(pageSize).Offset(offset) // scan results list = []*TaskItem{} err = db.Find(&list).Error if err != nil { return } ``` ### api `internal/api/task/func_list.go` ```go // 定义查询参数 type listRequest struct { Page int `json:"page" binding:"required"` PageSize int `json:"page_size" binding:"required"` Title *string `json:"title"` // 任务名称 Status *int32 `json:"status"` // 任务状态 CategoryId *int32 `json:"category_id"` // 任务分类 UserId *int32 `json:"user_id"` // 任务负责人 DueAt *int64 `json:"due_at"` // 任务截止时间 } // 定义返回结果 type listResponse struct { Total int64 `json:"total"` List []*task.TaskItem `json:"list"` } ``` 处理函数 ```go func (h *handler) List() core.HandlerFunc { return func(ctx core.Context) { // 绑定请求参数,并校验 req := new(listRequest) if err := ctx.ShouldBindJSON(req); err != nil { // 参数校验失败,需要返回错误信息 // 错误码封装参考 【状态编码】 ctx.AbortWithError(core.Error( http.StatusBadRequest, code.ParamBindError, code.Text(code.ParamBindError)).WithError(err), ) return } // 构造查询参数 searchData := &task.SearchData{ Page: req.Page, PageSize: req.PageSize, Title: req.Title, Status: req.Status, CategoryId: req.CategoryId, UserId: req.UserId, DueAt: req.DueAt, } // 调用服务 total, list, err := h.taskService.List(ctx, searchData) if err != nil { // 返回错误 ctx.AbortWithError(core.Error( http.StatusBadRequest, code.TaskError, code.Text(code.TaskError)).WithError(err), ) return } // 构造返回结果 res := &listResponse{ Total: total, List: list, } ctx.Payload(res) } } ``` ### router `internal/router/router_api.go` ```go // 定义路由分组 taskHandler := task.New(r.logger, r.db) taskApi := r.mux.Group("/task") { // 定义路由 taskApi.POST("/list", taskHandler.List()) } ``` ## 项目配置 ### 项目常量 `configs/constants.go` ```go // 定义项目名称 ProjectName = "mara-base" // 定义项目端口 ProjectPort = ":20001" ``` ### Logo 修改一下项目的Logo `internal/pkg/core/core.go` 访问 `http://patorjk.com/software/taag/#p=display&f=ANSI%20Shadow&t=mara-base` 将生成的Logo复制到 `_UI` 变量即可。 ## Swagger 生成Swagger文档 ```bash ./scripts/swagger.sh ``` 访问 `http://localhost:20001/swagger/index.html` 即可。 ## 调试 在 vscode 中调试项目,需要配置一下 `launch.json` 文件。 ```json { "version": "0.2.0", "configurations": [ { "name": "Launch Package", "type": "go", "request": "launch", "mode": "auto", "program": "${workspaceFolder}/main.go", "env": { "MYSQL_PASSWORD": "123456" } } ] } ``` 其中`MYSQL_PASSWORD`为环境变量,需要根据实际情况进行修改。