当前位置: 首页 > article >正文

【Go语言】Fyne GUI 库使用指南 (面向有经验开发者)

引言

Fyne 是一个使用 Go 语言编写的、易于使用的跨平台 GUI 工具包和应用程序 API。它旨在通过单一代码库构建在桌面和移动设备上运行的应用程序。本文档面向有一定 Go 语言开发经验的开发者,将详细介绍 Fyne 最新版的核心功能,包括基础组件、布局系统、事件处理、自定义组件和主题定制,并提供简洁、可运行的代码示例。

在开始之前,请确保您已安装 Go (建议 1.19 或更高版本) 和 GCC 编译器。

安装 Fyne 最新版:

go get fyne.io/fyne/v2@latest

基础组件 (Basic Widgets)

Fyne 提供了一系列丰富的内置组件,用于构建用户界面。这些组件会自动适应当前主题,并处理用户交互。

1. Label (标签)

widget.Label 用于显示静态文本。它可以处理简单的格式化(如换行 \n)和文本换行(通过设置 Wrapping 字段)。

package mainimport ("fyne.io/fyne/v2/app""fyne.io/fyne/v2/widget"
)func main() {myApp := app.New()myWindow := myApp.NewWindow("Label Widget")// 创建一个简单的标签label := widget.NewLabel("这是一个 Fyne 标签")myWindow.SetContent(label)myWindow.ShowAndRun()
}

2. Button (按钮)

widget.Button 用于触发操作。它可以包含文本、图标或两者兼有。构造函数包括 widget.NewButtonwidget.NewButtonWithIcon

package mainimport ("log""fyne.io/fyne/v2/app""fyne.io/fyne/v2/widget"// "fyne.io/fyne/v2/theme" // 如果使用图标,取消注释
)func main() {myApp := app.New()myWindow := myApp.NewWindow("Button Widget")// 创建一个文本按钮,并设置点击回调button := widget.NewButton("点我", func() {log.Println("按钮被点击了")})// 创建一个带图标的按钮 (需要 theme 包)/*iconButton := widget.NewButtonWithIcon("主页", theme.HomeIcon(), func() {log.Println("带图标的按钮被点击了")})*/myWindow.SetContent(button) // 或 iconButtonmyWindow.ShowAndRun()
}

3. Entry (输入框)

widget.Entry 用于接收用户输入的单行或多行文本。可以通过 Text 字段获取内容,或使用 OnChanged 回调实时获取变化。

widget.NewPasswordEntry 用于创建密码输入框。

package mainimport ("log""fyne.io/fyne/v2/app""fyne.io/fyne/v2/container""fyne.io/fyne/v2/widget"
)func main() {myApp := app.New()myWindow := myApp.NewWindow("Entry Widget")// 创建一个输入框input := widget.NewEntry()input.SetPlaceHolder("请输入文本...") // 设置占位符// 创建一个密码输入框password := widget.NewPasswordEntry()password.SetPlaceHolder("请输入密码...")// 获取输入内容的按钮submitBtn := widget.NewButton("提交", func() {log.Println("输入内容:", input.Text)log.Println("密码内容:", password.Text)})content := container.NewVBox(input, password, submitBtn)myWindow.SetContent(content)myWindow.ShowAndRun()
}

4. Choices (选择控件)

Fyne 提供了多种选择控件,如复选框 (widget.Check)、单选按钮组 (widget.RadioGroup) 和下拉选择框 (widget.Select)。

package mainimport ("log""fyne.io/fyne/v2/app""fyne.io/fyne/v2/container""fyne.io/fyne/v2/widget"
)func main() {myApp := app.New()myWindow := myApp.NewWindow("Choice Widgets")// 复选框check := widget.NewCheck("启用选项", func(checked bool) {log.Println("复选框状态:", checked)})// 单选按钮组radio := widget.NewRadioGroup([]string{"选项 A", "选项 B"}, func(selected string) {log.Println("单选按钮选择:", selected)})radio.Horizontal = true // 水平排列// 下拉选择框selectEntry := widget.NewSelect([]string{"选项 1", "选项 2", "选项 3"}, func(selected string) {log.Println("下拉框选择:", selected)})content := container.NewVBox(check, radio, selectEntry)myWindow.SetContent(content)myWindow.ShowAndRun()
}

5. Form (表单)

widget.Form 用于方便地布局标签和输入字段,并可选择性地添加提交和取消按钮。

