02 . Go之Gin+Vue开发一个线上外卖应用(集成第三方发送短信和xorm生成存储数据库表)

集成第三方发送短信

介绍

用户登录

用户登录有两种方式: 短信登录,密码登录

短信登录是使用手机号和验证码进行登录

短信平台

很多云平台,比如阿里云,腾讯云,七牛云等云厂商,向程序开发者提供了短信验证码套餐服务。借助云平台的短信服务,程序开发者可以非常简单方便的将短信服务集成到自己的程序中。

我们以接入和集成阿里云的短信服务sdk为例, 如果需要申请腾讯云短信服务可以看我另外写的一篇blog,使用两者都差不多

https://www.cnblogs.com/you-men/p/13088949.html

阿里云短信服务集成-登录阿里云

登录阿里云

登录阿里云:https://www.aliyun.com/

选择短信服务模块:https://www.aliyun.com/product/sms

注明:云平台的短信服务是收费的,有不同类别的套餐。开发者可以按照自己的需求进行选择。如下图:

Go短信服务SDK

可以访问https://api.aliyun.com/?spm=5176.12207334.0.0.54d71cbe3NE29f#/?product=Dysmsapi&lang=GO查看go语言版本的短信服务sdk代码。

安装阿里云GO SDK
go get github.com/aliyun/alibaba-cloud-sdk-go
创建签名和短信模板

在使用go sdk集成短息服务之前,需要首先创建短信签名和短信模板。

签名:短信签名是短信服务提供的一种快捷、方便的个性化签名方式。当发送短信时,短信平台会根据设置,在短信内容里附加个性签名,再发送给指定手机号码。比如,下图红框中的"招商银行”就是这条短信的签名,用以标识发送者的类别等内容。

在阿里云后台的短信服务控制面板的左侧功能栏中,选择国内消息,如下图所示,然后选择签名管理的TAB,然后选择添加签名,可以创建新的短信签名。如下图:

短信模板:短信模版,即具体发送的短信内容。短信模版可以支持验证码、短信通知、推广短信三种模式。验证码和短信通知,通过变量替换实现个性短信定制。
与创建签名同理,可以在模板管理TAB中,选择添加模板,用来创建新的短信模板。创建完成后,会进行审核。

创建成功后的短信模板CODE需要记住,后续会使用到

在短信服务管理平台的概览界面,可以选择AccessKey按钮进行创建集成短信服务所需要的AccessKey和AccessKeySecret。

程序中集成短信服务
client, err := dysmsapi.NewClientWithAccessKey(smsConfig.RegionId, smsConfig.AppKey, smsConfig.AppSecret)
	if err != nil {
		toolbox.Error(err.Error())
		return ""
	}

	request := dysmsapi.CreateSendSmsRequest()
	request.Scheme = "https"

	request.SignName = smsConfig.SignName
	request.TemplateCode = smsConfig.TemplateCode
	request.PhoneNumbers = phone


	par, err := json.Marshal(map[string]interface{}{
		"code": code,
	})
	request.TemplateParam = string(par)

	response, err := client.SendSms(request)
	
	fmt.Println( response)
	if err != nil {
		toolbox.Error(err.Error())
		return ""
	}

我们通过上述核心代码程序,完成阿里云短信服务的集成。其中:

  • SignName:在阿里云后台创建的前名,必传参数。
  • TemplateCode:在阿里云后台创建的短信模板ID,必传参数。
  • PhoneNumbers:接收短信的手机号码,必传参数。

创建阿里云短信服务sdk的client时,需要传regionID、appKey、accessKeySecret三个参数。regionID表示的是区域ID,可以填写cn-hangzhou。

创建Controller解析请求

无论是短信登录,还是用户名和密码登录,均属于用户功能模块。因此,创建MemberController用于解析用户模块的各个请求:

package controller

import (
	"CloudRestaurant/service"
	"fmt"
	"github.com/gin-gonic/gin"
)

type MemberController struct {}

func (mc *MemberController) Router(engine *gin.Engine)  {
	engine.GET("/api/sendcode",mc.sendSmsCode)
}

// http://localhost:8090/api/sendcode?phone=18621048481
func (mc *MemberController) sendSmsCode(c *gin.Context)  {
	// 发送验证码
	phone,exist := c.GetQuery("phone")
	fmt.Println(phone,"phone --->")
	if !exist {
		c.JSON(200,map[string]interface{}{
			"code":0,
			"msg":"参数解析失败",
		})
		return
	}
	ms := service.MemberService{}
	isSend := ms.Sendcode(phone)
	if isSend {
		c.JSON(200,map[string]interface{}{
			"code":1,
			"msg":"发送成功",
		})
		return
	}

	c.JSON(200,map[string]interface{}{
		"code":0,
		"msg":"发送失败",
	})
}

创建用户控制层程序MemberController,使用GET方法解析客户端发送短信验证码的请求,请求接口为:/api/sendcode,同时指定sendSmsCode方法处理接口请求。

在实际的开发中,程序功能往往是分层来进行开发的,controller层只负责控制和处理接口请求的逻辑,具体的功能调用,往往由另外称为service层的功能服务层来进行实现。

创建service层

在service层中,依然按照模块化开发的理念,将用户模块的服务统一由UserServicej进行提供。因此,创建MemberService,并提供SendCode方法。

package service

