【Go】Gin框架实战之云餐厅外卖

Gin入门基础

01.Gin简介

在这里插入图片描述

02.HTTP请求和参数解析

创建Engine

在这里插入图片描述

处理HTTP请求

在这里插入图片描述

RouterGroup

在这里插入图片描述

04. 多数据格式返回请求结果

05. 中间件的编写和使用

在这里插入图片描述

在这里插入图片描述

Next()的作用

在这里插入图片描述

07.Gin访问和使用数据库

增删改 使用Exec

在这里插入图片描述

查询使用Query

package main

import (
	"database/sql"
	"fmt"
	_ "github.com/go-sql-driver/mysql"
	"log"
)

type Echart struct {
	id       int
	province string
	city     string
}

func main() {
	connStr := "root:root123@tcp(127.0.0.1:3306)/echart"
	db, err := sql.Open("mysql", connStr)
	if err != nil {
		log.Fatal(err.Error())
		return
	}
	rows, err := db.Query("select id,province,city from details")
	if err != nil {
		log.Fatal(err.Error())
		return
	}

	defer db.Close()

scan:
	if rows.Next() {
		echart := new(Echart)
		err := rows.Scan(&echart.id, &echart.province, &echart.city)
		if err != nil {
			log.Fatal(err.Error())
			return
		}
		fmt.Println(echart.id, echart.province, echart.city)
		goto scan
	}
}

云餐厅项目

项目简介与开发工具

在这里插入图片描述

IDE: Goland
测试: Postman

实战

代码

14.全局跨域请求处理设置

在这里插入图片描述

在这里插入图片描述

//跨域访问:cross  origin resource share
func Cors() gin.HandlerFunc {
	return func(context *gin.Context) {
		method := context.Request.Method
		origin := context.Request.Header.Get("Origin")
		var headerKeys []string
		for key, _ := range context.Request.Header {
			headerKeys = append(headerKeys, key)
		}
		headerStr := strings.Join(headerKeys, ",")
		if headerStr != "" {
			headerStr = fmt.Sprintf("access-control-allow-origin, access-control-allow-headers, %s", headerStr)
		} else {
			headerStr = "access-control-allow-origin, access-control-allow-headers"
		}

		if origin != "" {
			context.Writer.Header().Set("Access-Control-Allow-Origin", "*")
			context.Header("Access-Control-Allow-Origin", "*") // 设置允许访问所有域
			context.Header("Access-Control-Allow-Methods", "POST, GET, OPTIONS, PUT, DELETE,UPDATE")
			context.Header("Access-Control-Allow-Headers", "Authorization, Content-Length, X-CSRF-Token, Token,session,X_Requested_With,Accept, Origin, Host, Connection, Accept-Encoding, Accept-Language,DNT, X-CustomHeader, Keep-Alive, User-Agent, X-Requested-With, If-Modified-Since, Cache-Control, Content-Type, Pragma")
			context.Header("Access-Control-Expose-Headers", "Content-Length, Access-Control-Allow-Origin, Access-Control-Allow-Headers,Cache-Control,Content-Language,Content-Type,Expires,Last-Modified,Pragma,FooBar")
			context.Header("Access-Control-Max-Age", "172800")
			context.Header("Access-Control-Allow-Credentials", "false")
			context.Set("content-type", "application/json")  设置返回格式是json
		}

		if method == "OPTIONS" {
			context.JSON(http.StatusOK, "Options Request!")
		}

		//处理请求
		context.Next()
	}
}

使用跨域请求访问

package main

import (
	"fmt"
	"gin_cloudrestaurant/controller"
	"gin_cloudrestaurant/tool"
	"log"
	"net/http"
	"strings"

	"github.com/gin-gonic/gin"
	"github.com/wonderivan/logger"
)

func main() {

	// 加载自定义的配置文件
	cfg, err := tool.ParseConfig("./config/app.json")
	if err != nil {
		panic(err.Error())
	}

	_, err = tool.OrmEngine(cfg)
	if err != nil {
		logger.Error(err.Error())
		return
	}

	tool.InitRedisStore() //初始化redis配置
	app := gin.Default()
	//设置全局跨域访问
	app.Use(Cors())
	//集成session
	tool.InitSession(app)

	registerRouter(app)
	if err := app.Run(cfg.AppHost + ":" + cfg.AppPort); err != nil {
		log.Fatal(err.Error())
	}
}

