├── 20180914 └── channel.go ├── 2018022401 └── main.go ├── 2018022402 └── main.go ├── 2018022601 └── main.go ├── 2018022602 └── main.go ├── 2018022701 └── main.go ├── 2018022801 └── main.go ├── 2018022802 └── main.go ├── 2018022803 └── main.go ├── 2018030501 ├── debug └── main.go ├── 2018030701 └── main.go ├── 2018030702 └── main.go ├── 2018030801 └── main.go ├── 2018030901 └── main.go ├── 2018030902 └── main.go ├── 2018033001 └── main.go ├── 2018033002 ├── debug └── main.go ├── 2018040201 └── main.go ├── 2018091401 └── select.go ├── 2018091402 └── func.go ├── 2018092501 └── main.go ├── 2018092502 ├── 2018092502 └── main.go ├── 2018092801 └── redis.go ├── 2018092802 └── redis.go ├── 2018092803 └── redis.go ├── 2018092804 └── redis.go ├── 2018092806 └── redis.go ├── 2018100901 └── main.go ├── .DS_Store ├── beego_short_url ├── beego_short_url ├── conf │ └── app.conf ├── controllers │ ├── default.go │ └── short_url.go ├── main.go ├── models │ └── data.go ├── routers │ └── router.go ├── static │ └── js │ │ └── reload.min.js ├── tests │ └── default_test.go └── views │ └── index.tpl ├── book_mgr_v1 ├── api │ ├── api.go │ └── error_code.go └── logic │ ├── book.go │ ├── book_mgr.go │ ├── student.go │ └── student_mgr.go ├── book_mgr_v2 ├── api │ ├── api.go │ └── error_code.go └── logic │ ├── book.go │ ├── book_mgr.go │ ├── student.go │ └── student_mgr.go ├── book_mgr_v3 ├── api │ ├── api.go │ └── error_code.go └── logic │ ├── book.go │ ├── book_mgr.go │ ├── constant.go │ ├── student.go │ └── student_mgr.go ├── config ├── config.go └── config_notify.go ├── config222 └── config.go ├── config_test ├── config.conf └── main.go ├── config_test222 ├── config_test.exe ├── main.go └── test.yaml ├── iniConfig ├── config.ini ├── go.mod ├── go.sum ├── iniConfig.go ├── iniConfig_test.go └── test.ini ├── interface_nest └── main.go ├── pay ├── alipay.go ├── main.go ├── pay.go ├── phone.go └── weixin.go ├── reverse └── reverse.go ├── short_url ├── api │ └── api.go ├── client │ └── client.go ├── logic │ └── logic.go └── model │ └── data.go └── tombv1 ├── tomb.go └── tomb_test.go /.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pythonsite/go_simple_code/43fa67a712e8bce178f479379071d9f167504505/.DS_Store -------------------------------------------------------------------------------- /2018022401/main.go: -------------------------------------------------------------------------------- 1 | /* 2 | 求出1000以内既能被3整除也能被5整除的所有数的和 3 | */ 4 | package main 5 | 6 | import "fmt" 7 | 8 | func main(){ 9 | var num int 10 | for i:=1;i<=1000;i++{ 11 | if i%3==0 || i%5==0{ 12 | num += i 13 | } 14 | } 15 | fmt.Println(num) 16 | } 17 | -------------------------------------------------------------------------------- /2018022402/main.go: -------------------------------------------------------------------------------- 1 | /* 2 | 通过计算一定数量的斐波那契数列,并求出偶数和 3 | */ 4 | 5 | package main 6 | 7 | import "fmt" 8 | 9 | // 用于计算获取斐波那契数列 10 | func fib(n int)int{ 11 | if n<=2{ 12 | return n 13 | }else{ 14 | return fib(n-1)+fib(n-2) 15 | } 16 | } 17 | 18 | func main() { 19 | var s []int 20 | var sum int 21 | for i:=1;i<10;i++{ 22 | res := fib(i) 23 | if res % 2 == 0{ 24 | sum += res 25 | } 26 | fmt.Println(res) 27 | s = append(s,res) 28 | } 29 | fmt.Println(s) 30 | fmt.Println(sum) 31 | } -------------------------------------------------------------------------------- /2018022601/main.go: -------------------------------------------------------------------------------- 1 | /* 2 | 13195的因素数是5,7,13,29 3 | 求某个整数最大素数是多少 4 | */ 5 | 6 | package main 7 | 8 | import "fmt" 9 | 10 | //获取一个整数除了1所有的因数的切片 11 | func getFactor(num int)(s []int) { 12 | s = append(s,num) 13 | for i := 2; i < num/2+1; i++ { 14 | if num%i == 0 { 15 | res := judge(i,s) 16 | if res == false{ 17 | s = append(s,i,num/i) 18 | } 19 | 20 | } 21 | } 22 | return 23 | } 24 | 25 | // 判断n是否已经在s切片中 26 | func judge(n int,s []int)(b bool){ 27 | for _,v := range s{ 28 | if v == n{ 29 | return true 30 | } 31 | } 32 | return false 33 | } 34 | 35 | // 判断n是否是质数 36 | func judgePrimeNum(s []int)(res []int){ 37 | 38 | for _,v := range s{ 39 | var b = true 40 | for i:=2;i<=v/2;i++{ 41 | if v%i==0{ 42 | b=false 43 | break 44 | } 45 | } 46 | if b == true{ 47 | res = append(res, v) 48 | } 49 | } 50 | return 51 | } 52 | 53 | func getBig(s []int)(n int){ 54 | bigNum := s[0] 55 | for i:=1;i bigNum{ 43 | bigNum = num 44 | one = i 45 | two = j 46 | } 47 | } 48 | } 49 | } 50 | fmt.Printf("%d*%d=%d",one,two,bigNum) 51 | 52 | } 53 | -------------------------------------------------------------------------------- /2018022701/main.go: -------------------------------------------------------------------------------- 1 | /* 2 | 2520是可以被1到10中的每个数字除以没有任何余数的最小数字 3 | 可以被1到20的所有数字整除的最小正数是多少 4 | */ 5 | package main 6 | 7 | import "fmt" 8 | 9 | func getSlice(num int) ([]int) { 10 | var s = []int{} 11 | var s2 = []int{} 12 | for i := 1; i <= num; i++ { 13 | s = append(s, i) 14 | } 15 | for j := 2; j < num; j++ { 16 | flag := 1 17 | for { 18 | flag = 0 19 | for k := 0; k < 20; k++ { 20 | if s[k]%j == 0 { 21 | s[k] = s[k] / j 22 | flag = 1 23 | } 24 | } 25 | if flag == 1 { 26 | s2 = append(s2, j) 27 | } else { 28 | break 29 | } 30 | } 31 | 32 | } 33 | return s2 34 | } 35 | 36 | func main() { 37 | s := getSlice(20) 38 | var result = 1 39 | for _,v:=range s{ 40 | result*=v 41 | } 42 | fmt.Println(result) 43 | } 44 | -------------------------------------------------------------------------------- /2018022801/main.go: -------------------------------------------------------------------------------- 1 | /* 2 | 平方差 3 | */ 4 | 5 | package main 6 | 7 | import ( 8 | "math" 9 | "fmt" 10 | ) 11 | 12 | func getSum()float64{ 13 | var num int 14 | for i:=1;i<=10;i++{ 15 | num += i 16 | } 17 | sum := math.Pow(float64(num),2) 18 | return sum 19 | 20 | } 21 | 22 | func getSum2()float64{ 23 | var num float64 24 | for i:=1;i<=10;i++{ 25 | num += math.Pow(float64(i),2) 26 | } 27 | return num 28 | } 29 | 30 | func main() { 31 | num1 := getSum() 32 | fmt.Println(num1) 33 | num2 :=getSum2() 34 | fmt.Println(num2) 35 | res := num1-num2 36 | fmt.Println(res) 37 | } 38 | -------------------------------------------------------------------------------- /2018022802/main.go: -------------------------------------------------------------------------------- 1 | /* 2 | 回去第1001个素数 3 | */ 4 | 5 | package main 6 | 7 | import "fmt" 8 | 9 | func main() { 10 | var num int 11 | for i:=2;;i++{ 12 | var b bool 13 | for j:=2;j<=i/2;j++{ 14 | if i%j == 0{ 15 | b = true 16 | break 17 | } 18 | } 19 | if b == false{ 20 | num += 1 21 | if num == 1001{ 22 | fmt.Println(i) 23 | break 24 | } 25 | } 26 | } 27 | } 28 | 29 | -------------------------------------------------------------------------------- /2018022803/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "strconv" 6 | ) 7 | 8 | func getRes(n int){ 9 | var str = "7316717653133062491922511967442657474235534919493496983520312774506326239578318016984801869478851843858615607891129494954595017379583319528532088055111254069874715852386305071569329096329522744304355766896648950445244523161731856403098711121722383113622298934233803081353362766142828064444866452387493035890729629049156044077239071381051585930796086670172427121883998797908792274921901699720888093776657273330010533678812202354218097512545405947522435258490771167055601360483958644670632441572215539753697817977846174064955149290862569321978468622482839722413756570560574902614079729686524145351004748216637048440319989000889524345065854122758866688116427171479924442928230863465674813919123162824586178664583591245665294765456828489128831426076900422421902267105562632111110937054421750694165896040807198403850962455444362981230987879927244284909188845801561660979191338754992005240636899125607176060588611646710940507754100225698315520005593572972571636269561882670428252483600823257530420752963450" 10 | var maxNum int 11 | for i:=0;i<=len(str)-n;i++{ 12 | num := str[i:i+n] 13 | var res = 1 14 | for i:=0;i=maxNum{ 19 | maxNum = res 20 | } 21 | 22 | } 23 | fmt.Println(maxNum) 24 | } 25 | 26 | func main() { 27 | getRes(13) 28 | 29 | } -------------------------------------------------------------------------------- /2018030501/debug: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pythonsite/go_simple_code/43fa67a712e8bce178f479379071d9f167504505/2018030501/debug -------------------------------------------------------------------------------- /2018030501/main.go: -------------------------------------------------------------------------------- 1 | /* 2 | 给定一个范围为 32 位 int 的整数,将其颠倒。 3 | 如 4 | 输入: 123 5 | 输出: 321 6 | 7 | 输入: -123 8 | 输出: -321 9 | 10 | 输入: 120 11 | 输出: 21 12 | 13 | 假设我们的环境只能处理 32 位 int 范围内的整数。根据这个假设,如果颠倒后的结果超过这个范围,则返回 0。 14 | */ 15 | 16 | 17 | package main 18 | 19 | import ( 20 | "strconv" 21 | "fmt" 22 | "math" 23 | ) 24 | 25 | func reverse(x int) int{ 26 | var b bool 27 | if x < 0{ 28 | x = int(math.Abs(float64(x))) 29 | b = true 30 | } 31 | xStr := strconv.Itoa(x) 32 | xSlice := []rune(xStr) 33 | for i,j:=0,len(xSlice)-1;i math.MaxInt32 { 40 | return 0 41 | } 42 | return -res 43 | } 44 | if res > math.MaxInt32{ 45 | return 0 46 | } 47 | return res 48 | 49 | } 50 | 51 | func main() { 52 | res := reverse(-10) 53 | fmt.Println(res) 54 | } -------------------------------------------------------------------------------- /2018030701/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | ) 6 | 7 | func twoSum(nums []int, target int) []int { 8 | var res = []int{} 9 | for k,v := range nums{ 10 | for j,q := range nums[k+1:]{ 11 | if v + q == target{ 12 | res = append(res,k,j+k+1) 13 | break 14 | } 15 | } 16 | } 17 | return res 18 | } 19 | 20 | func main() { 21 | nums := []int{2, 7, 11, 15} 22 | res := twoSum(nums,26) 23 | fmt.Println(res) 24 | } -------------------------------------------------------------------------------- /2018030702/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "fmt" 4 | 5 | func twoSum(nums []int, target int)[]int{ 6 | if len(nums) <2 { 7 | return nil 8 | } 9 | m := make(map[int]int,len(nums)) 10 | for i, v:= range nums{ 11 | if j, ok := m[v];ok{ 12 | return []int{j,i} 13 | }else{ 14 | m[target-v] = i 15 | } 16 | } 17 | return nil 18 | } 19 | 20 | func main() { 21 | nums := []int{2, 7, 11, 15} 22 | res := twoSum(nums,26) 23 | fmt.Println(res) 24 | } -------------------------------------------------------------------------------- /2018030801/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "fmt" 4 | 5 | func longestCommonPrefix(strs []string) string { 6 | if len(strs) == 0{ 7 | return "" 8 | } 9 | if len(strs) == 1{ 10 | return strs[0] 11 | } 12 | var minlen = len(strs[0]) 13 | var key int 14 | var minStr string 15 | for k,v := range strs{ 16 | if len(v) <= minlen{ 17 | minlen = len(v) 18 | key = k 19 | minStr = v 20 | } 21 | } 22 | strs = append(strs[:key],strs[key+1:]...) 23 | var prefixStr string 24 | BREAKPOINT: 25 | for k,v:=range []rune(minStr){ 26 | for _,value:=range strs{ 27 | if string(v) != string([]rune(value)[k]){ 28 | break BREAKPOINT 29 | } 30 | } 31 | prefixStr += string(v) 32 | } 33 | return prefixStr 34 | } 35 | 36 | func main() { 37 | res := longestCommonPrefix([]string{"abc","abcd","abc","abc"}) 38 | fmt.Println(res) 39 | } 40 | -------------------------------------------------------------------------------- /2018030901/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | func longestCommonPrefix(strs []string) string { 4 | row := len(strs) 5 | if row == 0 { 6 | return "" 7 | } 8 | if row == 1 { 9 | return strs[0] 10 | } 11 | lcp := "" 12 | minLen := (1 << 30) 13 | // 计算最长 14 | for _, v := range strs { 15 | vLen := len(v) 16 | if minLen > vLen { 17 | minLen = vLen 18 | } 19 | } 20 | BREAKPOINT: 21 | for i := 0; i < minLen; i++ { 22 | for j := 0; j < row; j++ { 23 | if strs[j][i] != strs[0][i] { 24 | break BREAKPOINT 25 | } 26 | } 27 | lcp += strs[0][i : i+1] 28 | } 29 | return lcp 30 | } 31 | 32 | func main() { 33 | } 34 | -------------------------------------------------------------------------------- /2018030902/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "fmt" 4 | 5 | func removeElement(nums []int, val int) int { 6 | var sum int 7 | for _,v:=range nums{ 8 | if val == v{ 9 | sum += 1 10 | } 11 | } 12 | var count int 13 | for { 14 | for k,v:=range nums{ 15 | if val == v{ 16 | count += 1 17 | nums = append(nums[:k],nums[k+1:]...) 18 | break 19 | } 20 | } 21 | if count == sum{ 22 | break 23 | } 24 | 25 | } 26 | return len(nums) 27 | } 28 | 29 | func main() { 30 | nums := []int{3,2,4,3} 31 | res := removeElement(nums, 3) 32 | fmt.Println(res) 33 | } 34 | -------------------------------------------------------------------------------- /2018033001/main.go: -------------------------------------------------------------------------------- 1 | /* 2 | 3 | 给定一个字符串, 包含大小写字母、空格 ' ',请返回其最后一个单词的长度。 4 | 5 | 如果不存在最后一个单词,请返回 0 。 6 | 7 | 注意事项:一个单词的界定是,由字母组成,但不包含任何的空格。 8 | */ 9 | 10 | package main 11 | 12 | import ( 13 | "strings" 14 | "fmt" 15 | ) 16 | 17 | func lengthOfLastWord(s string) int { 18 | s = strings.TrimSpace(s) 19 | arr := strings.Split(s," ") 20 | res := arr[len(arr)-1] 21 | return len(res) 22 | } 23 | 24 | func main() { 25 | res := lengthOfLastWord("hello world") 26 | fmt.Println(res) 27 | } -------------------------------------------------------------------------------- /2018033002/debug: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pythonsite/go_simple_code/43fa67a712e8bce178f479379071d9f167504505/2018033002/debug -------------------------------------------------------------------------------- /2018033002/main.go: -------------------------------------------------------------------------------- 1 | /* 2 | 给定一个范围为 32 位 int 的整数,将其颠倒。 3 | 如 4 | 输入: 123 5 | 输出: 321 6 | 7 | 输入: -123 8 | 输出: -321 9 | 10 | 输入: 120 11 | 输出: 21 12 | 13 | 假设我们的环境只能处理 32 位 int 范围内的整数。根据这个假设,如果颠倒后的结果超过这个范围,则返回 0。 14 | */ 15 | 16 | package main 17 | 18 | import ( 19 | "fmt" 20 | "math" 21 | ) 22 | 23 | func reverse(x int) int { 24 | res := 0 25 | for x != 0 { 26 | res = res*10 + x%10 27 | if res > math.MaxInt32 || res < math.MinInt32 { 28 | return 0 29 | } 30 | x /= 10 31 | } 32 | return res 33 | } 34 | 35 | func main() { 36 | res := reverse(123) 37 | fmt.Println(res) 38 | } 39 | -------------------------------------------------------------------------------- /2018040201/main.go: -------------------------------------------------------------------------------- 1 | /* 2 | 给定一个数组和一个值,在这个数组中原地移除指定值和返回移除后新的数组长度。 3 | 4 | 不要为其他数组分配额外空间,你必须使用 O(1) 的额外内存原地修改这个输入数组。 5 | 6 | 元素的顺序可以改变。超过返回的新的数组长度以外的数据无论是什么都没关系。 7 | 8 | 给定 nums = [3,2,2,3],val = 3, 9 | 10 | 你的函数应该返回 长度 = 2,数组的前两个元素是 2。 11 | */ 12 | 13 | package main 14 | 15 | import "fmt" 16 | 17 | //func removeElement(nums []int, val int) int { 18 | // 19 | //} 20 | 21 | func main() { 22 | nums := [20]int{3,2,2,3} 23 | for k,v := range nums{ 24 | if v == 3{ 25 | nums[k] = 0 26 | } 27 | } 28 | fmt.Println(nums) 29 | fmt.Println(cap(nums)) 30 | } 31 | 32 | -------------------------------------------------------------------------------- /20180914/channel.go: -------------------------------------------------------------------------------- 1 | /* 2 | 在select中所有的case都没有匹配,则会走default分支 3 | 如果所有的case分支都没有满足条件,那么默认分支就会被选中并执行 4 | 5 | 如果没有默认分支,那么一旦所有的case 表达式都没有满足条件的,那么select语句就会被阻塞,直到至少有一个case表达式满足条件为止 6 | 当from循环和select嵌套使用的时候需要注意: 7 | 简单地在select语句中使用break语句,智能结束当前的select语句的执行,而并不会对外层的for语句产生作用,这种错误的用法会让这个for语句 8 | 无休止的一直运行下去 9 | */ 10 | 11 | package main 12 | 13 | import ( 14 | "fmt" 15 | "math/rand" 16 | ) 17 | 18 | func main(){ 19 | intChannels := [3] chan int { 20 | make(chan int, 1), 21 | make(chan int, 1), 22 | make(chan int, 1), 23 | } 24 | 25 | index := rand.Intn(3) 26 | fmt.Printf("the index :%d\n", index) 27 | 28 | intChannels[index] <- index 29 | select { 30 | case <-intChannels[0]: 31 | fmt.Println("the first candidate case is selected") 32 | case <- intChannels[1]: 33 | fmt.Println("the second candidate case is selected") 34 | case <- intChannels[2]: 35 | fmt.Println("the third candidate case is selected") 36 | default: 37 | fmt.Println("no candidate case is selected") 38 | } 39 | 40 | } -------------------------------------------------------------------------------- /2018091401/select.go: -------------------------------------------------------------------------------- 1 | /* 2 | 这个例子用于理解select的用法 3 | 4 | 5 | */ 6 | 7 | package main 8 | 9 | 10 | import ( 11 | "time" 12 | "fmt" 13 | ) 14 | 15 | func main(){ 16 | intChan := make(chan int, 1) 17 | 18 | //声明了一个定时器,1秒之后关闭intChan 19 | time.AfterFunc(2*time.Second, func(){ 20 | close(intChan) 21 | }) 22 | 23 | // 因为初始的intChan中并没有任何元素,所有case语句会阻塞,并且没有default 24 | // 直到我们的的定时器关闭chan后,我们唯一的case才满足条件执行 25 | select { 26 | case _, ok := <- intChan: 27 | if !ok { 28 | fmt.Println("the candidate case is closed") 29 | break 30 | } 31 | fmt.Println("the candidate case is selected") 32 | } 33 | } -------------------------------------------------------------------------------- /2018091402/func.go: -------------------------------------------------------------------------------- 1 | /* 2 | 什么是高阶函数 3 | 1、接收其他的函数作为参数传入 4 | 2、把其他的函数作为结果返回 5 | */ 6 | 7 | 8 | package main 9 | 10 | import ( 11 | "fmt" 12 | "errors" 13 | ) 14 | 15 | 16 | type Printer func(content string) (n int, err error) 17 | 18 | 19 | func printToStd(content string) (n int, err error) { 20 | return fmt.Println(content) 21 | } 22 | 23 | type operate func(x, y int) int 24 | 25 | 26 | func calculate(x int ,y int, op operate) (int, error){ 27 | if op == nil { 28 | return 0, errors.New("invalid operation") 29 | } 30 | return op(x, y), nil 31 | } 32 | 33 | 34 | func main() { 35 | var p Printer 36 | p = printToStd 37 | p("something") 38 | 39 | 40 | op := func(x,y int) int { 41 | return x+y 42 | } 43 | res,_ := calculate(10,20,op) 44 | fmt.Println(res) 45 | } -------------------------------------------------------------------------------- /2018092501/main.go: -------------------------------------------------------------------------------- 1 | /* 2 | 关于巴贝奇差分机 3 | */ 4 | 5 | package main 6 | 7 | import ( 8 | "fmt" 9 | ) 10 | 11 | func bafenqi(n int)int { 12 | square_nminus1 := 1 13 | square_n := 4 14 | alpha_nminus1 := 1 15 | 16 | for i:=2;i<=n-1;i++ { 17 | alpha_n := square_n - square_nminus1 18 | beta_n := alpha_n - alpha_nminus1 19 | square_nplus1 := square_n + alpha_n + beta_n 20 | square_nminus1 = square_n 21 | square_n = square_nplus1 22 | alpha_nminus1 = alpha_n 23 | } 24 | return square_n 25 | } 26 | 27 | func main(){ 28 | res := bafenqi(10) 29 | fmt.Println(res) 30 | } -------------------------------------------------------------------------------- /2018092502/2018092502: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pythonsite/go_simple_code/43fa67a712e8bce178f479379071d9f167504505/2018092502/2018092502 -------------------------------------------------------------------------------- /2018092502/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "time" 5 | "fmt" 6 | "sync/atomic" 7 | ) 8 | 9 | 10 | func main() { 11 | var count uint32 12 | trigger := func(i uint32, fn func()) { 13 | for { 14 | if n := atomic.LoadUint32(&count); n == i { 15 | fn() 16 | atomic.AddUint32(&count, 1) 17 | break 18 | } 19 | time.Sleep(time.Nanosecond) 20 | } 21 | } 22 | for i := uint32(0); i < 10; i++ { 23 | go func(i uint32) { 24 | fn := func() { 25 | fmt.Println(i) 26 | } 27 | trigger(i, fn) 28 | }(i) 29 | } 30 | trigger(10, func() {}) 31 | } -------------------------------------------------------------------------------- /2018092801/redis.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "github.com/garyburd/redigo/redis" 6 | ) 7 | 8 | func main() { 9 | c, err := redis.Dial("tcp","192.168.0.116:6379") 10 | if err != nil { 11 | fmt.Println("conn redis failed:",err) 12 | return 13 | } 14 | fmt.Println("conn redis success") 15 | defer c.Close() 16 | _, err = c.Do("set","abc",100) 17 | if err != nil { 18 | fmt.Println("set error:",err) 19 | return 20 | } 21 | fmt.Println("set success") 22 | r, err := redis.Int(c.Do("get","abc")) 23 | if err != nil { 24 | fmt.Println("get error:",err) 25 | return 26 | } 27 | fmt.Println(r) 28 | } -------------------------------------------------------------------------------- /2018092802/redis.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "github.com/garyburd/redigo/redis" 6 | ) 7 | 8 | func main() { 9 | c, err := redis.Dial("tcp","192.168.0.116:6379") 10 | if err != nil { 11 | fmt.Println("conn redis err:",err) 12 | return 13 | } 14 | defer c.Close() 15 | 16 | fmt.Println("con redis success") 17 | _, err = c.Do("hset","book","abc",100) 18 | if err != nil { 19 | fmt.Println("hset err:",err) 20 | return 21 | } 22 | r, err := redis.Int(c.Do("hget","book","abc")) 23 | if err != nil { 24 | fmt.Println("hget is err:",err) 25 | return 26 | } 27 | fmt.Println(r) 28 | } -------------------------------------------------------------------------------- /2018092803/redis.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "github.com/garyburd/redigo/redis" 6 | ) 7 | 8 | func main() { 9 | c, err := redis.Dial("tcp","192.168.0.116:6379") 10 | if err != nil { 11 | fmt.Println("conn redis err:",err) 12 | return 13 | } 14 | fmt.Println("conn redis success") 15 | defer c.Close() 16 | 17 | _, err = c.Do("mset","abc",23,"age",1212) 18 | if err != nil { 19 | fmt.Println("mset error:",err) 20 | return 21 | } 22 | fmt.Println("mset success") 23 | 24 | r, err := redis.Ints(c.Do("mget","abc","age")) 25 | if err != nil { 26 | fmt.Println("redis mget err:",err) 27 | return 28 | } 29 | for _, v := range r{ 30 | fmt.Println(v) 31 | } 32 | } -------------------------------------------------------------------------------- /2018092804/redis.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "github.com/garyburd/redigo/redis" 6 | ) 7 | 8 | func main() { 9 | c, err := redis.Dial("tcp","192.168.0.116:6379") 10 | if err != nil { 11 | fmt.Println("con redis err:",err) 12 | return 13 | } 14 | fmt.Println("con redis success") 15 | defer c.Close() 16 | 17 | _, err = c.Do("lpush","book_list","abcd","age",23) 18 | if err != nil { 19 | fmt.Println("redis lpush err:",err) 20 | return 21 | } 22 | 23 | r, err := redis.String(c.Do("lpop","book_list")) 24 | if err !=nil { 25 | fmt.Println("redis lpop is err:",err) 26 | return 27 | } 28 | fmt.Println(r) 29 | 30 | } -------------------------------------------------------------------------------- /2018092806/redis.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import( 4 | "github.com/garyburd/redigo/redis" 5 | "time" 6 | "fmt" 7 | ) 8 | 9 | var pool *redis.Pool 10 | 11 | func newPool(server, password string) *redis.Pool { 12 | return &redis.Pool { 13 | MaxIdle: 64, 14 | MaxActive: 1000, 15 | IdleTimeout: 240 * time.Second, 16 | Dial: func() (redis.Conn, error) { 17 | c, err := redis.Dial("tcp",server) 18 | if err != nil { 19 | return nil,err 20 | } 21 | /* 22 | if _, err := c.Do("auth",password); err != nil { 23 | c.Close() 24 | return nil, err 25 | } 26 | */ 27 | return c,err 28 | }, 29 | TestOnBorrow: func(c redis.Conn,t time.Time) error { 30 | if time.Since(t) < time.Minute { 31 | return nil 32 | } 33 | _, err := c.Do("PING") 34 | return err 35 | }, 36 | } 37 | } 38 | 39 | func main() { 40 | pool = newPool("192.168.0.116:6379","") 41 | for { 42 | time.Sleep(time.Second) 43 | conn := pool.Get() 44 | conn.Do("set","abc",100) 45 | r, err := redis.Int(conn.Do("get","abc")) 46 | if err != nil { 47 | fmt.Println("err:",err) 48 | return 49 | } 50 | fmt.Println(r) 51 | } 52 | } -------------------------------------------------------------------------------- /2018100901/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "log" 6 | "time" 7 | 8 | "github.com/radovskyb/watcher" 9 | ) 10 | 11 | func main() { 12 | w := watcher.New() 13 | w.SetMaxEvents(1) 14 | w.FilterOps(watcher.Create, watcher.Write, watcher.Chmod) 15 | go func() { 16 | for { 17 | select { 18 | case event := <-w.Event: 19 | fmt.Println(event) 20 | case <-w.Closed: 21 | return 22 | } 23 | } 24 | }() 25 | 26 | if err := w.Add("/app/test"); err != nil { 27 | log.Fatalln(err) 28 | } 29 | if err := w.AddRecursive("/app/test"); err != nil { 30 | log.Fatalln(err) 31 | } 32 | 33 | go func() { 34 | w.Wait() 35 | w.TriggerEvent(watcher.Create, nil) 36 | w.TriggerEvent(watcher.Write, nil) 37 | w.TriggerEvent(watcher.Chmod, nil) 38 | }() 39 | if err := w.Start(time.Millisecond * 100); err != nil { 40 | log.Fatalln(err) 41 | } 42 | 43 | } 44 | -------------------------------------------------------------------------------- /beego_short_url/beego_short_url: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pythonsite/go_simple_code/43fa67a712e8bce178f479379071d9f167504505/beego_short_url/beego_short_url -------------------------------------------------------------------------------- /beego_short_url/conf/app.conf: -------------------------------------------------------------------------------- 1 | appname = beego_short_url 2 | httpport = 8080 3 | runmode = dev 4 | 5 | copyrequestbody = true 6 | recoverpanic=true 7 | 8 | 9 | [Db] 10 | dsn = "root:123456@tcp(192.168.0.114:3306)/short_url?parseTime=true&timeout=1s" -------------------------------------------------------------------------------- /beego_short_url/controllers/default.go: -------------------------------------------------------------------------------- 1 | package controllers 2 | 3 | import ( 4 | "github.com/astaxie/beego" 5 | ) 6 | 7 | type MainController struct { 8 | beego.Controller 9 | } 10 | 11 | func (c *MainController) Get() { 12 | c.Data["Website"] = "beego.me" 13 | c.Data["Email"] = "astaxie@gmail.com" 14 | c.TplName = "index.tpl" 15 | } 16 | -------------------------------------------------------------------------------- /beego_short_url/controllers/short_url.go: -------------------------------------------------------------------------------- 1 | package controllers 2 | 3 | import ( 4 | "github.com/astaxie/beego" 5 | "beego_short_url/models" 6 | "encoding/json" 7 | "database/sql" 8 | "crypto/md5" 9 | "github.com/jmoiron/sqlx" 10 | "fmt" 11 | _ "github.com/go-sql-driver/mysql" 12 | ) 13 | 14 | var ( 15 | Db *sqlx.DB 16 | ) 17 | 18 | func InitDb()(err error){ 19 | Db, err = sqlx.Open("mysql",beego.AppConfig.String("Db::dsn")) 20 | if err != nil{ 21 | beego.Error("connect to mysql failed:",err) 22 | return 23 | } 24 | return 25 | } 26 | 27 | type ShortUrl struct { 28 | Id int64 `db:"id"` 29 | ShortUrl string `db:"short_url"` 30 | OriginUrl string `db:"origin_url"` 31 | HashCode string `db:"hash_code"` 32 | } 33 | 34 | type ShortUrlController struct { 35 | beego.Controller 36 | } 37 | 38 | 39 | func (c *ShortUrlController) Jump() { 40 | shortUrl := c.GetString("shorturl") 41 | if len(shortUrl) == 0{ 42 | return 43 | } 44 | var req models.Short2LongRequest 45 | var resp *models.Short2LongResponse = &models.Short2LongResponse{} 46 | 47 | defer func(){ 48 | if err := recover();err != nil{ 49 | beego.Error("panic err:",err) 50 | //resp.Code = 500 51 | //resp.Message = "server busy" 52 | //c.Data["json"] = resp 53 | //c.ServeJSON() 54 | return 55 | } 56 | }() 57 | req.ShortUrl = shortUrl 58 | resp,err := Short2Long(&req) 59 | if err != nil{ 60 | beego.Error("short2Long failed error:",err) 61 | return 62 | } 63 | 64 | beego.Info("origin url:%s short url:%s",resp.OriginUrl,shortUrl) 65 | c.Redirect(resp.OriginUrl,301) 66 | } 67 | 68 | func (c *ShortUrlController) ShortUrlList() { 69 | limit,err := c.GetInt("limit") 70 | if err != nil{ 71 | beego.Warn("not have limit params use default 10") 72 | limit = 10 73 | } 74 | data,err := GetLastShortUrl(limit) 75 | if err != nil{ 76 | beego.Error("from db get url list error:",err) 77 | 78 | } 79 | 80 | for i,v:= range data{ 81 | v.ShortUrl = fmt.Sprintf("/jump/?shorturl=%s",v.ShortUrl) 82 | data[i] = v 83 | } 84 | 85 | c.Data["url_list"] = data 86 | c.TplName = "index.tpl" 87 | } 88 | 89 | func(c *ShortUrlController) Long2Short(){ 90 | var req models.Long2ShortRequest 91 | var resp *models.Long2ShortResponse = &models.Long2ShortResponse{} 92 | 93 | defer func(){ 94 | if err := recover();err != nil{ 95 | beego.Error("panic err:",err) 96 | resp.Code = 500 97 | resp.Message = "server busy" 98 | c.Data["json"] = resp 99 | c.ServeJSON() 100 | return 101 | } 102 | }() 103 | 104 | 105 | err := json.Unmarshal(c.Ctx.Input.RequestBody,&req) 106 | if err != nil{ 107 | beego.Error("unmarshal failed,err:",err) 108 | resp.Code = 1001 109 | resp.Message = "json unmarshal failed" 110 | c.Data["json"] = resp 111 | c.ServeJSON() 112 | return 113 | } 114 | resp,err = Long2Short(&req) 115 | if err != nil{ 116 | beego.Error("long2short failed,err:",err) 117 | resp.Code = 1002 118 | resp.Message = "long2short failed" 119 | c.Data["json"] = resp 120 | c.ServeJSON() 121 | return 122 | } 123 | c.Data["json"] = resp 124 | c.ServeJSON() 125 | 126 | 127 | 128 | } 129 | 130 | func(c *ShortUrlController) Short2Long(){ 131 | var req models.Short2LongRequest 132 | var resp *models.Short2LongResponse = &models.Short2LongResponse{} 133 | 134 | defer func(){ 135 | if err := recover();err != nil{ 136 | beego.Error("panic err:",err) 137 | resp.Code = 500 138 | resp.Message = "server busy" 139 | c.Data["json"] = resp 140 | c.ServeJSON() 141 | return 142 | } 143 | }() 144 | 145 | 146 | err := json.Unmarshal(c.Ctx.Input.RequestBody,&req) 147 | if err != nil{ 148 | beego.Error("unmarshal failed,err:",err) 149 | resp.Code = 1001 150 | resp.Message = "json unmarshal failed" 151 | c.Data["json"] = resp 152 | c.ServeJSON() 153 | return 154 | } 155 | resp,err = Short2Long(&req) 156 | if err != nil{ 157 | beego.Error("Short2Long failed,err:",err) 158 | resp.Code = 1002 159 | resp.Message = "long2short failed" 160 | c.Data["json"] = resp 161 | c.ServeJSON() 162 | return 163 | } 164 | c.Data["json"] = resp 165 | c.ServeJSON() 166 | } 167 | 168 | 169 | 170 | func Long2Short(req *models.Long2ShortRequest) (response *models.Long2ShortResponse, err error) { 171 | response = &models.Long2ShortResponse{} 172 | urlMd5 := fmt.Sprintf("%x",md5.Sum([]byte(req.OriginUrl))) 173 | var short ShortUrl 174 | err = Db.Get(&short,"select id,short_url,origin_url,hash_code from short_url where hash_code=?",urlMd5) 175 | if err == sql.ErrNoRows{ 176 | err = nil 177 | // 数据库中没有记录,重新生成一个新的短url 178 | shortUrl,errRet := generateShortUrl(req,urlMd5) 179 | if errRet != nil{ 180 | err = errRet 181 | return 182 | } 183 | response.ShortUrl = shortUrlt 184 | return 185 | } 186 | if err != nil{ 187 | return 188 | } 189 | response.ShortUrl = short.ShortUrl 190 | return 191 | } 192 | 193 | func generateShortUrl(req *models.Long2ShortRequest,hashcode string)(shortUrl string,err error){ 194 | result,err := Db.Exec("insert INTO short_url(origin_url,hash_code)VALUES (?,?)",req.OriginUrl,hashcode) 195 | if err != nil{ 196 | return 197 | } 198 | // 0-9a-zA-Z 六十二进制 199 | insertId,_:= result.LastInsertId() 200 | shortUrl = transTo62(insertId) 201 | _,err = Db.Exec("update short_url set short_url=? where id=?",shortUrl,insertId) 202 | if err != nil{ 203 | fmt.Println(err) 204 | return 205 | } 206 | return 207 | } 208 | 209 | // 将十进制转换为62进制 0-9a-zA-Z 六十二进制 210 | func transTo62(id int64)string{ 211 | // 1 -- > 1 212 | // 10-- > a 213 | // 61-- > Z 214 | charset := "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ" 215 | var shortUrl []byte 216 | for{ 217 | var result byte 218 | number := id % 62 219 | result = charset[number] 220 | var tmp []byte 221 | tmp = append(tmp,result) 222 | shortUrl = append(tmp,shortUrl...) 223 | id = id / 62 224 | if id == 0{ 225 | break 226 | } 227 | } 228 | fmt.Println(string(shortUrl)) 229 | return string(shortUrl) 230 | } 231 | 232 | 233 | func Short2Long(req *models.Short2LongRequest) (response *models.Short2LongResponse, err error) { 234 | response = &models.Short2LongResponse{} 235 | var short ShortUrl 236 | err = Db.Get(&short,"select id,short_url,origin_url,hash_code from short_url where short_url=?",req.ShortUrl) 237 | if err == sql.ErrNoRows{ 238 | response.Code = 404 239 | return 240 | } 241 | if err != nil{ 242 | response.Code = 500 243 | return 244 | } 245 | response.OriginUrl = short.OriginUrl 246 | return 247 | } 248 | 249 | 250 | func GetLastShortUrl(limit int)(result []*models.ShortUrl,err error){ 251 | err = Db.Select(&result,"select short_url from short_url ORDER BY id DESC limit ? ",limit) 252 | return 253 | } -------------------------------------------------------------------------------- /beego_short_url/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | _ "beego_short_url/routers" 5 | "github.com/astaxie/beego" 6 | ) 7 | 8 | func main() { 9 | beego.Run() 10 | } 11 | 12 | -------------------------------------------------------------------------------- /beego_short_url/models/data.go: -------------------------------------------------------------------------------- 1 | package models 2 | 3 | 4 | type Long2ShortRequest struct { 5 | OriginUrl string `json:"origin_url"` 6 | } 7 | 8 | type ResponseHeader struct { 9 | Code int `json:"code"` 10 | Message string `json:"message"` 11 | } 12 | 13 | type Long2ShortResponse struct { 14 | ResponseHeader 15 | ShortUrl string `json:"short_url"` 16 | } 17 | 18 | type Short2LongRequest struct { 19 | ShortUrl string `json:"short_url"` 20 | } 21 | 22 | type Short2LongResponse struct { 23 | ResponseHeader 24 | OriginUrl string `json:"origin_url"` 25 | } 26 | 27 | type ShortUrl struct { 28 | ShortUrl string `json:"short_url" db:"short_url"` 29 | } 30 | 31 | 32 | -------------------------------------------------------------------------------- /beego_short_url/routers/router.go: -------------------------------------------------------------------------------- 1 | package routers 2 | 3 | import ( 4 | "beego_short_url/controllers" 5 | "github.com/astaxie/beego" 6 | ) 7 | 8 | func init() { 9 | err := controllers.InitDb() 10 | if err != nil{ 11 | beego.Error("init db is error:",err) 12 | } 13 | beego.Router("/trans/long2short", &controllers.ShortUrlController{},"post:Long2Short") 14 | beego.Router("/trans/short2long", &controllers.ShortUrlController{},"post:Short2Long") 15 | beego.Router("/shorturl", &controllers.ShortUrlController{},"get:ShortUrlList") 16 | beego.Router("/jump", &controllers.ShortUrlController{},"get:Jump") 17 | 18 | } 19 | -------------------------------------------------------------------------------- /beego_short_url/static/js/reload.min.js: -------------------------------------------------------------------------------- 1 | function b(a){var c=new WebSocket(a);c.onclose=function(){setTimeout(function(){b(a)},2E3)};c.onmessage=function(){location.reload()}}try{if(window.WebSocket)try{b("ws://localhost:12450/reload")}catch(a){console.error(a)}else console.log("Your browser does not support WebSockets.")}catch(a){console.error("Exception during connecting to Reload:",a)}; 2 | -------------------------------------------------------------------------------- /beego_short_url/tests/default_test.go: -------------------------------------------------------------------------------- 1 | package test 2 | 3 | import ( 4 | "net/http" 5 | "net/http/httptest" 6 | "testing" 7 | "runtime" 8 | "path/filepath" 9 | _ "beego_short_url/routers" 10 | 11 | "github.com/astaxie/beego" 12 | . "github.com/smartystreets/goconvey/convey" 13 | ) 14 | 15 | func init() { 16 | _, file, _, _ := runtime.Caller(1) 17 | apppath, _ := filepath.Abs(filepath.Dir(filepath.Join(file, ".." + string(filepath.Separator)))) 18 | beego.TestBeegoInit(apppath) 19 | } 20 | 21 | 22 | // TestBeego is a sample to run an endpoint test 23 | func TestBeego(t *testing.T) { 24 | r, _ := http.NewRequest("GET", "/", nil) 25 | w := httptest.NewRecorder() 26 | beego.BeeApp.Handlers.ServeHTTP(w, r) 27 | 28 | beego.Trace("testing", "TestBeego", "Code[%d]\n%s", w.Code, w.Body.String()) 29 | 30 | Convey("Subject: Test Station Endpoint\n", t, func() { 31 | Convey("Status Code Should Be 200", func() { 32 | So(w.Code, ShouldEqual, 200) 33 | }) 34 | Convey("The Result Should Not Be Empty", func() { 35 | So(w.Body.Len(), ShouldBeGreaterThan, 0) 36 | }) 37 | }) 38 | } 39 | 40 | -------------------------------------------------------------------------------- /beego_short_url/views/index.tpl: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | {{range .url_list}} 11 | 12 | 13 | 14 | 15 | {{end}} 16 |
shorturl: {{.ShortUrl}}
17 | 18 | 19 | -------------------------------------------------------------------------------- /book_mgr_v1/api/api.go: -------------------------------------------------------------------------------- 1 | // api的主要处理逻辑 2 | package main 3 | 4 | import ( 5 | "net/http" 6 | "go_dev/06/book_mgr_v1/logic" 7 | "strconv" 8 | "encoding/json" 9 | ) 10 | 11 | 12 | var ( 13 | bookMgr *logic.BookMgr 14 | studentMgr *logic.StudentMgr 15 | ) 16 | 17 | func init(){ 18 | bookMgr = logic.NewBookMgr() 19 | studentMgr = logic.NewStudentMgr() 20 | } 21 | 22 | func responseError(w http.ResponseWriter,code int){ 23 | m := make(map[string]interface{},16) 24 | m["code"] = code 25 | m["message"] = getMessage(code) 26 | data,err := json.Marshal(m) 27 | if err != nil{ 28 | w.Write([]byte("{\"code\":500,\"message\":\"server busy\"}")) 29 | return 30 | } 31 | w.Write(data) 32 | } 33 | 34 | func responseSuccess(w http.ResponseWriter,code int,data interface{}){ 35 | m := make(map[string]interface{},16) 36 | m["code"] = code 37 | m["message"] = getMessage(code) 38 | m["data"] = data 39 | 40 | 41 | dataByte,err := json.Marshal(m) 42 | if err != nil{ 43 | w.Write([]byte("{\"code\":500,\"message\":\"server busy\"}")) 44 | return 45 | } 46 | w.Write(dataByte) 47 | } 48 | 49 | func addBook(w http.ResponseWriter,r *http.Request){ 50 | r.ParseForm() 51 | bookId := r.FormValue("book_id") 52 | name := r.FormValue("name") 53 | numStr := r.FormValue("num") 54 | author := r.FormValue("author") 55 | publishDateStr := r.FormValue("publish") 56 | 57 | num ,err := strconv.Atoi(numStr) 58 | if err != nil{ 59 | responseError(w,ErrInvalidParameter) 60 | return 61 | } 62 | 63 | publishDate ,err := strconv.Atoi(publishDateStr) 64 | if err != nil{ 65 | responseError(w,ErrInvalidParameter) 66 | return 67 | } 68 | 69 | if len(name) == 0 || len(author) == 0 || len(bookId) == 0{ 70 | responseError(w,ErrInvalidParameter) 71 | return 72 | } 73 | 74 | book := logic.NewBook(bookId,name,num,author,int64(publishDate)) 75 | err = bookMgr.AddBook(book) 76 | if err != nil{ 77 | responseError(w,ErrServerBusy) 78 | return 79 | } 80 | responseSuccess(w,ErrSuccess,nil) 81 | } 82 | 83 | func searchBookName(w http.ResponseWriter,r *http.Request){ 84 | r.ParseForm() 85 | 86 | name := r.FormValue("name") 87 | 88 | 89 | 90 | if len(name) == 0 { 91 | responseError(w,ErrInvalidParameter) 92 | return 93 | } 94 | 95 | bookList := bookMgr.SearchByBookName(name) 96 | 97 | responseSuccess(w,ErrSuccess,bookList) 98 | } 99 | 100 | func searchBookAuthor(w http.ResponseWriter,r *http.Request){ 101 | r.ParseForm() 102 | 103 | author := r.FormValue("author") 104 | 105 | 106 | 107 | if len(author) == 0 { 108 | responseError(w,ErrInvalidParameter) 109 | return 110 | } 111 | 112 | bookList := bookMgr.SearchByAuthor(author) 113 | 114 | responseSuccess(w,ErrSuccess,bookList) 115 | } 116 | 117 | func addStudent(w http.ResponseWriter,r *http.Request){ 118 | r.ParseForm() 119 | idStr := r.FormValue("id") 120 | name := r.FormValue("name") 121 | gradeStr := r.FormValue("grade") 122 | identify := r.FormValue("identify") 123 | sexStr := r.FormValue("sex") 124 | 125 | id,err := strconv.Atoi(idStr) 126 | if err != nil{ 127 | responseError(w,ErrInvalidParameter) 128 | return 129 | } 130 | grade,err := strconv.Atoi(gradeStr) 131 | if err != nil{ 132 | responseError(w,ErrInvalidParameter) 133 | return 134 | } 135 | 136 | sex,err := strconv.Atoi(sexStr) 137 | if err != nil{ 138 | responseError(w,ErrInvalidParameter) 139 | return 140 | } 141 | 142 | if len(name) == 0 || (sex != 0 && sex != 1)|| len(identify) == 0{ 143 | responseError(w,ErrInvalidParameter) 144 | return 145 | } 146 | 147 | stu := logic.NewStudent(id,name,grade,identify,sex) 148 | err = studentMgr.AddStudent(stu) 149 | if err != nil{ 150 | responseError(w,ErrServerBusy) 151 | return 152 | } 153 | responseSuccess(w,ErrSuccess,nil) 154 | } 155 | 156 | func borrow(w http.ResponseWriter,r *http.Request){ 157 | r.ParseForm() 158 | 159 | sidStr := r.FormValue("sid") 160 | bid := r.FormValue("bid") 161 | sid ,err := strconv.Atoi(sidStr) 162 | if err != nil{ 163 | responseError(w,ErrInvalidParameter) 164 | return 165 | } 166 | 167 | if len(bid) == 0{ 168 | responseError(w,ErrInvalidParameter) 169 | return 170 | } 171 | 172 | student,err := studentMgr.GetStudentByid(sid) 173 | if err != nil{ 174 | responseError(w,ErrInvalidParameter) 175 | return 176 | } 177 | err = bookMgr.Borrow(student,bid) 178 | if err != nil{ 179 | responseError(w,ErrInvalidParameter) 180 | return 181 | } 182 | 183 | responseSuccess(w,ErrSuccess,nil) 184 | } 185 | 186 | func bookList(w http.ResponseWriter,r *http.Request){ 187 | r.ParseForm() 188 | sidStr := r.FormValue("sid") 189 | sid ,err := strconv.Atoi(sidStr) 190 | if err != nil{ 191 | responseError(w,ErrInvalidParameter) 192 | return 193 | } 194 | bookList,err := studentMgr.GetStudentBorrowBooks(sid) 195 | if err != nil{ 196 | responseError(w,ErrInvalidParameter) 197 | return 198 | } 199 | 200 | responseSuccess(w,ErrSuccess,bookList) 201 | } 202 | 203 | func main(){ 204 | http.HandleFunc("/book/add",addBook) 205 | http.HandleFunc("/book/searchName",searchBookName) 206 | http.HandleFunc("/book/searchAuthor",searchBookAuthor) 207 | http.HandleFunc("/student/add",addStudent) 208 | http.HandleFunc("/student/borrow",borrow) 209 | http.HandleFunc("/student/bookList",bookList) 210 | 211 | http.ListenAndServe(":8080",nil) 212 | 213 | } -------------------------------------------------------------------------------- /book_mgr_v1/api/error_code.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | 4 | 5 | const( 6 | ErrSuccess = 0 7 | ErrInvalidParameter = 1001 8 | ErrServerBusy = 1002 9 | 10 | ) 11 | 12 | func getMessage(code int)(msg string){ 13 | switch code{ 14 | case ErrSuccess: 15 | msg = "success" 16 | case ErrInvalidParameter: 17 | msg = "invalid parameter" 18 | case ErrServerBusy: 19 | msg = "server busy" 20 | default: 21 | msg = "unknown error" 22 | } 23 | return 24 | } 25 | -------------------------------------------------------------------------------- /book_mgr_v1/logic/book.go: -------------------------------------------------------------------------------- 1 | // 关于书籍的处理逻辑 2 | 3 | package logic 4 | 5 | import ( 6 | "errors" 7 | "sync" 8 | ) 9 | 10 | // 定义一个书的结构体,包含名字,数量,作者和出版日期 11 | type Book struct { 12 | BookId string 13 | Name string 14 | Num int 15 | Author string 16 | PublishDate int64 17 | Lock sync.Mutex 18 | } 19 | 20 | // 这里是一个构造函数 21 | func NewBook(bookId,name string,num int,author string,publishDate int64)(book *Book){ 22 | book = &Book{ 23 | BookId:bookId, 24 | Name:name, 25 | Num:num, 26 | Author:author, 27 | PublishDate:publishDate, 28 | } 29 | return 30 | } 31 | 32 | // 借书 33 | func(b *Book) Borrow()(err error){ 34 | b.Lock.Lock() 35 | defer b.Lock.Unlock() 36 | if b.Num <= 0{ 37 | err = errors.New("book is not enough") 38 | return 39 | } 40 | b.Num -= 1 41 | 42 | return 43 | } 44 | 45 | // 还书 46 | func (b*Book) Back()(err error){ 47 | b.Lock.Lock() 48 | defer b.Lock.Lock() 49 | b.Num +=1 50 | return 51 | } 52 | 53 | -------------------------------------------------------------------------------- /book_mgr_v1/logic/book_mgr.go: -------------------------------------------------------------------------------- 1 | // 书籍管理的处理逻辑 2 | 3 | package logic 4 | 5 | import ( 6 | "sync" 7 | "fmt" 8 | ) 9 | 10 | type BookMgr struct { 11 | BookList []*Book 12 | // 存储bookid 到借书学生的列表 13 | BookStudentMap map[string][]*Student 14 | // 书籍名字到书籍的索引 15 | BookNameMap map[string][]*Book 16 | // 书籍作者到书籍的索引 17 | BookAuthorMap map[string][]*Book 18 | Lock sync.Mutex 19 | 20 | } 21 | 22 | // 这里是一个构造函数 23 | func NewBookMgr()(bookmgr*BookMgr){ 24 | bookmgr = &BookMgr{ 25 | BookStudentMap:make(map[string][]*Student,32), 26 | BookNameMap:make(map[string][]*Book), 27 | BookAuthorMap:make(map[string][]*Book,32), 28 | } 29 | return 30 | } 31 | 32 | // 添加书籍 33 | func (b *BookMgr) AddBook(book *Book)(err error){ 34 | b.Lock.Lock() 35 | defer b.Lock.Unlock() 36 | // 添加到book列表中 37 | b.BookList = append(b.BookList,book) 38 | // 更新书籍名字到同一个书籍名字对应的book列表 39 | bookList,ok := b.BookNameMap[book.Name] 40 | if !ok{ 41 | var tmp []*Book 42 | tmp = append(tmp,book) 43 | bookList = tmp 44 | }else{ 45 | bookList = append(bookList,book) 46 | } 47 | b.BookNameMap[book.Name] = bookList 48 | 49 | // 更新数据作者到同一个作者对应的book列表 50 | bookList,ok = b.BookAuthorMap[book.Author] 51 | if !ok{ 52 | var tmp []*Book 53 | tmp = append(tmp,book) 54 | bookList = tmp 55 | }else{ 56 | bookList = append(bookList,book) 57 | } 58 | b.BookAuthorMap[book.Author] = bookList 59 | 60 | 61 | return 62 | } 63 | 64 | // 通过书籍名字查找 65 | func (b *BookMgr) SearchByBookName(bookName string)(bookList []*Book){ 66 | b.Lock.Lock() 67 | b.Lock.Unlock() 68 | bookList = b.BookNameMap[bookName] 69 | return 70 | } 71 | 72 | // 通过书籍作者查找 73 | func (b *BookMgr) SearchByAuthor(Author string)(bookList []*Book){ 74 | b.Lock.Lock() 75 | b.Lock.Unlock() 76 | bookList = b.BookAuthorMap[Author] 77 | return 78 | } 79 | 80 | // 通过书籍出版日期查找,这里的参数是一个范围 81 | func (b *BookMgr) SearchByPushlish(min int64,max int64)(bookList []*Book){ 82 | b.Lock.Lock() 83 | b.Lock.Unlock() 84 | for _,v:= range b.BookList{ 85 | if v.PublishDate >= min && v.PublishDate <= max{ 86 | bookList = append(bookList,v) 87 | } 88 | } 89 | return 90 | } 91 | 92 | // 用于学生借书 93 | func (b *BookMgr) Borrow(student *Student,bookId string) (err error){ 94 | b.Lock.Lock() 95 | defer b.Lock.Unlock() 96 | var book *Book 97 | for _,v := range b.BookList{ 98 | if v.BookId == bookId{ 99 | book = v 100 | break 101 | } 102 | } 103 | if book == nil{ 104 | err = fmt.Errorf("book id [%d] is not exist",bookId) 105 | return 106 | } 107 | err = book.Borrow() 108 | if err != nil{ 109 | return 110 | } 111 | student.AddBook(book) 112 | return 113 | } 114 | 115 | 116 | -------------------------------------------------------------------------------- /book_mgr_v1/logic/student.go: -------------------------------------------------------------------------------- 1 | // 学生的处理逻辑 2 | package logic 3 | 4 | import ( 5 | "sync" 6 | "fmt" 7 | ) 8 | 9 | type Student struct { 10 | Id int 11 | Name string 12 | Grade int 13 | Identify string 14 | Sex int 15 | BookMap map[string]*Book 16 | Lock sync.Mutex //互斥锁 17 | } 18 | 19 | // 学生的构造函数 20 | func NewStudent(id int,name string,grade int,identify string,sex int)(stu *Student){ 21 | stu = &Student{ 22 | Id:id, 23 | Name:name, 24 | Grade:grade, 25 | Identify:identify, 26 | Sex:sex, 27 | BookMap:make(map[string]*Book,32), 28 | } 29 | return 30 | } 31 | 32 | // 学生添加书籍 33 | func (s *Student) AddBook(b *Book){ 34 | s.Lock.Lock() 35 | defer s.Lock.Unlock() 36 | s.BookMap[b.BookId]=b 37 | return 38 | } 39 | 40 | // 学生还书 41 | func (s *Student) BackBook(bookId string)(err error){ 42 | s.Lock.Lock() 43 | defer s.Lock.Unlock() 44 | _,ok := s.BookMap[bookId] 45 | if !ok{ 46 | // 格式化输出错误 47 | err = fmt.Errorf("student id:%d not exist book book_id:%s",s.Id,bookId) 48 | return 49 | } 50 | delete(s.BookMap,bookId) 51 | return 52 | } 53 | 54 | // 获取学生借的书籍 55 | func (s *Student) GetBookList()(bookList[]*Book){ 56 | s.Lock.Lock() 57 | defer s.Lock.Unlock() 58 | for _,v := range s.BookMap{ 59 | bookList = append(bookList,v) 60 | } 61 | return 62 | } -------------------------------------------------------------------------------- /book_mgr_v1/logic/student_mgr.go: -------------------------------------------------------------------------------- 1 | // 学生管理的处理逻辑 2 | package logic 3 | 4 | import ( 5 | "sync" 6 | "fmt" 7 | ) 8 | 9 | type StudentMgr struct { 10 | // 学生id对应student map 11 | StudentMap map[int]*Student 12 | Lock sync.Mutex 13 | } 14 | 15 | // 学生管理的构造函数 16 | func NewStudentMgr()(*StudentMgr){ 17 | return &StudentMgr{ 18 | StudentMap:make(map[int]*Student,32), 19 | } 20 | } 21 | 22 | // 添加学生 23 | func (s *StudentMgr) AddStudent(stu *Student)(err error){ 24 | s.Lock.Lock() 25 | defer s.Lock.Unlock() 26 | s.StudentMap[stu.Id] = stu 27 | return 28 | } 29 | 30 | // 根据学生id查询学生的信息 31 | func (s *StudentMgr) GetStudentByid(id int)(stu *Student,err error){ 32 | s.Lock.Lock() 33 | defer s.Lock.Unlock() 34 | 35 | stu,ok:=s.StudentMap[id] 36 | if !ok{ 37 | err = fmt.Errorf("student id %d is not exists",id) 38 | return 39 | } 40 | return 41 | } 42 | 43 | // 获取学生的借的书籍信息 44 | func (s *StudentMgr) GetStudentBorrowBooks(id int)(bookList []*Book,err error){ 45 | stu,err := s.GetStudentByid(id) 46 | if err != nil{ 47 | return 48 | } 49 | bookList = stu.GetBookList() 50 | return 51 | } -------------------------------------------------------------------------------- /book_mgr_v2/api/api.go: -------------------------------------------------------------------------------- 1 | // api的主要处理逻辑 2 | package main 3 | 4 | import ( 5 | "net/http" 6 | "go_dev/07/book_mgr_v2/logic" 7 | "strconv" 8 | "encoding/json" 9 | "fmt" 10 | ) 11 | 12 | 13 | var ( 14 | bookMgr *logic.BookMgr 15 | studentMgr *logic.StudentMgr 16 | ) 17 | 18 | func init(){ 19 | bookMgr = logic.NewBookMgr() 20 | studentMgr = logic.NewStudentMgr() 21 | } 22 | 23 | func responseError(w http.ResponseWriter,code int){ 24 | m := make(map[string]interface{},16) 25 | m["code"] = code 26 | m["message"] = getMessage(code) 27 | data,err := json.Marshal(m) 28 | if err != nil{ 29 | w.Write([]byte("{\"code\":500,\"message\":\"server busy\"}")) 30 | return 31 | } 32 | w.Write(data) 33 | } 34 | 35 | func responseSuccess(w http.ResponseWriter,code int,data interface{}){ 36 | m := make(map[string]interface{},16) 37 | m["code"] = code 38 | m["message"] = getMessage(code) 39 | m["data"] = data 40 | 41 | 42 | dataByte,err := json.Marshal(m) 43 | if err != nil{ 44 | w.Write([]byte("{\"code\":500,\"message\":\"server busy\"}")) 45 | return 46 | } 47 | w.Write(dataByte) 48 | } 49 | 50 | func addBook(w http.ResponseWriter,r *http.Request){ 51 | r.ParseForm() 52 | bookId := r.FormValue("book_id") 53 | name := r.FormValue("name") 54 | numStr := r.FormValue("num") 55 | author := r.FormValue("author") 56 | publishDateStr := r.FormValue("publish") 57 | 58 | num ,err := strconv.Atoi(numStr) 59 | if err != nil{ 60 | responseError(w,ErrInvalidParameter) 61 | return 62 | } 63 | 64 | publishDate ,err := strconv.Atoi(publishDateStr) 65 | if err != nil{ 66 | responseError(w,ErrInvalidParameter) 67 | return 68 | } 69 | 70 | if len(name) == 0 || len(author) == 0 || len(bookId) == 0{ 71 | responseError(w,ErrInvalidParameter) 72 | return 73 | } 74 | 75 | book := logic.NewBook(bookId,name,num,author,int64(publishDate)) 76 | err = bookMgr.AddBook(book) 77 | if err != nil{ 78 | responseError(w,ErrServerBusy) 79 | return 80 | } 81 | responseSuccess(w,ErrSuccess,nil) 82 | } 83 | 84 | func searchBookName(w http.ResponseWriter,r *http.Request){ 85 | r.ParseForm() 86 | 87 | name := r.FormValue("name") 88 | 89 | 90 | 91 | if len(name) == 0 { 92 | responseError(w,ErrInvalidParameter) 93 | return 94 | } 95 | 96 | bookList := bookMgr.SearchByBookName(name) 97 | 98 | responseSuccess(w,ErrSuccess,bookList) 99 | } 100 | 101 | func searchBookAuthor(w http.ResponseWriter,r *http.Request){ 102 | r.ParseForm() 103 | 104 | author := r.FormValue("author") 105 | 106 | 107 | 108 | if len(author) == 0 { 109 | responseError(w,ErrInvalidParameter) 110 | return 111 | } 112 | 113 | bookList := bookMgr.SearchByAuthor(author) 114 | 115 | responseSuccess(w,ErrSuccess,bookList) 116 | } 117 | 118 | func addStudent(w http.ResponseWriter,r *http.Request){ 119 | r.ParseForm() 120 | idStr := r.FormValue("id") 121 | name := r.FormValue("name") 122 | gradeStr := r.FormValue("grade") 123 | identify := r.FormValue("identify") 124 | sexStr := r.FormValue("sex") 125 | 126 | id,err := strconv.Atoi(idStr) 127 | if err != nil{ 128 | responseError(w,ErrInvalidParameter) 129 | return 130 | } 131 | grade,err := strconv.Atoi(gradeStr) 132 | if err != nil{ 133 | responseError(w,ErrInvalidParameter) 134 | return 135 | } 136 | 137 | sex,err := strconv.Atoi(sexStr) 138 | if err != nil{ 139 | responseError(w,ErrInvalidParameter) 140 | return 141 | } 142 | 143 | if len(name) == 0 || (sex != 0 && sex != 1)|| len(identify) == 0{ 144 | responseError(w,ErrInvalidParameter) 145 | return 146 | } 147 | 148 | stu := logic.NewStudent(id,name,grade,identify,sex) 149 | err = studentMgr.AddStudent(stu) 150 | if err != nil{ 151 | responseError(w,ErrServerBusy) 152 | return 153 | } 154 | responseSuccess(w,ErrSuccess,nil) 155 | } 156 | 157 | func borrow(w http.ResponseWriter,r *http.Request){ 158 | r.ParseForm() 159 | 160 | sidStr := r.FormValue("sid") 161 | bid := r.FormValue("bid") 162 | sid ,err := strconv.Atoi(sidStr) 163 | if err != nil{ 164 | responseError(w,ErrInvalidParameter) 165 | return 166 | } 167 | 168 | if len(bid) == 0{ 169 | responseError(w,ErrInvalidParameter) 170 | return 171 | } 172 | 173 | student,err := studentMgr.GetStudentByid(sid) 174 | if err != nil{ 175 | responseError(w,ErrInvalidParameter) 176 | return 177 | } 178 | err = bookMgr.Borrow(student,bid) 179 | if err != nil{ 180 | responseError(w,ErrInvalidParameter) 181 | return 182 | } 183 | 184 | responseSuccess(w,ErrSuccess,nil) 185 | } 186 | 187 | func bookList(w http.ResponseWriter,r *http.Request){ 188 | r.ParseForm() 189 | sidStr := r.FormValue("sid") 190 | sid ,err := strconv.Atoi(sidStr) 191 | if err != nil{ 192 | responseError(w,ErrInvalidParameter) 193 | return 194 | } 195 | bookList,err := studentMgr.GetStudentBorrowBooks(sid) 196 | if err != nil{ 197 | responseError(w,ErrInvalidParameter) 198 | return 199 | } 200 | 201 | responseSuccess(w,ErrSuccess,bookList) 202 | } 203 | 204 | func getTop10(w http.ResponseWriter,r *http.Request){ 205 | 206 | bookList := bookMgr.GetTop10() 207 | 208 | responseSuccess(w,ErrSuccess,bookList) 209 | } 210 | 211 | func main(){ 212 | http.HandleFunc("/book/add",addBook) 213 | http.HandleFunc("/book/searchName",searchBookName) 214 | http.HandleFunc("/book/searchAuthor",searchBookAuthor) 215 | http.HandleFunc("/student/add",addStudent) 216 | http.HandleFunc("/student/borrow",borrow) 217 | http.HandleFunc("/student/bookList",bookList) 218 | http.HandleFunc("/book/",getTop10) 219 | 220 | err := http.ListenAndServe(":8080",nil) 221 | if err != nil{ 222 | fmt.Println("server start failed,err is",err) 223 | } 224 | } -------------------------------------------------------------------------------- /book_mgr_v2/api/error_code.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | 4 | 5 | const( 6 | ErrSuccess = 0 7 | ErrInvalidParameter = 1001 8 | ErrServerBusy = 1002 9 | 10 | ) 11 | 12 | func getMessage(code int)(msg string){ 13 | switch code{ 14 | case ErrSuccess: 15 | msg = "success" 16 | case ErrInvalidParameter: 17 | msg = "invalid parameter" 18 | case ErrServerBusy: 19 | msg = "server busy" 20 | default: 21 | msg = "unknown error" 22 | } 23 | return 24 | } 25 | -------------------------------------------------------------------------------- /book_mgr_v2/logic/book.go: -------------------------------------------------------------------------------- 1 | // 关于书籍的处理逻辑 2 | 3 | package logic 4 | 5 | import ( 6 | "errors" 7 | "sync" 8 | ) 9 | 10 | // 定义一个书的结构体,包含名字,数量,作者和出版日期 11 | type Book struct { 12 | BookId string 13 | Name string 14 | Num int 15 | Author string 16 | PublishDate int64 17 | BorrowCount int 18 | Lock sync.Mutex 19 | } 20 | 21 | // 这里是一个构造函数 22 | func NewBook(bookId,name string,num int,author string,publishDate int64)(book *Book){ 23 | book = &Book{ 24 | BookId:bookId, 25 | Name:name, 26 | Num:num, 27 | Author:author, 28 | PublishDate:publishDate, 29 | } 30 | return 31 | } 32 | 33 | // 借书 34 | func(b *Book) Borrow()(err error){ 35 | b.Lock.Lock() 36 | defer b.Lock.Unlock() 37 | if b.Num <= 0{ 38 | err = errors.New("book is not enough") 39 | return 40 | } 41 | b.Num -= 1 42 | b.BorrowCount += 1 43 | return 44 | } 45 | 46 | // 还书 47 | func (b*Book) Back()(err error){ 48 | b.Lock.Lock() 49 | defer b.Lock.Lock() 50 | b.Num +=1 51 | return 52 | } 53 | 54 | -------------------------------------------------------------------------------- /book_mgr_v2/logic/book_mgr.go: -------------------------------------------------------------------------------- 1 | // 书籍管理的处理逻辑 2 | 3 | package logic 4 | 5 | import ( 6 | "sync" 7 | "fmt" 8 | "sort" 9 | ) 10 | 11 | type BookMgr struct { 12 | BookList []*Book 13 | // 存储bookid 到借书学生的列表 14 | BookStudentMap map[string][]*Student 15 | // 书籍名字到书籍的索引 16 | BookNameMap map[string][]*Book 17 | // 书籍作者到书籍的索引 18 | BookAuthorMap map[string][]*Book 19 | Lock sync.Mutex 20 | 21 | } 22 | 23 | // 这里是一个构造函数 24 | func NewBookMgr()(bookmgr*BookMgr){ 25 | bookmgr = &BookMgr{ 26 | BookStudentMap:make(map[string][]*Student,32), 27 | BookNameMap:make(map[string][]*Book), 28 | BookAuthorMap:make(map[string][]*Book,32), 29 | } 30 | return 31 | } 32 | 33 | // 添加书籍 34 | func (b *BookMgr) AddBook(book *Book)(err error){ 35 | b.Lock.Lock() 36 | defer b.Lock.Unlock() 37 | // 添加到book列表中 38 | b.BookList = append(b.BookList,book) 39 | // 更新书籍名字到同一个书籍名字对应的book列表 40 | bookList,ok := b.BookNameMap[book.Name] 41 | if !ok{ 42 | var tmp []*Book 43 | tmp = append(tmp,book) 44 | bookList = tmp 45 | }else{ 46 | bookList = append(bookList,book) 47 | } 48 | b.BookNameMap[book.Name] = bookList 49 | 50 | // 更新数据作者到同一个作者对应的book列表 51 | bookList,ok = b.BookAuthorMap[book.Author] 52 | if !ok{ 53 | var tmp []*Book 54 | tmp = append(tmp,book) 55 | bookList = tmp 56 | }else{ 57 | bookList = append(bookList,book) 58 | } 59 | b.BookAuthorMap[book.Author] = bookList 60 | 61 | 62 | return 63 | } 64 | 65 | // 通过书籍名字查找 66 | func (b *BookMgr) SearchByBookName(bookName string)(bookList []*Book){ 67 | b.Lock.Lock() 68 | b.Lock.Unlock() 69 | bookList = b.BookNameMap[bookName] 70 | return 71 | } 72 | 73 | // 通过书籍作者查找 74 | func (b *BookMgr) SearchByAuthor(Author string)(bookList []*Book){ 75 | b.Lock.Lock() 76 | b.Lock.Unlock() 77 | bookList = b.BookAuthorMap[Author] 78 | return 79 | } 80 | 81 | // 通过书籍出版日期查找,这里的参数是一个范围 82 | func (b *BookMgr) SearchByPushlish(min int64,max int64)(bookList []*Book){ 83 | b.Lock.Lock() 84 | b.Lock.Unlock() 85 | for _,v:= range b.BookList{ 86 | if v.PublishDate >= min && v.PublishDate <= max{ 87 | bookList = append(bookList,v) 88 | } 89 | } 90 | return 91 | } 92 | 93 | // 用于学生借书 94 | func (b *BookMgr) Borrow(student *Student,bookId string) (err error){ 95 | b.Lock.Lock() 96 | defer b.Lock.Unlock() 97 | var book *Book 98 | for _,v := range b.BookList{ 99 | if v.BookId == bookId{ 100 | book = v 101 | break 102 | } 103 | } 104 | if book == nil{ 105 | err = fmt.Errorf("book id [%d] is not exist",bookId) 106 | return 107 | } 108 | err = book.Borrow() 109 | if err != nil{ 110 | return 111 | } 112 | student.AddBook(book) 113 | return 114 | } 115 | 116 | // 这里实现了Len() Less() Swap()后就实现sort中的Interface接口,就可以调用sort.Sort方法 117 | func (b *BookMgr) Len() int{ 118 | return len(b.BookList) 119 | } 120 | 121 | // 如果是>是从大到小排序,如果是< 则是从小到大排序 122 | func (b *BookMgr) Less(i,j int) bool{ 123 | return b.BookList[i].BorrowCount > b.BookList[j].BorrowCount 124 | } 125 | 126 | func (b *BookMgr) Swap(i,j int){ 127 | b.BookList[i],b.BookList[j]= b.BookList[j],b.BookList[i] 128 | } 129 | 130 | // 获取top10 131 | func (b *BookMgr) GetTop10()(bookList []*Book){ 132 | sort.Sort(b) 133 | for i :=0;i<10;i++{ 134 | if i >= len(b.BookList){ 135 | break 136 | } 137 | bookList = append(bookList,b.BookList[i]) 138 | 139 | } 140 | return 141 | } 142 | 143 | -------------------------------------------------------------------------------- /book_mgr_v2/logic/student.go: -------------------------------------------------------------------------------- 1 | // 学生的处理逻辑 2 | package logic 3 | 4 | import ( 5 | "sync" 6 | "fmt" 7 | ) 8 | 9 | type Student struct { 10 | Id int 11 | Name string 12 | Grade int 13 | Identify string 14 | Sex int 15 | BookMap map[string]*Book 16 | Lock sync.Mutex //互斥锁 17 | } 18 | 19 | // 学生的构造函数 20 | func NewStudent(id int,name string,grade int,identify string,sex int)(stu *Student){ 21 | stu = &Student{ 22 | Id:id, 23 | Name:name, 24 | Grade:grade, 25 | Identify:identify, 26 | Sex:sex, 27 | BookMap:make(map[string]*Book,32), 28 | } 29 | return 30 | } 31 | 32 | // 学生添加书籍 33 | func (s *Student) AddBook(b *Book){ 34 | s.Lock.Lock() 35 | defer s.Lock.Unlock() 36 | s.BookMap[b.BookId]=b 37 | return 38 | } 39 | 40 | // 学生还书 41 | func (s *Student) BackBook(bookId string)(err error){ 42 | s.Lock.Lock() 43 | defer s.Lock.Unlock() 44 | _,ok := s.BookMap[bookId] 45 | if !ok{ 46 | // 格式化输出错误 47 | err = fmt.Errorf("student id:%d not exist book book_id:%s",s.Id,bookId) 48 | return 49 | } 50 | delete(s.BookMap,bookId) 51 | return 52 | } 53 | 54 | // 获取学生借的书籍 55 | func (s *Student) GetBookList()(bookList[]*Book){ 56 | s.Lock.Lock() 57 | defer s.Lock.Unlock() 58 | for _,v := range s.BookMap{ 59 | bookList = append(bookList,v) 60 | } 61 | return 62 | } -------------------------------------------------------------------------------- /book_mgr_v2/logic/student_mgr.go: -------------------------------------------------------------------------------- 1 | // 学生管理的处理逻辑 2 | package logic 3 | 4 | import ( 5 | "sync" 6 | "fmt" 7 | ) 8 | 9 | type StudentMgr struct { 10 | // 学生id对应student map 11 | StudentMap map[int]*Student 12 | Lock sync.Mutex 13 | } 14 | 15 | // 学生管理的构造函数 16 | func NewStudentMgr()(*StudentMgr){ 17 | return &StudentMgr{ 18 | StudentMap:make(map[int]*Student,32), 19 | } 20 | } 21 | 22 | // 添加学生 23 | func (s *StudentMgr) AddStudent(stu *Student)(err error){ 24 | s.Lock.Lock() 25 | defer s.Lock.Unlock() 26 | s.StudentMap[stu.Id] = stu 27 | return 28 | } 29 | 30 | // 根据学生id查询学生的信息 31 | func (s *StudentMgr) GetStudentByid(id int)(stu *Student,err error){ 32 | s.Lock.Lock() 33 | defer s.Lock.Unlock() 34 | 35 | stu,ok:=s.StudentMap[id] 36 | if !ok{ 37 | err = fmt.Errorf("student id %d is not exists",id) 38 | return 39 | } 40 | return 41 | } 42 | 43 | // 获取学生的借的书籍信息 44 | func (s *StudentMgr) GetStudentBorrowBooks(id int)(bookList []*Book,err error){ 45 | stu,err := s.GetStudentByid(id) 46 | if err != nil{ 47 | return 48 | } 49 | bookList = stu.GetBookList() 50 | return 51 | } -------------------------------------------------------------------------------- /book_mgr_v3/api/api.go: -------------------------------------------------------------------------------- 1 | // api的主要处理逻辑 2 | package main 3 | 4 | import ( 5 | "net/http" 6 | "go_dev/08/book_mgr_v3/logic" 7 | "strconv" 8 | "encoding/json" 9 | "fmt" 10 | "time" 11 | "log" 12 | ) 13 | 14 | 15 | var ( 16 | bookMgr *logic.BookMgr 17 | studentMgr *logic.StudentMgr 18 | ) 19 | 20 | func init(){ 21 | bookMgr = logic.NewBookMgr() 22 | studentMgr = logic.NewStudentMgr() 23 | } 24 | 25 | func responseError(w http.ResponseWriter,code int){ 26 | m := make(map[string]interface{},16) 27 | m["code"] = code 28 | m["message"] = getMessage(code) 29 | data,err := json.Marshal(m) 30 | if err != nil{ 31 | w.Write([]byte("{\"code\":500,\"message\":\"server busy\"}")) 32 | return 33 | } 34 | w.Write(data) 35 | } 36 | 37 | func responseSuccess(w http.ResponseWriter,code int,data interface{}){ 38 | m := make(map[string]interface{},16) 39 | m["code"] = code 40 | m["message"] = getMessage(code) 41 | m["data"] = data 42 | 43 | 44 | dataByte,err := json.Marshal(m) 45 | if err != nil{ 46 | w.Write([]byte("{\"code\":500,\"message\":\"server busy\"}")) 47 | return 48 | } 49 | w.Write(dataByte) 50 | } 51 | 52 | func addBook(w http.ResponseWriter,r *http.Request){ 53 | r.ParseForm() 54 | bookId := r.FormValue("book_id") 55 | name := r.FormValue("name") 56 | numStr := r.FormValue("num") 57 | author := r.FormValue("author") 58 | publishDateStr := r.FormValue("publish") 59 | 60 | num ,err := strconv.Atoi(numStr) 61 | if err != nil{ 62 | responseError(w,ErrInvalidParameter) 63 | return 64 | } 65 | 66 | publishDate ,err := strconv.Atoi(publishDateStr) 67 | if err != nil{ 68 | responseError(w,ErrInvalidParameter) 69 | return 70 | } 71 | 72 | if len(name) == 0 || len(author) == 0 || len(bookId) == 0{ 73 | responseError(w,ErrInvalidParameter) 74 | return 75 | } 76 | 77 | book := logic.NewBook(bookId,name,num,author,int64(publishDate)) 78 | err = bookMgr.AddBook(book) 79 | if err != nil{ 80 | responseError(w,ErrServerBusy) 81 | return 82 | } 83 | responseSuccess(w,ErrSuccess,nil) 84 | } 85 | 86 | func searchBookName(w http.ResponseWriter,r *http.Request){ 87 | r.ParseForm() 88 | 89 | name := r.FormValue("name") 90 | 91 | 92 | 93 | if len(name) == 0 { 94 | responseError(w,ErrInvalidParameter) 95 | return 96 | } 97 | 98 | bookList := bookMgr.SearchByBookName(name) 99 | 100 | responseSuccess(w,ErrSuccess,bookList) 101 | } 102 | 103 | func searchBookAuthor(w http.ResponseWriter,r *http.Request){ 104 | r.ParseForm() 105 | 106 | author := r.FormValue("author") 107 | 108 | 109 | 110 | if len(author) == 0 { 111 | responseError(w,ErrInvalidParameter) 112 | return 113 | } 114 | 115 | bookList := bookMgr.SearchByAuthor(author) 116 | 117 | responseSuccess(w,ErrSuccess,bookList) 118 | } 119 | 120 | func addStudent(w http.ResponseWriter,r *http.Request){ 121 | r.ParseForm() 122 | idStr := r.FormValue("id") 123 | name := r.FormValue("name") 124 | gradeStr := r.FormValue("grade") 125 | identify := r.FormValue("identify") 126 | sexStr := r.FormValue("sex") 127 | 128 | id,err := strconv.Atoi(idStr) 129 | if err != nil{ 130 | responseError(w,ErrInvalidParameter) 131 | return 132 | } 133 | grade,err := strconv.Atoi(gradeStr) 134 | if err != nil{ 135 | responseError(w,ErrInvalidParameter) 136 | return 137 | } 138 | 139 | sex,err := strconv.Atoi(sexStr) 140 | if err != nil{ 141 | responseError(w,ErrInvalidParameter) 142 | return 143 | } 144 | 145 | if len(name) == 0 || (sex != 0 && sex != 1)|| len(identify) == 0{ 146 | responseError(w,ErrInvalidParameter) 147 | return 148 | } 149 | 150 | stu := logic.NewStudent(id,name,grade,identify,sex) 151 | err = studentMgr.AddStudent(stu) 152 | if err != nil{ 153 | responseError(w,ErrServerBusy) 154 | return 155 | } 156 | responseSuccess(w,ErrSuccess,nil) 157 | } 158 | 159 | func borrow(w http.ResponseWriter,r *http.Request){ 160 | r.ParseForm() 161 | 162 | sidStr := r.FormValue("sid") 163 | bid := r.FormValue("bid") 164 | sid ,err := strconv.Atoi(sidStr) 165 | if err != nil{ 166 | responseError(w,ErrInvalidParameter) 167 | return 168 | } 169 | 170 | if len(bid) == 0{ 171 | responseError(w,ErrInvalidParameter) 172 | return 173 | } 174 | 175 | student,err := studentMgr.GetStudentByid(sid) 176 | if err != nil{ 177 | responseError(w,ErrInvalidParameter) 178 | return 179 | } 180 | err = bookMgr.Borrow(student,bid) 181 | if err != nil{ 182 | responseError(w,ErrInvalidParameter) 183 | return 184 | } 185 | studentMgr.Save() 186 | responseSuccess(w,ErrSuccess,nil) 187 | } 188 | 189 | func bookList(w http.ResponseWriter,r *http.Request){ 190 | r.ParseForm() 191 | sidStr := r.FormValue("sid") 192 | sid ,err := strconv.Atoi(sidStr) 193 | if err != nil{ 194 | responseError(w,ErrInvalidParameter) 195 | return 196 | } 197 | bookList,err := studentMgr.GetStudentBorrowBooks(sid) 198 | if err != nil{ 199 | responseError(w,ErrInvalidParameter) 200 | return 201 | } 202 | 203 | responseSuccess(w,ErrSuccess,bookList) 204 | } 205 | 206 | func getTop10(w http.ResponseWriter,r *http.Request){ 207 | 208 | bookList := bookMgr.GetTop10() 209 | 210 | responseSuccess(w,ErrSuccess,bookList) 211 | } 212 | 213 | func LogHandle(handle func(w http.ResponseWriter,r *http.Request))func(w http.ResponseWriter,r *http.Request){ 214 | return func(w http.ResponseWriter,r *http.Request){ 215 | start := time.Now().UnixNano() 216 | handle(w,r) 217 | end := time.Now().UnixNano() 218 | cost := (end-start)/1000 219 | log.Printf("url:%s cost:%d us\n",r.RequestURI,cost) 220 | } 221 | } 222 | 223 | func main(){ 224 | http.HandleFunc("/book/add",LogHandle(addBook)) 225 | http.HandleFunc("/book/searchName",LogHandle(searchBookName)) 226 | http.HandleFunc("/book/searchAuthor",LogHandle(searchBookAuthor)) 227 | http.HandleFunc("/student/add",LogHandle(addStudent)) 228 | http.HandleFunc("/student/borrow",LogHandle(borrow)) 229 | http.HandleFunc("/student/bookList",LogHandle(bookList)) 230 | http.HandleFunc("/book/",LogHandle(getTop10)) 231 | 232 | err := http.ListenAndServe(":8080",nil) 233 | if err != nil{ 234 | fmt.Println("server start failed,err is",err) 235 | } 236 | } -------------------------------------------------------------------------------- /book_mgr_v3/api/error_code.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | 4 | 5 | const( 6 | ErrSuccess = 0 7 | ErrInvalidParameter = 1001 8 | ErrServerBusy = 1002 9 | 10 | ) 11 | 12 | func getMessage(code int)(msg string){ 13 | switch code{ 14 | case ErrSuccess: 15 | msg = "success" 16 | case ErrInvalidParameter: 17 | msg = "invalid parameter" 18 | case ErrServerBusy: 19 | msg = "server busy" 20 | default: 21 | msg = "unknown error" 22 | } 23 | return 24 | } 25 | -------------------------------------------------------------------------------- /book_mgr_v3/logic/book.go: -------------------------------------------------------------------------------- 1 | // 关于书籍的处理逻辑 2 | 3 | package logic 4 | 5 | import ( 6 | "errors" 7 | "sync" 8 | ) 9 | 10 | // 定义一个书的结构体,包含名字,数量,作者和出版日期 11 | type Book struct { 12 | BookId string 13 | Name string 14 | Num int 15 | Author string 16 | PublishDate int64 17 | BorrowCount int 18 | Lock sync.Mutex 19 | } 20 | 21 | // 这里是一个构造函数 22 | func NewBook(bookId,name string,num int,author string,publishDate int64)(book *Book){ 23 | book = &Book{ 24 | BookId:bookId, 25 | Name:name, 26 | Num:num, 27 | Author:author, 28 | PublishDate:publishDate, 29 | } 30 | return 31 | } 32 | 33 | // 借书 34 | func(b *Book) Borrow()(err error){ 35 | b.Lock.Lock() 36 | defer b.Lock.Unlock() 37 | if b.Num <= 0{ 38 | err = errors.New("book is not enough") 39 | return 40 | } 41 | b.Num -= 1 42 | b.BorrowCount += 1 43 | return 44 | } 45 | 46 | // 还书 47 | func (b*Book) Back()(err error){ 48 | b.Lock.Lock() 49 | defer b.Lock.Lock() 50 | b.Num +=1 51 | return 52 | } 53 | 54 | -------------------------------------------------------------------------------- /book_mgr_v3/logic/book_mgr.go: -------------------------------------------------------------------------------- 1 | // 书籍管理的处理逻辑 2 | 3 | package logic 4 | 5 | import ( 6 | "sync" 7 | "fmt" 8 | "sort" 9 | "encoding/json" 10 | "io/ioutil" 11 | ) 12 | 13 | type BookMgr struct { 14 | BookList []*Book 15 | // 存储bookid 到借书学生的列表 16 | BookStudentMap map[string][]*Student 17 | // 书籍名字到书籍的索引 18 | BookNameMap map[string][]*Book 19 | // 书籍作者到书籍的索引 20 | BookAuthorMap map[string][]*Book 21 | Lock sync.Mutex 22 | 23 | } 24 | 25 | // 这里是一个构造函数 26 | func NewBookMgr()(bookmgr*BookMgr){ 27 | bookmgr = &BookMgr{ 28 | BookStudentMap:make(map[string][]*Student,32), 29 | BookNameMap:make(map[string][]*Book), 30 | BookAuthorMap:make(map[string][]*Book,32), 31 | } 32 | bookmgr.load() 33 | return 34 | } 35 | 36 | // 添加书籍 37 | func (b *BookMgr) AddBook(book *Book)(err error){ 38 | b.Lock.Lock() 39 | defer b.Lock.Unlock() 40 | // 添加到book列表中 41 | b.BookList = append(b.BookList,book) 42 | // 更新书籍名字到同一个书籍名字对应的book列表 43 | bookList,ok := b.BookNameMap[book.Name] 44 | if !ok{ 45 | var tmp []*Book 46 | tmp = append(tmp,book) 47 | bookList = tmp 48 | }else{ 49 | bookList = append(bookList,book) 50 | } 51 | b.BookNameMap[book.Name] = bookList 52 | 53 | // 更新数据作者到同一个作者对应的book列表 54 | bookList,ok = b.BookAuthorMap[book.Author] 55 | if !ok{ 56 | var tmp []*Book 57 | tmp = append(tmp,book) 58 | bookList = tmp 59 | }else{ 60 | bookList = append(bookList,book) 61 | } 62 | b.BookAuthorMap[book.Author] = bookList 63 | b.Save() 64 | 65 | return 66 | } 67 | 68 | // 通过书籍名字查找 69 | func (b *BookMgr) SearchByBookName(bookName string)(bookList []*Book){ 70 | b.Lock.Lock() 71 | b.Lock.Unlock() 72 | bookList = b.BookNameMap[bookName] 73 | return 74 | } 75 | 76 | // 通过书籍作者查找 77 | func (b *BookMgr) SearchByAuthor(Author string)(bookList []*Book){ 78 | b.Lock.Lock() 79 | b.Lock.Unlock() 80 | bookList = b.BookAuthorMap[Author] 81 | return 82 | } 83 | 84 | // 通过书籍出版日期查找,这里的参数是一个范围 85 | func (b *BookMgr) SearchByPushlish(min int64,max int64)(bookList []*Book){ 86 | b.Lock.Lock() 87 | b.Lock.Unlock() 88 | for _,v:= range b.BookList{ 89 | if v.PublishDate >= min && v.PublishDate <= max{ 90 | bookList = append(bookList,v) 91 | } 92 | } 93 | return 94 | } 95 | 96 | // 用于学生借书 97 | func (b *BookMgr) Borrow(student *Student,bookId string) (err error){ 98 | b.Lock.Lock() 99 | defer b.Lock.Unlock() 100 | var book *Book 101 | for _,v := range b.BookList{ 102 | if v.BookId == bookId{ 103 | book = v 104 | break 105 | } 106 | } 107 | if book == nil{ 108 | err = fmt.Errorf("book id [%d] is not exist",bookId) 109 | return 110 | } 111 | err = book.Borrow() 112 | if err != nil{ 113 | return 114 | } 115 | student.AddBook(book) 116 | b.Save() 117 | return 118 | } 119 | 120 | // 这里实现了Len() Less() Swap()后就实现sort中的Interface接口,就可以调用sort.Sort方法 121 | func (b *BookMgr) Len() int{ 122 | return len(b.BookList) 123 | } 124 | 125 | // 如果是>是从大到小排序,如果是< 则是从小到大排序 126 | func (b *BookMgr) Less(i,j int) bool{ 127 | return b.BookList[i].BorrowCount > b.BookList[j].BorrowCount 128 | } 129 | 130 | func (b *BookMgr) Swap(i,j int){ 131 | b.BookList[i],b.BookList[j]= b.BookList[j],b.BookList[i] 132 | } 133 | 134 | // 获取top10 135 | func (b *BookMgr) GetTop10()(bookList []*Book){ 136 | sort.Sort(b) 137 | for i :=0;i<10;i++{ 138 | if i >= len(b.BookList){ 139 | break 140 | } 141 | bookList = append(bookList,b.BookList[i]) 142 | 143 | } 144 | return 145 | } 146 | 147 | // 数据持续化到文件 148 | func(b *BookMgr) Save(){ 149 | data,err := json.Marshal(b) 150 | if err != nil{ 151 | fmt.Printf("save failed,err:%v\n",err) 152 | return 153 | } 154 | err = ioutil.WriteFile(BookMgrSavePath,data,0666) 155 | if err != nil{ 156 | fmt.Printf("write file failed,err:%v",err) 157 | return 158 | } 159 | return 160 | } 161 | 162 | func(b *BookMgr) load(){ 163 | data,err := ioutil.ReadFile(BookMgrSavePath) 164 | if err != nil{ 165 | fmt.Printf("load failed,err:%v",err) 166 | return 167 | } 168 | err = json.Unmarshal(data,b) 169 | if err != nil{ 170 | fmt.Printf("unmarshal failed,err:%v",err) 171 | return 172 | } 173 | fmt.Printf("load data from disk success\n") 174 | 175 | 176 | } 177 | 178 | -------------------------------------------------------------------------------- /book_mgr_v3/logic/constant.go: -------------------------------------------------------------------------------- 1 | package logic 2 | 3 | 4 | const( 5 | BookMgrSavePath = "book.json" 6 | StudentMgrSavaPaht = "student.json" 7 | ) 8 | -------------------------------------------------------------------------------- /book_mgr_v3/logic/student.go: -------------------------------------------------------------------------------- 1 | // 学生的处理逻辑 2 | package logic 3 | 4 | import ( 5 | "sync" 6 | "fmt" 7 | ) 8 | 9 | type Student struct { 10 | Id int 11 | Name string 12 | Grade int 13 | Identify string 14 | Sex int 15 | BookMap map[string]*Book 16 | Lock sync.Mutex //互斥锁 17 | } 18 | 19 | // 学生的构造函数 20 | func NewStudent(id int,name string,grade int,identify string,sex int)(stu *Student){ 21 | stu = &Student{ 22 | Id:id, 23 | Name:name, 24 | Grade:grade, 25 | Identify:identify, 26 | Sex:sex, 27 | BookMap:make(map[string]*Book,32), 28 | } 29 | return 30 | } 31 | 32 | // 学生添加书籍 33 | func (s *Student) AddBook(b *Book){ 34 | s.Lock.Lock() 35 | defer s.Lock.Unlock() 36 | s.BookMap[b.BookId]=b 37 | return 38 | } 39 | 40 | // 学生还书 41 | func (s *Student) BackBook(bookId string)(err error){ 42 | s.Lock.Lock() 43 | defer s.Lock.Unlock() 44 | _,ok := s.BookMap[bookId] 45 | if !ok{ 46 | // 格式化输出错误 47 | err = fmt.Errorf("student id:%d not exist book book_id:%s",s.Id,bookId) 48 | return 49 | } 50 | delete(s.BookMap,bookId) 51 | return 52 | } 53 | 54 | // 获取学生借的书籍 55 | func (s *Student) GetBookList()(bookList[]*Book){ 56 | s.Lock.Lock() 57 | defer s.Lock.Unlock() 58 | for _,v := range s.BookMap{ 59 | bookList = append(bookList,v) 60 | } 61 | return 62 | } -------------------------------------------------------------------------------- /book_mgr_v3/logic/student_mgr.go: -------------------------------------------------------------------------------- 1 | // 学生管理的处理逻辑 2 | package logic 3 | 4 | import ( 5 | "sync" 6 | "fmt" 7 | "encoding/json" 8 | "io/ioutil" 9 | ) 10 | 11 | type StudentMgr struct { 12 | // 学生id对应student map 13 | StudentMap map[int]*Student 14 | Lock sync.Mutex 15 | } 16 | 17 | // 学生管理的构造函数 18 | func NewStudentMgr()(*StudentMgr){ 19 | s := &StudentMgr{ 20 | StudentMap:make(map[int]*Student,32), 21 | } 22 | s.load() 23 | return s 24 | } 25 | 26 | // 添加学生 27 | func (s *StudentMgr) AddStudent(stu *Student)(err error){ 28 | s.Lock.Lock() 29 | defer s.Lock.Unlock() 30 | s.StudentMap[stu.Id] = stu 31 | s.Save() 32 | return 33 | } 34 | 35 | // 根据学生id查询学生的信息 36 | func (s *StudentMgr) GetStudentByid(id int)(stu *Student,err error){ 37 | s.Lock.Lock() 38 | defer s.Lock.Unlock() 39 | 40 | stu,ok:=s.StudentMap[id] 41 | if !ok{ 42 | err = fmt.Errorf("student id %d is not exists",id) 43 | return 44 | } 45 | return 46 | } 47 | 48 | // 获取学生的借的书籍信息 49 | func (s *StudentMgr) GetStudentBorrowBooks(id int)(bookList []*Book,err error){ 50 | stu,err := s.GetStudentByid(id) 51 | if err != nil{ 52 | return 53 | } 54 | bookList = stu.GetBookList() 55 | return 56 | } 57 | 58 | 59 | // 数据持续化到文件 60 | func(s *StudentMgr) Save(){ 61 | data,err := json.Marshal(s) 62 | if err != nil{ 63 | fmt.Printf("save failed,err:%v\n",err) 64 | return 65 | } 66 | err = ioutil.WriteFile(StudentMgrSavaPaht,data,0666) 67 | if err != nil{ 68 | fmt.Printf("write file failed,err:%v",err) 69 | return 70 | } 71 | return 72 | } 73 | 74 | func(s *StudentMgr) load(){ 75 | data,err := ioutil.ReadFile(StudentMgrSavaPaht) 76 | if err != nil{ 77 | fmt.Printf("load failed,err:%v",err) 78 | return 79 | } 80 | err = json.Unmarshal(data,s) 81 | if err != nil{ 82 | fmt.Printf("unmarshal failed,err:%v",err) 83 | return 84 | } 85 | fmt.Printf("load data from disk success\n") 86 | 87 | 88 | } -------------------------------------------------------------------------------- /config/config.go: -------------------------------------------------------------------------------- 1 | package config 2 | 3 | import ( 4 | "sync" 5 | "os" 6 | "bufio" 7 | "io" 8 | "strings" 9 | "fmt" 10 | "strconv" 11 | "time" 12 | ) 13 | 14 | type Config struct { 15 | filename string 16 | lastModifyTime int64 17 | data map[string]string 18 | rwLock sync.RWMutex 19 | notifyList []Notifyer 20 | } 21 | 22 | func NewConfig(filename string)(conf *Config,err error){ 23 | conf = &Config{ 24 | filename:filename, 25 | data:make(map[string]string,1024), 26 | } 27 | m,err := conf.parse() 28 | if err != nil{ 29 | return 30 | } 31 | conf.rwLock.Lock() 32 | conf.data = m 33 | conf.rwLock.Unlock() 34 | go conf.reload() 35 | return 36 | } 37 | 38 | func (c *Config) AddNotifyer(n Notifyer){ 39 | c.notifyList = append(c.notifyList,n) 40 | } 41 | 42 | func (c *Config) reload(){ 43 | // 这里启动一个定时器,每5秒重新加载一次配置文件 44 | ticker := time.NewTicker(time.Second*5) 45 | for _ = range ticker.C{ 46 | func(){ 47 | file,err := os.Open(c.filename) 48 | if err != nil{ 49 | fmt.Printf("open %s failed,err:%v\n",c.filename,err) 50 | return 51 | } 52 | defer file.Close() 53 | fileInfo,err := file.Stat() 54 | if err != nil{ 55 | fmt.Printf("stat %s failed,err:%v\n",c.filename,err) 56 | return 57 | } 58 | curModifyTime := fileInfo.ModTime().Unix() 59 | fmt.Printf("%v --- %v\n",curModifyTime,c.lastModifyTime) 60 | if curModifyTime > c.lastModifyTime{ 61 | m,err := c.parse() 62 | if err != nil{ 63 | fmt.Println("parse failed,err:",err) 64 | return 65 | } 66 | c.rwLock.Lock() 67 | c.data = m 68 | c.rwLock.Unlock() 69 | for _, n:=range c.notifyList{ 70 | n.Callback(c) 71 | } 72 | c.lastModifyTime = curModifyTime 73 | } 74 | }() 75 | } 76 | } 77 | 78 | func (c *Config) parse()(m map[string]string,err error){ 79 | // 读文件并或将文件中的数据以k/v的形式存储到map中 80 | m = make(map[string]string,1024) 81 | file,err := os.Open(c.filename) 82 | if err != nil{ 83 | return 84 | } 85 | var lineNo int 86 | reader := bufio.NewReader(file) 87 | for{ 88 | // 一行行的读文件 89 | line,errRet := reader.ReadString('\n') 90 | if errRet == io.EOF{ 91 | // 表示读到文件的末尾 92 | break 93 | } 94 | if errRet != nil{ 95 | // 表示读文件出问题 96 | err = errRet 97 | return 98 | } 99 | lineNo++ 100 | line = strings.TrimSpace(line) // 取出空格 101 | if len(line) == 0 || line[0] == '\n' || line[0] == '+' || line[0] == ';'{ 102 | // 当前行为空行或者是注释行等 103 | continue 104 | } 105 | arr := strings.Split(line,"=") // 通过=进行切割取出k/v结构 106 | if len(arr) == 0{ 107 | fmt.Printf("invalid config,line:%d\n",lineNo) 108 | continue 109 | } 110 | key := strings.TrimSpace(arr[0]) 111 | if len(key) == 0{ 112 | fmt.Printf("invalid config,line:%d\n",lineNo) 113 | continue 114 | } 115 | if len(arr) == 1{ 116 | m[key] = "" 117 | continue 118 | } 119 | value := strings.TrimSpace(arr[1]) 120 | m[key] = value 121 | } 122 | return 123 | } 124 | 125 | func (c *Config) GetInt(key string)(value int,err error){ 126 | // 根据int获取 127 | c.rwLock.RLock() 128 | defer c.rwLock.RUnlock() 129 | str,ok:=c.data[key] 130 | if !ok{ 131 | err = fmt.Errorf("key[%s] not found",key) 132 | return 133 | } 134 | value,err = strconv.Atoi(str) 135 | return 136 | } 137 | 138 | func (c *Config)GetIntDefault(key string,defval int)(value int){ 139 | // 默认值 140 | c.rwLock.RLock() 141 | defer c.rwLock.RUnlock() 142 | str,ok:=c.data[key] 143 | if !ok{ 144 | value = defval 145 | return 146 | } 147 | value,err := strconv.Atoi(str) 148 | if err != nil{ 149 | value =defval 150 | return 151 | } 152 | return 153 | } 154 | 155 | func (c *Config) GetString(key string)(value string,err error){ 156 | // 根据字符串获取 157 | c.rwLock.RLock() 158 | defer c.rwLock.RUnlock() 159 | value,ok := c.data[key] 160 | if !ok{ 161 | err = fmt.Errorf("key[%s] not found",key) 162 | return 163 | } 164 | return 165 | } 166 | -------------------------------------------------------------------------------- /config/config_notify.go: -------------------------------------------------------------------------------- 1 | package config 2 | 3 | // 定义一个通知的接口 4 | type Notifyer interface { 5 | Callback(*Config) 6 | } 7 | -------------------------------------------------------------------------------- /config222/config.go: -------------------------------------------------------------------------------- 1 | package config 2 | 3 | import ( 4 | "strings" 5 | "errors" 6 | "io/ioutil" 7 | "gopkg.in/yaml.v2" 8 | "reflect" 9 | "fmt" 10 | "strconv" 11 | ) 12 | 13 | type ConfigEngine struct { 14 | data map[interface{}]interface{} 15 | } 16 | 17 | //func NewConfigEngine() *ConfigEngine { 18 | // return &ConfigEngine{ 19 | // data:make(map[interface{}]interface{},10), 20 | // } 21 | //} 22 | 23 | func (c *ConfigEngine) Load (path string) error { 24 | ext := c.guessFileType(path) 25 | if ext == "" { 26 | return errors.New("cant not load" + path + " config") 27 | } 28 | return c.loadFromYaml(path) 29 | } 30 | 31 | func (c *ConfigEngine) guessFileType(path string) string { 32 | s := strings.Split(path,".") 33 | ext := s[len(s) - 1] 34 | switch ext { 35 | case "yaml","yml": 36 | return "yaml" 37 | } 38 | return "" 39 | } 40 | 41 | func (c *ConfigEngine) loadFromYaml(path string) error { 42 | yamlS,readErr := ioutil.ReadFile(path) 43 | if readErr != nil { 44 | return readErr 45 | } 46 | err := yaml.Unmarshal(yamlS, &c.data) 47 | if err != nil { 48 | return errors.New("can not parse "+ path + " config" ) 49 | } 50 | return nil 51 | } 52 | 53 | 54 | func (c *ConfigEngine) Get(name string) interface{}{ 55 | path := strings.Split(name,".") 56 | data := c.data 57 | for key, value := range path { 58 | fmt.Println(data) 59 | v, ok := data[value] 60 | if !ok { 61 | break 62 | } 63 | if (key + 1) == len(path) { 64 | return v 65 | } 66 | if reflect.TypeOf(v).String() == "map[interface {}]interface {}"{ 67 | data = v.(map[interface {}]interface {}) 68 | } 69 | } 70 | return nil 71 | } 72 | 73 | func (c *ConfigEngine) GetString(name string) string { 74 | value := c.Get(name) 75 | switch value:=value.(type){ 76 | case string: 77 | return value 78 | case bool,float64,int: 79 | return fmt.Sprint(value) 80 | default: 81 | return "" 82 | } 83 | } 84 | 85 | func (c *ConfigEngine) GetInt(name string) int { 86 | value := c.Get(name) 87 | switch value := value.(type){ 88 | case string: 89 | i,_:= strconv.Atoi(value) 90 | return i 91 | case int: 92 | return value 93 | case bool: 94 | if value{ 95 | return 1 96 | } 97 | return 0 98 | case float64: 99 | return int(value) 100 | default: 101 | return 0 102 | } 103 | } 104 | 105 | func (c *ConfigEngine) GetBool(name string) bool { 106 | value := c.Get(name) 107 | switch value := value.(type){ 108 | case string: 109 | str,_:= strconv.ParseBool(value) 110 | return str 111 | case int: 112 | if value != 0 { 113 | return true 114 | } 115 | return false 116 | case bool: 117 | return value 118 | case float64: 119 | if value != 0.0 { 120 | return true 121 | } 122 | return false 123 | default: 124 | return false 125 | } 126 | } 127 | 128 | func (c *ConfigEngine) GetFloat64(name string) float64 { 129 | value := c.Get(name) 130 | switch value := value.(type){ 131 | case string: 132 | str,_ := strconv.ParseFloat(value,64) 133 | return str 134 | case int: 135 | return float64(value) 136 | case bool: 137 | if value { 138 | return float64(1) 139 | } 140 | return float64(0) 141 | case float64: 142 | return value 143 | default: 144 | return float64(0) 145 | } 146 | } 147 | 148 | func (c *ConfigEngine) GetStruct(name string,s interface{}) interface{}{ 149 | d := c.Get(name) 150 | switch d.(type){ 151 | case string: 152 | c.setField(s,name,d) 153 | case map[interface{}]interface{}: 154 | // 155 | } 156 | return s 157 | } 158 | 159 | func (c *ConfigEngine) mapToStruct(m map[interface{}]interface{},s interface{}) interface{}{ 160 | for key, value := range m { 161 | switch key.(type) { 162 | case string: 163 | c.setField(s,key.(string),value) 164 | } 165 | } 166 | return s 167 | } 168 | 169 | func (c *ConfigEngine) setField(obj interface{},name string,value interface{}) error { 170 | structValue := reflect.Indirect(reflect.ValueOf(obj)) 171 | structFieldValue := structValue.FieldByName(name) 172 | 173 | if !structFieldValue.IsValid() { 174 | return fmt.Errorf("No such field: %s in obj",name) 175 | } 176 | 177 | if !structFieldValue.CanSet() { 178 | return fmt.Errorf("Cannot set %s field value", name) 179 | } 180 | 181 | structFieldType := structFieldValue.Type() 182 | val := reflect.ValueOf(value) 183 | 184 | if structFieldType.Kind() == reflect.Struct && val.Kind() == reflect.Map { 185 | vint := val.Interface() 186 | 187 | switch vint.(type) { 188 | case map[interface{}]interface{}: 189 | for key, value := range vint.(map[interface{}]interface{}) { 190 | c.setField(structFieldValue.Addr().Interface(), key.(string), value) 191 | } 192 | case map[string]interface{}: 193 | for key, value := range vint.(map[string]interface{}) { 194 | c.setField(structFieldValue.Addr().Interface(), key, value) 195 | } 196 | } 197 | 198 | } else { 199 | if structFieldType != val.Type() { 200 | return errors.New("Provided value type didn't match obj field type") 201 | } 202 | 203 | structFieldValue.Set(val) 204 | } 205 | 206 | return nil 207 | 208 | 209 | } 210 | 211 | 212 | 213 | 214 | 215 | -------------------------------------------------------------------------------- /config_test/config.conf: -------------------------------------------------------------------------------- 1 | listen_addr = localhost 2 | server_port = 1000 3 | 4 | # Nginx addr 5 | nginx_addr = 192.168.1.100:9090 6 | -------------------------------------------------------------------------------- /config_test/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "go_dev/13/config" 5 | "fmt" 6 | "time" 7 | "sync/atomic" 8 | ) 9 | 10 | type AppConfig struct { 11 | port int 12 | nginxAddr string 13 | } 14 | 15 | type AppconfigMgr struct { 16 | config atomic.Value 17 | } 18 | 19 | var appConfigMgr = &AppconfigMgr{} 20 | 21 | 22 | func(a *AppconfigMgr)Callback(conf *config.Config){ 23 | 24 | var appConfig = &AppConfig{} 25 | 26 | port,err := conf.GetInt("server_port") 27 | if err != nil{ 28 | fmt.Println("get port failed,err:",err) 29 | return 30 | } 31 | appConfig.port = port 32 | fmt.Println("port:",appConfig.port) 33 | nginxAddr,err := conf.GetString("nginx_addr") 34 | if err != nil{ 35 | fmt.Println("get nginx addr failed,err:",err) 36 | return 37 | } 38 | appConfig.nginxAddr = nginxAddr 39 | fmt.Println("nginx addr :",appConfig.nginxAddr) 40 | 41 | appConfigMgr.config.Store(appConfig) 42 | 43 | } 44 | 45 | func run(){ 46 | for { 47 | // 每5秒打印一次数据,查看自己更改配置文件后是否可以热刷新 48 | appConfig := appConfigMgr.config.Load().(*AppConfig) 49 | fmt.Println("port:",appConfig.port) 50 | fmt.Println("nginx addr:",appConfig.nginxAddr) 51 | time.Sleep(5* time.Second) 52 | } 53 | } 54 | 55 | func main() { 56 | conf,err := config.NewConfig("/Users/zhaofan/go_project/src/go_dev/13/config_test/config.conf") 57 | if err != nil{ 58 | fmt.Println("parse config failed,err:",err) 59 | return 60 | } 61 | //打开文件获取内容后,将自己加入到被通知的切片中 62 | conf.AddNotifyer(appConfigMgr) 63 | 64 | var appConfig = &AppConfig{} 65 | 66 | appConfig.port,err = conf.GetInt("server_port") 67 | if err != nil{ 68 | fmt.Println("get port failed,err:",err) 69 | return 70 | } 71 | fmt.Println("port:",appConfig.port) 72 | 73 | appConfig.nginxAddr,err = conf.GetString("nginx_addr") 74 | if err != nil{ 75 | fmt.Println("get nginx addr failed,err:",err) 76 | return 77 | } 78 | fmt.Println("nginx addr:",appConfig.nginxAddr) 79 | appConfigMgr.config.Store(appConfig) 80 | run() 81 | 82 | } -------------------------------------------------------------------------------- /config_test222/config_test.exe: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pythonsite/go_simple_code/43fa67a712e8bce178f479379071d9f167504505/config_test222/config_test.exe -------------------------------------------------------------------------------- /config_test222/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "go_dev/config" 5 | "fmt" 6 | ) 7 | 8 | func main() { 9 | c := config.ConfigEngine{} 10 | c.Load("test.yaml") 11 | fmt.Println(c.GetInt("Main.HttpPort")) 12 | } 13 | 14 | -------------------------------------------------------------------------------- /config_test222/test.yaml: -------------------------------------------------------------------------------- 1 | Main: 2 | HttpPort: 8082 3 | HttpsOn: false 4 | Domain: "pythonsite.com" 5 | HttpsPort: 443 6 | -------------------------------------------------------------------------------- /iniConfig/config.ini: -------------------------------------------------------------------------------- 1 | [server] 2 | ip = 127.0.0.1 3 | port = 90 4 | 5 | [mysql] 6 | username = root 7 | passwd = 123123 8 | database = aa 9 | host = 127.0.0.1 10 | port = 3306 11 | timeout = 1.2 12 | 13 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /iniConfig/go.mod: -------------------------------------------------------------------------------- 1 | module go_simple_code/iniConfig 2 | 3 | go 1.12 4 | -------------------------------------------------------------------------------- /iniConfig/go.sum: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /iniConfig/iniConfig.go: -------------------------------------------------------------------------------- 1 | package iniConfig 2 | 3 | import ( 4 | "errors" 5 | "fmt" 6 | "io/ioutil" 7 | "reflect" 8 | "strconv" 9 | "strings" 10 | ) 11 | 12 | func MarshalFile(fileName string, data interface{})(err error) { 13 | result, err := marshal(data) 14 | if err != nil { 15 | return 16 | } 17 | return ioutil.WriteFile(fileName,result,0755) 18 | } 19 | 20 | func UnmarshalFile(fileName string, result interface{})(err error) { 21 | data, err := ioutil.ReadFile(fileName) 22 | if err != nil { 23 | return 24 | } 25 | return unmarshal(data, result) 26 | } 27 | 28 | func marshal(data interface{})(result []byte,err error) { 29 | typeInfo := reflect.TypeOf(data) 30 | if typeInfo.Kind() != reflect.Struct { 31 | err = errors.New("please pass struct") 32 | return 33 | } 34 | var conf []string 35 | valueInfo := reflect.ValueOf(data) 36 | for i := 0;i < typeInfo.NumField();i++ { 37 | sectionField := typeInfo.Field(i) 38 | sectionVal := valueInfo.Field(i) 39 | fieldType := sectionField.Type 40 | if fieldType.Kind() != reflect.Struct { 41 | continue 42 | } 43 | tagVal := sectionField.Tag.Get("ini") 44 | if len(tagVal) == 0 { 45 | tagVal = sectionField.Name 46 | } 47 | var section string 48 | if i != 0 { 49 | section = fmt.Sprintf("\n[%s]\n", tagVal) 50 | }else { 51 | section = fmt.Sprintf("[%s]\n", tagVal) 52 | } 53 | conf = append(conf, section) 54 | for j :=0;j< fieldType.NumField();j++ { 55 | keyField := fieldType.Field(j) 56 | fieldTagval := keyField.Tag.Get("ini") 57 | if len(fieldTagval) == 0 { 58 | fieldTagval = keyField.Name 59 | } 60 | valueField := sectionVal.Field(j) 61 | item := fmt.Sprintf("%s=%v\n", fieldTagval, valueField) 62 | conf = append(conf, item) 63 | } 64 | } 65 | for _, val:= range conf { 66 | byteVal := []byte(val) 67 | result = append(result, byteVal...) 68 | } 69 | return 70 | } 71 | 72 | func unmarshal(data []byte, result interface{}) (err error){ 73 | typeInfo := reflect.TypeOf(result) 74 | if typeInfo.Kind() != reflect.Ptr { 75 | err = errors.New("please pass address") 76 | return 77 | } 78 | typeStruct := typeInfo.Elem() 79 | if typeStruct.Kind() != reflect.Struct { 80 | err = errors.New("please pass struct") 81 | return 82 | } 83 | lineArr := strings.Split(string(data),"\n") 84 | var lastFieldName string 85 | for index, line := range lineArr { 86 | line = strings.TrimSpace(line) 87 | if len(line) == 0 { 88 | continue 89 | } 90 | // 如果是注释,忽略 91 | if line[0] == ';'|| line[0] == '#' { 92 | continue 93 | } 94 | if line[0] == '[' { 95 | lastFieldName, err = parseSection(line, typeStruct) 96 | if err != nil { 97 | err =fmt.Errorf("%v lineNo:%d",err,index+1) 98 | return 99 | } 100 | continue 101 | } 102 | err = parseItem(lastFieldName, line, result) 103 | if err != nil { 104 | err = fmt.Errorf("%v lineNo:%d",err, index + 1) 105 | return 106 | } 107 | } 108 | return 109 | } 110 | 111 | 112 | func parseSection(line string, typeInfo2 reflect.Type) (fieldName string,err error) { 113 | 114 | if line[0] == '[' && len(line) <= 2 { 115 | err = fmt.Errorf("error invalid section:%s ", line) 116 | return 117 | } 118 | if line[0] == '[' && line[len(line) -1] != ']' { 119 | err = fmt.Errorf("error invalid section:%s", line) 120 | return 121 | } 122 | if line[0] == '[' && line[len(line) -1] == ']'{ 123 | sectionName := strings.TrimSpace(line[1:len(line) -1]) 124 | if len(sectionName) == 0 { 125 | err = fmt.Errorf("error invalid sectionName:%s", line,) 126 | return 127 | } 128 | for i := 0;i< typeInfo2.NumField();i ++ { 129 | field := typeInfo2.Field(i) 130 | tagValue := field.Tag.Get("ini") 131 | if tagValue == sectionName { 132 | fieldName = field.Name 133 | fmt.Println("field name:", fieldName) 134 | break 135 | } 136 | } 137 | } 138 | return 139 | } 140 | 141 | func parseItem(lastFieldName string, line string, result interface{}) (err error) { 142 | index := strings.Index(line, "=") 143 | if index == -1 { 144 | err = fmt.Errorf("sytax error not found '=' line:%s", line) 145 | return 146 | } 147 | key := strings.TrimSpace(line[0:index]) 148 | value := strings.TrimSpace(line[index+1:]) 149 | if len(key) == 0 { 150 | err = fmt.Errorf("syntax error, line:%s", line) 151 | return 152 | } 153 | resultValue := reflect.ValueOf(result) 154 | sectionValue := resultValue.Elem().FieldByName(lastFieldName) 155 | sectionType := sectionValue.Type() 156 | if sectionType.Kind() != reflect.Struct { 157 | err = fmt.Errorf("field: %s nust be struct", lastFieldName) 158 | return 159 | } 160 | keyFieldName :="" 161 | for i :=0;i< sectionType.NumField();i++ { 162 | field := sectionType.Field(i) 163 | tagVal := field.Tag.Get("ini") 164 | if tagVal == key { 165 | keyFieldName = field.Name 166 | break 167 | } 168 | } 169 | if len(keyFieldName) == 0 { 170 | return 171 | } 172 | 173 | fieldValue := sectionValue.FieldByName(keyFieldName) 174 | if fieldValue == reflect.ValueOf(nil) { 175 | return 176 | } 177 | switch fieldValue.Type().Kind(){ 178 | case reflect.String: 179 | fieldValue.SetString(value) 180 | case reflect.Int,reflect.Int8,reflect.Int16,reflect.Int32,reflect.Int64: 181 | intVal,err2 := strconv.ParseInt(value,10, 64) 182 | if err2 != nil { 183 | err = err2 184 | return 185 | } 186 | fieldValue.SetInt(intVal) 187 | case reflect.Uint, reflect.Uint8,reflect.Uint16,reflect.Uint32, reflect.Uint64: 188 | uintVal, err2 := strconv.ParseUint(value, 10, 64) 189 | if err2 != nil { 190 | err = err2 191 | return 192 | } 193 | fieldValue.SetUint(uintVal) 194 | case reflect.Float32, reflect.Float64: 195 | floadVal, err2 := strconv.ParseFloat(value, 64) 196 | if err2 != nil { 197 | err = err2 198 | return 199 | } 200 | fieldValue.SetFloat(floadVal) 201 | default: 202 | err = fmt.Errorf("unsupport type:%v",fieldValue.Type().Kind()) 203 | } 204 | 205 | fmt.Println(keyFieldName) 206 | 207 | return 208 | } 209 | 210 | 211 | -------------------------------------------------------------------------------- /iniConfig/iniConfig_test.go: -------------------------------------------------------------------------------- 1 | package iniConfig 2 | 3 | import ( 4 | "fmt" 5 | "io/ioutil" 6 | "testing" 7 | ) 8 | 9 | type ServerConfig struct { 10 | Ip string `ini:"ip"` 11 | Port int `ini:"port"` 12 | } 13 | 14 | type MysqlConfig struct { 15 | UserName string `ini:"username"` 16 | Passwd string `ini:"passwd"` 17 | DataBase string `ini:"database"` 18 | Host string `ini:"host"` 19 | Port int `ini:"port"` 20 | Timeout float32 `ini:"timeout"` 21 | } 22 | 23 | type Config struct { 24 | ServerConf ServerConfig `ini:"server"` 25 | MysqlConf MysqlConfig `ini:"mysql"` 26 | } 27 | 28 | func TestIniConfig(t *testing.T) { 29 | fmt.Println("hello") 30 | data, err := ioutil.ReadFile("./config.ini") 31 | if err != nil { 32 | t.Error("open file error:",err) 33 | } 34 | var conf Config 35 | err = unmarshal(data, &conf) 36 | if err != nil { 37 | t.Fatalf("unmarshal failed, err:%v",err) 38 | } 39 | t.Log("unmarshall success") 40 | t.Logf("unmarshal success, conf:%#v\n",conf) 41 | 42 | confData , err := marshal(conf) 43 | if err != nil { 44 | t.Fatalf("marshal error:%v",err) 45 | } 46 | t.Logf("marshal success: confData:\n%v", string(confData)) 47 | 48 | err = MarshalFile("./test.ini", conf) 49 | if err != nil { 50 | t.Fatalf("MarshalFile error:%v",err) 51 | } 52 | } 53 | 54 | func TestUnmarshalFile(t *testing.T) { 55 | serverConfig := &ServerConfig{ 56 | Ip: "192.168.11.1", 57 | Port: 8080, 58 | } 59 | mysqlConfig := &MysqlConfig{ 60 | UserName: "zhaofan", 61 | Passwd:"root123", 62 | DataBase:"mydb", 63 | Host:"127.0.0.1", 64 | Port:3309, 65 | Timeout:1.222, 66 | } 67 | conf := Config{ 68 | ServerConf:*serverConfig, 69 | MysqlConf:*mysqlConfig, 70 | } 71 | err := MarshalFile("./test.ini", conf) 72 | if err != nil { 73 | t.Errorf("marshalfile failed,err:%v",err) 74 | return 75 | } 76 | var conf2 Config 77 | err =UnmarshalFile("./test.ini", &conf2) 78 | if err != nil { 79 | t.Errorf("unmarshalfile failed,err:%v",err) 80 | return 81 | } 82 | t.Logf("unmarhsal success, conf:%v", conf2) 83 | } -------------------------------------------------------------------------------- /iniConfig/test.ini: -------------------------------------------------------------------------------- 1 | [server] 2 | ip=192.168.11.1 3 | port=8080 4 | 5 | [mysql] 6 | username=zhaofan 7 | passwd=root123 8 | database=mydb 9 | host=127.0.0.1 10 | port=3309 11 | timeout=1.222 12 | -------------------------------------------------------------------------------- /interface_nest/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "fmt" 4 | 5 | // 这里定义一个Eater接口 6 | type Eater interface { 7 | Eat() 8 | } 9 | 10 | // 这里定义一个Talker接口 11 | type Talker interface { 12 | Talk() 13 | } 14 | 15 | // 这里定义个动物的接口,同时嵌套了Eater和Talker接口 16 | type Animal interface { 17 | Eater 18 | Talker 19 | } 20 | 21 | // 这里定义一个Dog的struct,并实现talk方法和eat方法,这样就实现了动物的接口 22 | type Dog struct { 23 | 24 | } 25 | 26 | func (d *Dog) Talk(){ 27 | fmt.Println("talk....") 28 | } 29 | 30 | func (d *Dog) Eat(){ 31 | fmt.Println("eating....") 32 | } 33 | 34 | func main() { 35 | d := &Dog{} 36 | var a Animal 37 | a = d 38 | a.Eat() 39 | a.Talk() 40 | } -------------------------------------------------------------------------------- /pay/alipay.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "fmt" 4 | 5 | // 这里定义一个struct 6 | type AliPay struct { 7 | 8 | } 9 | // 这里给AliPay添加一个支付方法,实现了Pay接口中的pay方法 10 | func (a *AliPay) pay(userId int64,money float32) error{ 11 | fmt.Println("1.连接到阿里支付的服务器") 12 | fmt.Println("2.连接到对应的用户") 13 | fmt.Println("3.检查余额") 14 | fmt.Println("4.扣钱") 15 | fmt.Println("5.返回支付是否成功") 16 | 17 | return nil 18 | } -------------------------------------------------------------------------------- /pay/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "fmt" 4 | 5 | func main(){ 6 | // 这里切记 字典类型的数据是需要初始化的 7 | phone := &Phone{ 8 | PayMap:make(map[string]Pay,10), 9 | } 10 | 11 | // 这里是用于开通自己有哪些支付方式 12 | //phone.OpenWeChatPay() 13 | //phone.OpenAliPay() 14 | //phone.OpenPay("weChatPay",&WeChatPay{}) 15 | phone.OpenPay("aLiPay",&AliPay{}) 16 | err := phone.PayMoney("weChatPay",100) 17 | if err != nil{ 18 | // 如果微信支付失败了,用支付宝支付 19 | fmt.Printf("支付失败,失败原因:%v\n",err) 20 | fmt.Println("使用支付宝支付") 21 | err = phone.PayMoney("aLiPay",100) 22 | if err != nil{ 23 | fmt.Printf("支付失败,失败原因:%v\n",err) 24 | return 25 | } 26 | } 27 | fmt.Println("支付成功,欢迎再次光临") 28 | } 29 | -------------------------------------------------------------------------------- /pay/pay.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | // 定义一个支付的接口 4 | type Pay interface { 5 | pay(userId int64,money float32) error 6 | } 7 | -------------------------------------------------------------------------------- /pay/phone.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "fmt" 4 | 5 | type Phone struct { 6 | PayMap map[string]Pay 7 | } 8 | 9 | func (p *Phone) OpenWeChatPay(){ 10 | weChatPay := &WeChatPay{} 11 | p.PayMap["weChatPay"] = weChatPay 12 | } 13 | 14 | func (p *Phone) OpenAliPay(){ 15 | AliPay := &AliPay{} 16 | p.PayMap["aLiPay"] = AliPay 17 | } 18 | 19 | func (p *Phone) OpenPay(name string,pay Pay){ 20 | // 可以把上面两个方法更改为这一个方法 21 | p.PayMap[name] = pay 22 | } 23 | 24 | func (p *Phone) PayMoney(name string,money float32)(err error){ 25 | pay,ok:= p.PayMap[name] 26 | if !ok{ 27 | err = fmt.Errorf("不支持【%s】支付方式",name) 28 | return 29 | } 30 | err = pay.pay(1024,money) 31 | return 32 | } 33 | -------------------------------------------------------------------------------- /pay/weixin.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "fmt" 4 | 5 | type WeChatPay struct { 6 | 7 | } 8 | 9 | // 这里也是实现了Pay接口中的pay方法 10 | func (w *WeChatPay) pay(userId int64,money float32) error{ 11 | fmt.Println("1.连接到微信支付的服务器") 12 | fmt.Println("2.连接到对应的用户") 13 | fmt.Println("3.检查余额") 14 | fmt.Println("4.扣钱") 15 | fmt.Println("5.返回支付是否成功") 16 | 17 | return nil 18 | } -------------------------------------------------------------------------------- /reverse/reverse.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "fmt" 4 | 5 | func reverse(runes []rune) []rune{ 6 | // 将切片内容进行翻转 7 | for i,j:=0,len(runes)-1;i 1 74 | // 10-- > a 75 | // 61-- > Z 76 | charset := "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ" 77 | var shortUrl []byte 78 | for{ 79 | var result byte 80 | number := id % 62 81 | result = charset[number] 82 | var tmp []byte 83 | tmp = append(tmp,result) 84 | shortUrl = append(tmp,shortUrl...) 85 | id = id / 62 86 | if id == 0{ 87 | break 88 | } 89 | } 90 | fmt.Println(string(shortUrl)) 91 | return string(shortUrl) 92 | } 93 | 94 | 95 | func Short2Long(req *model.Short2LongRequest) (response *model.Short2LongResponse, err error) { 96 | response = &model.Short2LongResponse{} 97 | var short ShortUrl 98 | err = Db.Get(&short,"select id,short_url,origin_url,hash_code from short_url where short_url=?",req.ShortUrl) 99 | if err == sql.ErrNoRows{ 100 | response.Code = 404 101 | return 102 | } 103 | if err != nil{ 104 | response.Code = 500 105 | return 106 | } 107 | response.OriginUrl = short.OriginUrl 108 | return 109 | } -------------------------------------------------------------------------------- /short_url/model/data.go: -------------------------------------------------------------------------------- 1 | package model 2 | 3 | 4 | type Long2ShortRequest struct { 5 | OriginUrl string `json:"origin_url"` 6 | } 7 | 8 | type ResponseHeader struct { 9 | Code int `json:"code"` 10 | Message string `json:"message"` 11 | } 12 | 13 | type Long2ShortResponse struct { 14 | ResponseHeader 15 | ShortUrl string `json:"short_url"` 16 | } 17 | 18 | type Short2LongRequest struct { 19 | ShortUrl string `json:"short_url"` 20 | } 21 | 22 | type Short2LongResponse struct { 23 | ResponseHeader 24 | OriginUrl string `json:"origin_url"` 25 | } 26 | 27 | -------------------------------------------------------------------------------- /tombv1/tomb.go: -------------------------------------------------------------------------------- 1 | package tombv1 2 | 3 | import ( 4 | "fmt" 5 | "sync" 6 | "errors" 7 | ) 8 | 9 | 10 | type Tomb struct { 11 | m sync.Mutex 12 | dying chan struct{} 13 | dead chan struct{} 14 | reason error 15 | } 16 | 17 | 18 | var ( 19 | ErrStilAlive = errors.New("tomb: still alive") 20 | ErrDying = errors.New("tomb: dying") 21 | ) 22 | 23 | func (t *Tomb) init() { 24 | t.m.Lock() 25 | if t.dead == nil { 26 | // 这里默认创建的是无缓冲区的chan 27 | t.dead = make(chan struct{}) 28 | t.dying = make(chan struct{}) 29 | t.reason = ErrStilAlive 30 | } 31 | t.m.Unlock() 32 | } 33 | 34 | func (t *Tomb) Dying () <- chan struct{} { 35 | t.init() 36 | return t.dying 37 | } 38 | 39 | // 将会阻塞直到这个goroutine是dead状态,并且返回这个goroutine的death的原因 40 | func (t *Tomb) Wait() error { 41 | t.init() 42 | <- t.dead 43 | t.m.Lock() 44 | reason := t.reason 45 | t.m.Unlock() 46 | return reason 47 | } 48 | 49 | func (t *Tomb) Done() { 50 | t.Kill(nil) 51 | close(t.dead) 52 | } 53 | 54 | func (t *Tomb) Kill(reason error) { 55 | t.init() 56 | t.m.Lock() 57 | defer t.m.Unlock() 58 | if reason == ErrDying { 59 | if t.reason == ErrStilAlive { 60 | panic("tomb: Kill with ErrDying while still alive") 61 | } 62 | return 63 | } 64 | if t.reason == nil || t.reason == ErrStilAlive { 65 | t.reason = reason 66 | } 67 | select { 68 | case <- t.dying: 69 | default: 70 | close(t.dying) 71 | } 72 | } 73 | 74 | 75 | func (t *Tomb) Killf(f string, a...interface{}) error { 76 | err := fmt.Errorf(f,a...) 77 | t.Kill(err) 78 | return err 79 | } 80 | 81 | 82 | func (t *Tomb) Err()(reason error) { 83 | t.init() 84 | t.m.Lock() 85 | reason = t.reason 86 | t.m.Unlock() 87 | return 88 | } 89 | -------------------------------------------------------------------------------- /tombv1/tomb_test.go: -------------------------------------------------------------------------------- 1 | package tombv1 2 | 3 | import ( 4 | "reflect" 5 | "testing" 6 | "gopkg.in/tomb.v1" 7 | "errors" 8 | ) 9 | 10 | func TestNewTomb(t *testing.T) { 11 | tb := &tomb.Tomb{} 12 | testState(t,tb,false,false,tomb.ErrStillAlive) 13 | 14 | tb.Done() 15 | testState(t,tb,true,true,nil) 16 | } 17 | 18 | func TestKill(t *testing.T) { 19 | tb := &tomb.Tomb{} 20 | tb.Kill(nil) 21 | testState(t,tb,true,false,nil) 22 | 23 | err := errors.New("some error") 24 | tb.Kill(err) 25 | testState(t, tb, true, false, err) 26 | 27 | tb.Kill(errors.New("ignore me")) 28 | testState(t, tb,true,false,err) 29 | 30 | tb.Done() 31 | testState(t,tb,true,true,err) 32 | } 33 | 34 | 35 | 36 | func testState(t *testing.T, tb *tomb.Tomb, wantDying, wantDead bool, wantErr error) { 37 | select { 38 | case <- tb.Dying(): 39 | if !wantDying { 40 | t.Error("<-Dying:should block") 41 | } 42 | default: 43 | if wantDying { 44 | t.Error("<-DYing: should not block") 45 | } 46 | } 47 | 48 | seemsDead := false 49 | select { 50 | case <- tb.Dead(): 51 | if !wantDead { 52 | t.Error("<-Dead: should block") 53 | } 54 | seemsDead = true 55 | default: 56 | if wantDead { 57 | t.Error("<-Dead: should not block") 58 | } 59 | } 60 | 61 | 62 | if err := tb.Err();err!= wantErr { 63 | t.Errorf("Err: want %#v, got %#v", wantErr, err) 64 | } 65 | 66 | if wantDead && seemsDead { 67 | waitErr := tb.Wait() 68 | switch { 69 | case waitErr == tomb.ErrStillAlive: 70 | t.Errorf("Wait should not return ErrStillAlive") 71 | case !reflect.DeepEqual(waitErr, wantErr): 72 | t.Errorf("Want: want %#v, got %#v", wantErr, waitErr) 73 | } 74 | } 75 | } 76 | --------------------------------------------------------------------------------