JAVA转GO

GO

环境配置

go环境

下载go并安装(win下),环境变量他自己要配置上

https://dl.google.com/go/go1.21.3.windows-amd64.msi

验证是否安装成功:

//打开cmd
go version

VSCODE环境

下载VSCODE…略

配置VSCODE的环境

下载插件

image-20231016151040758

go开发工具包

打开cmd,或者VSCODE自带的终端,逐条复制

//打开go mod ,go mod相当于java的maven
go env -w GO111MODULE=on
//设置代理
go env -w GOPROXY=https://goproxy.cn,direct

然后再在VSCODE上下载工具包

Ctrl+Shift+P

输入go

点第一个,安装工具包

image-20231016151403203

全选,确定

image-20231016151434951

等待下载

go mod

go modules是官方推荐的替换GOPATH而诞生的依赖库管理工具(相当于java的maven),之前的包都放在GOPATH了

首先自己下载的go路径应该是在C盘

go env

image-20231016151625930

这样创建一个初始化案例(先转到需要初始化的文件下)

go mod init example.com/m

image-20231016151651807

发现出现了像配置文件的东西,这是用于记录依赖库和版本号的东西

image-20231016152034034

如果使用网上说的初始化

PS D:\work\GoWork\modtest> go mod init
go: cannot determine module path for source directory D:\work\GoWork\modtest (outside GOPATH, module path must be specified)

Example usage:
        'go mod init example.com/m' to initialize a v0 or v1 module    
        'go mod init example.com/m/v2' to initialize a v2 module       

Run 'go help mod init' for more information.

会提示没有指定module

意思是后面要取一个模块的名字,打开生成的go.mod文件就能看见,说明这个模块名字是module

image-20231016153050406

GO的语法

GO的小知识点

go的程序中一行就表示一个语句的结束,如果要多个语句写一行就必须用";"人为区分,实际开发中不用写分号

go的注释

//单行注释

/*

多行注释
*/

标识符:用来命名变量.类型等程序实体,一个标识符就是一个或多个字母和数字,下划线组成,第一个字符不能是数字(就是java的变量名)

字符串连接

package main
import "fmt"
func main() {
    fmt.Println("Google" + "Runoob")
    //输出GoogleRunoob
}

GO的空格

分隔标识符、关键字、运算符和表达式,以提高代码的可读性

一般VSCODE会自动帮忙填空格

在函数调用时,函数名和左边等号之间要使用空格,参数之间也要使用空格。

例如:

result := add(2, 3)

关键字和保留字

关键字

下面列举了 Go 代码中会使用到的 25 个关键字或保留字:

breakdefaultfuncinterfaceselect
casedefergomapstruct
chanelsegotopackageswitch
constfallthroughifrangetype
continueforimportreturnvar

除了以上介绍的这些关键字,Go 语言还有 36 个预定义标识符:

appendboolbytecapclosecomplexcomplex64complex128uint16
copyfalsefloat32float64imagintint8int16uint32
int32int64iotalenmakenewnilpanicuint64
printprintlnrealrecoverstringtrueuintuint8uintptr

程序一般由关键字、常量、变量、运算符、类型和函数组成。

程序中可能会使用到这些分隔符:括号 (),中括号 [] 和大括号 {}。

程序中可能会使用到这些标点符号:.,;:

数据类型

按照语言分:

序号类型和描述
1布尔型 布尔型的值只可以是常量 true 或者 false。一个简单的例子:var b bool = true。
2数字类型 整型 int 和浮点型 float32、float64,Go 语言支持整型和浮点型数字,并且支持复数,其中位的运算采用补码。
3字符串类型: 字符串就是一串固定长度的字符连接起来的字符序列。Go 的字符串是由单个字节连接起来的。Go 语言的字符串的字节使用 UTF-8 编码标识 Unicode 文本。
4派生类型: 包括:(a) 指针类型(Pointer)(b) 数组类型© 结构化类型(struct)(d) Channel 类型(e) 函数类型(f) 切片类型(g) 接口类型(interface)(h) Map 类型
数字类型

Go 也有基于架构的类型,例如:int、uint 和 uintptr。