import (
	"CloudRestaurant/tool"
	"encoding/json"
	"fmt"
	"github.com/aliyun/alibaba-cloud-sdk-go/services/dysmsapi"
	"github.com/wonderivan/logger"
	"math/rand"
	"time"
)

type MemberService struct {

}

func (ms *MemberService) Sendcode(phone string) bool {
	// 1.产生一个验证码
	code := fmt.Sprintf("%06v",rand.New(rand.NewSource(time.Now().UnixNano())).Int31n(1000000))

	// 2.调用阿里云服务
	config := tool.GetConfig().Sms
	client, err := dysmsapi.NewClientWithAccessKey(config.RegionId, config.AppKey, config.AppSecret)
	if err != nil {
		logger.Error(err.Error())
		return false
	}

	request := dysmsapi.CreateSendSmsRequest()
	request.Scheme = "https"
	request.SignName = config.SignName
	request.TemplateCode = config.TemplateCode
	request.PhoneNumbers = phone

	par,err := json.Marshal(map[string]interface{}{
		"code":code,
	})
	request.TemplateParam = string(par)

	response,err :=client.SendSms(request)
	fmt.Println(response,"response --->")
	if err != nil {
		logger.Error(err.Error())
		return false
	}

	// 3. 接受返回结果,并判断发送状态
	if response.Code == "OK" {
		return true
	}
	return false
}

测试

在postman中, 使用/api/sendcode接口进行测试,详细url如下:

http://localhost:8090/api/sendcode?phone=13167582436

然后就能在手机端收到验证码

创建数据库和数据表

上面已经接入了第三方的短信服务SDK功能,可以接受短信验证码。在用户接受到验证码以后,输入验证码进行登录,我们需要验证用户输入的验证码是否正确。

因此,我们需要将发送过的验证码通过持久化的方式保存下来,方便我们进行校验。

我们选择通过数据库来存储用户手机验证码。

xorm介绍及安装

在项目开发过程中,我们会使用一些成熟的框架来操作数据库。xorm就是一个比较流行的数据库操作orm框架。

安装xorm

go get github.com/go-xorm/xorm

安装Mysql驱动

go get github.com/go-sql-driver/mysql
连接数据库

在连接数据库之前,首先要创建数据库。在mysql中创建cloudrestaurant数据库:

create database cloudrestaurant;

创建完数据库并安装好xorm库以后,使用xorm进行连接数据库

import (
	"github.com/go-xorm/xorm"
	_ "github.com/go-sql-driver/mysql"
)
database := cfg.Database
conn := database.User + ":" + database.Password + "@tcp(" + database.Host + ":" + database.Port + ")/" + database.DbName + "?charset=" + database.Charset
engine, err := xorm.NewEngine(database.Driver, conn)
if err != nil {
	return nil, err
}

连接数据库有些参数需要自己指定,比如说驱动类型,登录数据库的用户名,密码,数据库名等。将这些变量配置在app.json配置文件中,如下所示:

{
"database": {
    "driver": "mysql",
    "user": "root",
    "password": "12345678",
    "host": "127.0.0.1",
    "port": "3306",
    "db_name": "cloudrestaurant",
    "charset": "utf8mb4",
    "show_sql": true
}
}

在Config结构体中添加对database的解析

type Config struct {
	AppName  string         `json:"app_name"`
	AppMode  string         `json:"app_mode"`
	AppHost  string         `json:"app_host"`
	AppPort  string         `json:"app_port"`
	Database DatabaseConfig `json:"database"`
	Sms      SmsConfig      `json:"sms"`
}
type DatabaseConfig struct {
	Driver   string `json:"driver"`
	User     string `json:"user"`
	Password string `json:"password"`
	Host     string `json:"host"`
	Port     string `json:"port"`
	DbName   string `json:"db_name"`
	Charset  string `json:"charset"`
	ShowSql  bool   `json:"show_sql"`
}
创建SmsCode

要存储验证码,需要在数据库中创建表结构进行存储。我们可以创建SmsCode结构体,并通过tag设置数据库字段约束,具体的SmsCode定义如下:

package model

type SmsCode struct {
	Id         int64  `xorm:"pk autoincr" json:"id"`
	Phone      string `xorm:"varchar(11)" json:"phone"`
	BizId      string `xorm:"varchar(30)" json:"biz_id"`
	Code       string `xorm:"varchar(4)" json:"code"`
	CreateTime int64  `xorm:"bigint" json:"create_time"`
}

通过tag的xorm设置字段数据类型以及约束。

  • pk:表示主键
  • autoinc:表示自增
  • bigint:整形变量
  • varchar:字符串类型
Sync2同步生成数据库表

可以调用engine.Sync2方法,将结构体类型同步映射到数据库中,生成数据库表。

err = engine.Sync2(new(model.SmsCode))
	if err != nil {
		return nil, err
}
将验证码数据保存到数据库

在MemberService的SendCode方法,添加保存验证码到数据库的操作:

func (msi *MemberServiceImpl) SendCode(phone string) string {
	code := fmt.Sprintf("%06v", rand.New(rand.NewSource(time.Now().UnixNano())).Int31n(1000000))
	...
	dao := impl.NewMemberDao()
	smsCode := model.SmsCode{Phone: phone, Code: code, BizId: response.BizId, CreateTime: time.Now().Unix()}

	if result := dao.InsertCode(smsCode); result > 0 {
		return code
	}
	return ""
}
posted @ 2020-11-02 09:05  常见-youmen  阅读(829)  评论(1编辑  收藏  举报