分类 Golang 下的文章

var addresses []model.Address
if ret := s.db.WithContext(ctx).Model(&model.Address{}).
    Where("member_id = ?", memberId).Find(&addresses); ret.Error != nil {
    return
}
if len(addresses) > 0 {
    defineAddressIndex := 0
    for i, address := range addresses {
        if address.IsDefault == 1 {
            defineAddressIndex = i
            break
        }
    }
    result.Address = addresses[defineAddressIndex]
}

代码

package utils

import (
    "crypto/rand"
    "encoding/hex"
    "fmt"
)

func New() string {
    uuid, _ := GenerateUUID()
    return uuid
}

// GenerateRandomBytes is used to generate random bytes of given size.
func GenerateRandomBytes(size int) ([]byte, error) {
    buf := make([]byte, size)
    if _, err := rand.Read(buf); err != nil {
        return nil, fmt.Errorf("failed to read random bytes: %v", err)
    }
    return buf, nil
}

const uuidLen = 16

// GenerateUUID is used to generate a random UUID
func GenerateUUID() (string, error) {
    buf, err := GenerateRandomBytes(uuidLen)
    if err != nil {
        return "", err
    }
    return FormatUUID(buf)
}

func FormatUUID(buf []byte) (string, error) {
    if buflen := len(buf); buflen != uuidLen {
        return "", fmt.Errorf("wrong length byte slice (%d)", buflen)
    }

    return fmt.Sprintf("%x-%x-%x-%x-%x",
        buf[0:4],
        buf[4:6],
        buf[6:8],
        buf[8:10],
        buf[10:16]), nil
}

func ParseUUID(uuid string) ([]byte, error) {
    if len(uuid) != 2*uuidLen+4 {
        return nil, fmt.Errorf("uuid string is wrong length")
    }

    if uuid[8] != '-' ||
        uuid[13] != '-' ||
        uuid[18] != '-' ||
        uuid[23] != '-' {
        return nil, fmt.Errorf("uuid is improperly formatted")
    }

    hexStr := uuid[0:8] + uuid[9:13] + uuid[14:18] + uuid[19:23] + uuid[24:36]

    ret, err := hex.DecodeString(hexStr)
    if err != nil {
        return nil, err
    }
    if len(ret) != uuidLen {
        return nil, fmt.Errorf("decoded hex is the wrong length")
    }

    return ret, nil
}

使用

uud := utils.New()
fmt.Println(uud)
//9a317a2c-b5d1-ae15-7d76-27f2b48d539a

------------ js --------------

<script src="http://crypto-js.googlecode.com/svn/tags/3.0.2/build/rollups/hmac-sha256.js"></script>
<script src="http://crypto-js.googlecode.com/svn/tags/3.0.2/build/components/enc-base64-min.js"></script>

<script>
  var hash = CryptoJS.HmacSHA256("Message", "secret");
  var hashInBase64 = CryptoJS.enc.Base64.stringify(hash);
  document.write(hashInBase64);
</script>

------------- php ----------------

$s = hash_hmac('sha256', 'Message', 'secret', true);
echo base64_encode($s);

------------ go ------------------

func ComputeHmac256(message string, secret string) string {
    key := []byte(secret)
    h := hmac.New(sha256.New, key)
    h.Write([]byte(message))
    return base64.StdEncoding.EncodeToString(h.Sum(nil))
}

func main() {
    fmt.Println(ComputeHmac256("Message", "secret"))
}

通过网盘分享的文件:海康相关

链接: https://pan.baidu.com/s/1HFi-LUVvfEmJsSiNkX43Bg 提取码: 48y8

package common

import "study/model"

type MenuTree struct {
    *model.Menu
    Children []MenuTree `json:"children"`
}

// BuildTree 构建菜单树
func BuildTree(allMenu []*model.Menu, pid int64) []MenuTree {
    menuTree := make([]MenuTree, 0, len(allMenu))
    for _, menu := range allMenu {
        if pid != menu.ParentId {
            continue
        }
        mt := MenuTree{
            Menu:     menu,
            Children: BuildTree(allMenu, menu.ID),
        }
        menuTree = append(menuTree, mt)
    }
    return menuTree
}

1、下载安装包

https://studygolang.com/dl/golang/go1.22.0.linux-amd64.tar.gz

2、解压安装包

tar -zxvf go1.16.2.linux-amd64.tar.gz -C /usr/local/

3、设置环境变量

export GOROOT=/usr/local/go
export GOPATH=$HOME/go
export PATH=$PATH:$GOROOT/bin:$GOPATH/bin

4、刷新配置文件使配置生效

source /etc/profile