//路由设置
func registerRouter(router *gin.Engine) {
	new(controller.HelloController).Router(router)
	new(controller.MemberController).Router(router)
}

15.图形验证码生成和验证

func (mc *MemberController) Router(engine *gin.Engine) {
	engine.GET("/api/sendcode", mc.sendSmsCode)        //发送短信验证码
	engine.POST("/api/login_sms", mc.smsLogin)         //手机号短信方式登录
	engine.GET("/api/captcha", mc.captcha)             //生产验证码
	engine.POST("/api/vertifycha", mc.vertifyCaptcha)  //验证验证码
	engine.POST("/api/login_pwd", mc.nameLogin)        //用户名和密码登陆接口
	engine.POST("/api/upload/avator", mc.uploadAvator) //头像上传
}

//验证验证码是否正确
func (mc *MemberController) vertifyCaptcha(context *gin.Context) {
	var captcha tool.CaptchaResult
	// 验证是否符合captcha struct的值
	err := tool.Decode(context.Request.Body, &captcha)
	if err != nil {
		tool.Failed(context, " 参数解析失败 ")
		return
	}

	result := tool.VertifyCaptcha(captcha.Id, captcha.VertifyValue)
	if result {
		fmt.Println("验证通过")
	} else {
		fmt.Println("验证失败")
	}
}

base64Captcha 利用封装的方法调用 redis set方法,默认有时间

package tool

import (
	"fmt"
	"image/color"

	"github.com/gin-gonic/gin"
	"github.com/mojocn/base64Captcha"
)

type CaptchaResult struct {
	Id           string `json:"id"`
	Base64Blob   string `json:"base_64_blob"`
	VertifyValue string `json:"code"`
}

//生成图形化验证码
func GenerateCaptcha(ctx *gin.Context) {

	parameters := base64Captcha.ConfigCharacter{
		Height:             30,
		Width:              60,
		Mode:               3,
		ComplexOfNoiseText: 0,
		ComplexOfNoiseDot:  0,
		IsUseSimpleFont:    true,
		IsShowHollowLine:   false,
		IsShowNoiseDot:     false,
		IsShowNoiseText:    false,
		IsShowSlimeLine:    false,
		IsShowSineLine:     false,
		CaptchaLen:         4,
		BgColor: &color.RGBA{
			R: 3,
			G: 102,
			B: 214,
			A: 254,
		},
	}

	captchaId, captchaInterfaceInstance := base64Captcha.GenerateCaptcha("", parameters)
	base64blob := base64Captcha.CaptchaWriteToBase64Encoding(captchaInterfaceInstance)

	captchaResult := CaptchaResult{Id: captchaId, Base64Blob: base64blob}


	Success(ctx, map[string]interface{}{
		"captcha_result": captchaResult,
	})

}

func VertifyCaptcha(id string, value string) bool {
	fmt.Println(id, value)
	vertifyResult := base64Captcha.VerifyCaptcha(id, value)
	return vertifyResult
}

func Decode(io io.ReadCloser, v interface{}) error {
	return json.NewDecoder(io).Decode(v)
}

验证码被获取到,base64Captcha在获取到验证码后会自动删除redis中的key

在这里插入图片描述

16.用户名密码登录

//用户名+密码、验证码登录
func (mc *MemberController) nameLogin(context *gin.Context) {

	//1、解析用户登录传递参数
	var loginParam param.LoginParam
	err := tool.Decode(context.Request.Body, &loginParam)
	if err != nil {
		tool.Failed(context, "参数解析失败")
		return
	}

	//2、验证验证码
	validate := tool.VertifyCaptcha(loginParam.Id, loginParam.Value)
	if !validate {
		tool.Failed(context, "验证码不正确,请重新验证")
		return
	}

	//3、登录
	ms := service.MemberService{}
	member := ms.Login(loginParam.Name, loginParam.Password)
	if member.Id != 0 {

		//登陆成功 用户信息保存到session
		sess, _ := json.Marshal(member)
		// fmt.Printf("未初始化数据是 %v , 初始化之后的数据是 %v\n", member, sess)
		err = tool.SetSess(context, "user_"+string(member.Id), sess)
		if err != nil {
			tool.Failed(context, "登录失败")
			return
		}

		tool.Success(context, &member)
		return
	}

	tool.Failed(context, "登录失败")
}
//用户登录
func (ms *MemberService) Login(name string, password string) *model.Member {

	//1、使用用户名 + 密码 查询用户信息 如果存在用户 直接返回
	md := dao.MemberDao{tool.DbEngine}
	member := md.Query(name, password)
	if member.Id != 0 {
		return member
	}

	//2、用户信息不存在,作为新用户保存到数据库中
	user := model.Member{}
	user.UserName = name
	user.Password = tool.EncoderSha256(password)
	user.RegisterTime = time.Now().Unix()

	result := md.InsertMember(user)
	user.Id = result

	return &user
}