package mainimport ("log""fyne.io/fyne/v2/app""fyne.io/fyne/v2/widget"
)func main() {myApp := app.New()myWindow := myApp.NewWindow("Form Widget")nameEntry := widget.NewEntry()emailEntry := widget.NewEntry()messageEntry := widget.NewMultiLineEntry() // 多行输入// 创建表单项form := &widget.Form{Items: []*widget.FormItem{{Text: "姓名", Widget: nameEntry},{Text: "邮箱", Widget: emailEntry},},OnSubmit: func() {log.Println("表单提交:")log.Println("姓名:", nameEntry.Text)log.Println("邮箱:", emailEntry.Text)log.Println("消息:", messageEntry.Text)myWindow.Close()},OnCancel: func() {log.Println("表单取消")myWindow.Close()},SubmitText: "发送", // 自定义提交按钮文本CancelText: "放弃", // 自定义取消按钮文本}// 动态添加表单项form.Append("消息", messageEntry)myWindow.SetContent(form)myWindow.ShowAndRun()
}

布局系统 (Layout System)

Fyne 的布局系统负责排列和调整界面元素的大小。布局管理器决定了容器中元素的位置和尺寸。

1. Box 布局

Box 布局是最常用的布局,有水平 (HBox) 和垂直 (VBox) 两种变体。

package mainimport ("image/color""fyne.io/fyne/v2/app""fyne.io/fyne/v2/canvas""fyne.io/fyne/v2/container""fyne.io/fyne/v2/layout"
)func main() {myApp := app.New()myWindow := myApp.NewWindow("Box Layout")// 创建三个文本对象text1 := canvas.NewText("左侧", color.White)text2 := canvas.NewText("中间", color.White)text3 := canvas.NewText("右侧", color.White)// 水平布局,使用弹性空间将第三个元素推到右侧hBox := container.New(layout.NewHBoxLayout(),text1,text2,layout.NewSpacer(), // 弹性空间text3,)// 垂直布局vBox := container.New(layout.NewVBoxLayout(),canvas.NewText("顶部", color.White),canvas.NewText("中部", color.White),layout.NewSpacer(), // 弹性空间canvas.NewText("底部", color.White),)// 组合布局content := container.New(layout.NewVBoxLayout(), hBox, vBox)myWindow.SetContent(content)myWindow.ShowAndRun()
}

2. Grid 布局

Grid 布局将元素排列在固定大小的网格中。

package mainimport ("image/color""strconv""fyne.io/fyne/v2/app""fyne.io/fyne/v2/canvas""fyne.io/fyne/v2/container""fyne.io/fyne/v2/layout"
)func main() {myApp := app.New()myWindow := myApp.NewWindow("Grid Layout")// 创建一个 3x3 的网格var gridItems []interface{}for i := 1; i <= 9; i++ {text := canvas.NewText(strconv.Itoa(i), color.White)text.Alignment = fyne.TextAlignCentergridItems = append(gridItems, text)}// 使用 GridLayout,3 列grid := container.New(layout.NewGridLayout(3), gridItems...)myWindow.SetContent(grid)myWindow.ShowAndRun()
}

3. GridWrap 布局

GridWrap 布局类似于 Grid,但不固定列数,而是根据容器大小自动调整。

package mainimport ("image/color""strconv""fyne.io/fyne/v2""fyne.io/fyne/v2/app""fyne.io/fyne/v2/canvas""fyne.io/fyne/v2/container""fyne.io/fyne/v2/layout"
)func main() {myApp := app.New()myWindow := myApp.NewWindow("GridWrap Layout")// 创建多个文本对象var items []interface{}for i := 1; i <= 12; i++ {text := canvas.NewText(strconv.Itoa(i), color.White)text.Alignment = fyne.TextAlignCenteritems = append(items, text)}// 使用 GridWrapLayout,每个单元格大小为 50x50gridWrap := container.New(layout.NewGridWrapLayout(fyne.NewSize(50, 50)), items...)myWindow.Resize(fyne.NewSize(300, 200))myWindow.SetContent(gridWrap)myWindow.ShowAndRun()
}

4. Border 布局

Border 布局允许在容器的四个边缘和中心放置元素。

package mainimport ("fyne.io/fyne/v2/app""fyne.io/fyne/v2/container""fyne.io/fyne/v2/layout""fyne.io/fyne/v2/widget"
)func main() {myApp := app.New()myWindow := myApp.NewWindow("Border Layout")// 创建边框布局top := widget.NewLabel("顶部")bottom := widget.NewLabel("底部")left := widget.NewLabel("左侧")right := widget.NewLabel("右侧")center := widget.NewLabel("中心内容")border := container.New(layout.NewBorderLayout(top, bottom, left, right),top, bottom, left, right, center)myWindow.SetContent(border)myWindow.ShowAndRun()
}

5. Center 布局

Center 布局将单个元素居中显示。

