go 生成图片,邮件发送问题
一、问题背景:
每天发送各个部门的财报到邮件.
由于部门较多,且数据量较大,导致单纯的表格模式数字量太多.
影响观看,且不易发现问题,分析数据。
二、项目初审,项目技术选型
1、后端做定时任务调度
2、后端提供明细数据接口
3、前端做数据页面展示
4、使用PhantomJS 实现网页截图功能
5、图片以对象存储的形势保存
6、定时任务推送数据
三、项目涉及的技术解决方案
1、PhantomJS
官网链接:https://www.cnblogs.com/bangejingting/p/6907628.html
1.1、phantomjs的安装
-
安装目录放在data目录下
$ cd /data/ -
远程下载
$ wget https://bitbucket.org/ariya/phantomjs/downloads/phantomjs-2.1.1-linux-x86_64.tar.bz2 -
解压tar.bz2文件
$ tar -jxvf phantomjs-2.1.1-linux-x86_64.tar.bz2
$ cd phantomjs-2.1.1-linux-x86_64/bin/ -
对可执行文件进行web用户授权
$ chown -R web:web bin/ -
将该脚本命令作为全局脚本
$ cp phantomjs /bin/
1.2、phantomjs的使用
- 调用脚本 参数为执行的js脚本文件
$ phantomjs --web-security=no xxx.js htmlPath imgPath
说明:
--web-security=no // 解决跨域问题
xxx.js // 需要执行的脚本
htmlPath // 需要生成的网页地址, 可以是绝对路径下的html /data/html/index.html
imgPath // 生成的图片地址及图片名称 /data/img/xxx.jpg
- xxx.js样例:
var page = require('webpage').create(),
system = require('system'),
address, output, size;
// 设置整体渲染页面的大小,非必需设置
// page.viewportSize = {width: 800, height: 400};
address = system.args[1];
output = system.args[2];
// 打开的html文件,可以是相对地址
page.open(address, function (status) {
page.render(output);
page.close();
phantom.exit(1);
console.log('render ok');
});
说明:
address:需要截图的地址
output: 输出的图片
phantomjs的注意事项
- 不支持es6语法,只能使用es5
2、对象存储文件上传
- 单文件上传
// 单文件上传
func CloudUploadFile(f *multipart.FileHeader, fileName string) error {
appID := AppID
secretID := SecretID
secretKey :=SecretKey
u, _ := url.Parse("http://"+bucketName+"-"+appID+".cos.ap-xianggang.myqcloud.com")
client := libcos.NewClient1(u, appID, secretID, secretKey, 10)
// 读取文件内容
fileContent, err := f.Open()
if err != nil {
fmt.Sprintf("err:%v\n",e.Error())
return err
}
fi, err := ioutil.ReadAll(fileContent)
if err != nil {
fmt.Sprintf("err:%v\n",e.Error())
return err
}
fReader := bytes.NewReader(fi)
// 上传
err = client.Put(context.Background(), fileName, fReader)
if err != nil {
fmt.Sprintf("err:%v\n",e.Error())
return err
}
return nil
}
- 文件夹上传
//获取指定目录下的所有文件,包含子目录下的文件
func GetAllFiles(dirPth string) (files []string, err error) {
var dirs []string
dir, err := ioutil.ReadDir(dirPth)
if err != nil {
return nil, err
}
PthSep := string(os.PathSeparator)
//suffix = strings.ToUpper(suffix) //忽略后缀匹配的大小写
for _, fi := range dir {
if fi.IsDir() { // 目录, 递归遍历
dirs = append(dirs, dirPth+PthSep+fi.Name())
GetAllFiles(dirPth + PthSep + fi.Name())
} else {
files = append(files, dirPth+PthSep+fi.Name())
}
}
// 读取子目录下文件
for _, table := range dirs {
temp, _ := GetAllFiles(table)
for _, temp1 := range temp {
files = append(files, temp1)
}
}
return files, nil
}
// 文件逐个上传
func DownloadFile(c *gin.Context, filePath string) error {
// 获取所有文件
files, err := GetAllFiles(filePath)
if err != nil {
fmt.Sprintf("err:%v\n", e.Error())
return err
}
start := time.Now().Unix()
var wg sync.WaitGroup
con := make(chan int, 30)
// 遍历文件 逐个上传
for _, v := range files {
wg.Add(1)
go func(v string) {
con <- 1
defer func() {
<-con
wg.Done()
}()
file, _ := os.Open(v)
defer file.Close()
stats, _ := file.Stat()
fileByte := make([]byte, stats.Size())
file.Read(fileByte)
// 取每一个文件的实际地址 /home/web/game/1.txt => 实际目录 /game/1.txt
filepath := strings.Replace(v, "/home/web", "", 1)
err = FileUploading(c, fileByte, filepath)
if err != nil {
fmt.Sprintf("err:%v\n", e.Error())
}
}(v)
}
wg.Wait()
return err
}
// 上传文件夹到腾讯云 对象存储
func FileUploading(fileByte []byte, fileName string) error {
bucketName := BucketName
appID := AppID
secretID := SecretID
secretKey := SecretKey
u, _ := url.Parse("http://" + bucketName + "-" + appID + ".cos.ap-xiangguang.myqcloud.com")
client := libcos.NewClient1(u, appID, secretID, secretKey, 10)
fReader := bytes.NewReader(fileByte)
// 上传
err := client.Put(context.Background(), fileName, fReader)
if err != nil {
fmt.Sprintf("err:%v\n", e.Error())
return err
}
return nil
}
3、邮件发送
3.1、解决邮件文字显示乱码
$ yum install -y fontconfig mkfontscale
$ fc-list :lang=zh
$ mkdir -p /usr/share/fonts/zh_CN
# 提前复制平方、微软雅黑到服务器
$ cp /tmp/PingFang.ttc .
$ cp /tmp/msyh.ttf .
$ chmod -R 766 ../zh_CN/
$ mkfontscale
$ mkfontdir
3.2、发送邮件
邮箱配置
3.3、发送邮件
func SendEmail() error {
m := gomail.NewMessage()
m.SetHeader("From", xxx) //发送人
m.SetHeader("To",[]string{xxx,xxx}) //接收人
m.SetHeader("Subject",xxx ) //邮件主题 string
m.SetBody("text/html", xxxx) //正文 string
// 发邮件地址 smtp.exmail.qq.com qq邮箱, port 邮箱设置里可以查到, 发送者邮箱名称, 邮箱密钥, 上一步可以查到,不是邮箱登录密码
d := gomail.NewDialer(FromEmailAddr, FromEmailPort, FromEmailName, FromEmailPass)
if err := d.DialAndSend(m); err != nil {
return fmt.Errorf("err:%v\n", err.Error())
}
return nil
}