测试登录接口: 通过验证码接口 带着redis中验证码的key跟value登录
在这里插入图片描述
在这里插入图片描述

在这里插入图片描述

17.用户头像上传

//头像上传
func (mc *MemberController) uploadAvator(context *gin.Context) {

	//1、解析上传的参数:file、user_id
	userId := context.PostForm("user_id") //用户id
	// fmt.Println(userId)
	file, err := context.FormFile("avatar")
	if err != nil || userId == "" {
		tool.Failed(context, "参数解析失败")
		return
	}

	//2、判断user_id对应的用户是否已经登录
	sess := tool.GetSess(context, "user_"+userId)
	if sess == nil {
		tool.Failed(context, "参数不合法")
		return
	}
	var member model.Member
	json.Unmarshal(sess.([]byte), &member)

	//3、file保存到本地
	fileName := "./uploadfile/" + strconv.FormatInt(time.Now().Unix(), 10) + file.Filename
	err = context.SaveUploadedFile(file, fileName)
	if err != nil {
		tool.Failed(context, "头像更新失败")
		return
	}

	// http://localhost:8080/static/.../davie.png
	//4、将保存后的文件本地路径 保存到用户表中的头像字段
	memberService := service.MemberService{}
	path := memberService.UploadAvatar(member.Id, fileName[1:])
	if path != "" {
		tool.Success(context, "http://localhost:8090"+path)
		return
	}
	//5、返回结果
	tool.Failed(context, "上传失败")
}

service调用将DB封装好, dao层操作数据库

func (ms *MemberService) UploadAvatar(userId int64, fileName string) string {
	memberDao := dao.MemberDao{tool.DbEngine}
	result := memberDao.UpdateMemberAvatar(userId, fileName)
	if result == 0 {
		return ""
	}

	return fileName
}

dao层更新数据库

//更新member记录,头像属性
func (md *MemberDao) UpdateMemberAvatar(userId int64, fileName string) int64 {
	member := model.Member{Avatar: fileName}
	result, err := md.Where(" id = ? ", userId).Update(&member)
	if err != nil {
		fmt.Println(err.Error())
		return 0
	}
	return result
}

18.搭建FastDFS分布式文件系统

上传文件到本地

//头像上传
func (mc *MemberController) uploadAvator(context *gin.Context) {

	//1、解析上传的参数:file、user_id
	userId := context.PostForm("user_id") //用户id
	// fmt.Println(userId)
	file, err := context.FormFile("avatar")
	if err != nil || userId == "" {
		tool.Failed(context, "参数解析失败")
		return
	}

	//2、判断user_id对应的用户是否已经登录
	sess := tool.GetSess(context, "user_"+userId)
	if sess == nil {
		tool.Failed(context, "参数不合法")
		return
	}
	var member model.Member
	json.Unmarshal(sess.([]byte), &member)

	//3、file保存到本地
	fileName := "./uploadfile/" + strconv.FormatInt(time.Now().Unix(), 10) + file.Filename
	err = context.SaveUploadedFile(file, fileName)
	if err != nil {
		tool.Failed(context, "头像更新失败")
		return
	}

	// http://localhost:8080/static/.../davie.png
	//4、将保存后的文件本地路径 保存到用户表中的头像字段
	memberService := service.MemberService{}
	path := memberService.UploadAvatar(member.Id, fileName[1:])
	if path != "" {
		tool.Success(context, "http://localhost:8090"+path)
		return
	}
	//5、返回结果
	tool.Failed(context, "上传失败")
}
保存fastdfs