序号类型和描述
1uint8 无符号 8 位整型 (0 到 255)
2uint16 无符号 16 位整型 (0 到 65535)
3uint32 无符号 32 位整型 (0 到 4294967295)
4uint64 无符号 64 位整型 (0 到 18446744073709551615)
5int8 有符号 8 位整型 (-128 到 127)
6int16 有符号 16 位整型 (-32768 到 32767)
7int32 有符号 32 位整型 (-2147483648 到 2147483647)
8int64 有符号 64 位整型 (-9223372036854775808 到 9223372036854775807)
浮点型
序号类型和描述
1float32 IEEE-754 32位浮点型数
2float64 IEEE-754 64位浮点型数
3complex64 32 位实数和虚数
4complex128 64 位实数和虚数

其他数字类型

以下列出了其他更多的数字类型:

序号类型和描述
1byte 类似 uint8
2rune 类似 int32
3uint 32 或 64 位
4int 与 uint 一样大小
5uintptr 无符号整型,用于存放一个指针

四种变量的声明方式

单变量,多变量,全局变量,变量类型

package main

import (
	"fmt"
)

// 声明全局变量 方法一,方法二,方法三
var gA int = 100
var gB = "qwd"

//方法四的  :=只能用在函数体内
//gc :=200

func main() {
	//方法一:声明一个变量,默认值是0
	var a int
	fmt.Println("a = ", a)
	//方法二:声明一个变量,初始化一个值
	var b int = 100
	fmt.Println("b = ", b)

	//方法三:初始化值的时候,省去数据类型,自动匹配数据类型
	var c = 1
	fmt.Println("c =", c)

	var d = "1"
	fmt.Printf("d=%s ,type of d = %T\n", d, d) //输出这里用的Printf,,输出类型

	//方法四,常用的,省去var关键字,自动匹配
	e := 100.12
	fmt.Println("e=", e)

	//声明多变量
	//var xx,yy int=100,120
	var xx, yy = "a0", 12
	fmt.Println("xx=", xx, ",yy=", yy)

	//多行的,多变量声明
	var (
		vv int  = 100
		jj bool = true
	)
	fmt.Println("vv=", vv, ",jj=", jj)

}

int的零值为0

bool的零值为false

字符串的零值为""

下面类型的零值为nil

var a *int
var a []int
var a map[string] int
var a chan int
var a func(string) int
var a error // error 是接口

值与引用

使用等号就是将一个变量的值赋值给另一个变量,例如j=i,实际上是在内存中将i的值进行了拷贝

获取内存地址: &i

也称为指针

变量需要被使用,不然会报错

极简的混合赋值:

a, b, c := 5, 7, "abc"

格式化从字符串

Go 语言中使用 fmt.Sprintffmt.Printf 格式化字符串并赋值给新串:

  • Sprintf 根据格式化参数生成格式化的字符串并返回该字符串。
  • Printf 根据格式化参数生成格式化的字符串并写入标准输出。

GO语言常量

在程序运行时不会改变的量

const b = "ab"

常量枚举

const(
	Unknown=0
	Female=1
	Male=2
)

常量函数使用

可以使用len(),cap(), unsafe.Sizeof()计算值,函数必须是内置函数

package main

import "unsafe"
const (
    a = "abc"
    b = len(a)
    c = unsafe.Sizeof(a)
)

func main(){
    println(a, b, c)
}

iota(特殊常量)

可被编译器修改的常量,在const关键词出现时重置为0,

在const中每新增一行常量声明就使iota计数一次

用法:

package main

import "fmt"

func main() {
    const (
            a = iota   //0
            b          //1
            c          //2
            d = "ha"   //独立值,iota += 1
            e          //"ha"   iota += 1
            f = 100    //iota +=1
            g          //100  iota +=1
            h = iota   //7,恢复计数
            i          //8
    )
    fmt.Println(a,b,c,d,e,f,g,h,i)
    //0 1 2 ha ha 100 100 7 8
}

GO运算符

算术运算符

下表列出了所有Go语言的算术运算符。假定 A 值为 10,B 值为 20。

运算符描述实例
+相加A + B 输出结果 30
-相减A - B 输出结果 -10
*相乘A * B 输出结果 200
/相除B / A 输出结果 2
%求余B % A 输出结果 0
++自增A++ 输出结果 11
自减A-- 输出结果 9

关系运算符

下表列出了所有Go语言的关系运算符。假定 A 值为 10,B 值为 20。

运算符描述实例
==检查两个值是否相等,如果相等返回 True 否则返回 False。(A == B) 为 False
!=检查两个值是否不相等,如果不相等返回 True 否则返回 False。(A != B) 为 True
>检查左边值是否大于右边值,如果是返回 True 否则返回 False。(A > B) 为 False
<检查左边值是否小于右边值,如果是返回 True 否则返回 False。(A < B) 为 True
>=检查左边值是否大于等于右边值,如果是返回 True 否则返回 False。(A >= B) 为 False
<=检查左边值是否小于等于右边值,如果是返回 True 否则返回 False。(A <= B) 为 True

