【小工具】 招生网出新信息则通过邮箱推送

前言

由于不经常上学校的招生信息网,故写个小工具,每隔半个小时扫描一遍招生网,若发现新消息,则将通知的链接和发布时间推送到在此之前登记过的用户邮箱。

体验

体验网址:http://47.107.103.76:9092/

博客链接:http://waiterxiaoyy.ltd/index.php/archives/49/

仓库链接:https://gitee.com/waiterxiaoyy/gdut-mail

使用技术

技术说明
SpringBoot2.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,便于手机端适配

展示页面

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值