保存fastdfs、从配置文件中读取文件服务器的ip和端口相关配置

package tool

import (
	"bufio"
	"fmt"
	"github.com/tedcy/fdfs_client"
	"os"
	"strings"
)

/**
 * 上传文件到fastDFS系统
 */
func UploadFile(fileName string)string{
	client,err:=fdfs_client.NewClientWithConfig("./config/fastdfs.conf")
	defer client.Destory()
	if err!=nil{
		fmt.Println(err.Error())
		return ""
	}
	fileId,err:=client.UploadByFilename(fileName)
	if err!=nil{
		fmt.Println(err.Error())
		return ""
	}
	return  fileId
}

/**
 * 从配置文件中读取文件服务器的ip和端口相关配置
 */
func FileServerAddr()string{
	file,err:=os.Open("./config/fastdfs.conf")
	defer file.Close()
	if err!=nil{
		fmt.Println(err.Error())
		return ""
	}
	reader:=bufio.NewReader(file)
	for{
		line,err:=reader.ReadString('\n')
		if err!=nil{
			return ""
		}
		line=strings.TrimSuffix(line,"\n")
		str:=strings.SplitN(line,"=",2)
		switch  str[0] {
		case "http_server_port":
			return  str[1]
		}
	}
}

FastDFS 文件系统搭建好之后,可以将上传、保存方式更新

//头像上传
func (mc *MemberController) uploadAvator(context *gin.Context) {

	//1、解析上传的参数:file、user_id
	userId := context.PostForm("user_id")//用户id
	file, err := context.FormFile("avator")
	if err != nil || userId == "" {
		tool.Failed(context, "参数解析失败")
		return
	}

	//2、判断user_id对应的用户是否已经登录
	sess := tool.GetSess(context, "user_"+userId)
	if sess == nil {
		tool.Failed(context, "参数不合法")
		return
	}
	var member model.Member
    json.Unmarshal(sess.([]byte),&member)

	//3、file保存到本地
	fileName:="./uploadfile/"+strconv.FormatInt(time.Now().Unix(),10)+file.Filename
	err=context.SaveUploadedFile(file,fileName)
	if err!=nil{
		tool.Failed(context,"头像更新失败")
		return
	}

	//3.1 将文件上传到fastDFS系统
	fileId:=tool.UploadFile(fileName)
	if fileId!="" {
		//删除本地uploadfile下的文件
		os.Remove(fileName)

		//4、将保存后的文件本地路径 保存到用户表中的头像字段
		memberService := service.MemberService{}
		path := memberService.UploadAvatar(member.Id, fileId)
		if path != "" {
			tool.Success(context,tool.FileServerAddr()+path)
			return
		}
	}
	//5、返回结果
	tool.Failed(context,"上传失败")
}

21.获取食品类别数据

package controller

import (
	"gin_cloudrestaurant/service"
	"gin_cloudrestaurant/tool"
	"github.com/gin-gonic/gin"
)

type FoodCategoryController struct {
}

func (fcc *FoodCategoryController) Router(engine *gin.Engine) {
	engine.GET("/api/food_category", fcc.foodCategory)
}
func (fcc *FoodCategoryController) foodCategory(context *gin.Context) {
	//调用service功能获取食品种类信息
	foodCategoryService := &service.FoodCategoryService{}
	categories, err := foodCategoryService.Categories()
	if err != nil {
		tool.Failed(context, "食品种类数据获取失败")
		return
	}
	//转换格式
	//imgUrl: hello.png
	for _, category := range categories {
		if category.ImageUrl != "" { //图片url的拼接
			category.ImageUrl = tool.FileServerAddr() + "/" + category.ImageUrl
		}
	}
	tool.Success(context, categories)
}

在这里插入图片描述

22- 23.根据经纬度、关键词获取商家列表信息

package controller

import (
	"gin_cloudrestaurant/service"
	"gin_cloudrestaurant/tool"
	"github.com/gin-gonic/gin"
)

type ShopController struct {

}

/**
 * shop模块的路由解析
 */
