实现效果
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
}
<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>
<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到数据库。嗯,结束