Kaynağa Gözat

frist commit

zjxpcyc 6 yıl önce
işleme
ba97428cdb
12 değiştirilmiş dosya ile 588 ekleme ve 0 silme
  1. 2
    0
      .gitignore
  2. 18
    0
      conf/app.conf
  3. 29
    0
      conf/db.conf
  4. 72
    0
      controllers/base.go
  5. 107
    0
      controllers/h5.go
  6. 15
    0
      main.go
  7. 97
    0
      models/h5.go
  8. 13
    0
      models/model/ta_customer.go
  9. 57
    0
      models/models.go
  10. 24
    0
      routers/router.go
  11. 38
    0
      tests/default_test.go
  12. 116
    0
      utils/wechat.go

+ 2
- 0
.gitignore Dosyayı Görüntüle

@@ -0,0 +1,2 @@
1
+*.exe
2
+*.exe~

+ 18
- 0
conf/app.conf Dosyayı Görüntüle

@@ -0,0 +1,18 @@
1
+appname = h5-2019
2
+httpport = 8080
3
+runmode = dev
4
+autorender = false
5
+copyrequestbody = true
6
+EnableDocs = true
7
+sessionon = true
8
+
9
+
10
+[wechat]
11
+appid = wx776f26b70b03902b
12
+secret = 36ad3e2017a77cb4005770bfa405d7b1
13
+wxid = gh_1ec36e12f0a9
14
+token = yansenisashit
15
+aeskey =
16
+
17
+# 最后要加 /
18
+service = http://localhost:9000/

+ 29
- 0
conf/db.conf Dosyayı Görüntüle

@@ -0,0 +1,29 @@
1
+; 数据库类型,目前只支持mysql
2
+db_type      = mysql
3
+
4
+; 连接协议
5
+con_protocol = tcp
6
+
7
+; 数据库地址,可以使用IP
8
+db_addr      = rm-uf6z3z6jq11x653d77o.mysql.rds.aliyuncs.com
9
+
10
+; 端口
11
+db_port      = 3306
12
+
13
+; 用户名
14
+username     = h5-2019
15
+
16
+; 密码
17
+password     = 8YTxJn2zgljIBikv
18
+
19
+; 数据库名或者schema
20
+database     = h5-2019
21
+
22
+; 前缀,目前尚未使用
23
+dbprefix     = 
24
+
25
+; 模式,目前尚未使用
26
+db_debug     = false
27
+
28
+; 字符集
29
+char_set     = utf8

+ 72
- 0
controllers/base.go Dosyayı Görüntüle

@@ -0,0 +1,72 @@
1
+package controllers
2
+
3
+import (
4
+	"h5-2019/utils"
5
+	"reflect"
6
+
7
+	"github.com/astaxie/beego"
8
+
9
+	"net/http"
10
+)
11
+
12
+//Message api统一的返回消息格式
13
+type Message struct {
14
+	Code    int         `json:"code"`
15
+	Message interface{} `json:"message"`
16
+}
17
+
18
+//BaseController 基础controller
19
+type BaseController struct {
20
+	beego.Controller
21
+}
22
+
23
+const (
24
+	SESSION_USER = "h5.user"
25
+	PAGENUM      = 10
26
+	LISTPAGENUM  = 20
27
+)
28
+
29
+// BaseControllerInterface 项目约定的 Controller 须满足的接口
30
+type BaseControllerInterface interface {
31
+	Constructor()
32
+}
33
+
34
+//Prepare 继承beego的
35
+func (c *BaseController) Prepare() {
36
+	// 微信初始化
37
+	utils.WechatInit()
38
+
39
+	// 路由对应的实际 Controller 初始化
40
+	c.initController()
41
+}
42
+
43
+// ResponseJson 自定义的JSON返回
44
+func (c *BaseController) ResponseJson(msg interface{}, code ...int) {
45
+	status := http.StatusOK
46
+	if len(code) > 0 {
47
+		status = code[0]
48
+	}
49
+
50
+	if reflect.ValueOf(msg).Type().String() == "*errors.errorString" {
51
+		err := msg.(error)
52
+		c.Data["json"] = Message{status, err.Error()}
53
+	} else {
54
+		c.Data["json"] = Message{status, msg}
55
+	}
56
+
57
+	c.ServeJSON()
58
+	c.StopRun()
59
+}
60
+
61
+// initAppController 执行当前路由请求对应的 Controller 初始化
62
+func (c *BaseController) initController() {
63
+	if ctrl, ok := c.AppController.(BaseControllerInterface); ok {
64
+		ctrl.Constructor()
65
+	}
66
+}
67
+
68
+func (c *BaseController) WechatAppID() {
69
+	c.ResponseJson(map[string]interface{}{
70
+		"appid": beego.AppConfig.String("wechat::appid"),
71
+	})
72
+}

