前言
由于不经常上学校的招生信息网,故写个小工具,每隔半个小时扫描一遍招生网,若发现新消息,则将通知的链接和发布时间推送到在此之前登记过的用户邮箱。
体验
体验网址:http://47.107.103.76:9092/
博客链接:http://waiterxiaoyy.ltd/index.php/archives/49/
仓库链接:https://gitee.com/waiterxiaoyy/gdut-mail
使用技术
技术 | 说明 |
---|---|
SpringBoot | 2.3.4.RELEASE |
MyBatis | 用于连接数据库,将通知和用户邮箱持久化 |
JavaMailSender | 用于发送邮件 |
thymeleaf | 用户登记邮箱、后台管理页面 |
Jsoup | 用户抓取招生信息网网页 |
抓取网页信息
通过Jsoup,用一个GET请求招生信息网,先将网页全部抓取下来,然后再对通知列表进行解析,把通知标题、通知链接、通知发布时间分离出来,使用一个实体类记录,将此通知与数据库中已经存在的通知进行比对,若为新通知,而加入新通知链表,之后将新通知链表通过JavaMailSender推送给用户。
下面使用了@Scheduled,这是SpringBoot的一个注解,通过它可以定时执行某个服务,这样就可以实现扫描网页,详情可以参考https://www.jianshu.com/p/1defb0f22ed1
@Component
public class ZhaoShengJsoup {
public static Date basiTime = new Date(2020-1900,9-1,19); //这串代码没有什么作用,只是为了声明一个静态变量,没有的话则下面的Mapper和SendMail无法注入
@Autowired
private MailMapper mailMapper;
@Autowired
private SendEmail sendEmail;
// @Scheduled(cron = "0 0/2 * * * ?") //每2秒执行一次
// @Scheduled(cron = "0/50 * * * * ? ") //每50秒执行一次
@Scheduled(cron="0 0/30 * * * ?") //每30分钟
public void task() throws Exception {
Connection connection1 = Jsoup.connect("https://yzw.gdut.edu.cn/sszs.htm")
.header("Accept", "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9")
.userAgent("Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/81.0.4044.138 Safari/537.36")
.method(Connection.Method.GET)
.timeout(3000);
Connection.Response response1 = connection1.execute();
// 以下是解析网页常规操作,如果需要学习可以前往Jsoup官网。网页标签通过在浏览器F12或查看源代码查看
Document document = response1.parse();
Elements lis = document.getElementsByTag("ul").get(1).getElementsByTag("li");
Notice notice = null;
//获取当前时间
Date date1 = new Date();
String nowTime = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(date1);
//插入更新表
Renew renew = new Renew();
renew.setRenewTime(nowTime);
mailMapper.renewInsert(renew);
//新通知链表
ArrayList<Notice> newNotice = new ArrayList<>();
for(int i = lis.size() - 1; i >= 0 ; i--) {
notice = new Notice();
String title = lis.get(i).getElementsByTag("a").attr("title").toString();
String noticeUrl = "https://yzw.gdut.edu.cn/" + lis.get(i).getElementsByTag("a").attr("href");
String date = lis.get(i).getElementsByTag("span").get(0).text().toString();
notice.setDate(date);
notice.setNoticeUrl(noticeUrl);
notice.setNoticeTitle(title);
notice.setZhaoshengUrl("https://yzw.gdut.edu.cn/sszs.htm");
notice.setCreateTime(nowTime);
//新通知
if(mailMapper.existNotice(notice.getNoticeTitle()) != 1) {
newNotice.add(notice);
//插入日志,没什么用
if(mailMapper.addNotice(notice) == 1) {
Log log = new Log();
log.setMessage("【新通知加入】" + notice.getNoticeTitle());
log.setDateTime(nowTime);
mailMapper.addLog(log);
}
}
}
//新通知链表不为空,则需要推送通知了
if(newNotice.size() > 0) {
sendEmail.sendEmail(newNotice);
}
}
}
邮件推送
邮件推送分为两部分,第一部分是用户登记邮箱成功时,推送一次。第二部分是推送新通知,将数据库中所有的用户读取出来一一推送,中间休眠一点时间,以免服务器压力太大。
# 在pom.xml引入
<dependency>
<groupId>javax.mail</groupId>
<artifactId>mail</artifactId>
<version>1.4.5</version>
</dependency>
@Component
public class SendEmail {
// 此处是JavaMailSender用法,但还需要再application.yml文件中进行配置,yml配置放在后面
@Autowired
private JavaMailSender mailSender;
@Autowired
private MailMapper mailMapper;
//第一部分,对新用户发送登记成功的消息
public void sendNewUser(String userMail) {
SimpleMailMessage mailMessage = null;
try {
//生成并填充消息体
mailMessage = new SimpleMailMessage();
mailMessage.setFrom("你的邮箱");//发送邮箱
mailMessage.setTo(userMail);//接收邮箱
mailMessage.setSubject("【提醒小助手】广东工业大学招生网发布了新的信息"); //邮件主题
StringBuilder builder = new StringBuilder();
mailMessage.setSubject("【提醒小助手】您已成功订阅消息通知"); //邮件主题
builder.append("小哲阳阳已记录您的邮箱了,到时候广工大出新消息就会推送给您,记得查收噢!!!\n" );
builder.append("\n招生信息官网:" + "https://yzw.gdut.edu.cn/sszs.htm");
String time = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date());
builder.append("\n[注]:" + "此邮件可放心查看(来自小哲阳阳)" + "--推送时间:"+ time );
mailMessage.setText(builder.toString()); //邮件正文
//发送邮件
mailSender.send(mailMessage);
} catch (Exception e) {
e.printStackTrace();
}
}
//第二部分,对所有用户发送邮件
public void sendEmail(List<Notice> newNotice) {
try {
//生成并填充消息体
SimpleMailMessage mailMessage = new SimpleMailMessage();
mailMessage.setSubject("【提醒小助手】广东工业大学招生网发布了新的信息"); //邮件主题
StringBuilder builder = new StringBuilder();
int count = 1;
for(int i = newNotice.size() - 1; i >= 0; i--) {
builder.append("第" + count + "条\n");count++;
builder.append("标题:" + newNotice.get(i).getNoticeTitle());
builder.append("\n通知链接:" + newNotice.get(i).getNoticeUrl());
builder.append("\n发布时间:" + newNotice.get(i).getDate());
builder.append("\n--------------\n");
}
builder.append("\n招生信息官网:" + "https://yzw.gdut.edu.cn/sszs.htm");
String time = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date());
builder.append("\n[注]:" + "此邮件可放心查看(来自小哲阳阳)" + "--推送时间:"+ time );
mailMessage.setText(builder.toString()); //邮件正文
//获取当前时间
Date date1 = new Date();
String nowTime = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(date1);
//获取用户
List<User> userList = mailMapper.selectUser();
for(int i = 0; i < userList.size(); i++) {
mailMessage.setFrom("你的邮箱xxxxx@--.com");//发送邮箱
mailMessage.setTo(userList.get(i).getUserEmail());//接收邮箱
//发送邮件
mailSender.send(mailMessage);
//更新发送时间,以便查看
mailMapper.updateSendTime(userList.get(i).getUserEmail(), nowTime);
//休息一点时间
Thread.currentThread().sleep(20000);
}
} catch (MailException | InterruptedException e) {
e.printStackTrace();
}
}
}
发送通知情况
发送新用户
新通知推送
![]() | ![]() |
---|
配置文件application.yml
server:
port: 9092
spring:
thymeleaf:
enabled: true #开启thymeleaf视图解析
encoding: utf-8 #编码
prefix: classpath:/templates/ #前缀
cache: false #是否使用缓存
mode: HTML #严格的HTML语法模式
suffix: .html #后缀名
datasource:
url: jdbc:mysql://localhost:3306/db_gdut_mail?useUnicode=true&characterEncoding=UTF-8&serverTimezone=GMT%2b8&useSSL=false
username: root
password: #你的数据库密码
driver-class-name: com.mysql.cj.jdbc.Driver
jackson:
time-zone: GMT+8
servlet:
multipart:
max-file-size: 20MB
max-request-size: 100MB
mvc:
async:
request-timeout: 30000
#由于服务器封闭了25号端口,故使用465端口
mail:
# 邮件服务地址
host: smtp.163.com
# 端口
port: 465
protocol: smtp
# 编码格式
default-encoding: utf-8
# 用户名
username: #你的邮箱
# 授权码
password: #此处不是邮箱密码,而是邮箱的IMAP/SMTP服务的授权码,在邮箱设置里面获取
# 其它参数
properties:
mail:
smtp:
# 如果是用 SSL 方式,需要配置如下属性
ssl:
enable: true
socketFactory:
port: 465
class: javax.net.ssl.SSLSocketFactory
mybatis:
mapper-locations: classpath:/mapping/*.xml
type-aliases-package: com.waiterxiaoyy
pagehelper:
helperDialect: mysql
reasonable: true
supportMethodsArguments: true
params: count=countSql
thymeleaf前台
前台使用jquery-moblie,便于手机端适配
展示页面
![]() | ![]() |
---|---|
![]() | ![]() |