func (sc *ShopController)Router(engine *gin.Engine){
	engine.GET("/api/shops",sc.GetShopList)
	engine.GET("/api/search_shops", sc.SearchShop)
}
func (sc *ShopController)SearchShop(context *gin.Context){
	longitude:=context.Query("longitude")
	latitude:=context.Query("latitude")
	keyword:=context.Query("keyword")
	if keyword==""{
		tool.Failed(context,"请重新输入商铺名称")
		return
	}
	if longitude==""||longitude=="undefined"||latitude==""||latitude=="undefined"{
		longitude="116.34"
		latitude="40.34"
	}
	shopService:=service.ShopService{}
	shops:=shopService.SearchShops(longitude,latitude,keyword)
	if len(shops)!=0{
		tool.Success(context,shops)
		return
	}
	tool.Failed(context,"暂未获取到商户信息")
}

/**
 * 获取商铺列表
 */
func (sc *ShopController)GetShopList(context *gin.Context){
	longitude:=context.Query("longitude")
	latitude:=context.Query("latitude")
	if longitude==""||longitude=="undefined"||latitude==""||latitude=="undefined"{
		longitude="116.34"
		latitude="40.34"
	}
	shopService:=service.ShopService{}
	shops:=shopService.ShopList(longitude,latitude)
	if len(shops)==0{
		tool.Failed(context,"暂未获取到商户信息")
		return
	}
	for _,shop:=range shops{
		shopServices:=shopService.GetService(shop.Id)
		if len(shopServices)==0{
			shop.Supports=nil
		}else {
			shop.Supports=shopServices
		}
		tool.Success(context,shop)
	}
}
package service

import (
	"gin_cloudrestaurant/dao"
	"gin_cloudrestaurant/model"
	"strconv"
)

type ShopService struct {

}

func (ss *ShopService)GetService(shopId int64)[]model.Service{
	shopDao:=dao.NewShopDao()
	return shopDao.QueryServiceByShopId(shopId)
}
func (ss *ShopService)SearchShops(long,lat,keyword string)[]model.Shop{
	shopDao:=dao.NewShopDao()
	longitude,err:=strconv.ParseFloat(long,10)
	if err!=nil{
		return nil
	}
	latitude,err:=strconv.ParseFloat(lat,10)
	if err!=nil{
		return nil
	}
	return shopDao.QueryShops(longitude,latitude,keyword)
}

/**
 * 查询商铺列表数据
 */
func (ss *ShopService)ShopList(long,lat string)[]model.Shop{
	shopDao:=dao.NewShopDao()
	longitude,err:=strconv.ParseFloat(long,10)
	if err!=nil{
		return nil
	}
	latitude,err:=strconv.ParseFloat(lat,10)
	if err!=nil{
		return nil
	}
	return shopDao.QueryShops(longitude,latitude,"")
}

package service

import (
	"gin_cloudrestaurant/dao"
	"gin_cloudrestaurant/model"
	"strconv"
)

type ShopService struct {

}

func (ss *ShopService)GetService(shopId int64)[]model.Service{
	shopDao:=dao.NewShopDao()
	return shopDao.QueryServiceByShopId(shopId)
}
func (ss *ShopService)SearchShops(long,lat,keyword string)[]model.Shop{
	shopDao:=dao.NewShopDao()
	longitude,err:=strconv.ParseFloat(long,10)
	if err!=nil{
		return nil
	}
	latitude,err:=strconv.ParseFloat(lat,10)
	if err!=nil{
		return nil
	}
	return shopDao.QueryShops(longitude,latitude,keyword)
}

/**
 * 查询商铺列表数据
 */
func (ss *ShopService)ShopList(long,lat string)[]model.Shop{
	shopDao:=dao.NewShopDao()
	longitude,err:=strconv.ParseFloat(long,10)
	if err!=nil{
		return nil
	}
	latitude,err:=strconv.ParseFloat(lat,10)
	if err!=nil{
		return nil
	}
	return shopDao.QueryShops(longitude,latitude,"")
}

package dao

import (
	"gin_cloudrestaurant/model"
	"gin_cloudrestaurant/tool"
	"fmt"
)

type ShopDao struct {
	*tool.Orm
}

func NewShopDao()*ShopDao{
	return &ShopDao{tool.DbEngine}
}

