1
0
mirror of https://github.com/silenceper/wechat.git synced 2026-02-06 05:32:26 +08:00
Files
wechat/cloudbase/guestbook-demo/database.md
2020-03-17 19:47:29 +08:00

8.3 KiB
Raw Blame History

数据库:调用云开发数据库实现文本保存

在这一节,我们主要描述如何利用wechat sdk将留言的内容保存在云开发数据库中。

API说明

参考微信云开发文档 数据库篇可以先阅读其原始的api提供的方法和说明SDK DOC中都可以找到对应的方法以及参数。

主要利用到SDK DOC中的如下方法其他方法可在文档中找到sdk文档中以 Database 开头的方法即为数据库相关的方法调用。

func (tcb *Tcb) DatabaseAdd(env, query string) (*DatabaseAddRes, error) //数据库内容保存
func (tcb *Tcb) DatabaseCount(env, query string) (*DatabaseCountRes, error)//数据库计数
func (tcb *Tcb) DatabaseQuery(env, query string) (*DatabaseQueryRes, error)//数据库内容查询

返回结果对应字段说明: DatabaseAddRes , DatabaseCountRes , DatabaseQueryRes 

包引入

本例中引入的WeChat sdk版本为v1.2.3版本,通过如下方法引入

go get github.com/silenceper/wechat@v1.2.3

可以在go.mod文件中看到引入的包以及对应的版本

module github.com/go-demo/guestbook

go 1.13

require (
	github.com/gin-gonic/gin v1.5.0
	github.com/silenceper/wechat v1.2.3 // indirect
)

保存至云开发数据库

WeChat SDK配置

为了方便在其他方法中调用
创建config.go用于解析云开发对应的配置参数appkeyapp_secret等

package main

import (
	"io/ioutil"

	"github.com/silenceper/wechat"
	"github.com/silenceper/wechat/cache"
	"github.com/silenceper/wechat/tcb"
	"gopkg.in/yaml.v2"
)

//Config 配置信息
type Config struct {
	TcbEnv    string `yaml:"tcb_env"`
	AppID     string `yaml:"app_id"`
	AppSecret string `yaml:"app_secret"`
}

var cfg *Config
var _ = getConfig()

//通过getConfig方法获取配置参数
func getConfig() *Config {
	if cfg != nil {
		return cfg
	}
	data, err := ioutil.ReadFile("./config.yaml")
	if err != nil {
		panic(err)
	}
	cfg = &Config{}
	err = yaml.Unmarshal(data, cfg)
	if err != nil {
		panic(err)
	}
	return cfg
}

var wechatTcb *tcb.Tcb
var _ = getTcb()
//通过getTcb获取wechat sdk的配置参数
func getTcb() *tcb.Tcb {
	if wechatTcb != nil {
		return wechatTcb
	}
	memCache := cache.NewMemory()

	//配置小程序参数
	config := &wechat.Config{
		AppID:     getConfig().AppID,
		AppSecret: getConfig().AppSecret,
		Cache:     memCache,
	}
	wc := wechat.NewWechat(config)
	wechatTcb = wc.GetTcb()
	return wechatTcb
}

其中config.yaml写入三个配置参数

tcb_env: test-6ku2s //云开发环境
app_id: xxxxxx //云开发appid
app_secret: xxxxxxxxx //云开发对应的app secret

调用API

为了方便在其他方法中方便调用sdk中的方法这里新建一个 feedbackService struct创建对应的save方法用于保存留言, feedback.go :

package main

import (
	"fmt"
	"time"
)

//FeedbackService service
type FeedbackService struct {
}

//NewFeedbackService new
func NewFeedbackService() *FeedbackService {
	return &FeedbackService{}
}

//Feedback 留言记录
type Feedback struct {
	Username   string `form:"username",json:"username"`
	Content    string `form:"content",json:"content"`
	FilePath   string `json:"filePath"`//文件路径
	FileID     string `json:"fileId"` //存放文件
	CreateTime string `json:"createTime"`
}

func (svc *FeedbackService) Save(feedback *Feedback) error {
	if feedback.Username == "" || feedback.Content == "" {
		return fmt.Errorf("用户名或留言内容不能为空")
	}
	query := `db.collection(\"%s\").add({
      data: [{
        username: \"%s\",
        content: \"%s\",
		filePath: \"%s\",
		fileId: \"%s\",
        createTime: \"%s\",
      }]
      })`
	feedback.CreateTime = time.Now().Format("2006-01-02 15:04:05")
	query = fmt.Sprintf(query, "guestbook", feedback.Username, feedback.Content, feedback.FilePath, feedback.FileID, feedback.CreateTime)
	_, err := getTcb().DatabaseAdd(getConfig().TcbEnv, query)
	if err != nil {
		return err
	}
	return nil
}