5、校验是否安装成功 查看 golang 的安装版本

go version

6、出现以下信息 表示安装完成

go version go1.22.0 linux/amd64

将 vue 与 golang 开发的项目部署上线的注意事宜。
1、整理本机的项目端口路径。
2、用 BT 新建一个项目网站点。
3、配置好数据库与 Redis 等。
4、最主要的是 Nignx 的配置,如下:

server
{
    listen 80;
    server_name go.studio.com;
    index index.html index.htm default.php default.htm default.html;
    root /www/wwwroot/go.studio.com/public;

    #SSL-START SSL相关配置,请勿删除或修改下一行带注释的404规则
    #error_page 404/404.html;
    #SSL-END

    #ERROR-PAGE-START  错误页配置,可以注释、删除或修改
    #error_page 404 /404.html;
    #error_page 502 /502.html;
    #ERROR-PAGE-END

    #PHP-INFO-START  PHP引用配置,可以注释或修改
    include enable-php-00.conf;
    #PHP-INFO-END

    #REWRITE-START URL重写规则引用,修改后将导致面板设置的伪静态规则失效
    include /www/server/panel/vhost/rewrite/go.studio.com.conf;
    #REWRITE-END
    
    
    #禁止访问的文件或目录
    location ~ ^/(\.user.ini|\.htaccess|\.git|\.env|\.svn|\.project|LICENSE|README.md)
    {
        return 404;
    }

    #一键申请SSL证书验证目录相关设置
    location ~ \.well-known{
        allow all;
    }

    #禁止在证书验证目录放入敏感文件
    if ( $uri ~ "^/\.well-known/.*\.(php|jsp|py|js|css|lua|ts|go|zip|tar\.gz|rar|7z|sql|bak)$" ) {
        return 403;
    }

    location ~ .*\.(gif|jpg|jpeg|png|bmp|swf)$
    {
        expires      30d;
        error_log /dev/null;
        access_log /dev/null;
    }

    location ~ .*\.(js|css)?$
    {
        expires      12h;
        error_log /dev/null;
        access_log /dev/null;
    }
    
    
    location /api {
        proxy_pass http://127.0.0.1:9985;
        proxy_set_header Host 127.0.0.1:$server_port;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header REMOTE-HOST $remote_addr;
        add_header X-Cache $upstream_cache_status;
        proxy_set_header X-Host $host:$server_port;
        proxy_set_header X-Scheme $scheme;
        proxy_connect_timeout 30s;
        proxy_read_timeout 86400s;
        proxy_send_timeout 30s;
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection "upgrade";
    }
    
    # 开启 gzip 功能
    gzip on;
    gzip_min_length 10k;
    gzip_comp_level 9;
    gzip_types text/plain text/css application/javascript application/x-javascript text/javascript application/xml;
    gzip_vary on;
    gzip_disable "MSIE [1-6]\.";
    
    access_log  /www/wwwlogs/go.studio.com.log;
    error_log  /www/wwwlogs/go.studio.com.error.log;
    
    # 显式的根路径配置
    location / {
        try_files $uri $uri/ /manage/index.html;

        # 这里可以添加其他指令或配置
    }
    
}



服务器的截图:
QQ20240318-164854@2x.png

Go 包的概念

  1. 把相同的功能放到一个目录,称之为包
  2. 包可以被其他的包引用
  3. main包用来生成可执行文件,每个程序只有一个main包
  4. 包可以提高代码的可复用性

Go 包 的特征

一个文件夹下只能有一个package。

• import后面的其实是GOPATH开始的相对目录路径,包括最后一段。但由于一个目录下只能有一个package,所以import一个路径就等于是import了这个路径下的包。
• 注意,这里指的是“直接包含”的go文件。如果有子目录,那么子目录的父目录是完全两个包。
• 比如你实现了一个计算器package,名叫calc,位于calc目录下;但又想给别人一个使用范例,于是在calc下可以建个example子目录(calc/example/),这个子目录里有个example.go(calc/example/example.go)。此时,example.go可以是main包,里面还可以有个main函数。

一个package的文件不能在多个文件夹下。

在 Golang 的文档中,Language Specification 页面,Package clause 下,指明了 A set of
files sharing the same PackageName form the implementation of a
package. An implementation may require that all source files for a
package inhabit the same directory.也就是说,一个包所有的文件,必须位于同一个目录下

•如果多个文件夹下有重名的package,它们其实是彼此无关的package。
•如果一个go文件需要同时使用不同目录下的同名package,需要在import这些目录时为每个目录指定一个package的别名。