package mainimport ("fyne.io/fyne/v2/app""fyne.io/fyne/v2/container""fyne.io/fyne/v2/layout""fyne.io/fyne/v2/widget"
)func main() {myApp := app.New()myWindow := myApp.NewWindow("Center Layout")// 创建一个按钮并居中显示button := widget.NewButton("居中按钮", func() {})centered := container.New(layout.NewCenterLayout(), button)myWindow.SetContent(centered)myWindow.ShowAndRun()
}

事件处理 (Event Handling)

Fyne 提供了多种方式来处理用户交互事件。从 Fyne v2.6.0 开始,所有事件和回调都在同一个 goroutine 上执行,这提高了性能并改善了线程安全性。

1. 基本回调函数

最简单的事件处理方式是通过组件构造函数提供回调函数。

package mainimport ("log""fyne.io/fyne/v2/app""fyne.io/fyne/v2/container""fyne.io/fyne/v2/widget"
)func main() {myApp := app.New()myWindow := myApp.NewWindow("Event Callbacks")// 按钮点击事件button := widget.NewButton("点击我", func() {log.Println("按钮被点击")})// 输入框内容变化事件entry := widget.NewEntry()entry.OnChanged = func(text string) {log.Println("输入内容变化:", text)}// 复选框状态变化事件check := widget.NewCheck("选择", func(checked bool) {log.Println("复选框状态:", checked)})content := container.NewVBox(button, entry, check)myWindow.SetContent(content)myWindow.ShowAndRun()
}

2. 使用 Goroutines

虽然 Fyne 的事件处理在单一 goroutine 上执行,但有时需要在后台执行耗时操作。

package mainimport ("log""time""fyne.io/fyne/v2""fyne.io/fyne/v2/app""fyne.io/fyne/v2/container""fyne.io/fyne/v2/widget"
)func main() {myApp := app.New()myWindow := myApp.NewWindow("Goroutine Example")progress := widget.NewProgressBar()status := widget.NewLabel("就绪")// 启动耗时操作的按钮startBtn := widget.NewButton("开始处理", func() {status.SetText("处理中...")progress.SetValue(0)// 在后台 goroutine 中执行耗时操作go func() {// 模拟耗时操作for i := 0.0; i <= 1.0; i += 0.1 {time.Sleep(200 * time.Millisecond)// 更新 UI 必须在主 goroutine 上执行fyne.CurrentApp().Driver().RunOnMain(func() {progress.SetValue(i)})}// 完成后更新 UIfyne.CurrentApp().Driver().RunOnMain(func() {status.SetText("处理完成")})}()})content := container.NewVBox(startBtn, progress, status)myWindow.SetContent(content)myWindow.ShowAndRun()
}

3. 键盘和鼠标事件

Fyne 允许监听键盘和鼠标事件。

package mainimport ("fmt""fyne.io/fyne/v2""fyne.io/fyne/v2/app""fyne.io/fyne/v2/container""fyne.io/fyne/v2/widget"
)func main() {myApp := app.New()myWindow := myApp.NewWindow("Input Events")eventLog := widget.NewMultiLineEntry()eventLog.Wrapping = fyne.TextWrapWord// 创建一个可以接收键盘焦点的画布canvas := container.NewVBox()canvas.Resize(fyne.NewSize(300, 200))// 键盘事件myWindow.Canvas().SetOnTypedKey(func(key *fyne.KeyEvent) {eventLog.Text += fmt.Sprintf("键盘事件: %v\n", key.Name)eventLog.Refresh()})// 鼠标事件myWindow.Canvas().SetOnTapped(func(pe *fyne.PointEvent) {eventLog.Text += fmt.Sprintf("点击事件: 位置 x=%v, y=%v\n", pe.Position.X, pe.Position.Y)eventLog.Refresh()})content := container.NewVBox(widget.NewLabel("在窗口中点击或按键:"),canvas,widget.NewLabel("事件日志:"),eventLog,)myWindow.SetContent(content)myWindow.Resize(fyne.NewSize(400, 300))myWindow.ShowAndRun()
}

自定义组件 (Custom Widgets)

Fyne 允许开发者创建自定义组件,以满足特定需求。

1. 创建自定义布局

自定义布局需要实现 fyne.Layout 接口,该接口定义了如何排列和调整容器中的对象大小。