func (sd *ShopDao)QueryServiceByShopId(shopId int64)[]model.Service{
	var services []model.Service
	err:=sd.Table("service").Join("INNER","shop_service",
		"service.id=shop_service.service_id and shop_id=?",shopId).Find(&services)
	if err!=nil{
		return nil
	}
	return services
}

const DEFAULT_RANGE = 5

/**
 * 操作数据库查询商铺数据列表
 */
func (sd *ShopDao)QueryShops(Longitude,latitude float64,keyword string)[]model.Shop{
	var shops []model.Shop
	if keyword==""{
		err:=sd.Engine.Where("Longitude<? and Longitude>? and latitude<? and latitude>? and status=1",
			Longitude+DEFAULT_RANGE,Longitude-DEFAULT_RANGE,latitude+DEFAULT_RANGE,latitude-DEFAULT_RANGE).Find(&shops)
		if err!=nil{
			fmt.Println(err.Error())
			return nil
		}
	}else{
		err:=sd.Engine.Where("Longitude<? and Longitude>? and latitude<? and latitude>? and status=1 and name like ?",
			Longitude+DEFAULT_RANGE,Longitude-DEFAULT_RANGE,latitude+DEFAULT_RANGE,latitude-DEFAULT_RANGE,keyword).Find(&shops)
		if err!=nil{
			fmt.Println(err.Error())
			return nil
		}
	}

	return shops
}

在这里插入图片描述

24.用户信息查询(cookie验证是否登录)

查询信息

func (mc *MemberController)userInfo(context *gin.Context){
	cookie,err:=tool.CookieAuth(context)
	if err!=nil{
		context.Abort()
		tool.Failed(context,"还未登录,请先登录")
		return
	}
	memberService:=service.MemberService{}
	member:=memberService.GetUserInfo(cookie.Value)
	if member!=nil{
		tool.Success(context,map[string]interface{}{
			"id":            member.Id,
			"user_name":     member.UserName,
			"mobile":        member.Mobile,
			"register_time": member.RegisterTime,
			"avatar":        member.Avatar,
			"balance":       member.Balance,
			"city":          member.City,
		})
		return
	}
	tool.Failed(context,"获取用户信息失败")
}
func (ms *MemberService)GetUserInfo(userId string)*model.Member{
	id,err:=strconv.Atoi(userId)
	if err!=nil{
		return nil
	}
	memberDao:=dao.MemberDao{tool.DbEngine}
	return memberDao.QueryMemberById(id)
}
func (md *MemberDao)QueryMemberById(userId int)*model.Member{
	var member model.Member
	if _,err:=md.Where("id=?",userId).Get(&member);err!=nil{
		return nil
	}
	return &member
}

cookie 验证

package tool

import (
	"github.com/gin-gonic/gin"
	"net/http"
)

const CookieName  = "cookie_user"
const CookieTimeLength  = 10 * 60 //10分钟

func CookieAuth(ctx *gin.Context)(*http.Cookie,error)  {
	cookie,err := ctx.Request.Cookie(CookieName)
	if err ==nil{
		ctx.SetCookie(cookie.Name,cookie.Value,cookie.MaxAge,cookie.Path,cookie.Domain,cookie.Secure,cookie.HttpOnly)
		return cookie,nil
	}else {
		return nil, err
	}
}

因此,登录与注册时都需要建立 cookie信息

context.SetCookie("cookie_user",strconv.Itoa(int(member.Id)), 10*60, "/", "localhost",4 ,true, true)

在这里插入图片描述

25.多表查询商家信息(商铺关联服务service表)

service结构体

package model

type Service struct {
	Id int64 `xorm:"pk autoincr" json:"id"`
	Name string `xorm:"varchar(20)" json:"name"`
	Description string  `xorm:"varchar(30)" json:"description"`
	IconName string 	`xorm:"varchar(3)" json:"icon_name"`
	IconColor string 	`xorm:"varchar(6)" json:"icon_color"`
}
/**
 * 获取商铺列表
 */