包名自然可以和文件夹名不一样,毕竟一个是导入路径,一个是包名 但不建议这么做,这样容易造成调用这个包的人,无法快速知道这个包的名称是什么
至于为什么不用目录名作为包名,我想也正如大家所说,为了避免目录中出现奇怪的字符,也为了调用者方便使用 在 Golang 的文档中,
Language Specification 页面,Import declarations 下,有这样的说明 在Go
语言规范官方文档中有对PackageName和ImportPath的具体描述:
ImportDecl       = "import" ( ImportSpec | "(" { ImportSpec ";" } ")" ) .
ImportSpec       = [ "." | PackageName ] ImportPath .
ImportPath       = string_lit .
The PackageName is used in qualified identifiers to access exported
identifiers of the package within the importing source file. It is
declared in the file block. If the PackageName is omitted, it defaults
to the identifier specified in the package clause of the imported
package. If an explicit period (.) appears instead of a name, all the
package’s exported identifiers declared in that package’s package
block will be declared in the importing source file’s file block and
must be accessed without a qualifier.
也就是说,在执行导入的时候,若不手动定义包名,则从导入路径的源码文件中的 package 行获取包名,也即目录名和包名没有直接的关系。

结论

1、import 导入的参数是路径,而非包名。
2、尽管习惯将包名和目录名保证一致,但这不是强制规定;
3、在代码中引用包成员时,使用包名而非目录名;
4、同一目录下,所有源文件必须使用相同的包名称(因为导入时使用绝对路径,所以在搜索路径下,包必须有唯一路径,但无须是唯一名字);
5、至于文件名,更没啥限制(扩展名为.go);

中间件代码

func Cors() gin.HandlerFunc {
    return func(c *gin.Context) {
        // 这里可以用*,也可以用你指定的域名
        c.Header("Access-Control-Allow-Origin", "*")
        // 允许头部参数
        c.Header("Access-Control-Allow-Headers", "Content-Type,AccessToken,X-CSRF-Token, Authorization, Token")
        // 允许的方法
        c.Header("Access-Control-Allow-Methods", "POST, GET, OPTIONS")
        c.Header("Access-Control-Expose-Headers", "Content-Length, Access-Control-Allow-Origin, Access-Control-Allow-Headers, Content-Type")
        c.Header("Access-Control-Allow-Credentials", "true")

        method := c.Request.Method
        //放行OPTIONS方法
        if method == "OPTIONS" {
            c.AbortWithStatus(http.StatusOK)
        }
        // 处理请求
        c.Next()
    }
}

使用

// g : *gin.Engine
g.Use(Cors())




在 Go 中,defer 语句和 return 语句的执行顺序是相对固定的。当一个函数中同时存在 defer 语句和 return 语句时,它们的执行顺序如下:

1、当遇到 defer 语句时,会先计算并保存相关的表达式和参数(如果有的话),但不会立即执行这些被延迟的操作。相当于将这些操作入栈,以便稍后执行。
2、接下来,return 语句会计算返回值(如果有的话),但不会立即返回函数调用者。
3、程序会执行被延迟的 defer 语句(按照后进先出的顺序),这些被延迟的操作可能会修改函数的返回值。
4、最后,函数会返回到调用者,并将之前计算的返回值传递给调用者。
简而言之,defer 语句和 return 语句的执行顺序是 defer -> return -> defer 中的延迟操作。

让我们通过一个示例来说明这个执行顺序:

func example() int {
    defer fmt.Println("defer 1")
    defer fmt.Println("defer 2")

    fmt.Println("before return")
    return 42
}

在这个示例中,当调用 example() 函数时,输出的顺序将如下:

before return
defer 2
defer 1

我们可以看到,fmt.Println("before return") 语句会在 return 语句之前执行。然后,被延迟的 defer 语句按照后进先出的顺序执行,即先执行 "defer 2",然后执行 "defer 1"。

需要注意的是,虽然 defer 语句在 return 语句之前执行,但它们可以访问并修改函数中的变量。这是因为 defer 语句中的匿名函数会捕获并保存相关的变量引用,以便在被执行时使用。因此,当 defer 语句中的函数修改变量时,这些修改会在最终的返回值中反映出来。

默认使用方式是需要两个文件:模型文件,规则文件。这里可以直接抄代码
Editor | Casbin,这里选择RBAC模型的。
在写管理系统时,不会将规则保存在文件中,会存入数据库中使用。这个时候可能就需要我们自己写一个适配器来转换它的存储方式Policy的存储 | Casbin

QQ20231129-101300@2x.png

在进行匹配判断时,是将g类型的规则转换为p类型的规则,图中的例子,就是(g,42,1)= >(p,1,xxx)。

作者:往昔不悔
链接:https://juejin.cn/post/7164667666773311501