+ 107
- 0
controllers/h5.go Dosyayı Görüntüle

@@ -0,0 +1,107 @@
1
+package controllers
2
+
3
+import (
4
+	"errors"
5
+	"h5-2019/models"
6
+	"h5-2019/models/model"
7
+	"h5-2019/utils"
8
+	"net/http"
9
+
10
+	"github.com/astaxie/beego"
11
+)
12
+
13
+// H5Controller 基础controller
14
+type H5Controller struct {
15
+	dao *models.H5Model
16
+	BaseController
17
+}
18
+
19
+// Constructor 初始化
20
+func (c *H5Controller) Constructor() {
21
+	c.dao = new(models.H5Model)
22
+}
23
+
24
+// GetCustomer 获取用户及分享信息
25
+func (c *H5Controller) GetCustomer() {
26
+	code := c.GetString("code")
27
+	link := c.GetString("link")
28
+
29
+	// 已经存在的用户直接从数据库拿
30
+	userID := 0
31
+	userSesn := c.GetSession(SESSION_USER)
32
+	if userSesn != nil {
33
+		userID, _ = userSesn.(int)
34
+	}
35
+
36
+	var err error
37
+	user := new(model.TaCustomer)
38
+	if userID > 0 {
39
+		user, err = c.dao.GetCustomer(userID)
40
+		if err != nil {
41
+			beego.Error("获取用户信息失败:", err.Error())
42
+			c.ResponseJson(errors.New("获取用户信息失败"), http.StatusInternalServerError)
43
+		}
44
+	} else {
45
+		// 不存在的用户,则保存入库
46
+		if res, err := utils.GetUserInfo(code); err != nil {
47
+			beego.Error("获取微信用户失败:", err.Error())
48
+			c.ResponseJson(errors.New("获取微信用户失败"), http.StatusInternalServerError)
49
+		} else if user, err = c.dao.SaveCustomer(res.(map[string]interface{})); err != nil {
50
+			beego.Error("校验微信用户失败:", err.Error())
51
+			c.ResponseJson(errors.New("校验微信用户失败"), http.StatusInternalServerError)
52
+		}
53
+	}
54
+
55
+	// 获取分享 ticket
56
+	res, err := utils.GetJSTicket(link)
57
+	if err != nil {
58
+		c.ResponseJson(errors.New("微信分享设置校验失败"), http.StatusInternalServerError)
59
+	}
60
+
61
+	c.SetSession(SESSION_USER, user.Id)
62
+
63
+	c.ResponseJson(map[string]interface{}{
64
+		"user":  user,
65
+		"share": res,
66
+	})
67
+}
68
+
69
+// PutShare 更新分享记录
70
+func (c *H5Controller) PutShare() {
71
+	userSesn := c.GetSession(SESSION_USER)
72
+	if userSesn == nil {
73
+		c.ResponseJson(errors.New("记录分享失败, 请重新获取用户信息"), http.StatusUnauthorized)
74
+	}
75
+
76
+	userID, _ := userSesn.(int)
77
+	if userID == 0 {
78
+		c.ResponseJson(errors.New("未知错误, 请重新获取用户信息"), http.StatusUnauthorized)
79
+	}
80
+
81
+	if err := c.dao.SharePage(userID); err != nil {
82
+		beego.Error("记录分享失败:", err.Error())
83
+		c.ResponseJson(errors.New("记录分享失败"), http.StatusInternalServerError)
84
+	}
85
+
86
+	c.ResponseJson("ok")
87
+}
88
+
89
+// GetTotalShare 获取分享总数
90
+func (c *H5Controller) GetTotalShare() {
91
+	total, err := c.dao.TotalShareNum()
92
+	if err != nil {
93
+		beego.Error("获取分享总数失败:", err.Error())
94
+		c.ResponseJson(errors.New("获取分享总数失败"), http.StatusInternalServerError)
95
+	}
96
+
97
+	custnum, err := c.dao.TotalCustomer()
98
+	if err != nil {
99
+		beego.Error("获取人数失败:", err.Error())
100
+		c.ResponseJson(errors.New("获取人数失败"), http.StatusInternalServerError)
101
+	}
102
+
103
+	c.ResponseJson(map[string]interface{}{
104
+		"total":   total,
105
+		"custnum": custnum,
106
+	})
107
+}