逻辑运算符

下表列出了所有Go语言的逻辑运算符。假定 A 值为 True,B 值为 False。

运算符描述实例
&&逻辑 AND 运算符。 如果两边的操作数都是 True,则条件 True,否则为 False。(A && B) 为 False
||逻辑 OR 运算符。 如果两边的操作数有一个 True,则条件 True,否则为 False。(A || B) 为 True
!逻辑 NOT 运算符。 如果条件为 True,则逻辑 NOT 条件 False,否则为 True。!(A && B) 为 True

位运算符

位运算符对整数在内存中的二进制位进行操作。

下表列出了位运算符 &, |, 和 ^ 的计算:

pqp & qp | qp ^ q
00000
01011
11110
10011

赋值运算符

下表列出了所有Go语言的赋值运算符。

运算符描述实例
=简单的赋值运算符,将一个表达式的值赋给一个左值C = A + B 将 A + B 表达式结果赋值给 C
+=相加后再赋值C += A 等于 C = C + A
-=相减后再赋值C -= A 等于 C = C - A
*=相乘后再赋值C *= A 等于 C = C * A
/=相除后再赋值C /= A 等于 C = C / A
%=求余后再赋值C %= A 等于 C = C % A
<<=左移后赋值C <<= 2 等于 C = C << 2
>>=右移后赋值C >>= 2 等于 C = C >> 2
&=按位与后赋值C &= 2 等于 C = C & 2
^=按位异或后赋值C ^= 2 等于 C = C ^ 2
|=按位或后赋值C |= 2 等于 C = C | 2

下表列出了Go语言的其他运算符。

运算符描述实例
&返回变量存储地址&a; 将给出变量的实际地址。
*指针变量。*a; 是一个指针变量

条件运算符

Go 语言提供了以下几种条件判断语句:

语句描述
if 语句if 语句 由一个布尔表达式后紧跟一个或多个语句组成。
if…else 语句if 语句 后可以使用可选的 else 语句, else 语句中的表达式在布尔表达式为 false 时执行。
if 嵌套语句你可以在 ifelse if 语句中嵌入一个或多个 ifelse if 语句。
switch 语句switch 语句用于基于不同条件执行不同动作。
select 语句select 语句类似于 switch 语句,但是select会随机执行一个可运行的case。如果没有case可运行,它将阻塞,直到有case可运行。

注意:Go 没有三目运算符,所以不支持 ?: 形式的条件判断。

switch var1 {
    case val1:
        ...
    case val2:
        ...
    default:
        ...
}

循环语句

计算1到10的数字之和

//没得括号,而且{必须放在后面

package main

import "fmt"

func main() {
   sum := 0
      for i := 0; i <= 10; i++ {
         sum += i
      }
   fmt.Println(sum)
}

使用循环外变量

package main

import "fmt"

func main() {
   sum := 1
   for ; sum <= 10; {
      sum += sum
   }
   fmt.Println(sum)

   // 这样写也可以,更像 While 语句形式
   for sum <= 10{
      sum += sum
   }
   fmt.Println(sum)
}

死循环

就一个for加花括号

package main

import "fmt"

func main() {
   sum := 0
   for {
      sum++ // 无限循环下去
   }
   fmt.Println(sum) // 无法输出
}

停止死循环就用 ctrl+C

迭代输出

package main

import "fmt"

func main() {
	strings := []string{"google", "runoob"}
	for i, s := range strings {
		fmt.Println(i, s)
	}

	numbers := [6]int{1, 2, 3, 5}
	for i, x := range numbers {
		fmt.Printf("第 %d 位 x 的值 = %d\n", i, x)
	}
}

迭代输出省略key和value

package main
import "fmt"

func main() {
    map1 := make(map[int]float32)
    map1[1] = 1.0
    map1[2] = 2.0
    map1[3] = 3.0
    map1[4] = 4.0
    
    // 读取 key 和 value
    for key, value := range map1 {
      fmt.Printf("key is: %d - value is: %f\n", key, value)
    }

    // 读取 key
    for key := range map1 {
      fmt.Printf("key is: %d\n", key)
    }

    // 读取 value
    for _, value := range map1 {
      fmt.Printf("value is: %f\n", value)
    }
}
输出
key is: 4 - value is: 4.000000
key is: 1 - value is: 1.000000
key is: 2 - value is: 2.000000
key is: 3 - value is: 3.000000
key is: 1
key is: 2
key is: 3
key is: 4
value is: 1.000000
value is: 2.000000
value is: 3.000000
value is: 4.000000

