{"id":23052139,"url":"https://github.com/Dusongg/UF2.0-TodoList-server","last_synced_at":"2025-08-15T03:32:20.385Z","repository":{"id":250141387,"uuid":"833590221","full_name":"Dusongg/UF2.0-TodoList-server","owner":"Dusongg","description":"适用于hundsun经纪线UF2.0的修改单、补丁、日常任务管理（服务端）","archived":false,"fork":false,"pushed_at":"2024-08-28T08:11:20.000Z","size":107,"stargazers_count":1,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"main","last_synced_at":"2024-12-16T00:11:37.467Z","etag":null,"topics":["docker","golang","gorm","grpc","mysql","nginx","protobuf","redis","smtp"],"latest_commit_sha":null,"homepage":"","language":"Go","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/Dusongg.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2024-07-25T11:00:08.000Z","updated_at":"2024-08-28T08:11:23.000Z","dependencies_parsed_at":"2024-09-21T21:03:25.068Z","dependency_job_id":"4ad99e35-4dcc-43ed-a548-4b4aeb32d7a5","html_url":"https://github.com/Dusongg/UF2.0-TodoList-server","commit_stats":{"total_commits":40,"total_committers":2,"mean_commits":20.0,"dds":"0.025000000000000022","last_synced_commit":"2b44291914e9f0cd2a54f57ab33283f31ad913de"},"previous_names":["dusongg/uf2.0-todolist"],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Dusongg%2FUF2.0-TodoList-server","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Dusongg%2FUF2.0-TodoList-server/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Dusongg%2FUF2.0-TodoList-server/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Dusongg%2FUF2.0-TodoList-server/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/Dusongg","download_url":"https://codeload.github.com/Dusongg/UF2.0-TodoList-server/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":229890117,"owners_count":18140043,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["docker","golang","gorm","grpc","mysql","nginx","protobuf","redis","smtp"],"created_at":"2024-12-16T00:11:53.721Z","updated_at":"2024-12-16T00:11:54.656Z","avatar_url":"https://github.com/Dusongg.png","language":"Go","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Why use ？\n\n- **Efficiency**：采用gRPC与客户端进行通信，Protobuf压缩传输数据，并依赖Golang的高并发\n- **Function**：redis + gRPC流 实现消息广播\n- **Readability \u0026 concise**：采用GORM管理数据库\n- **Stability**：采用Nginx作反向代理，负载均衡，切换挂掉的服务节点\n- **Containerization**：`docker compose up`一键部署运行\n\n\n\n# 安装部署\n\n## 1.1 Docker\n\n1. `git clone git@github.com:Dusongg/UF2.0-TodoList-server.git`\n\n   或`git clone https://github.com/Dusongg/UF2.0-TodoList-server.git`\n\n2. 在docker-compose.yml文件目录下，运行`docker compose up`\n\n3. 查看是否运行成功\n\n   1. `grpcurl -plaintext -d '{\"name\": \"dusong\"}' localhost:8001 notification.Service/SayHello`\n\n      ![image-20240815111932773](https://typora-dusong.oss-cn-chengdu.aliyuncs.com/image-20240815111932773.png)\n\n   2. `docker ps`![image-20240815131511204](https://typora-dusong.oss-cn-chengdu.aliyuncs.com/image-20240815131511204.png)\n\n4. **环境变量说明**\n\n   在`./.env`文件中（`docker compose up`时会读取该文件到环境变量中）\n\n   1. Redis![image-20240816151657078](https://typora-dusong.oss-cn-chengdu.aliyuncs.com/image-20240816151657078.png)\n   2. MySQL![image-20240816151812767](https://typora-dusong.oss-cn-chengdu.aliyuncs.com/image-20240816151812767.png)\n   3. SMTP![image-20240816152117264](https://typora-dusong.oss-cn-chengdu.aliyuncs.com/image-20240816152117264.png)\n   4. Admin![image-20240816152206912](https://typora-dusong.oss-cn-chengdu.aliyuncs.com/image-20240816152206912.png)\n\n\n\n## 1.2 手动部署\n\n1. 安装redis和mysql\n\n2. 配置好mysql用户和密码，进入mysql`mysql -uroot -p`， 创建数据库`create database OrderManager`（数据库名可以更改，同时修改config.json文件内容）\n\n3. `git clone git@github.com:Dusongg/UF2.0-TodoList-server.git`或`git clone https://github.com/Dusongg/UF2.0-TodoList-server.git` 拉取远程仓库到本地\n\n4. 在`./config/config.json`文件下修改相应配置，大部分与**1.1**中的环境变量配置相同\n\n   ```json\n   {\n     \"redis\": {\n       \"host\": \"localhost\",\n       \"port\": \"6379\"\n     },\n   \n     \"mysql\": {\n       \"gorm_dns\": \"root:123123@tcp(127.0.0.1:3306)/OrderManager?charset=utf8mb4\u0026parseTime=True\u0026loc=Local\" \n     },\n   \n     \"smtp\": {\n       \"host\": \"smtp.gmail.com\",\n       \"port\": \"587\",\n       \"sender\" : \"dusong700@gmail.com\",\n       \"password\": \"xxxx xxxx xxxx xxxx\",  \n       \"send_time_point_1\": \"9\",\n       \"send_time_point_2\": \"13\"\n   \n     },\n   \n     \"log_path\": \"./logs/app.log\",\n   \n     \"admins\" : [\n       \"dusong\",\n       \"游洋\"\n     ]\n   \n   }\n   ```\n\n\n\n5. 以Linux为例\n   1. `cd UF2.0-TodoList-server `\n   2. `go mod tidy`\n   3. `go run .`\n\n\n\n\n# 数据库字段说明\n\n## 2.1 任务表(tasklist_table)\n\n### 字段说明\n\n- 主键：task_id\n\n- 唯一键：req_no\n\n![image-20240816161009673](https://typora-dusong.oss-cn-chengdu.aliyuncs.com/image-20240816161009673.png)\n\n### DDL\n\n```mysql\n-- auto-generated definition\ncreate table tasklist_table\n(\n    comment              varchar(100)                                                                    null comment '任务描述',\n    task_id              varchar(25)                                                                     not null comment '任务单号'\n        primary key,\n    emergency_level      int         default 0                                                           null comment '紧急程度',\n    deadline             date        default (date_format((now() + interval 3 day), _utf8mb4'%Y-%m-%d')) null comment '截止日期',\n    principal            varchar(20)                                                                     not null comment '负责人',\n    req_no               varchar(20)                                                                     not null comment '需求号',\n    estimated_work_hours double      default 16                                                          null comment '预计工时',\n    state                varchar(20) default '带启动'                                                    null comment '任务状态',\n    type                 int         default 0                                                           null comment '任务类型'\n);\n\ncreate index tasklist_req_no_index\n    on tasklist_table (req_no);\n\n\n```\n\n### GORM模型\n\n```go\ntype TaskInfo struct {\n\tTaskID             string    `gorm:\"column:task_id;type:varchar(25);primaryKey;not null;comment:任务单号\"`\n\tComment            string    `gorm:\"column:comment;type:varchar(100);comment:任务描述\"`\n\tEmergencyLevel     int       `gorm:\"column:emergency_level;default:0;comment:紧急程度\"`\n\tDeadline           time.Time `gorm:\"column:deadline;type:date;default:(date_format((now() + interval 3 day),_utf8mb4'%Y-%m-%d'));comment:截止日期\"`\n\tPrincipal          string    `gorm:\"column:principal;type:varchar(20);not null;comment:负责人\"`\n\tReqNo              string    `gorm:\"column:req_no;type:varchar(20);not null;comment:需求号;index:tasklist_req_no_index\"`\n\tEstimatedWorkHours float64   `gorm:\"column:estimated_work_hours;default:16;comment:预计工时\"`\n\tState              string    `gorm:\"column:state;type:varchar(20);default:带启动;comment:任务状态\"`\n\tType               int       `gorm:\"column:type;default:0;comment:任务类型\"`\n}\n\nfunc (TaskInfo) TableName() string {\n\treturn \"tasklist_table\"\n}\n```\n\n\n\n## 2.2 补丁表(patch_table)\n\n### 字段说明\n\n- 主键：patch_no\n\n- 唯一键：req_no\n\n![image-20240816161402947](https://typora-dusong.oss-cn-chengdu.aliyuncs.com/image-20240816161402947.png)\n\n### DDL\n\n```mysql\n-- auto-generated definition\ncreate table patch_table\n(\n    patch_no    varchar(20)  not null comment '补丁号'\n        primary key,\n    req_no      varchar(40)  not null comment '需求号',\n    `describe`  text         null comment '问题描述',\n    client_name varchar(20)  not null comment '客户名称',\n    deadline    date         not null comment '预计发布时间',\n    reason      varchar(100) null comment '补丁原因',\n    sponsor     varchar(20)  not null comment '发起人',\n    state       varchar(10)  null comment '发布状态'\n);\n\ncreate index patch_table_req_no_index\n    on patch_table (req_no);\n\n```\n\n### GORM模型\n\n```go\ntype PatchsInfo struct {\n\tPatchNo    string    `gorm:\"column:patch_no;type:varchar(20);primaryKey;not null;comment:补丁号\"`\n\tReqNo      string    `gorm:\"column:req_no;type:varchar(40);not null;comment:需求号;index:patch_table_req_no_index\"`\n\tDescribe   string    `gorm:\"column:describe;type:text;comment:问题描述\"`\n\tClientName string    `gorm:\"column:client_name;type:varchar(20);not null;comment:客户名称\"`\n\tDeadline   time.Time `gorm:\"column:deadline;type:date;not null;comment:预计发布时间\"`\n\tReason     string    `gorm:\"column:reason;type:varchar(100);comment:补丁原因\"`\n\tSponsor    string    `gorm:\"column:sponsor;type:varchar(20);not null;comment:发起人\"`\n\tState      string    `gorm:\"column:state;type:varchar(10);comment:发布状态\"`\n}\n\nfunc (PatchsInfo) TableName() string {\n\treturn \"patch_table\"\n}\n```\n\n\n\n## 2.3 用户表(user_table)\n\n### 字段说明\n\n- 普通索引：name\n\n![image-20240816161457805](https://typora-dusong.oss-cn-chengdu.aliyuncs.com/image-20240816161457805.png)\n\n### DDL\n\n```mysql\n-- auto-generated definition\ncreate table user_table\n(\n    name     varchar(20)      not null comment '姓名',\n    job_no   bigint           not null comment '工号',\n    password varchar(60)      not null comment '密码',\n    email    varchar(50)      not null comment '邮箱',\n    `group`  bigint default 0 null comment '分组编号',\n    role_no  bigint default 0 null comment '角色编号'\n);\n\ncreate index idx_user_table_name\n    on user_table (name);\n\n\n```\n\n### GORM模型\n\n```go\ntype UserInfo struct {\n\tName     string `gorm:\"column:name;type:varchar(20);not null;index;comment:姓名\"`\n\tJobNo    int32  `gorm:\"column:job_no;not null;comment:工号\"`\n\tPassword string `gorm:\"column:password;type:varchar(60);not null;comment:密码\"`\n\tEmail    string `gorm:\"column:email;type:varchar(50);not null;comment:邮箱\"`\n\tGroup    int8   `gorm:\"column:group;default:0;comment:分组编号\"`\n\tRoleNo   int8   `gorm:\"column:role_no;default:0;comment:角色编号\"`\n\t//State    bool   `gorm:\"column:state;default:false;comment:登录状态\"`\n}\n\nfunc (UserInfo) TableName() string {\n\treturn \"user_table\"\n}\n```\n\n\n\n# 部分API说明\n\n![image-20240816153407027](https://typora-dusong.oss-cn-chengdu.aliyuncs.com/image-20240816153407027.png)\n\n![image-20240816155011703](https://typora-dusong.oss-cn-chengdu.aliyuncs.com/image-20240816155011703.png)\n\n## 2.1 任务相关\n\n## 2.1.1 AddTask \u0026 ImportXLSToTaskTable\n\n- 导入或新增任务如果有主键或者唯一键冲突，**那么会插入失败，并将报错写入日志**\n\n### 2.1.2 DelTask \u0026 ModTask\n\n- 当当前用户不是管理员时，无法删除或修改其他用户任务\n- 当修改或删除的是他人的任务时，会将消息发送给他人\n\n\n\n## 2.2 补丁相关\n\n### 2.2.1 ImportXLSToPatchTable\n\n- 如果任务表中有与导入补丁相关联时，任务的截止日期会与补丁的截止日期两者取较小值，最终将补丁导入的消息通知给所有人\n- 导入补丁与导入任务不同， 导入补丁如果遇见主键或唯一键冲突会**覆盖改行内容，而不会报错**\n\n\n\n### 2.2.2 DelPatch\n\n- 调用该函数会将补丁以及与补丁相关联的所有任务都删除\n\n### 2.2.3 ModPatch\n\n- 如果修改了补丁的时间，此时会将与补丁相关联的任务时间取两者较小值修改\n\n\n\n\n\n## 2.3 发布订阅模式\n\n### 2.3.1 Subscribe\n\n- 订阅redis的updates频道，并接受消息通过stream发送给客户端\n\n\n\n\n\n# Why gRPC ?\n\n### 1. **协议层次和数据格式**：\n\n- **HTTP**：HTTP是一种应用层协议，通常用于Web服务，通过请求和响应传输数据。常见的数据格式是JSON或XML，易于人类读取和调试。\n- **gRPC**：gRPC基于HTTP/2协议，使用Protobuf（Protocol Buffers）作为数据序列化格式。Protobuf是一种二进制格式，比JSON更紧凑、更高效，尤其在传输大规模数据时优势明显。\n\n### 2. **性能和效率**：\n\n- **HTTP**：由于使用了文本格式（如JSON），HTTP请求和响应的数据量相对较大，解析速度相对较慢。\n- **gRPC**：gRPC利用了HTTP/2的多路复用、流控制、头部压缩等特性，结合Protobuf的高效数据编码，在网络和处理性能上都有明显优势。\n\n### 3. **流式通信**：\n\n- **HTTP**：标准的HTTP是基于请求-响应的模型，不支持双向流通信。WebSocket可以实现实时双向通信，但不是HTTP本身的特性。\n- **gRPC**：gRPC原生支持双向流式通信（双向流、服务器流、客户端流），适合需要实时数据交换的场景。\n\n### 4. **类型安全**：\n\n- **HTTP**：使用JSON时，由于没有严格的类型定义，容易在服务端和客户端之间产生类型不匹配的错误。\n- **gRPC**：gRPC使用Protobuf定义服务和消息的结构，提供了强类型的接口，编译时即能发现数据结构不匹配的问题。\n\n### 5. **生态系统和兼容性**：\n\n- **HTTP**：作为Web应用的基础协议，HTTP有着广泛的生态系统支持和兼容性。几乎所有编程语言和平台都支持HTTP。\n- **gRPC**：gRPC提供了跨语言支持，但在一些特定场景下（如浏览器端）不如HTTP普遍。此外，gRPC对客户端和服务端都需要依赖Protobuf定义文件，这可能增加复杂性。\n\n\n\n\n\n# 进入容器内部，使用mysql客户端与redis-cli\n\n```bash\ndocker exec -it ordermanager1 bash\n\nmysql -uroot -p -h db   \n \nredis-cli -h redis --raw\n```\n\n\n\n# 问题\n\n## 1. mysql中文乱码\n\n1. ![image-20240828155001025](https://typora-dusong.oss-cn-chengdu.aliyuncs.com/image-20240828155001025.png)\n2. `SET NAMES 'utf8mb4';`\n3. ![image-20240828155046648](https://typora-dusong.oss-cn-chengdu.aliyuncs.com/image-20240828155046648.png)\n\n## 2. redis-cli中文显示十六进制编码\n\n- 添加`--raw`选项\n\n```\nredis-cli -h redis --raw\n```\n\n\n\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2FDusongg%2FUF2.0-TodoList-server","html_url":"https://awesome.ecosyste.ms/projects/github.com%2FDusongg%2FUF2.0-TodoList-server","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2FDusongg%2FUF2.0-TodoList-server/lists"}