golang

分类下相关文章

通过 go embed.FS 将 gin 模板及静态资源文件打包进二进制程序

使用 gin 写网站会涉及到大量的外部文件: HTML 模板文件 静态资源文件:js,css,图片等 多语言翻译文件 发布时,除了要将编译好的二进制文件上传到服务器,还需要将上面提到的三类文件同步到二进制文件所在的目录。这样有两个弊端: 部署麻烦 如果是交付给客户,放在客户服务器上运行,客户能拿到这些文件的明文 embed 打包 go 1.16 引入的新特性 embed 支持将这些外部文件打包入二进制文件。 而且 gin 也支持了 embed,配置起来就更方便了。 首先需要过一遍 go embed 的官方文档,否则 gin 里的 embed 代码不容易理解。 template 及 st ...

阅读全文...

golang template range 循环中引用外部变量

LocalizeUrl 是我自定义的一个函数,接受两个参数,第一个参数是 url,第二个是语言。 但是在 gin template 中使用时报错。 报错的模板代码 {{ range $index, $product := .products }} <a href={{ LocalizeUrl (printf "/product/%d" $product.ID) .lang }}> {{ end }} 晦涩的报错信息 template: index.html:88:69: executing "index.html" at .lang: c ...

阅读全文...

sync.Map 实现 gin template 全局共享变量

需求背景 在用 gin 开发网站的时候,每个页面都需要相同的页眉和页脚。 里面有些变量是通用的,例如: 公司 logo 电话 公司名称 备案号 等等。 但是,每次都在 controller 里从数据库里读取这些配置,有两个弊端: 每个页面的 controller 都需要重复写这个配置参数传入逻辑,啰嗦 这些配置极少变化,每次都读取数据库,没有必要。可以通过缓存来优化 实现逻辑 增加一个 template func,方便 template 中直接调用,省去 controller 中传参的步骤 定义一个全局缓存,sync.Map 类型。 实现代码 cache.go langs 作为可选 ...

阅读全文...

golang 查看变量的原始定义类型