+ 15
- 0
main.go Dosyayı Görüntüle

@@ -0,0 +1,15 @@
1
+package main
2
+
3
+import (
4
+	_ "h5-2019/routers"
5
+
6
+	"github.com/astaxie/beego"
7
+)
8
+
9
+func main() {
10
+	if beego.BConfig.RunMode == "dev" {
11
+		beego.BConfig.WebConfig.DirectoryIndex = true
12
+		beego.BConfig.WebConfig.StaticDir["/swagger"] = "swagger"
13
+	}
14
+	beego.Run()
15
+}

+ 97
- 0
models/h5.go Dosyayı Görüntüle

@@ -0,0 +1,97 @@
1
+package models
2
+
3
+import (
4
+	"h5-2019/models/model"
5
+	"time"
6
+
7
+	"github.com/astaxie/beego"
8
+)
9
+
10
+// H5Model model
11
+type H5Model struct{}
12
+
13
+// GetCustomer 获取
14
+func (m *H5Model) GetCustomer(id int) (*model.TaCustomer, error) {
15
+	cust := model.TaCustomer{}
16
+	_, err := Dao.Where("id=?", id).Get(&cust)
17
+	if err != nil {
18
+		return nil, err
19
+	}
20
+
21
+	return &cust, nil
22
+}
23
+
24
+// SaveCustomer 新增
25
+func (m *H5Model) SaveCustomer(mem map[string]interface{}) (*model.TaCustomer, error) {
26
+	cust := model.TaCustomer{}
27
+	openid := mem["openid"].(string)
28
+
29
+	if _, err := Dao.Where("openid=?", openid).Get(&cust); err != nil {
30
+		beego.Error("查询错误->", err)
31
+		return nil, err
32
+	}
33
+
34
+	beego.Info("获取到用户信息, ", cust)
35
+
36
+	cust.Nickyname = mem["nickname"].(string)
37
+	cust.Headimgurl = mem["headimgurl"].(string)
38
+
39
+	if cust.Openid != "" {
40
+		// 如果用户已经存在, 则更新
41
+		if _, err := Dao.Where("openid=?", openid).
42
+			Cols([]string{"nickyname", "headimgurl"}...).
43
+			Update(&cust); err != nil {
44
+			beego.Error("更新错误->", err)
45
+			return nil, err
46
+		}
47
+		return &cust, nil
48
+	}
49
+
50
+	cust.Openid = openid
51
+	cust.Unionid, _ = mem["unionid"].(string)
52
+	cust.CreateDate = time.Now().Local()
53
+	cust.Sharedpage = 0
54
+
55
+	_, err := Dao.Insert(&cust)
56
+	if err != nil {
57
+		return nil, err
58
+	}
59
+
60
+	return &cust, nil
61
+}
62
+
63
+// SharePage 分享
64
+func (m *H5Model) SharePage(id int) error {
65
+	sql := `
66
+		update ta_customer
67
+		set sharedpage = IFNULL(sharedpage,0) + 1
68
+		where id = ?
69
+	`
70
+
71
+	_, err := Dao.Exec(sql, id)
72
+	return err
73
+}
74
+
75
+// TotalShareNum 获取总次数
76
+func (m *H5Model) TotalShareNum() (int64, error) {
77
+	query := `select sum(IFNULL(sharedpage,0)) as total from ta_customer`
78
+
79
+	var total []int64
80
+	if err := Dao.SQL(query).Find(&total); err != nil {
81
+		return 0, err
82
+	}
83
+
84
+	return total[0], nil
85
+}
86
+
87
+// TotalCustomer 获取总人数
88
+func (m *H5Model) TotalCustomer() (int64, error) {
89
+	query := `select count(1) as total from ta_customer`
90
+
91
+	var total []int64
92
+	if err := Dao.SQL(query).Find(&total); err != nil {
93
+		return 0, err
94
+	}
95
+
96
+	return total[0], nil
97
+}

+ 13
- 0
models/model/ta_customer.go Dosyayı Görüntüle

@@ -0,0 +1,13 @@
1
+package model
2
+
3
+import "time"
4
+
5
+type TaCustomer struct {
6
+	Id         int       `xorm:"not null pk autoincr INT(11)"`
7
+	Openid     string    `xorm:"VARCHAR(128)"`
8
+	Nickyname  string    `xorm:"VARCHAR(255)"`
9
+	Headimgurl string    `xorm:"TEXT"`
10
+	Unionid    string    `xorm:"VARCHAR(128)"`
11
+	CreateDate time.Time `xorm:"DATETIME"`
12
+	Sharedpage int       `xorm:"SMALLINT(6)"`
13
+}