其中对于数据库中的query语句可以参考https://developers.weixin.qq.com/miniprogram/dev/wxcloud/guide/database/add.html

这里调用 DatabaseAdd 方法实现内容的保存。

接收表单提交内容

将表单提交的内容提交到 /feedback 路由中,并创建 feedback方法接收表单提交的参数,

func main() {
	r := gin.Default()

	//包含html模板
	r.LoadHTMLGlob("./template/*")
	//渲染留言页面
	r.GET("/",index)
	//提交留言
	r.POST("/feedback", feedback)

	r.Run() // listen and serve on 0.0.0.0:8080 (for windows "localhost:8080")
}

其中feedback方法如下

//接收提交的内容
func feedback(c *gin.Context) {
	//1、接收提交参数
	feedback := &Feedback{}
	err := c.Bind(feedback)
	if err != nil {
		showError(c, err)
		return
	}
	feedbackService := NewFeedbackService()
	//保存内容
	err = feedbackService.Save(feedback)
	if err != nil {
		showError(c, err)
		return
	}

	c.Redirect(http.StatusMovedPermanently, "/")
}

这里通过c.Bind方法将form表单中的内容绑定到 Feedback stuct中再通过调用feedbackService中的Save方法对文本内容进行保存。

展示留言内容

留言内容的展示主要分为两步,一先从数据库展示出来,二是将留言内容展示在页面:
查询的sql语句为

db.collection("guestbook").orderBy('createTime','desc').skip(0).limit(10).get()

feedback.go 中新增List方法其中参数传入skip和limit参数用于分页

//List 文本列表
func (svc *FeedbackService) List(skip, limit int) ([]*Feedback, error) {
	query := fmt.Sprintf("db.collection(\"guestbook\").orderBy('createTime','desc').skip(%d).limit(%d).get()", skip, limit)
	data, err := getTcb().DatabaseQuery(getConfig().TcbEnv, query)
	if err != nil {
		return nil, err
	}
	feedbacks := make([]*Feedback, 0, len(data.Data))
	for _, v := range data.Data {
		feedbackItem := &Feedback{}
		err := json.Unmarshal([]byte(v), feedbackItem)
		if err != nil {
			return nil, err
		}
		feedbacks = append(feedbacks, feedbackItem)

	}
	//fmt.Println(data.Pager)
	return feedbacks, nil
}

这里主要调用 DatabaseQuery 方法对db进行查询。

在main.go中的index方法在从数据中获取的数据取出并渲染在index.html中

//首页
func index(c *gin.Context) {
	page := c.Query("page")
	//获取记录数量
	feedbackService := NewFeedbackService()
	count, err := feedbackService.Count()
	if err != nil {
		showError(c, err)
		return
	}
	limit := 10
	totalPage := math.Ceil(float64(count) / float64(limit))
	totalPageInt := int(totalPage)
	pageInt, _ := strconv.Atoi(page)
	if pageInt > totalPageInt {
		pageInt = totalPageInt
	}
	if pageInt < 1 {
		pageInt = 1
	}

	//展示留言列表
	skip := (pageInt - 1) * limit
	list, err := feedbackService.List(skip, limit)
	if err != nil {
		showError(c, err)
		return
	}

	c.HTML(http.StatusOK, "index.html", gin.H{
		"title":     "留言板",
		"list":      list,
		"prevPage":  pageInt - 1,
		"nextPage":  pageInt + 1,
		"page":      pageInt,
		"totalPage": totalPageInt,
	})
}

其中index.html通过go template语法对内容进行渲染

    <div class="list-group list-group-flush">
        {{range .list}}
        <div class="list-group-item">
            <div><span><b>{{.Username}} 在 {{.CreateTime}} 说:</b></span></div>
            <div><p>{{.Content}}</p></div>
        </div>
        {{end}}
    </div>
    <div>
        <span>第{{.page}}页</span>
        {{if gt .page 1}}<a href="/?page={{.prevPage}}">上一页</a>{{end}}
       {{if lt .page .totalPage}} <a href="/?page={{.nextPage}}">下一页</a>{{end}}
    </div>

这样就实现了对文本内容的保存