Go开发学习 | 如何使用Gomail.v2模块包发送邮箱验证码消息及附件学习记录

news2024/11/19 12:31:58

欢迎关注「全栈工程师修炼指南」公众号

点击 👇 下方卡片 即可关注我哟!

设为星标⭐每天带你 基础入门 到 进阶实践 再到 放弃学习

  花开堪折直须折,莫待无花空折枝 


作者主页:[ https://www.weiyigeek.top ]  

博客:[ https://blog.weiyigeek.top ]

作者安全运维学习答疑交流群:请关注公众号回复【学习交流群


文章目录:

0x00 前言简述

0x01 常用模块

    • Gomail 模块 - 邮件发送模块

      • 示例演示

        • 示例1.gomail快速上手实践

        • 示例2.gomail邮件消息群发

        • 示例3.自定义方法封装Gomail实现发送文本、HTML以及附件

        • 示例4.Gomail发送HTML注册找回验证码

        • 示例 5.正式环境中我们一般会用管道 channel 来创建一个邮件发送服务.

      • 入坑出坑


0x00 前言简述

描述: 在某些系统中往往需要实时的监控应用的健康信息以及关键操作信息的发送,若要使用Go语言实现上述报警信息的发送,通常会在企业中使用邮件的形式或者Webhook钩子的形式进行预警(例如,钉钉、企业微信)推荐,当然你也可以使用openwechat项目实现个人微信推送以及go-cqhttp项目实现QQ推送,不论你使用何种方式实现信息发送都是可以请根据自身的实际情况进行选择。


0x01 常用模块

Gomail 模块 - 邮件发送模块

描述: Gomail是一个简单高效的发送电子邮件go语言的模块包,其使用SMTP服务器发送电子邮件含附件,请注意它需要 Go 1.2 或更高版本。
项目地址: https://github.com/go-gomail/gomail
文档地址: https://pkg.go.dev/gopkg.in/gomail.v2
支持特性:

  • 附件发送

  • 嵌入的图像

  • 网页和文本模板

  • 特殊字符的自动编码

  • SSL 和 TLS

  • 使用相同的 SMTP 连接发送多封电子邮件

示例演示

示例1.gomail快速上手实践

描述: 使用 gopkg.in/gomail.v2发送邮件一般有 9 个步骤,分别如下

  •  首先构建一个 Message 对象,也就是邮件对象

  •  填充发件人 From

  •  填充收件人 To

  •  填充抄送 Cc

  •  设置邮件标题 Subject

  •  设置邮件正文

  •  如果有需要,可以添加附件

  •  实例化一个邮件发送器

  •  连接到邮件服务器并发送,此处主要有两个方法 mailer.NewDialer 和 mailer.Send 或者通过管道形式。

package main

import (
  mailer "gopkg.in/gomail.v2"
)

func main() {
    // 1. 首先构建一个 Message 对象,也就是邮件对象
    msg := mailer.NewMessage()
    // 2. 填充 From,注意第一个字母要大写
    msg.SetHeader("From", "from_address@example.com")
    // 3. 填充 To
    msg.SetHeader("To", "to_address@example.com")
    // 4. 如果需要可以填充 cc,也就是抄送
    msg.SetHeader("Cc", "cc_address@example.com")
    // 5. 设置邮件标题
    msg.SetHeader("Subject", "Go 语言发送邮件")
    // 6. 设置要发送的邮件正文
    // 第一个参数是类型,第二个参数是内容
    // 如果是 html,第一个参数则是 `text/html` 如果是文本则是"text/plain"
    msg.SetBody("text/html", "<h3>欢迎来到简单教程</h3><p>简单教程,简单编程</p>")
    // 7. 添加附件,注意,这个附件是完整路径
    // msg.Attach("/Users/yufei/Downloads/1.jpg")
    // 到此,邮件消息构建完毕

    // 8. 创建 smtp 实例
    // 如果你的阿里云企业邮箱则是密码,否则一般情况下国内国外使用的都是授权码(例如,腾讯云企业邮箱)
    // 请注意 DialAndSend() 方法是一次性的,也就是连接邮件服务器,发送邮件,然后关闭连接。
    // dialer := mailer.NewDialer("smtp.mxhichina.com", 465, "阿里云企业邮箱账号", "阿里云企业邮箱密码")
    dialer := mailer.NewDialer("smtp.exmail.qq.com", 465, "腾讯云企业邮箱账号", "腾讯云企业邮箱授权码")
    // 9. 发送邮件,连接邮件服务器,发送完就关闭
    if err := dialer.DialAndSend(msg); err != nil {
        panic(err)
    }
}
示例2.gomail邮件消息群发

上述代码中的 DialAndSend() 方法是一次性的,也就是连接邮件服务器,发送邮件,然后关闭连接。
如果你有很多封邮件要发,那么正确的方法应该是 创建一个连接器然后不断的发,可以参考如下代码。

代码示例

package main
import (
  "gopkg.in/gomail.v2"
  "log"
)

type Address struct {
  Name, Address string
}
func main() {
    // 先连接到邮件服务器
    dialer := gomail.NewDialer("smtp.exmail.qq.com", 465, "腾讯云企业邮箱账号", "腾讯云企业邮箱授权码")

    // dialer 的 sock 通道
    sock, err := dialer.Dial()
    if err != nil {
      panic(err)
    }

    // 收件人
    list := []Address{
      Address{Name: "管理员", Address: "master@weiyigeek.top"},
      Address{Name: "测试人员", Address: "test@weiyigeek.top"},
    }

    // 然后发送多封邮件
    msg := gomail.NewMessage()
    for _, r := range list {
        msg.SetHeader("From", "from_address@example.com")
        msg.SetHeader("To", msg.FormatAddress(r.Address, r.Name))
        msg.SetHeader("Subject", "Go 语言发送邮件")
        msg.SetBody("text/html", "<h3>欢迎来到简单教程</h3><p>简单教程,简单编程</p>")
        // 关键点
        if err := gomail.Send(sock, msg); err != nil {
            log.Printf("Could not send email to %q: %v", r.Address, err)
        }
        // 千万不要忘记调用这个
        msg.Reset()
    }
}

<br/>

示例3.自定义方法封装Gomail实现发送文本、HTML以及附件

代码示例:

// 邮件对象&邮件信息结构体以及模板body缓存区
type Emailer struct {
	host, user, pass string
	port             int
	d                *gomail.Dialer
	m                *gomail.Message
	bodyBuffer       bytes.Buffer
}

var Email *Emailer

// Emailer 构造函数
func NewEmailer(host string, port int, user, pass string) *Emailer {
	Email = &Emailer{
		host: host,
		port: port,
		user: user,
		pass: pass,
		d:    gomail.NewDialer(host, port, user, pass),
		m:    gomail.NewMessage(),
	}
	return Email
}

// Setup 初始化邮件函数
func (e *Emailer) Setup() *gomail.Dialer {
	if e.d == nil {
		// 实例化gomail邮件连接对象
		emailhost := setting.Conf.Get("email.host").(string)
		emailport := setting.Conf.Get("email.port").(int)
		emailuser := fmt.Sprintf("%s", setting.Conf.Get("email.user"))
		emailpass := fmt.Sprintf("%s", setting.Conf.Get("email.pass"))

		// 若有错误就关闭连接
		var s gomail.SendCloser
		defer func() {
			if err := recover(); err != nil {
				fmt.Println("gomail.NewDialer connect failed!")
				s.Close()
				panic(err)
			}
		}()

		// 创建 smtp 实例
		e.d = gomail.NewDialer(emailhost, emailport, emailuser, emailpass)
		// 允许跳过不安全的认证
		// d.TLSConfig = &tls.Config{InsecureSkipVerify: true}
		return e.d
	}
	return e.d
}

// MailDialAndSend 发送邮件后立即关闭连接。
func (e *Emailer) MailDialAndSend(msg *gomail.Message) (string, error) {
	if err := e.d.DialAndSend(msg); err != nil {
		return "邮件发送失败!", err
	} else {
		msg.Reset()
		return "邮件发送成功!", nil
	}
}

// SendMsg text文本以及HTML格式邮件信息发送
func (e *Emailer) SendMsg(to []string, cc, subject, body, sendtype string) (string, error) {
	// 初始化连接验证
	e.Setup()

	// 构建一个 Message 对象也就是邮件对象
	e.m = gomail.NewMessage()

	// 设置发信人,收信人、抄送
	e.m.SetHeader("From", setting.Conf.Get("email.user").(string))
	e.m.SetHeader("To", to...)
	if cc != "" {
		chaosong := strings.Split(cc, ",")
		e.m.SetAddressHeader("Cc", chaosong[0], chaosong[1])
	}

	// 设置邮件标题与正文
	if subject != "" && body != "" {
		// 邮件标题
		e.m.SetHeader("Subject", subject)
		// 判断发送邮件的类型设置对应正文
		if sendtype == "text" {
			e.m.SetBody("text/plain", body)
		} else if sendtype == "html" {
			e.m.SetBody("text/html", body)
		}
	} else {
		return "邮件 subject 或 body 字段不能为空", errors.New("Email Message The subject or body field cannot be empty")
	}

	// 发送邮件
	if err := e.d.DialAndSend(e.m); err != nil {
		return "邮件发送失败!", err
	} else {
		e.m.Reset()
		return "邮件发送成功!", err
	}
}


func (e *Emailer) SendAttachMsg(to []string, cc, subject, body, file, filename string) (string, error) {
	// 初始化连接验证
	e.Setup()

	// 构建一个 Message 对象也就是邮件对象
	e.m = gomail.NewMessage()

	// 设置发信人,收信人、抄送
	e.m.SetHeader("From", setting.Conf.Get("email.user").(string))
	e.m.SetHeader("To", to...)
	if cc != "" {
		chaosong := strings.Split(cc, ",")
		e.m.SetAddressHeader("Cc", chaosong[0], chaosong[1])
	}
	// 设置邮件标题与正文
	e.m.SetHeader("Subject", subject)
	e.m.SetBody("text/html", body)

	// 添加附件,注意附件是需要传入完整路径
	if file != "" && len(file) > 0 {
		e.m.Attach(file,
			gomail.Rename(filename),
			gomail.SetHeader(map[string][]string{
				"Content-Disposition": {
					fmt.Sprintf(`attachment; filename="%s"`, mime.QEncoding.Encode("UTF-8", filename)),
				},
			}),
		)
	}

	// 发送邮件
	if err := e.d.DialAndSend(e.m); err != nil {
		e.m.Reset()
		return "邮件发送失败!", err
	} else {
		e.m.Reset()
		return "邮件发送成功!", nil
	}
}


func main() {
  // 执行 Emailer 的构造函数
  obj := NewEmailer("smtp.exmail.qq.com", 465, "腾讯云企业邮箱账号", "腾讯云企业邮箱授权码")

  // 定义要发送的邮箱地址数组
  mailTo := []String{
    "master@weiyigeek.top",
    "weiyigeek@qq.com",
  }

  // 调用示例1: 文本信息发送
  obj.SendMsg(mailTo,"chaosong@weiyigeek.top","文本邮件示例","来自【全栈工程师修炼指南】公众号的消息","text")
  
  // 调用示例2: HTML信息发送带
  obj.EmailMsg(mailTo,"chaosong@weiyigeek.top","网页邮件示例","来自<b>【全栈工程师修炼指南】</b>公众号的消息","html")

  // 调用示例3: HTML信息发送带附件
  obj.SendAttachMsg(mailTo,"chaosong@weiyigeek.top","网页邮件示例","来自<b>【全栈工程师修炼指南】</b>公众号的消息","/app/devops/res/tmp/weiyigeek.docx","公众号文档.docx")

}

代码执行效果:

b2daa2b0a075657e2ca2809c83c9e427.png

bd0e99be74acb8f088126f4b695dba5d.png

示例4.Gomail发送HTML注册找回验证码

描述: 我们需要在上节代码文件中加入如下函数。

HTML模板文件:

<!-- template\email\TemplateVerifiy.html -->
<div style="background:#fff">
    <table width="100%" border="0" cellspacing="0" cellpadding="0">
        <thead>
        <tr>
            <td valign="middle" style="padding-left:30px;background-color:#415A94;color:#fff;padding:20px 40px;font-size: 21px;">{{.SiteName}}</td>
        </tr>
        </thead>
        <tbody>
        <tr style="padding:40px 40px 0 40px;display:table-cell">
            <td style="font-size:24px;line-height:1.5;color:#000;margin-top:40px">邮箱验证码</td>
        </tr>
        <tr>
            <td style="font-size:14px;color:#333;padding:24px 40px 0 40px">
                尊敬的 <b> {{.UserName}} </b>用户您好!
                <br>
                <br>
                您的验证码是:<b>{{.UserCode}} </b>,请在 <b>{{.UserCodeTime}} 分钟内</b>进行验证, 过期将失效!
                <br> 
                如果该验证码不为您本人申请,请无视。
            </td>
        </tr>
        <tr style="padding:40px;display:table-cell">
        </tr>
        </tbody>
    </table>
</div>
<div>
    <table width="100%" border="0" cellspacing="0" cellpadding="0">
        <tbody>
        <tr>
            <td style="padding:20px 40px;font-size:12px;color:#999;line-height:20px;background:#f7f7f7"><a href="{{.SiteAddr}}" style="font-size:14px;color:#929292" rel="noopener" target="_blank">返回 {{.SiteName}} </a></td>
        </tr>
        </tbody>
    </table>
</div>

关键函数

// TemplateVerifiy 发送注册、登录、找回密码验证码模板字符串
func (e *Emailer) TemplateVerifiy(tpl *template.Template, body ...string) string {
	e.bodyBuffer.Reset()
	tpl.Execute(&e.bodyBuffer, struct {
		SiteName     string
		UserName     string
		UserCode     string
		UserCodeTime string
		SiteAddr     string
	}{
		SiteName:     body[0],
		UserName:     body[1],
		UserCode:     body[2],
		UserCodeTime: body[3],
		SiteAddr:     body[4],
	})
	return e.bodyBuffer.String()
}

// 此处值得学习利用反射实现传入string字符串解析为对应函数以及call参数进行执行,
func (e *Emailer) reflectFunc(tpl *template.Template, tplname string, body ...string) string {
	var t Emailer
	ref := reflect.ValueOf(&t)
	refFunc := ref.MethodByName(tplname)
	fmt.Printf("Kind : %s, Type : %s\n", refFunc.Kind(), refFunc.Type())
	refVal := make([]reflect.Value, 0)
	refVal = append(refVal, reflect.ValueOf(tpl))
	for _, v := range body {
		fmt.Println(v)
		refVal = append(refVal, reflect.ValueOf(v))
	}
	fmt.Println(refVal)
	res := refFunc.Call(refVal)
	return res[0].String()

}

// 模板信息发送
func (e *Emailer) TemplateMsg(to []string, tplname, subject string, bodys ...string) (string, error) {
	// 初始化连接验证
	e.Setup()

	// 构建一个 Message 对象也就是邮件对象
	e.m = gomail.NewMessage()

	// 设置发信人,收信人、抄送
	e.m.SetHeader("From", setting.Conf.Get("email.user").(string), "全栈工程师")
	e.m.SetHeader("To", to...)
	e.m.SetHeader("Subject", subject)

	// 模板读取并返回template对象
	tpl, err := template.ParseFiles(fmt.Sprintf("./template/email/%s.html", tplname))
	if err != nil {
		return "传入的模板文件名称有误", err
	}
	body := e.reflectFunc(tpl, tplname, bodys...)
	e.m.SetBody("text/html", body)

	// 邮件发送
	res, err := e.MailDialAndSend(e.m)
	return res, err
}

执行效果:
718be75da04c8321df42ab0e035e76e5.png

示例 5.正式环境中我们一般会用管道 channel 来创建一个邮件发送服务.
package main
import (
    mailer "gopkg.in/gomail.v2"
    "log"
    "time"
)
type Address struct {
    Name, Address string
}
func main() {
  // 收件人
  list := []Address{
    Address{Name: "管理员", Address: "master@weiyigeek.top"},
    Address{Name: "测试人员", Address: "test@weiyigeek.top"},
  }
  ch := make(chan *mailer.Message)
  go func() {
      dialer := mailer.NewDialer("smtp.exmail.qq.com", 465, "腾讯云企业邮箱账号", "腾讯云企业邮箱授权码")
      var sock mailer.SendCloser
      var err error
      var lasted int64 = 0
      open := false
      for {
          select {
          case msg, ok := <-ch:
              log.Printf("%v\n", msg)
              if !ok {
                  return
              }
              if !open {
                  if sock, err = dialer.Dial(); err != nil {
                      panic(err)
                  }
                  open = true
              }
              if err := mailer.Send(sock, msg); err != nil {
                  lasted = time.Now().Unix()
                  log.Printf("发送错误:%s\n", err.Error())
              }
          // 如果 30s 没有再发送邮件则关闭
          case <-time.Tick(30 * time.Second):
              if open && time.Now().Unix()- lasted > 30 {
                  log.Printf("30 秒没有任何邮件,直接关闭")
                  if err := sock.Close(); err != nil {
                      panic(err)
                  }
                  open = false
              }
          }
      }
  }()

  // 然后利用循环遍历发送多封邮件
  for _, r := range list {
      msg := mailer.NewMessage()
      msg.SetHeader("From", "from_address@example.com")
      msg.SetHeader("To", msg.FormatAddress(r.Address, r.Name))
      msg.SetHeader("Subject", "Go 语言发送邮件")
      msg.SetBody("text/html", "<h3>欢迎来到简单教程</h3><p>简单教程,简单编程</p>")
      ch <- msg
  }
  
  // 程序休眠30秒
  time.Sleep(120 * time.Second)

  // 程序接受后关闭管道
  close(ch)
}

入坑出坑

问题1.使用Gomail时报x509:由未知颁发机构签名的证书解决办法.
描述: 如果收到此错误,则表示SMTP服务器使用的证书不是被运行 Gomail 的客户端视为有效。
解决办法: 作为快速解决方法,您可以使用绕过对服务器的证书链和主机名的验证SetTLSConfig, 但请注意这是不安全的其不应在生产中使用。

package main

import (
	"crypto/tls"

	"gopkg.in/gomail.v2"
)

func main() {
	d := gomail.NewDialer("smtp.example.com", 587, "user", "123456")
	d.TLSConfig = &tls.Config{InsecureSkipVerify: true}
  // Send emails using d.
  ......
}

亲,文章就要看完了,不关注一下作者吗?

bc25a7af13ba68e06c76d9c92e172f4d.jpeg

问题2.gomail 执行时报 could not send email 1: 550 Error: content rejected.http://mail.qq.com/zh_CN/help/content/rejectedmail.html 错误解决办法。
描述: 上述QQ邮箱返回的退信信息,QQ邮箱认为您的邮件内容涉及群发的垃圾邮件而拒绝,由于发信smtp服务器中主题或者内容包含关键敏感字已经频繁发送邮件也会触发,则报如上所示信息。
解决办法: 删除敏感关键字,重新发送即可,尽量不同时且减少推销性文字,否则将被认为是垃圾邮件。

# 建议
联系收件方将您发信地址加入白名单;
更改邮件的主题和内容,避免出现广告和推广之类的字眼;
一次发送的收件人数不要超过100人;
如果还是退信,建议联系收件方管理员核实具体的退信原因。

本文至此完毕,更多技术文章,尽情等待下篇好文!

原文地址: https://blog.weiyigeek.top/2023/5-18-739.html

如果此篇文章对你有帮助,请你将它分享给更多的人! 

6f14f36a86bf13b2d75c7890bf934c80.gif

1b8f19a3d624c344509f463c64136bb8.png 学习书籍推荐 往期发布文章 ad8ee82577caca37b4f842fb3aabcc1d.png

公众号回复【0008】获取【Ubuntu22.04安装与加固建脚本】

公众号回复【10001】获取【WinServer安全加固脚本】

公众号回复【1000】获取【PowerShell操作FTP脚本】

公众号回复【0015】获取【Jenkins学习之路汇总】

 热文推荐  

  • 容灾恢复 | 记一次K8S集群中etcd数据快照的备份恢复实践

  • 开发基础 | Golang语言的RESTfulAPI接口设计规范快速入门

  • 企业实践 | 如何从VMWare ESXi Shell中挂载以及拷贝NTFS或者FAT32分区格式的USB闪存驱动器

  • 网安等保-国产Linux操作系统银河麒麟KylinOS-V10SP3常规配置、系统优化与安全加固基线实践文档

  • 硬件玩物 | 闲置物理主机安装群辉NAS-DSM-7.x系统实践试用初体验(保姆篇)

欢迎长按(扫描)二维码 2bc5944355976ac715763d06bb1fe3ce.gif取更多渠道哟!

69991f71a0769d9bde778b7374e3c92a.jpeg0e09f35f47ab1f74d815797c7a857e8a.jpeg525df4f60d97da8d008e40de16246e07.jpeg

4445a33be8d840bab36c66945c17071c.gif

欢迎关注 【全栈工程师修炼指南】(^U^)ノ~YO

== 全栈工程师修炼指南 ==

微信沟通交流: weiyigeeker 

关注回复【学习交流群】即可加入【安全运维沟通交流小群

温馨提示: 由于作者水平有限,本章错漏缺点在所难免,希望读者批评指正,若有问题或建议请在文章末尾留下您宝贵的经验知识,或联系邮箱地址

master@weiyigeek.top 或 关注公众号 [全栈工程师修炼指南] 留言。

[全栈工程师修炼指南]  关注 企业运维实践、网络安全、系统运维、应用开发、物联网实战、全栈文章,尽在博客站点,谢谢支持!

点个【 赞 + 在 】看吧!

82aee2e173a8a0db6f56afdbc0aac201.gif 点击【"阅读原文"】获取更多有趣的知识!   

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/591743.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

vulhub-Jarbas(易)

打靶练习Jarbas 0x00 部署0x01 信息收集&#xff1a;端口扫描、服务发现0x02 路径爬取0x03 反弹shell0x04 内网信息收集0x05 crontab定时任务提权0x06 总结 0x00 部署 靶机&#xff1a;下载地址 宿主机&#xff1a;kali2021版本 0x01 信息收集&#xff1a;端口扫描、服务发现…

《计算机组成原理》唐朔飞 第9章 控制单元的功能 - 学习笔记

写在前面的话&#xff1a;此系列文章为笔者学习计算机组成原理时的个人笔记&#xff0c;分享出来与大家学习交流。使用教材为唐朔飞第3版&#xff0c;笔记目录大体与教材相同。 网课 计算机组成原理&#xff08;哈工大刘宏伟&#xff09;135讲&#xff08;全&#xff09;高清_…

git (本地仓库)和(远程仓库)之间的代码推送:013

这里先说明一下循序&#xff1a; 1. 创建(远程仓库)和(本地仓库) 2. 创建(远程仓库)和(本地仓库)之间的链接 3. 将(本地仓库)的代码推通过命令送到(远程仓库)&#xff1b;将(本地仓库)的代码通过(TortoiseGit小乌龟)推送到(远程仓库) 1. 创建(远程仓库)和(本地仓库)&#xff0c…

PHP异步:在PHP中使用 fsockopen curl 实现类似异步处理的功能

PHP从主流来看&#xff0c;是一门面向过程的语言&#xff0c;它的最大缺点就是无法实现多线程管理&#xff0c;其程序的执行都是从头到尾&#xff0c;按照逻辑一路执行下来&#xff0c;不可能出现分支&#xff0c;这一点是限制php在主流程序语言中往更高级的语言发展的原因之一…

C++实现sqlite单表增删改查的详细步骤

1.环境准备 coding之前需要先安装好C的集成开发环境&#xff0c; 我这里选择的是Visual Studio 2022&#xff0c;本来想使用CLion的&#xff0c; 但是破解太麻烦&#xff0c;懒得整了。 Visual Studio 2022 2.项目创建及编码 启动visual studio, 点击创建项目&#xff0c;选…

《MYSQL必知必会》读书笔记1

目录 行 主键 MYSQL工具 使用MYSQL 连接 检索数据 检索&#xff08;SELECT&#xff09; 限制结果&#xff08;LIMIT&#xff09; 排序检索&#xff08;ORDER BY&#xff09; 过滤数据&#xff08;WHERE&#xff09; 过滤数据&#xff08;AND、OR&#xff09; 通配符…

软件测试总结

软件生命周期(SDLC)的六个阶段 1、问题的定义及规划 此阶段是软件开发方与需求方共同讨论&#xff0c;主要确定软件的开发目标及其可行性。 2、需求分析 在确定软件开发可行的情况下&#xff0c;对软件需要实现的各个功能进行详细分析。需求分析阶段是一个很重要…

ML | 6 支持向量机

ML | 6 支持向量机 文章目录 ML | 6 支持向量机SVM介绍线性不可分数据线性可分数据 寻找最大间隔分类器求解的优化问题 SMO高效优化算法简化版SMO处理小规模数据集伪代码程序清单 完整Platt SMO 算法加速优化完整 Platt SMO的支持函数完整Platt SMO算法中的优化例程完整Platt S…

记录--Vue3自定义一个Hooks,实现一键换肤

这里给大家分享我在网上总结出来的一些知识&#xff0c;希望对大家有所帮助 核心 使用CSS变量, 准备两套CSS颜色, 一套是在 light模式下的颜色,一套是在dark模式下的颜色dark模式下的 CSS 权重要比 light 模式下的权重高, 不然当我们给html添加自定义属性[data-themedark]的时候…

CVPR 2023 | 南大王利民团队提出LinK:用线性核实现3D激光雷达感知任务中的large kernel...

点击下方卡片&#xff0c;关注“CVer”公众号 AI/CV重磅干货&#xff0c;第一时间送达 点击进入—>【Transformer】微信交流群 【CVPR 2023】LinK&#xff1a;用线性核实现3D激光雷达感知任务中的large kernel 本文介绍我们媒体计算研究组&#xff08;MCG&#xff09;在3D激…

chatgpt赋能python:Python中的提取函数——数据清洗中必不可少的利器

Python中的提取函数——数据清洗中必不可少的利器 数据清洗是数据分析过程中不可或缺的一步&#xff0c;而Python中的提取函数则是数据清洗中必不可少的利器。本文将重点介绍一些Python中常用的提取函数&#xff0c;以帮助数据分析师更好地应对实际问题。 什么是提取函数&…

react antd Modal里Form设置值不起作用

问题描述&#xff1a; react antd Modal里Form设置值不起作用&#xff0c;即使用form的api。比如&#xff1a;编辑时带出原有的值。 造成的原因&#xff1a;一般设置值都是在声明周期里设置&#xff0c;比如&#xff1a;componentDidMounted里设置&#xff0c;hook则在useEff…

云网络安全与数据中心安全

近年来&#xff0c;许多云架构师宣称随着公共云的采用&#xff0c;网络安全性将消亡。然而&#xff0c;网络安全仍然是最大的安全市场之一&#xff0c;并且是每个主要云服务提供商 (CSP) 在过去几年中推出重要新产品的领域。 网络对安全仍然至关重要&#xff0c;即使在云中也是…

【软考系统规划与管理师笔记】第4篇 信息技术服务知识

目录 1 产品、服务和信息技术服务 1.1 产品 1.2 服务 1.3 信息技术服务 2运维、运营和经营 2.1运维 2.2运营 2.3经营 3 IT治理 4 IT服务管理 4.1传统管理方式 4.2体系化管理方式 5项目管理 6质量管理理论 6.1质量管理发展历史 6.2质量管理常见理论方法 6.3质…

【公网远程Jellyfin】——本地部署Jellyfin影音服务器

文章目录 1. 前言2. Jellyfin服务网站搭建2.1. Jellyfin下载和安装2.2. Jellyfin网页测试 3.本地网页发布3.1 cpolar的安装和注册3.2 Cpolar云端设置3.3 Cpolar本地设置 4.公网访问测试5. 结语 1. 前言 随着移动智能设备的普及&#xff0c;各种各样的使用需求也被开发出来&…

面向Java开发者的ChatGPT提示词工程(5)

GPT 的局限性 在探讨开发大型语言模型应用程序时&#xff0c;我们必须认识到 GPT 存在一些局限性。这些限制对于我们保持清醒的头脑至关重要。 尽管在 GP T的训练过程中融入了大量知识&#xff0c;但它并非能够完美地记住所见之物&#xff0c;并且对这些知识的边界了解有限。…

玩转用户旅程地图

图&#xff1a;史江鸿 从事需求分析和产品设计工作已经有几个年头了&#xff0c;我很享受这个职业。因为在这段职业历程中&#xff0c;我学到了很多有意思的方法和工具&#xff0c;用户旅程地图就是其中一个。 如今在国内外许多IT公司&#xff0c;用户旅程地图已经成为需求分析…

ElasticSearch安装部署

ElasticSearch安装部署 简介 全文搜索属于最常见的需求&#xff0c;开源的 Elasticsearch &#xff08;以下简称 es&#xff09;是目前全文搜索引擎的首选。 它可以快速地储存、搜索和分析海量数据。维基百科、Stack Overflow、Github 都采用它。 Elasticsearch简称es&…

C++【实现红黑树(核心插入)】

文章目录 一、红黑树概念介绍二、红黑树模拟实现&#xff08;1&#xff09;红黑树节点&#xff08;2&#xff09;红黑树插入分析(核心)&#xff08;3&#xff09;插入代码思路(如何快速写插入算法)&#xff08;4&#xff09;判断平衡函数&#xff08;5&#xff09;查找函数&…

01_java基础语法

1. Java概述 1.1 Java语言背景介绍&#xff08;了解&#xff09; 语言&#xff1a;人与人交流沟通的表达方式 计算机语言&#xff1a;人与计算机之间进行信息交流沟通的一种特殊语言 Java语言是美国Sun公司&#xff08;Stanford University Network&#xff09;在1995年推出的…