+ 57
- 0
models/models.go Dosyayı Görüntüle

@@ -0,0 +1,57 @@
1
+package models
2
+
3
+import (
4
+	"github.com/astaxie/beego/config"
5
+	_ "github.com/go-sql-driver/mysql"
6
+	"github.com/go-xorm/xorm"
7
+)
8
+
9
+var (
10
+	Dao *xorm.Engine
11
+)
12
+
13
+func init() {
14
+	Dao = NewDAO()
15
+}
16
+
17
+// NewDAO 初始化数据库连接
18
+func NewDAO() *xorm.Engine {
19
+	dbType := "mysql"
20
+	dns := getMysqlDns()
21
+
22
+	dao, err := xorm.NewEngine(dbType, dns)
23
+	// dao.ShowSQL()
24
+
25
+	if err != nil {
26
+		panic(err)
27
+		return nil
28
+	}
29
+
30
+	Dao = dao
31
+	return dao
32
+}
33
+
34
+func getMysqlDns() string {
35
+	dbconf, _ := config.NewConfig("ini", "conf/db.conf")
36
+
37
+	// db_type  := dbconf.DefaultString("db_type", "mysql")
38
+	conProt := dbconf.DefaultString("con_protocol", "tcp")
39
+	dbAddr := dbconf.DefaultString("db_addr", "localhost")
40
+	dbPort := dbconf.DefaultString("db_port", "3306")
41
+	userName := dbconf.DefaultString("username", "root")
42
+	password := dbconf.String("password")
43
+	database := dbconf.String("database")
44
+	// dbprefix := dbconf.String("dbprefix")
45
+	// db_debug := dbconf.DefaultBool("db_debug", false)
46
+	charSet := dbconf.DefaultString("char_set", "utf8")
47
+
48
+	dns := userName
49
+
50
+	if len(password) > 0 {
51
+		dns += ":" + password
52
+	}
53
+
54
+	dns += "@" + conProt + "(" + dbAddr + ":" + dbPort + ")" + "/" + database + "?charset=" + charSet
55
+
56
+	return dns
57
+}

+ 24
- 0
routers/router.go Dosyayı Görüntüle

@@ -0,0 +1,24 @@
1
+// @APIVersion 1.0.0
2
+// @Title beego Test API
3
+// @Description beego has a very cool tools to autogenerate documents for your API
4
+// @Contact astaxie@gmail.com
5
+// @TermsOfServiceUrl http://beego.me/
6
+// @License Apache 2.0
7
+// @LicenseUrl http://www.apache.org/licenses/LICENSE-2.0.html
8
+package routers
9
+
10
+import (
11
+	"h5-2019/controllers"
12
+
13
+	"github.com/astaxie/beego"
14
+)
15
+
16
+func init() {
17
+	ns := beego.NewNamespace("/api",
18
+		beego.NSRouter("/appid", &controllers.BaseController{}, "get:WechatAppID"),
19
+		beego.NSRouter("/user", &controllers.H5Controller{}, "get:GetCustomer"),
20
+		beego.NSRouter("/share", &controllers.H5Controller{}, "get:GetTotalShare"),
21
+		beego.NSRouter("/share", &controllers.H5Controller{}, "put:PutShare"),
22
+	)
23
+	beego.AddNamespace(ns)
24
+}

+ 38
- 0
tests/default_test.go Dosyayı Görüntüle

@@ -0,0 +1,38 @@
1
+package test
2
+
3
+import (
4
+	"net/http"
5
+	"net/http/httptest"
6
+	"testing"
7
+	"runtime"
8
+	"path/filepath"
9
+	_ "h5-2019/routers"
10
+
11
+	"github.com/astaxie/beego"
12
+	. "github.com/smartystreets/goconvey/convey"
13
+)
14
+
15
+func init() {
16
+	_, file, _, _ := runtime.Caller(1)
17
+	apppath, _ := filepath.Abs(filepath.Dir(filepath.Join(file, ".." + string(filepath.Separator))))
18
+	beego.TestBeegoInit(apppath)
19
+}
20
+
21
+// TestGet is a sample to run an endpoint test
22
+func TestGet(t *testing.T) {
23
+	r, _ := http.NewRequest("GET", "/v1/object", nil)
24
+	w := httptest.NewRecorder()
25
+	beego.BeeApp.Handlers.ServeHTTP(w, r)
26
+
27
+	beego.Trace("testing", "TestGet", "Code[%d]\n%s", w.Code, w.Body.String())
28
+
29
+	Convey("Subject: Test Station Endpoint\n", t, func() {
30
+	        Convey("Status Code Should Be 200", func() {
31
+	                So(w.Code, ShouldEqual, 200)
32
+	        })
33
+	        Convey("The Result Should Not Be Empty", func() {
34
+	                So(w.Body.Len(), ShouldBeGreaterThan, 0)
35
+	        })
36
+	})
37
+}
38
+