函数

最少有个main()函数

命名格式:

func function_name( [parameter list] ) [return_types] {
   函数体
}

func:函数由 func 开始声明
function_name:函数名称,参数列表和返回值类型构成了函数签名。
parameter list:参数列表,参数就像一个占位符,当函数被调用时,你可以将值传递给参数,这个值被称为实际参数。参数列表指定的是参数类型、顺序、及参数个数。参数是可选的,也就是说函数也可以不包含参数。
return_types:返回类型,函数返回一列值。return_types 是该列值的数据类型。有些功能不需要返回值,这种情况下 return_types 不是必须的。
函数体:函数定义的代码集合。

例子:

/* 函数返回两个数的最大值 */
func max(num1, num2 int) int {
   /* 声明局部变量 */
   var result int

   if (num1 > num2) {
      result = num1
   } else {
      result = num2
   }
   return result 
}

GO函数可以返回多个值

package main

import "fmt"

func swap(x, y string) (string, string) {
   return y, x
}

func main() {
   a, b := swap("Google", "Runoob")
   fmt.Println(a, b)
}

函数的值传递

/* 定义相互交换值的函数 */
func swap(x, y int) int {
   var temp int

   temp = x /* 保存 x 的值 */
   x = y    /* 将 y 值赋给 x */
   y = temp /* 将 temp 值赋给 y*/

   return temp;
}

后面的int是指(int,int),好像可以简写

引用传递

/* 定义交换值函数*/
func swap(x *int, y *int) {
   var temp int
   temp = *x    /* 保持 x 地址上的值 */
   *x = *y      /* 将 y 值赋给 x */
   *y = temp    /* 将 temp 值赋给 y */
}

变量作用域

函数内定义的变量称为局部变量
函数外定义的变量称为全局变量
函数定义中的变量称为形式参数

数组

例子:

var balance [10]float32
var numbers [5]int
var numbers = [5]int{1, 2, 3, 4, 5}
numbers := [5]int{1, 2, 3, 4, 5}

多维数组:

a := [3][4]int{  
 {0, 1, 2, 3} ,   /*  第一行索引为 0 */
 {4, 5, 6, 7} ,   /*  第二行索引为 1 */
 {8, 9, 10, 11},   /* 第三行索引为 2 */
}

var threedim [5][10][4]int

函数里的数组:

void myFunction(param []int)
{
.
.
.
}

指针

取地址符&

取值 *

package main

import "fmt"

func main() {
   var a int= 20   /* 声明实际变量 */
   var ip *int        /* 声明指针变量 */

   ip = &a  /* 指针变量的存储地址 */

   fmt.Printf("a 变量的地址是: %x\n", &a  )

   /* 指针变量的存储地址 */
   fmt.Printf("ip 变量储存的指针地址: %x\n", ip )

   /* 使用指针访问值 */
   fmt.Printf("*ip 变量的值: %d\n", *ip )
}

空指针

if(ptr != nil)     /* ptr 不是空指针 */
if(ptr == nil)    /* ptr 是空指针 */

指针交换

package main

import "fmt"

func main() {
    /* 定义局部变量 */
   var a int = 100
   var b int= 200
   a, b = b, a

   fmt.Printf("交换后 a 的值 : %d\n", a )
   fmt.Printf("交换后 b 的值 : %d\n", b )
}

结构体

相当于对象

package main

import "fmt"

type Books struct {
	title   string
	author  string
	subject string
	book_id int
}

func main() {
	// 创建一个新的结构体
	fmt.Println(Books{"Go 语言", "www.runoob.com", "Go 语言教程", 6495407})

	// 也可以使用 key => value 格式

	fmt.Println(Books{title: "Go 语言", author: "www.runoob.com", subject: "Go 语言教程", book_id: 6495407})

	// 忽略的字段为 0 或 空
	fmt.Println(Books{title: "Go 语言", author: "www.runoob.com"})

	//访问结构成员

	var book1 Books
	book1.author = "这是作者"
	book1.book_id = 123
	fmt.Println(book1)
	fmt.Println(book1.author)

}

Go语言切片

相当于arraylist,可以动态追加元素的数组(动态数组)

切片不需要说明长度。

或使用 make() 函数来创建切片:

