原文链接:http://studygolang.com/articles/9154
情景:将工资条的内容发送到相应员工的邮箱中。
xlsx文件内容格式:
- 获取excel文件内容,使用第三方库:github.com/tealeg/xlsx
代码:
package main
import (
"fmt"
"github.com/tealeg/xlsx"
"log"
)
func main() {
/* 获取excel文件路径 */
excelFileName := "F:\\Test\\list.xlsx"
/* 获取excel文件对象 */
xlFIle, err := xlsx.OpenFile(excelFileName)
/* 日志打印 */
if err != nil {
log.Fatalln("err:", err.Error())
}
/* 通过for循环获取表格中单元格的内容 */
for _, sheet := range xlFIle.Sheet{
for _, row := range sheet.Rows {
for _, cell := range row.Cells {
fmt.Printf("%s\n", cell.Value)
}
}
}
}
知识点:
xlsx操作excel文件先获取Sheet对象,代表excel文件的sheet,通过遍历Sheet对象,获取每个sheet的行结果Rows,对Rows遍历,就获取到了每个单元格的内容,封装在Cells对象中。
- 分割工资条
使用正则表达式,将每个人的工资条分开,如果读取到新的邮箱地址,就用新的存储空间存储工资条的内容。这里使用一个函数:isEmailRow()
func isEmailRow(r []string) (isEmail bool, email string) {
/* 编译正则表达式 */
reg := regexp.MustCompile(`^[a-zA-Z_0-9.-]{1,64}@([a-zA-Z0-9-]{1,200}.){1,5}[a-zA-Z]{1,6}$`)
/* 遍历r中内容,匹配正则表达式 */
for _, v := range r{
if reg.MatchString(v) {
return true, v
}
}
return false, ""
}
isEmailRow函数接收的参数是数组,所以将单元格内容转换为数组形式,并且去除了空格和空行:
func _getCellValues(r *xlsx.Row) (cells []string) {
for _, cell := range r.Cells{
/* 去除换行和空格 */
txt := strings.Replace(strings.Replace(cell.Value, "\n", "", -1)," ", "", -1)
/* 使用append函数拼接 */
cells = append(cells, txt)
}
return
}
使用map来存储每个人的工资条数据,并且用电子邮件作为键值,然后将数据组装成一个HTML的表格行代码(因为需要发送HTML格式的电子邮件才能以表格的形式展现)。于是,main里的循环代码就变成了这样:
/* 创建map */
sendList := make(map[string]string)
for _, sheet := range xlFile.Sheets {
curMail := ""
for _, row := range sheet.Rows {
cells := getCellValues(row)
//如果行包含电子邮件,创建一个新字典项
if isEmail, emailStr := isEmailRow(cells); isEmail {
curMail = emailStr
}
sendList[curMail] += fmt.Sprintf("<tr><td>%s</td></tr>", strings.Join(cells, "</td><td>"))
}
}
- 发送电子邮件
使用标准包:net/smtp就可以发送电子邮件
封装一个函数:
func sendToMail(user, password, host, to, subject, body, mailtype string) error {
/* 返回一个实现了PLAIN身份认证机制的Auth接口 */
auth := smtp.PlainAuth("", user, password, strings.Split(host, ":")[0])
/* 邮件元数据 */
msg := []byte("To: " + to + "\r\nFrom: " + user + "\r\nSubject: " + subject + "\r\n" + "Content-Type: text/" + mailtype + "; charset=UTF-8" + "\r\n\r\n" + body)
sendto := strings.Split(to, ";")
/* 发送邮件 */
err := smtp.SendMail(host, auth, user, sendto, msg)
return err
}
创建一个函数,遍历所有内容并调用发送邮件函数发送出去
func sendMail(sendList map[string]string) {
fmt.Printf("共需要发送%d封邮件\n", len(sendList))
index := 1
for mail, content := range sendList {
fmt.Printf("发送第%d封", index)
/* 将里边的用户名密码,smtp服务器换成自己的 */
if err := sendToMail("xxx@xxxxxx.com",
"xxxxxxx",
"smtp.xxxxxx.com:25",
mail,
"工资条",
fmt.Sprintf("<table border='2'>%s</table>", content),
"html"); err != nil {
fmt.Printf(" ... 发送错误(X) %s %s \n", mail, err.Error())
} else {
fmt.Printf(" ... 发送成功(V) %s \n", mail)
}
index++
fmt.Printf("<table border='2'>%s</table> \n", content)
}
}
最后的main函数:
excelFileName := "F:\\Test\\list.xlsx"
xlFile, err := xlsx.OpenFile(excelFileName)
if err != nil {
log.Fatalln("err:", err.Error())
}
sendList := make(map[string]string)
for _, sheet := range xlFile.Sheets {
curMail := ""
for _, row := range sheet.Rows {
cells := getCellValues(row)
//如果行包含电子邮件,创建一个新字典项
if isEmail, emailStr := isEmailRow(cells); isEmail {
curMail = emailStr
} else {
count := 0
for _, c := range cells {
if len(c) > 0 {
count++
}
}
if count > 1 {
sendList[curMail] += fmt.Sprintf("<tr><td>%s</td></tr>", strings.Join(cells, "</td><td>"))
} else {
sendList[curMail] += fmt.Sprintf("<tr><td colspan='%d'>%s</td></tr>", len(cells), strings.Join(cells, ""))
}
}
}
}
sendMail(sendList)
fmt.Print("按下回车结束")
bufio.NewReader(os.Stdin).ReadLine()
亲测可用。作为学习收藏。