├── .gitignore ├── Chapter1 ├── 1-1 │ └── main.go ├── 1-2 │ └── main.go └── 1-6 │ └── main.go ├── Chapter10 ├── 10-10 │ └── main.go ├── 10-2 │ └── main.go ├── 10-3 │ └── main.go ├── 10-6 │ └── main.go ├── 10-7 │ └── main.go └── 10-9 │ └── main.go ├── Chapter11 ├── 11-1 │ └── main.go ├── 11-2 │ └── main.go ├── 11-3 │ └── main.go ├── 11-4 │ └── main.go ├── 11-5 │ └── main.go └── 11-6 │ └── main.go ├── Chapter13 └── test1 │ ├── op.go │ └── op_test.go ├── Chapter14 ├── 14-2 │ └── main.go ├── 14-3 │ └── main.go ├── 14-4 │ └── main.go ├── 14-5 │ └── main.go ├── 14-6 │ └── main.go └── 14-7 │ └── main.go ├── Chapter15 ├── 15-2 │ └── main.go ├── 15-4 │ └── main.go ├── 15-5 │ └── main.go ├── 15-6 │ └── main.go ├── 15-7 │ └── main.go └── 15-8 │ └── main.go ├── Chapter16 ├── Handler.go ├── MyLog │ └── MyLog.go ├── app.myerr ├── conf │ ├── app_config.yaml │ └── db_conf.go ├── config │ └── config.go ├── handler │ ├── dp.go │ └── param │ │ ├── OrderSeatParam.go │ │ └── TeamPostOrderParam.go ├── health │ └── health.go ├── main.go ├── middleware │ ├── logging.go │ └── traceid.go ├── model │ ├── OrderSeat.go │ ├── choose_food.go │ ├── comment.go │ ├── comment_tag.go │ ├── discount.go │ ├── guess.go │ ├── hotel.go │ ├── hotel_food_category.go │ ├── indexNavItem.go │ ├── log │ │ └── logger.go │ ├── market.go │ ├── meItem.go │ ├── my_token │ │ └── token.go │ ├── mysql.go │ ├── nav.go │ ├── restrant.go │ ├── same_city.go │ ├── sugguest.go │ ├── suguest_food.go │ ├── take_out.go │ ├── team.go │ ├── team_choose_food.go │ ├── team_choose_item.go │ ├── team_detail.go │ └── team_post_order.go ├── myerr │ ├── code.go │ └── errnum.go ├── repository │ ├── OrderSeat.go │ ├── comment.go │ ├── comment_tag.go │ ├── discount.go │ ├── guess.go │ ├── hotel.go │ ├── indexNavItem.go │ ├── log │ │ └── logger.go │ ├── market.go │ ├── meItem.go │ ├── my_token │ │ └── token.go │ ├── nav.go │ ├── restrant.go │ ├── same_city.go │ ├── sugguest.go │ ├── suguest_food.go │ ├── take_out.go │ ├── team.go │ └── team_post_order.go ├── res │ ├── RespEntity.go │ ├── TeamChooseItemResp.go │ ├── WXLoginResponse.go │ ├── accountResp.go │ ├── hotelFoodCategoryResp.go │ ├── navResp.go │ ├── takeOutItemResp.go │ ├── takeoutResp.go │ ├── teamChooseFoodResp.go │ └── teamResp.go ├── router.go ├── service │ ├── dp_service │ │ ├── OrderSeat.go │ │ ├── comment.go │ │ ├── comment_tag.go │ │ ├── discount.go │ │ ├── guess.go │ │ ├── hotel.go │ │ ├── market.go │ │ ├── me.go │ │ ├── nav_item.go │ │ ├── restrant.go │ │ ├── sugguest_food.go │ │ ├── take_out.go │ │ ├── team.go │ │ └── team_order_post.go │ └── wx_service │ │ └── WXService.go ├── static │ └── images │ │ ├── 001.png │ │ ├── 002.png │ │ ├── 003.png │ │ ├── 21.png │ │ ├── 42.png │ │ ├── 50.png │ │ ├── 51.png │ │ ├── 60.png │ │ ├── 61.png │ │ ├── 80.png │ │ ├── KTVdatu.png │ │ ├── ad8408ec7aa0e3e76cbb92eca2808c7c10489.png │ │ ├── all-small.png │ │ ├── anmo.png │ │ ├── arrow.png │ │ ├── banner.jpg │ │ ├── banner.png │ │ ├── bath.png │ │ ├── cart.jpeg │ │ ├── chuancai.png │ │ ├── chuangyi.png │ │ ├── dongbei.png │ │ ├── dongnanya.png │ │ ├── douyin001.png │ │ ├── douyin002.png │ │ ├── douyin003.png │ │ ├── douyin004.png │ │ ├── douyin005.png │ │ ├── douyin006.png │ │ ├── douyin007.png │ │ ├── douyin008.png │ │ ├── edu.png │ │ ├── food.png │ │ ├── good_restrant001.png │ │ ├── good_restrant002.png │ │ ├── good_restrant003.png │ │ ├── good_restrant_huoguo.png │ │ ├── goods001.png │ │ ├── goods002.png │ │ ├── goods003.png │ │ ├── goods004.png │ │ ├── goods005.png │ │ ├── goods006.png │ │ ├── goods007.png │ │ ├── goods008.png │ │ ├── hair.png │ │ ├── haixian.png │ │ ├── hanguo.png │ │ ├── headPic.png │ │ ├── health.png │ │ ├── heizhenzhu.png │ │ ├── hotel.png │ │ ├── huoguo.png │ │ ├── icon.png │ │ ├── jiangzhe.png │ │ ├── jingdianmenpiaodatu.png │ │ ├── kafei.png │ │ ├── ktv.png │ │ ├── liren.png │ │ ├── lirenmeifadatu.png │ │ ├── maoyandianyingdatu.png │ │ ├── me001.png │ │ ├── me002.png │ │ ├── me003.png │ │ ├── me004.png │ │ ├── me005.png │ │ ├── me006.png │ │ ├── me007.png │ │ ├── me008.png │ │ ├── meishidatu.png │ │ ├── miaosha.png │ │ ├── minsu.png │ │ ├── myCode.png │ │ ├── my_code.png │ │ ├── niuroumian.png │ │ ├── profile.png │ │ ├── qinzi.png │ │ ├── quan.png │ │ ├── ribencai.png │ │ ├── rush.png │ │ ├── search_list_coupon.png │ │ ├── search_list_tuan.png │ │ ├── shaokao.png │ │ ├── sports.png │ │ ├── star.png │ │ ├── star0.png │ │ ├── star1.png │ │ ├── star2.png │ │ ├── team.jpg │ │ ├── team.png │ │ ├── tiandian.png │ │ ├── travel.png │ │ ├── vote.png │ │ ├── waimai.png │ │ ├── waimaidatu.png │ │ ├── xiang.png │ │ ├── xiaochi.png │ │ ├── xican.png │ │ ├── xinjiang.png │ │ ├── xiuxianyuledatu.png │ │ ├── yanchu.png │ │ ├── yuecai.png │ │ ├── yule.png │ │ ├── yundong.png │ │ └── zhoubian.png ├── token │ └── token.go └── utils │ ├── auth.go │ └── utils.go ├── Chapter17 ├── 17-1 │ ├── health │ │ └── health.go │ ├── main.go │ └── router │ │ └── router.go ├── 17-2 │ ├── conf │ │ └── config.yaml │ ├── config │ │ └── config.go │ └── main.go ├── 17-3 │ ├── MyLog │ │ └── MyLog.go │ └── main.go ├── Chapter17 ├── app.MyLog ├── conf │ ├── app_config.yaml │ └── db_conf.go ├── config │ └── config.go ├── handler │ ├── account.go │ ├── handler.go │ └── param │ │ └── AccountParam.go ├── logs │ └── app.MyLog.20210317 ├── main.go ├── model │ ├── account.go │ └── mysql.go ├── repository │ └── account.go ├── router │ └── router.go └── service │ └── account.go ├── Chapter2 ├── 2-1 │ └── main.go ├── 2-2 │ └── main.go ├── 2-3-1 │ └── main.go ├── 2-3-2 │ └── main.go ├── 2-3-3 │ └── main.go ├── 2-3-4 │ └── main.go ├── 2-4-1 │ └── main.go ├── 2-4-2 │ └── main.go ├── 2-4-3 │ └── main.go └── 2-5 │ └── main.go ├── Chapter3 ├── 3-2 │ └── main.go ├── 3-3 │ └── main.go ├── 3-4 │ └── main.go ├── 3-5 │ └── main.go ├── 3-6 │ └── main.go ├── 3-8 │ └── main.go └── 3-9 │ └── main.go ├── Chapter4 ├── 4-1-1 │ └── main.go ├── 4-1-2 │ └── main.go ├── 4-1-3 │ └── main.go ├── 4-1-4 │ └── main.go ├── 4-2-1 │ └── main.go ├── 4-2-2 │ └── main.go ├── 4-2-3 │ └── main.go ├── 4-3 │ └── main.go └── 4-4 │ └── main.go ├── Chapter5 ├── 5-1 │ └── main.go ├── 5-2-1 │ └── main.go ├── 5-2-2 │ └── main.go ├── 5-2-3 │ └── main.go ├── 5-2-4 │ └── main.go ├── 5-3 │ └── main.go └── 5-4 │ └── main.go ├── Chapter6 ├── 6-1 │ └── main.go ├── 6-2 │ └── main.go ├── 6-3-1 │ └── main.go ├── 6-3-2 │ └── main.go ├── 6-3-3 │ └── main.go ├── 6-3-4 │ └── main.go ├── 6-4-1 │ └── main.go ├── 6-4-2 │ └── main.go ├── 6-4 │ └── main.go └── 6-5 │ └── main.go ├── Chapter7 ├── 7-1-1 │ └── main.go ├── 7-1-3 │ └── main.go ├── 7-1-4 │ └── main.go ├── 7-1-5 │ └── main.go ├── 7-1-6 │ └── main.go ├── 7-1 │ └── main.go ├── 7-10 │ └── main.go ├── 7-2-1 │ └── main.go ├── 7-2-2 │ └── main.go ├── 7-3 │ └── main.go ├── 7-4 │ └── main.go ├── 7-5 │ └── main.go ├── 7-6 │ └── main.go ├── 7-7 │ └── main.go ├── 7-8 │ └── main.go └── 7-9 │ └── main.go ├── Chapter8 ├── 8-1 │ └── main.go ├── 8-2 │ └── main.go ├── 8-3 │ └── main.go ├── 8-4 │ └── main.go ├── 8-5 │ └── main.go ├── 8-6 │ └── main.go ├── 8-7 │ └── main.go ├── 8-8 │ └── main.go └── 8-9 │ └── main.go ├── Chapter9 ├── 9-1 │ └── main.go ├── 9-2 │ └── main.go ├── 9-3 │ └── main.go ├── 9-4 │ └── main.go ├── 9-5 │ └── main.go ├── 9-6 │ └── main.go ├── 9-7 │ └── main.go ├── 9-8 │ └── main.go └── 9-9 │ └── main.go ├── Dump20210612.zip ├── LICENSE ├── README.md ├── app.MyLog ├── context_demo └── main.go ├── go.mod └── go.sum /.gitignore: -------------------------------------------------------------------------------- 1 | # Binaries for programs and plugins 2 | *.exe 3 | *.exe~ 4 | *.dll 5 | *.so 6 | *.dylib 7 | 8 | # Test binary, built with `go test -c` 9 | *.test 10 | 11 | # Output of the go coverage tool, specifically when used with LiteIDE 12 | *.out 13 | 14 | # Dependency directories (remove the comment below to include it) 15 | # vendor/ 16 | /.idea/ 17 | /app.err 18 | /logs/app.err.20200613 19 | /app.log 20 | /logs/app.log.20200613 21 | /Chapter13/13-1/13-3 22 | /Chapter13/13-2/13-2 23 | /logs/ 24 | /logs/ 25 | /Chapter16/logs/ 26 | /Chapter13/13-4/13-4 27 | /Chapter13/13-3/app.myerr 28 | /Chapter13/13-3/logs/app.myerr.20200705 29 | /Chapter13/13-3/app.MyLog 30 | /Chapter13/13-3/logs/app.MyLog.20200705 31 | .DS_Store 32 | /Chapter16/Chapter16 33 | 34 | /Chapter2/2-1/main 35 | /Chapter17/17-1/17-1 36 | /Chapter17/17-2/17-2 37 | -------------------------------------------------------------------------------- /Chapter1/1-1/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | ) 6 | 7 | func main() { 8 | fmt.Println("hello Go world") 9 | } 10 | -------------------------------------------------------------------------------- /Chapter1/1-2/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "fmt" 4 | 5 | func main() { 6 | fmt.Println("hello Go world") 7 | } 8 | -------------------------------------------------------------------------------- /Chapter1/1-6/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "fmt" 4 | 5 | var msg = "去外面吃点好的。" 6 | 7 | func main() { 8 | msg := "main函数内" 9 | { 10 | msg := "在家吃点好的" 11 | fmt.Println(msg) 12 | } 13 | fmt.Println(msg) 14 | } 15 | -------------------------------------------------------------------------------- /Chapter10/10-10/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "fmt" 4 | 5 | func MakeFood(c chan string) { 6 | foods := []string{"红烧肉", "清蒸鱼", "溜大虾", "蒸螃蟹", "鲍鱼粥"} 7 | for _, item := range foods { 8 | c <- item 9 | } 10 | close(c) 11 | } 12 | 13 | func main() { 14 | ch := make(chan string) 15 | go MakeFood(ch) 16 | for i := range ch { 17 | fmt.Println(i + " 菜好了") 18 | } 19 | fmt.Println("您的菜,上齐了。") 20 | } 21 | -------------------------------------------------------------------------------- /Chapter10/10-2/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | ) 6 | 7 | func main() { 8 | 9 | for i := 0; i < 10; i++ { 10 | go func() { 11 | fmt.Println(i) 12 | }() 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /Chapter10/10-3/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "time" 6 | ) 7 | 8 | func Work() { 9 | fmt.Println("我在工作") 10 | } 11 | 12 | func main() { 13 | fmt.Println("主协程开始运行") 14 | go Work() 15 | time.Sleep(1 * time.Second) 16 | fmt.Println("主协程运行技术") 17 | } 18 | -------------------------------------------------------------------------------- /Chapter10/10-6/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "fmt" 4 | 5 | func first(c chan<- string) { 6 | c <- "买菜" 7 | close(c) 8 | } 9 | func second(c1 <-chan string, c2 chan<- string) { 10 | r := <-c1 11 | c2 <- r + " 买肉" 12 | close(c2) 13 | } 14 | 15 | func Cook(c <-chan string) { 16 | for r := range c { 17 | fmt.Println(r + "\n已经准备好,吃顿好的!") 18 | } 19 | } 20 | 21 | func main() { 22 | ch1 := make(chan string) 23 | ch2 := make(chan string) 24 | go first(ch1) 25 | go second(ch1, ch2) 26 | Cook(ch2) 27 | fmt.Println("洗碗...") 28 | } 29 | -------------------------------------------------------------------------------- /Chapter10/10-7/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "fmt" 4 | 5 | func Eat(foodName string, c chan bool) { 6 | fmt.Println("我正在吃" + foodName) 7 | c <- true 8 | } 9 | 10 | func main() { 11 | fmt.Println("主协程开始运行") 12 | c := make(chan bool) 13 | go Eat("生蚝", c) 14 | fmt.Println("主协程运行结束") 15 | <-c 16 | } 17 | -------------------------------------------------------------------------------- /Chapter10/10-9/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "time" 6 | ) 7 | 8 | func GetFood1(c chan string) { 9 | time.Sleep(3 * time.Second) 10 | close(c) 11 | } 12 | 13 | func GetFood2(c chan string) { 14 | time.Sleep(3 * time.Second) 15 | c <- "清蒸鱼好了。" 16 | } 17 | 18 | func GetFood3(c chan string) { 19 | time.Sleep(2 * time.Second) 20 | c <- "烤生蚝好了。" 21 | } 22 | 23 | var ch1 chan string 24 | var ch2 chan string 25 | var ch3 chan string 26 | var foods = []string{"红烧肉", "清蒸鱼", "烤生蚝"} 27 | var chs = []chan string{ch1, ch2, ch3} 28 | 29 | func getFood(i int) string { 30 | fmt.Printf("Foods [%d]\n", i) 31 | return foods[i] 32 | } 33 | func getChan(i int) chan string { 34 | fmt.Printf("chs[%d]\n", i) 35 | return chs[i] 36 | } 37 | 38 | func main() { 39 | c1 := make(chan string) 40 | c2 := make(chan string) 41 | c3 := make(chan string) 42 | 43 | go GetFood1(c1) 44 | go GetFood2(c2) 45 | go GetFood3(c3) 46 | 47 | select { 48 | case r := <-c1: 49 | fmt.Println(r) 50 | case r := <-c2: 51 | fmt.Println(r) 52 | case r := <-c3: 53 | fmt.Println(r) 54 | default: 55 | fmt.Println("菜还没有好。") 56 | } 57 | 58 | select { 59 | case r := <-c1: 60 | fmt.Println(r) 61 | case r := <-c2: 62 | fmt.Println(r) 63 | case r := <-c3: 64 | fmt.Println(r) 65 | break 66 | } 67 | 68 | select { 69 | case getChan(0) <- getFood(2): 70 | fmt.Println("1th case is selected.") 71 | case getChan(1) <- getFood(1): 72 | 73 | fmt.Println("2th case is selected.") 74 | default: 75 | fmt.Println("default!.") 76 | } 77 | 78 | } 79 | -------------------------------------------------------------------------------- /Chapter11/11-1/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "fmt" 4 | 5 | var balance int 6 | 7 | func Sum(amount int) { 8 | balance = balance + amount 9 | } 10 | func GetTotal() int { 11 | return balance 12 | } 13 | 14 | func main() { 15 | for i := 0; i < 10; i++ { 16 | go Sum(i) 17 | } 18 | fmt.Println(GetTotal()) 19 | } 20 | -------------------------------------------------------------------------------- /Chapter11/11-2/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "sync" 6 | "time" 7 | ) 8 | 9 | func GetSeatNoLock(name string) { 10 | fmt.Println(name + " 已经抢到位置。") 11 | time.Sleep(1 * time.Second) 12 | fmt.Println(name + " 已经离开。") 13 | } 14 | 15 | var m sync.Mutex 16 | 17 | func GetSeat(name string) { 18 | m.Lock() 19 | defer m.Unlock() 20 | fmt.Println(name + " 已经抢到位置。") 21 | time.Sleep(1 * time.Second) 22 | fmt.Println(name + " 已经离开。") 23 | } 24 | 25 | func main() { 26 | s := []string{"老张", "老王", "老李"} 27 | for i := 0; i < len(s); i++ { 28 | go GetSeatNoLock(s[i]) 29 | } 30 | time.Sleep(5 * time.Second) 31 | fmt.Println("-------------------") 32 | for i := 0; i < len(s); i++ { 33 | go GetSeat(s[i]) 34 | } 35 | time.Sleep(5 * time.Second) 36 | fmt.Println("-------------------") 37 | for i := 0; i < len(s); i++ { 38 | go CheckSeatWithRWLock(s[i]) 39 | go GetSeatWithRWLock(s[i]) 40 | } 41 | 42 | time.Sleep(8 * time.Second) 43 | } 44 | 45 | var rw sync.RWMutex 46 | 47 | func GetSeatWithRWLock(name string) { 48 | rw.Lock() 49 | defer rw.Unlock() 50 | fmt.Println(name + " 已经抢到位置。") 51 | time.Sleep(1 * time.Second) 52 | fmt.Println(name + " 已经离开。") 53 | } 54 | func CheckSeatWithRWLock(name string) { 55 | rw.RLock() 56 | defer rw.RUnlock() 57 | fmt.Println(name + " 查看位置。") 58 | time.Sleep(1 * time.Second) 59 | } 60 | -------------------------------------------------------------------------------- /Chapter11/11-3/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "sync" 6 | ) 7 | 8 | func main() { 9 | var buySth string 10 | var box sync.RWMutex 11 | sendCond := sync.NewCond(&box) 12 | recvCond := sync.NewCond(box.RLocker()) 13 | flag := make(chan bool, 5) 14 | go func() { 15 | defer func() { 16 | fmt.Println("已投递,完成~") 17 | flag <- true 18 | }() 19 | box.Lock() 20 | for buySth == "已投递" { 21 | sendCond.Wait() 22 | } 23 | buySth = "已投递" 24 | box.Unlock() 25 | recvCond.Signal() 26 | }() 27 | 28 | go func() { 29 | defer func() { 30 | fmt.Println("货物已经取走") 31 | flag <- true 32 | }() 33 | box.RLock() 34 | for buySth == "" { 35 | recvCond.Wait() 36 | } 37 | buySth = "" 38 | box.RUnlock() 39 | sendCond.Signal() 40 | }() 41 | 42 | <-flag 43 | <-flag 44 | } 45 | -------------------------------------------------------------------------------- /Chapter11/11-4/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "sync/atomic" 6 | ) 7 | 8 | func main() { 9 | var num1 uint64 10 | atomic.AddUint64(&num1, 70) 11 | fmt.Println(num1) 12 | atomic.AddUint64(&num1, ^uint64(23)) 13 | fmt.Println(num1) 14 | 15 | var num2 uint64 16 | num2 = 5 17 | ok := atomic.CompareAndSwapUint64(&num2, 5, 50) 18 | fmt.Println(ok) 19 | fmt.Println(num2) 20 | ok = atomic.CompareAndSwapUint64(&num2, 40, 50) 21 | fmt.Println(ok) 22 | fmt.Println(num2) 23 | 24 | var num3 uint64 25 | num3 = 10 26 | num := atomic.LoadUint64(&num3) 27 | fmt.Println(num) 28 | 29 | var num4 uint64 30 | num4 = 1 31 | atomic.StoreUint64(&num4, 28) 32 | fmt.Println(num4) 33 | } 34 | -------------------------------------------------------------------------------- /Chapter11/11-5/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "sync" 6 | "time" 7 | ) 8 | 9 | func main() { 10 | var wg sync.WaitGroup 11 | fmt.Println("可以点菜了吗?") 12 | wg.Add(1) 13 | go func() { 14 | defer wg.Done() 15 | fmt.Println("老张没没到") 16 | time.Sleep(1 * time.Second) 17 | fmt.Println("老张到了") 18 | }() 19 | 20 | wg.Add(1) 21 | go func() { 22 | defer wg.Done() 23 | fmt.Println("老王还没到") 24 | time.Sleep(500 * time.Millisecond) 25 | fmt.Println("老王到了") 26 | }() 27 | fmt.Println("等所有人到齐 ") 28 | wg.Wait() 29 | fmt.Println("所有人到齐了,可以点菜了!") 30 | 31 | var once sync.Once 32 | for i := 0; i < 5; i++ { 33 | once.Do(func() { 34 | fmt.Println("春节快乐。") 35 | }) 36 | } 37 | 38 | } 39 | -------------------------------------------------------------------------------- /Chapter11/11-6/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "context" 5 | "fmt" 6 | "math/rand" 7 | "strconv" 8 | "sync/atomic" 9 | "time" 10 | ) 11 | 12 | func main() { 13 | Free() 14 | 15 | d := time.Now().Add(100 * time.Millisecond) 16 | ctx, cancel := context.WithDeadline(context.Background(), d) 17 | defer cancel() 18 | select { 19 | case <-time.After(1 * time.Second): 20 | fmt.Println("overslept") 21 | case <-ctx.Done(): 22 | fmt.Println(ctx.Err()) 23 | } 24 | 25 | f := func(ctx context.Context, k string) { 26 | if v := ctx.Value(k); v != nil { 27 | fmt.Println("找到了:", v) 28 | return 29 | } 30 | fmt.Println("没找到:", k) 31 | } 32 | 33 | k := "language" 34 | ctx2 := context.WithValue(context.Background(), k, "Go") 35 | 36 | f(ctx2, k) 37 | f(ctx, "color") 38 | } 39 | 40 | func Free() { 41 | fmt.Println("如果今天有过生日的人,会说出一个数字,这个数字如果和我们的一致,则这顿饭免单") 42 | secret := rand.Intn(100) 43 | //secret := 87 44 | ctx, cancelFunc := context.WithCancel(context.Background()) 45 | defer cancelFunc() 46 | for i := 1; i <= 3; i++ { 47 | var num int32 48 | r := rand.Intn(100) 49 | num = int32(r) 50 | fmt.Printf("我猜的数字是: %d\n", num) 51 | go choose(func() { 52 | if atomic.LoadInt32(&num) == int32(secret) { 53 | fmt.Println("猜对了,给您免单") 54 | } 55 | }) 56 | } 57 | go func() { 58 | <-ctx.Done() 59 | }() 60 | time.Sleep(3*time.Second) 61 | fmt.Println("答案是" + strconv.Itoa(secret)) 62 | fmt.Println("感谢光临,聚餐结束。") 63 | } 64 | func choose(deferFunc func()) { 65 | defer func() { 66 | deferFunc() 67 | }() 68 | time.Sleep(time.Second * 2) 69 | } 70 | -------------------------------------------------------------------------------- /Chapter13/test1/op.go: -------------------------------------------------------------------------------- 1 | package test1 2 | 3 | func Sum() int { 4 | total:=0 5 | for i:=0;i<10;i++{ 6 | total+=i 7 | } 8 | return total 9 | } -------------------------------------------------------------------------------- /Chapter13/test1/op_test.go: -------------------------------------------------------------------------------- 1 | package test1 2 | 3 | import ( 4 | "fmt" 5 | "github.com/stretchr/testify/assert" 6 | "testing" 7 | ) 8 | 9 | func TestSum(t *testing.T) { 10 | result := Sum() 11 | fmt.Println(result) 12 | assert.Equal(t, result, 45) 13 | } 14 | 15 | func BenchmarkSum(b *testing.B) { 16 | for i := 0; i < 100; i++ { 17 | Sum() 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /Chapter14/14-2/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "reflect" 6 | ) 7 | 8 | type T struct{} 9 | 10 | func (t *T) GoodDinner() { 11 | fmt.Println("吃顿好的。") 12 | } 13 | 14 | func main() { 15 | name := "GoodDinner" 16 | t := &T{} 17 | reflect.ValueOf(t).MethodByName(name).Call(nil) 18 | } 19 | -------------------------------------------------------------------------------- /Chapter14/14-3/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "reflect" 6 | ) 7 | 8 | type T struct{} 9 | 10 | func main() { 11 | name := "GoodDinner" 12 | t := &T{} 13 | param1 := reflect.ValueOf(666) 14 | param2 := reflect.ValueOf("红烧肉") 15 | params := []reflect.Value{param1, param2} 16 | reflect.ValueOf(t).MethodByName(name).Call(params) 17 | } 18 | 19 | func (t *T) GoodDinner(a int, b string) { 20 | fmt.Println("吃顿好的,"+b, a) 21 | } 22 | -------------------------------------------------------------------------------- /Chapter14/14-4/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "reflect" 6 | ) 7 | 8 | type Person struct { 9 | Age int `json:"name" test:"testname"` 10 | Name string `json:"age" test:"testage"` 11 | } 12 | 13 | func main() { 14 | p := Person{ 15 | Age: 23, 16 | Name: "小明", 17 | } 18 | refType := reflect.TypeOf(p) 19 | for i := 0; i < refType.NumField(); i++ { 20 | field := refType.Field(i) 21 | if jsonItem, ok := field.Tag.Lookup("json"); ok { 22 | fmt.Println(jsonItem) 23 | } 24 | testItem := field.Tag.Get("test") 25 | fmt.Println(testItem) 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /Chapter14/14-5/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "reflect" 6 | ) 7 | 8 | type Person struct { 9 | Age int `json:"NewAge"` 10 | Name string `json:"NewName"` 11 | } 12 | type newPerson struct { 13 | NewAge int 14 | NewName string 15 | } 16 | 17 | func main() { 18 | t := Person{ 19 | Age: 23, 20 | Name: "小明", 21 | } 22 | refType := reflect.TypeOf(t) 23 | refValue := reflect.ValueOf(t) 24 | newPerson := &newPerson{} 25 | newValue := reflect.ValueOf(newPerson) 26 | for i := 0; i < refType.NumField(); i++ { 27 | field := refType.Field(i) 28 | newTag := field.Tag.Get("json") 29 | tValue := refValue.Field(i) 30 | newValue.Elem().FieldByName(newTag).Set(tValue) 31 | } 32 | fmt.Println(newPerson) 33 | } 34 | -------------------------------------------------------------------------------- /Chapter14/14-6/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "reflect" 6 | ) 7 | 8 | func main() { 9 | v := "红烧肉" 10 | t := reflect.TypeOf(v) 11 | switch t.Kind() { 12 | case reflect.Int: 13 | fmt.Println("int") 14 | case reflect.String: 15 | fmt.Println("string") 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /Chapter14/14-7/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "reflect" 6 | ) 7 | 8 | type IFly interface { 9 | Fly() 10 | } 11 | type Bird struct { 12 | Name string 13 | } 14 | 15 | func (b *Bird) Fly() {} 16 | 17 | func main() { 18 | bird := &Bird{} 19 | t := reflect.TypeOf((*IFly)(nil)).Elem() 20 | refType := reflect.TypeOf(bird) 21 | fmt.Println(refType.Implements(t)) 22 | } 23 | -------------------------------------------------------------------------------- /Chapter15/15-2/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "github.com/gin-gonic/gin" 4 | 5 | func main() { 6 | r := gin.Default() 7 | r.GET("/", func(c *gin.Context) { 8 | c.JSON(200, gin.H{ 9 | "Blog":"www.coolpest8.com", 10 | "wechat":"zb13161658867", 11 | }) 12 | }) 13 | r.Run(":8080") 14 | 15 | } 16 | -------------------------------------------------------------------------------- /Chapter15/15-4/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "github.com/gin-gonic/gin" 4 | 5 | func main() { 6 | r := gin.Default() 7 | 8 | r.GET("/users/:id", func(c *gin.Context) { 9 | id := c.Param("id") 10 | c.String(200, "The user id is %s", id) 11 | }) 12 | r.Run(":8080") 13 | 14 | } 15 | -------------------------------------------------------------------------------- /Chapter15/15-5/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "github.com/gin-gonic/gin" 4 | 5 | func main() { 6 | r := gin.Default() 7 | 8 | r.GET("/", func(c *gin.Context) { 9 | c.String(200, c.Query("wechat")) 10 | }) 11 | r.Run(":8080") 12 | 13 | } 14 | -------------------------------------------------------------------------------- /Chapter15/15-6/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "github.com/gin-gonic/gin" 4 | 5 | func main() { 6 | r := gin.Default() 7 | r.GET("/", func(c *gin.Context) { 8 | c.JSON(200, c.QueryArray("media")) 9 | }) 10 | r.GET("/map", func(c *gin.Context) { 11 | c.JSON(200, c.Query("ids")) 12 | }) 13 | r.Run(":8080") 14 | 15 | } 16 | -------------------------------------------------------------------------------- /Chapter15/15-7/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "github.com/gin-gonic/gin" 4 | 5 | func main() { 6 | r := gin.Default() 7 | r.POST("/", func(c *gin.Context) { 8 | wechat := c.PostForm("wechat") 9 | c.String(200, wechat) 10 | }) 11 | 12 | r.Run(":8080") 13 | 14 | } 15 | -------------------------------------------------------------------------------- /Chapter15/15-8/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "github.com/gin-gonic/gin" 4 | 5 | type user struct { 6 | ID int 7 | Name string 8 | Age int 9 | } 10 | 11 | func main() { 12 | r := gin.Default() 13 | r.GET("/hello", func(c *gin.Context) { 14 | c.JSON(200, gin.H{"message": "hello world"}) 15 | }) 16 | r.GET("/users/123", func(c *gin.Context) { 17 | c.JSON(200, user{ID: 123, Name: "欢喜哥", Age: 20}) 18 | }) 19 | r.Run(":8080") 20 | 21 | } 22 | -------------------------------------------------------------------------------- /Chapter16/Handler.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "github.com/i-coder-robot/book_final_code/Chapter16/conf" 6 | "github.com/i-coder-robot/book_final_code/Chapter16/config" 7 | "github.com/i-coder-robot/book_final_code/Chapter16/handler" 8 | "github.com/i-coder-robot/book_final_code/Chapter16/model" 9 | "github.com/i-coder-robot/book_final_code/Chapter16/repository" 10 | "github.com/i-coder-robot/book_final_code/Chapter16/service/dp_service" 11 | "github.com/jinzhu/gorm" 12 | "github.com/spf13/viper" 13 | "log" 14 | ) 15 | 16 | var ( 17 | DB *gorm.DB 18 | ) 19 | 20 | func initViper() { 21 | if err := config.Init(""); err != nil { 22 | panic(err) 23 | } 24 | } 25 | 26 | func initDB() { 27 | fmt.Println("数据库 init") 28 | var err error 29 | conf := &conf.DBConf{ 30 | Host: viper.GetString("database.host"), 31 | User: viper.GetString("database.username"), 32 | Password: viper.GetString("database.password"), 33 | DbName: viper.GetString("database.name"), 34 | } 35 | 36 | config := fmt.Sprintf("%s:%s@tcp(%s)/%s?parseTime=true&charset=utf8&parseTime=%t&loc=%s", 37 | conf.User, 38 | conf.Password, 39 | conf.Host, 40 | conf.DbName, 41 | true, 42 | "Local") 43 | 44 | DB, err = gorm.Open("mysql", config) 45 | if err != nil { 46 | log.Fatalf("connect error: %v\n", err) 47 | } 48 | DB.SingularTable(true) 49 | fmt.Println("数据库 init 结束...") 50 | } 51 | 52 | func initHandler() { 53 | DiscountHandler = handler.DiscountHandler{ 54 | Srv: &dp_service.DiscountService{ 55 | Repo: &repository.Discount{ 56 | DB: model.DataBase{ 57 | MyDB: DB, 58 | }, 59 | }, 60 | }, 61 | } 62 | RestaurantNavHandler = handler.RestaurantNavHandler{ 63 | Srv: &dp_service.RestaurantService{ 64 | Repo: &repository.RestaurantNavRepo{ 65 | DB: model.DataBase{ 66 | MyDB: DB, 67 | }, 68 | }, 69 | ItemRepo: &repository.RestaurantTabItemRepo{ 70 | DB: model.DataBase{ 71 | MyDB: DB, 72 | }, 73 | }, 74 | }, 75 | } 76 | HotelDetailHandler = handler.HotelDetailHandler{ 77 | Srv: &dp_service.HotelService{ 78 | Repo: &repository.HotelRepo{ 79 | DB: model.DataBase{ 80 | MyDB: DB, 81 | }, 82 | }, 83 | TeamRepo: &repository.TeamRepo{ 84 | DB: model.DataBase{ 85 | MyDB: DB, 86 | }, 87 | }, 88 | SuggestFoodRepo: &repository.SuggestFoodRepo{ 89 | DB: model.DataBase{ 90 | MyDB: DB, 91 | }, 92 | }, 93 | CommentTagRepo: &repository.CommentTagRepo{ 94 | DB: model.DataBase{ 95 | MyDB: DB, 96 | }, 97 | }, 98 | CommentRepo: &repository.CommentRepo{ 99 | DB: model.DataBase{ 100 | MyDB: DB, 101 | }, 102 | }, 103 | MarketRepo: &repository.MarketRepo{ 104 | DB: model.DataBase{ 105 | MyDB: DB, 106 | }, 107 | }, 108 | }, 109 | } 110 | TeamDetailHandler = handler.TeamDetailHandler{ 111 | Srv: &dp_service.TeamService{ 112 | Repo: &repository.TeamRepo{ 113 | DB: model.DataBase{ 114 | MyDB: DB, 115 | }, 116 | }, 117 | }, 118 | } 119 | OrderSeatHandler = handler.OrderSeatHandler{ 120 | Srv: &dp_service.OrderSeatService{ 121 | Repo: &repository.OrderSeatRepo{ 122 | DB: model.DataBase{ 123 | MyDB: DB, 124 | }, 125 | }, 126 | }, 127 | } 128 | TakeOutHandler = handler.TakeOutHandler{ 129 | Srv: &dp_service.TakeOutService{ 130 | Repo: &repository.TakeOutItemRepo{ 131 | DB: model.DataBase{ 132 | MyDB: DB, 133 | }, 134 | }, 135 | }, 136 | } 137 | MeHandler = handler.MeHandler{ 138 | Srv: &dp_service.MeService{ 139 | Repo: &repository.MeItemRepo{ 140 | DB: model.DataBase{ 141 | MyDB: DB, 142 | }, 143 | }, 144 | }, 145 | } 146 | SuggestFoodHandler = handler.SuggestFoodHandler{ 147 | Srv: &dp_service.SuggestFoodService{ 148 | Repo: &repository.SuggestFoodRepo{ 149 | DB: model.DataBase{ 150 | MyDB: DB, 151 | }, 152 | }, 153 | }, 154 | } 155 | SuggestHandler = handler.SuggestHandler{ 156 | Srv: &dp_service.SuggestService{ 157 | Repo: &repository.SuggestRepo{ 158 | DB: model.DataBase{ 159 | MyDB: DB, 160 | }, 161 | }, 162 | }, 163 | } 164 | GuessHandler = handler.GuessHandler{ 165 | Srv: &dp_service.GuessService{ 166 | Repo: &repository.GuessRepo{ 167 | DB: model.DataBase{ 168 | MyDB: DB, 169 | }, 170 | }, 171 | }, 172 | } 173 | NavHandler = handler.NavHandler{ 174 | Srv: &dp_service.ListNavItemService{ 175 | Repo: &repository.ListNavItemRepo{ 176 | DB: model.DataBase{ 177 | MyDB: DB, 178 | }, 179 | }, 180 | }, 181 | } 182 | PostTeamOrderHandler = handler.PostTeamOrderHandler{ 183 | Srv: &dp_service.PostTeamOrderService{ 184 | Repo: &repository.TeamPostOrderRepo{ 185 | DB: model.DataBase{ 186 | MyDB: DB, 187 | }, 188 | }, 189 | TeamRepo: &repository.TeamRepo{ 190 | DB: model.DataBase{ 191 | MyDB: DB, 192 | }, 193 | }, 194 | }, 195 | } 196 | } 197 | -------------------------------------------------------------------------------- /Chapter16/MyLog/MyLog.go: -------------------------------------------------------------------------------- 1 | package MyLog 2 | 3 | import ( 4 | "fmt" 5 | rotatelogs "github.com/lestrrat-go/file-rotatelogs" 6 | "go.uber.org/zap" 7 | "go.uber.org/zap/zapcore" 8 | "io" 9 | "os" 10 | "time" 11 | ) 12 | 13 | var Log *zap.SugaredLogger 14 | 15 | const ( 16 | output_dir = "./logs/" 17 | out_path = "app.MyLog" 18 | err_path = "app.myerr" 19 | ) 20 | 21 | func init() { 22 | _, err := os.Stat(output_dir) 23 | if err != nil { 24 | if os.IsNotExist(err) { 25 | err := os.Mkdir(output_dir, os.ModePerm) 26 | if err != nil { 27 | fmt.Printf("创建目录失败![%v]\n", err) 28 | } 29 | } 30 | } 31 | // 设置一些基本日志格式 32 | encoder := zapcore.NewConsoleEncoder(zapcore.EncoderConfig{ 33 | MessageKey: "msg", 34 | LevelKey: "level", 35 | TimeKey: "ts", 36 | CallerKey: "caller", 37 | StacktraceKey: "trace", 38 | LineEnding: zapcore.DefaultLineEnding, 39 | EncodeLevel: zapcore.LowercaseLevelEncoder, 40 | EncodeCaller: zapcore.ShortCallerEncoder, 41 | EncodeTime: func(t time.Time, enc zapcore.PrimitiveArrayEncoder) { 42 | enc.AppendString(t.Format("2006-01-02 15:04:05")) 43 | }, 44 | EncodeDuration: func(d time.Duration, enc zapcore.PrimitiveArrayEncoder) { 45 | enc.AppendInt64(int64(d) / 1000000) 46 | }, 47 | }) 48 | 49 | // 实现两个判断日志等级的interface 50 | infoLevel := zap.LevelEnablerFunc(func(lvl zapcore.Level) bool { 51 | return true 52 | }) 53 | 54 | warnLevel := zap.LevelEnablerFunc(func(lvl zapcore.Level) bool { 55 | return lvl >= zapcore.WarnLevel 56 | }) 57 | 58 | // 获取 info、warn日志文件的io.Writer 抽象 getWriter() 在下方实现 59 | infoHook_1 := os.Stdout 60 | infoHook_2 := getWriter(out_path) 61 | errorHook := getWriter(err_path) 62 | 63 | // 最后创建具体的Logger 64 | core := zapcore.NewTee( 65 | zapcore.NewCore(encoder, zapcore.AddSync(infoHook_1), infoLevel), 66 | zapcore.NewCore(encoder, zapcore.AddSync(infoHook_2), infoLevel), 67 | zapcore.NewCore(encoder, zapcore.AddSync(errorHook), warnLevel), 68 | ) 69 | 70 | // 需要传入 zap.AddCaller() 才会显示打日志点的文件名和行数 71 | logger := zap.New(core, zap.AddCaller(), zap.AddStacktrace(zap.ErrorLevel)) 72 | Log = logger.Sugar() 73 | defer logger.Sync() 74 | } 75 | func getWriter(filename string) io.Writer { 76 | // 生成rotatelogs的Logger 实际生成的文件名 app.MyLog.YYmmddHH 77 | // app.log是指向最新日志的链接 78 | // 保存7天内的日志,每1小时(整点)分割一次日志 79 | hook, err := rotatelogs.New( 80 | output_dir+filename+".%Y%m%d", 81 | rotatelogs.WithLinkName(filename), 82 | rotatelogs.WithMaxAge(time.Hour*24*7), 83 | rotatelogs.WithRotationTime(time.Hour*24), 84 | ) 85 | if err != nil { 86 | panic(err) 87 | } 88 | return hook 89 | } 90 | -------------------------------------------------------------------------------- /Chapter16/app.myerr: -------------------------------------------------------------------------------- 1 | ./logs/app.myerr.20201110 -------------------------------------------------------------------------------- /Chapter16/conf/app_config.yaml: -------------------------------------------------------------------------------- 1 | runmode: debug # 开发模式, debug, release, test 2 | addr: :9090 # HTTP绑定端口 3 | url: http://127.0.0.1:9090 # pingServer函数请求的API服务器的ip:port 4 | max_check_count: 10 # pingServer函数尝试的次数 5 | database: 6 | name: db 7 | addr: 127.0.0.1:3306 8 | username: root 9 | password: smartwell 10 | wx_app_id: 123 11 | wx_secret: 123 -------------------------------------------------------------------------------- /Chapter16/conf/db_conf.go: -------------------------------------------------------------------------------- 1 | package conf 2 | 3 | type DBConf struct { 4 | Driver string 5 | // Host 主机地址 6 | Host string 7 | // Port 主机端口 8 | Port string 9 | // User 用户名 10 | User string 11 | // Password 密码 12 | Password string 13 | // DbName 数据库名称 14 | DbName string 15 | // Charset 数据库编码 16 | Charset string 17 | } 18 | -------------------------------------------------------------------------------- /Chapter16/config/config.go: -------------------------------------------------------------------------------- 1 | package config 2 | 3 | import ( 4 | "github.com/fsnotify/fsnotify" 5 | "github.com/i-coder-robot/book_final_code/Chapter16/MyLog" 6 | "github.com/spf13/viper" 7 | "log" 8 | ) 9 | 10 | type Config struct { 11 | Name string 12 | } 13 | 14 | func Init(name string) error { 15 | c := Config{ 16 | Name: name, 17 | } 18 | 19 | // 初始化配置文件 20 | if err := c.initConfig(); err != nil { 21 | MyLog.Log.Error(err) 22 | return err 23 | } 24 | 25 | // 监控配置文件变化并热加载程序 26 | c.watchConfig() 27 | 28 | return nil 29 | } 30 | 31 | func (c *Config) initConfig() error { 32 | if c.Name != "" { 33 | viper.SetConfigFile(c.Name) // 如果指定了配置文件,则解析指定的配置文件 34 | } else { 35 | //viper.AddConfigPath("./Chapter16/conf/") //goland debug的配置 36 | viper.AddConfigPath("./conf/") //命令行的配置 37 | viper.SetConfigName("app_config") 38 | } 39 | viper.SetConfigType("yaml") // 设置配置文件格式为YAML 40 | if err := viper.ReadInConfig(); err != nil { // viper解析配置文件 41 | return err 42 | } 43 | 44 | return nil 45 | } 46 | 47 | // 监控配置文件变化并热加载程序 48 | func (c *Config) watchConfig() { 49 | viper.WatchConfig() 50 | viper.OnConfigChange(func(e fsnotify.Event) { 51 | log.Printf("Config file changed: %s", e.Name) 52 | }) 53 | } 54 | -------------------------------------------------------------------------------- /Chapter16/handler/dp.go: -------------------------------------------------------------------------------- 1 | package handler 2 | 3 | import ( 4 | "fmt" 5 | "github.com/gin-gonic/gin" 6 | "github.com/i-coder-robot/book_final_code/Chapter16/handler/param" 7 | "github.com/i-coder-robot/book_final_code/Chapter16/service/dp_service" 8 | "io/ioutil" 9 | "net/http" 10 | "os" 11 | ) 12 | 13 | const domain = "http://192.168.0.104:8080" 14 | 15 | type DiscountHandler struct { 16 | Srv *dp_service.DiscountService 17 | } 18 | type RestaurantNavHandler struct { 19 | Srv *dp_service.RestaurantService 20 | } 21 | 22 | type HotelDetailHandler struct { 23 | Srv *dp_service.HotelService 24 | } 25 | 26 | type TeamDetailHandler struct { 27 | Srv *dp_service.TeamService 28 | } 29 | 30 | type OrderSeatHandler struct { 31 | Srv *dp_service.OrderSeatService 32 | } 33 | 34 | type TakeOutHandler struct { 35 | Srv *dp_service.TakeOutService 36 | } 37 | 38 | type MeHandler struct { 39 | Srv *dp_service.MeService 40 | } 41 | 42 | type SuggestFoodHandler struct { 43 | Srv *dp_service.SuggestFoodService 44 | } 45 | 46 | type SuggestHandler struct { 47 | Srv *dp_service.SuggestService 48 | } 49 | 50 | type GuessHandler struct { 51 | Srv *dp_service.GuessService 52 | } 53 | type NavHandler struct { 54 | Srv *dp_service.ListNavItemService 55 | } 56 | 57 | type PostTeamOrderHandler struct { 58 | Srv *dp_service.PostTeamOrderService 59 | } 60 | 61 | func (h *DiscountHandler) DiscountList(c *gin.Context) { 62 | discounts := h.Srv.ListDiscounts() 63 | c.JSON(http.StatusOK, gin.H{ 64 | "items": discounts, 65 | }) 66 | } 67 | 68 | func (h *RestaurantNavHandler) RestaurantNav(c *gin.Context) { 69 | items := h.Srv.ListRestaurantNav(1) 70 | c.JSON(http.StatusOK, gin.H{ 71 | "items": items, 72 | }) 73 | } 74 | 75 | func (h *RestaurantNavHandler) GoodRestaurantBillBoardHandler(c *gin.Context) { 76 | items := h.Srv.ListRestaurantNav(2) 77 | c.JSON(http.StatusOK, gin.H{ 78 | "items": items, 79 | }) 80 | } 81 | 82 | func (h *RestaurantNavHandler) GoodRestaurantTabItemHandler(c *gin.Context) { 83 | items := h.Srv.ListGoodRestaurantTabItem() 84 | c.JSON(http.StatusOK, gin.H{ 85 | "items": items, 86 | }) 87 | } 88 | 89 | func (h *HotelDetailHandler) HotelDetailHandler(c *gin.Context) { 90 | hotelId := c.Param("id") 91 | 92 | hotel, err := h.Srv.GetHotelDetailByID(hotelId) 93 | //TODO 直接记录错误日志 94 | if err != nil { 95 | c.JSON(http.StatusOK, gin.H{ 96 | "item": nil, 97 | "msg": err.Error(), 98 | }) 99 | } else { 100 | c.JSON(http.StatusOK, gin.H{ 101 | "item": hotel, 102 | "msg": "", 103 | }) 104 | } 105 | } 106 | 107 | func (h *TeamDetailHandler) TeamDetailHandler(c *gin.Context) { 108 | teamId := c.Param("id") 109 | detail := h.Srv.GetTeamDetail(teamId) 110 | 111 | c.JSON(http.StatusOK, gin.H{ 112 | "item": detail, 113 | }) 114 | } 115 | 116 | func (h *PostTeamOrderHandler) TeamOrderHandler(c *gin.Context) { 117 | var p param.TeamPostOrder 118 | err := c.BindJSON(&p) 119 | if err != nil { 120 | c.JSON(http.StatusOK, gin.H{ 121 | "err": err.Error(), 122 | }) 123 | } 124 | id, err := h.Srv.PostTeamOrder(p) 125 | if err != nil { 126 | c.JSON(http.StatusOK, gin.H{ 127 | "id": "", 128 | "err": err.Error(), 129 | }) 130 | } else { 131 | c.JSON(http.StatusOK, gin.H{ 132 | "id": id, 133 | "err": "", 134 | }) 135 | } 136 | } 137 | 138 | func (h *OrderSeatHandler) OrderSeat(c *gin.Context) { 139 | var p param.OrderSeat 140 | err := c.BindJSON(&p) 141 | if err != nil { 142 | c.JSON(http.StatusOK, gin.H{ 143 | "err": err.Error(), 144 | }) 145 | } 146 | id := h.Srv.OrderSeatOp(p) 147 | c.JSON(http.StatusOK, gin.H{ 148 | "id": id, 149 | "err": "", 150 | }) 151 | } 152 | 153 | func (h *TakeOutHandler) GetTakeOutByHotelId(c *gin.Context) { 154 | hotelId := c.Param("hotelId") 155 | item := h.Srv.GetTakeOutListByHotelId(hotelId) 156 | c.JSON(http.StatusOK, gin.H{ 157 | "item": item, 158 | }) 159 | } 160 | 161 | func (h *MeHandler) MeHandler(c *gin.Context) { 162 | items := h.Srv.ListMe() 163 | c.JSON(http.StatusOK, gin.H{ 164 | "items": items, 165 | }) 166 | } 167 | 168 | func (h *NavHandler) NavHandler(c *gin.Context) { 169 | items := h.Srv.ListNavItems(1) 170 | c.JSON(http.StatusOK, gin.H{ 171 | "items": items, 172 | }) 173 | } 174 | 175 | func (h *NavHandler) SubNavHandler(c *gin.Context) { 176 | items := h.Srv.ListNavItems(2) 177 | c.JSON(http.StatusOK, gin.H{ 178 | "items": items, 179 | }) 180 | } 181 | 182 | func (h *SuggestFoodHandler) TeamHandler(c *gin.Context) { 183 | items := h.Srv.ListSuggestList(1) 184 | c.JSON(http.StatusOK, gin.H{"item": items}) 185 | } 186 | 187 | func (h *SuggestFoodHandler) RushHandler(c *gin.Context) { 188 | items := h.Srv.ListSuggestList(2) 189 | c.JSON(http.StatusOK, gin.H{"item": items}) 190 | } 191 | 192 | func (h *SuggestHandler) TeamHandler(c *gin.Context) { 193 | fmt.Println("TeamHandler....") 194 | item := h.Srv.GetSuggestByLevel(1) 195 | fmt.Println(item) 196 | c.JSON(http.StatusOK, gin.H{"item": item}) 197 | } 198 | 199 | func (h *SuggestHandler) RushHandler(c *gin.Context) { 200 | item := h.Srv.GetSuggestByLevel(2) 201 | c.JSON(http.StatusOK, gin.H{"item": item}) 202 | } 203 | 204 | func (h *GuessHandler) Guess(c *gin.Context) { 205 | items := h.Srv.ListGuess() 206 | c.JSON(http.StatusOK, gin.H{ 207 | "items": items, 208 | }) 209 | } 210 | 211 | func ImageHandler(c *gin.Context) { 212 | imageName := c.Query("imageName") 213 | fmt.Println(imageName) 214 | dir, _ := os.Getwd() 215 | file, ok := ioutil.ReadFile(dir + "/static/images/" + imageName + ".png") 216 | if ok != nil { 217 | fmt.Println(ok.Error()) 218 | } 219 | c.Writer.WriteString(string(file)) 220 | } 221 | -------------------------------------------------------------------------------- /Chapter16/handler/param/OrderSeatParam.go: -------------------------------------------------------------------------------- 1 | package param 2 | 3 | type OrderSeat struct { 4 | HotelID string `json:"hotelId"` 5 | Persons int `json:"persons"` 6 | DateTime int64 `json:"datetime"` 7 | RoomType int `json:"room_Type"` 8 | Mobile int `json:"mobile"` 9 | Name string `json:"name"` 10 | Sex int `json:"sex"` 11 | Message string `json:"message"` 12 | } 13 | -------------------------------------------------------------------------------- /Chapter16/handler/param/TeamPostOrderParam.go: -------------------------------------------------------------------------------- 1 | package param 2 | 3 | type TeamPostOrder struct { 4 | TeamDetailId string `json:"teamDetailId"` 5 | RealPrice int `json:"realPrice"` 6 | Quantity int `json:"quantity"` 7 | Mobile string `json:"mobile"` 8 | Name string `json:"name"` 9 | Sex int `json:"sex"` 10 | Message string `json:"message"` 11 | } 12 | -------------------------------------------------------------------------------- /Chapter16/health/health.go: -------------------------------------------------------------------------------- 1 | package health 2 | 3 | import ( 4 | "github.com/gin-gonic/gin" 5 | "net/http" 6 | ) 7 | 8 | // Health 输出 `OK` 作为可以访问的结果. 9 | func Health(c *gin.Context) { 10 | message := "OK" 11 | c.String(http.StatusOK, "\n"+message) 12 | } 13 | -------------------------------------------------------------------------------- /Chapter16/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "flag" 5 | "github.com/gin-gonic/gin" 6 | "github.com/i-coder-robot/book_final_code/Chapter16/MyLog" 7 | "github.com/i-coder-robot/book_final_code/Chapter16/config" 8 | "github.com/i-coder-robot/book_final_code/Chapter16/handler" 9 | "github.com/i-coder-robot/book_final_code/Chapter16/middleware" 10 | "github.com/i-coder-robot/book_final_code/Chapter16/model" 11 | "github.com/spf13/viper" 12 | "log" 13 | "net/http" 14 | ) 15 | 16 | var ( 17 | cfg = flag.String("config", "", "") 18 | DiscountHandler handler.DiscountHandler 19 | RestaurantNavHandler handler.RestaurantNavHandler 20 | HotelDetailHandler handler.HotelDetailHandler 21 | TeamDetailHandler handler.TeamDetailHandler 22 | OrderSeatHandler handler.OrderSeatHandler 23 | TakeOutHandler handler.TakeOutHandler 24 | MeHandler handler.MeHandler 25 | SuggestFoodHandler handler.SuggestFoodHandler 26 | SuggestHandler handler.SuggestHandler 27 | GuessHandler handler.GuessHandler 28 | NavHandler handler.NavHandler 29 | PostTeamOrderHandler handler.PostTeamOrderHandler 30 | ) 31 | 32 | func init() { 33 | initViper() 34 | initDB() 35 | initHandler() 36 | } 37 | 38 | func main() { 39 | flag.Parse() 40 | 41 | if err := config.Init(*cfg); err != nil { 42 | panic(err) 43 | } 44 | model.DB.Init() 45 | defer model.DB.Close() 46 | r := gin.New() 47 | Load( 48 | r, 49 | middleware.ProcessTraceID(), 50 | middleware.Logging(), 51 | ) 52 | port := viper.GetString("addr") 53 | MyLog.Log.Info("开始监听http地址", port) 54 | log.Printf(http.ListenAndServe(port, r).Error()) 55 | } 56 | -------------------------------------------------------------------------------- /Chapter16/middleware/logging.go: -------------------------------------------------------------------------------- 1 | package middleware 2 | 3 | import ( 4 | "bytes" 5 | "encoding/json" 6 | "github.com/gin-gonic/gin" 7 | "github.com/i-coder-robot/book_final_code/Chapter16/MyLog" 8 | "github.com/i-coder-robot/book_final_code/Chapter16/model/log" 9 | "github.com/i-coder-robot/book_final_code/Chapter16/myerr" 10 | "github.com/i-coder-robot/book_final_code/Chapter16/res" 11 | "github.com/willf/pad" 12 | "io/ioutil" 13 | "strings" 14 | "time" 15 | ) 16 | 17 | func Logging() gin.HandlerFunc { 18 | return func(context *gin.Context) { 19 | start := time.Now().UTC() 20 | path := context.Request.URL.Path 21 | 22 | reqUrl := context.Request.URL.Path 23 | if strings.Contains(reqUrl, "image") { 24 | //context.Next() 25 | return 26 | } 27 | 28 | var bodies []byte 29 | if context.Request.Body != nil { 30 | bodies, _ = ioutil.ReadAll(context.Request.Body) 31 | } 32 | context.Request.Body = ioutil.NopCloser(bytes.NewBuffer(bodies)) 33 | method := context.Request.Method 34 | ip := context.ClientIP() 35 | 36 | blw := &log.BodyLoggerWriter{ 37 | ResponseWriter: context.Writer, 38 | Body: bytes.NewBufferString(""), 39 | } 40 | context.Writer = blw 41 | 42 | context.Next() 43 | 44 | end := time.Now().UTC() 45 | sub := end.Sub(start) 46 | code := -100 47 | message := "" 48 | var response res.Response 49 | if err := json.Unmarshal(blw.Body.Bytes(), &response); err != nil { 50 | code = myerr.InternalServerError.Code 51 | message = err.Error() 52 | MyLog.Log.Error(err) 53 | } else { 54 | code = response.Code 55 | message = response.Message 56 | } 57 | MyLog.Log.Infof("%-13s | %-12s | %s %s | {code: %d, message: %s}", sub, ip, pad.Right(method, 5, ""), path, code, message) 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /Chapter16/middleware/traceid.go: -------------------------------------------------------------------------------- 1 | package middleware 2 | 3 | import ( 4 | "github.com/gin-gonic/gin" 5 | "github.com/hashicorp/go-uuid" 6 | ) 7 | 8 | func ProcessTraceID() gin.HandlerFunc{ 9 | return func(context *gin.Context) { 10 | traceId:= context.Request.Header.Get("X-Trace-Id") 11 | if traceId == "" { 12 | u4id, _ := uuid.GenerateUUID() 13 | traceId = u4id 14 | } 15 | context.Set("X-Trace-Id",traceId) 16 | context.Writer.Header().Set("X-Trace-Id",traceId) 17 | context.Next() 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /Chapter16/model/OrderSeat.go: -------------------------------------------------------------------------------- 1 | package model 2 | 3 | //订座 4 | type OrderSeat struct { 5 | //OrderSeatId 6 | OrderSeatId string `json:"orderSeatId"` 7 | //餐馆ID 8 | HotelID string `json:"hotelId"` 9 | //订座人数 10 | Persons int `json:"persons"` 11 | //预定时间 12 | DateTime int64 `json:"datetime"` 13 | //联系手机号 14 | Mobile int `json:"mobile"` 15 | //房间类型 16 | RoomType int `json:"room_Type"` 17 | //联系人名称 18 | Name string `json:"name"` 19 | //联系人性别 20 | Sex int `json:"sex"` 21 | //留言 22 | Message string `json:"message"` 23 | } -------------------------------------------------------------------------------- /Chapter16/model/choose_food.go: -------------------------------------------------------------------------------- 1 | package model 2 | 3 | type ChooseFood struct { 4 | ChooseFoodId string `json:"chooseFoodId"` 5 | ChooseName string `json:"chooseName"` 6 | } 7 | -------------------------------------------------------------------------------- /Chapter16/model/comment.go: -------------------------------------------------------------------------------- 1 | package model 2 | 3 | type Comment struct { 4 | //评论ID 5 | CommentId string `json:"commentId"` 6 | //评论 7 | Comment string `json:"comment"` 8 | //评论人 9 | AccountName string `json:"accountName"` 10 | //评论人头像 11 | AccountPic string `json:"accountPic"` 12 | //评分 13 | Star int `json:"star"` 14 | //人均消费 15 | AveragePerson int `json:"averagePerson"` 16 | //是否是优质点评 17 | IsGood int `json:"isGood"` 18 | } -------------------------------------------------------------------------------- /Chapter16/model/comment_tag.go: -------------------------------------------------------------------------------- 1 | package model 2 | 3 | type CommentTag struct { 4 | //TagID 5 | TagId string `json:"tagId"` 6 | //Tag名称 7 | TagName string `json:"tagName"` 8 | //Tag数 9 | TagNum int `json:"tagNum"` 10 | //餐馆ID 11 | HotelId string `json:"hotelId"` 12 | } 13 | 14 | -------------------------------------------------------------------------------- /Chapter16/model/discount.go: -------------------------------------------------------------------------------- 1 | package model 2 | 3 | type Discount struct { 4 | //自增ID 5 | Id string `json:"id"` 6 | //DiscountId 7 | DiscountId string `json:"discountId"` 8 | //优惠icon地址 9 | DiscountItemIcon string `json:"discountItemIcon"` 10 | //优惠项目src 11 | DiscountItemSrc string `json:"discountItemSrc"` 12 | //优惠标题 13 | DiscountItemTitle string `json:"discountItemTitle"` 14 | //优惠餐馆 15 | DiscountItemHotel string `json:"discountItemHotel"` 16 | //优惠价格 17 | DiscountItemGoodPrice int32 `json:"discountItemGoodsPrice"` 18 | //原始价格 19 | DiscountItemPrice int32 `json:"discountItemPrice"` 20 | //折扣 21 | Discount string `json:"discount"` 22 | //TODO 最后做 23 | Pos int `json:"pos"` 24 | } 25 | -------------------------------------------------------------------------------- /Chapter16/model/guess.go: -------------------------------------------------------------------------------- 1 | package model 2 | 3 | // 猜你喜欢 4 | type Guess struct { 5 | //GuessId 6 | GuessId string `json:"guess_id"` 7 | // 图片的地址 8 | Src string `json:"src"` 9 | // 展示标题 10 | Title string `json:"title"` 11 | // 描述 12 | Desc string `json:"desc"` 13 | //优惠价格 14 | GoodPrice string `json:"goodPrice"` 15 | //原始价格 16 | Price string `json:"price"` 17 | //售出分数 18 | SoldNum int32 `json:"soldNum"` 19 | } -------------------------------------------------------------------------------- /Chapter16/model/hotel.go: -------------------------------------------------------------------------------- 1 | package model 2 | 3 | type Hotel struct { 4 | //餐馆ID 5 | HotelID string `json:"hotelId"` 6 | //餐馆名称 7 | HotelName string `json:"hotelName"` 8 | // 餐馆图片地址 9 | Pic string `json:"pic"` 10 | // 餐馆打分 11 | Star string `json:"star"` 12 | //评论数 13 | Num int `json:"num"` 14 | //人均消费 15 | AveragePrice float64 `json:"averagePrice"` 16 | //口味 17 | Taste float64 `json:"taste"` 18 | //环境 19 | Env float64 `json:"env"` 20 | //服务 21 | Service float64 `json:"service"` 22 | //详细地址 (某路某号某广场2层) 23 | MapAddr string `json:"mapAddr"` 24 | //详细地址2 (距地铁几号线某站 A 西北口步行多少米) 25 | MapAddr2 string `json:"mapAddr2"` 26 | //类型(潮汕菜/湘菜) 27 | ShortType string `json:"shortType"` 28 | //营业时间 29 | BusinessTime string `json:"businessTime"` 30 | //榜单排行 31 | Bang string `json:"bang"` 32 | //团购列表 33 | TeamList []Team 34 | //推荐菜列表 35 | FoodList []SuggestFood 36 | //评论tag列表 37 | CommentTagList []CommentTag 38 | //评论列表 39 | CommentList []Comment 40 | //商场 41 | Market Market 42 | } 43 | -------------------------------------------------------------------------------- /Chapter16/model/hotel_food_category.go: -------------------------------------------------------------------------------- 1 | package model 2 | 3 | type HotelFoodCategory struct { 4 | //HotelFoodCategoryId 5 | HotelFoodCategoryId string `json:"hotelFoodCategoryId"` 6 | // 分类名称 7 | HotelFoodCategoryName string `json:"hotelFoodCategoryName"` 8 | // 餐馆ID 9 | HotelId string `json:"hotelId"` 10 | } 11 | 12 | -------------------------------------------------------------------------------- /Chapter16/model/indexNavItem.go: -------------------------------------------------------------------------------- 1 | package model 2 | 3 | //首页导航项 4 | type IndexNavItem struct { 5 | Id string `json:"id"` 6 | Src string `json:"src"` 7 | Title string `json:"title"` 8 | } 9 | -------------------------------------------------------------------------------- /Chapter16/model/log/logger.go: -------------------------------------------------------------------------------- 1 | package log 2 | 3 | import ( 4 | "bytes" 5 | "github.com/gin-gonic/gin" 6 | ) 7 | 8 | type BodyLoggerWriter struct { 9 | gin.ResponseWriter 10 | Body *bytes.Buffer 11 | } 12 | 13 | func (w BodyLoggerWriter) Write(b []byte) (int, error) { 14 | w.Body.Write(b) 15 | return w.ResponseWriter.Write(b) 16 | } 17 | -------------------------------------------------------------------------------- /Chapter16/model/market.go: -------------------------------------------------------------------------------- 1 | package model 2 | 3 | type Market struct { 4 | //MarketId 5 | MarketId string `json:"marketId"` 6 | //商场名称 7 | MarketName string `json:"marketName"` 8 | //商场地址 9 | Addr string `json:"addr"` 10 | //类型 11 | ShortType string `json:"shortType"` 12 | //评价 13 | Star int `json:"star"` 14 | //商场图片地址 15 | Pic string `json:"pic"` 16 | } 17 | -------------------------------------------------------------------------------- /Chapter16/model/meItem.go: -------------------------------------------------------------------------------- 1 | package model 2 | 3 | //我的 页面配置项 4 | type MeItem struct { 5 | //ItemId 6 | ItemId string `json:"itemId"` 7 | //图片地址 8 | Src string `json:"src"` 9 | //标题 10 | Title string `json:"title"` 11 | Type string `json:"type"` 12 | } 13 | -------------------------------------------------------------------------------- /Chapter16/model/my_token/token.go: -------------------------------------------------------------------------------- 1 | package my_token 2 | 3 | type Token struct { 4 | Token string `json:"token"` 5 | } -------------------------------------------------------------------------------- /Chapter16/model/mysql.go: -------------------------------------------------------------------------------- 1 | package model 2 | 3 | import ( 4 | "fmt" 5 | "github.com/i-coder-robot/book_final_code/Chapter16/MyLog" 6 | "github.com/jinzhu/gorm" 7 | // MySQL driver. 8 | _ "github.com/jinzhu/gorm/dialects/mysql" 9 | "github.com/spf13/viper" 10 | ) 11 | 12 | type DataBase struct { 13 | MyDB *gorm.DB 14 | } 15 | 16 | var DB *DataBase 17 | 18 | func (db *DataBase) Init() { 19 | DB = &DataBase{ 20 | MyDB: GetMySqlDB(), 21 | } 22 | } 23 | 24 | func (db *DataBase) Close() { 25 | DB.MyDB.Close() 26 | } 27 | 28 | func InitSelfDB() *gorm.DB { 29 | db := openDB(viper.GetString("database.username"), 30 | viper.GetString("database.password"), 31 | viper.GetString("database.addr"), 32 | viper.GetString("database.name")) 33 | return db 34 | } 35 | 36 | func GetMySqlDB() *gorm.DB { 37 | return InitSelfDB() 38 | } 39 | 40 | func openDB(username, password, addr, name string) *gorm.DB { 41 | config := fmt.Sprintf("%s:%s@tcp(%s)/%s?parseTime=true&charset=utf8&parseTime=%t&loc=%s", 42 | username, 43 | password, 44 | addr, 45 | name, 46 | true, 47 | "Local") 48 | 49 | db, err := gorm.Open("mysql", config) 50 | if err != nil { 51 | MyLog.Log.Errorf("Database connection failed. Database name: %s,Eroor:%s", name, err.Error()) 52 | } 53 | 54 | setupDB(db) 55 | db.SingularTable(true) 56 | return db 57 | } 58 | 59 | func setupDB(db *gorm.DB) { 60 | // 用于设置闲置的连接数. 61 | db.DB().SetMaxIdleConns(5) 62 | } 63 | -------------------------------------------------------------------------------- /Chapter16/model/nav.go: -------------------------------------------------------------------------------- 1 | package model 2 | 3 | 4 | 5 | //首页导航 6 | type Nav struct{ 7 | 8 | NavId string `json:"navId"` 9 | //图片地址 10 | Src string `json:"src"` 11 | //导航标题 12 | Title string `json:"title"` 13 | } 14 | -------------------------------------------------------------------------------- /Chapter16/model/restrant.go: -------------------------------------------------------------------------------- 1 | package model 2 | 3 | //美食热门排行榜 4 | type RestaurantNav struct { 5 | //NavId 6 | NavId string `json:"navId"` 7 | //标题 8 | Title string `json:"title"` 9 | //描述 10 | Desc string `json:"desc"` 11 | //图片地址 12 | Src string `json:"src"` 13 | //等级 14 | Level int `json:"level"` 15 | } 16 | 17 | type RestaurantTabItem struct { 18 | ItemId string `json:"itemId"` 19 | Src string `json:"src"` 20 | Title string `json:"title"` 21 | Star float32 `json:"star"` 22 | Price string `json:"price"` 23 | Area string `json:"area"` 24 | Type string `json:"type"` 25 | Desc string `json:"desc"` 26 | Team string `json:"team"` 27 | Quan string `json:"quan"` 28 | } 29 | 30 | 31 | -------------------------------------------------------------------------------- /Chapter16/model/same_city.go: -------------------------------------------------------------------------------- 1 | package model 2 | 3 | type SameCity struct { 4 | Id string `json:"id"` 5 | Title string `json:"title"` 6 | PhotoAddr string `json:"photoAddr"` 7 | Distance string `json:"distance"` 8 | AvatarUrl string `json:"avatarUrl"` 9 | Location string `json:"location"` 10 | Random int32 `json:"random"` 11 | Desc string `json:"desc"` 12 | } 13 | 14 | type SameCityItems struct { 15 | Items1 []SameCity `json:"items1"` 16 | Items2 []SameCity `json:"items2"` 17 | } 18 | -------------------------------------------------------------------------------- /Chapter16/model/sugguest.go: -------------------------------------------------------------------------------- 1 | package model 2 | 3 | //首页推荐 4 | type Suggest struct { 5 | //SuggestId 6 | 7 | SuggestId string `json:"suggestId"` 8 | //关键字 9 | KeyWord1 string `json:"keyWord1"` 10 | KeyWord2 string `json:"keyWord2"` 11 | KeyWord3 string `json:"keyWord3"` 12 | KeyWord4 string `json:"keyWord4"` 13 | //图片地址 14 | Src string `json:"src"` 15 | //菜品名称 16 | FoodName string `json:"foodName"` 17 | //icon图标 18 | Icon string `json:"icon"` 19 | //餐馆名称 20 | HotelName string `json:"hotelName"` 21 | //参加人数 22 | JoinPersons string `json:"joinPersons"` 23 | //价格 24 | Price string `json:"price"` 25 | //优惠价格 26 | GoodPrice string `json:"goodPrice"` 27 | //距离我多远 28 | Distance string `json:"distance"` 29 | //等级分类 30 | Level int `json:"level"` 31 | } 32 | -------------------------------------------------------------------------------- /Chapter16/model/suguest_food.go: -------------------------------------------------------------------------------- 1 | package model 2 | 3 | type SuggestFood struct { 4 | SuggestFoodId string `json:"suggestFoodId"` 5 | SuggestFoodName string `json:"suggestFoodName"` 6 | SuggestPersons string `json:"suggestPersons"` 7 | } 8 | -------------------------------------------------------------------------------- /Chapter16/model/take_out.go: -------------------------------------------------------------------------------- 1 | package model 2 | 3 | //外卖 4 | type TakeOut struct { 5 | //TakeOutId 6 | TakeOutId string `json:"takeOutId"` 7 | //餐馆分类ID 8 | HotelFoodCategoryId string `json:"hotelFoodCategoryId"` 9 | //菜品名称 10 | FoodName string `json:"foodName"` 11 | //菜品图片 12 | Pic string `json:"pic"` 13 | //月销售数量 14 | MonthSoldNum string `json:"monthSoldNum"` 15 | //好评率 16 | Zan int `json:"zan"` 17 | //价格 18 | Price int `json:"price"` 19 | //是否为推荐 20 | IsSuggest int `json:"isSuggest"` 21 | //折扣价格 22 | DiscountPrice int `json:"discountPrice"` 23 | //优惠 24 | Discount float64 `json:"discount"` 25 | } 26 | 27 | type TakeOutItem struct { 28 | Hotel 29 | HotelFoodCategory 30 | TakeOut 31 | } 32 | 33 | -------------------------------------------------------------------------------- /Chapter16/model/team.go: -------------------------------------------------------------------------------- 1 | package model 2 | 3 | //团购 4 | type Team struct { 5 | //团购Id 6 | TeamId string `json:"teamId"` 7 | //餐馆ID 8 | HotelId string `json:"hotelId"` 9 | //餐馆名称 10 | TeamName string `json:"teamName"` 11 | //原价 12 | Price int `json:"price"` 13 | //团购价格 14 | TeamPrice int `json:"teamPrice"` 15 | //销售数量 16 | SoldNum string `json:"soldNum"` 17 | } 18 | 19 | 20 | -------------------------------------------------------------------------------- /Chapter16/model/team_choose_food.go: -------------------------------------------------------------------------------- 1 | package model 2 | 3 | //团购套餐选取(如烧腊2选1) 4 | type TeamChooseFood struct { 5 | //TeamChooseFoodId 6 | TeamChooseFoodId string `gorm:"column:team_choose_food_id" json:"teamChooseFoodId"` 7 | //名称 8 | TeamChooseFoodName string `gorm:"column:team_choose_food_name" json:"teamChooseName"` 9 | } 10 | -------------------------------------------------------------------------------- /Chapter16/model/team_choose_item.go: -------------------------------------------------------------------------------- 1 | package model 2 | 3 | //团购套餐选取 4 | type TeamChooseItem struct{ 5 | //TeamChoseItemId 6 | TeamChoseItemId string `gorm:"column:team_chose_item_id" json:"choseItemId"` 7 | //套餐名称(如 干贝虾蟹粥) 8 | TeamChooseItemName string `gorm:"column:team_choose_item_name" json:"chooseItemName"` 9 | //提示(如两人份) 10 | TeamChooseItemTip string `gorm:"column:team_choose_item_tip" json:"chooseItemTip"` 11 | //团购价格 12 | TeamPrice int `gorm:"column:team_price" json:"teamPrice"` 13 | } 14 | -------------------------------------------------------------------------------- /Chapter16/model/team_detail.go: -------------------------------------------------------------------------------- 1 | package model 2 | 3 | type TeamDetail struct { 4 | //TeamDetailId 5 | TeamDetailId string `gorm:"column:team_detail_id" json:"teamDetailId"` 6 | //团购详细名称 7 | TeamDetailName string `gorm:"column:team_detail_name" json:"teamDetailName"` 8 | //团购政策 9 | Policy string `gorm:"column:policy" json:"policy"` 10 | //团购提示 11 | Tips string `gorm:"column:tips" json:"tips"` 12 | } 13 | 14 | type TeamAggregation struct { 15 | TeamDetail 16 | TeamChooseFood 17 | TeamChooseItem 18 | } -------------------------------------------------------------------------------- /Chapter16/model/team_post_order.go: -------------------------------------------------------------------------------- 1 | package model 2 | 3 | //团购下单 4 | type TeamPostOrder struct { 5 | TeamPostOrderId string `json:"teamPostOrderId"` 6 | //团购详情ID 7 | TeamDetailId string `json:"teamDetailId"` 8 | //支付价格 9 | RealPrice int `json:"realPrice"` 10 | //数量 11 | Quantity int `json:"quantity"` 12 | //下单人手机号 13 | Mobile string `json:"mobile"` 14 | //下单人名称 15 | Name string `json:"name"` 16 | //下单人性别 17 | Sex int `json:"sex"` 18 | //附加消息 19 | Message string `json:"message"` 20 | } 21 | -------------------------------------------------------------------------------- /Chapter16/myerr/code.go: -------------------------------------------------------------------------------- 1 | package myerr 2 | 3 | var ( 4 | // Common errors 5 | OK = &ErrNum{Code: 0, Message: "OK"} 6 | InternalServerError = &ErrNum{Code: 30001, Message: "内部错误."} 7 | ErrBind = &ErrNum{Code: 30002, Message: "请求信息无法转换成结构体."} 8 | ErrDatabase = &ErrNum{Code: 30002, Message: "Database error."} 9 | ErrValidation = &ErrNum{Code: 30001, Message: "Validation failed."} 10 | ErrEncrypt = &ErrNum{Code: 30101, Message: "Error occurred while encrypting the user password."} 11 | // user errors 12 | ErrAccountNotFound = &ErrNum{Code: 50102, Message: "用户不存在."} 13 | ErrPassword = &ErrNum{Code: 50103, Message: "密码错误."} 14 | ErrAccountEmpty = &ErrNum{Code: 50104, Message: "用户名不能为空."} 15 | ErrPasswordEmpty = &ErrNum{Code: 50103, Message: "密码不能为空."} 16 | ErrMissingHeader = &ErrNum{Code: 50104,Message: "Header 不存在"} 17 | ErrToken = &ErrNum{Code: 50105,Message: "生成 Token 错误"} 18 | PassParamCheck = &ErrNum{Code: 60000, Message: "参数校验通过"} 19 | ) 20 | -------------------------------------------------------------------------------- /Chapter16/myerr/errnum.go: -------------------------------------------------------------------------------- 1 | package myerr 2 | 3 | import "fmt" 4 | 5 | type ErrNum struct { 6 | Code int 7 | Message string 8 | } 9 | 10 | func (e *ErrNum) Error() string{ 11 | return e.Message 12 | } 13 | 14 | type Err struct { 15 | ErrNum ErrNum 16 | Err error 17 | } 18 | 19 | func New(num ErrNum, err error) *Err { 20 | return &Err{ 21 | ErrNum: ErrNum{Code: num.Code, Message: num.Message}, 22 | Err: err, 23 | } 24 | } 25 | 26 | func (e *Err) Add(message string) Err { 27 | e.ErrNum.Message += " " + message 28 | return *e 29 | } 30 | 31 | func (err *Err) AddFormat(format string, args ...interface{}) Err { 32 | err.ErrNum.Message += " " + fmt.Sprintf(format, args...) 33 | return *err 34 | } 35 | 36 | func (err *Err) Error() string { 37 | return fmt.Sprintf("Err - code: %d, message: %s, error: %s", err.ErrNum.Code, err.ErrNum.Message, err.Err) 38 | } 39 | 40 | func IsErrAccountNotFound(err error) bool { 41 | code, _ := DecodeErr(err) 42 | return code == ErrAccountNotFound.Code 43 | } 44 | 45 | 46 | 47 | func DecodeErr(err error) (int, string) { 48 | if err == nil { 49 | return OK.Code, OK.Message 50 | } 51 | 52 | switch typed := err.(type) { 53 | case *Err: 54 | return typed.ErrNum.Code, typed.ErrNum.Message 55 | case *ErrNum: 56 | return typed.Code, typed.Message 57 | default: 58 | } 59 | 60 | return InternalServerError.Code, err.Error() 61 | } 62 | -------------------------------------------------------------------------------- /Chapter16/repository/OrderSeat.go: -------------------------------------------------------------------------------- 1 | package repository 2 | 3 | import ( 4 | "github.com/i-coder-robot/book_final_code/Chapter16/model" 5 | "log" 6 | ) 7 | 8 | type OrderSeatRepo struct { 9 | DB model.DataBase 10 | } 11 | 12 | func (s *OrderSeatRepo) OrderSeatOp(o model.OrderSeat) string { 13 | err := s.DB.MyDB.Save(o).Error 14 | if err != nil { 15 | log.Println(err) 16 | } 17 | return o.OrderSeatId 18 | } 19 | -------------------------------------------------------------------------------- /Chapter16/repository/comment.go: -------------------------------------------------------------------------------- 1 | package repository 2 | 3 | import "github.com/i-coder-robot/book_final_code/Chapter16/model" 4 | 5 | type CommentRepo struct { 6 | DB model.DataBase 7 | } 8 | 9 | func (c *CommentRepo) GetCommentList(hotelId string) []model.Comment { 10 | var commentList []model.Comment 11 | c.DB.MyDB.Where("hotel_id=?", hotelId).Find(&commentList) 12 | return commentList 13 | } 14 | -------------------------------------------------------------------------------- /Chapter16/repository/comment_tag.go: -------------------------------------------------------------------------------- 1 | package repository 2 | 3 | import "github.com/i-coder-robot/book_final_code/Chapter16/model" 4 | 5 | type CommentTagRepo struct { 6 | DB model.DataBase 7 | } 8 | 9 | func (t *CommentTagRepo) GetCommentTagList(hotelId string) []model.CommentTag { 10 | var tagList []model.CommentTag 11 | t.DB.MyDB.Where("hotel_id=?", hotelId).Find(&tagList) 12 | return tagList 13 | } 14 | -------------------------------------------------------------------------------- /Chapter16/repository/discount.go: -------------------------------------------------------------------------------- 1 | package repository 2 | 3 | import ( 4 | "github.com/i-coder-robot/book_final_code/Chapter16/model" 5 | ) 6 | 7 | type Discount struct { 8 | DB model.DataBase 9 | } 10 | 11 | func (d *Discount) ListDiscounts(pos int) []model.Discount { 12 | var discounts []model.Discount 13 | d.DB.MyDB.Where("pos=?", pos).Find(&discounts) 14 | return discounts 15 | } 16 | -------------------------------------------------------------------------------- /Chapter16/repository/guess.go: -------------------------------------------------------------------------------- 1 | package repository 2 | 3 | import "github.com/i-coder-robot/book_final_code/Chapter16/model" 4 | 5 | type GuessRepo struct { 6 | DB model.DataBase 7 | } 8 | 9 | func (g *GuessRepo) ListGuesses() []model.Guess { 10 | var guessList []model.Guess 11 | g.DB.MyDB.Find(&guessList) 12 | return guessList 13 | } 14 | -------------------------------------------------------------------------------- /Chapter16/repository/hotel.go: -------------------------------------------------------------------------------- 1 | package repository 2 | 3 | import "github.com/i-coder-robot/book_final_code/Chapter16/model" 4 | 5 | type HotelRepo struct { 6 | DB model.DataBase 7 | } 8 | 9 | func (h *HotelRepo) GetHotelById(hotelId string) model.Hotel { 10 | var hotel model.Hotel 11 | //select * from hotel where hotel_id = hotelId 12 | h.DB.MyDB.Where("hotel_id = ?", hotelId).First(&hotel) 13 | return hotel 14 | } 15 | -------------------------------------------------------------------------------- /Chapter16/repository/indexNavItem.go: -------------------------------------------------------------------------------- 1 | package repository 2 | 3 | import "github.com/i-coder-robot/book_final_code/Chapter16/model" 4 | 5 | type IndexNavItemRepo struct { 6 | DB model.DataBase 7 | } 8 | 9 | func (item *IndexNavItemRepo) ListIndexNavItem() ([]*model.IndexNavItem, uint64, error) { 10 | NavItems := make([]*model.IndexNavItem, 0) 11 | var count uint64 12 | 13 | if err := model.DB.MyDB.Model(NavItems).Count(count).Error; err != nil { 14 | return nil, 0, err 15 | } 16 | return NavItems, count, nil 17 | } 18 | -------------------------------------------------------------------------------- /Chapter16/repository/log/logger.go: -------------------------------------------------------------------------------- 1 | package log 2 | 3 | import ( 4 | "bytes" 5 | "github.com/gin-gonic/gin" 6 | ) 7 | 8 | type BodyLoggerWriter struct { 9 | gin.ResponseWriter 10 | Body *bytes.Buffer 11 | } 12 | 13 | func (w BodyLoggerWriter) Write(b []byte) (int, error) { 14 | w.Body.Write(b) 15 | return w.ResponseWriter.Write(b) 16 | } 17 | -------------------------------------------------------------------------------- /Chapter16/repository/market.go: -------------------------------------------------------------------------------- 1 | package repository 2 | 3 | import ( 4 | "github.com/i-coder-robot/book_final_code/Chapter16/model" 5 | ) 6 | 7 | type MarketRepo struct { 8 | DB model.DataBase 9 | } 10 | 11 | func (m *MarketRepo) GetMarketInfo(hotelId string) model.Market { 12 | var market model.Market 13 | m.DB.MyDB.Where("hotel_id=?", hotelId).Find(&market) 14 | return market 15 | } 16 | -------------------------------------------------------------------------------- /Chapter16/repository/meItem.go: -------------------------------------------------------------------------------- 1 | package repository 2 | 3 | import "github.com/i-coder-robot/book_final_code/Chapter16/model" 4 | 5 | type MeItemRepo struct { 6 | DB model.DataBase 7 | } 8 | 9 | func (item *MeItemRepo) ListMe() []model.MeItem { 10 | var items []model.MeItem 11 | item.DB.MyDB.Find(&items) 12 | return items 13 | } 14 | -------------------------------------------------------------------------------- /Chapter16/repository/my_token/token.go: -------------------------------------------------------------------------------- 1 | package my_token 2 | 3 | type Token struct { 4 | Token string `json:"token"` 5 | } -------------------------------------------------------------------------------- /Chapter16/repository/nav.go: -------------------------------------------------------------------------------- 1 | package repository 2 | 3 | import ( 4 | "github.com/i-coder-robot/book_final_code/Chapter16/model" 5 | ) 6 | 7 | type ListNavItemRepo struct { 8 | DB model.DataBase 9 | } 10 | 11 | func (i *ListNavItemRepo) ListNavItems(level int) []model.Nav { 12 | var items []model.Nav 13 | i.DB.MyDB.Where("level=?", level).Find(&items) 14 | return items 15 | } 16 | -------------------------------------------------------------------------------- /Chapter16/repository/restrant.go: -------------------------------------------------------------------------------- 1 | package repository 2 | 3 | import "github.com/i-coder-robot/book_final_code/Chapter16/model" 4 | 5 | type RestaurantNavRepo struct { 6 | DB model.DataBase 7 | } 8 | 9 | func (r *RestaurantNavRepo) ListRestaurantNav(level int) []model.RestaurantNav { 10 | var items []model.RestaurantNav 11 | model.DB.MyDB.Where("level=?", level).Find(&items) 12 | return items 13 | } 14 | 15 | type RestaurantTabItemRepo struct { 16 | DB model.DataBase 17 | } 18 | 19 | func (r *RestaurantTabItemRepo) ListGoodRestaurantTabItem() []model.RestaurantTabItem { 20 | var items []model.RestaurantTabItem 21 | r.DB.MyDB.Find(&items) 22 | return items 23 | } 24 | 25 | func (r *RestaurantTabItemRepo) ListRestaurantNav(level int) []model.RestaurantNav { 26 | var items []model.RestaurantNav 27 | r.DB.MyDB.Where("level=?", level).Find(&items) 28 | return items 29 | } 30 | -------------------------------------------------------------------------------- /Chapter16/repository/same_city.go: -------------------------------------------------------------------------------- 1 | package repository 2 | 3 | import "github.com/i-coder-robot/book_final_code/Chapter16/model" 4 | 5 | type SameCityRepo struct { 6 | DB model.DataBase 7 | } 8 | 9 | func (s *SameCityRepo) ListSameCity() []model.SameCity { 10 | var sameCities []model.SameCity 11 | 12 | model.DB.MyDB.Find(sameCities) 13 | return sameCities 14 | } 15 | -------------------------------------------------------------------------------- /Chapter16/repository/sugguest.go: -------------------------------------------------------------------------------- 1 | package repository 2 | 3 | import "github.com/i-coder-robot/book_final_code/Chapter16/model" 4 | 5 | type SuggestRepo struct { 6 | DB model.DataBase 7 | } 8 | 9 | func (s *SuggestRepo) ListSuggest(level int) model.Suggest { 10 | var item model.Suggest 11 | model.DB.MyDB.Where("level=?", level).Find(&item) 12 | return item 13 | } 14 | -------------------------------------------------------------------------------- /Chapter16/repository/suguest_food.go: -------------------------------------------------------------------------------- 1 | package repository 2 | 3 | import "github.com/i-coder-robot/book_final_code/Chapter16/model" 4 | 5 | type SuggestFoodRepo struct { 6 | DB model.DataBase 7 | } 8 | 9 | func (s *SuggestFoodRepo) GetFoodByHotelId(hotelId string) []model.SuggestFood { 10 | var foods []model.SuggestFood 11 | s.DB.MyDB.Where("hotel_id=?", hotelId).Find(&foods) 12 | return foods 13 | } 14 | 15 | func (s *SuggestFoodRepo) ListSuggest(level int) []model.Suggest { 16 | var items []model.Suggest 17 | model.DB.MyDB.Where("level=?", level).Find(&items) 18 | return items 19 | } 20 | -------------------------------------------------------------------------------- /Chapter16/repository/take_out.go: -------------------------------------------------------------------------------- 1 | package repository 2 | 3 | import "github.com/i-coder-robot/book_final_code/Chapter16/model" 4 | 5 | type TakeOutItemRepo struct { 6 | DB model.DataBase 7 | } 8 | 9 | func (t *TakeOutItemRepo) GetTakeOutListByHotelId(hotelId string) []model.TakeOutItem { 10 | var takeOutItemList []model.TakeOutItem 11 | t.DB.MyDB.Table("hotel").Joins("JOIN hotel_food_category on hotel.hotel_id=hotel_food_category.hotel_id").Joins("JOIN take_out on hotel_food_category.hotel_food_category_id=take_out.hotel_food_category_id").Where("hotel.hotel_id=?", hotelId).Select("hotel.hotel_name,hotel_food_category.*,take_out.*").Find(&takeOutItemList) 12 | return takeOutItemList 13 | } 14 | -------------------------------------------------------------------------------- /Chapter16/repository/team.go: -------------------------------------------------------------------------------- 1 | package repository 2 | 3 | import ( 4 | "github.com/i-coder-robot/book_final_code/Chapter16/model" 5 | ) 6 | 7 | type TeamRepo struct { 8 | DB model.DataBase 9 | } 10 | 11 | func (t *TeamRepo) GetTeamListByHotelId(hotelId string) []model.Team { 12 | var teamList []model.Team 13 | t.DB.MyDB.Where("hotel_id=?", hotelId).Find(&teamList) 14 | return teamList 15 | } 16 | 17 | func (t *TeamRepo) GetTeamDetail(teamDetailId string) []model.TeamAggregation { 18 | var teamAggregations []model.TeamAggregation 19 | t.DB.MyDB.Table("team_detail").Where("team_detail.team_detail_id = ?", teamDetailId).Joins("JOIN team_choose_food on team_detail.team_detail_id=team_choose_food.team_detail_id").Joins("JOIN team_choose_item on team_choose_food.team_choose_food_id=team_choose_item.team_choose_food_id").Select("team_detail.*,team_choose_food.*,team_choose_item.*").Scan(&teamAggregations) 20 | return teamAggregations 21 | } 22 | -------------------------------------------------------------------------------- /Chapter16/repository/team_post_order.go: -------------------------------------------------------------------------------- 1 | package repository 2 | 3 | import ( 4 | "github.com/i-coder-robot/book_final_code/Chapter16/model" 5 | ) 6 | 7 | type TeamPostOrderRepo struct { 8 | DB model.DataBase 9 | } 10 | 11 | func (t *TeamPostOrderRepo) Save(order model.TeamPostOrder) string { 12 | tx := t.DB.MyDB.Begin() 13 | defer func() { 14 | if r := recover(); r != nil { 15 | tx.Rollback() 16 | } 17 | }() 18 | err := tx.Create(order).Error 19 | if err != nil { 20 | tx.Rollback() 21 | return "" 22 | } 23 | err = tx.Commit().Error 24 | if err != nil { 25 | tx.Rollback() 26 | return "" 27 | } 28 | return order.TeamPostOrderId 29 | } 30 | -------------------------------------------------------------------------------- /Chapter16/res/RespEntity.go: -------------------------------------------------------------------------------- 1 | package res 2 | 3 | import ( 4 | "github.com/gin-gonic/gin" 5 | "github.com/i-coder-robot/book_final_code/Chapter16/myerr" 6 | "net/http" 7 | ) 8 | 9 | type Response struct { 10 | Code int `json:"code"` 11 | Message string `json:"message"` 12 | Data interface{} `json:"data"` 13 | } 14 | 15 | func SendResponse(c *gin.Context, err error, data interface{}) { 16 | code, message := myerr.DecodeErr(err) 17 | 18 | //http.StatusOK这个值是200 19 | c.JSON(http.StatusOK, Response{ 20 | Code: code, 21 | Message: message, 22 | Data: data, 23 | }) 24 | } 25 | -------------------------------------------------------------------------------- /Chapter16/res/TeamChooseItemResp.go: -------------------------------------------------------------------------------- 1 | package res 2 | 3 | //团购套餐选取 4 | type TeamChooseItemResp struct{ 5 | //TeamChoseItemId 6 | TeamChoseItemId string `gorm:"column:team_chose_item_id" json:"choseItemId"` 7 | //套餐名称(如 干贝虾蟹粥) 8 | TeamChooseItemName string `gorm:"column:team_choose_item_name" json:"chooseItemName"` 9 | //提示(如两人份) 10 | TeamChooseItemTip string `gorm:"column:team_choose_item_tip" json:"chooseItemTip"` 11 | //团购价格 12 | TeamPrice int `gorm:"column:team_price" json:"teamPrice"` 13 | } 14 | -------------------------------------------------------------------------------- /Chapter16/res/WXLoginResponse.go: -------------------------------------------------------------------------------- 1 | package res 2 | 3 | type WXLoginResponse struct { 4 | OpenId string `json:"openid"` 5 | SessionKey string `json:"session_key"` 6 | UnionId string `json:"unionid"` 7 | ErrCode int `json:"errcode"` 8 | ErrMsg string `json:"errmsg"` 9 | } 10 | 11 | -------------------------------------------------------------------------------- /Chapter16/res/accountResp.go: -------------------------------------------------------------------------------- 1 | package res 2 | 3 | type AccountResp struct { 4 | AccountName string `json:"accountName"` 5 | } 6 | 7 | type ListResponse struct { 8 | TotalCount uint64 `json:"totalCount"` 9 | AccountList []*AccountResp `json:"accountList"` 10 | } 11 | -------------------------------------------------------------------------------- /Chapter16/res/hotelFoodCategoryResp.go: -------------------------------------------------------------------------------- 1 | package res 2 | 3 | type HotelFoodCategoryResp struct { 4 | //HotelFoodCategoryId 5 | HotelFoodCategoryId string `json:"hotelFoodCategoryId"` 6 | // 分类名称 7 | HotelFoodCategoryName string `json:"hotelFoodCategoryName"` 8 | // 餐馆ID 9 | HotelId string `json:"hotelId"` 10 | } 11 | 12 | 13 | -------------------------------------------------------------------------------- /Chapter16/res/navResp.go: -------------------------------------------------------------------------------- 1 | package res 2 | //首页导航 3 | type Nav struct{ 4 | 5 | NavId string `json:"navId"` 6 | //图片地址 7 | Src string `json:"src"` 8 | //导航标题 9 | Title string `json:"title"` 10 | } 11 | -------------------------------------------------------------------------------- /Chapter16/res/takeOutItemResp.go: -------------------------------------------------------------------------------- 1 | package res 2 | 3 | type TakeOutItemResp struct { 4 | //TakeOutId 5 | TakeOutId string `json:"takeOutId"` 6 | //餐馆分类ID 7 | HotelFoodCategoryId string `json:"hotelFoodCategoryId"` 8 | //菜品名称 9 | FoodName string `json:"foodName"` 10 | //菜品图片 11 | Pic string `json:"pic"` 12 | //月销售数量 13 | MonthSoldNum string `json:"monthSoldNum"` 14 | //好评率 15 | Zan int `json:"zan"` 16 | //价格 17 | Price int `json:"price"` 18 | //是否为推荐 19 | IsSuggest int `json:"isSuggest"` 20 | //折扣价格 21 | DiscountPrice int `json:"discountPrice"` 22 | //优惠 23 | Discount float64 `json:"discount"` 24 | } 25 | -------------------------------------------------------------------------------- /Chapter16/res/takeoutResp.go: -------------------------------------------------------------------------------- 1 | package res 2 | 3 | type TakeOutRsp struct { 4 | HotelName string `json:"hotelName"` 5 | CategoryList []HotelFoodCategoryResp 6 | ItemList []TakeOutItemResp 7 | } -------------------------------------------------------------------------------- /Chapter16/res/teamChooseFoodResp.go: -------------------------------------------------------------------------------- 1 | package res 2 | 3 | //团购套餐选取(如烧腊2选1) 4 | type TeamChooseFoodResp struct { 5 | //TeamChooseFoodId 6 | TeamChooseFoodId string `gorm:"column:team_choose_food_id" json:"teamChooseFoodId"` 7 | //名称 8 | TeamChooseFoodName string `gorm:"column:team_choose_food_name" json:"teamChooseName"` 9 | } 10 | -------------------------------------------------------------------------------- /Chapter16/res/teamResp.go: -------------------------------------------------------------------------------- 1 | package res 2 | 3 | import "github.com/i-coder-robot/book_final_code/Chapter16/model" 4 | 5 | type TeamResp struct { 6 | model.TeamDetail 7 | FoodList []TeamChooseFoodResp 8 | ChooseItems []TeamChooseItemResp 9 | } 10 | -------------------------------------------------------------------------------- /Chapter16/router.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "github.com/gin-gonic/gin" 5 | "github.com/i-coder-robot/book_final_code/Chapter16/handler" 6 | "github.com/i-coder-robot/book_final_code/Chapter16/health" 7 | "net/http" 8 | ) 9 | 10 | func Load(engine *gin.Engine, middlewares ...gin.HandlerFunc) *gin.Engine { 11 | engine.Use(gin.Recovery()) 12 | engine.Use(middlewares...) 13 | engine.NoRoute(func(context *gin.Context) { 14 | context.String(http.StatusNotFound, "API路由不正确.") 15 | }) 16 | check := engine.Group("/check") 17 | { 18 | check.GET("/health", health.Health) 19 | } 20 | 21 | dp := engine.Group("/v1/dp") 22 | { 23 | 24 | //dp.GET("/index",handler.IndexHandler) 25 | 26 | //首页相关 27 | //首页导航 28 | dp.GET("/nav", NavHandler.NavHandler) 29 | dp.GET("/subnav", NavHandler.SubNavHandler) 30 | //首页拼团 31 | dp.GET("/team", SuggestHandler.TeamHandler) 32 | //首页秒杀 33 | dp.GET("/rush", SuggestHandler.RushHandler) 34 | //首页猜你喜欢 35 | dp.GET("/guess", GuessHandler.Guess) 36 | 37 | //找优惠页面相关 38 | dp.GET("/discount", DiscountHandler.DiscountList) 39 | //获取图片 40 | dp.GET("/image", handler.ImageHandler) 41 | 42 | //找好店相关 43 | //美食排行榜 44 | dp.GET("/restaurantNav", RestaurantNavHandler.RestaurantNav) 45 | //精品榜单 46 | dp.GET("/restaurantBillBoard", RestaurantNavHandler.GoodRestaurantBillBoardHandler) 47 | //附近上榜和全域上榜 48 | dp.GET("/restaurantTabItem", RestaurantNavHandler.GoodRestaurantTabItemHandler) 49 | 50 | //获取餐馆详细信息 51 | dp.GET("/hotel/detail/:id", HotelDetailHandler.HotelDetailHandler) 52 | //获取团购详细信息 53 | dp.GET("/team/detail/:id", TeamDetailHandler.TeamDetailHandler) 54 | //团购下单 55 | dp.POST("/team/order", PostTeamOrderHandler.TeamOrderHandler) 56 | //订座下单 57 | dp.POST("/seat/order/:hotelId", OrderSeatHandler.OrderSeat) 58 | //外卖 59 | dp.GET("/takeout/:hotelId", TakeOutHandler.GetTakeOutByHotelId) 60 | //我的 61 | dp.GET("/me", MeHandler.MeHandler) 62 | 63 | } 64 | 65 | return engine 66 | } 67 | -------------------------------------------------------------------------------- /Chapter16/service/dp_service/OrderSeat.go: -------------------------------------------------------------------------------- 1 | package dp_service 2 | 3 | import ( 4 | "github.com/hashicorp/go-uuid" 5 | "github.com/i-coder-robot/book_final_code/Chapter16/handler/param" 6 | "github.com/i-coder-robot/book_final_code/Chapter16/model" 7 | "github.com/i-coder-robot/book_final_code/Chapter16/repository" 8 | ) 9 | 10 | type OrderSeatService struct { 11 | Repo *repository.OrderSeatRepo 12 | } 13 | 14 | func (os *OrderSeatService) OrderSeatOp(p param.OrderSeat) string { 15 | //order.HotelId-- 到数据库 查看是否有这个团购优惠 16 | //防止黑客捏造优惠 17 | //order.time 是否超选择的范围 18 | //order.Mobile 格式是否正确 19 | //数据格式要求 20 | //order.roomtype 检查预订类型是否合法 21 | //成功预订以后,要发送短信 22 | id, _ := uuid.GenerateUUID() 23 | o := model.OrderSeat{ 24 | OrderSeatId: id, 25 | HotelID: p.HotelID, 26 | Mobile: p.Mobile, 27 | Name: p.Name, 28 | Sex: p.Sex, 29 | Message: p.Message, 30 | } 31 | 32 | return os.Repo.OrderSeatOp(o) 33 | } 34 | -------------------------------------------------------------------------------- /Chapter16/service/dp_service/comment.go: -------------------------------------------------------------------------------- 1 | package dp_service 2 | 3 | import ( 4 | "github.com/i-coder-robot/book_final_code/Chapter16/model" 5 | "github.com/i-coder-robot/book_final_code/Chapter16/repository" 6 | ) 7 | 8 | type CommentService struct { 9 | Repo repository.CommentRepo 10 | } 11 | 12 | func (c *CommentService) GetCommentList(hotelId string) []model.Comment { 13 | return c.Repo.GetCommentList(hotelId) 14 | } 15 | -------------------------------------------------------------------------------- /Chapter16/service/dp_service/comment_tag.go: -------------------------------------------------------------------------------- 1 | package dp_service 2 | 3 | import ( 4 | "github.com/i-coder-robot/book_final_code/Chapter16/model" 5 | "github.com/i-coder-robot/book_final_code/Chapter16/repository" 6 | ) 7 | 8 | type CommentTagService struct { 9 | Repo repository.CommentTagRepo 10 | } 11 | 12 | func (c *CommentTagService) GetCommentTagList(hotelId string) []model.CommentTag { 13 | return c.Repo.GetCommentTagList(hotelId) 14 | } 15 | -------------------------------------------------------------------------------- /Chapter16/service/dp_service/discount.go: -------------------------------------------------------------------------------- 1 | package dp_service 2 | 3 | import ( 4 | "github.com/i-coder-robot/book_final_code/Chapter16/model" 5 | "github.com/i-coder-robot/book_final_code/Chapter16/repository" 6 | ) 7 | 8 | type DiscountService struct { 9 | Repo *repository.Discount 10 | } 11 | 12 | func (d *DiscountService) ListDiscounts() []model.Discount { 13 | itemsLeft := d.Repo.ListDiscounts(1) 14 | itemsRight := d.Repo.ListDiscounts(2) 15 | itemsLeft = append(itemsLeft, itemsRight...) 16 | return itemsLeft 17 | } 18 | -------------------------------------------------------------------------------- /Chapter16/service/dp_service/guess.go: -------------------------------------------------------------------------------- 1 | package dp_service 2 | 3 | import ( 4 | "github.com/i-coder-robot/book_final_code/Chapter16/model" 5 | "github.com/i-coder-robot/book_final_code/Chapter16/repository" 6 | ) 7 | 8 | type GuessService struct { 9 | Repo *repository.GuessRepo 10 | } 11 | 12 | func (g *GuessService) ListGuess() []model.Guess { 13 | return g.Repo.ListGuesses() 14 | } 15 | -------------------------------------------------------------------------------- /Chapter16/service/dp_service/hotel.go: -------------------------------------------------------------------------------- 1 | package dp_service 2 | 3 | import ( 4 | "errors" 5 | "github.com/i-coder-robot/book_final_code/Chapter16/model" 6 | "github.com/i-coder-robot/book_final_code/Chapter16/repository" 7 | ) 8 | 9 | type HotelService struct { 10 | Repo *repository.HotelRepo 11 | TeamRepo *repository.TeamRepo 12 | SuggestFoodRepo *repository.SuggestFoodRepo 13 | CommentTagRepo *repository.CommentTagRepo 14 | CommentRepo *repository.CommentRepo 15 | MarketRepo *repository.MarketRepo 16 | } 17 | 18 | func (h *HotelService) GetHotelDetailByID(id string) (*model.Hotel, error) { 19 | if id == "" { 20 | return nil, errors.New("参数错误!") 21 | } 22 | hotel := h.Repo.GetHotelById(id) 23 | if &hotel == nil { 24 | return nil, errors.New("餐馆查询错误!") 25 | } 26 | teamList := h.TeamRepo.GetTeamListByHotelId(id) 27 | hotel.TeamList = teamList 28 | foodList := h.SuggestFoodRepo.GetFoodByHotelId(id) 29 | hotel.FoodList = foodList 30 | tagList := h.CommentTagRepo.GetCommentTagList(id) 31 | hotel.CommentTagList = tagList 32 | commentList := h.CommentRepo.GetCommentList(id) 33 | hotel.CommentList = commentList 34 | market := h.MarketRepo.GetMarketInfo(id) 35 | hotel.Market = market 36 | return &hotel, nil 37 | } 38 | -------------------------------------------------------------------------------- /Chapter16/service/dp_service/market.go: -------------------------------------------------------------------------------- 1 | package dp_service 2 | 3 | import ( 4 | "github.com/i-coder-robot/book_final_code/Chapter16/model" 5 | "github.com/i-coder-robot/book_final_code/Chapter16/repository" 6 | ) 7 | 8 | type MarketService struct { 9 | Repo repository.MarketRepo 10 | } 11 | 12 | func (m *MarketService) GetMarketInfo(hotelId string) model.Market { 13 | var market model.Market 14 | m.Repo.DB.MyDB.Where("hotel_id=?", hotelId).Find(&market) 15 | return market 16 | } 17 | -------------------------------------------------------------------------------- /Chapter16/service/dp_service/me.go: -------------------------------------------------------------------------------- 1 | package dp_service 2 | 3 | import ( 4 | "github.com/i-coder-robot/book_final_code/Chapter16/model" 5 | "github.com/i-coder-robot/book_final_code/Chapter16/repository" 6 | ) 7 | 8 | type MeService struct { 9 | Repo *repository.MeItemRepo 10 | } 11 | 12 | func (m *MeService) ListMe() []model.MeItem { 13 | return m.Repo.ListMe() 14 | } 15 | -------------------------------------------------------------------------------- /Chapter16/service/dp_service/nav_item.go: -------------------------------------------------------------------------------- 1 | package dp_service 2 | 3 | import ( 4 | "github.com/i-coder-robot/book_final_code/Chapter16/model" 5 | "github.com/i-coder-robot/book_final_code/Chapter16/repository" 6 | "github.com/i-coder-robot/book_final_code/Chapter16/res" 7 | ) 8 | 9 | type ListNavItemService struct { 10 | Repo *repository.ListNavItemRepo 11 | } 12 | 13 | func model2res(nav model.Nav) res.Nav { 14 | navRes := res.Nav{ 15 | NavId: nav.NavId, 16 | Src: nav.Src, 17 | Title: nav.Title, 18 | } 19 | return navRes 20 | } 21 | 22 | func (i *ListNavItemService) ListNavItems(level int) []res.Nav { 23 | result := i.Repo.ListNavItems(level) 24 | var newList []res.Nav 25 | for _, item := range result { 26 | r := model2res(item) 27 | newList = append(newList, r) 28 | } 29 | 30 | return newList 31 | } 32 | -------------------------------------------------------------------------------- /Chapter16/service/dp_service/restrant.go: -------------------------------------------------------------------------------- 1 | package dp_service 2 | 3 | import ( 4 | "github.com/i-coder-robot/book_final_code/Chapter16/model" 5 | "github.com/i-coder-robot/book_final_code/Chapter16/repository" 6 | ) 7 | 8 | type RestaurantService struct { 9 | Repo *repository.RestaurantNavRepo 10 | ItemRepo *repository.RestaurantTabItemRepo 11 | } 12 | 13 | func (r *RestaurantService) ListRestaurantNav(level int) []model.RestaurantNav { 14 | items := r.Repo.ListRestaurantNav(level) 15 | return items 16 | } 17 | 18 | func (r *RestaurantService) ListGoodRestaurantTabItem() []model.RestaurantTabItem { 19 | items := r.ItemRepo.ListGoodRestaurantTabItem() 20 | return items 21 | } 22 | -------------------------------------------------------------------------------- /Chapter16/service/dp_service/sugguest_food.go: -------------------------------------------------------------------------------- 1 | package dp_service 2 | 3 | import ( 4 | "github.com/i-coder-robot/book_final_code/Chapter16/model" 5 | "github.com/i-coder-robot/book_final_code/Chapter16/repository" 6 | ) 7 | 8 | type SuggestFoodService struct { 9 | Repo *repository.SuggestFoodRepo 10 | } 11 | 12 | func (sf *SuggestFoodService) ListSuggestList(level int) []model.Suggest { 13 | return sf.Repo.ListSuggest(level) 14 | } 15 | 16 | func (sf *SuggestFoodService) GetFoodByHotelId(hotelId string) []model.SuggestFood { 17 | return sf.Repo.GetFoodByHotelId(hotelId) 18 | } 19 | 20 | type SuggestService struct { 21 | Repo *repository.SuggestRepo 22 | } 23 | 24 | func (sf *SuggestService) GetSuggestByLevel(level int) model.Suggest { 25 | return sf.Repo.ListSuggest(level) 26 | } 27 | -------------------------------------------------------------------------------- /Chapter16/service/dp_service/take_out.go: -------------------------------------------------------------------------------- 1 | package dp_service 2 | 3 | import ( 4 | "github.com/i-coder-robot/book_final_code/Chapter16/model" 5 | "github.com/i-coder-robot/book_final_code/Chapter16/repository" 6 | "github.com/i-coder-robot/book_final_code/Chapter16/res" 7 | ) 8 | 9 | type TakeOutService struct { 10 | Repo *repository.TakeOutItemRepo 11 | } 12 | 13 | func Convert2HotelFoodCategoryResp(c model.HotelFoodCategory) res.HotelFoodCategoryResp { 14 | 15 | r := res.HotelFoodCategoryResp{ 16 | HotelFoodCategoryId: c.HotelFoodCategoryId, 17 | HotelFoodCategoryName: c.HotelFoodCategoryName, 18 | HotelId: c.HotelId, 19 | } 20 | return r 21 | } 22 | 23 | func convert2TakeOutItemResp(t *model.TakeOut) res.TakeOutItemResp { 24 | r := res.TakeOutItemResp{ 25 | TakeOutId: t.TakeOutId, 26 | HotelFoodCategoryId: t.HotelFoodCategoryId, 27 | FoodName: t.FoodName, 28 | Pic: t.Pic, 29 | MonthSoldNum: t.MonthSoldNum, 30 | Zan: t.Zan, 31 | Price: t.Price, 32 | IsSuggest: t.IsSuggest, 33 | DiscountPrice: t.DiscountPrice, 34 | Discount: t.Discount, 35 | } 36 | return r 37 | } 38 | 39 | func (to *TakeOutService) GetTakeOutListByHotelId(hotelId string) res.TakeOutRsp { 40 | items := to.Repo.GetTakeOutListByHotelId(hotelId) 41 | var takeoutRsp res.TakeOutRsp 42 | if len(items) > 0 { 43 | takeoutRsp.HotelName = items[0].HotelName 44 | for _, item := range items { 45 | c := model.HotelFoodCategory{ 46 | HotelFoodCategoryId: item.HotelFoodCategory.HotelFoodCategoryId, 47 | HotelFoodCategoryName: item.HotelFoodCategoryName, 48 | HotelId: item.HotelID, 49 | } 50 | takeoutRsp.CategoryList = append(takeoutRsp.CategoryList, Convert2HotelFoodCategoryResp(c)) 51 | t := model.TakeOut{ 52 | TakeOutId: item.TakeOutId, 53 | HotelFoodCategoryId: item.HotelFoodCategory.HotelFoodCategoryId, 54 | FoodName: item.FoodName, 55 | Pic: item.TakeOut.Pic, 56 | MonthSoldNum: item.MonthSoldNum, 57 | Zan: item.Zan, 58 | Price: item.Price, 59 | IsSuggest: item.IsSuggest, 60 | DiscountPrice: item.DiscountPrice, 61 | Discount: item.Discount, 62 | } 63 | takeoutRsp.ItemList = append(takeoutRsp.ItemList, convert2TakeOutItemResp(&t)) 64 | } 65 | } 66 | return takeoutRsp 67 | } 68 | -------------------------------------------------------------------------------- /Chapter16/service/dp_service/team.go: -------------------------------------------------------------------------------- 1 | package dp_service 2 | 3 | import ( 4 | "github.com/i-coder-robot/book_final_code/Chapter16/model" 5 | "github.com/i-coder-robot/book_final_code/Chapter16/repository" 6 | "github.com/i-coder-robot/book_final_code/Chapter16/res" 7 | ) 8 | 9 | type TeamService struct { 10 | Repo *repository.TeamRepo 11 | } 12 | 13 | func (t *TeamService) GetTeamListByHotelId(hotelId string) []model.Team { 14 | return t.Repo.GetTeamListByHotelId(hotelId) 15 | } 16 | 17 | func (t *TeamService) GetTeamDetail(teamId string) res.TeamResp { 18 | detail := t.Repo.GetTeamDetail(teamId) 19 | item := convert2TeamResp(detail) 20 | return item 21 | } 22 | 23 | func convert2TeamResp(items []model.TeamAggregation) res.TeamResp { 24 | var resp res.TeamResp 25 | resp.TeamDetail = items[0].TeamDetail 26 | for _, item := range items { 27 | f := &item.TeamChooseFood 28 | resp.FoodList = append(resp.FoodList, Convert2TeamChooseFoodResp(f)) 29 | i := &item.TeamChooseItem 30 | resp.ChooseItems = append(resp.ChooseItems, TeamChooseItem(i)) 31 | } 32 | return resp 33 | } 34 | func TeamChooseItem(item *model.TeamChooseItem) res.TeamChooseItemResp { 35 | r := res.TeamChooseItemResp{ 36 | TeamChoseItemId: item.TeamChoseItemId, 37 | TeamChooseItemName: item.TeamChooseItemName, 38 | TeamChooseItemTip: item.TeamChooseItemTip, 39 | TeamPrice: item.TeamPrice, 40 | } 41 | return r 42 | } 43 | func Convert2TeamChooseFoodResp(food *model.TeamChooseFood) res.TeamChooseFoodResp { 44 | r := res.TeamChooseFoodResp{} 45 | r.TeamChooseFoodId = food.TeamChooseFoodId 46 | r.TeamChooseFoodName = food.TeamChooseFoodName 47 | return r 48 | } 49 | -------------------------------------------------------------------------------- /Chapter16/service/dp_service/team_order_post.go: -------------------------------------------------------------------------------- 1 | package dp_service 2 | 3 | import ( 4 | "errors" 5 | "github.com/hashicorp/go-uuid" 6 | "github.com/i-coder-robot/book_final_code/Chapter16/handler/param" 7 | "github.com/i-coder-robot/book_final_code/Chapter16/model" 8 | "github.com/i-coder-robot/book_final_code/Chapter16/repository" 9 | ) 10 | 11 | type PostTeamOrderService struct { 12 | TeamRepo *repository.TeamRepo 13 | Repo *repository.TeamPostOrderRepo 14 | } 15 | 16 | func (t *PostTeamOrderService) PostTeamOrder(order param.TeamPostOrder) (string, error) { 17 | //到数据库查看是否有这个团购优惠 18 | teamDetail := t.TeamRepo.GetTeamDetail(order.TeamDetailId) 19 | if teamDetail == nil { 20 | return "", errors.New("TeamDetailId参数错误") 21 | } 22 | //下单数量不能小于1 23 | if order.Quantity < 1 { 24 | return "", errors.New("Quantity参数错误") 25 | } 26 | //售卖价格要大于0 27 | if order.RealPrice < 0 { 28 | return "", errors.New("RealPrice参数错误") 29 | } 30 | //下单人的手机号,不能为空 31 | if order.Mobile == "" { 32 | return "", errors.New("Mobile参数错误") 33 | } 34 | 35 | id, _ := uuid.GenerateUUID() 36 | o := model.TeamPostOrder{ 37 | TeamPostOrderId: id, 38 | TeamDetailId: order.TeamDetailId, 39 | RealPrice: order.RealPrice, 40 | Quantity: order.Quantity, 41 | Mobile: order.Mobile, 42 | Name: order.Name, 43 | Sex: order.Sex, 44 | Message: order.Message, 45 | } 46 | 47 | return t.Repo.Save(o), nil 48 | } 49 | -------------------------------------------------------------------------------- /Chapter16/service/wx_service/WXService.go: -------------------------------------------------------------------------------- 1 | package wx_service 2 | 3 | import ( 4 | "encoding/json" 5 | "errors" 6 | "fmt" 7 | "github.com/i-coder-robot/book_final_code/Chapter16/res" 8 | "github.com/spf13/viper" 9 | "net/http" 10 | ) 11 | 12 | // 这个函数以 code 作为输入, 返回调用微信接口得到的对象指针和异常情况 13 | func WXLogin(code string) (*res.WXLoginResponse, error) { 14 | url := "https://api.weixin.qq.com/sns/jscode2session?appid=%s&secret=%s&js_code=%s&grant_type=authorization_code" 15 | 16 | // 这里的appId和secret是在微信公众平台上获取的 17 | url = fmt.Sprintf(url, viper.GetString("wx_app_id"), viper.GetString("wx_secret"), code) 18 | 19 | // 创建http get请求 20 | resp, err := http.Get(url) 21 | if err != nil { 22 | return nil, err 23 | } 24 | defer resp.Body.Close() 25 | 26 | // 解析http请求中body 数据到我们定义的结构体中 27 | wxResp := res.WXLoginResponse{} 28 | decoder := json.NewDecoder(resp.Body) 29 | if err := decoder.Decode(&wxResp); err != nil { 30 | return nil, err 31 | } 32 | 33 | // 判断微信接口是否返回一个异常情况 34 | if wxResp.ErrCode != 0 { 35 | return nil, errors.New(fmt.Sprintf("ErrCode:%s ErrMsg:%s", wxResp.ErrCode, wxResp.ErrMsg)) 36 | } 37 | 38 | return &wxResp, nil 39 | } 40 | -------------------------------------------------------------------------------- /Chapter16/static/images/001.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/i-coder-robot/book_final_code/00ec2d69dc7e2bc68aa78019cbceb9bdb87290fb/Chapter16/static/images/001.png -------------------------------------------------------------------------------- /Chapter16/static/images/002.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/i-coder-robot/book_final_code/00ec2d69dc7e2bc68aa78019cbceb9bdb87290fb/Chapter16/static/images/002.png -------------------------------------------------------------------------------- /Chapter16/static/images/003.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/i-coder-robot/book_final_code/00ec2d69dc7e2bc68aa78019cbceb9bdb87290fb/Chapter16/static/images/003.png -------------------------------------------------------------------------------- /Chapter16/static/images/21.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/i-coder-robot/book_final_code/00ec2d69dc7e2bc68aa78019cbceb9bdb87290fb/Chapter16/static/images/21.png -------------------------------------------------------------------------------- /Chapter16/static/images/42.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/i-coder-robot/book_final_code/00ec2d69dc7e2bc68aa78019cbceb9bdb87290fb/Chapter16/static/images/42.png -------------------------------------------------------------------------------- /Chapter16/static/images/50.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/i-coder-robot/book_final_code/00ec2d69dc7e2bc68aa78019cbceb9bdb87290fb/Chapter16/static/images/50.png -------------------------------------------------------------------------------- /Chapter16/static/images/51.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/i-coder-robot/book_final_code/00ec2d69dc7e2bc68aa78019cbceb9bdb87290fb/Chapter16/static/images/51.png -------------------------------------------------------------------------------- /Chapter16/static/images/60.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/i-coder-robot/book_final_code/00ec2d69dc7e2bc68aa78019cbceb9bdb87290fb/Chapter16/static/images/60.png -------------------------------------------------------------------------------- /Chapter16/static/images/61.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/i-coder-robot/book_final_code/00ec2d69dc7e2bc68aa78019cbceb9bdb87290fb/Chapter16/static/images/61.png -------------------------------------------------------------------------------- /Chapter16/static/images/80.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/i-coder-robot/book_final_code/00ec2d69dc7e2bc68aa78019cbceb9bdb87290fb/Chapter16/static/images/80.png -------------------------------------------------------------------------------- /Chapter16/static/images/KTVdatu.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/i-coder-robot/book_final_code/00ec2d69dc7e2bc68aa78019cbceb9bdb87290fb/Chapter16/static/images/KTVdatu.png -------------------------------------------------------------------------------- /Chapter16/static/images/ad8408ec7aa0e3e76cbb92eca2808c7c10489.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/i-coder-robot/book_final_code/00ec2d69dc7e2bc68aa78019cbceb9bdb87290fb/Chapter16/static/images/ad8408ec7aa0e3e76cbb92eca2808c7c10489.png -------------------------------------------------------------------------------- /Chapter16/static/images/all-small.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/i-coder-robot/book_final_code/00ec2d69dc7e2bc68aa78019cbceb9bdb87290fb/Chapter16/static/images/all-small.png -------------------------------------------------------------------------------- /Chapter16/static/images/anmo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/i-coder-robot/book_final_code/00ec2d69dc7e2bc68aa78019cbceb9bdb87290fb/Chapter16/static/images/anmo.png -------------------------------------------------------------------------------- /Chapter16/static/images/arrow.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/i-coder-robot/book_final_code/00ec2d69dc7e2bc68aa78019cbceb9bdb87290fb/Chapter16/static/images/arrow.png -------------------------------------------------------------------------------- /Chapter16/static/images/banner.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/i-coder-robot/book_final_code/00ec2d69dc7e2bc68aa78019cbceb9bdb87290fb/Chapter16/static/images/banner.jpg -------------------------------------------------------------------------------- /Chapter16/static/images/banner.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/i-coder-robot/book_final_code/00ec2d69dc7e2bc68aa78019cbceb9bdb87290fb/Chapter16/static/images/banner.png -------------------------------------------------------------------------------- /Chapter16/static/images/bath.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/i-coder-robot/book_final_code/00ec2d69dc7e2bc68aa78019cbceb9bdb87290fb/Chapter16/static/images/bath.png -------------------------------------------------------------------------------- /Chapter16/static/images/cart.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/i-coder-robot/book_final_code/00ec2d69dc7e2bc68aa78019cbceb9bdb87290fb/Chapter16/static/images/cart.jpeg -------------------------------------------------------------------------------- /Chapter16/static/images/chuancai.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/i-coder-robot/book_final_code/00ec2d69dc7e2bc68aa78019cbceb9bdb87290fb/Chapter16/static/images/chuancai.png -------------------------------------------------------------------------------- /Chapter16/static/images/chuangyi.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/i-coder-robot/book_final_code/00ec2d69dc7e2bc68aa78019cbceb9bdb87290fb/Chapter16/static/images/chuangyi.png -------------------------------------------------------------------------------- /Chapter16/static/images/dongbei.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/i-coder-robot/book_final_code/00ec2d69dc7e2bc68aa78019cbceb9bdb87290fb/Chapter16/static/images/dongbei.png -------------------------------------------------------------------------------- /Chapter16/static/images/dongnanya.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/i-coder-robot/book_final_code/00ec2d69dc7e2bc68aa78019cbceb9bdb87290fb/Chapter16/static/images/dongnanya.png -------------------------------------------------------------------------------- /Chapter16/static/images/douyin001.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/i-coder-robot/book_final_code/00ec2d69dc7e2bc68aa78019cbceb9bdb87290fb/Chapter16/static/images/douyin001.png -------------------------------------------------------------------------------- /Chapter16/static/images/douyin002.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/i-coder-robot/book_final_code/00ec2d69dc7e2bc68aa78019cbceb9bdb87290fb/Chapter16/static/images/douyin002.png -------------------------------------------------------------------------------- /Chapter16/static/images/douyin003.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/i-coder-robot/book_final_code/00ec2d69dc7e2bc68aa78019cbceb9bdb87290fb/Chapter16/static/images/douyin003.png -------------------------------------------------------------------------------- /Chapter16/static/images/douyin004.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/i-coder-robot/book_final_code/00ec2d69dc7e2bc68aa78019cbceb9bdb87290fb/Chapter16/static/images/douyin004.png -------------------------------------------------------------------------------- /Chapter16/static/images/douyin005.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/i-coder-robot/book_final_code/00ec2d69dc7e2bc68aa78019cbceb9bdb87290fb/Chapter16/static/images/douyin005.png -------------------------------------------------------------------------------- /Chapter16/static/images/douyin006.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/i-coder-robot/book_final_code/00ec2d69dc7e2bc68aa78019cbceb9bdb87290fb/Chapter16/static/images/douyin006.png -------------------------------------------------------------------------------- /Chapter16/static/images/douyin007.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/i-coder-robot/book_final_code/00ec2d69dc7e2bc68aa78019cbceb9bdb87290fb/Chapter16/static/images/douyin007.png -------------------------------------------------------------------------------- /Chapter16/static/images/douyin008.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/i-coder-robot/book_final_code/00ec2d69dc7e2bc68aa78019cbceb9bdb87290fb/Chapter16/static/images/douyin008.png -------------------------------------------------------------------------------- /Chapter16/static/images/edu.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/i-coder-robot/book_final_code/00ec2d69dc7e2bc68aa78019cbceb9bdb87290fb/Chapter16/static/images/edu.png -------------------------------------------------------------------------------- /Chapter16/static/images/food.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/i-coder-robot/book_final_code/00ec2d69dc7e2bc68aa78019cbceb9bdb87290fb/Chapter16/static/images/food.png -------------------------------------------------------------------------------- /Chapter16/static/images/good_restrant001.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/i-coder-robot/book_final_code/00ec2d69dc7e2bc68aa78019cbceb9bdb87290fb/Chapter16/static/images/good_restrant001.png -------------------------------------------------------------------------------- /Chapter16/static/images/good_restrant002.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/i-coder-robot/book_final_code/00ec2d69dc7e2bc68aa78019cbceb9bdb87290fb/Chapter16/static/images/good_restrant002.png -------------------------------------------------------------------------------- /Chapter16/static/images/good_restrant003.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/i-coder-robot/book_final_code/00ec2d69dc7e2bc68aa78019cbceb9bdb87290fb/Chapter16/static/images/good_restrant003.png -------------------------------------------------------------------------------- /Chapter16/static/images/good_restrant_huoguo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/i-coder-robot/book_final_code/00ec2d69dc7e2bc68aa78019cbceb9bdb87290fb/Chapter16/static/images/good_restrant_huoguo.png -------------------------------------------------------------------------------- /Chapter16/static/images/goods001.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/i-coder-robot/book_final_code/00ec2d69dc7e2bc68aa78019cbceb9bdb87290fb/Chapter16/static/images/goods001.png -------------------------------------------------------------------------------- /Chapter16/static/images/goods002.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/i-coder-robot/book_final_code/00ec2d69dc7e2bc68aa78019cbceb9bdb87290fb/Chapter16/static/images/goods002.png -------------------------------------------------------------------------------- /Chapter16/static/images/goods003.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/i-coder-robot/book_final_code/00ec2d69dc7e2bc68aa78019cbceb9bdb87290fb/Chapter16/static/images/goods003.png -------------------------------------------------------------------------------- /Chapter16/static/images/goods004.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/i-coder-robot/book_final_code/00ec2d69dc7e2bc68aa78019cbceb9bdb87290fb/Chapter16/static/images/goods004.png -------------------------------------------------------------------------------- /Chapter16/static/images/goods005.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/i-coder-robot/book_final_code/00ec2d69dc7e2bc68aa78019cbceb9bdb87290fb/Chapter16/static/images/goods005.png -------------------------------------------------------------------------------- /Chapter16/static/images/goods006.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/i-coder-robot/book_final_code/00ec2d69dc7e2bc68aa78019cbceb9bdb87290fb/Chapter16/static/images/goods006.png -------------------------------------------------------------------------------- /Chapter16/static/images/goods007.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/i-coder-robot/book_final_code/00ec2d69dc7e2bc68aa78019cbceb9bdb87290fb/Chapter16/static/images/goods007.png -------------------------------------------------------------------------------- /Chapter16/static/images/goods008.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/i-coder-robot/book_final_code/00ec2d69dc7e2bc68aa78019cbceb9bdb87290fb/Chapter16/static/images/goods008.png -------------------------------------------------------------------------------- /Chapter16/static/images/hair.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/i-coder-robot/book_final_code/00ec2d69dc7e2bc68aa78019cbceb9bdb87290fb/Chapter16/static/images/hair.png -------------------------------------------------------------------------------- /Chapter16/static/images/haixian.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/i-coder-robot/book_final_code/00ec2d69dc7e2bc68aa78019cbceb9bdb87290fb/Chapter16/static/images/haixian.png -------------------------------------------------------------------------------- /Chapter16/static/images/hanguo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/i-coder-robot/book_final_code/00ec2d69dc7e2bc68aa78019cbceb9bdb87290fb/Chapter16/static/images/hanguo.png -------------------------------------------------------------------------------- /Chapter16/static/images/headPic.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/i-coder-robot/book_final_code/00ec2d69dc7e2bc68aa78019cbceb9bdb87290fb/Chapter16/static/images/headPic.png -------------------------------------------------------------------------------- /Chapter16/static/images/health.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/i-coder-robot/book_final_code/00ec2d69dc7e2bc68aa78019cbceb9bdb87290fb/Chapter16/static/images/health.png -------------------------------------------------------------------------------- /Chapter16/static/images/heizhenzhu.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/i-coder-robot/book_final_code/00ec2d69dc7e2bc68aa78019cbceb9bdb87290fb/Chapter16/static/images/heizhenzhu.png -------------------------------------------------------------------------------- /Chapter16/static/images/hotel.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/i-coder-robot/book_final_code/00ec2d69dc7e2bc68aa78019cbceb9bdb87290fb/Chapter16/static/images/hotel.png -------------------------------------------------------------------------------- /Chapter16/static/images/huoguo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/i-coder-robot/book_final_code/00ec2d69dc7e2bc68aa78019cbceb9bdb87290fb/Chapter16/static/images/huoguo.png -------------------------------------------------------------------------------- /Chapter16/static/images/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/i-coder-robot/book_final_code/00ec2d69dc7e2bc68aa78019cbceb9bdb87290fb/Chapter16/static/images/icon.png -------------------------------------------------------------------------------- /Chapter16/static/images/jiangzhe.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/i-coder-robot/book_final_code/00ec2d69dc7e2bc68aa78019cbceb9bdb87290fb/Chapter16/static/images/jiangzhe.png -------------------------------------------------------------------------------- /Chapter16/static/images/jingdianmenpiaodatu.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/i-coder-robot/book_final_code/00ec2d69dc7e2bc68aa78019cbceb9bdb87290fb/Chapter16/static/images/jingdianmenpiaodatu.png -------------------------------------------------------------------------------- /Chapter16/static/images/kafei.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/i-coder-robot/book_final_code/00ec2d69dc7e2bc68aa78019cbceb9bdb87290fb/Chapter16/static/images/kafei.png -------------------------------------------------------------------------------- /Chapter16/static/images/ktv.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/i-coder-robot/book_final_code/00ec2d69dc7e2bc68aa78019cbceb9bdb87290fb/Chapter16/static/images/ktv.png -------------------------------------------------------------------------------- /Chapter16/static/images/liren.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/i-coder-robot/book_final_code/00ec2d69dc7e2bc68aa78019cbceb9bdb87290fb/Chapter16/static/images/liren.png -------------------------------------------------------------------------------- /Chapter16/static/images/lirenmeifadatu.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/i-coder-robot/book_final_code/00ec2d69dc7e2bc68aa78019cbceb9bdb87290fb/Chapter16/static/images/lirenmeifadatu.png -------------------------------------------------------------------------------- /Chapter16/static/images/maoyandianyingdatu.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/i-coder-robot/book_final_code/00ec2d69dc7e2bc68aa78019cbceb9bdb87290fb/Chapter16/static/images/maoyandianyingdatu.png -------------------------------------------------------------------------------- /Chapter16/static/images/me001.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/i-coder-robot/book_final_code/00ec2d69dc7e2bc68aa78019cbceb9bdb87290fb/Chapter16/static/images/me001.png -------------------------------------------------------------------------------- /Chapter16/static/images/me002.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/i-coder-robot/book_final_code/00ec2d69dc7e2bc68aa78019cbceb9bdb87290fb/Chapter16/static/images/me002.png -------------------------------------------------------------------------------- /Chapter16/static/images/me003.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/i-coder-robot/book_final_code/00ec2d69dc7e2bc68aa78019cbceb9bdb87290fb/Chapter16/static/images/me003.png -------------------------------------------------------------------------------- /Chapter16/static/images/me004.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/i-coder-robot/book_final_code/00ec2d69dc7e2bc68aa78019cbceb9bdb87290fb/Chapter16/static/images/me004.png -------------------------------------------------------------------------------- /Chapter16/static/images/me005.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/i-coder-robot/book_final_code/00ec2d69dc7e2bc68aa78019cbceb9bdb87290fb/Chapter16/static/images/me005.png -------------------------------------------------------------------------------- /Chapter16/static/images/me006.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/i-coder-robot/book_final_code/00ec2d69dc7e2bc68aa78019cbceb9bdb87290fb/Chapter16/static/images/me006.png -------------------------------------------------------------------------------- /Chapter16/static/images/me007.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/i-coder-robot/book_final_code/00ec2d69dc7e2bc68aa78019cbceb9bdb87290fb/Chapter16/static/images/me007.png -------------------------------------------------------------------------------- /Chapter16/static/images/me008.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/i-coder-robot/book_final_code/00ec2d69dc7e2bc68aa78019cbceb9bdb87290fb/Chapter16/static/images/me008.png -------------------------------------------------------------------------------- /Chapter16/static/images/meishidatu.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/i-coder-robot/book_final_code/00ec2d69dc7e2bc68aa78019cbceb9bdb87290fb/Chapter16/static/images/meishidatu.png -------------------------------------------------------------------------------- /Chapter16/static/images/miaosha.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/i-coder-robot/book_final_code/00ec2d69dc7e2bc68aa78019cbceb9bdb87290fb/Chapter16/static/images/miaosha.png -------------------------------------------------------------------------------- /Chapter16/static/images/minsu.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/i-coder-robot/book_final_code/00ec2d69dc7e2bc68aa78019cbceb9bdb87290fb/Chapter16/static/images/minsu.png -------------------------------------------------------------------------------- /Chapter16/static/images/myCode.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/i-coder-robot/book_final_code/00ec2d69dc7e2bc68aa78019cbceb9bdb87290fb/Chapter16/static/images/myCode.png -------------------------------------------------------------------------------- /Chapter16/static/images/my_code.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/i-coder-robot/book_final_code/00ec2d69dc7e2bc68aa78019cbceb9bdb87290fb/Chapter16/static/images/my_code.png -------------------------------------------------------------------------------- /Chapter16/static/images/niuroumian.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/i-coder-robot/book_final_code/00ec2d69dc7e2bc68aa78019cbceb9bdb87290fb/Chapter16/static/images/niuroumian.png -------------------------------------------------------------------------------- /Chapter16/static/images/profile.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/i-coder-robot/book_final_code/00ec2d69dc7e2bc68aa78019cbceb9bdb87290fb/Chapter16/static/images/profile.png -------------------------------------------------------------------------------- /Chapter16/static/images/qinzi.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/i-coder-robot/book_final_code/00ec2d69dc7e2bc68aa78019cbceb9bdb87290fb/Chapter16/static/images/qinzi.png -------------------------------------------------------------------------------- /Chapter16/static/images/quan.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/i-coder-robot/book_final_code/00ec2d69dc7e2bc68aa78019cbceb9bdb87290fb/Chapter16/static/images/quan.png -------------------------------------------------------------------------------- /Chapter16/static/images/ribencai.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/i-coder-robot/book_final_code/00ec2d69dc7e2bc68aa78019cbceb9bdb87290fb/Chapter16/static/images/ribencai.png -------------------------------------------------------------------------------- /Chapter16/static/images/rush.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/i-coder-robot/book_final_code/00ec2d69dc7e2bc68aa78019cbceb9bdb87290fb/Chapter16/static/images/rush.png -------------------------------------------------------------------------------- /Chapter16/static/images/search_list_coupon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/i-coder-robot/book_final_code/00ec2d69dc7e2bc68aa78019cbceb9bdb87290fb/Chapter16/static/images/search_list_coupon.png -------------------------------------------------------------------------------- /Chapter16/static/images/search_list_tuan.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/i-coder-robot/book_final_code/00ec2d69dc7e2bc68aa78019cbceb9bdb87290fb/Chapter16/static/images/search_list_tuan.png -------------------------------------------------------------------------------- /Chapter16/static/images/shaokao.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/i-coder-robot/book_final_code/00ec2d69dc7e2bc68aa78019cbceb9bdb87290fb/Chapter16/static/images/shaokao.png -------------------------------------------------------------------------------- /Chapter16/static/images/sports.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/i-coder-robot/book_final_code/00ec2d69dc7e2bc68aa78019cbceb9bdb87290fb/Chapter16/static/images/sports.png -------------------------------------------------------------------------------- /Chapter16/static/images/star.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/i-coder-robot/book_final_code/00ec2d69dc7e2bc68aa78019cbceb9bdb87290fb/Chapter16/static/images/star.png -------------------------------------------------------------------------------- /Chapter16/static/images/star0.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/i-coder-robot/book_final_code/00ec2d69dc7e2bc68aa78019cbceb9bdb87290fb/Chapter16/static/images/star0.png -------------------------------------------------------------------------------- /Chapter16/static/images/star1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/i-coder-robot/book_final_code/00ec2d69dc7e2bc68aa78019cbceb9bdb87290fb/Chapter16/static/images/star1.png -------------------------------------------------------------------------------- /Chapter16/static/images/star2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/i-coder-robot/book_final_code/00ec2d69dc7e2bc68aa78019cbceb9bdb87290fb/Chapter16/static/images/star2.png -------------------------------------------------------------------------------- /Chapter16/static/images/team.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/i-coder-robot/book_final_code/00ec2d69dc7e2bc68aa78019cbceb9bdb87290fb/Chapter16/static/images/team.jpg -------------------------------------------------------------------------------- /Chapter16/static/images/team.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/i-coder-robot/book_final_code/00ec2d69dc7e2bc68aa78019cbceb9bdb87290fb/Chapter16/static/images/team.png -------------------------------------------------------------------------------- /Chapter16/static/images/tiandian.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/i-coder-robot/book_final_code/00ec2d69dc7e2bc68aa78019cbceb9bdb87290fb/Chapter16/static/images/tiandian.png -------------------------------------------------------------------------------- /Chapter16/static/images/travel.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/i-coder-robot/book_final_code/00ec2d69dc7e2bc68aa78019cbceb9bdb87290fb/Chapter16/static/images/travel.png -------------------------------------------------------------------------------- /Chapter16/static/images/vote.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/i-coder-robot/book_final_code/00ec2d69dc7e2bc68aa78019cbceb9bdb87290fb/Chapter16/static/images/vote.png -------------------------------------------------------------------------------- /Chapter16/static/images/waimai.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/i-coder-robot/book_final_code/00ec2d69dc7e2bc68aa78019cbceb9bdb87290fb/Chapter16/static/images/waimai.png -------------------------------------------------------------------------------- /Chapter16/static/images/waimaidatu.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/i-coder-robot/book_final_code/00ec2d69dc7e2bc68aa78019cbceb9bdb87290fb/Chapter16/static/images/waimaidatu.png -------------------------------------------------------------------------------- /Chapter16/static/images/xiang.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/i-coder-robot/book_final_code/00ec2d69dc7e2bc68aa78019cbceb9bdb87290fb/Chapter16/static/images/xiang.png -------------------------------------------------------------------------------- /Chapter16/static/images/xiaochi.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/i-coder-robot/book_final_code/00ec2d69dc7e2bc68aa78019cbceb9bdb87290fb/Chapter16/static/images/xiaochi.png -------------------------------------------------------------------------------- /Chapter16/static/images/xican.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/i-coder-robot/book_final_code/00ec2d69dc7e2bc68aa78019cbceb9bdb87290fb/Chapter16/static/images/xican.png -------------------------------------------------------------------------------- /Chapter16/static/images/xinjiang.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/i-coder-robot/book_final_code/00ec2d69dc7e2bc68aa78019cbceb9bdb87290fb/Chapter16/static/images/xinjiang.png -------------------------------------------------------------------------------- /Chapter16/static/images/xiuxianyuledatu.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/i-coder-robot/book_final_code/00ec2d69dc7e2bc68aa78019cbceb9bdb87290fb/Chapter16/static/images/xiuxianyuledatu.png -------------------------------------------------------------------------------- /Chapter16/static/images/yanchu.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/i-coder-robot/book_final_code/00ec2d69dc7e2bc68aa78019cbceb9bdb87290fb/Chapter16/static/images/yanchu.png -------------------------------------------------------------------------------- /Chapter16/static/images/yuecai.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/i-coder-robot/book_final_code/00ec2d69dc7e2bc68aa78019cbceb9bdb87290fb/Chapter16/static/images/yuecai.png -------------------------------------------------------------------------------- /Chapter16/static/images/yule.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/i-coder-robot/book_final_code/00ec2d69dc7e2bc68aa78019cbceb9bdb87290fb/Chapter16/static/images/yule.png -------------------------------------------------------------------------------- /Chapter16/static/images/yundong.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/i-coder-robot/book_final_code/00ec2d69dc7e2bc68aa78019cbceb9bdb87290fb/Chapter16/static/images/yundong.png -------------------------------------------------------------------------------- /Chapter16/static/images/zhoubian.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/i-coder-robot/book_final_code/00ec2d69dc7e2bc68aa78019cbceb9bdb87290fb/Chapter16/static/images/zhoubian.png -------------------------------------------------------------------------------- /Chapter16/token/token.go: -------------------------------------------------------------------------------- 1 | package token 2 | 3 | import ( 4 | "fmt" 5 | "github.com/dgrijalva/jwt-go" 6 | "github.com/gin-gonic/gin" 7 | "github.com/i-coder-robot/book_final_code/Chapter16/myerr" 8 | "github.com/spf13/viper" 9 | "time" 10 | ) 11 | 12 | type Context struct { 13 | ID string 14 | Username string 15 | } 16 | 17 | // secretFunc validates the secret format. 18 | func secretFunc(secret string) jwt.Keyfunc { 19 | return func(token *jwt.Token) (interface{}, error) { 20 | // Make sure the `alg` is what we except. 21 | if _, ok := token.Method.(*jwt.SigningMethodHMAC); !ok { 22 | return nil, jwt.ErrSignatureInvalid 23 | } 24 | 25 | return []byte(secret), nil 26 | } 27 | } 28 | 29 | // Parse validates the token with the specified secret, 30 | // and returns the context if the token was valid. 31 | func Parse(tokenString string, secret string) (*Context, error) { 32 | ctx := &Context{} 33 | 34 | // Parse the token. 35 | token, err := jwt.Parse(tokenString, secretFunc(secret)) 36 | 37 | // Parse error. 38 | if err != nil { 39 | return ctx, err 40 | 41 | // Read the token if it's valid. 42 | } else if claims, ok := token.Claims.(jwt.MapClaims); ok && token.Valid { 43 | ctx.ID = claims["id"].(string) 44 | ctx.Username = claims["username"].(string) 45 | return ctx, nil 46 | 47 | // Other errors. 48 | } else { 49 | return ctx, err 50 | } 51 | } 52 | 53 | // ParseRequest gets the token from the header and 54 | // pass it to the Parse function to parses the token. 55 | func ParseRequest(c *gin.Context) (*Context, error) { 56 | header := c.Request.Header.Get("Authorization") 57 | 58 | // Load the jwt secret from config 59 | secret := viper.GetString("jwt_secret") 60 | 61 | if len(header) == 0 { 62 | return &Context{}, myerr.ErrMissingHeader 63 | } 64 | 65 | var t string 66 | // Parse the header to get the token part. 67 | fmt.Sscanf(header, "Bearer %s", &t) 68 | return Parse(t, secret) 69 | } 70 | 71 | // Sign signs the context with the specified secret. 72 | func Sign(ctx *gin.Context, c Context, secret string) (tokenString string, err error) { 73 | // Load the jwt secret from the Gin config if the secret isn't specified. 74 | if secret == "" { 75 | secret = viper.GetString("jwt_secret") 76 | } 77 | // The token content. 78 | token := jwt.NewWithClaims(jwt.SigningMethodHS256, jwt.MapClaims{ 79 | "id": c.ID, 80 | "username": c.Username, 81 | "nbf": time.Now().Unix(), 82 | "iat": time.Now().Unix(), 83 | }) 84 | // Sign the token with the specified secret. 85 | tokenString, err = token.SignedString([]byte(secret)) 86 | 87 | return 88 | } 89 | -------------------------------------------------------------------------------- /Chapter16/utils/auth.go: -------------------------------------------------------------------------------- 1 | package utils 2 | 3 | import ( 4 | "github.com/go-playground/validator/v10" 5 | "github.com/i-coder-robot/book_final_code/Chapter16/myerr" 6 | "github.com/i-coder-robot/book_final_code/Chapter17/model" 7 | "golang.org/x/crypto/bcrypt" 8 | ) 9 | 10 | // 给文本加密 11 | func Encrypt(source string) (string, error) { 12 | hashedBytes, err := bcrypt.GenerateFromPassword([]byte(source), bcrypt.DefaultCost) 13 | return string(hashedBytes), err 14 | } 15 | 16 | // 比较密码 17 | func Compare(hashedPassword, password string) error { 18 | return bcrypt.CompareHashAndPassword([]byte(hashedPassword), []byte(password)) 19 | } 20 | 21 | // 验证字段是否有效. 22 | func Validate(m model.Account) error { 23 | validate := validator.New() 24 | return validate.Struct(m) 25 | } 26 | 27 | func CheckParam(accountName, password string) myerr.Err { 28 | if accountName == "" { 29 | return myerr.New(*myerr.ErrValidation, nil).Add("用户名为空.") 30 | } 31 | 32 | if password == "" { 33 | return myerr.New(*myerr.ErrValidation, nil).Add("密码为空.") 34 | } 35 | return myerr.Err{ErrNum: *myerr.PassParamCheck, Err: nil} 36 | } 37 | -------------------------------------------------------------------------------- /Chapter16/utils/utils.go: -------------------------------------------------------------------------------- 1 | package utils 2 | 3 | import ( 4 | "crypto/md5" 5 | "encoding/hex" 6 | "github.com/gin-gonic/gin" 7 | ) 8 | 9 | const ( 10 | Limit=20 11 | ) 12 | 13 | 14 | func GetRequestID(c *gin.Context) string { 15 | v, ok := c.Get("X-Request-Id") 16 | if !ok { 17 | return "" 18 | } 19 | if requestId, ok := v.(string); ok { 20 | return requestId 21 | } 22 | return "" 23 | } 24 | 25 | // 将一个字符串进行MD5加密后返回加密后的字符串 26 | func GetMD5Encode(data string) string { 27 | h := md5.New() 28 | h.Write([]byte(data)) 29 | return hex.EncodeToString(h.Sum(nil)) 30 | } -------------------------------------------------------------------------------- /Chapter17/17-1/health/health.go: -------------------------------------------------------------------------------- 1 | package health 2 | 3 | import ( 4 | "github.com/gin-gonic/gin" 5 | "net/http" 6 | ) 7 | 8 | 9 | func Health(c *gin.Context) { 10 | message := "OK" 11 | c.String(http.StatusOK, "\n"+message) 12 | } 13 | -------------------------------------------------------------------------------- /Chapter17/17-1/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "errors" 5 | "github.com/gin-gonic/gin" 6 | "github.com/i-coder-robot/book_final_code/Chapter17/17-1/router" 7 | "log" 8 | "net/http" 9 | "time" 10 | ) 11 | 12 | func main() { 13 | g := gin.New() 14 | middlewares := []gin.HandlerFunc{} 15 | router.Load( 16 | g, 17 | middlewares..., 18 | ) 19 | 20 | go func() { 21 | if err := checkServer(); err != nil { 22 | log.Fatal("自检程序发生错误...", err) 23 | } 24 | log.Print("路由成功部署.") 25 | }() 26 | 27 | log.Printf("开始监听http地址: %s", "9090") 28 | log.Printf(http.ListenAndServe(":9090", g).Error()) 29 | } 30 | 31 | func checkServer() error { 32 | for i := 0; i < 10; i++ { 33 | //发送一个GET请求给 `/check/health`,验证服务器是否成功. 34 | resp, err := http.Get("http://127.0.0.1:9090/check/health") 35 | if err == nil && resp.StatusCode == 200 { 36 | return nil 37 | } 38 | 39 | // Sleep 1 second 继续重试. 40 | log.Print("等待路由,1秒后重试。") 41 | time.Sleep(time.Second) 42 | } 43 | return errors.New("无法连接到路由.") 44 | } 45 | -------------------------------------------------------------------------------- /Chapter17/17-1/router/router.go: -------------------------------------------------------------------------------- 1 | package router 2 | 3 | import ( 4 | "github.com/gin-gonic/gin" 5 | "github.com/i-coder-robot/book_final_code/Chapter16/health" 6 | "net/http" 7 | ) 8 | 9 | func Load(engine *gin.Engine, middlewares ...gin.HandlerFunc) *gin.Engine { 10 | engine.Use(gin.Recovery()) 11 | engine.Use(middlewares...) 12 | engine.NoRoute(func(context *gin.Context) { 13 | context.String(http.StatusNotFound, "API路由不正确.") 14 | }) 15 | check := engine.Group("/check") 16 | { 17 | check.GET("/health", health.Health) 18 | } 19 | 20 | return engine 21 | } 22 | -------------------------------------------------------------------------------- /Chapter17/17-2/conf/config.yaml: -------------------------------------------------------------------------------- 1 | runmode: debug # 开发模式, debug, release, test 2 | addr: :9090 # HTTP绑定端口 3 | url: http://127.0.0.1:9090 4 | max_check_count: 10 5 | database: 6 | name: db 7 | addr: 127.0.0.1:3306 8 | username: root 9 | password: smartwell -------------------------------------------------------------------------------- /Chapter17/17-2/config/config.go: -------------------------------------------------------------------------------- 1 | package config 2 | 3 | import ( 4 | "github.com/fsnotify/fsnotify" 5 | "github.com/spf13/viper" 6 | "log" 7 | ) 8 | 9 | type Config struct { 10 | Name string 11 | } 12 | 13 | func Init(name string) error { 14 | c := Config{ 15 | Name: name, 16 | } 17 | 18 | // 初始化配置文件 19 | if err := c.initConfig(); err != nil { 20 | return err 21 | } 22 | 23 | // 监控配置文件变化并热加载程序 24 | c.watchConfig() 25 | 26 | return nil 27 | } 28 | 29 | func (c *Config) initConfig() error { 30 | if c.Name != "" { 31 | viper.SetConfigFile(c.Name) // 如果指定了配置文件,则解析指定的配置文件 32 | } else { 33 | viper.AddConfigPath("./conf/") //命令行的配置 34 | viper.SetConfigName("config") 35 | } 36 | viper.SetConfigType("yaml") // 设置配置文件格式为YAML 37 | if err := viper.ReadInConfig(); err != nil { // viper解析配置文件 38 | return err 39 | } 40 | 41 | return nil 42 | } 43 | 44 | // 监控配置文件变化并热加载程序 45 | func (c *Config) watchConfig() { 46 | viper.WatchConfig() 47 | viper.OnConfigChange(func(e fsnotify.Event) { 48 | log.Printf("Config file changed: %s", e.Name) 49 | }) 50 | } 51 | -------------------------------------------------------------------------------- /Chapter17/17-2/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "errors" 5 | "flag" 6 | "github.com/gin-gonic/gin" 7 | "github.com/i-coder-robot/book_final_code/Chapter17/17-1/router" 8 | "github.com/i-coder-robot/book_final_code/Chapter17/17-2/config" 9 | "github.com/spf13/viper" 10 | "log" 11 | "net/http" 12 | "time" 13 | ) 14 | 15 | var ( 16 | cfg = flag.String("config", "", "") 17 | ) 18 | 19 | func main() { 20 | flag.Parse() 21 | 22 | // init config 23 | if err := config.Init(*cfg); err != nil { 24 | panic(err) 25 | } 26 | gin.SetMode(viper.GetString("runmode")) 27 | g := gin.New() 28 | middlewares := []gin.HandlerFunc{} 29 | router.Load( 30 | g, 31 | middlewares..., 32 | ) 33 | 34 | go func() { 35 | if err := checkServer(); err != nil { 36 | log.Fatal("自检程序发生错误...", err) 37 | } 38 | log.Print("路由成功部署.") 39 | }() 40 | port := viper.GetString("addr") 41 | log.Printf("开始监听http地址%s", port) 42 | log.Printf(http.ListenAndServe(port, g).Error()) 43 | 44 | } 45 | 46 | func checkServer() error { 47 | max := viper.GetInt("max_check_count") 48 | for i := 0; i < max; i++ { 49 | //发送一个GET请求给 `/check/health`,验证服务器是否成功. 50 | url := viper.GetString("url") + "/check/health" 51 | resp, err := http.Get(url) 52 | if err == nil && resp.StatusCode == 200 { 53 | return nil 54 | } 55 | 56 | // Sleep 1 second 继续重试. 57 | log.Print("等待路由,1秒后重试。") 58 | time.Sleep(time.Second) 59 | } 60 | return errors.New("无法连接到路由.") 61 | } 62 | -------------------------------------------------------------------------------- /Chapter17/17-3/MyLog/MyLog.go: -------------------------------------------------------------------------------- 1 | package MyLog 2 | 3 | import ( 4 | "fmt" 5 | rotatelogs "github.com/lestrrat-go/file-rotatelogs" 6 | "go.uber.org/zap" 7 | "go.uber.org/zap/zapcore" 8 | "io" 9 | "os" 10 | "time" 11 | ) 12 | 13 | var Log *zap.SugaredLogger 14 | 15 | const ( 16 | output_dir = "./logs/" 17 | out_path = "app.MyLog" 18 | err_path = "app.myerr" 19 | ) 20 | 21 | func init() { 22 | _, err := os.Stat(output_dir) 23 | if err != nil { 24 | if os.IsNotExist(err) { 25 | err := os.Mkdir(output_dir, os.ModePerm) 26 | if err != nil { 27 | fmt.Printf("创建目录失败![%v]\n", err) 28 | } 29 | } 30 | } 31 | // 设置一些基本日志格式 32 | encoder := zapcore.NewConsoleEncoder(zapcore.EncoderConfig{ 33 | MessageKey: "msg", 34 | LevelKey: "level", 35 | TimeKey: "ts", 36 | CallerKey: "caller", 37 | StacktraceKey: "trace", 38 | LineEnding: zapcore.DefaultLineEnding, 39 | EncodeLevel: zapcore.LowercaseLevelEncoder, 40 | EncodeCaller: zapcore.ShortCallerEncoder, 41 | EncodeTime: func(t time.Time, enc zapcore.PrimitiveArrayEncoder) { 42 | enc.AppendString(t.Format("2006-01-02 15:04:05")) 43 | }, 44 | EncodeDuration: func(d time.Duration, enc zapcore.PrimitiveArrayEncoder) { 45 | enc.AppendInt64(int64(d) / 1000000) 46 | }, 47 | }) 48 | 49 | // 实现两个判断日志等级的interface 50 | infoLevel := zap.LevelEnablerFunc(func(lvl zapcore.Level) bool { 51 | return true 52 | }) 53 | 54 | warnLevel := zap.LevelEnablerFunc(func(lvl zapcore.Level) bool { 55 | return lvl >= zapcore.WarnLevel 56 | }) 57 | 58 | // 获取 info、warn日志文件的io.Writer 抽象 getWriter() 在下方实现 59 | infoHook_1 := os.Stdout 60 | infoHook_2 := getWriter(out_path) 61 | errorHook := getWriter(err_path) 62 | 63 | // 最后创建具体的Logger 64 | core := zapcore.NewTee( 65 | zapcore.NewCore(encoder, zapcore.AddSync(infoHook_1), infoLevel), 66 | zapcore.NewCore(encoder, zapcore.AddSync(infoHook_2), infoLevel), 67 | zapcore.NewCore(encoder, zapcore.AddSync(errorHook), warnLevel), 68 | ) 69 | 70 | // 需要传入 zap.AddCaller() 才会显示打日志点的文件名和行数 71 | logger := zap.New(core, zap.AddCaller(), zap.AddStacktrace(zap.ErrorLevel)) 72 | Log = logger.Sugar() 73 | defer logger.Sync() 74 | } 75 | func getWriter(filename string) io.Writer { 76 | // 生成rotatelogs的Logger 实际生成的文件名 app.MyLog.YYmmddHH 77 | // app.log是指向最新日志的链接 78 | // 保存7天内的日志,每1小时(整点)分割一次日志 79 | hook, err := rotatelogs.New( 80 | output_dir+filename+".%Y%m%d", 81 | rotatelogs.WithLinkName(filename), 82 | rotatelogs.WithMaxAge(time.Hour*24*7), 83 | rotatelogs.WithRotationTime(time.Hour*24), 84 | ) 85 | if err != nil { 86 | panic(err) 87 | } 88 | return hook 89 | } 90 | -------------------------------------------------------------------------------- /Chapter17/17-3/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "github.com/i-coder-robot/book_final_code/Chapter17/17-3/MyLog" 5 | ) 6 | 7 | func main() { 8 | MyLog.Log.Info("Info日志开始") 9 | MyLog.Log.Error(" Eroor错误日志") 10 | MyLog.Log.Info("Info日志结束") 11 | } 12 | -------------------------------------------------------------------------------- /Chapter17/Chapter17: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/i-coder-robot/book_final_code/00ec2d69dc7e2bc68aa78019cbceb9bdb87290fb/Chapter17/Chapter17 -------------------------------------------------------------------------------- /Chapter17/app.MyLog: -------------------------------------------------------------------------------- 1 | ./logs/app.MyLog.20210317 -------------------------------------------------------------------------------- /Chapter17/conf/app_config.yaml: -------------------------------------------------------------------------------- 1 | runmode: debug # 开发模式, debug, release, test 2 | addr: :9091 # HTTP绑定端口 3 | url: http://127.0.0.1:9091 # pingServer函数请求的API服务器的ip:port 4 | max_check_count: 10 # pingServer函数尝试的次数 5 | database: 6 | name: db 7 | addr: 127.0.0.1:3306 8 | username: root 9 | password: smartwell 10 | wx_app_id: 123 11 | wx_secret: 123 -------------------------------------------------------------------------------- /Chapter17/conf/db_conf.go: -------------------------------------------------------------------------------- 1 | package conf 2 | 3 | type DBConf struct { 4 | Driver string 5 | // Host 主机地址 6 | Host string 7 | // Port 主机端口 8 | Port string 9 | // User 用户名 10 | User string 11 | // Password 密码 12 | Password string 13 | // DbName 数据库名称 14 | DbName string 15 | // Charset 数据库编码 16 | Charset string 17 | } 18 | -------------------------------------------------------------------------------- /Chapter17/config/config.go: -------------------------------------------------------------------------------- 1 | package config 2 | 3 | import ( 4 | "github.com/fsnotify/fsnotify" 5 | "github.com/spf13/viper" 6 | "log" 7 | ) 8 | 9 | type Config struct { 10 | Name string 11 | } 12 | 13 | func Init(name string) error { 14 | c := Config { 15 | Name: name, 16 | } 17 | 18 | // 初始化配置文件 19 | if err := c.initConfig(); err != nil { 20 | return err 21 | } 22 | 23 | // 监控配置文件变化并热加载程序 24 | c.watchConfig() 25 | 26 | return nil 27 | } 28 | 29 | func (c *Config) initConfig() error { 30 | if c.Name != "" { 31 | viper.SetConfigFile(c.Name) // 如果指定了配置文件,则解析指定的配置文件 32 | } else { 33 | //viper.AddConfigPath("./Chapter16/conf/") //goland debug的配置 34 | viper.AddConfigPath("./conf/") //命令行的配置 35 | viper.SetConfigName("app_config") 36 | } 37 | viper.SetConfigType("yaml") // 设置配置文件格式为YAML 38 | if err := viper.ReadInConfig(); err != nil { // viper解析配置文件 39 | return err 40 | } 41 | 42 | return nil 43 | } 44 | 45 | // 监控配置文件变化并热加载程序 46 | func (c *Config) watchConfig() { 47 | viper.WatchConfig() 48 | viper.OnConfigChange(func(e fsnotify.Event) { 49 | log.Printf("Config file changed: %s", e.Name) 50 | }) 51 | } -------------------------------------------------------------------------------- /Chapter17/handler/account.go: -------------------------------------------------------------------------------- 1 | package handler 2 | 3 | import ( 4 | "github.com/gin-contrib/sessions" 5 | "github.com/gin-gonic/gin" 6 | "github.com/hashicorp/go-uuid" 7 | "github.com/i-coder-robot/book_final_code/Chapter16/MyLog" 8 | "github.com/i-coder-robot/book_final_code/Chapter16/model/my_token" 9 | "github.com/i-coder-robot/book_final_code/Chapter16/myerr" 10 | "github.com/i-coder-robot/book_final_code/Chapter16/res" 11 | "github.com/i-coder-robot/book_final_code/Chapter16/service/wx_service" 12 | "github.com/i-coder-robot/book_final_code/Chapter16/token" 13 | "github.com/i-coder-robot/book_final_code/Chapter16/utils" 14 | "github.com/i-coder-robot/book_final_code/Chapter17/handler/param" 15 | "github.com/i-coder-robot/book_final_code/Chapter17/model" 16 | "github.com/i-coder-robot/book_final_code/Chapter17/service" 17 | ) 18 | 19 | type AccountHandler struct { 20 | Srv *service.AccountService 21 | } 22 | 23 | // 新建一个account. 24 | func (h *AccountHandler) AccountCreate(c *gin.Context) { 25 | var r param.AccountRequest 26 | if err := c.Bind(&r); err != nil { 27 | res.SendResponse(c, myerr.ErrBind, nil) 28 | return 29 | } 30 | 31 | if err := utils.CheckParam(r.AccountName, r.Password); err.Err != nil { 32 | res.SendResponse(c, err.Err, nil) 33 | return 34 | } 35 | 36 | accountName := r.AccountName 37 | MyLog.Log.Infof("用户名: %s", accountName) 38 | 39 | desc := c.Query("desc") 40 | MyLog.Log.Infof("desc: %s", desc) 41 | 42 | contentType := c.GetHeader("Content-Type") 43 | MyLog.Log.Infof("Header Content-Type: %s", contentType) 44 | 45 | // 把明文密码加密 46 | md5Pwd, err := utils.Encrypt(r.Password) 47 | if err != nil { 48 | res.SendResponse(c, myerr.ErrEncrypt, nil) 49 | return 50 | } 51 | id, err := uuid.GenerateUUID() 52 | if err != nil { 53 | res.SendResponse(c, myerr.InternalServerError, nil) 54 | return 55 | } 56 | // 添加用户到数据库 57 | a := model.Account{ 58 | AccountId: id, 59 | AccountName: r.AccountName, 60 | Password: md5Pwd, 61 | } 62 | if err := h.Srv.CreateAccount(a); err != nil { 63 | res.SendResponse(c, myerr.ErrDatabase, nil) 64 | return 65 | } 66 | 67 | rsp := res.AccountResp{ 68 | AccountName: r.AccountName, 69 | } 70 | 71 | // 现实新建的 Acccount 信息. 72 | res.SendResponse(c, nil, rsp) 73 | } 74 | 75 | func (h *AccountHandler) ListAccount(c *gin.Context) { 76 | var r param.AccountListRequest 77 | if err := c.Bind(&r); err != nil { 78 | res.SendResponse(c, myerr.ErrBind, nil) 79 | return 80 | } 81 | if r.Offset < 0 { 82 | r.Offset = 0 83 | } 84 | if r.Limit < 1 { 85 | r.Limit = utils.Limit 86 | } 87 | 88 | list, count, err := h.Srv.ListAccount(r.Offset, r.Limit) 89 | if err != nil { 90 | res.SendResponse(c, err, nil) 91 | return 92 | } 93 | var resp []*res.AccountResp 94 | for _, item := range list { 95 | r := res.AccountResp{AccountName: item.AccountName} 96 | resp = append(resp, &r) 97 | } 98 | 99 | res.SendResponse(c, nil, res.ListResponse{ 100 | TotalCount: count, 101 | AccountList: resp, 102 | }) 103 | } 104 | 105 | func (h *AccountHandler) GetAccount(c *gin.Context) { 106 | accountName := c.Param("account_name") 107 | // 从数据库中选择Account. 108 | account, err := h.Srv.GetAccount(accountName) 109 | if err != nil { 110 | res.SendResponse(c, myerr.ErrAccountNotFound, nil) 111 | return 112 | } 113 | r := res.AccountResp{AccountName: account.AccountName} 114 | res.SendResponse(c, nil, r) 115 | } 116 | 117 | func (h *AccountHandler) Update(c *gin.Context) { 118 | 119 | // 绑定 account. 120 | var m model.Account 121 | if err := c.Bind(&m); err != nil { 122 | res.SendResponse(c, myerr.ErrBind, nil) 123 | return 124 | } 125 | 126 | // 密码加密处理. 127 | md5Pwd, err := utils.Encrypt(m.Password) 128 | if err != nil { 129 | res.SendResponse(c, myerr.ErrEncrypt, nil) 130 | return 131 | } 132 | m.Password = md5Pwd 133 | // 保存更新. 134 | if err := h.Srv.UpdateAccount(m); err != nil { 135 | res.SendResponse(c, myerr.ErrDatabase, nil) 136 | return 137 | } 138 | res.SendResponse(c, nil, nil) 139 | } 140 | 141 | func (h *AccountHandler) Delete(c *gin.Context) { 142 | accountId := c.Param("id") 143 | if err := h.Srv.DeleteAccount(accountId); err != nil { 144 | res.SendResponse(c, myerr.ErrDatabase, nil) 145 | return 146 | } 147 | res.SendResponse(c, nil, nil) 148 | } 149 | 150 | func (h *AccountHandler) Login(c *gin.Context) { 151 | var m model.Account 152 | if err := c.Bind(&m); err != nil { 153 | res.SendResponse(c, myerr.ErrBind, nil) 154 | return 155 | } 156 | account, err := h.Srv.Repo.GetAccountByName(m.AccountName) 157 | if err != nil { 158 | res.SendResponse(c, myerr.ErrAccountNotFound, nil) 159 | return 160 | } 161 | 162 | if err := utils.Compare(account.Password, m.Password); err != nil { 163 | res.SendResponse(c, myerr.ErrPassword, nil) 164 | return 165 | } 166 | 167 | sign, err := token.Sign(c, token.Context{ID: account.AccountId, Username: account.AccountName}, "") 168 | if err != nil { 169 | res.SendResponse(c, myerr.ErrToken, nil) 170 | return 171 | } 172 | 173 | res.SendResponse(c, nil, my_token.Token{Token: sign}) 174 | } 175 | 176 | // 微信小程序登录 177 | func (h *AccountHandler) WXLogin(c *gin.Context) { 178 | code := c.Query("code") // 获取code 179 | // 根据code获取 openID 和 session_key 180 | wxLoginResp, err := wx_service.WXLogin(code) 181 | if err != nil { 182 | res.SendResponse(c, nil, nil) 183 | return 184 | } 185 | // 保存登录态 186 | session := sessions.Default(c) 187 | session.Set("openid", wxLoginResp.OpenId) 188 | session.Set("sessionKey", wxLoginResp.SessionKey) 189 | 190 | // 这里可以用openid和sessionkey的串接,或者使用你自己的规则进行拼接,然后进行MD5之后作为该用户的自定义登录态, 要保证mySession唯一, 191 | mySession := utils.GetMD5Encode(wxLoginResp.OpenId + wxLoginResp.SessionKey) 192 | // 接下来可以将openid 和 sessionkey, mySession 存储到数据库或缓存中, 可以用mySession去索引openid 和sessionkey 193 | res.SendResponse(c, nil, mySession) 194 | } 195 | -------------------------------------------------------------------------------- /Chapter17/handler/handler.go: -------------------------------------------------------------------------------- 1 | package handler 2 | 3 | import ( 4 | "fmt" 5 | "github.com/i-coder-robot/book_final_code/Chapter17/conf" 6 | "github.com/i-coder-robot/book_final_code/Chapter17/config" 7 | "github.com/i-coder-robot/book_final_code/Chapter17/model" 8 | "github.com/i-coder-robot/book_final_code/Chapter17/repository" 9 | "github.com/i-coder-robot/book_final_code/Chapter17/service" 10 | "github.com/jinzhu/gorm" 11 | "github.com/spf13/viper" 12 | "log" 13 | ) 14 | 15 | var ( 16 | DB *gorm.DB 17 | AccountHandle AccountHandler 18 | ) 19 | 20 | func InitViper() { 21 | if err := config.Init(""); err != nil { 22 | panic(err) 23 | } 24 | } 25 | 26 | func InitDB() { 27 | fmt.Println("数据库 init") 28 | var err error 29 | conf := &conf.DBConf{ 30 | Host: viper.GetString("database.host"), 31 | User: viper.GetString("database.username"), 32 | Password: viper.GetString("database.password"), 33 | DbName: viper.GetString("database.name"), 34 | } 35 | 36 | config := fmt.Sprintf("%s:%s@tcp(%s)/%s?parseTime=true&charset=utf8&parseTime=%t&loc=%s", 37 | conf.User, 38 | conf.Password, 39 | conf.Host, 40 | conf.DbName, 41 | true, 42 | "Local") 43 | 44 | DB, err = gorm.Open("mysql", config) 45 | if err != nil { 46 | log.Fatalf("connect error: %v\n", err) 47 | } 48 | DB.SingularTable(true) 49 | fmt.Println("数据库 init 结束...") 50 | } 51 | 52 | func InitHandler() { 53 | AccountHandle = AccountHandler{ 54 | Srv: &service.AccountService{ 55 | Repo: &repository.AccountModelRepo{ 56 | DB: model.DataBase{MyDB: DB}, 57 | }, 58 | }} 59 | } 60 | -------------------------------------------------------------------------------- /Chapter17/handler/param/AccountParam.go: -------------------------------------------------------------------------------- 1 | package param 2 | 3 | type AccountRequest struct { 4 | AccountName string `json:"accountName"` 5 | Password string `json:"password"` 6 | } 7 | 8 | type AccountListRequest struct { 9 | AccountName string `json:"accountName"` 10 | Offset int `json:"offset"` 11 | Limit int `json:"limit"` 12 | } 13 | -------------------------------------------------------------------------------- /Chapter17/logs/app.MyLog.20210317: -------------------------------------------------------------------------------- 1 | 2021-03-17 15:46:22 info Chapter17/main.go:42 开始监听http地址:9091 2 | -------------------------------------------------------------------------------- /Chapter17/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "flag" 5 | "github.com/gin-gonic/gin" 6 | "github.com/i-coder-robot/book_final_code/Chapter16/MyLog" 7 | "github.com/i-coder-robot/book_final_code/Chapter16/config" 8 | "github.com/i-coder-robot/book_final_code/Chapter16/middleware" 9 | "github.com/i-coder-robot/book_final_code/Chapter17/handler" 10 | "github.com/i-coder-robot/book_final_code/Chapter17/model" 11 | "github.com/i-coder-robot/book_final_code/Chapter17/router" 12 | "github.com/spf13/viper" 13 | "log" 14 | "net/http" 15 | ) 16 | 17 | var ( 18 | cfg = flag.String("config", "", "") 19 | ) 20 | 21 | func init() { 22 | handler.InitViper() 23 | handler.InitDB() 24 | handler.InitHandler() 25 | } 26 | 27 | func main() { 28 | flag.Parse() 29 | 30 | if err := config.Init(*cfg); err != nil { 31 | panic(err) 32 | } 33 | model.DB.Init() 34 | defer model.DB.Close() 35 | r := gin.New() 36 | router.Load( 37 | r, 38 | middleware.ProcessTraceID(), 39 | middleware.Logging(), 40 | ) 41 | port := viper.GetString("addr") 42 | MyLog.Log.Info("开始监听http地址", port) 43 | log.Printf(http.ListenAndServe(port, r).Error()) 44 | } 45 | -------------------------------------------------------------------------------- /Chapter17/model/account.go: -------------------------------------------------------------------------------- 1 | package model 2 | 3 | import ( 4 | "sync" 5 | "time" 6 | ) 7 | 8 | type BaseModel struct { 9 | Id uint64 `gorm:"primary_key;AUTO_INCREMENT;column:id" json:"-"` 10 | CreatedAt time.Time `gorm:"column:createdAt" json:"-"` 11 | UpdatedAt time.Time `gorm:"column:updatedAt" json:"-"` 12 | DeletedAt *time.Time `gorm:"column:deletedAt" sql:"index" json:"-"` 13 | } 14 | 15 | type AccountInfo struct { 16 | AccountId string `json:"id"` 17 | AccountName string `json:"username"` 18 | Password string `json:"password"` 19 | CreatedAt string `json:"createdAt"` 20 | UpdatedAt string `json:"updatedAt"` 21 | } 22 | 23 | type List struct { 24 | Lock *sync.RWMutex 25 | IdMap map[uint64]*AccountInfo 26 | } 27 | 28 | // Token-令牌. 29 | type Token struct { 30 | Token string `json:"token"` 31 | } 32 | 33 | type Account struct { 34 | AccountId string `json:"accountId" gorm:"column:account_id;not null"` 35 | AccountName string `json:"accountName" gorm:"column:account_name;not null" binding:"required" validate:"min=1,max=32"` 36 | Password string `json:"password" gorm:"column:password;not null" binding:"required" validate:"min=5,max=128"` 37 | } 38 | -------------------------------------------------------------------------------- /Chapter17/model/mysql.go: -------------------------------------------------------------------------------- 1 | package model 2 | 3 | import ( 4 | "fmt" 5 | "github.com/i-coder-robot/book_final_code/Chapter16/MyLog" 6 | "github.com/jinzhu/gorm" 7 | // MySQL driver. 8 | _ "github.com/jinzhu/gorm/dialects/mysql" 9 | "github.com/spf13/viper" 10 | ) 11 | 12 | type DataBase struct { 13 | MyDB *gorm.DB 14 | } 15 | 16 | var DB *DataBase 17 | 18 | func (db *DataBase) Init() { 19 | DB = &DataBase{ 20 | MyDB: GetMySqlDB(), 21 | } 22 | } 23 | 24 | func (db *DataBase) Close() { 25 | DB.MyDB.Close() 26 | } 27 | 28 | func InitSelfDB() *gorm.DB { 29 | db := openDB(viper.GetString("database.username"), 30 | viper.GetString("database.password"), 31 | viper.GetString("database.addr"), 32 | viper.GetString("database.name")) 33 | return db 34 | } 35 | 36 | func GetMySqlDB() *gorm.DB { 37 | return InitSelfDB() 38 | } 39 | 40 | func openDB(username, password, addr, name string) *gorm.DB { 41 | config := fmt.Sprintf("%s:%s@tcp(%s)/%s?parseTime=true&charset=utf8&parseTime=%t&loc=%s", 42 | username, 43 | password, 44 | addr, 45 | name, 46 | true, 47 | "Local") 48 | 49 | db, err := gorm.Open("mysql", config) 50 | if err != nil { 51 | MyLog.Log.Errorf("Database connection failed. Database name: %s,Eroor:%s", name, err.Error()) 52 | } 53 | 54 | setupDB(db) 55 | db.SingularTable(true) 56 | return db 57 | } 58 | 59 | func setupDB(db *gorm.DB) { 60 | // 用于设置闲置的连接数. 61 | db.DB().SetMaxIdleConns(5) 62 | } 63 | -------------------------------------------------------------------------------- /Chapter17/repository/account.go: -------------------------------------------------------------------------------- 1 | package repository 2 | 3 | import ( 4 | "fmt" 5 | "github.com/i-coder-robot/book_final_code/Chapter16/utils" 6 | "github.com/i-coder-robot/book_final_code/Chapter17/model" 7 | ) 8 | 9 | type AccountModelRepo struct { 10 | DB model.DataBase 11 | } 12 | 13 | func (m AccountModelRepo) TableName() string { 14 | return "account" 15 | } 16 | 17 | // 新建一个 account. 18 | func (m *AccountModelRepo) CreateAccount(account model.Account) error { 19 | return m.DB.MyDB.Create(&account).Error 20 | } 21 | 22 | // 通过一个 Id. 删除 Account 23 | func (m *AccountModelRepo) DeleteAccount(id string) error { 24 | err := m.DB.MyDB.Where("account_id = ?", id).Delete(&model.Account{}).Error 25 | if err != nil { 26 | return err 27 | } 28 | return nil 29 | } 30 | 31 | // 更新 account. 32 | func (m *AccountModelRepo) UpdateAccount(account model.Account) error { 33 | err := m.DB.MyDB.Model(model.Account{}).Where("account_id=?", account.AccountId).Updates(map[string]interface{}{ 34 | "account_name": account.AccountName, 35 | "password": account.Password, 36 | }).Error 37 | return err 38 | } 39 | 40 | // 获取指定 Account. 41 | func (m *AccountModelRepo) GetAccountByName(name string) (model.Account, error) { 42 | var account model.Account 43 | err := m.DB.MyDB.Where("account_name = ?", name).First(&account).Error 44 | if err != nil { 45 | return account, err 46 | } 47 | return account, nil 48 | } 49 | 50 | // Account列表 51 | func (m *AccountModelRepo) ListAccount(offset, limit int) ([]*model.Account, uint64, error) { 52 | 53 | accounts := make([]*model.Account, 0) 54 | var count uint64 55 | 56 | if err := m.DB.MyDB.Model(&model.Account{}).Count(&count).Error; err != nil { 57 | return nil, 0, err 58 | } 59 | 60 | err := m.DB.MyDB.Model(&model.Account{}).Limit(limit).Offset(offset).Order("id desc").Find(&accounts).Error 61 | if err != nil { 62 | return nil, count, err 63 | } 64 | return accounts, count, nil 65 | } 66 | 67 | func (m *AccountModelRepo) ListAccountByName(account_name string, offset, limit int) ([]*model.Account, uint64, error) { 68 | if limit == 0 { 69 | limit = utils.Limit 70 | } 71 | 72 | accounts := make([]*model.Account, 0) 73 | var count uint64 74 | 75 | where := fmt.Sprintf("account_name like '%%%s%%'", account_name) 76 | if err := model.DB.MyDB.Model(&model.Account{}).Where(where).Count(&count).Error; err != nil { 77 | return nil, 0, err 78 | } 79 | 80 | if err := model.DB.MyDB.Where(where).Offset(offset).Limit(limit).Order("id desc").Find(&accounts).Error; err != nil { 81 | return accounts, count, err 82 | } 83 | return accounts, count, nil 84 | } 85 | 86 | func (m *AccountModelRepo) GetAccountInfo(accountId string) (model.Account, error) { 87 | var account model.Account 88 | if err := m.DB.MyDB.Where("account_id=?", accountId).First(&account).Error; err != nil { 89 | return account, err 90 | } 91 | return account, nil 92 | } 93 | -------------------------------------------------------------------------------- /Chapter17/router/router.go: -------------------------------------------------------------------------------- 1 | package router 2 | 3 | import ( 4 | "github.com/gin-gonic/gin" 5 | "github.com/i-coder-robot/book_final_code/Chapter17/handler" 6 | "net/http" 7 | ) 8 | 9 | func Load(engine *gin.Engine, middlewares ...gin.HandlerFunc) *gin.Engine { 10 | engine.Use(gin.Recovery()) 11 | engine.Use(middlewares...) 12 | engine.NoRoute(func(context *gin.Context) { 13 | context.String(http.StatusNotFound, "API路由不正确.") 14 | }) 15 | 16 | account := engine.Group("/v1/account") 17 | { 18 | 19 | account.GET("", handler.AccountHandle.ListAccount) // 获取用户列表 20 | account.GET("/:account_name", handler.AccountHandle.GetAccount) // 获取指定用户的详细信息 21 | account.POST("", handler.AccountHandle.AccountCreate) //新增用户 22 | account.DELETE("/:id", handler.AccountHandle.Delete) // 删除用户 23 | account.PUT("/", handler.AccountHandle.Update) // 更新用户 24 | account.POST("/login", handler.AccountHandle.Login) //登录 25 | account.POST("/wxlogin", handler.AccountHandle.WXLogin) 26 | 27 | } 28 | return engine 29 | } 30 | -------------------------------------------------------------------------------- /Chapter17/service/account.go: -------------------------------------------------------------------------------- 1 | package service 2 | 3 | import ( 4 | "errors" 5 | "github.com/i-coder-robot/book_final_code/Chapter17/model" 6 | "github.com/i-coder-robot/book_final_code/Chapter17/repository" 7 | ) 8 | 9 | type AccountService struct { 10 | Repo *repository.AccountModelRepo 11 | } 12 | 13 | func (ac *AccountService) ListAccountByName(username string, offset, limit int) ([]*model.AccountInfo, uint64, error) { 14 | infos := make([]*model.AccountInfo, 0) 15 | accounts, count, err := ac.Repo.ListAccount(offset, limit) 16 | if err != nil { 17 | return nil, count, err 18 | } 19 | 20 | for _, item := range accounts { 21 | info := &model.AccountInfo{ 22 | AccountId: item.AccountId, 23 | AccountName: item.AccountName, 24 | Password: item.Password, 25 | } 26 | infos = append(infos, info) 27 | } 28 | 29 | return infos, count, nil 30 | } 31 | 32 | func (ac *AccountService) ListAccount(offset, limit int) ([]*model.AccountInfo, uint64, error) { 33 | infos := make([]*model.AccountInfo, 0) 34 | accounts, count, err := ac.Repo.ListAccount(offset, limit) 35 | if err != nil { 36 | return nil, count, err 37 | } 38 | 39 | for _, item := range accounts { 40 | info := &model.AccountInfo{ 41 | AccountId: item.AccountId, 42 | AccountName: item.AccountName, 43 | Password: item.Password, 44 | } 45 | infos = append(infos, info) 46 | } 47 | 48 | return infos, count, nil 49 | } 50 | 51 | func (ac *AccountService) CreateAccount(account model.Account) error { 52 | return ac.Repo.CreateAccount(account) 53 | } 54 | 55 | func (ac *AccountService) DeleteAccount(id string) error { 56 | return ac.Repo.DeleteAccount(id) 57 | } 58 | 59 | func (ac *AccountService) UpdateAccount(account model.Account) error { 60 | accountInfo, err := ac.Repo.GetAccountInfo(account.AccountId) 61 | if err != nil { 62 | return err 63 | } 64 | if accountInfo.AccountId == "" { 65 | return errors.New("用户不存在") 66 | } 67 | return ac.Repo.UpdateAccount(account) 68 | } 69 | 70 | func (ac *AccountService) GetAccount(accountName string) (model.Account, error) { 71 | return ac.Repo.GetAccountByName(accountName) 72 | } 73 | -------------------------------------------------------------------------------- /Chapter2/2-1/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "fmt" 4 | 5 | func main() { 6 | fmt.Println("hello Go world") 7 | } 8 | -------------------------------------------------------------------------------- /Chapter2/2-2/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "fmt" 4 | 5 | func main() { 6 | message := "hello Go world" 7 | fmt.Println(message) 8 | 9 | message = "Hello Go world, Wonderfully" 10 | fmt.Println(message) 11 | } 12 | -------------------------------------------------------------------------------- /Chapter2/2-3-1/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "strings" 6 | ) 7 | 8 | func main() { 9 | name := "peter" 10 | fmt.Println(strings.ToUpper(name)) 11 | } 12 | -------------------------------------------------------------------------------- /Chapter2/2-3-2/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "bytes" 5 | "fmt" 6 | "strings" 7 | ) 8 | 9 | func main() { 10 | 11 | name := "peter" 12 | phone := "13000000000" 13 | user := name + " " + phone 14 | fmt.Println(user) 15 | 16 | user1 := strings.Join([]string{"hello", "world"}, " ") 17 | fmt.Println(user1) 18 | 19 | user2 := fmt.Sprintf("%s:%s", name, phone) 20 | fmt.Println(user2) 21 | 22 | user3 := bytes.Buffer{} 23 | user3.WriteString("hello") 24 | user3.WriteString(" world") 25 | fmt.Println(user3.String()) 26 | 27 | } 28 | -------------------------------------------------------------------------------- /Chapter2/2-3-3/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "fmt" 4 | 5 | func main() { 6 | message := "hello Go world" 7 | fmt.Println(message) 8 | fmt.Println("\t"+message) 9 | 10 | foods := "清蒸鱼\n红烧肉\n鱼香肉丝" 11 | fmt.Println(foods) 12 | 13 | foods2 := "您选择的菜品:\n\t清蒸鱼\n\t红烧肉\n\t鱼香肉丝" 14 | fmt.Println(foods2) 15 | 16 | 17 | } 18 | -------------------------------------------------------------------------------- /Chapter2/2-3-4/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "strings" 6 | ) 7 | 8 | func main() { 9 | foods3 := " 米饭,馒头,面条 " 10 | foods3 = strings.Trim(foods3, " ") 11 | fmt.Println(foods3) 12 | 13 | foods4 := "米饭,馒头,面条" 14 | result := strings.Trim(foods4, "米饭") 15 | fmt.Println(result) 16 | 17 | } 18 | -------------------------------------------------------------------------------- /Chapter2/2-4-1/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "fmt" 4 | 5 | func main() { 6 | fmt.Println(3 + 4) 7 | 8 | fmt.Println(10 - 3) 9 | 10 | fmt.Println(2 * 3) 11 | 12 | fmt.Println(9 / 3) 13 | 14 | fmt.Println(1 + 2*3) 15 | 16 | fmt.Println((1 + 2) * 3) 17 | } 18 | -------------------------------------------------------------------------------- /Chapter2/2-4-2/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "math" 6 | ) 7 | 8 | func main() { 9 | fmt.Println(math.MaxFloat32) 10 | fmt.Println(math.MaxFloat64) 11 | } 12 | -------------------------------------------------------------------------------- /Chapter2/2-4-3/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "strconv" 6 | ) 7 | 8 | func main() { 9 | age := 23 10 | fmt.Println("我的年龄是:" + strconv.Itoa(age)) 11 | 12 | } 13 | -------------------------------------------------------------------------------- /Chapter2/2-5/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "strings" 6 | ) 7 | 8 | func main() { 9 | // 提供的主食如下 10 | foods4:="米饭,馒头,面条" 11 | result:=strings.Trim(foods4,"米饭") 12 | fmt.Println(result) 13 | 14 | } 15 | -------------------------------------------------------------------------------- /Chapter3/3-2/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "fmt" 4 | 5 | func main() { 6 | var list [5]string 7 | fmt.Println(list) 8 | 9 | var list2 = [5]string{ 10 | "红烧肉", "清蒸鱼", "溜大虾", "蒸螃蟹", "蒜蓉粉丝扇贝", 11 | } 12 | fmt.Println(list2) 13 | 14 | list3 := [5]string{"红烧肉", "清蒸鱼", "溜大虾", "蒸螃蟹", "蒜蓉粉丝扇贝"} 15 | fmt.Println(list3) 16 | 17 | list4 := [...]string{"红烧肉", "清蒸鱼", "溜大虾", "蒸螃蟹", "蒜蓉粉丝扇贝"} 18 | fmt.Println(list4) 19 | 20 | var list5 = [3]string{"米饭", "馒头", "包子"} 21 | //list5=list4 22 | fmt.Println(list5) 23 | 24 | fmt.Println(list2 == list4) 25 | } 26 | -------------------------------------------------------------------------------- /Chapter3/3-3/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "fmt" 4 | 5 | func main() { 6 | var list2 = [5]string{ 7 | "红烧肉", "清蒸鱼", "溜大虾", "蒸螃蟹", "蒜蓉粉丝扇贝", 8 | } 9 | fmt.Println(list2[0]) 10 | } 11 | -------------------------------------------------------------------------------- /Chapter3/3-4/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "fmt" 4 | 5 | func main() { 6 | var list2 = [5]string{ 7 | "红烧肉", "清蒸鱼", "溜大虾", "蒸螃蟹", "蒜蓉粉丝扇贝", 8 | } 9 | fmt.Println(list2[2]) 10 | } 11 | -------------------------------------------------------------------------------- /Chapter3/3-5/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "fmt" 4 | 5 | func main() { 6 | var list = [5]string{ 7 | "红烧肉", "清蒸鱼", "溜大虾", "蒸螃蟹", "蒜蓉粉丝扇贝", 8 | } 9 | message := "我点一个菜" + list[1] 10 | fmt.Println(message) 11 | } 12 | -------------------------------------------------------------------------------- /Chapter3/3-6/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "fmt" 4 | 5 | func main() { 6 | var list = [5]string{ 7 | "红烧肉", "清蒸鱼", "溜大虾", "蒸螃蟹", "蒜蓉粉丝扇贝", 8 | } 9 | for idx, item := range list { 10 | desc := fmt.Sprintf("%d-%s", idx, item) 11 | fmt.Println(desc) 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /Chapter3/3-8/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "fmt" 4 | 5 | func main() { 6 | var list = [3]string{"米饭", "馒头", "包子"} 7 | list[0] = "饺子" 8 | fmt.Println(list) 9 | } 10 | -------------------------------------------------------------------------------- /Chapter3/3-9/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | func main() { 4 | //var list = [5]string{ 5 | // "红烧肉", "清蒸鱼", "溜大虾", "蒸螃蟹", "蒜蓉粉丝扇贝" 6 | //} 7 | //fmt.Println(list) 8 | //fmt.Println(list[5]) 9 | } 10 | -------------------------------------------------------------------------------- /Chapter4/4-1-1/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "fmt" 4 | 5 | func main() { 6 | var foods = [5]string{"红烧肉", "清蒸鱼", "溜大虾", "蒸螃蟹", "鲍鱼粥"} 7 | var foodsSlice []string = foods[0:3] 8 | fmt.Println(foodsSlice) 9 | fmt.Println(foods[1:4]) 10 | fmt.Println(foods[:2]) 11 | fmt.Println(foods[3:]) 12 | 13 | var foodsSlice2 = []string{"红烧肉", "清蒸鱼", "溜大虾", "蒸螃蟹", "鲍鱼粥"} 14 | 15 | foodsSlice5 := foodsSlice2[1:4] 16 | fmt.Println(len(foodsSlice5)) 17 | fmt.Println(cap(foodsSlice5)) 18 | foodSlice4 := []string{"红烧肉"} 19 | fmt.Println(foodSlice4) 20 | fmt.Println(fmt.Sprintf("Len:%d", len(foodSlice4))) 21 | fmt.Println(fmt.Sprintf("Cap:%d", cap(foodSlice4))) 22 | 23 | foodSlice4 = append(foodSlice4, "清蒸鱼") 24 | fmt.Println(fmt.Sprintf("Len:%d", len(foodSlice4))) 25 | fmt.Println(fmt.Sprintf("Cap:%d", cap(foodSlice4))) 26 | foodSlice4 = append(foodSlice4, "溜大虾") 27 | fmt.Println(fmt.Sprintf("Len:%d", len(foodSlice4))) 28 | fmt.Println(fmt.Sprintf("Cap:%d", cap(foodSlice4))) 29 | foodSlice4 = append(foodSlice4, "蒸螃蟹") 30 | fmt.Println(fmt.Sprintf("Len:%d", len(foodSlice4))) 31 | fmt.Println(fmt.Sprintf("Cap:%d", cap(foodSlice4))) 32 | foodSlice4 = append(foodSlice4, "鲍鱼粥") 33 | fmt.Println(fmt.Sprintf("Len:%d", len(foodSlice4))) 34 | fmt.Println(fmt.Sprintf("Cap:%d", cap(foodSlice4))) 35 | } 36 | -------------------------------------------------------------------------------- /Chapter4/4-1-2/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "fmt" 4 | 5 | func main() { 6 | foods := make([]string, 5, 8) 7 | foods[0] = "红烧肉" 8 | foods[1] = "清蒸鱼" 9 | foods[2] = "溜大虾" 10 | foods[3] = "蒸螃蟹" 11 | foods[4] = "鲍鱼粥" 12 | fmt.Println(foods[3]) 13 | 14 | last := foods[len(foods)-1] 15 | fmt.Println(last) 16 | } 17 | -------------------------------------------------------------------------------- /Chapter4/4-1-3/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "fmt" 4 | 5 | func main() { 6 | foods := make([]string, 6, 8) 7 | foods[0] = "红烧肉" 8 | foods[1] = "清蒸鱼" 9 | foods[2] = "溜大虾" 10 | foods[3] = "蒸螃蟹" 11 | foods[4] = "鲍鱼粥" 12 | for idx, item := range foods { 13 | fmt.Println(idx) 14 | fmt.Println(item) 15 | fmt.Println("-------") 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /Chapter4/4-1-4/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "fmt" 4 | 5 | func main() { 6 | var foods = []string{"红烧肉", "清蒸鱼", "溜大虾", "蒸螃蟹", "鲍鱼粥"} 7 | var other_foods = foods[:] 8 | fmt.Println(other_foods) 9 | 10 | var foodsSlice2 = []string{"红烧肉", "清蒸鱼", "溜大虾", "蒸螃蟹", "鲍鱼粥"} 11 | foodsSlice6 := []string{"米饭", "面条"} 12 | copy(foodsSlice6, foodsSlice2) 13 | fmt.Println(foodsSlice2) 14 | fmt.Println(foodsSlice6) 15 | 16 | var foodsSlice3 = []string{"红烧肉", "清蒸鱼", "溜大虾", "蒸螃蟹", "鲍鱼粥"} 17 | foodsSlice7 := []string{"米饭", "面条"} 18 | copy(foodsSlice3, foodsSlice7) 19 | fmt.Println(foodsSlice3) 20 | fmt.Println(foodsSlice7) 21 | } 22 | -------------------------------------------------------------------------------- /Chapter4/4-2-1/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "fmt" 4 | 5 | func main() { 6 | var foods = []string{"红烧肉", "清蒸鱼", "溜大虾", "蒸螃蟹", "鲍鱼粥"} 7 | fmt.Println(foods) 8 | foods[0] = "烤生蚝" 9 | fmt.Println(foods) 10 | } 11 | -------------------------------------------------------------------------------- /Chapter4/4-2-2/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "fmt" 4 | 5 | func main() { 6 | var foods = []string{"红烧肉", "清蒸鱼", "溜大虾", "蒸螃蟹", "鲍鱼粥"} 7 | fmt.Println(foods) 8 | foods = append(foods, "三文鱼") 9 | fmt.Println(foods) 10 | 11 | foods2 := []string{} 12 | foods2 = append(foods2, "红烧肉") 13 | foods2 = append(foods2, "清蒸鱼") 14 | foods2 = append(foods2, "溜大虾") 15 | foods2 = append(foods2, "蒸螃蟹") 16 | foods2 = append(foods2, "鲍鱼粥") 17 | fmt.Println(foods2) 18 | 19 | foods3 := []string{"红烧肉", "清蒸鱼", "溜大虾", "蒸螃蟹", "鲍鱼粥"} 20 | foods3 = append(foods3, make([]string, 5)...) 21 | fmt.Printf("长度:%d\n", len(foods3)) 22 | fmt.Printf("容量:%d\n", cap(foods3)) 23 | 24 | foods4 := []string{"红烧肉", "清蒸鱼", "溜大虾", "蒸螃蟹", "鲍鱼粥"} 25 | foods5 := append(foods4[:2], append([]string{"三文鱼"}, foods4[2:]...)...) 26 | fmt.Println(foods5) 27 | 28 | foods6 := []string{"红烧肉", "清蒸鱼", "溜大虾", "蒸螃蟹", "鲍鱼粥"} 29 | foods7 := append(foods6[:4], append(make([]string, 3), foods6[4:]...)...) 30 | fmt.Println(foods7) 31 | 32 | foods8 := []string{"米饭", "面条", "馒头"} 33 | var foods9 = []string{"红烧肉", "清蒸鱼", "溜大虾", "蒸螃蟹", "鲍鱼粥"} 34 | foods10 := append(foods9[:4], append(foods8, foods9[4:]...)...) 35 | fmt.Println(foods10) 36 | } 37 | -------------------------------------------------------------------------------- /Chapter4/4-2-3/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "fmt" 4 | 5 | func main() { 6 | var foods = []string{"红烧肉", "清蒸鱼", "溜大虾", "蒸螃蟹", "鲍鱼粥"} 7 | foods2 := append(foods[:3], foods[4:]...) 8 | fmt.Println(foods2) 9 | } 10 | -------------------------------------------------------------------------------- /Chapter4/4-3/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "fmt" 4 | 5 | func main() { 6 | foods := []string{"红烧肉", "清蒸鱼", "熘大虾", "蒸螃蟹", "蒜蓉粉丝扇贝"} 7 | //fmt.Println(foods[5]) 8 | fmt.Println(foods[len(foods)-1]) 9 | } 10 | -------------------------------------------------------------------------------- /Chapter4/4-4/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "fmt" 4 | 5 | func main() { 6 | //foods := []string{"红烧肉", "清蒸鱼", "溜大虾", "蒸螃蟹", "鲍鱼粥"} 7 | //foods2 := make([]*string, len(foods)) 8 | //for i, value := range foods { 9 | // foods2[i] = &value 10 | //} 11 | //fmt.Println(foods[0], foods[1], foods[2], foods[3], foods[4]) 12 | //fmt.Println(*foods2[0], *foods2[1], *foods2[2], *foods2[3], *foods2[4]) 13 | 14 | //解决上面代码的错误,可以参照书中的例子 15 | foods := []string{"红烧肉", "清蒸鱼", "溜大虾", "蒸螃蟹", "鲍鱼粥"} 16 | foods2 := make([]*string, len(foods)) 17 | for i, _ := range foods { 18 | foods2[i] = &foods[i] 19 | } 20 | fmt.Println(foods[0], foods[1], foods[2], foods[3], foods[4]) 21 | fmt.Println(*foods2[0], *foods2[1], *foods2[2], *foods2[3], *foods2[4]) 22 | } 23 | -------------------------------------------------------------------------------- /Chapter5/5-1/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "fmt" 4 | 5 | func main() { 6 | foods := []string{"红烧肉", "清蒸鱼", "溜大虾", "蒸螃蟹", "鲍鱼粥"} 7 | 8 | for _, item := range foods { 9 | if item == "鲍鱼粥" { 10 | fmt.Println("鲍鱼粥,今日免费赠送") 11 | } else { 12 | fmt.Println(item) 13 | } 14 | } 15 | } -------------------------------------------------------------------------------- /Chapter5/5-2-1/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "fmt" 4 | 5 | func main() { 6 | name := "麻辣小龙虾" 7 | if name == "麻辣小龙虾" { 8 | fmt.Println("晚上吃麻辣小龙虾") 9 | } 10 | 11 | cause := "正常下班" 12 | if cause != "加班" { 13 | fmt.Println("晚上吃大餐去") 14 | } 15 | 16 | } 17 | -------------------------------------------------------------------------------- /Chapter5/5-2-2/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "fmt" 4 | 5 | func main() { 6 | price := 1288 7 | if price==1288{ 8 | fmt.Println("赠送优惠卡一张") 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /Chapter5/5-2-3/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "fmt" 4 | 5 | func main() { 6 | foods :=[]string{"红烧肉", "清蒸鱼", "溜大虾", "蒸螃蟹", "蒜蓉粉丝扇贝"} 7 | price := 1288 8 | if price==1288 && len(foods)>3{ 9 | fmt.Println("赠送优惠卡三张") 10 | } 11 | 12 | 13 | if price==1288 || len(foods)<3{ 14 | fmt.Println("赠送优惠卡一张") 15 | } 16 | 17 | 18 | } 19 | -------------------------------------------------------------------------------- /Chapter5/5-2-4/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "fmt" 4 | 5 | func main() { 6 | foods := []string{"红烧肉", "清蒸鱼", "溜大虾", "蒸螃蟹", "蒜蓉粉丝扇贝", "鲍鱼粥"} 7 | for _, item := range foods { 8 | if item == "鲍鱼粥" { 9 | fmt.Println("鲍鱼粥,今日免费赠送") 10 | } else { 11 | fmt.Println(item) 12 | } 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /Chapter5/5-3/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "fmt" 4 | 5 | func main() { 6 | i := 3 7 | switch i { 8 | case 0: 9 | fmt.Printf("红烧肉") 10 | case 1: 11 | fmt.Printf("清蒸鱼") 12 | case 2: 13 | fmt.Printf("溜大虾") 14 | case 3: 15 | fmt.Printf("蒸螃蟹") 16 | case 4: 17 | fmt.Printf("鲍鱼粥") 18 | default: 19 | fmt.Printf("再等等") 20 | } 21 | 22 | // 编译不通过 23 | //prices := [...]int16{32, 68, 96, 153, 198, 77, 100} 24 | //switch 32 + 68 { 25 | //case prices[0], prices[1]: 26 | // fmt.Println("0 or 1") 27 | //case prices[2], prices[3]: 28 | // fmt.Println("2 or 3") 29 | //case prices[4], prices[5], prices[6]: 30 | // fmt.Println("4 or 5 or 6") 31 | //} 32 | 33 | prices := [...]int16{32, 68, 96, 153, 198, 77, 100} 34 | switch prices[1] { 35 | case 32, 68: 36 | fmt.Println("0 or 1") 37 | case 96, 153: 38 | fmt.Println("2 or 3") 39 | case 198, 77, 100: 40 | fmt.Println("4 or 5 or 6") 41 | } 42 | // 编译不通过 43 | //prices := [...]int16{32, 68, 96, 153, 198, 77, 100} 44 | //switch prices[1] { 45 | //case 32, 68,96: 46 | // fmt.Println("0 or 1 or 2") 47 | //case 96, 153: 48 | // fmt.Println("2 or 3") 49 | //case 198, 77, 100: 50 | // fmt.Println("4 or 5 or 6") 51 | //} 52 | 53 | prices = [...]int16{32, 68, 96, 153, 198, 77, 100} 54 | switch prices[1] { 55 | case prices[0], prices[1], prices[2]: 56 | fmt.Println("0 or 1 or 2") 57 | case prices[2], prices[3]: 58 | fmt.Println("2 or 3") 59 | case prices[4], prices[5], prices[6]: 60 | fmt.Println("4 or 5 or 6") 61 | } 62 | 63 | } 64 | -------------------------------------------------------------------------------- /Chapter5/5-4/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "fmt" 4 | 5 | func main() { 6 | total := 0 7 | 8 | for i := 0; i < 10; i++ { 9 | total += i 10 | } 11 | 12 | total2 := 0 13 | 14 | for { 15 | total2++ 16 | if total2 > 100 { 17 | break 18 | } 19 | } 20 | 21 | total3 := 0 22 | Out: 23 | for { 24 | total3++ 25 | if total3 > 10 { 26 | break Out 27 | } 28 | } 29 | 30 | foods := []string{"红烧肉", "清蒸鱼", "溜大虾", "蒸螃蟹", "鲍鱼粥"} 31 | for i := range foods { 32 | fmt.Println(i) 33 | } 34 | 35 | //foods2 := []string{"红烧肉", "清蒸鱼", "溜大虾", "蒸螃蟹", "鲍鱼粥"} 36 | foods2 := []string{"红烧肉", "清蒸鱼", "溜大虾", "蒸螃蟹", "鲍鱼粥"} 37 | for i, item := range foods2 { 38 | if i == len(foods2) { 39 | item = "蒜蓉粉丝扇贝" 40 | } 41 | result := fmt.Sprintf("%d--%q", i, item) 42 | fmt.Println(result) 43 | } 44 | 45 | fmt.Println(foods2) 46 | 47 | } 48 | -------------------------------------------------------------------------------- /Chapter6/6-1/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "fmt" 4 | 5 | func main() { 6 | var m map[string]int = map[string]int{"红烧肉": 88, "清蒸鱼": 98, "溜大虾": 128, "蒸螃蟹": 198, "鲍鱼粥": 68} 7 | price, ok := m["鲍鱼粥"] 8 | if !ok { 9 | fmt.Println("没有对应的键值对") 10 | } else { 11 | fmt.Println(price) 12 | } 13 | 14 | //var errorMap = map[interface{}]int{ 15 | // "红烧肉": 88, 16 | // []string{"清蒸鱼"}: 98, // 这里会引发panic 17 | // "溜大虾": 128, 18 | //} 19 | //fmt.Println(errorMap) 20 | } 21 | -------------------------------------------------------------------------------- /Chapter6/6-2/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "fmt" 4 | 5 | func main() { 6 | var m map[string]int = map[string]int{"红烧肉":88,"清蒸鱼":98, "溜大虾":128, "蒸螃蟹":198, "鲍鱼粥":68} 7 | fmt.Println(m) 8 | 9 | foodsMap := make(map[string]int) 10 | foodsMap["红烧肉"] = 88 11 | foodsMap["清蒸鱼"] = 98 12 | foodsMap["溜大虾"] = 128 13 | foodsMap["蒸螃蟹"] = 198 14 | foodsMap["鲍鱼粥"] = 68 15 | fmt.Println(foodsMap) 16 | } 17 | -------------------------------------------------------------------------------- /Chapter6/6-3-1/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "fmt" 4 | 5 | func main() { 6 | var m map[string]int = map[string]int{"红烧肉": 88, "清蒸鱼": 98, "溜大虾": 128, "蒸螃蟹": 198, "鲍鱼粥": 68} 7 | fmt.Println(m["红烧肉"]) 8 | 9 | i,ok := m["麻辣小龙虾"] 10 | if !ok { 11 | fmt.Println("没有对应的键元素对") 12 | } else{ 13 | fmt.Println(i) 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /Chapter6/6-3-2/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "fmt" 4 | 5 | func main() { 6 | var m map[string]int = map[string]int{"红烧肉": 88, "清蒸鱼": 98, "溜大虾": 128, "蒸螃蟹": 198, "鲍鱼粥": 68} 7 | fmt.Println(m) 8 | m["麻婆豆腐"] = 48 9 | m["水煮鱼"] = 99 10 | fmt.Println(m) 11 | 12 | } 13 | -------------------------------------------------------------------------------- /Chapter6/6-3-3/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "fmt" 4 | 5 | func main() { 6 | var m map[string]int = map[string]int{"红烧肉":88,"清蒸鱼":98, "溜大虾":128, "蒸螃蟹":198, "鲍鱼粥":68} 7 | m["蒸螃蟹"]=398 8 | fmt.Println(m) 9 | } 10 | -------------------------------------------------------------------------------- /Chapter6/6-3-4/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "fmt" 4 | 5 | func main() { 6 | var m map[string]int = map[string]int{"红烧肉": 88, "清蒸鱼": 98, "溜大虾": 128, "蒸螃蟹": 198, "鲍鱼粥": 68} 7 | delete(m, "红烧肉") 8 | fmt.Println(m) 9 | } 10 | -------------------------------------------------------------------------------- /Chapter6/6-4-1/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "fmt" 4 | 5 | func main() { 6 | var m2 map[string][]string = map[string][]string{ 7 | "火锅店":{"牛肉","羊肉","蔬菜拼盘"}, 8 | "披萨店":{"超级至尊披萨","鸡翅","奶油蘑菇汤","香草凤尾虾"}, 9 | } 10 | 11 | fmt.Println(m2) 12 | 13 | for k,v :=range m2{ 14 | fmt.Println(k) 15 | fmt.Println(v) 16 | fmt.Println("=======") 17 | } 18 | 19 | } 20 | -------------------------------------------------------------------------------- /Chapter6/6-4-2/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "fmt" 4 | 5 | func main() { 6 | var shops map[string]map[string]int = map[string]map[string]int { 7 | "火锅店":map[string]int{"牛肉":168,"羊肉":168,"蔬菜拼盘":98}, 8 | "披萨店":map[string]int{"超级至尊披萨":138,"鸡翅":48,"奶油蘑菇汤":68,"香草凤尾虾":78}, 9 | } 10 | fmt.Println(shops) 11 | } 12 | -------------------------------------------------------------------------------- /Chapter6/6-4/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "fmt" 4 | 5 | func main() { 6 | var m map[string]int = map[string]int{"红烧肉": 88, "清蒸鱼": 98, "溜大虾": 128, "蒸螃蟹": 198, "鲍鱼粥": 68} 7 | 8 | for k,v :=range m{ 9 | fmt.Printf("菜品:%s,价钱:%d\n",k,v) 10 | } 11 | 12 | } 13 | -------------------------------------------------------------------------------- /Chapter6/6-5/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "fmt" 4 | 5 | func main() { 6 | var m map[string]int = map[string]int{"红烧肉": 88, "清蒸鱼": 98, "溜大虾": 128, "蒸螃蟹": 198, "鲍鱼粥": 68} 7 | var prices []*int 8 | //有问题的 9 | //for k, v := range m { 10 | // fmt.Printf("k:[%p].v:[%p]\n", &k, &v) 11 | // prices = append(prices, &v) 12 | //} 13 | //for _, price := range prices { 14 | // fmt.Println(*price) 15 | //} 16 | 17 | //正确的 18 | for k, v := range m { 19 | fmt.Printf("k:[%p].v:[%p]\n", &k, &v) 20 | vv := m[k] 21 | prices = append(prices, &vv) 22 | } 23 | for _, price := range prices { 24 | fmt.Println(*price) 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /Chapter7/7-1-1/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "fmt" 4 | 5 | func Fav(userName string) { 6 | fmt.Println(userName + " 喜欢吃生蚝") 7 | } 8 | 9 | func main() { 10 | Fav("小明") 11 | } 12 | -------------------------------------------------------------------------------- /Chapter7/7-1-3/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "fmt" 4 | 5 | func Desc(foodType string, foodName string) { 6 | fmt.Println("这是" + foodType + "的" + foodName) 7 | } 8 | 9 | func main() { 10 | Desc("卤菜", "葱烧海参") 11 | Desc("川菜","麻婆豆腐") 12 | } 13 | -------------------------------------------------------------------------------- /Chapter7/7-1-4/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "fmt" 4 | 5 | func ShowFoods(foods [3]string) { 6 | //修改第一个元素 7 | foods[0] = "蛋炒饭" 8 | fmt.Println(foods) 9 | } 10 | 11 | func ShowFoods2(foods *[3]string) { 12 | foods[0] = "蛋炒饭" 13 | fmt.Println(foods) 14 | } 15 | 16 | func main() { 17 | todayFoods := [3]string{"卤肉饭", "西红柿鸡蛋饭", "肥牛饭"} 18 | ShowFoods(todayFoods) 19 | fmt.Println(todayFoods) 20 | 21 | todayFoods2 := &[3]string{"卤肉饭", "西红柿鸡蛋饭", "肥牛饭"} 22 | ShowFoods2(todayFoods2) 23 | fmt.Println(todayFoods2) 24 | 25 | } 26 | -------------------------------------------------------------------------------- /Chapter7/7-1-5/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "fmt" 4 | 5 | func ShowFoods3(foods []string) { 6 | foods[0] = "蛋炒饭" 7 | fmt.Println(foods) 8 | } 9 | 10 | func main() { 11 | todayFoods3 := []string{"卤肉饭", "西红柿鸡蛋饭", "肥牛饭"} 12 | ShowFoods3(todayFoods3) 13 | fmt.Println(todayFoods3) 14 | 15 | } 16 | -------------------------------------------------------------------------------- /Chapter7/7-1-6/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "fmt" 4 | 5 | func Desc(foodType string, foodName string) { 6 | fmt.Println("这是" + foodType) 7 | fmt.Println("这是" + foodType + "的" + foodName) 8 | } 9 | 10 | func main() { 11 | //Desc() 12 | } 13 | -------------------------------------------------------------------------------- /Chapter7/7-1/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "fmt" 4 | 5 | //方法注释 6 | func Fav() { 7 | fmt.Println("我喜欢吃生蚝") 8 | } 9 | 10 | func add(x, y int) (result int) { 11 | result = x + y 12 | return 13 | } 14 | 15 | func main() { 16 | 17 | Fav() 18 | } 19 | -------------------------------------------------------------------------------- /Chapter7/7-10/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | ) 6 | 7 | func start() { 8 | fmt.Println("程序开始执行...") 9 | } 10 | 11 | func testFood() { 12 | foods := []string{"红烧肉", "清蒸鱼", "熘大虾", "蒸螃蟹", "鲍鱼粥"} 13 | defer func() { 14 | if err := recover(); err != nil { 15 | fmt.Println(err) 16 | } 17 | fmt.Println("defer finished") 18 | }() 19 | fmt.Println(foods[5]) 20 | } 21 | 22 | func end() { 23 | fmt.Println("程序执行结束...") 24 | } 25 | 26 | func main() { 27 | start() 28 | testFood() 29 | end() 30 | } 31 | -------------------------------------------------------------------------------- /Chapter7/7-2-1/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "fmt" 4 | 5 | func Desc(foodType string,foodName string) string{ 6 | return "这是" +foodType+"的"+foodName 7 | } 8 | 9 | func main() { 10 | result := Desc("粤菜","盐焗鸡") 11 | fmt.Println(result) 12 | } 13 | -------------------------------------------------------------------------------- /Chapter7/7-2-2/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "fmt" 4 | 5 | func Menu(name string,price int) map[string]int{ 6 | m:=make(map[string]int) 7 | m[name]=price 8 | return m 9 | } 10 | 11 | func main() { 12 | m:=Menu("红烧肉",88) 13 | fmt.Println(m) 14 | } 15 | -------------------------------------------------------------------------------- /Chapter7/7-3/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "fmt" 4 | 5 | func Greet(name string) string { 6 | fmt.Println("Hello," + name) 7 | return "你也好" 8 | } 9 | 10 | func main() { 11 | 12 | var m map[string]int = map[string]int{"红烧肉": 88, "清蒸鱼": 98, "熘大虾": 128, "蒸螃蟹": 198, "蒜蓉粉丝扇贝": 68} 13 | v, ok := m["麻辣小龙虾"] 14 | if !ok { 15 | fmt.Println("没有对应的键值对") 16 | } else { 17 | fmt.Println(v) 18 | } 19 | 20 | result := Greet("小明") 21 | fmt.Println(result) 22 | } 23 | -------------------------------------------------------------------------------- /Chapter7/7-4/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "fmt" 4 | 5 | type Hi func(num string) string 6 | 7 | func Hello(num string) string { 8 | return num + "位客人,欢迎光临" 9 | } 10 | 11 | func Hello4DongBei(num string) string { 12 | return num + "位兄弟,欢迎光临" 13 | } 14 | 15 | func SayHello(num string, hi Hi) { 16 | result := hi(num) 17 | fmt.Println(result) 18 | } 19 | 20 | func main() { 21 | var hello Hi 22 | hello = Hello 23 | words := hello("3") 24 | fmt.Printf("%s\n", words) 25 | 26 | hello = Hello4DongBei 27 | words = hello("5") 28 | fmt.Printf("%s\n", words) 29 | 30 | target := "东北食客" 31 | if target == "东北食客" { 32 | SayHello("3", Hello4DongBei) 33 | } else { 34 | SayHello("6", Hello) 35 | } 36 | 37 | } 38 | -------------------------------------------------------------------------------- /Chapter7/7-5/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | ) 6 | 7 | type Hi func(num string) string 8 | 9 | func SayHello(num string, hi Hi) { 10 | result := hi(num) 11 | fmt.Println(result) 12 | } 13 | 14 | func main() { 15 | target := "东北食客" 16 | 17 | if target == "东北食客" { 18 | SayHello("3", func(num string) string { 19 | return num + "位兄弟,欢迎光临" 20 | }) 21 | } else { 22 | SayHello("3", func(num string) string { 23 | return num + "位客人,欢迎光临" 24 | }) 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /Chapter7/7-6/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "strconv" 6 | ) 7 | 8 | type Discount func() float64 9 | type CheckSum func(name string, price float64) float64 10 | 11 | func PayOrder(discount Discount) CheckSum { 12 | var total float64 13 | return func(name string, price float64) float64 { 14 | fmt.Println("菜品名称:" + name + "单价:" + strconv.FormatFloat(price, 'f', -1, 64)) 15 | total = total + price 16 | if discount == nil { 17 | return total 18 | } 19 | return total * discount() 20 | } 21 | } 22 | 23 | func main() { 24 | f := PayOrder(func() float64 { 25 | return 0.8 26 | }) 27 | result := f("红烧肉", 88) 28 | fmt.Println(result) 29 | result = f("清蒸鱼", 98) 30 | fmt.Println(result) 31 | result = f("溜大虾", 128) 32 | fmt.Println(result) 33 | result = f("蒸螃蟹", 198) 34 | fmt.Println(result) 35 | result = f("蒜蓉粉丝扇贝", 68) 36 | fmt.Println(result) 37 | 38 | } 39 | -------------------------------------------------------------------------------- /Chapter7/7-7/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "fmt" 4 | 5 | func Total(prices ...int) int { 6 | result := 0 7 | for _, val := range prices { 8 | result += val 9 | } 10 | return result 11 | } 12 | 13 | func Total3(prices ...int) int { 14 | fmt.Printf("%T\n", Total) 15 | return 0 16 | } 17 | 18 | func Total2(prices []int) int { 19 | fmt.Printf("%T\n", Total2) 20 | return 0 21 | } 22 | 23 | func main() { 24 | fmt.Println(Total(88, 98, 128, 198, 68)) 25 | Total3(11, 22) 26 | Total2([]int{11}) 27 | 28 | } 29 | -------------------------------------------------------------------------------- /Chapter7/7-8/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "sync" 4 | 5 | var mu sync.Mutex 6 | var m map[string]int 7 | 8 | func lookup(key string) int { 9 | mu.Lock() 10 | defer mu.Unlock() 11 | return m[key] 12 | } 13 | 14 | func main() { 15 | m := make(map[string]int) 16 | m["abc"] = 123 17 | m["m"] = 3 18 | m["g"] = 80 19 | lookup("g") 20 | } 21 | -------------------------------------------------------------------------------- /Chapter7/7-9/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "fmt" 4 | 5 | func main() { 6 | 7 | foods := []string{"红烧肉", "清蒸鱼", "熘大虾", "蒸螃蟹", "鲍鱼粥"} 8 | 9 | fmt.Printf("%s", foods[5]) 10 | } 11 | -------------------------------------------------------------------------------- /Chapter8/8-1/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "time" 4 | 5 | type Chef struct { 6 | Name string //名称 7 | Age int //年龄 8 | Honor //荣誉 9 | Trainee *Chef //徒弟,这里为了演示,可以认为徒弟有多个,用切片表示 10 | } 11 | 12 | type Honor struct { 13 | Title string //获奖名称 14 | GetTime time.Time //获奖时间 15 | } 16 | 17 | func main() { 18 | 19 | } 20 | -------------------------------------------------------------------------------- /Chapter8/8-2/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "time" 6 | ) 7 | 8 | type Chef struct { 9 | Name string //名称 10 | Age int //年龄 11 | Honor //荣誉 12 | Trainee *Chef //徒弟,这里为了演示,可以认为徒弟有多个,用切片表示 13 | } 14 | 15 | type Honor struct { 16 | Title string //获奖名称 17 | GetTime time.Time //获奖时间 18 | } 19 | 20 | func main() { 21 | wang := Chef{"王师傅", 25, Honor{}, nil} 22 | fmt.Printf("%s", wang.Name) 23 | fmt.Println((&wang).Name) 24 | 25 | li := Chef{ 26 | Name: "李师傅", 27 | Age: 25, 28 | Honor: Honor{}, 29 | Trainee: nil, 30 | } 31 | fmt.Println(li.Name) 32 | 33 | li2 := new(Chef) 34 | *li2 = Chef{ 35 | Name: "李师傅", 36 | Age: 25, 37 | Honor: Honor{}, Trainee: nil, 38 | } 39 | fmt.Println(li2.Name) 40 | } 41 | -------------------------------------------------------------------------------- /Chapter8/8-3/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "time" 6 | ) 7 | 8 | type Chef struct { 9 | Name string //名称 10 | Age int //年龄 11 | *Honor //荣誉 12 | Trainee *Chef //徒弟,这里为了演示,可以认为徒弟有多个,用切片表示 13 | } 14 | 15 | type Honor struct { 16 | Title string //获奖名称 17 | GetTime time.Time //获奖时间 18 | } 19 | 20 | func ShowName(names []string) { 21 | for _, name := range names { 22 | fmt.Println("这是:" + name) 23 | } 24 | } 25 | 26 | func main() { 27 | chef := struct { 28 | Name string 29 | Age int 30 | }{ 31 | Name: "老王", 32 | Age: 30, 33 | } 34 | fmt.Println(chef) 35 | 36 | list := []string{ 37 | "红烧肉", "清蒸鱼", "熘大虾", "蒸螃蟹", "蒜蓉粉丝扇贝", 38 | } 39 | ShowName(list) 40 | 41 | } 42 | -------------------------------------------------------------------------------- /Chapter8/8-4/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "encoding/json" 5 | "fmt" 6 | ) 7 | 8 | type Chef struct { 9 | Name string 10 | Age int 11 | } 12 | 13 | func main() { 14 | 15 | c := Chef{ 16 | Name: "老王", 17 | Age: 28, 18 | } 19 | 20 | marshal, err := json.Marshal(&c) 21 | if err != nil { 22 | fmt.Println(err) 23 | } 24 | fmt.Println(string(marshal)) 25 | 26 | var cc Chef 27 | s := `{"Name":"小李","Age":24}` 28 | err = json.Unmarshal([]byte(s), &cc) 29 | if err != nil { 30 | fmt.Println(err) 31 | } 32 | fmt.Println(cc.Name) 33 | fmt.Println(cc.Age) 34 | } 35 | -------------------------------------------------------------------------------- /Chapter8/8-5/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "time" 6 | ) 7 | 8 | type Chef struct { 9 | Name string 10 | Age int 11 | Honor 12 | Trainee *Chef 13 | } 14 | 15 | type Honor struct { 16 | Title string //获奖名称 17 | GetTime time.Time //获奖时间 18 | } 19 | 20 | func (c *Chef) Cook(name string) string { 21 | return c.Name + ":做好了 " + name 22 | } 23 | func (c *Chef) FavCook(name string) string { 24 | return c.Name + ":这是我的拿手菜" + name + ",做好了。" 25 | } 26 | 27 | func main() { 28 | li := &Chef{ 29 | Name: "李师傅", 30 | Age: 25, 31 | Honor: Honor{}, 32 | Trainee: nil, 33 | } 34 | result := li.Cook("红烧肉") 35 | fmt.Println(result) 36 | result = li.FavCook("葱烧海参") 37 | fmt.Println(result) 38 | 39 | } 40 | -------------------------------------------------------------------------------- /Chapter8/8-6/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "time" 6 | ) 7 | 8 | type Honor struct { 9 | Title string //获奖名称 10 | GetTime time.Time //获奖时间 11 | } 12 | type Chef struct { 13 | Name string //名称 14 | Age int //年龄 15 | Honor //荣誉 16 | Trainee *Chef //徒弟,这里为了演示,可以认为徒弟有多个,用切片表示 17 | } 18 | 19 | func (c *Chef) Cook(name string) string { 20 | return c.Name + ":做好了 " + name + "\n" 21 | } 22 | func (c *Chef) FavCook(name string) string { 23 | return c.Name + ":这是我的拿手菜" + name + ",做好了。\n" 24 | } 25 | 26 | func main() { 27 | li := &Chef{ 28 | Name: "李师傅", 29 | Age: 25, 30 | Honor: Honor{}, 31 | Trainee: nil, 32 | } 33 | result := li.Cook("红烧肉") 34 | fmt.Printf("%s", result) 35 | result = li.FavCook("葱烧海参") 36 | fmt.Printf("%s", result) 37 | 38 | li2 := Chef{ 39 | Name: "李师傅", 40 | Age: 25, 41 | Honor: Honor{}, 42 | Trainee: nil, 43 | } 44 | liPoint := &li2 45 | result2 := liPoint.Cook("红烧肉") 46 | fmt.Printf("%s", result2) 47 | result2 = liPoint.FavCook("葱烧海参") 48 | fmt.Printf("%s", result2) 49 | 50 | li3 := Chef{ 51 | Name: "李师傅", 52 | Age: 25, 53 | Honor: Honor{}, 54 | Trainee: nil, 55 | } 56 | 57 | result3 := (&li3).Cook("红烧肉") 58 | fmt.Printf("%s", result3) 59 | result3 = (&li3).FavCook("葱烧海参") 60 | fmt.Printf("%s", result3) 61 | } 62 | -------------------------------------------------------------------------------- /Chapter8/8-7/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "time" 6 | ) 7 | 8 | type Chef2 struct { 9 | Name string 10 | Age int 11 | Honor2 12 | Trainee *Chef2 13 | } 14 | 15 | type Honor2 struct { 16 | Title string //获奖名称 17 | GetTime time.Time //获奖时间 18 | } 19 | 20 | func (c *Chef2) Cook(name string) string { 21 | return c.Name + ":做好了 " + name + "\n" 22 | } 23 | 24 | func (c *Chef2) FavCook(name string) string { 25 | return c.Name + ":这是我的拿手菜" + name + ",做好了。\n" 26 | } 27 | 28 | func (c *Chef3) GetName() string { 29 | return c.Name 30 | } 31 | 32 | type Honor3 struct { 33 | Title string //获奖名称 34 | GetTime time.Time //获奖时间 35 | } 36 | 37 | type Chef3 struct { 38 | Name string 39 | Age int 40 | Honor3 41 | Trainee *Chef3 42 | } 43 | 44 | func (c *Chef3) Cook(name string) string { 45 | return c.Name + ":做好了 " + name + "\n" 46 | } 47 | 48 | func (c *Chef3) FavCook(name string) string { 49 | return c.Name + ":这是我的拿手菜" + name + ",做好了。\n" 50 | } 51 | 52 | func main() { 53 | wang := Chef2{ 54 | Name: "王师傅", 55 | Age: 23, 56 | Honor2: Honor2{}, 57 | Trainee: nil, 58 | } 59 | 60 | result := wang.Cook("番茄炒蛋") 61 | fmt.Printf("%s", result) 62 | result = wang.FavCook("糖心鲍鱼") 63 | fmt.Printf("%s", result) 64 | 65 | zhao := Chef3{ 66 | Name: "赵师傅", 67 | Age: 26, 68 | Honor3: Honor3{}, 69 | Trainee: nil, 70 | } 71 | fmt.Printf("%s", zhao.Cook("蛋炒饭")) 72 | fmt.Printf("%s", zhao.FavCook("小炒肉")) 73 | } 74 | -------------------------------------------------------------------------------- /Chapter8/8-8/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "time" 6 | ) 7 | 8 | type Honor3 struct { 9 | Title string //获奖名称 10 | GetTime time.Time //获奖时间 11 | } 12 | 13 | type Chef3 struct { 14 | Name string 15 | Age int 16 | Honor3 17 | Trainee *Chef3 18 | } 19 | 20 | func (c Chef3) Cook(name string) string { 21 | return c.Name + ":做好了 " + name + "\n" 22 | } 23 | 24 | func (c Chef3) FavCook(name string) string { 25 | return c.Name + ":这是我的拿手菜" + name + ",做好了。\n" 26 | } 27 | 28 | func main() { 29 | zhao := &Chef3{ 30 | Name: "赵师傅", 31 | Age: 26, 32 | Honor3: Honor3{}, 33 | Trainee: nil, 34 | } 35 | fmt.Printf("%s", zhao.Cook("蛋炒饭")) 36 | fmt.Printf("%s", zhao.FavCook("小炒肉")) 37 | } 38 | -------------------------------------------------------------------------------- /Chapter8/8-9/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "time" 6 | ) 7 | 8 | type Honor3 struct { 9 | Title string //获奖名称 10 | GetTime time.Time //获奖时间 11 | } 12 | 13 | type Chef3 struct { 14 | Name string 15 | Age int 16 | Honor3 17 | Trainee *Chef3 18 | } 19 | 20 | func (c Chef3) Cook(name string) string { 21 | return c.Name + ":做好了 " + name + "\n" 22 | } 23 | 24 | func (c Chef3) FavCook(name string) string { 25 | return c.Name + ":这是我的拿手菜" + name + ",做好了。\n" 26 | } 27 | 28 | func main() { 29 | li := &Chef3{ 30 | Name: "李师傅", 31 | Age: 26, 32 | Honor3: Honor3{}, 33 | Trainee: nil, 34 | } 35 | liFav := li.FavCook 36 | r := liFav("葱烧海参") 37 | fmt.Printf("%s", r) 38 | 39 | } 40 | -------------------------------------------------------------------------------- /Chapter9/9-1/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "fmt" 4 | 5 | type ChefInterface interface { 6 | Cook() bool 7 | FavCook(foodName string) bool 8 | } 9 | type Chef struct { 10 | Name string 11 | Age int 12 | } 13 | 14 | func (c Chef) Cook() bool { 15 | fmt.Println(c.Name + "饭菜做好了") 16 | return true 17 | } 18 | func (c Chef) FavCook(foodName string) bool { 19 | fmt.Println(c.Name + "的拿手菜" + foodName + "做好了") 20 | return true 21 | } 22 | 23 | func Say(i interface{}) { 24 | fmt.Printf("(%v, %T)\n", i, i) 25 | } 26 | 27 | func main() { 28 | li := Chef{ 29 | Name: "李师傅", 30 | Age: 28, 31 | } 32 | li.FavCook("红烧肉") 33 | li.Cook() 34 | 35 | var i interface{} 36 | Say(i) 37 | i = 77 38 | Say(i) 39 | i = "Go语言学习" 40 | Say(i) 41 | 42 | } 43 | -------------------------------------------------------------------------------- /Chapter9/9-2/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "fmt" 4 | 5 | //定义一个鸭子接口 6 | type Duck interface { 7 | Cook() 8 | } 9 | 10 | //吊炉烤鸭 11 | type DiaoLu struct{} 12 | 13 | func (dl *DiaoLu) Cook() { 14 | fmt.Println("今天去吃,吊炉烤鸭") 15 | } 16 | 17 | //焖炉烤鸭 18 | type MenLu struct{} 19 | 20 | func (ml *MenLu) Cook() { 21 | fmt.Println("今天去吃,焖炉烤鸭") 22 | } 23 | 24 | func CookDuck(d Duck) { 25 | d.Cook() 26 | } 27 | 28 | func main() { 29 | fmt.Println("duck typing") 30 | var d DiaoLu 31 | var m MenLu 32 | 33 | CookDuck(&d) 34 | CookDuck(&m) 35 | } 36 | -------------------------------------------------------------------------------- /Chapter9/9-3/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "fmt" 4 | 5 | type ChefInterface interface { 6 | Cook() bool 7 | FavCook(foodName string) bool 8 | } 9 | 10 | type Chef struct { 11 | Name string 12 | Age int 13 | } 14 | func (c *Chef) Cook() bool { 15 | fmt.Println(c.Name + "饭菜做好了") 16 | fmt.Printf("%p\n",c) 17 | return true 18 | } 19 | 20 | func (c *Chef) FavCook(foodName string) bool { 21 | fmt.Println(c.Name + "的拿手菜" + foodName + "做好了") 22 | fmt.Printf("%p\n",c) 23 | return true 24 | } 25 | func WorkForDinner(c *Chef,foodsName string){ 26 | var ci ChefInterface=c 27 | ci.Cook() 28 | ci.FavCook(foodsName) 29 | } 30 | 31 | func main() { 32 | li := Chef{ 33 | Name: "李师傅", 34 | Age: 28, 35 | } 36 | fmt.Printf("李师傅对象的地址%p\n",&li) 37 | WorkForDinner(&li,"红烧肉") 38 | zhang:=Chef{ 39 | Name: "张师傅", 40 | Age: 25, 41 | } 42 | fmt.Printf("张师傅对象的地址%p\n",&zhang) 43 | WorkForDinner(&zhang,"盐焗鸡") 44 | } 45 | -------------------------------------------------------------------------------- /Chapter9/9-4/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "time" 6 | ) 7 | 8 | type Chef struct { 9 | Name string 10 | Age int 11 | Honor 12 | Trainee *Chef 13 | } 14 | 15 | 16 | type Honor struct { 17 | Title string //获奖名称 18 | GetTime time.Time //获奖时间 19 | } 20 | 21 | type ChefInterface interface { 22 | Cook() bool 23 | FavCook(foodName string) bool 24 | } 25 | type FarmInterface interface { 26 | FarmVegeTables(string) string 27 | } 28 | type AdvanceChef interface { 29 | ChefInterface 30 | FarmInterface 31 | } 32 | 33 | func (c Chef) Cook() string { 34 | return c.Name+"饭菜做好了 "} 35 | 36 | func ( c Chef) FavCook(name string) string { 37 | return c.Name+":这是我的拿手菜"+name+",做好了。" 38 | } 39 | func (c *Chef) FarmVegeTables(name string) string{ 40 | return name+"可以收割了。\n" 41 | } 42 | 43 | func main() { 44 | zhang := Chef{ 45 | Name: "张师傅", 46 | Age: 28, 47 | } 48 | fmt.Printf("%s",zhang.FarmVegeTables("豆角")) 49 | r:=zhang.FavCook("干煸豆角") 50 | fmt.Println(r) 51 | r=zhang.Cook() 52 | fmt.Println(r) 53 | } 54 | -------------------------------------------------------------------------------- /Chapter9/9-5/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "fmt" 4 | 5 | type ChefInterface interface { 6 | Cook() bool 7 | FavCook(foodName string) bool 8 | Hidden(b bool) string 9 | GetHonor() string 10 | } 11 | 12 | type Chef struct { 13 | Name string 14 | Age int 15 | Honor string 16 | } 17 | 18 | func (c *Chef) Cook() bool { 19 | fmt.Println(c.Name + "饭菜做好了") 20 | return true 21 | } 22 | 23 | func (c *Chef) FavCook(foodName string) bool { 24 | fmt.Println(c.Name + "的拿手菜" + foodName + "做好了") 25 | return true 26 | } 27 | 28 | func (c Chef) Hidden(b bool) string { 29 | if b { 30 | return c.Name + "有隐藏绝活" 31 | } 32 | return "" 33 | } 34 | 35 | func (c Chef) GetHonor() string { 36 | return c.Honor 37 | } 38 | 39 | func WorkForDinner(c *Chef, foodsName string) { 40 | var ci ChefInterface = c 41 | ci.Cook() 42 | ci.FavCook(foodsName) 43 | } 44 | 45 | func main() { 46 | li := Chef{ 47 | Name: "李师傅", 48 | Age: 28, 49 | } 50 | WorkForDinner(&li, "红烧肉") 51 | zhang := Chef{ 52 | Name: "张师傅", 53 | Age: 25, 54 | } 55 | WorkForDinner(&zhang, "盐焗鸡") 56 | 57 | var ci ChefInterface 58 | fmt.Printf("%T\n", ci) 59 | fmt.Println(ci == nil) 60 | ci = new(Chef) 61 | fmt.Printf("%T\n", ci) 62 | } 63 | -------------------------------------------------------------------------------- /Chapter9/9-6/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "errors" 5 | "fmt" 6 | ) 7 | 8 | type WrapError struct { 9 | msg string 10 | err error 11 | } 12 | 13 | func (e *WrapError) Error() string { 14 | return e.msg 15 | } 16 | 17 | func (e *WrapError) Unwrap() error { 18 | return e.err 19 | } 20 | 21 | type ErrorString struct { 22 | s string 23 | } 24 | 25 | func (e *ErrorString) Error() string { 26 | return e.s 27 | } 28 | 29 | func main() { 30 | //err1:=errors.New("My Error 1") 31 | //err11:=fmt.Errorf("err11:[%w]",err1) 32 | //err111:=fmt.Errorf("err111: [%w]",err11) 33 | //e1 := fmt.Errorf("【%w】", err111) 34 | //fmt.Println(e1) 35 | 36 | err2 := errors.New("My Error 2") 37 | e2 := fmt.Errorf("err2:【%w】", err2) 38 | e22 := fmt.Errorf("err22:【%w】", e2) 39 | fmt.Println(e2) 40 | fmt.Println(errors.Unwrap(e2)) 41 | fmt.Println(errors.Unwrap(errors.Unwrap(e22))) 42 | 43 | err3 := errors.New("My Error 3") 44 | e3 := fmt.Errorf("err3:【%w】", err3) 45 | e33 := fmt.Errorf("err33:【%w】", e3) 46 | 47 | fmt.Println(errors.Is(e33, e3)) 48 | fmt.Println(errors.Is(e33, err3)) 49 | 50 | var targetErr *ErrorString 51 | err4 := fmt.Errorf("new error:[%w]", &ErrorString{s: "target err"}) 52 | fmt.Println(errors.As(err4, &targetErr)) 53 | } 54 | -------------------------------------------------------------------------------- /Chapter9/9-7/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "fmt" 4 | 5 | type ChefInterface interface { 6 | Cook() bool 7 | FavCook(foodName string) bool 8 | Hidden(b bool) string 9 | GetHonor() string 10 | } 11 | 12 | type Chef struct { 13 | Name string 14 | Age int 15 | Honor string 16 | } 17 | 18 | func (c *Chef) Cook() bool { 19 | fmt.Println(c.Name + "饭菜做好了") 20 | return true 21 | } 22 | 23 | func (c *Chef) FavCook(foodName string) bool { 24 | fmt.Println(c.Name + "的拿手菜" + foodName + "做好了") 25 | return true 26 | } 27 | 28 | func (c Chef) Hidden(b bool) string { 29 | if b { 30 | return c.Name + "有隐藏绝活" 31 | } 32 | return "" 33 | } 34 | 35 | func (c Chef) GetHonor() string { 36 | return c.Honor 37 | } 38 | 39 | func WorkForDinner(c *Chef, foodsName string) { 40 | var ci ChefInterface = c 41 | ci.Cook() 42 | ci.FavCook(foodsName) 43 | } 44 | 45 | func main() { 46 | var ci ChefInterface 47 | zhang := Chef{ 48 | Name: "张师傅", 49 | Age: 25, 50 | Honor: "", 51 | } 52 | ci = &zhang 53 | c := ci.(*Chef) 54 | fmt.Println(c) 55 | 56 | ci = &zhang 57 | c2 := ci.(ChefInterface) 58 | fmt.Println(c2) 59 | 60 | } 61 | -------------------------------------------------------------------------------- /Chapter9/9-8/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "fmt" 4 | 5 | func main() { 6 | var x interface{} 7 | x = "abc" 8 | switch x.(type) { 9 | case string: 10 | fmt.Println("这是string类型") 11 | case bool: 12 | fmt.Println("这是bool类型") 13 | case int: 14 | fmt.Println("这是int类型") 15 | } 16 | 17 | } 18 | -------------------------------------------------------------------------------- /Chapter9/9-9/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "fmt" 4 | 5 | type ChefInterface interface { 6 | GetHonor() string 7 | Hidden(b bool) string 8 | } 9 | type Chef struct { 10 | Name string 11 | Age int 12 | Honor string 13 | } 14 | 15 | func (c Chef) Hidden(b bool) string { 16 | if b { 17 | return c.Name + "有隐藏绝活" 18 | } 19 | return "" 20 | } 21 | 22 | func (c Chef) GetHonor() string { 23 | return c.Honor 24 | } 25 | func (c *Chef) SetHonor(title string) { 26 | c.Honor = title 27 | } 28 | 29 | func main() { 30 | zhang := Chef{ 31 | Name: "张师傅", 32 | Age: 36, 33 | Honor: "米其林1星", 34 | } 35 | fmt.Println(zhang.GetHonor()) 36 | 37 | var ci ChefInterface = zhang 38 | zhang.SetHonor("米其林3星") 39 | fmt.Println(zhang.GetHonor()) 40 | fmt.Println(ci.GetHonor()) 41 | 42 | var zhang2 Chef 43 | var ci2 ChefInterface 44 | if ci2 == nil { 45 | fmt.Println("ci2 is nil") 46 | } 47 | ci2 = zhang2 48 | 49 | if ci2 == nil { 50 | fmt.Println("ci2 is nil,too") 51 | } 52 | zhang2.SetHonor("米其林3星") 53 | fmt.Println(zhang2.GetHonor()) 54 | fmt.Println(ci2.GetHonor()) 55 | 56 | } 57 | -------------------------------------------------------------------------------- /Dump20210612.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/i-coder-robot/book_final_code/00ec2d69dc7e2bc68aa78019cbceb9bdb87290fb/Dump20210612.zip -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "[]" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright [yyyy] [name of copyright owner] 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. 202 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # book_final_code -------------------------------------------------------------------------------- /app.MyLog: -------------------------------------------------------------------------------- 1 | ./logs/app.MyLog.20201110 -------------------------------------------------------------------------------- /context_demo/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "context" 5 | "fmt" 6 | "time" 7 | ) 8 | 9 | func main() { 10 | ctx, cancel := context.WithCancel(context.Background()) 11 | //ctx, cancelFunc := context.WithDeadline(context.Background(),time.Now().Add(10*time.Second)) 12 | //ctx.Done() 13 | //defer cancelFunc() 14 | //fmt.Println(ctx) 15 | } 16 | -------------------------------------------------------------------------------- /go.mod: -------------------------------------------------------------------------------- 1 | module github.com/i-coder-robot/book_final_code 2 | 3 | go 1.15 4 | 5 | require ( 6 | github.com/dgrijalva/jwt-go v3.2.0+incompatible 7 | github.com/fastly/go-utils v0.0.0-20180712184237-d95a45783239 // indirect 8 | github.com/fsnotify/fsnotify v1.4.9 9 | github.com/gin-contrib/sessions v0.0.3 10 | github.com/gin-gonic/gin v1.6.3 11 | github.com/go-playground/validator/v10 v10.4.1 12 | github.com/hashicorp/go-uuid v1.0.2 13 | github.com/jehiah/go-strftime v0.0.0-20171201141054-1d33003b3869 // indirect 14 | github.com/jinzhu/gorm v1.9.16 15 | github.com/lestrrat-go/file-rotatelogs v2.4.0+incompatible 16 | github.com/lestrrat-go/strftime v1.0.3 // indirect 17 | github.com/spf13/viper v1.7.1 18 | github.com/stretchr/testify v1.6.1 19 | github.com/tebeka/strftime v0.1.5 // indirect 20 | github.com/willf/pad v0.0.0-20200313202418-172aa767f2a4 21 | go.uber.org/zap v1.10.0 22 | golang.org/x/crypto v0.0.0-20201016220609-9e8e0b390897 23 | ) 24 | --------------------------------------------------------------------------------