golang打造基于mail的提醒服务
初识golang
逻辑如下:
程序开启http服务器接收请求,且每隔20秒查询一次表auto_backup中flag为0的值,如果有查到且计划执行时间小于当前时间,则将表to_do的数据抓出来,通过邮件发送,完成后将数据表flag update 为1
表结构:
MySQL []> desc auto_backup; +----------+---------------+------+-----+---------+----------------+ | Field | Type | Null | Key | Default | Extra | +----------+---------------+------+-----+---------+----------------+ ) | NO | PRI | NULL | auto_increment | ) | NO | | NULL | | ) | NO | | NULL | | ) | NO | MUL | NULL | | +----------+---------------+------+-----+---------+----------------+ rows in set (0.04 sec)
表数据:
MySQL []> SELECT
-> `id`,
-> FROM_UNIXTIME(`auto_backup`.`datetime`) AS `datetimes`,
-> `auto_backup`.`to_do` AS `to_do`,
-> `auto_backup`.`flag` AS `flag`
-> FROM
-> `auto_backup`
-> order by datetimes desc
;
+----+---------------------+-----------------+------+
| id | datetimes | to_do | flag |
+----+---------------------+-----------------+------+
:: |
+----+---------------------+-----------------+------+
row in set (0.04 sec)
效果如下:
添加记录

发送记录

服务器log:

