结构精减

This commit is contained in:
suguo.yao 2020-03-19 20:35:09 +08:00
parent c3ba6f7afe
commit b61ba1e863
17 changed files with 575 additions and 39 deletions

5
.gitignore vendored
View File

@ -10,3 +10,8 @@
# Output of the go coverage tool, specifically when used with LiteIDE # Output of the go coverage tool, specifically when used with LiteIDE
*.out *.out
rubbish-class
logs/
*.log
go.sum

5
Makefile Normal file
View File

@ -0,0 +1,5 @@
build:
go build .
dev:
go run .

View File

@ -1,36 +0,0 @@
# rubbish-class
#### Description
{**When you're done, you can delete the content in this README and update the file with details for others getting started with your repository**}
#### Software Architecture
Software architecture description
#### Installation
1. xxxx
2. xxxx
3. xxxx
#### Instructions
1. xxxx
2. xxxx
3. xxxx
#### Contribution
1. Fork the repository
2. Create Feat_xxx branch
3. Commit your code
4. Create Pull Request
#### Gitee Feature
1. You can use Readme\_XXX.md to support different languages, such as Readme\_en.md, Readme\_zh.md
2. Gitee blog [blog.gitee.com](https://blog.gitee.com)
3. Explore open source project [https://gitee.com/explore](https://gitee.com/explore)
4. The most valuable open source project [GVP](https://gitee.com/gvp)
5. The manual of Gitee [https://gitee.com/help](https://gitee.com/help)
6. The most popular members [https://gitee.com/gitee-stars/](https://gitee.com/gitee-stars/)

View File

@ -2,11 +2,11 @@
#### 介绍 #### 介绍
{**以下是码云平台说明,您可以替换此简介** {**以下是码云平台说明,您可以替换此简介**
码云是 OSCHINA 推出的基于 Git 的代码托管平台(同时支持 SVN。专为开发者提供稳定、高效、安全的云端软件开发协作平台 垃圾分类
无论是个人、团队、或是企业,都能够用码云实现代码托管、项目管理、协作开发。企业项目请看 [https://gitee.com/enterprises](https://gitee.com/enterprises)}
#### 软件架构 #### 软件架构
软件架构说明 * PC端文件下载
* 微信小程序端用户与工作人员摄像上传并记分查询
#### 安装教程 #### 安装教程

16
admin/admin-handler.go Normal file
View File

@ -0,0 +1,16 @@
package admin
import (
"net/http"
"github.com/gin-gonic/gin"
)
//HomeHandle 基础验证试验
//HTTP基本认证(Basic Authentication)
//"用户名+冒号+密码"用BASE64算法加密后的字符串放在http request 中的header的Authorization中发送给服务端
//最终格式Authorization: Basic BASE64("用户名+冒号+密码")
func HomeHandle(c *gin.Context) {
user := c.MustGet(gin.AuthUserKey).(string)
c.JSON(http.StatusOK, user)
}

119
app/app-handler.go Normal file
View File

@ -0,0 +1,119 @@
package app
import (
"io"
"io/ioutil"
"mime/multipart"
"net/http"
"os"
"strings"
"github.com/gin-gonic/gin"
"github.com/prometheus/common/log"
)
//Indexhandle index
func Indexhandle(c *gin.Context) {
}
//Code2SessionHandle 登录凭证校验,通过 wx.login 接口获得临时登录凭证 code 后传到开发者服务器调用此接口完成登录流程。
//GET https://api.weixin.qq.com/sns/jscode2session?appid=APPID&secret=SECRET&js_code=JSCODE&grant_type=authorization_code
func Code2SessionHandler(c *gin.Context) {
jscode := c.Param("jscode")
result, err := wxa.Code2Session(jscode)
if err != nil {
log.Warn(err)
c.AbortWithStatusJSON(http.StatusBadRequest, err.Error())
return
}
c.JSON(http.StatusOK, result)
}
//HistoryVideoHandle 视频(文件)下载
func HistoryVideoHandler(c *gin.Context) {
openid := c.Param("openid")
p := "./video/" + openid
files, err := ioutil.ReadDir(p)
if err != nil {
log.Warn(err)
c.AbortWithStatusJSON(http.StatusBadRequest, err.Error())
return
}
var videos []string
for _, f := range files {
if f.IsDir() {
continue
}
if !strings.HasSuffix(f.Name(), ".mp4") {
continue
}
videos = append(videos, f.Name())
}
c.JSON(http.StatusOK, gin.H{
"videos": videos,
})
}
type newForm struct {
File *multipart.FileHeader `form:"file"`
Openid string `form:"openid"`
}
//UploadfileAndFormHandle 上传带form
func UploadfileAndFormHandler(c *gin.Context) {
var data newForm
if err := c.ShouldBind(&data); err != nil {
c.AbortWithStatusJSON(http.StatusBadRequest, err.Error)
return
}
filepath, err := SaveVideoFileService(data.File, &data.Openid)
if err != nil {
log.Warn(err)
c.AbortWithStatusJSON(http.StatusBadRequest, err.Error)
return
}
c.JSON(http.StatusOK, gin.H{
"code": 0,
"data": gin.H{
"filepath": filepath,
"openid": data.Openid,
},
})
}
//UploadHandle 小程序中文件上传,正式环境中使用云存储
func UploadHandler(c *gin.Context) {
header, err := c.FormFile("file")
if err != nil {
log.Warn(err)
c.AbortWithStatusJSON(http.StatusBadRequest, err.Error)
return
}
dst := header.Filename
src, err := header.Open()
if err != nil {
log.Warn(err)
c.AbortWithStatusJSON(http.StatusBadRequest, err.Error)
return
}
defer src.Close()
out, err := os.Create(`video/` + dst)
if err != nil {
log.Warn(err)
c.AbortWithStatusJSON(http.StatusBadRequest, err.Error)
return
}
defer out.Close()
n, err := io.Copy(out, src)
if err != nil {
log.Warn(err)
c.AbortWithStatusJSON(http.StatusBadRequest, err.Error)
return
}
c.JSON(http.StatusOK, gin.H{
"code": 0,
"data": n,
})
}

65
app/app-service.go Normal file
View File

@ -0,0 +1,65 @@
package app
import (
"io"
"mime/multipart"
"os"
"strings"
"github.com/silenceper/wechat"
"github.com/silenceper/wechat/cache"
"github.com/silenceper/wechat/miniprogram"
)
var (
wxa *miniprogram.MiniProgram
//RedisHost redis地址用于小程序缓存DB号10
RedisHost *string
)
//init先于主程序运行如何使配置生效
func init() {
// memCache := cache.NewRedis(&cache.RedisOpts{
// Host: *RedisHost,
// Database: 10,
// MaxIdle: 2,
// MaxActive: 50,
// IdleTimeout: 60,
// })
mem := cache.NewMemory()
appConfig := &wechat.Config{
AppID: "wx49cced01eec31847",
AppSecret: "0090134e4a137554a271133d7f73e633",
Cache: mem,
}
wx := wechat.NewWechat(appConfig)
wxa = wx.GetMiniProgram()
}
//SaveVideoFileService 文件上传服务
func SaveVideoFileService(file *multipart.FileHeader, openid *string) (*string, error) {
p := "./video/" + *openid
_, err := os.Stat(p)
if err != nil {
if os.IsNotExist(err) {
os.Mkdir(p, os.ModePerm)
os.Chmod(p, 0755)
}
}
src, err := file.Open()
if err != nil {
return nil, err
}
defer src.Close()
//创建 dst 文件
fn := strings.TrimLeft(file.Filename, "tmp_")
out, err := os.Create(p + `/` + fn)
if err != nil {
return nil, err
}
defer out.Close()
// 拷贝文件
_, err = io.Copy(out, src)
filename := out.Name()
return &filename, err
}

2
app/readme.md Normal file
View File

@ -0,0 +1,2 @@
# 微信小程序

9
go.mod Normal file
View File

@ -0,0 +1,9 @@
module yyjishu.com/rubbish-class
go 1.13
require (
github.com/gin-gonic/gin v1.5.0
github.com/prometheus/common v0.9.1
github.com/silenceper/wechat v1.2.3
)

52
server.go Normal file
View File

@ -0,0 +1,52 @@
package main
import (
"flag"
"net/http"
"os"
"github.com/gin-gonic/gin"
"yyjishu.com/rubbish-class/admin"
"yyjishu.com/rubbish-class/app"
)
var (
endpoint = flag.String("s", "localhost:8080", "service endpoint")
)
func main() {
flag.Parse()
//启动时检查与创建文件夹video用于存放用户上传的视频文件
_, err := os.Stat("video")
if err != nil {
if os.IsNotExist(err) {
os.Mkdir("./video", os.ModePerm)
os.Chmod("./video", 0755)
}
}
r := gin.Default()
r.Use(gin.Recovery())
r.StaticFS(`/video`, http.Dir("./video"))
authorized := r.Group(`/admin`, gin.BasicAuth(gin.Accounts{
"foo": "bar",
"admin": "admin",
}))
{
authorized.GET(`/index`, admin.HomeHandle)
}
appGroup := r.Group(`/app`)
{
appGroup.POST(`/index`, app.Indexhandle)
appGroup.GET(`/code2session/:jscode`, app.Code2SessionHandler)
appGroup.POST(`/upload`, app.UploadHandler)
appGroup.POST(`/uploadvideo`, app.UploadfileAndFormHandler)
appGroup.GET(`/history/:openid`, app.HistoryVideoHandler)
}
r.Run(*endpoint)
}

89
service.rest Normal file
View File

@ -0,0 +1,89 @@
@url=http://localhost:8080
//@url=https://api.xintijiao.com
@token=31_uHgfsKEOrH5l3EUXM_nb_u_lTL2fRwPzxGbgvOlbM9PTGHxsH9hBzvnnP-SKOf59fb0SdUwrs-wcpTKfd_I99g
@refresh_token=31_T-96lys-lZtR4B9OtRMkFOqyX_zxJNwMH6vcKxenk7enK5jeDZ6Av-Ipj9aVWr1dzdsMaCACoxbmEFKmReHwTgtQNrOpY3TdiTkM5pEyvIQ
@openid=oYmRQxLw6UKdlQsZYIkRKbWlCijI
############################### 以下微信小程序 ########################################
@jscode={{$guid}}
GET {{url}}/app/code2session/{{jscode}} HTTP/1.1
### 视频历史下载
GET {{url}}/app/history/ozgDT5KzARnML4khh70BEypaLlf8 HTTP/1.1
### 文件上传
POST {{url}}/app/upload HTTP/1.1
Content-Type: multipart/form-data; boundary=----WebKitFormBoundary7MA4YWxkTrZu0gW
------WebKitFormBoundary7MA4YWxkTrZu0gW
Content-Disposition: form-data; name="text"
title
------WebKitFormBoundary7MA4YWxkTrZu0gW
Content-Disposition: form-data; name="file"; filename="readme.txt"
Content-Type: text/plain
dsfsdfdsfsdaf 这里就是文件内容了!
t={{$timestamp}}&a={{$guid}}
------WebKitFormBoundary7MA4YWxkTrZu0gW--
### 视频上传
POST {{url}}/app/uploadvideo HTTP/1.1
Content-Type: multipart/form-data; boundary=----WebKitFormBoundary7MA4YWxkTrZu0gW
------WebKitFormBoundary7MA4YWxkTrZu0gW
Content-Disposition: form-data; name="openid"
ddddddd
------WebKitFormBoundary7MA4YWxkTrZu0gW
Content-Disposition: form-data; name="age"
12
------WebKitFormBoundary7MA4YWxkTrZu0gW
Content-Disposition: form-data; name="file"; filename="readme12.txt"
Content-Type: text/plain
这里就是文件内容了!
t={{$timestamp}}&a={{$guid}}
------WebKitFormBoundary7MA4YWxkTrZu0gW--
############################ 以下网页基础认证 ####################################
### admin http基本认证测试以下二种方式均可
GET {{url}}/admin/index HTTP/1.1
Authorization: Basic admin admin
//Authorization: Basic YWRtaW46YWRtaW4= //BASE64处理后方式
######################## 以下微信服务号及订阅号 ###############################
### wechat 验证
GET {{url}}/wechat/index?signature=cc31b8d03faab03a06d7d9fba9d2fb011650680e&echostr=2755367349555518703&timestamp=1583570152&nonce=1947789919
### wechat消息回调
POST {{url}}/wechat/index HTTP/1.1
Content-Type: application/x-www-form-urlencoded
#### wechat获取用户accesstoken
GET {{url}}/wechat/access_token/081sBRac1YXCqz0H7Abc1K20bc1sBRaM HTTP/1.1
### wechat获取用户信息
GET {{url}}/wechat/userinfo/{{token}}/{{openid}} HTTP/1.1
### wechat jssdk配置获取
GET {{url}}/wechat/jssdk?url=http%3A%2F%2F127.0.0.1%3A5500%2Fstatic%2Fsdk.html HTTP/1.1
######################### 以下开放平台 ###################################
### open 获取用户token
GET {{url}}/open/access_token/001HbLN007pXLJ1B4NO002nUN00HbLN6 HTTP/1.1
### open 刷新token
GET {{url}}/open/refresh_token/{{refresh_token}} HTTP/1.1
### open 获取用户信息
GET {{url}}/open/userinfo?token=31_mhulwBPAd-H0f8Flj6DKUZ1mfiKxlydpC0rt5bq43mPgHCaHCiZbux9C_170hu3JswLHQMxZp0xMNTXA0znpluZV3R4q_yhYf7I5BnAskSs&openid=o9DpN1RQlkdgEXM2wWGvYNo4AZmA HTTP/1.1
token: {{token}}

12
static/index.html Normal file
View File

@ -0,0 +1,12 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>微信通用框架-网页登录</title>
</head>
<body>
<a href="https://open.weixin.qq.com/connect/qrconnect?appid=wx8466bd57e3f3e42e&redirect_uri=https%3A%2F%2Fwww.xintijiao.com%2Fwechat%2Fmain.html&response_type=code&scope=snsapi_login&state=98766554#wechat_redirect">snsapi_login授权</a>
<script src="js/site.js"></script>
</body>
</html>

27
static/js/site.js Normal file
View File

@ -0,0 +1,27 @@
const url='https://api.xintijiao.com';
const tokenname="token";
function GetQueryString(name) {
var reg = new RegExp("(^|&)" + name + "=([^&]*)(&|$)");
var r = window.location.search.substr(1).match(reg);
if(r != null)
return unescape(r[2]);
return null;
}
function getUserToken(code) {
if(code != null){
$.ajaxSettings.async = false;
$.getJSON(url + '/open/access_token/' + code, function(data,ok) {
if(ok=='success') {
sessionStorage.setItem(tokenname, JSON.stringify(data));
}
});
$.ajaxSettings.async = true;
}
var userstr=sessionStorage.getItem(tokenname);
if (userstr!=null){
return JSON.parse(userstr);
}
}

52
static/main.html Normal file
View File

@ -0,0 +1,52 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>admin</title>
</head>
<body>
<div id="app">
<p>code: {{code}}</p>
<hr>
<p>access_token: {{usertoken.access_token}}</p>
<p>openid: {{usertoken.openid}}</p>
<hr>
<img :src='user.headimgurl'>
<p>nickname: {{user.nickname}}</p>
</div>
<script src="https://cdn.bootcss.com/jquery/3.4.1/jquery.min.js"></script>
<script src="https://cdn.bootcss.com/vue/2.6.11/vue.min.js"></script>
<script src="js/site.js"></script>
<script>
new Vue({
el: '#app',
data: {
code:'',
user: {},
usertoken:{},
},
methods: {
},
created: function() {
var that=this;
this.code = GetQueryString('code');
this.usertoken = getUserToken(this.code);
if (this.usertoken == null || this.usertoken.access_token == ""){
window.location.href="https://open.weixin.qq.com/connect/qrconnect?appid=wx8466bd57e3f3e42e&redirect_uri=https%3A%2F%2Fwww.xintijiao.com%2Fwechat%2Fmain.html&response_type=code&scope=snsapi_login&state=98766554#wechat_redirect";
}
$.ajax({
url:url + '/open/userinfo?token='+this.usertoken.access_token+'&openid='+this.usertoken.openid,
type:"GET",
success:function(data,ok){
if (ok=='success'){
that.user=data;
}
}
});
}
})
</script>
</body>
</html>

52
static/mobile.html Normal file
View File

@ -0,0 +1,52 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>微信通用框架</title>
</head>
<body>
<div id="app">
<p>code: {{code}}</p>
<hr>
<p>openid: {{usertoken.openid}}</p>
<p>access token: {{usertoken.access_token}}</p>
<hr>
<img :src='user.headimgurl'>
<p>nickname: {{user.nickname}}</p>
<p>province: {{user.province}}</p>
<p>city: {{user.city}}</p>
</div>
<script src="https://cdn.bootcss.com/jquery/3.4.1/jquery.min.js"></script>
<script src="https://cdn.bootcss.com/vue/2.6.11/vue.min.js"></script>
<script src="js/site.js"></script>
<script>
new Vue({
el:'#app',
data: {
user:{},
usertoken:{},
code:'',
},
created () {
var that=this;
this.code = GetQueryString('code');
$.ajaxSettings.async = false; //同步执行
$.getJSON(url + '/wechat/access_token/' + this.code, function(data,status) {
if (status == "success"){
sessionStorage.setItem('token', JSON.stringify(data));
}
var userstring=sessionStorage.getItem('token');
that.usertoken=JSON.parse(userstring);
});
$.getJSON(url+'/wechat/userinfo/'+that.usertoken.access_token+'/'+that.usertoken.openid,function(data,status){
if(status=="success"){
that.user=data;
}
});
$.ajaxSettings.async = true; //恢复异步执行
}
});
</script>
</body>
</html>

55
static/sdk.html Normal file
View File

@ -0,0 +1,55 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>JSSDK</title>
<link href="https://cdn.bootcss.com/weui/2.2.0/style/weui.min.css" rel="stylesheet">
</head>
<body>
<div>
<p>注意此页面功能要在微信开发工具中进行调试!!!</p>
</div>
<script src="https://cdn.bootcss.com/jquery/3.4.1/jquery.min.js"></script>
<script src="https://res.wx.qq.com/open/js/jweixin-1.6.0.js"></script>
<script src="js/site.js"></script>
<script>
wx.ready(function(){
//检查jsapi
wx.checkJsApi({
jsApiList: ['chooseImage'],
success: function(res) {
console.log(res);
}
});
//分享给朋友的配置
wx.updateAppMessageShareData({
title:'模拟网页',
desc:'模拟网页模拟网页模拟网页模拟网页',
link:'https://www.xintijiao.com/wechat/sdk.html',
imgUrl:'https://www.xintijiao.com/img/sitelogo.af54d163.png',
success:function(){
console.log('配置成功');
}
});
});
wx.error(function(res){
console.log(res);
});
$(function(){
$.getJSON(url+"/wechat/jssdk?url="+encodeURIComponent(window.location.href),function(res,status){
if (status=='success'){
wx.config({
debug:true,
appId:res.app_id,
timestamp:res.timestamp,
nonceStr:res.nonce_str,
signature:res.signature,
jsApiList:["getLocation","updateAppMessageShareData","updateTimelineShareData","chooseImage","previewImage"],
});
}
});
});
</script>
</body>
</html>

12
static/sign.html Normal file
View File

@ -0,0 +1,12 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>微信通用框架</title>
</head>
<body>
<a href="https://open.weixin.qq.com/connect/oauth2/authorize?appid=wx3ac2549f640d5800&redirect_uri=https%3A%2F%2Fwww.xintijiao.com%2Fwechat%2Fmobile.html&response_type=code&scope=snsapi_base&state=12345678#wechat_redirec">snsapi_base授权</a>
<a href="https://open.weixin.qq.com/connect/oauth2/authorize?appid=wx3ac2549f640d5800&redirect_uri=https%3A%2F%2Fwww.xintijiao.com%2Fwechat%2Fmobile.html&response_type=code&scope=snsapi_userinfo&state=12345678#wechat_redirec">snsapi_userinfo授权</a>
</body>
</html>