GO Web编程---网上书店(4)实现购物车,利用session

实现效果

GO Web编程---网上书店(4)实现购物车,利用session_第1张图片GO Web编程---网上书店(4)实现购物车,利用session_第2张图片

1、将图书加入购物车
依然引入两个结构体
购物车 Cart
购物项 Cartitem,图书数量未知,一个购物项对应一种图书

package model

type Cart struct {
	CartID string
	CartItems []*CartItem //所有的商品
	TotalCount int64 //商品数总和
	TotalAmount float64 //金额总和
	UserID int //购物车所属的用户
}

func (cart *Cart) GetTotalCount() int64{
	var totalCount int64
	for _, v := range cart.CartItems{
		totalCount += v.Count
	}
	return totalCount
}

func (cart *Cart) GetTotalAmount() float64 {
	var totalAmount float64
	for _, v := range cart.CartItems {
		totalAmount += v.GetAmount()
	}
	return totalAmount
}

package model

//购物车里的一项商品
type CartItem struct {
	CartItemID int64
	Book *Book
	Count int64
	Amount float64 //计算得到
	CartID string //属于哪一个购物车
}

func (cartItem *CartItem) GetAmount() float64 {
	price := cartItem.Book.Price
	return float64(cartItem.Count) * price //数量*单价
}

2、数据库插入两个表,carts, cartitems

--创建购物车表
CREATE TABLE carts(
id VARCHAR(100) PRIMARY KEY,
total_count INT NOT NULL,
total_amount DOUBLE(11,2) NOT NULL,
user_id INT NOT NULL,
FOREIGN KEY(user_id) REFERENCES users(id)
)

-- 创建购物项表
CREATE TABLE cart_items(
id INT PRIMARY KEY AUTO_INCREMENT,
COUNT INT NOT NULL,
amount DOUBLE(11,2) NOT NULL,
book_id INT NOT NULL,
cart_id VARCHAR(100) NOT NULL,
FOREIGN KEY(book_id) REFERENCES books(id),
FOREIGN KEY(cart_id) REFERENCES carts(id)
)

3、cartdo.go

//AddCart 向购物车数据库中插入购物车
func AddCart(cart *model.Cart) error {
	//写sql语句
	sqlStr := "insert into carts(id,total_count,total_amount,user_id) values(?,?,?,?)"
	//执行sql
	_, err := utils.Db.Exec(sqlStr, cart.CartID, cart.GetTotalCount(), cart.GetTotalAmount(), cart.UserID)
	if err != nil {
		panic(err)
	}
	//获取购物车中的所有购物项
	cartItems := cart.CartItems
	//遍历得到每一个购物项
	for _, cartItem := range cartItems {
		//将购物项插入到数据库中
		AddCartItem(cartItem)
	}
	return nil
}

Addcart接收*model.cart为参数,将里面的id,total_count,total_amount,user_id 插入数据库中,同时cart.CartItems也必须同时插入数据库

4、cartitemdao.go

//AddCartItem 向购物项表中插入购物项
func AddCartItem(cartItem *model.CartItem) error {
	//写sql
	sqlStr := "insert into cart_items(count,amount,book_id,cart_id) values(?,?,?,?)"
	//执行sql
	_, err := utils.Db.Exec(sqlStr, cartItem.Count, cartItem.GetAmount(), cartItem.Book.ID, cartItem.CartID)
	if err != nil {
		return err
	}
	return nil
}

AddCartItem以*model.CartItem为参数,将它存储的count,amount,book_id,cart_id插入数据库中

5、carthandler.go

先考虑用户已经登陆
(1)要么用户还没有将任何一项物品加入购物车:
那么新建一个购物车;
这本新加入的书之前是否加入过购物车呢?
没加入过,新建购物项;
加入过,只需要更新数据库,把数量+1就可以
(2)要么已经有商品在购物车中了:
不需要新建购物车
这本新加入的书之前是否加入过购物车呢?
没加入过,新建购物项;
加入过,只需要更新数据库,把数量+1就可以