var slice1 []type = make([]type, len)

也可以简写为

slice1 := make([]type, len)

len()和cap()函数

len()是计算长度的,cap()是测量切片最长长度(额外长度?)

切片截取

package main

import "fmt"

func main() {
	/* 创建切片 */
	numbers := []int{0, 1, 2, 3, 4, 5, 6, 7, 8}
	printSlice(numbers)

	/* 打印原始切片 */
	fmt.Println("numbers ==", numbers)

	/* 打印子切片从索引1(包含) 到索引4(不包含)*/
	fmt.Println("numbers[1:4] ==", numbers[1:4])

	/* 默认下限为 0*/
	fmt.Println("numbers[:3] ==", numbers[:3])

	/* 默认上限为 len(s)*/
	fmt.Println("numbers[4:] ==", numbers[4:])

	numbers1 := make([]int, 0, 5)
	printSlice(numbers1)

	/* 打印子切片从索引  0(包含) 到索引 2(不包含) */
	number2 := numbers[:2]
	printSlice(number2)

	/* 打印子切片从索引 2(包含) 到索引 5(不包含) */
	number3 := numbers[2:5]
	printSlice(number3)

}

func printSlice(x []int) {
	fmt.Printf("len=%d cap=%d slice=%v\n", len(x), cap(x), x)
}


append()和copy()

例:
numbers = append(numbers,-2)//追加数字"-2"
numbers = append(numbers,-2,2,99)//追加数字"-2,2,99"

//创建切片numbers1,为上个切片的两倍容量
numbers1 := make([]int, len(numbers), (cap(numbers))*2)


//从numbers拷贝到numbers1
copy(numbers1,numbers)


Range(迭代元素)

用于 for 循环中迭代数组(array)、切片(slice)、通道(channel)或集合(map)的元素

for key, value := range numbers {
		fmt.Printf("%d-->%d", key, value)
	}
	//key在map之类的正常用,在切片/数组之类的key是数组索引

可以迭代字符串,迭代出来是Unicode

Map

键值对

//创建一个空map,键是string,值是int
m := make(map[string]int)
//创建带有初始容量的
m := make(map[string]int,10)
//创建自带键值对的
// 使用字面量创建 Map
m := map[string]int{
    "apple": 1,
    "banana": 2,
    "orange": 3,
}

// 获取键值对
value := m["apple"]
value, ok := m["pear"]  
//如果键不存在,ok 的值为 false,v2 的值为该类型的零值
//这里不能用bool,因为bool是关键字
//也记得不要取名为map,map也是关键字,小写有些是关键字

//修改元素
m["apple"]=5

//获取Map的长度
len:=len(m)

//遍历
for k,v:=range m{
    fmt.Printf("key=%s,value=%d\n",k,v)
}

//删除元素
delete(m,"banana")

递归

记得写好退出条件

func recursion() {
   recursion() /* 函数调用自身 */
}

func main() {
   recursion()
}

类型转换

整形转浮点

var a int = 10
var b float64 = float64(a)
//貌似像强转,但是换了括号位置

字符串类型转换

字符串转成整数

var str string="10"
var num int
num,_=strconv.Atoi(str)
//conv的意思是转换器/卷积
//Atoi的意思是ASCII to Integer

整数转换成字符串

num := 123
str := strconv.Itoa(num)

浮点转换字符串

num := 3.14
str := strconv.FormatFloat(num, 'f', 2, 64)
//f是格式说明符, 2是精度 小数点后两位,  64是表示浮点的位数 表示双精度

可以兼容的转换(int8转int64之类的)

	var i8 int8 = 12
	var i64 = int64(i)

接口

接口可以让我们将不同类型绑定到一组公共方法上,从而实现多态和灵活的设计

Go的接口是隐式实现的(如果一个类型实现了一个接口定义的所有方法,那么它就自动地实现了该接口)

package main

import (
	"fmt"
)

//接口类型
type Phone interface {
	call()
}

//诺基亚手机类型,用结构体代替对象
type NokiaPhone struct {
	str string
}

//诺基亚手机的call方法 ,带有参数,是为了类似于java中的this
func (nokiaPhone NokiaPhone) call() {
	nokiaPhone.str = "I am Nokia"
	fmt.Println(nokiaPhone.str, ", I can call you! ")
}

//苹果手机的结构体
type IPhone struct {
    
}

//苹果手机的call方法
func (iPhone IPhone) call() {
	fmt.Println("I am iPhone, I can call you!")
}