func (sc *ShopController)GetShopList(context *gin.Context){
	longitude:=context.Query("longitude")
	latitude:=context.Query("latitude")
	if longitude==""||longitude=="undefined"||latitude==""||latitude=="undefined"{
		longitude="116.34"
		latitude="40.34"
	}
	shopService:=service.ShopService{}
	shops:=shopService.ShopList(longitude,latitude)
	if len(shops)==0{
		tool.Failed(context,"暂未获取到商户信息")
		return
	}
	for _,shop:=range shops{
		shopServices:=shopService.GetService(shop.Id)
		if len(shopServices)==0{
			shop.Supports=nil
		}else {
			shop.Supports=shopServices
		}
		tool.Success(context,shop)
	}
}
func (ss *ShopService)GetService(shopId int64)[]model.Service{
	shopDao:=dao.NewShopDao()
	return shopDao.QueryServiceByShopId(shopId)
}
package dao

import (
	"gin_cloudrestaurant/model"
	"gin_cloudrestaurant/tool"
	"fmt"
)

type ShopDao struct {
	*tool.Orm
}

func NewShopDao()*ShopDao{
	return &ShopDao{tool.DbEngine}
}

func (sd *ShopDao)QueryServiceByShopId(shopId int64)[]model.Service{
	var services []model.Service
	err:=sd.Table("service").Join("INNER","shop_service",
		"service.id=shop_service.service_id and shop_id=?",shopId).Find(&services)
	if err!=nil{
		return nil
	}
	return services
}

26.商家在售食品信息展示


package model

/**
 * 食品结构体的定义
 */
type Goods struct {
	Id          int64   `xorm:"pk autoincr" json:"id"`
	Name        string  `xorm:"varchar(12)" json:"name"`
	Description string  `xorm:"varchar(32)" json:"description"`
	Icon        string  `xorm:"varchar(255)" json:"icon"` //商品图标
	SellCount   int64   `xorm:"int" json:"sell_count"`
	Price       float32 `xorm:"float" json:"price"`
	OldPrice    float32 `xorm:"float" json:"old_price"`
	ShopId      int64   `xorm:"int" json:"shop_id"`
}

package controller

import (
	"gin_cloudrestaurant/service"
	"gin_cloudrestaurant/tool"
	"github.com/gin-gonic/gin"
	"strconv"
)

type GoodController struct {
}

func (gc *GoodController) Router(engine *gin.Engine) {
	engine.GET("/api/foods", gc.getGoods)
}
//获取某个商户下面所包含的食品
func (gc *GoodController) getGoods(context *gin.Context) {
	shopId, exist := context.GetQuery("shop_id")
	if !exist {
		tool.Failed(context, "请求参数错误,请重试")
		return
	}
	//实例化一个goodService,并调用对应的service方法
	id, err := strconv.Atoi(shopId)
	if err != nil {
		tool.Failed(context, "请求参数错误,请重试")
		return
	}
	goodService := service.NewGoodService()
	goods := goodService.GetFoods(int64(id))
	if len(goods) == 0 {
		tool.Failed(context, "未查询到数据")
		return
	}
	//查询到商户中的食品数据
	tool.Success(context, goods)

}
package service

import (
	"gin_cloudrestaurant/dao"
	"gin_cloudrestaurant/model"
)

type GoodService struct {

}

func NewGoodService()*GoodService{
	return &GoodService{}
}

/**
 * 获取商家的食品列表
 */
func (gs *GoodService)GetFoods(shop_id int64)[]model.Goods{
	goodDao:=dao.NewGoodDao()
	return goodDao.QueryFoods(shop_id)
}

package dao

import (
	"gin_cloudrestaurant/model"
	"gin_cloudrestaurant/tool"
	"fmt"
)

type GoodDao struct {
	*tool.Orm
}

func NewGoodDao()*GoodDao{
	return &GoodDao{tool.DbEngine}
}

//根据商家的id查询商户下所拥有的所有的食品数据
func (gd *GoodDao)QueryFoods(shop_id int64)[]model.Goods{
	var goods []model.Goods
	err:=gd.Where("shop_id = ?",shop_id).Find(&goods)
	if err!=nil{
		fmt.Println(err.Error())
		return nil
	}
	return  goods
}

在这里插入图片描述

27.Gin框架开发课程总结

请求与返回数据格式

在这里插入图片描述

中间件的使用

在这里插入图片描述
全局使用
在这里插入图片描述
使用session中间件
在这里插入图片描述

在这里插入图片描述
在这里插入图片描述

在这里插入图片描述

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值