作业个人总结
作业个人总结
| 博客班级 | 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通过数据库连接查询出来的数据表结构体structpkg和src是go get 命令获取的第三方包。这里使用gin搭建web框架,go-sql-driver建立数据库连接池连接数据库。gin.log存放gin的日志文件,本来是输出在终端,我将他保存在文件里了goget.sh包含需要获取的第三方包内容Main.gogo主程序
目录介绍完了,接下来简单介绍一下为什么要用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的请求都部署好了,接下来就是配合管理员的前端写一些管理员需要用到的接口了。

浙公网安备 33010602011771号