+ 116
- 0
utils/wechat.go Dosyayı Görüntüle

@@ -0,0 +1,116 @@
1
+package utils
2
+
3
+import (
4
+	"encoding/json"
5
+	"fmt"
6
+	"io"
7
+	"io/ioutil"
8
+	"net/http"
9
+
10
+	"github.com/astaxie/beego"
11
+	"github.com/zjxpcyc/request"
12
+)
13
+
14
+type WxResult struct {
15
+	Code    int
16
+	Message string
17
+	Result  interface{}
18
+}
19
+
20
+var wechatInited = false
21
+
22
+// WechatInit 微信初始化
23
+func WechatInit() error {
24
+	if wechatInited {
25
+		return nil
26
+	}
27
+
28
+	wxconf, err := beego.AppConfig.GetSection("wechat")
29
+	if err != nil {
30
+		beego.Error("获取微信配置失败: ", err.Error())
31
+		return err
32
+	}
33
+
34
+	config := request.NewConfig(wxconf["service"] + "wx/register")
35
+	config.AddParam("appid", wxconf["appid"])
36
+	config.AddParam("secret", wxconf["secret"])
37
+	config.AddParam("token", wxconf["token"])
38
+	config.AddParam("aeskey", wxconf["aeskey"])
39
+	config.Method = http.MethodPost
40
+
41
+	_, err = Request(config)
42
+	if err == nil {
43
+		wechatInited = true
44
+	}
45
+
46
+	return err
47
+}
48
+
49
+// GetUserInfo 获取个人信息
50
+func GetUserInfo(code string) (interface{}, error) {
51
+	wxconf, err := beego.AppConfig.GetSection("wechat")
52
+	if err != nil {
53
+		beego.Error("获取微信配置失败: ", err.Error())
54
+		return nil, err
55
+	}
56
+
57
+	config := request.NewConfig(wxconf["service"] + "wx/userinfo")
58
+	config.AddParam("appid", wxconf["appid"])
59
+	config.AddParam("code", code)
60
+	config.Method = http.MethodGet
61
+
62
+	return Request(config)
63
+}
64
+
65
+// GetJSTicket 获取分享 ticket
66
+func GetJSTicket(link string) (interface{}, error) {
67
+	wxconf, err := beego.AppConfig.GetSection("wechat")
68
+	if err != nil {
69
+		beego.Error("获取微信配置失败: ", err.Error())
70
+		return nil, err
71
+	}
72
+
73
+	config := request.NewConfig(wxconf["service"] + "wx/jssdk")
74
+	config.AddParam("appid", wxconf["appid"])
75
+	config.AddParam("url", link)
76
+	config.Method = http.MethodGet
77
+
78
+	return Request(config)
79
+}
80
+
81
+func Request(config *request.Config) (interface{}, error) {
82
+	body, _, err := request.Do(config)
83
+	if err != nil {
84
+		beego.Error("请求微信服务失败: ", err.Error())
85
+		return nil, err
86
+	}
87
+
88
+	res, err := getResult(body)
89
+	if err != nil {
90
+		return nil, err
91
+	}
92
+
93
+	if res.Code != http.StatusOK {
94
+		return nil, fmt.Errorf("请求微信服务失败: %s", res.Message)
95
+	}
96
+
97
+	return res.Result.(interface{}), nil
98
+}
99
+
100
+func getResult(body io.ReadCloser) (*WxResult, error) {
101
+	defer body.Close()
102
+
103
+	bs, err := ioutil.ReadAll(body)
104
+	if err != nil {
105
+		beego.Error("读取微信服务结果失败: ", err.Error())
106
+		return nil, err
107
+	}
108
+
109
+	res := WxResult{}
110
+	if err := json.Unmarshal(bs, &res); err != nil {
111
+		beego.Error("转换微信服务结果失败: ", err.Error())
112
+		return nil, err
113
+	}
114
+
115
+	return &res, nil
116
+}