EvIsX

荧 · 维思

GoFrame 示例项目 gf-demo-user

任务 一

“快速开始” 需要做什么?

  • 拉代码1到本地并阅读 README 一步步执行并跑起来

Installation

  1. You need a go development environment setup before everything starts taking off.
  2. Use git clone to clone the repo to your local folder.
  3. Import manifest/sql/create.sql to your database.
  4. Update manifest/config/config.yaml according to your local configurations if necessary.
  5. Run command go run main.go, and you’ll see something as follows if success:

数据库准备

  1. Import manifest/sql/create.sql to your database.

导入之前确保有 mysql 环境,可基于 docker 部署 mysql 容器。(以下默认基于容器部署,非容器部署略有不同)

docker (orbstack 管理) 部署 mysql

# 搜索、拉取、查看
docker search mysql
docker pull mysql
docker images
# 创建数据卷
docker volume create mysql-data
docker volume create mysql-config
docker volume create mysql-log
# 创建并运行容器
docker run -id --name=mysql -v mysql-config:/etc/mysql/conf.d \ 
-v mysql-log:/logs \
-v mysql-data:/var/lib/mysql \
-p 3306:3306 \
-e MYSQL_ROOT_PASSWORD=123456 \
-e LANG=C.UTF-8 mysql
# 参数解释
# `-id` 将MySQL容器挂在后台运行
# `--name=mysql` 将容器起名为 `mysql`
# `-v mysql-config:/etc/mysql/conf.d` 把MySQL容器中的配置文件目录挂载至上述创建的名为`mysql-config`的数据卷上面,其他两个 `-v` 挂载数据卷的参数同理
# `-p 3306:3306` 将主机的 `3306` 端口映射到容器的 `3306`
# `-e MYSQL_ROOT_PASSWORD=12345678` 设置 `root` 用户的密码为`12345678`
# `-e LANG=C.UTF-8` 设置容器的语言环境变量 `LANG` 值为 `C.UTF-8`

阅读项目默认配置

  1. Update manifest/config/config.yaml according to your local configurations if necessary.
# manifest/config/config.yaml
  default:
    link: "mysql:root:12345678@tcp(127.0.0.1:3306)/test" # 表示 databasename: test
    debug: true

sql 文件准备

将 sql 文件放入主机为容器创建的数据卷以供容器内的 mysql 访问使用。

# in project root, copy sql to docker volumes folder
cp manifest/sql/create.sql /Users/yyds/OrbStack/docker/volumes/mysql-config/

查看 sql 文件