func AddBook2Cart(w http.ResponseWriter, r *http.Request) {
	//判断是否登录
	flag, session := dao.IsLogin(r)
	if flag {
		//已经登录
		//获取要添加的图书的id
		bookID := r.FormValue("bookId")
		//根据图书的id获取图书信息
		book, _ := dao.GetBookById(bookID)

		//获取用户的id
		userID := session.UserID
		//判断数据库中是否有当前用户的购物车
		cart, _ := dao.GetCartByUserID(userID)
		if cart != nil {
			//当前用户已经有购物车,此时需要判断购物车中是否有当前这本图书
			carItem, _ := dao.GetCartItemByBookIDAndCartID(bookID, cart.CartID)
			if carItem != nil {
				//购物车的购物项中已经有该图书,只需要将该图书所对应的购物项中的数量加1即可
				//1.获取购物车切片中的所有的购物项
				cts := cart.CartItems
				//2.遍历得到每一个购物项
				for _, v := range cts {
					//3.找到当前的购物项
					if v.Book.ID == carItem.Book.ID {
						//将购物项中的图书的数量加1
						v.Count = v.Count + 1
						//更新数据库中该购物项的图书的数量
						dao.UpdateBookCount(v)
					}
				}
			} else {
				//购物车的购物项中还没有该图书,此时需要创建一个购物项(1本书)并添加到数据库中
				//创建购物车中的购物项
				cartItem := &model.CartItem{
					Book:   book,
					Count:  1,
					CartID: cart.CartID,
				}
				//将购物项添加到当前cart的切片中
				cart.CartItems = append(cart.CartItems, cartItem)
				//将新创建的购物项添加到数据库中
				dao.AddCartItem(cartItem)
			}
			//更新购物车中的图书的总数量和总金额
			dao.UpdateCart(cart)

6、session

season的实现是通过一组32位的唯一标识,体现它的是哪个用户,与cookie一同使用。
session存储在服务器,存储在mysql中,一个username对应唯一的32位标识
cookie存储在浏览器,它可以储存服务器发过来的session
例子:
用户登陆之后,将username,password表单提交给服务器,服务器在数据库中查询为符合,登陆成功,创建一个seeeion,在数据库写入,同时将它通过cookie发送到浏览器。这个session会永久存储(大概),之后浏览器发送请求都会在请求头附带这个session,服务器就可以获得,然后判断用户是哪一个

发送session:

//用户名密码正确
fmt.Println("用户 ", username, "登陆")
			//session和cookie
			//创建随机数生成的唯一id
			uuid := utils.CreateUUID()
			//创建session,保存uuid,用户名,用户id
			sess := &model.Session{
				SessionID: uuid,
				UserName:  user.Username,
				UserID:    user.Uid,
			}
			//将session保存到数据库中
			dao.AddSession(sess)
			//创建一个cookie,值等于uuid
			cookie := http.Cookie{
				Name:     "user",
				Value:    uuid,
				HttpOnly: true,
			}
			//把cookie发个浏览器,这个cookie会一直存在 Request Headers中
			http.SetCookie(w, &cookie)

接收session:

//获取cookie的value
	cookie, _ := r.Cookie("user")
	if cookie != nil {
		cookieValue := cookie.Value
		session, _:= GetSession(cookieValue)
		if session.UserID > 0 {
			//登陆过了
			session, _ := GetSession(cookieValue)
			return true, session
		}
	}else {
		//没有cookie

session数据结构以及创建其的sql语句

package model

//session
type Session struct {
	SessionID string
	UserName string
	UserID int
	//实现购物车功能
	Cart *Cart
	//实现订单功能加入OrderID
	OrderID string
	Orders []*Order //所有订单
}

----------------------------------------
-- 创建sessions表
CREATE TABLE sessions(
session_id VARCHAR(100) PRIMARY KEY,
username VARCHAR(100) NOT NULL,
user_id INT NOT NULL,
FOREIGN KEY(user_id) REFERENCES users(id)
)

7、
cartdao.go 其他相关操作函数

//GetCartByUserID 根据用户id获得购物车
func GetCartByUserID(userID int) (*model.Cart, error) {
	sqlStr := "select id, total_count, total_amount, user_id from carts where user_id=?"
	row := utils.Db.QueryRow(sqlStr, userID)
	cart := &model.Cart{}
	err := row.Scan(&cart.CartID, &cart.TotalCount, &cart.TotalAmount, &cart.UserID)
	if err!= nil{
		return nil, err
	}
	//CartItems还没有加入,加上,使用查询购物项的函数
	cartItems, _ := GetCartItemsByCartID(cart.CartID)
	cart.CartItems = cartItems
	return cart,nil
}
//UpdateCart 更新购物车中的图书的总数量和总金额
func UpdateCart(cart *model.Cart) error {
	//写sql语句
	sql := "update carts set total_count = ? , total_amount = ? where id = ?"
	//执行
	_, err := utils.Db.Exec(sql, cart.GetTotalCount(), cart.GetTotalAmount(), cart.CartID)
	if err != nil {
		return err
	}
	return nil
}

cartitemdao.go 其他相关操作函数

//GetCartItemsByCartID 根据购物车的id获取购物车中所有的购物项
func GetCartItemsByCartID(cartID string) ([]*model.CartItem, error) {
	//写sql语句
	sqlStr := "select id,count,amount,book_id,cart_id from cart_items where cart_id = ?"
	//执行
	rows, err := utils.Db.Query(sqlStr, cartID)
	if err != nil {
		return nil, err
	}
	var cartItems []*model.CartItem
	for rows.Next() {
		//设置一个变量接收bookId
		var bookID string
		//创建cartItem
		cartItem := &model.CartItem{}
		err2 := rows.Scan(&cartItem.CartItemID, &cartItem.Count, &cartItem.Amount, &bookID, &cartItem.CartID)
		if err2 != nil {
			return nil, err2
		}
		//根据bookID获取图书信息
		book, _ := GetBookById(bookID)
		//将book设置到购物项中
		cartItem.Book = book
		cartItems = append(cartItems, cartItem)
	}
	return cartItems, nil
}

//GetCartItemByBookIDAndCartID 根据图书的id和购物车的id获取对应的购物项
func GetCartItemByBookIDAndCartID(bookID string, cartID string) (*model.CartItem, error) {
	//写sql语句
	sqlStr := "select id,count,amount,cart_id from cart_items where book_id = ? and cart_id = ?"
	//执行
	row := utils.Db.QueryRow(sqlStr, bookID, cartID)
	//设置一个变量接收图书的id
	//创建cartItem
	cartItem := &model.CartItem{}
	err := row.Scan(&cartItem.CartItemID, &cartItem.Count, &cartItem.Amount, &cartItem.CartID)
	if err != nil {
		return nil, err
	}
	//根据图书的id查询图书信息
	book, _ := GetBookById(bookID)
	//将book设置到购物项
	cartItem.Book = book
	return cartItem, nil
}

//UpdateBookCount 根据购物项中的相关信息更新购物项中图书的数量和金额小计
func UpdateBookCount(cartItem *model.CartItem) error {
	//写sql语句
	sql := "update cart_items set count = ? , amount = ? where book_id = ? and cart_id = ?"
	//执行
	_, err := utils.Db.Exec(sql, cartItem.Count, cartItem.GetAmount(), cartItem.Book.ID, cartItem.CartID)
	if err != nil {
		return err
	}
	return nil
}

8、html
index.htnl部分
GO Web编程---网上书店(4)实现购物车,利用session_第3张图片

<div class="book_add">
	{{if .Stock}}
		<button id="{{.ID}}" class="addBook2Cart">加入购物车</button>
	{{else}}
		<span style="color:red">小二拼命补货中...</span>
	{{end}}
</div>

<script>
		$(function(){
			//给添加购物车的按钮绑定单击事件
			$(".addBook2Cart").click(function(){
				//获取要添加的图书的id
				var bookId = $(this).attr("id");
				//设置请求的url
				var url = "/addBook2Cart"
				//设置请求参数
				var param = {"bookId":bookId}
				//发送Ajax请求
				$.post(url,param,function(res){
					if(res == "请先登录!"){
						location = "/pages/user/login.html"
					}else{
						//将响应信息设置到span中
						$("#bookMsg").text(res)
					}
				});
			});
		});
	</script>

cart.html部分
GO Web编程---网上书店(4)实现购物车,利用session_第4张图片

<div id="main">

	{{if .Cart}}
	<table>
		<tr>
			<td>商品名称</td>
			<td>数量</td>
			<td>单价</td>
			<td>金额</td>
			<td>操作</td>
		</tr>
		{{range .Cart.CartItems}}
		<tr>
			<td>{{.Book.Title}}</td>
			<td>
				<input id="{{.CartItemID}}" class="updateCartItem" type="number" min="1" value="{{.Count}}" style="text-align:center;width: 50px;"/>
			</td>
			<td>{{.Book.Price}}</td>
			<td>{{.Amount}}</td>
			<td><a id="{{.Book.Title}}" class="deleteCartItem" href="/deleteCartItem?cartItemId={{.CartItemID}}">删除</a></td>
		</tr>
		{{end}}
	</table>

	<div class="cart_info">
		<span class="cart_span">购物车中共有<span class="b_count" id="totalCount">{{.Cart.TotalCount}}</span>件商品</span>
		<span class="cart_span">总金额<span class="b_price" id="totalAmount">{{.Cart.TotalAmount}}</span></span>
		<span class="cart_span"><a href="/getPageBooksByPrice">继续购物</a></span>
		<span class="cart_span"><a href="/deleteCart?cartId={{.Cart.CartID}}" id="emptyCart">清空购物车</a></span>
		<span class="cart_span"><a href="/checkout">去结账</a></span>
	</div>
	{{else}}
	<br/><br/><br/><br/><br/><br/><br/><br/><br/>
	<h1 style="text-align: center">您的购物车饥渴难耐,快去<a href="/getPageBooksByPrice" style="color:red">购物</a>吧!</h1>
	{{end}}
</div>

总结:几个跟数据库相关的dao函数并不是很难,花点时间想想,有个地方要注意,就是cart里的cartItems参数,它是[ ]*cartitem,需要查询所有的cartitem再append到cartItems里才是正确的。
重点是写业务逻辑的代码:就是考虑用户之前是否有购物车,或者之前是否加入一本一摸一样的书。如果没有就是new一下,插入数据库,这简单;如果有,就要把它们全部找到,再把相应的变化的数据update到数据库。嗯,结束

你可能感兴趣的:(go,web,go语言,web,service)