package mainimport ("fyne.io/fyne/v2""fyne.io/fyne/v2/app""fyne.io/fyne/v2/container""fyne.io/fyne/v2/widget"
)// 自定义布局:将所有元素堆叠在一起,但每个元素有一个偏移量
type OffsetLayout struct {Offset fyne.Position
}// MinSize 计算所有子元素所需的最小尺寸
func (o *OffsetLayout) MinSize(objects []fyne.CanvasObject) fyne.Size {minSize := fyne.NewSize(0, 0)for _, obj := range objects {objMin := obj.MinSize()minSize.Width = fyne.Max(minSize.Width, objMin.Width+o.Offset.X*float32(len(objects)-1))minSize.Height = fyne.Max(minSize.Height, objMin.Height+o.Offset.Y*float32(len(objects)-1))}return minSize
}// Layout 排列子元素
func (o *OffsetLayout) Layout(objects []fyne.CanvasObject, containerSize fyne.Size) {pos := fyne.NewPos(0, 0)for _, obj := range objects {size := obj.MinSize()obj.Resize(size)obj.Move(pos)pos = pos.Add(o.Offset)}
}func main() {myApp := app.New()myWindow := myApp.NewWindow("Custom Layout")// 创建三个按钮btn1 := widget.NewButton("按钮 1", nil)btn2 := widget.NewButton("按钮 2", nil)btn3 := widget.NewButton("按钮 3", nil)// 使用自定义布局customLayout := &OffsetLayout{Offset: fyne.NewPos(10, 10)}content := container.New(customLayout, btn1, btn2, btn3)myWindow.SetContent(content)myWindow.Resize(fyne.NewSize(200, 200))myWindow.ShowAndRun()
}

2. 创建自定义小部件

自定义小部件需要实现 fyne.Widget 接口,通常通过嵌入 widget.BaseWidget 来简化实现。

package mainimport ("image/color""fyne.io/fyne/v2""fyne.io/fyne/v2/app""fyne.io/fyne/v2/canvas""fyne.io/fyne/v2/widget"
)// 自定义彩色按钮小部件
type ColoredButton struct {widget.BaseWidgetText     stringBgColor  color.ColorOnTapped func()
}// 创建新的彩色按钮
func NewColoredButton(text string, bgColor color.Color, tapped func()) *ColoredButton {button := &ColoredButton{Text:     text,BgColor:  bgColor,OnTapped: tapped,}button.ExtendBaseWidget(button)return button
}// CreateRenderer 是实现 Widget 接口的必要方法
func (b *ColoredButton) CreateRenderer() fyne.WidgetRenderer {background := canvas.NewRectangle(b.BgColor)text := canvas.NewText(b.Text, color.White)text.Alignment = fyne.TextAlignCenterreturn &coloredButtonRenderer{button:     b,background: background,text:       text,objects:    []fyne.CanvasObject{background, text},}
}// 按钮渲染器
type coloredButtonRenderer struct {button     *ColoredButtonbackground *canvas.Rectangletext       *canvas.Textobjects    []fyne.CanvasObject
}func (r *coloredButtonRenderer) MinSize() fyne.Size {return fyne.NewSize(100, 40) // 固定大小
}func (r *coloredButtonRenderer) Layout(size fyne.Size) {r.background.Resize(size)r.text.Resize(size)
}func (r *coloredButtonRenderer) Refresh() {r.background.FillColor = r.button.BgColorr.text.Text = r.button.Textr.background.Refresh()r.text.Refresh()
}func (r *coloredButtonRenderer) Objects() []fyne.CanvasObject {return r.objects
}func (r *coloredButtonRenderer) Destroy() {}// 实现 Tappable 接口
func (b *ColoredButton) Tapped(*fyne.PointEvent) {if b.OnTapped != nil {b.OnTapped()}
}func main() {myApp := app.New()myWindow := myApp.NewWindow("Custom Widget")// 创建自定义彩色按钮redButton := NewColoredButton("红色按钮", color.NRGBA{R: 200, G: 30, B: 30, A: 255}, func() {println("红色按钮被点击")})blueButton := NewColoredButton("蓝色按钮", color.NRGBA{R: 30, G: 30, B: 200, A: 255}, func() {println("蓝色按钮被点击")})greenButton := NewColoredButton("绿色按钮", color.NRGBA{R: 30, G: 200, B: 30, A: 255}, func() {println("绿色按钮被点击")})// 垂直排列按钮content := container.NewVBox(redButton, blueButton, greenButton)myWindow.SetContent(content)myWindow.ShowAndRun()
}

主题定制 (Theme Customization)

Fyne 允许通过实现 fyne.Theme 接口来自定义应用程序的外观。