代码如下:
package main
// 导入相关包
import (
"database/sql"
"fmt"
_ "github.com/go-sql-driver/mysql"
"gopkg.in/gomail.v2"
"log"
"net/http"
"strconv"
"time"
)
// http 服务器
func Httpd_beiwang(w http.ResponseWriter, r *http.Request) {
r.ParseForm()
// 赛选掉访问的url路径为 /favicon.ico
if "/favicon.ico" != r.URL.Path {
log.Println(r.Form)
// 获取url参数
time_value, timeOK := r.Form["time"]
beiwang_value, beiwangOK := r.Form["beiwang"]
// 如果两个参数正确,则判断参数正确,需要将定时任务写到数据库中去
if timeOK && beiwangOK {
log.Println("参数判断ok,参数值为:")
log.Println(time_value[])
log.Println(beiwang_value[])
// 定义初始时间
const base_format = "\"2006-01-02 15:04\""
// 转化为unix时间
loc, _ := time.LoadLocation("Local")
parse_time, err := time.ParseInLocation(base_format, time_value[], loc)
unix_parse_time := parse_time.Unix()
log.Println("Unix 时间为: ", unix_parse_time)
if err != nil {
fmt.Println(err)
}
// 需要Insert的sql
insert_sql := fmt.Sprintf(])
log.Println("执行的sql: ", insert_sql)
// 执行sql
results, err := db.Exec(insert_sql)
if err != nil {
log.Println("sql执行错误,错误内容为:")
log.Println(err)
} else {
log.Println("执行成功,", results)
fmt.Fprintf(w, "request ok")
}
} else {
fmt.Fprintf(w, "request error")
}
}
}
// 发送邮件
func SendMail(body string) error {
mailConn := map[string]string{
"user": "from_user",
"pass": "password",
"host": "smtp",
"port": "port",
}
port, _ := strconv.Atoi(mailConn["port"])
m := gomail.NewMessage()
//m.SetHeader("From" , "XD Game" + "<" mailConn["user"] + ">")
m.SetHeader("From", "XD Game"+"<"+mailConn["user"]+">")
m.SetHeader("To", "to_user")
m.SetHeader("Subject", "执行计划")
m.SetBody("text/html", body)
d := gomail.NewDialer(mailConn["host"], port, mailConn["user"], mailConn["pass"])
err := d.DialAndSend(m)
return err
}
// 返回需要执行定时任务的id,返回值为Int数组
func Deal_Exec_id(db *sql.DB) []int {
var send_id []int
// 获取当前时间戳
now_t := time.Now()
// 执行查询sql
select_datetime := fmt.Sprintf("select id from auto_backup where flag = 0 and datetime <= %d", now_t.Unix())
// 执行sql
select_rows, err := db.Query(select_datetime)
log.Println(select_datetime)
if err != nil {
log.Println(err)
}
for select_rows.Next() {
var id int
if err := select_rows.Scan(&id); err != nil {
log.Println(err)
}
//fmt.Println(id)
// 将查询的结果追加到send_id中
send_id = append(send_id, id)
}
log.Println("查询结果返回ID", send_id)
// 将send_id数组返回
return send_id
}
func Deal_SendMail(db *sql.DB, send_id []int) {
var to_do string
for id := range (send_id) {
fmt.Println(send_id[id])
// 根据send_id查询 messages
select_sql := fmt.Sprintf("SELECT to_do FROM auto_backup WHERE id = '%d';", send_id[id])
log.Println(select_sql)
err := db.QueryRow(select_sql).Scan(&to_do)
if err != nil {
log.Println(err)
}
log.Println("发送的内容", to_do)
SendMail(to_do)
// 执行 update sql
update_sql := fmt.Sprintf("UPDATE auto_backup SET flag = 1 WHERE id = '%d'", send_id[id])
log.Println(update_sql)
results, err := db.Exec(update_sql)
if err != nil {
log.Println(err)
} else {
log.Println(results)
}
}
}
func start_jobs() {
for {
log.Println("Auto Time jobs Start")
send_id := Deal_Exec_id(db)
== len(send_id) {
log.Println("未找到相关jobs")
} else {
Deal_SendMail(db, send_id)
}
// 每隔20秒刷新一次数据库,查看是否存在新数据
time.Sleep(time.Second * )
}
}
// 定义*sql.DB 变量
var db *sql.DB
func main() {
// 连接mysql
var err error
c := make(chan )
db, err = sql.Open("mysql", "username:password@tcp(host)/database_name")
// 在main退出时关闭链接
defer db.Close()
if err != nil {
log.Println("Connect DB failed")
log.Println(err)
}
// 开启http服务器
http.HandleFunc("/", Httpd_beiwang)
// 开启协程
go func() {
err = http.ListenAndServe("0.0.0.0:9090", nil)
if err != nil {
log.Fatal(err)
}
}()
go start_jobs()
<- c
}
golang打造基于mail的提醒服务的更多相关文章
- 翻译-使用Ratpack和Spring Boot打造高性能的JVM微服务应用
这是我为InfoQ翻译的文章,原文地址:Build High Performance JVM Microservices with Ratpack & Spring Boot,InfoQ上的中 ...
- 基于 REST 的 Web 服务:基础
代表性状态传输(Representational State Transfer,REST)在 Web 领域已经得到了广泛的接受,是基于 SOAP 和 Web 服务描述语言(Web Services D ...
- 新项目架构从零开始(三)------基于简单ESB的服务架构
这几个月一直在修改架构,所以迟迟没有更新博客. 新的架构是一个基于简单esb的服务架构,主要构成是esb服务注册,wcf服务,MVC项目构成. 首先,我门来看一看解决方案, 1.Common 在Com ...
- 使用Ratpack和Spring Boot打造高性能的JVM微服务应用
使用Ratpack和Spring Boot打造高性能的JVM微服务应用 这是我为InfoQ翻译的文章,原文地址:Build High Performance JVM Microservices wit ...
- Golang 在电商即时通讯服务建设中的实践
马蜂窝技术原创文章,更多干货请搜索公众号:mfwtech 即时通讯(IM)功能对于电商平台来说非常重要,特别是旅游电商. 从商品复杂性来看,一个旅游商品可能会包括用户在未来一段时间的衣.食.住.行等 ...
- 通过Dapr实现一个简单的基于.net的微服务电商系统
本来想在Dpar 1.0GA时发布这篇文章,由于其他事情耽搁了放到现在.时下微服务和云原生技术如何如荼,微软也不甘示弱的和阿里一起适时推出了Dapr(https://dapr.io/),园子里关于da ...
- 基于thrift的微服务框架
前一阵开源过一个基于spring-boot的rest微服务框架,今天再来一篇基于thrift的微服务加框,thrift是啥就不多了,大家自行百度或参考我之前介绍thrift的文章, thrift不仅支 ...
- Jquery打造的类似新浪微博@提醒功能
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/ ...
- 基于TCPCopy的Dubbo服务引流工具-DubboCopy
TCPCopy顾名思义,就是一个可以将tcp流量复制的工具(其实也可以复制UDP).有了这样一个工具,我们就可以真实的复制线上流量,然后将这些流量复制到我们的测试服务器上.这样就可以很容易模拟线上真实 ...
随机推荐
- python bmp转jpg 且灰度图转彩色
今天在简书,上看到了一个 bmp转jpg的代码,便记录一下. # coding:utf-8 import os from PIL import Image # bmp 转换为jpg,灰度图转RGB d ...
- 移动端rem适配
(function(_D) { var _self = {}; _self.resizeEvt = 'orientationchange' in window ? 'orientationchange ...
- View控件跟随鼠标移动
public boolean onTouch(View view, MotionEvent motionEvent) { if(motionEvent.getAction() == MotionEve ...
- springboot添加自定义注解
spring拦截器是基于动态代理,注解就是拦截器,所以关于动态代理需要注意的坑,注解同样要注意. 1.创建注解类 /** * @Target 此注解的作用目标,括号里METHOD的意思说明此注解只能加 ...
- HTTP协议转码
为什么要有转义的功能? 一些特殊字符需要转义,才能被访问,否则变为空格 UrlEnCode与UrlDeCode 有些符号在URL中是不能直接传递的,如果要在URL中传递这些特殊符号,那么就要使用他们的 ...
- ArgumentOutOfRangeException: 指定的参数已超出有效值的范围。 参数名: site
新装的win10系统,跑原来的asp.net 程序报错,原想着vs2017用iis express,不用配置iis了,貌似不行 在控制面板,程序,开启windows功能 勾选用到的asp.net版本, ...
- Linux使用yum安装JDK
安装jdk8 检查系统是否自带open-jdk输入命令: #rpm -qa|grep java #rpm -qa|grep jdk 如果没有输入信息表示没有安装,如果安装可以输入命令:#rpm -qa ...
- CSS3--2D&3D的使用
transform 过渡属性 向元素进行2D或3D转换 transform-origin:该元素基于某个点来旋转 transform-style: preserve-3d 规定嵌套元素如何在3D空间 ...
- ThinkPHP5 与ThinkPHP3.2公共函数放置位置
最初使用ThinkPHP3..3的时候,我们自己定义的公共函数常常放置于 \Common\function.php 由于最近准备重新捡起微信开发,准备用ThinkPHP5进行微信公众号开发,使用到公共 ...
- C#使用CefSharp开源库开发Chrome 浏览器
一.介绍 这个东西我以前没有接触过,但是公司项目里面有用到这个东西,所以就顺便研究一下.今天只是做了 WinForm 的测试,有时间了在试试 WPF 是如何实现的.刚开始一塌糊涂,有点麻 ...