CREATE TABLE `user`
(
    `id`        int(10) unsigned NOT NULL AUTO_INCREMENT COMMENT 'User ID',
    `passport`  varchar(45) NOT NULL COMMENT 'User Passport',
    `password`  varchar(45) NOT NULL COMMENT 'User Password',
    `nickname`  varchar(45) NOT NULL COMMENT 'User Nickname',
    `create_at` datetime DEFAULT NULL COMMENT 'Created Time',
    `update_at` datetime DEFAULT NULL COMMENT 'Updated Time',
    PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

访问 mysql 并执行项目 sql 文件

# 通过 docker 访问 mysql
docker exec -it mysql bash

由于项目 sql 文件仅创建 table 因此需要提前准备好配置访问的数据库 /test

# in mysql container
# 登录到 mysql
mysql -u root -p
## 输入密码,上面设置为 123456
-- 创建数据库,名称为 test
$mysql> CREATE DATABASE IF NOT EXISTS test DEFAULT CHARSET utf8 COLLATE utf8_general_ci;
-- 解释上面 sql 命令
-- 1. 仅不存在该数据库才创建
-- 2. 指定一些选项,如字符集和排序规则

-- 执行`SHOW DATABASES;`命令来验证数据库是否成功创建。
$mysql> SHOW DATABASES;
-- +--------------------+
-- | Database           |
-- +--------------------+
-- | information_schema |
-- | mysql              |
-- | performance_schema |
-- | sys                |
-- | test               |
-- +--------------------+
-- 5 rows in set (0.01 sec)
$mysql> \q
-- Bye

bash 命令环境导入项目的 sql 文件

# test 是上面创建的数据库
# sql 文件的路径 是因为 mysql-config 映射为: /etc/mysql/conf.d
mysql -u root -p test < /etc/mysql/conf.d/create.sql
## 输入密码,上面设置为 123456

查看是否导入成功

-- 直接
$mysql> SHOW COLUMNS FROM test.user;

-- 或e先,选择数据库:
$mysql> USE test;
-- 然后,查看`user`表的结构:
$mysql> ESCRIBE user;

-- 如
-- +-----------+--------------+------+-----+---------+----------------+
-- | Field     | Type         | Null | Key | Default | Extra          |
-- +-----------+--------------+------+-----+---------+----------------+
-- | id        | int unsigned | NO   | PRI | NULL    | auto_increment |
-- | passport  | varchar(45)  | NO   |     | NULL    |                |
-- | password  | varchar(45)  | NO   |     | NULL    |                |
-- | nickname  | varchar(45)  | NO   |     | NULL    |                |
-- | create_at | datetime     | YES  |     | NULL    |                |
-- | update_at | datetime     | YES  |     | NULL    |                |
-- +-----------+--------------+------+-----+---------+----------------+
-- 6 rows in set (0.00 sec)

运行

go run main.go
# 2024-05-07 13:05:21.464 [INFO] pid[14325]: http server started listening on [:8000]
# 2024-05-07 13:05:21.464 [INFO] {00a86ce3741ccd178cc8535f29256c90} swagger ui is serving at address: http://127.0.0.1:8000/swagger/
# 2024-05-07 13:05:21.464 [INFO] {00a86ce3741ccd178cc8535f29256c90} openapi specification is serving at address: http://127.0.0.1:8000/api.json

访问 http://127.0.0.1:8000/swagger/

测试

通过curl命令来对其中两个接口执行简单的测试1

用户注册接口

curl -d 'nickname=john&passport=test001&password=123456&password2=123456' http://127.0.0.1:8000/user/sign-up

{"code":52,"message":"SELECT COUNT(1) FROM `user`: Error 1045 (28000): Access denied for user 'root'@'192.168.215.1' (using password: YES)","data":null}% 

这里报数据库连接无权限错误,排查发现,mysql 上面设置的密码是 123456 而项目配置的连接使用的密码是 12345678。

   default:
-    link: "mysql:root:12345678@tcp(127.0.0.1:3306)/test"
+    link: "mysql:root:123456@tcp(127.0.0.1:3306)/test"
     debug: true

重启服务,再执行测试命令。

curl -d 'nickname=john&passport=test001&password=123456&password2=123456' http://127.0.0.1:8000/user/sign-up

{"code":0,"message":"","data":null}%   

再次用相同的信息执行测试(注册用户)。

curl -d 'nickname=john&passport=test001&password=123456&password2=123456' http://127.0.0.1:8000/user/sign-up

{"code":50,"message":"Passport \"test001\" is already token by others","data":null}% 

用户登录接口

curl -i -d 'passport=test001&password=123456' http://127.0.0.1:8000/user/sign-in

HTTP/1.1 200 OK
Access-Control-Allow-Credentials: true
Access-Control-Allow-Headers: Origin,Content-Type,Accept,User-Agent,Cookie,Authorization,X-Auth-Token,X-Requested-With
Access-Control-Allow-Methods: GET,PUT,POST,DELETE,PATCH,HEAD,CONNECT,OPTIONS,TRACE
Access-Control-Allow-Origin: *
Access-Control-Max-Age: 3628800
Content-Type: application/json
Server: GoFrame HTTP Server
Set-Cookie: gfsessionid=jt7br30y5x7060d135pul5lt342000l0; Path=/; Expires=Wed, 08 May 2024 05:18:39 GMT
Trace-Id: c0b7e1b12e1dcd178aa95b42073336e4
Date: Tue, 07 May 2024 05:18:39 GMT
Transfer-Encoding: chunked

{"code":0,"message":"","data":null}%  

提取 sessionid

(Set-Cookie: gfsessionid=jt7br30y5x7060d135pul5lt342000l0; Path=/; Expires=Wed, 08 May 2024 05:18:39 GMT)2

并使用(这里通过 header 的方式提交)

curl -H 'gfsessionid:jt7br30y5x7060d135pul5lt342000l0' http://127.0.0.1:8000/user/profile

{"code":0,"message":"","data":{"id":1,"passport":"test001","password":"123456","nickname":"john","createAt":"2024-05-07 05:16:38","updateAt":"2024-05-07 05:16:38"}}%  

尝试看看不提供会怎么样

curl http://127.0.0.1:8000/user/profile

Forbidden

通过 cookies 的方式提供给服务端

curl -b "gfsessionid=jt7br30y5x7060d135pul5lt342000l0" http://127.0.0.1:8000/user/profile

{"code":0,"message":"","data":{"id":1,"passport":"test001","password":"123456","nickname":"john","createAt":"2024-05-07 05:16:38","updateAt":"2024-05-07 05:16:38"}}%    

任务 二

数据库从 mysql 更换为 postgresql。需要对默认配置做如下修改:

  1. create.sql
-CREATE TABLE `user` (
-    `id` int unsigned NOT NULL AUTO_INCREMENT COMMENT 'User ID',
-    `passport` varchar(45) NOT NULL COMMENT 'User Passport',
-    `password` varchar(45) NOT NULL COMMENT 'User Password',
-    `nickname` varchar(45) NOT NULL COMMENT 'User Nickname',
-    `create_at` datetime DEFAULT NULL COMMENT 'Created Time',
-    `update_at` datetime DEFAULT NULL COMMENT 'Updated Time',
-    `delete_at` datetime DEFAULT NULL COMMENT 'Deleted Time',
-    PRIMARY KEY (`id`),
-    UNIQUE KEY `uniq_passport` (`passport`)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
+create table "user"
+(
+    id serial primary key,
+    passport  varchar(45) not null unique,
+    password  varchar(45) not null,
+    nickname  varchar(45) not null,
+    create_at timestamp,
+    update_at timestamp,
+    delete_at timestamp
+);
  1. config.yaml
  default:
-    link: "mysql:root:12345678@tcp(127.0.0.1:3306)/test"
+    link: "pgsql:postgres:postgres@tcp(localhost:5432)/test"
    debug: true

差异总结:

  • mysql 和 pgsql 语法风格不同
  • 自增主键方案不同(AUTO_INCREMENT vs serial
  • 存储引擎和字符集:mysql 需要指定,而 pgsql 不需要(或者在创建数据库时指定字符集)

docker 部署 pgsql

与 mysql 类似(最新版本的pgsql)

# 搜索、拉取、查看
docker search postgres
docker pull postgres
docker images
# 创建数据卷
docker volume create gf-pgsql-data;
# 创建并运行容器
docker run -id --name=gf-pgsql -v gf-pgsql-data:/var/lib/postgresql/data \ 
-p 5432:5432 \ 
-e POSTGRES_PASSWORD=postgres\
-e LANG=C.UTF-8 postgres
# 参数解释
# `-id` 将MySQL容器挂在后台运行
# `--name=gf-pgsql` 将容器起名为 `gf-pgsql`
# `-v gf-pgsql-data:/var/lib/postgresql/data` 把MySQL容器中的配置文件目录挂载至上述创建的名为`mysql-config`的数据卷上面,其他两个 `-v` 挂载数据卷的参数同理
# `-p 5432:5432` 将主机的 `5432` 端口映射到容器的 `5432`
# `-e POSTGRES_PASSWORD=postgres` 设置 `postgres` 用户的密码为`postgres`
# `-e LANG=C.UTF-8` 设置容器的语言环境变量 `LANG` 值为 `C.UTF-8`

差异总结

  1. 配置文件卷路径:PostgreSQL通常不需要显式的配置文件卷挂载,除非你有特定的配置文件要加载。如果确实需要加载配置文件,应该挂载到/etc/postgresql或者具体版本的子目录下,具体取决于PostgreSQL的版本和Docker镜像的构建方式。
  2. 日志卷路径:PostgreSQL的日志通常输出到标准输出,由Docker直接管理,不需要单独的日志卷。如果你想要将日志文件保存到特定位置,需要在PostgreSQL的配置中指定日志输出路径,并确保容器有权限写入该路径。

初始化 pgsql 数据库

  1. 创建数据库 test
  2. 导入 create.sql
  3. 确定初始化成果
# 通过 docker 访问 gf-pgsql
docker exec -it gf-pgsql bash
# 默认进入 root 用户,切换到 postgres 用户
$> su - postgres
$> psql
# 创建数据库 test
$psql> CREATE DATABASE test WITH ENCODING='UTF8' LC_COLLATE='en_US.utf8' LC_CTYPE='en_US.utf8' TEMPLATE=template0;
# 查看数据库
$psql> \l

将新的 create.sql 传入容器并导入数据库,比如放到 gf-pgsql-data: /var/lib/postgresql/data

# 登录到 postgres
$> psql -d test -U postgres -f /var/lib/postgresql/data/create.sql
# 查看 tables
$> psql
# 切换到 test 库
$psql> \c test
# You are now connected to database "test" as user "postgres".
# 查看表结构
$psql-test> \d user
Table "public.user"
  Column   |            Type             | Collation | Nullable |             Default              
-----------+-----------------------------+-----------+----------+----------------------------------
 id        | integer                     |           | not null | nextval('user_id_seq'::regclass)
 passport  | character varying(45)       |           | not null | 
 password  | character varying(45)       |           | not null | 
 nickname  | character varying(45)       |           | not null | 
 create_at | timestamp without time zone |           |          | 
 update_at | timestamp without time zone |           |          | 
 delete_at | timestamp without time zone |           |          | 
Indexes:
    "user_pkey" PRIMARY KEY, btree (id)
    "user_passport_key" UNIQUE CONSTRAINT, btree (passport)

差异总结

- $mysql> CREATE DATABASE IF NOT EXISTS test DEFAULT CHARSET utf8 COLLATE utf8_general_ci;
+ $psql> CREATE DATABASE test WITH ENCODING='UTF8' LC_COLLATE='en_US.utf8' LC_CTYPE='en_US.utf8' TEMPLATE=template0;

几点说明:

  • PostgreSQL不直接支持IF NOT EXISTS语法。在CREATE DATABASE命令中。如果你尝试创建一个已经存在的数据库,PostgreSQL将会报错。要避免这种情况,你可以写一个脚本来先检查数据库是否存在,或者使用psql的条件命令执行。
  • ENCODING='UTF8'指定了字符集。这是PostgreSQL支持的UTF-8编码。
  • LC_COLLATELC_CTYPE参数控制数据库的排序规则和字符分类行为。这里使用en_US.utf8作为示例,你应该根据你的具体需求选择适当的区域设置。注意,这些设置在数据库创建后不能更改。
  • TEMPLATE=template0是创建数据库的模板。template0是一个干净的模板,没有任何预先加载的对象或数据,这允许你指定自己的编码和排序规则。

总结

拉取了 demo 项目并部署运行,测试了注册、登录和获取用户信息三个接口。成功将示例项目跑起来。中途更换了数据库方案(mysql 到 pgsql)。

References

Footnotes

  1. 快速开始-示例项目 - GoFrame 2

  2. GoFrame框架默认的sessionid名称为gfsessionid,我们看到返回的Header中已经有了,并且是通过Cookie方式返回的。