func main() {
	var phone Phone

	phone = new(NokiaPhone)
	phone.call()

	phone = new(IPhone)
	phone.call()

}

错误处理

内置错误接口提供了简单的错误处理机制

error类型是一个接口类型

在返回值的后面加上错误处理

func Sqrt(f float64) (float64, error) {
    if f < 0 {
        return 0, errors.New("math: square root of negative number")
    }
    // 实现
}

自定义异常结构(类)

package main

import (
    "fmt"
)

// 定义一个 DivideError 结构
type DivideError struct {
    dividee int
    divider int
}

// 实现 `error` 接口
func (de *DivideError) Error() string {
    strFormat := `
    Cannot proceed, the divider is zero.
    dividee: %d
    divider: 0
`
    return fmt.Sprintf(strFormat, de.dividee)
}

// 定义 `int` 类型除法运算的函数
func Divide(varDividee int, varDivider int) (result int, errorMsg string) {
    if varDivider == 0 {
            dData := DivideError{
                    dividee: varDividee,
                    divider: varDivider,
            }
            errorMsg = dData.Error()
            return
    } else {
            return varDividee / varDivider, ""
    }

}

func main() {

    // 正常情况
    if result, errorMsg := Divide(100, 10); errorMsg == "" {
            fmt.Println("100/10 = ", result)
    }
    // 当除数为零的时候会返回错误信息
    if _, errorMsg := Divide(100, 0); errorMsg != "" {
            fmt.Println("errorMsg is: ", errorMsg)
    }

}

并发

通过关键字开启goroutine

goroutine就是轻量级线程,

//开启新线程方法
go func1(x,y,z)

//go是关键字,func1是方法,xyz是参数

通道(channel)

传递数据的一个数据结构

用于两个goroutine传递指定类型的值来同步运行和通讯

操作符<-用于指定通道方向,没有指定方向就是表示双向通道

//channel创建
ch :=make(chan int)

ch <- v //把v发送给ch
v :<- ch  //从ch里接收数据,赋值给v


默认情况不带缓冲区,意思就是像水龙头接水一样,错过了就不管

带缓冲的通道

ch :=make(chan int, 100)//100是指,可hu
package main

import (
	"fmt"
)

func fibonacci(n int, c chan int) {
	x, y := 0, 1
	for i := 0; i < n; i++ {
		c <- x
		x, y = y, x+y
	}
	close(c)
}

func main() {
	c := make(chan int, 10)
	go fibonacci(cap(c), c)
	// range 函数遍历每个从通道接收到的数据,因为 c 在发送完 10 个
	// 数据之后就关闭了通道,所以这里我们 range 函数在接收到 10 个数据
	// 之后就结束了。如果上面的 c 通道不关闭,那么 range 函数就不
	// 会结束,从而在接收第 11 个数据的时候就阻塞了。
	for i := range c {
		fmt.Println(i)
	}
}

小练习:

Gin

Gin是一个 go 写的 web 框架,具有高性能的优点。官方地址:https://github.com/gin-gonic/gin

Gin用下面语句导一下包,就能用

 go get -u github.com/gin-gonic/gin

Gin的简单实践:

package main

import (
	"fmt"
	"github.com/gin-gonic/gin"
	"os"
	"time"
)

func main() {
	router := gin.Default()
	router.Use(RequestTimingMiddleware)
	router.GET("/hi", func(context *gin.Context) {
		context.JSON(200, gin.H{"msg": "hello"})
	})

	router.GET("/healthz", func(context *gin.Context) {
		//获取请求头
		requestHeader := context.Request.Header
		//添加VERSION环境变量
		requestHeader.Add("VERSION", os.Getenv("VERSION"))

		//Server 端记录访问日志包括客户端 IP,HTTP 返回码,输出到 server 端的标准输出
		fmt.Printf("Client IP为%s, HTTP Status: %d, Method: %s, Path: %s\n", context.ClientIP(), context.Writer.Status(), context.Request.Method, context.Request.URL.Path)
		//迭代设置请求头
		for key, values := range requestHeader {
			for _, value := range valu2es {
				context.Writer.Header().Set(key, value)
			}
		}
		//返回
		context.JSON(200, gin.H{"msg": "返回请求"})
	})

	router.Run(":8099")
}

// 时间计算中间件
func RequestTimingMiddleware(c *gin.Context) {
	startTime := time.Now()
	c.Next()
	endTime := time.Now()
	countTime := endTime.Sub(startTime)

	fmt.Printf("耗时: %v\n", countTime)
}

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值