作业个人总结
作业个人总结
博客班级 | https://edu.cnblogs.com/campus/zjcsxy/SE2020 |
---|---|
作业要求 | https://edu.cnblogs.com/campus/zjcsxy/SE2020/homework/11633 |
姓名 | 郭浩源 |
学号 | 31801201 |
院系 班级 | 浙大城市学院计算机系 计算1803 |
个人任务
- 后端API接口
- 静态图片服务器配置
完成情况
后端API接口
详细接口信息在https://www.showdoc.com.cn/passtest?page_id=5863047982283518
后端接口分为以下这些,具体如何用golang
实现后面再介绍
用户反馈
用户反馈这里做了两次转发,首先是向下方的请求URL发送所有数据,在这个URL对应的服务器上对图片解码,并将图片保存在此服务器上,然后向后端服务器发送对应该服务器的图片访问地址
请求URL
https://app.morii.top/feedback
请求方式
- POST
参数
参数名 | 必选 | 类型 | 说明 |
---|---|---|---|
openid | 是 | int | 用户id |
feedback_type | 是 | string | 反馈类型 |
contact_info | 否 | string | 联系方式 |
feedback_content | 是 | string | 反馈内容 |
imagelist | 否 | list |
图片 |
用户注册
请求URL
http://api.zghy.xyz/api/user/login
请求方式
- POST
参数
参数名 | 必选 | 类型 | 说明 |
---|---|---|---|
code | 是 | string | wx.login获取的临时登录凭证 |
nickname | 是 | string | 昵称 |
gender | 是 | int | 性别 |
用户信息
请求URL
http://api.zghy.xyz/api/user/info
请求方式
- POST
参数
参数名 | 必选 | 类型 | 说明 |
---|---|---|---|
openid | 是 | string | 用户openid |
birthday | 是 | date | 格式 2016-01-01 |
gender | 是 | int | 1:男,2:女 |
获得题目参数
请求URL
https://api.zghy.xyz/api/test/configuration
请求方式
- POST
参数
参数名 | 必选 | 类型 | 说明 |
---|---|---|---|
age_group | 是 | number | 0:10岁以下,1:10岁以上 |
test_id | 是 | string | 题目编号 |
获得题目详细内容
请求URL
https://api.zghy.xyz/api/test/detail
请求方式
- POST
参数
参数名 | 必选 | 类型 | 说明 |
---|---|---|---|
test_id | 是 | string | 题目编号 |
category | 是 | int | 表示难度或分类 |
num | 是 | int | 题目数量 |
提交测试成绩
请求URL
https://api.zghy.xyz/api/test/submit
请求方式
- POST
参数
参数名 | 必选 | 类型 | 说明 |
---|---|---|---|
openid | 是 | string | 用户id |
age | 是 | int | 用户年龄 |
score | 是 | array | 用户得分 |
+plan_score | 是 | double | 计划测试得分 |
+attention_score | 是 | double | 注意测试得分 |
+simul_score | 是 | double | 同时性测试得分 |
+suc_score | 是 | double | 继时性测试得分 |
+total_score | 是 | double | 综合得分 |
cost_time | 是 | int | 测试耗时 |
排行榜
请求URL
https://api.zghy.xyz/api/test/ranklist
请求方式
- POST
参数
参数名 | 必选 | 类型 | 说明 |
---|---|---|---|
openid | 是 | int | 用户id |
age | 是 | int | 用户年龄 |
type | 是 | string | P:计划,A:注意,S1:同时,S2:继时,T:综合 |
page_num | 是 | int | 查询页码 |
list_num | 是 | int | 查询记录数 |
历史测试
请求URL
http://api.zghy.xyz/api/test/gethistory
请求方式
- POST
参数
参数名 | 必选 | 类型 | 说明 |
---|---|---|---|
openid | 是 | string | 用户id |
testyear | 是 | int | 测试年份 |
testmonth | 是 | int | 测试月份 |
查询测试详细结果
请求URL
https://api.zghy.xyz/api/test/getresult
请求方式
- POST
参数
参数名 | 必选 | 类型 | 说明 |
---|---|---|---|
testid | 是 | int | 测试编号 |
静态图片服务器配置
静态图片服务器在nginx中配置信息如下
端口配置在23333端口,服务器的图片存放地址通过root /root/workspace/passgo/images/
来指定,可以直接通过23333端口访问来自root这个位置的图片。在后端中只需要先将图片存放到这个静态服务器上,再通过这个服务器把访问这个图片的地址存放到数据库中,这样就可以避免图片的数据直接存放在数据库中。
这里静态图片服务器写了python flask
进行数据接收以及post转发。
server {
listen 23333;
server_name localhost;
#charset utf-8;
#access_log logs/host.access.log main;
location ~ .*\.(gif|jpg|jpeg|png)$ {
root /root/workspace/passgo/images/; #指定图片存放路径
proxy_store on; #启用缓存到本地的功能
proxy_store_access user:rw group:rw all:rw; #设置权限
proxy_redirect off;
proxy_set_header Host 127.0.0.1;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
client_body_buffer_size 1280k; #设置请求体缓冲区大小
proxy_connect_timeout 900; #连接超时
proxy_send_timeout 900; #发送超时
proxy_read_timeout 900; #读取超时
proxy_buffer_size 40k; #设置缓冲区大小,从代理后端服务器取得的第一部分的响应内容,会放到这里
proxy_buffers 40 320k;
proxy_busy_buffers_size 640k;
proxy_temp_file_write_size 640k;
}
}
总结
用golang完成一个后端程序是怎样的体验
我的go程序目录如下
build
目录是编译后的go文件,可以直接在服务器上运行(需要设置为可执行权限)driver
数据库连接池的建立,在程序开始的时候会调用连接池的创建models
通过数据库连接查询出来的数据表结构体struct
pkg
和src
是go get 命令获取的第三方包。这里使用gin
搭建web框架,go-sql-driver
建立数据库连接池连接数据库。gin.log
存放gin的日志文件,本来是输出在终端,我将他保存在文件里了goget.sh
包含需要获取的第三方包内容Main.go
go主程序
目录介绍完了,接下来简单介绍一下为什么要用go来完成这个后端
Go 语言被设计成一门应用于搭载 Web 服务器,存储集群或类似用途的巨型中央服务器的系统编程语言。对于高性能分布式系统领域而言,Go 语言无疑比大多数其它语言有着更高的开发效率。
之前有准备继续用python flask来搭建后端,但是后来看到一篇文章,上面进行了一项高并发测试,go的速度比python快了1000倍。一个是us级,一个是ms级,没得比。当然go代码成本很高,并不像python这样的解释型语言写起来方便。go和C语言非常像,但是go的要求更加苛刻,没有被用到的变量就不能被定义,如果你定义了一个毫无用处的变量,这个程序根本无法编译。
在写go后端的时候我大概遇到了下面这几个很难受的问题
时间转换问题
数据库中对于时间有三种类型,date、datetime、timestamp。在我们这个项目中用到了date和datetime这两种类型。
首先一定要在连接数据库的地方加上parseTime=false
,不然拿到的就是一个被连接池事先解析过的时间,这样的时间是无法被golang中的time库进行解析的。
golang中的时间解析也非常的奇怪time.Parse("2006-01-02 15:04:05", registerTime)
,他需要输入一个固定的时间,而这个时间查了以后才知道是go语言诞生的时间。
当然在我们想要把时间插入数据库的时候,直接通过time.Now()
方式获取的时间是无法插入的,需要使用time.Format("2006-01-02 15:04:05")
的方式将时间再转换一次,用起来比较麻烦。
json处理
看完这张图应该懂的都懂了。
当然我还是使用了官方的json库,因为试了第三方的json库,对于json数据的生成感觉不太友好(也可能只是我不太会用)
在生成json的时候,我们需要先创建一个map,map是key-value的形式,和json这样key-value的形式非常像,所以map转为json会很方便,当然也可以使用结构体。
一般我都需要先创建这样一个result map,然后通过key-value的方式加上数据。这里的interface指任何类型,这样就和json更像了。然后通过json.Marshal
这个方法就可以转为一个json类型,并通过gin的web框架返回这个json给发送post的ip
result := make(map[string]interface{})
result["error_code"] = 0
mapJson, err := json.Marshal(result)
checkErr(err)
c.JSON(200, string(mapJson))
异常捕获
写过python或者java的都知道,异常捕获真香,他可以避免程序的因为这个异常而退出,只需要用类似try catch这样的语句就可以将可能报错的语句进行异常捕获。而在go中并没有这样的try catch。
在go中的异常捕获需要用panic
和recover
这两个方法进行实现。panic
用来抛出异常,recover
用来获取panic
丢出的异常,并保持程序正常运行。
所以在每个post请求的回调函数中,我都需要先用defer
的方式设置一个recover
。比如说我们这里的用户登录,如果在接收到的post
数据包中没有code
这个字段的值,就可以通过panic
来抛出一个异常让recover
提前捕获,防止后面因为这个问题而造成其他的程序奔溃。
func recoverErr() {
if err := recover(); err != nil {
log.Println(err)
fmt.Println("程序捕获,继续执行")
}
}
func userLogin(c *gin.Context) {
defer recoverErr()
code := c.PostForm("code")
if code == "" {
result["error_code"] = 10001
mapJson, err := json.Marshal(result)
checkErr(err)
c.JSON(200, string(mapJson))
panic("code" + "字段为空")
}
}
简单来说就是go里面的异常捕获是通过异常的提前处理来防止程序异常终止的。
目前一些基本的POST的请求都部署好了,接下来就是配合管理员的前端写一些管理员需要用到的接口了。