GoFrame 示例项目 gf-demo-user
任务 一
“快速开始” 需要做什么?
Installation
- You need a go development environment setup before everything starts taking off.
- Use
git clone
to clone the repo to your local folder.- Import
manifest/sql/create.sql
to your database.- Update
manifest/config/config.yaml
according to your local configurations if necessary.- Run command
go run main.go
, and you’ll see something as follows if success:
数据库准备
- 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`
阅读项目默认配置
- 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。需要对默认配置做如下修改:
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
+);
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
vsserial
) - 存储引擎和字符集: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`
差异总结
- 配置文件卷路径:PostgreSQL通常不需要显式的配置文件卷挂载,除非你有特定的配置文件要加载。如果确实需要加载配置文件,应该挂载到
/etc/postgresql
或者具体版本的子目录下,具体取决于PostgreSQL的版本和Docker镜像的构建方式。 - 日志卷路径:PostgreSQL的日志通常输出到标准输出,由Docker直接管理,不需要单独的日志卷。如果你想要将日志文件保存到特定位置,需要在PostgreSQL的配置中指定日志输出路径,并确保容器有权限写入该路径。
初始化 pgsql 数据库
- 创建数据库 test
- 导入
create.sql
- 确定初始化成果
# 通过 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_COLLATE
和LC_CTYPE
参数控制数据库的排序规则和字符分类行为。这里使用en_US.utf8
作为示例,你应该根据你的具体需求选择适当的区域设置。注意,这些设置在数据库创建后不能更改。TEMPLATE=template0
是创建数据库的模板。template0
是一个干净的模板,没有任何预先加载的对象或数据,这允许你指定自己的编码和排序规则。
总结
拉取了 demo 项目并部署运行,测试了注册、登录和获取用户信息三个接口。成功将示例项目跑起来。中途更换了数据库方案(mysql 到 pgsql)。
References
Footnotes
-
GoFrame
框架默认的sessionid
名称为gfsessionid
,我们看到返回的Header
中已经有了,并且是通过Cookie
方式返回的。 ↩