我想把 golang gin 多语言网站的语言配置提取出来,作为项目的配置项。 而我不知道 language.Chinese 到底是什么类型,是不是 zh 这样的字符串,于是想打印一下输出。 测试一下 package main import ( "fmt" "reflect" "golang.org/x/text/language" ) func main() { fmt.Println("Hello, 世界") fmt.Println(language.Chinese) // zh fmt.P ...

阅读全文...

golang gin 的多语言网站国际化支持 i18n

需求 我想在 golang gin 同一套网站模板中同时支持中文和英文,类似 SpringBoot 中的 Thymeleaf I18N 那样,能在模板中调用翻译。 <label th:text="#{label}"></label> 改造思路 但是 gin i18n 的文档里并没有介绍如何在 template 中使用翻译。大概是很少有人用 gin 写网站吧,都是如何在 api 中使用翻译的方式。 Google 搜素了半天,几乎没找到几个模板国际化相关的参考。好不容易找到一个台湾大哥的实现方案,给了我很大启发。 其实就是使用 golang templ ...

阅读全文...

golang gin 项目代码组织结构能否像 python django 一样清晰

现有的组织结构 现在使用的 golang gin 的代码组织结构是延续了之前使用 php laravel 的组织方式, 主要目录包括: models controllers views / templates public 每个目录下都是一堆堆的 go 文件,例如 controllers 下是 user.go, article.go 等。 现有结构的弊端 现有组织结构用了快两年,经历的 gin 项目多了之后,弊端就逐渐显露了出来。例如: 所有 controllers 都在一个 package 内,就算是我一个人开发、维护,都很容易出现全局变量重名的情况。不得已就得加前缀,但是这样就增加了 ...

阅读全文...

golang fmt.Sprintf 中 %d 与 %s 混用会怎样

写了一个后台分页的 bug,问题的原因在 fmt.Sprintf 中我将 int 类型传递给了 %s。 有问题的代码 categoryId := 5 if categoryId > 0 { url += fmt.Sprintf("?category=%s", categoryId) } 其输出是: /solutions?category=%!s(int=5) 导致之后的参数解析逻辑没有正常执行。 而且这个 bug 具有隐蔽性,从打印日志输出看,我看了半天也没有发现这是一个错误的输出。 后来看 golang fmt 的文档,才知道这是错误信息。 Format ...

阅读全文...

golang 生成文章简介

主要是为了用 golang 生成文章简介,及 html description 标签的内容。 逻辑 去除 html tag 取前 N 个字符 (160 个字母,或 80 个中文字符) HTML StripTags for Go, 去除 HTML 标签 https://github.com/grokify/html-strip-tags-go go get github.com/grokify/html-strip-tags-go 使用方法 import( strip "github.com/grokify/html-strip-tags-go" ) fun ...

阅读全文...

Golang 后台模板分页组件,基于 Tailwind CSS

为何不适用基于 Javascript 的分页组件 For SEO. 写 Web 就是为了能被用户搜素到,如果不是为了这个目的,web 版本都没有存在的价值。 而分页导航又是被搜索引擎收录的关键,所以一定要在后台进行渲染,不要使用 Javascript。 后台模板实现 现在来看,Laravel Django 这类框架还是比 gin 爽,毕竟内置了分页组件。 可以参考这个封装,顺便学习一些 template html 库的使用。 https://github.com/AndyEverLie/go-pagination-bootstrap 封装的很好,复用性很强。但是需要改造的地方。 TODO [ ...

阅读全文...

Golang Gorm Sum decimal 字段类型

感觉是 Gorm 的 Bug,在使用 Pluck 获取 Sum 结果时总是报错。 而用 Scan 就没有问题。 可行的做法 Scan type FHSum struct { Total float64 } var total FHSum db.Select("sum(money) as total").Scan(&total) 这样能获取到 sum 的结果。 Pluck float64 报错 var total []float64 // slice 的第一个数字就是 sum 值 db.Select("sum(money) as total&quot ...

阅读全文...

Go 1.18 版本新特性,及升级步骤

今年 315 唯一的好消息是,Golang 1.18 版本发布。 新特性 支持泛型 Generics 模糊测试 Fuzzing Workspaces 性能提升 20%。但是由于支持了泛型,编译时间比 1.17 慢 15%。 详见:https://go.dev/blog/go1.18 总体而言,新特性,我个人基本用不上。。。我果然是一个不合格的 CRUD 程序员。 泛型 Generics golang 官方文档介绍得通俗易懂,不需要过多解释。 https://go.dev/doc/tutorial/generics 可惜,我至今所有语言都没用过泛型这个特性。 模糊测试 Fuzzing 使用随 ...

阅读全文...

golang gorm 的多对多关系 CRUD 操作

例如,一个财务预算管理系统,需要能设置各部门的负责人,以方便控制查看权限。 而且可以一个部门设置多个负责人。 golang gorm 的数据结构 因为我独立建了个关系表,兼容出现多对多的关系,所以用到了 gorm many2many: type Department struct { Id int `json:"id"` Name string `json:"name"` Managers []User `gorm:"many2many:department_manager;"` Mana ...

阅读全文...

Golang 使用 sql.NullString 替代 string 类型,避免空字符串引起的唯一索引报错

例如: 用户表的用户名字段为可 Null 字段,但是如果在 golang struct 中定义为 string,则在保存时,不指定值,会默认存入空字符串。 正常情况下并没有什么影响,但是如果恰好这个字段上建了唯一索引。那么非 Null 值都必须保证唯一性。就会造成运行时异常了。 此时,需要将该字段定义为 sql.NullString import ( "database/sql" ) type User struct { gorm.Model Name sql.NullString } // 新建一个用户 models.DB.Where(models.User{ ...

阅读全文...

Golang Gorm 数据插入 MySQL 失败 Error 1054: Unknown column 'xx' in 'field list'

原因是,我 Struct 中定义了一个新字段,为了方便在接口返回数据时,能补充一个数据库中没有的信息。 这导致在 Gorm 插入 MySQL 时报错,提示未知字段错误。 插入时,忽略指定字段 查了一下,发现 Gorm 有个字段标签的功能,可以方便的忽略特定字段: https://gorm.io/zh_CN/docs/models.html#%E5%AD%97%E6%AE%B5%E6%A0%87%E7%AD%BE - 忽略该字段,- 无读写权限 甚至可以更细分的控制,读和写分别设置是否忽略。 例如: type User struct { Name string `gorm:"-& ...

阅读全文...

sql.NullTime 计算时间差

定了一个类型,实际上是 sql.NullTime。我想计算当前时间与其值的时间差。 type NullTime struct { sql.NullTime } sql.NullTime https://pkg.go.dev/database/sql#NullTime type NullTime struct { Time time.Time Valid bool // Valid is true if Time is not NULL } NullTime 实际上是个 struct,时间值存储在 Time 字段中。 time.Time 如何计算时间差 https://stackov ...

阅读全文...