package mainimport ("image/color""fyne.io/fyne/v2""fyne.io/fyne/v2/app""fyne.io/fyne/v2/container""fyne.io/fyne/v2/theme""fyne.io/fyne/v2/widget"
)// 自定义主题
type myTheme struct{}// 确保实现了 fyne.Theme 接口
var _ fyne.Theme = (*myTheme)(nil)// 自定义颜色
func (m myTheme) Color(name fyne.ThemeColorName, variant fyne.ThemeVariant) color.Color {if name == theme.ColorNameBackground {if variant == theme.VariantLight {return color.NRGBA{R: 0xf0, G: 0xf0, B: 0xff, A: 0xff} // 浅蓝色背景}return color.NRGBA{R: 0x30, G: 0x30, B: 0x40, A: 0xff} // 深蓝色背景}if name == theme.ColorNamePrimary {return color.NRGBA{R: 0x80, G: 0x80, B: 0xff, A: 0xff} // 紫蓝色主色调}// 其他颜色使用默认主题return theme.DefaultTheme().Color(name, variant)
}// 使用默认字体
func (m myTheme) Font(style fyne.TextStyle) fyne.Resource {return theme.DefaultTheme().Font(style)
}// 使用默认图标
func (m myTheme) Icon(name fyne.ThemeIconName) fyne.Resource {return theme.DefaultTheme().Icon(name)
}// 自定义尺寸
func (m myTheme) Size(name fyne.ThemeSizeName) float32 {if name == theme.SizeNamePadding {return 10 // 自定义内边距}return theme.DefaultTheme().Size(name)
}func main() {myApp := app.New()// 应用自定义主题myApp.Settings().SetTheme(&myTheme{})myWindow := myApp.NewWindow("Custom Theme")// 创建一些组件来展示主题label := widget.NewLabel("自定义主题示例")button := widget.NewButton("按钮", func() {})entry := widget.NewEntry()entry.SetPlaceHolder("输入文本...")check := widget.NewCheck("复选框", nil)radio := widget.NewRadioGroup([]string{"选项1", "选项2"}, nil)content := container.NewVBox(label,button,entry,check,radio,)myWindow.SetContent(content)myWindow.Resize(fyne.NewSize(300, 300))myWindow.ShowAndRun()
}

四则运算计算器示例

下面是一个完整的四则运算计算器 GUI 示例,展示了 Fyne 的实际应用。

package mainimport ("fmt""strconv""strings""fyne.io/fyne/v2""fyne.io/fyne/v2/app""fyne.io/fyne/v2/container""fyne.io/fyne/v2/layout""fyne.io/fyne/v2/theme""fyne.io/fyne/v2/widget"
)func main() {myApp := app.New()myWindow := myApp.NewWindow("四则运算计算器")// 显示结果的输入框display := widget.NewLabel("")display.SetText("0")// 存储操作数和运算符var (firstNumber  float64 = 0operator     string  = ""resetDisplay bool    = true)// 数字按钮处理函数numberPressed := func(num string) {if resetDisplay {display.SetText(num)resetDisplay = false} else {current := display.Textif current == "0" {display.SetText(num)} else {display.SetText(current + num)}}}// 运算符按钮处理函数operatorPressed := func(op string) {var err errorfirstNumber, err = strconv.ParseFloat(display.Text, 64)if err != nil {display.SetText("错误")return}operator = opresetDisplay = true}// 等号按钮处理函数equalsPressed := func() {if operator == "" {return}secondNumber, err := strconv.ParseFloat(display.Text, 64)if err != nil {display.SetText("错误")return}var result float64switch operator {case "+":result = firstNumber + secondNumbercase "-":result = firstNumber - secondNumbercase "*":result = firstNumber * secondNumbercase "/":if secondNumber == 0 {display.SetText("除数不能为零")return}result = firstNumber / secondNumber}// 格式化结果,去除不必要的小数点和零resultStr := fmt.Sprintf("%.6f", result)resultStr = strings.TrimRight(strings.TrimRight(resultStr, "0"), ".")display.SetText(resultStr)operator = ""resetDisplay = true}// 清除按钮处理函数clearPressed := func() {display.SetText("0")firstNumber = 0operator = ""resetDisplay = true}// 创建数字按钮 (0-9)buttons := make([]*widget.Button, 10)for i := 0; i <= 9; i++ {num := strconv.Itoa(i)buttons[i] = widget.NewButton(num, func(n string) func() {return func() {numberPressed(n)}}(num))}// 创建运算符按钮addButton := widget.NewButton("+", func() { operatorPressed("+") })subtractButton := widget.NewButton("-", func() { operatorPressed("-") })multiplyButton := widget.NewButton("*", func() { operatorPressed("*") })divideButton := widget.NewButton("/", func() { operatorPressed("/") })equalsButton := widget.NewButton("=", equalsPressed)clearButton := widget.NewButton("C", clearPressed)// 创建小数点按钮decimalButton := widget.NewButton(".", func() {if !strings.Contains(display.Text, ".") {display.SetText(display.Text + ".")resetDisplay = false}})// 布局计算器界面buttonGrid := container.New(layout.NewGridLayout(4),buttons[7], buttons[8], buttons[9], addButton,buttons[4], buttons[5], buttons[6], subtractButton,buttons[1], buttons[2], buttons[3], multiplyButton,buttons[0], decimalButton, equalsButton, divideButton,)// 组合显示区域和按钮区域content := container.NewVBox(display,clearButton,buttonGrid,)myWindow.SetContent(content)myWindow.Resize(fyne.NewSize(300, 250))myWindow.ShowAndRun()
}

fyne示例

总结

本文档详细介绍了 Fyne GUI 库最新版的核心功能,包括基础组件、布局系统、事件处理、自定义组件和主题定制,并提供了简洁、可运行的代码示例。通过这些示例,有经验的 Go 开发者可以快速上手 Fyne,构建跨平台的 GUI 应用程序。

Fyne 的优势在于其简洁的 API 设计、跨平台能力和现代化的外观。它适合开发各种规模的应用程序,从简单的工具到复杂的企业级应用。

要深入了解 Fyne 的更多功能,请参考官方文档:https://docs.fyne.io/

参考资源

  1. Fyne 官方文档:https://docs.fyne.io/
  2. Fyne GitHub 仓库:https://github.com/fyne-io/fyne
  3. Fyne API 文档:https://pkg.go.dev/fyne.io/fyne/v2
  4. Fyne 扩展组件:https://addons.fyne.io/

相关文章:

【Go语言】Fyne GUI 库使用指南 (面向有经验开发者)

引言 Fyne 是一个使用 Go 语言编写的、易于使用的跨平台 GUI 工具包和应用程序 API。它旨在通过单一代码库构建在桌面和移动设备上运行的应用程序。本文档面向有一定 Go 语言开发经验的开发者&#xff0c;将详细介绍 Fyne 最新版的核心功能&#xff0c;包括基础组件、布局系统…...

Nginx Lua模块(OpenResty)实战:动态化、智能化你的Nginx,实现复杂Web逻辑 (2025)

更多服务器知识&#xff0c;尽在hostol.com 嘿&#xff0c;各位Nginx的“铁杆粉丝”和“配置大师”们&#xff01;咱们都知道&#xff0c;Nginx以其超凡的性能、稳定性和丰富的模块化功能&#xff0c;在Web服务器、反向代理、负载均衡等领域独步青云&#xff0c;简直是服务器软…...

openssl 怎么生成吊销列表

mkdir test cd test # 根据 /usr/lib/ssl/openssl.cnf 配置文件中目录结构可知有个demoCA目录&#xff0c;目录下有各种文件。 mkdir ./demoCA ./demoCA/newcerts ./demoCA/private sudo chmod 777 -R ./demoCA/ echo 01 > ./demoCA/serial touch ./demoCA/index.txt # /usr…...

Go语言包的组织与导入 -《Go语言实战指南》

在 Go 语言中&#xff0c;包&#xff08;Package&#xff09; 是管理代码模块化、复用性与可维护性的核心单位。本章将讲解如何组织包结构、如何导入其他包、以及项目中的最佳实践。 一、什么是包&#xff1f; • 每个 .go 文件都属于某个包&#xff08;通过 package 声明&…...

springboot-响应接收与ioc容器控制反转、Di依赖注入

1.想将服务器中的数据返回给客户端&#xff0c;需要在controller类上加注解&#xff1a;ResponseBody; 这个注解其实在前面已经使用过&#xff0c;RestController其实就包含两个注解&#xff1a; Controller ResponseBody 返回值如果是实体对象/集合&#xff0c;将会转换为j…...

CSP使用严格设置

文章目录 说明示例 说明 日期&#xff1a;2025年6月2日。 内容安全政策&#xff08;MPS&#xff09;是一个额外的安全层&#xff0c;有助于检测和缓解某些类型的攻击。包括&#xff08;但不限于&#xff09;跨站点脚本&#xff08;XSS&#xff09;和数据注入攻击。这些攻击用…...

Spring代理工厂类ProxyFactory作用以及实现原理

代理工厂类ProxyFactory AdvisedSupport&#xff08;代理配置信息类&#xff09;ProxyFactory&#xff08;代理工厂类&#xff09;小结测试 源码见&#xff1a;mini-spring 在 AOP&#xff08;面向切面编程&#xff09;中&#xff0c;Spring 支持两种常见的代理机制&#xff1a…...

SpringBoot使用MQTT协议简述

在 Spring Boot 中使用 MQTT 协议连接硬件设备&#xff0c;可以通过以下步骤实现。这里以 Eclipse Paho MQTT 客户端为例&#xff1a; 1. 添加 Maven 依赖 <dependencies><!-- Spring Boot Starter --><dependency><groupId>org.springframework.boo…...

【GraphQL】深入解析 Apollo Client:从架构到实践的一站式 GraphQL 解决方案

深入解析 Apollo Client&#xff1a;从架构到实践的一站式 GraphQL 解决方案 1. 引言 GraphQL 作为现代 API 开发的核心技术&#xff0c;其灵活性和高效性正在重塑数据交互模式。Apollo Client 作为 GraphQL 生态中最受欢迎的客户端库&#xff0c;凭借强大的缓存机制、框架集…...

集成电路制造设备防震基座选型指南:为稳定护航-江苏泊苏系统集成有限公司

集成电路制造设备防震基座选型指南&#xff1a;为稳定护航 在集成电路制造这一精密复杂的领域&#xff0c;每一个环节都如同精密仪器中的微小齿轮&#xff0c;一丝偏差都可能导致严重后果。制造设备的稳定运行更是重中之重&#xff0c;而防震基座作为守护设备稳定的第一道防线…...

华为OD机试真题——阿里巴巴找黄金宝箱(II)(2025A卷:100分)Java/python/JavaScript/C/C++/GO最佳实现

2025 A卷 100分 题型 本专栏内全部题目均提供Java、python、JavaScript、C、C++、GO六种语言的最佳实现方式; 并且每种语言均涵盖详细的问题分析、解题思路、代码实现、代码详解、3个测试用例以及综合分析; 本文收录于专栏:《2025华为OD真题目录+全流程解析+备考攻略+经验分…...

Vue中 toRaw 和 markRaw 的使用

背景 针对一些特殊的需求&#xff0c;在项目里&#xff0c;需要将响应式数据变为普通原始类型数据&#xff0c;这种情况是有的 在 Vue 中&#xff0c;能够将普通数据类型的数据变为响应式数据&#xff0c;也能将响应式类型数据变为普通类型数据&#xff0c;用于提升数据的性能…...

探索DeepSeek提示词:关键策略与实用场景

在人工智能飞速发展的时代&#xff0c;DeepSeek作为一款备受关注的AI工具&#xff0c;其强大的功能为用户提供了高效便捷的服务。然而&#xff0c;要充分发挥DeepSeek的潜力&#xff0c;掌握提示词的使用策略至关重要。本文将深入探讨DeepSeek提示词的关键策略&#xff0c;并结…...

海底三维可视化平台

1. 摘要 本文作者为视觉分析构建了一个真实海底的“虚拟世界”。在3D环境中导入底部轮廓。在该模型中&#xff0c;通过地震反射获得的海床地层剖面被数字化为离散点&#xff0c;并用克里金算法进行插值&#xff0c;以在每个地层中产生均匀的网格。然后在每一层构建 Delaunay三…...

Elasticsearch 读写流程深度解析

在数据驱动的数字化浪潮中&#xff0c;Elasticsearch 凭借其毫秒级搜索响应与水平扩展能力&#xff0c;已成为现代数据架构的核心引擎。本文将深入剖析其读写流程的设计思想、实现细节与工程权衡&#xff0c;揭示这一分布式系统的精妙架构。 一、 架构基石&#xff1a;分布式设…...

AIoT赋能场馆数字化转型:智能管理新生态

在数字化浪潮席卷全球的当下&#xff0c;传统场馆管理模式已难以满足日益增长的高效运营与精细化服务需求。智慧场馆建设成为行业发展的必然趋势&#xff0c;而AIoT&#xff08;人工智能物联网&#xff09;技术的深度应用&#xff0c;为多系统集成提供了全新的解决方案&#xf…...

1、Pytorch介绍与安装

1、Pytorch介绍 PyTorch 是由 Facebook AI Research (FAIR) 团队开发并维护的一款开源深度学习框架&#xff0c;于 2016 年首次发布。它因其直观的设计、卓越的灵活性以及强大的动态计算图功能&#xff0c;迅速在学术界和工业界获得了广泛认可&#xff0c;成为当前深度学习研究…...

【从零开始学习QT】Qt 概述

目录 一、什么是 Qt 1.1 简介 1.2 Qt 的发展史 1.3 Qt 支持的平台 1.5 Qt 的优点 1.6 Qt 的应用场景 二、搭建 Qt 开发环境 2.1 Qt SDK 的下载 2.2 Qt SDK 的安装 2.3 验证 Qt SDK 安装是否成功 2.4 Qt 环境变量配置 三、认识 Qt Creator 3.1 Qt Creator 概览 3.…...

家庭路由器改装,搭建openwrt旁路由以及手机存储服务器,实现外网节点转发、内网穿透、远程存储、接入满血DeepSeek方案

大家好&#xff0c;也是好久没有发文了&#xff0c;最近在捣鼓一些比较有趣的东西&#xff0c;打算跟大家分享一下&#xff01; 先聊一下我的大致方案嘛&#xff0c;最近感觉家里路由器平时一直就只有无线广播供网的功能&#xff0c;感觉这么好的一下嵌入式设备产品不应该就干这…...

人工智能工程技术专业 和 其他信息技术专业 有哪些关联性?

人工智能工程技术专业与其他信息技术专业之间存在紧密的关联性&#xff0c;这些关联既体现在基础理论、技术体系上&#xff0c;也反映在行业应用和技术融合的趋势中。以下从多个维度解析它们的关联性&#xff1a; 一、基础学科与核心技术的共通性 数学与算法基础 关联专业&…...

基于本地模型+多级校验设计的高效缓存,有效节省token数量(有点鸡肋doge)。

前言 我是基于token有限而考虑的一个省钱方案&#xff0c;还能够快速返回结果&#xff0c;但是劣势也很明显&#xff0c;设计不好容易出问题&#xff0c;就如下面所介绍的语义飘逸和缓存污染&#xff0c;我认为在自己学习大模型的过程用来省钱非常可以&#xff0c;再加上学习过…...

逐步检索增强推理的跨知识库路由学习

摘要 多模态检索增强生成&#xff08;MRAG&#xff09;在多模态大语言模型&#xff08;MLLM&#xff09;中通过在生成过程中结合外部知识来减轻幻觉的发生&#xff0c;已经显示出了良好的前景。现有的MRAG方法通常采用静态检索流水线&#xff0c;该流水线从多个知识库&#xff…...

用Git管理你的服务器配置文件与自动化脚本:版本控制、变更追溯、团队协作与安全回滚的运维之道

更多服务器知识&#xff0c;尽在hostol.com 咱们在和服务器打交道的日子里&#xff0c;是不是经常要和各种各样的配置文件&#xff08;Nginx的、Apache的、PHP的、防火墙的……&#xff09;还有自己辛辛苦苦写下的自动化脚本打交道&#xff1f;那你有没有遇到过这样的“抓狂”…...

【数据库】关系数据库标准语言-SQL(金仓)下

4、数据查询 语法&#xff1a; SELECT [ALL | DISTINCT] <目标列表达式> [,<目标列表达式>] … FROM <表名或视图名>[, <表名或视图名> ] … [ WHERE <条件表达式> ] [ GROUP BY <列名1> [ HAVING <条件表达式> ] ] [ ORDER BY <…...

Vue3+SpringBoot全栈开发:从零实现增删改查与分页功能

前言 在现代化Web应用开发中&#xff0c;前后端分离架构已成为主流。本文将详细介绍如何使用Vue3作为前端框架&#xff0c;SpringBoot作为后端框架&#xff0c;实现一套完整的增删改查(CRUD)功能&#xff0c;包含分页查询、条件筛选等企业级特性。 技术栈介绍 前端&#xff1…...

小黑大语言模型应用探索:langchain智能体构造源码demo搭建1(初步流程)

导入工具包 rom langchain_core.tools import BaseTool from typing import Sequence, Optional, List from langchain_core.prompts import BasePromptTemplate import re from langchain_core.tools import tool from langchain_core.prompts.chat import (ChatPromptTempla…...

极客时间:用 FAISS、LangChain 和 Google Colab 模拟 LLM 的短期与长期记忆

每周跟踪AI热点新闻动向和震撼发展 想要探索生成式人工智能的前沿进展吗&#xff1f;订阅我们的简报&#xff0c;深入解析最新的技术突破、实际应用案例和未来的趋势。与全球数同行一同&#xff0c;从行业内部的深度分析和实用指南中受益。不要错过这个机会&#xff0c;成为AI领…...

leetcode hot100刷题日记——35.子集

解答&#xff1a; 方法一&#xff1a;选or不选的dfs&#xff08;输入视角&#xff09; 思路&#xff1a;[1,2,3]的全部子集可以看成是对数组的每一位数字做选择。 eg.空集就是一个数字都不选&#xff0c;[1,2]就是1&#xff0c;2选&#xff0c;3不选。 class Solution { pub…...

MybatisPlus(含自定义SQL、@RequiredArgsConstructor、静态工具类Db)

大家在日常开发中应该能发现&#xff0c;单表的CRUD功能代码重复度很高&#xff0c;也没有什么难度。而这部分代码量往往比较大&#xff0c;开发起来比较费时。 因此&#xff0c;目前企业中都会使用一些组件来简化或省略单表的CRUD开发工作。目前在国内使用较多的一个组件就是…...

React 组件异常捕获机制详解

1. 错误边界&#xff08;Error Boundaries&#xff09;基础 在React应用开发中&#xff0c;组件异常的有效捕获对于保证应用稳定性至关重要。React提供了一种称为"错误边界"的机制&#xff0c;专门用于捕获和处理组件树中的JavaScript错误。 错误边界是React的一种…...