首页 > 技术文章 > go编写简单接口的过程

sentangle 2020-01-09 11:24 原文

环境

系统

Windows server 2016 Datacener

go version

go1.13.3 windows/amd64

数据库

Microsoft SQL Server 2014(64位)

基本构成

接口代码使用扩展类库

"crypto/md5"
"encoding/json"
"fmt"
_ "github.com/denisenkom/go-mssqldb"
"github.com/gin-gonic/gin"
"github.com/go-xorm/xorm"
"github.com/satori/go.uuid"

gin web框架 负责web服务器及路由请求处理
xorm和go-mssqldb 数据库对象orm处理
go.uuid 生成uuid标识

代码

main.go

package main

import (
	"crypto/md5"
	"encoding/json"
	"fmt"
	_ "github.com/denisenkom/go-mssqldb"
	"github.com/gin-gonic/gin"
	"github.com/go-xorm/xorm"
	"github.com/satori/go.uuid"
)

func main() {

	//关闭gin debug
	gin.SetMode(gin.ReleaseMode)
	router := gin.Default()

	//提交生产api
	router.POST("/test", productionOrderHandler)
	//测试api是否正常访问
	router.GET("/ping", func(c *gin.Context) {
		c.String(200, "pong")
	})

	router.Run(":8080")
}

/**
获取uuid
*/
func GetUuid() string {
	// or error handling
	val, err := uuid.NewV4()
	if err != nil {
		panic("生成uuid错误:"+err.Error())
	}
	return val.String()
}

/**
md函数
*/
func GetMd5(str string) string {

	hash := md5.New()
	hash.Write([]byte(str))
	result := hash.Sum([]byte(""))
	return fmt.Sprintf("%x",result)
}

/**
提交生产逻辑
*/
func productionOrder(orderNo interface{}, orderMap []interface{}, booksMap []interface{}, engineDb *xorm.Engine) (bool, string) {

	message := "执行成功"
	//事务开启
	session := engineDb.NewSession()
	defer session.Close()
	//4.1 pm_order表
	var orderData pm_order
	for _, item := range orderMap {
		// 类型转换
		orderItem := item.(map[string]interface{})
		orderData.Key_seq = GetUuid()
		//此处隐藏数据结构
		if _, err := engineDb.Insert(orderData); err != nil {
			session.Rollback()
			message = "pm_order添加数据失败:" + err.Error()
			return false, message
		}
	}
	//4.2 pm_order表 PM_OrderStatus表 PM_OrderStatusDetail表
	var bookData pm_books
	var orderStatusData pm_orderstatus
	var orderStatusDetailData pm_orderstatusdetail
	for _, item := range booksMap {
		// 类型转换
		bookItem := item.(map[string]interface{})
		//4.2.1 pm_order数据处理
		bookData.Key_seq = GetUuid()
		//此处隐藏数据结构
		//4.2.2 PM_OrderStatus数据处理
		orderStatusData.Orderno = bookItem["OrderNo"].(string)
		//此处隐藏数据结构
		//4.2.3 PM_OrderStatusDetail表
		orderStatusDetailData.Orderno = bookItem["OrderNo"].(string)
		//此处隐藏数据结构

		if _, err := engineDb.Insert(bookData, orderStatusData, orderStatusDetailData); err != nil {
			session.Rollback()
			message = "pm_books/pm_orderstatus/pm_orderstatusdetail添加数据失败:" + err.Error()
			return false, message
		}
	}

	session.Commit()

	return true, message
}

func productionOrderHandler(c *gin.Context) {
	message := "未知错误"
	//c.Request.ParseForm()
	//for k, v := range c.Request.PostForm {
	//	fmt.Printf("%v=>%v\n", k,v)
	//}
	//c.String(200, message)
	//return

	//验证数据合法性
	orderInfoJson := c.PostForm("OrderInfo")
	if false {
		message = "验证数据合法性失败"
		c.String(200, message)
		return
	}

	//1.获取post数据并解析
	var orderInfo map[string]interface{}
	// 解析字符串为Json
	json.Unmarshal([]byte(orderInfoJson), &orderInfo)
	//转换成map对象
	orderMap := orderInfo["PM_Order"].([]interface{})
	booksMap := orderInfo["PM_Books"].([]interface{})
	if orderMap == nil || booksMap == nil{
		message = "数据json解析失败"
		c.String(200, message)
		return
	}
	var orderNo string
	for _, item := range orderMap {
		// 类型转换
		orderItem := item.(map[string]interface{})
		orderNo = orderItem["OrderNo"].(string)
		if orderNo == "" {
			message = "数据json解析失败:orderno解析失败"
			c.String(200, message)
			return
		}
	}

	//2 建立连接
	var dbConfig = [...]string{
		"127.0.0.1",
		"sa",
		"123456",
		"test",
	}
	//fmt.Println(dbConfig)
	//c.String(200, message)
	//return

	connString := fmt.Sprintf("server=%s;port%d;user id=%s;password=%s;database=%s;", dbConfig[0], 1433, dbConfig[1], dbConfig[2], dbConfig[3])
	engineDb, err := xorm.NewEngine("mssql", connString)
	if err != nil {
		message = "连接数据库失败"
		c.String(200, message)
		return
	}
	//3 检查订单是否已提交,已提交则返回成功
	has, err := engineDb.SQL("select * from PM_Order where orderNo = ?", orderNo).Exist()
	if err != nil {
		message = "数据查询失败"
		c.String(200, message)
		return
	}
	if has {
		c.String(200, "ok")
		return
	}
	//4.开始提交订单数据
	result, errmsg := productionOrder(orderNo, orderMap, booksMap, engineDb)
	if result == false {
		c.String(200, errmsg)
		return
	}
	c.String(200, "ok")
	return
}

com_model.go

/**
数据库对应的struct
*/
package main
import "time"
//PM_Order表
type pm_order struct {
	Key_seq string
	...
}
//PM_Books表
type pm_books struct {

	Key_seq string
	Orderno string
	...

}
//PM_OrderStatus表
type pm_orderstatus struct {
	Orderno string
	...
	Updatetime time.Time  `xorm:"created"`
}
//PM_OrderStatusDetail表
type pm_orderstatusdetail struct {
	Key_seq string
	...
	Createtime time.Time `xorm:"created"`
}

可执行文件压缩

使用upx打压缩壳, upx 下载地址 https://upx.github.io/

编译无符号表和调试信息的可执行文件

go build -ldflags "-s -w"

调用upx压缩

upx.exe -9 ginTest.exe

推荐阅读