day08

监听器和邮箱服务

第1章 监听器介绍

监听器:监听事件源,根据事件源上发生事件,做出相应的处理。

1.2 监听机制相关概念

事件源:发生事件的源头,监听器需要监听的对象。
事件:事件源上发生的动作,监听器监听的内容。
监听器:负责监听事件源的对象。

图片1.png

第2章 web监听器介绍

2.1 javaweb监听器介绍

JavaWEB中的监听器主要监听JavaWEB中的request、session、ServletContext对象的各种变化。
主要监听的任务:

监听request、ServletContext 、session对象的创建和销毁 (练习)
ServletRequestListener
ServletContextListener
HttpSessionListener

监听request、session、ServletContext 对象存放的数据变化情况(练习)
ServletContextAttributeListener
HttpSessionAttributeListener
ServletRequestAttributeListener

监听session中保存的JavaBean的状态
HttpSessionBindingListener

2.2 javaweb监听器创建步骤(示例:ServletRequestListener)

2.2.1 需要定义一个类实现对应的监听器接口

ServletRequestListener定义(API截图):


ServletRequestListener.png
RequestListener.png
@WebListener
public class MyServletRequestListener implements ServletRequestListener{
    @Override
    //监听request对象销毁的方法
    public void requestDestroyed(ServletRequestEvent sre) {
        System.out.println("MyServletRequestListener.....requestDestroyed....");    
    }
    @Override
    //监听request对象初始化的方法
    public void requestInitialized(ServletRequestEvent sre) {
        System.out.println("MyServletRequestListener.....requestInitialized....");
    }
}
结果.png

2.2.2 配置监听器对象

注意:当服务器加载项目的时候,会读取web.xml文件中listener标签,那么服务器会自动创建监听器对象,并且自动调用其方法
自动调用其方法,也是通过反射调用(因为他的方法名称和参数是固定的)
监听器的小结:
1)创建一个类,实现监听器接口
2)在监听器对象的方法中,书写相关的代码
3)在web.xml中配置当前监听器。省略

2.3 ServletContext创建销毁监听

ServletContextListener定义(API截图):

ServletContextListener.png
ContextListener.png

代码演示:

@WebListener
public class MyServletContextListener implements ServletContextListener{
    @Override
    public void contextInitialized(ServletContextEvent sce) {
        System.out.println("MyServletContextListener.....contextInitialized....");  
    }
    @Override
    public void contextDestroyed(ServletContextEvent sce) {
        System.out.println("MyServletContextListener.....contextDestroyed....");
    }
}

监听servletcontext对象初始化截图:

初始化.png

监听servletcontext对象销毁截图:

销毁.png

2.4 ServletContextListener案例:定时任务

需求:项目启动时,获取服务器时间(new Date()),每一秒钟更新一次,打印在控制台

思路:
1)监控项目的启动(使用ServletContextListener来监听ServletContext对象的初始化)
1)获取服务器时间:new Date();
2)每一秒更新一次:定时器Timer
4)给定时器设置定时任务

Timer:定时器 任务调度的对象

timer.png
图片2.png
图片3.png
参数.png

timeTask:定时器的任务(类)
delay:从什么时候开始执行,立即执行设置为:0
period :间隔多少时间重复执行,毫秒值,1秒=1000毫秒
TimerTask:定时器的任务(类)

timerTask.png
图片4.png

Run方法中应该写我们的定时任务:每一秒钟更新一次时间,打印在控制台上

代码实现:

Timer timer= new Timer();
timer.schedule(new TimerTask(){
    @Override
public void run() {
    SimpleDateFormat sdf=new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
    //打印时间
        System.out.println(sdf.format(new Date()));
            }
        }, 0, 3000);

2.5 HttpSessionListener对象监听session的创建与销毁监听

HttpSessionListener定义(API截图):

HttpSessionListener.png
SessionListener.png

代码演示:

public class MyHttpSessionListener implements HttpSessionListener{
    @Override
    public void sessionCreated(HttpSessionEvent se) {
        System.out.println("MyHttpSessionListener....sessionCreated....");
    }
    @Override
    public void sessionDestroyed(HttpSessionEvent se) {
        System.out.println("MyHttpSessionListener....sessionDestroyed....");
    }
}
ss.png

2.6 案例——统计在线人数

需求:统计当前访问网站的人数有多少人?

问题:什么时候我们可以知道用户访问了网站?
只要用户访问了我们的网站,session一定会创建。只要用户离开,点退出(注销),session就销毁。

思路:
只要判断session创建,在线人数就加一
只要判断session销毁,在线人数就减一

在线人数的数据,要存在哪里?
答:ServletContext对象中,所有应用程序范围都可以获取,所有访问当前网站的用户,都应该可以看到在线人数

总思路:
1 现在项目启动的时候,初始化在线人数0,保存在ServletContext
2 监听到session创建数据加一
3 监听到session销毁数据减一
4 在页面展示数据

代码实现:

@WebListener
public class MyHttpSessionListener implements HttpSessionListener {

    /**
     * Default constructor. 
     */
    public MyHttpSessionListener() {
        // TODO Auto-generated constructor stub
    }


    public void sessionCreated(HttpSessionEvent se)  { 
        System.out.println("MyHttpSessionListener-------sessionCreated");
        // 在监听器中只要判断session创建,在线人数就加一
        ServletContext context = se.getSession().getServletContext();
        //获取里面的在线人数
        Integer onlineNum=(Integer)context.getAttribute("onlineNum");
        onlineNum++;
        context.setAttribute("onlineNum", onlineNum);
         se.getSession().setMaxInactiveInterval(60);
    }

    public void sessionDestroyed(HttpSessionEvent se)  { 
        System.out.println("MyHttpSessionListener-------sessionDestroyed");
        // 在监听器中只要判断session销毁,在线人数就减去一
        ServletContext context = se.getSession().getServletContext();
        //获取里面的在线人数
        Integer onlineNum=(Integer)context.getAttribute("onlineNum");
        onlineNum--;
        context.setAttribute("onlineNum", onlineNum);
    }   
}
@WebListener
public class MyServletContextListener implements ServletContextListener {

    public MyServletContextListener() {     
    }
    public void contextDestroyed(ServletContextEvent arg0)   { 
    }

    public void contextInitialized(ServletContextEvent sce)  { 
        System.out.println("MyServletContextListener---------contextInitialized");
        ServletContext context= sce.getServletContext();
        context.setAttribute("onlineNum", 0);
    }   
}

index.jsp

  当前在线人数:${onlineNum }

第3章 属性变化的监听

主要是监听使用setAttribute、removeAttribute方法。

ServletContextAttributeListener 专门用于监听ServletContext对象中的属性的变化情况
HttpSessionAttributeListener 专门用于监听session对象中的属性的变化情况
ServletRequestAttributeListener 专门用于监听request对象中的属性的变化情况
它们中的的监听 添加 、删除 、 修改的方法名称全部一致:

图片1.png

代码演示:
Jsp:

<%
    session.setAttribute("name", "毛爷爷");
    session.setAttribute("name", "邓爷爷");
        session.removeAttribute("name");
%>

监听器:

public class MyHttpSessionAttributeListener implements HttpSessionAttributeListener    {

    @Override
public void attributeAdded(HttpSessionBindingEvent se) {
        System.out.println("MyHttpSessionAttributeListener....attributeAdded...");
    }

    @Override
public void attributeRemoved(HttpSessionBindingEvent se) {
        System.out.println("MyHttpSessionAttributeListener....attributeRemoved...");
    }

    @Override
public void attributeReplaced(HttpSessionBindingEvent se) {
        System.out.println("MyHttpSessionAttributeListener....attributeReplaced...");
    }

}

结果:

图片2.png

第4章 Session中的bean(JavaBean)监听

当我们给Session中保存一个Java对象的时候,或者把Java对象从Session中移除的时候会触发专门用来监听Session中对象变化的监听器中的方法。拥有这个方法的对象——HttpSessionBindingListener接口

属性监听和bean监听的区别:

属性监听:是对三个容器中的任何属性(包括对象和不是对象的数据,基本类型数据)的变化,进行监听
Bean监听:它只监听javabean对象往session中保存和session中移出的过程。

图片2.png
图片3.png

由于HttpSessionBindingListener是用来监听某个JavaBean对象的绑定(存入session容器)和解绑(从session容器中移除)的,所以这个监听器的实现类必须是被操作的JavaBean(HttpSessionBindingListener不需要再web.xml中配置)

javaBean:

public class User implements HttpSessionBindingListener{

    private int age;
    private String name;
    public int getAge() {
        return age;
    }
    public void setAge(int age) {
        this.age = age;
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    @Override
    public String toString() {
        return "User [age=" + age + ", name=" + name + "]";
    }
    @Override
    public void valueBound(HttpSessionBindingEvent event) {
        System.out.println("User....valueBound...");
        
    }
    @Override
    public void valueUnbound(HttpSessionBindingEvent event) {
        System.out.println("User....valueUnbound...");
        
    }
}

JSP:

 <%
    session.setAttribute("user", new User());
     session.removeAttribute("user");
     %>

效果:

图片4.png

Bean监听需求:
在线人数,根据session创建和销毁,来做人数的增减。
在线会员统计:
1)User类实现bean监听接口
2)每次监听到loginUser对象被绑定到session中的时候,会员人数加一
3)每次监听到loginUser对象被解绑的时候,会员人数减一

总结:
1 熟悉监听器相关的概念(事件源 事件 监听器)
2 掌握监听器的创建步骤
3 完成笔记中两个案例(定时任务 在线人数)

服务器的启动时间动态获取如何做?

第5章 电子邮件学习

5.1 一、电子邮件运行机制?

平时生活中写信:

用户1——————》邮局——————————》邮局——————》用户2

5.1.1 错误的常识:

图片5.png

5.1.2 正确的原理:

图片6.png

今天的邮件服务器逻辑:

图片8.png

6.使用外网服务器(QQ)发送邮件

获取QQ邮箱服务器地址:

图片9.png
图片10.png
图片11.png

修改服务器地址:
props.put("mail.smtp.host", "smtp.qq.com");

错误:需要认证信息

com.sun.mail.smtp.SMTPSendFailedException: 503 Error: need EHLO and AUTH first !
  nested exception is:
    com.sun.mail.smtp.SMTPSenderFailedException: 503 Error: need EHLO and AUTH first !

添加认证:
在javamail-samples,找到红框内容,查看代码:

图片12.png

在集合多添加了一行用户认证:


图片15.png

代码添加:认证

图片16.png

报错:认证需要用户名和密码:

javax.mail.AuthenticationFailedException: failed to connect, no password specified?

填上用户名和密码,继续报错:设置ssl端口587

javax.mail.AuthenticationFailedException: 530 Error: A secure connection is requiered(such as ssl). More information at http://service.mail.qq.com/cgi-bin/help?id=28

添加端口,继续报错:需要授权码(使用第三方客户端登录QQ邮箱),根据网址提示操作

javax.mail.AuthenticationFailedException: 535 Error: ÇëʹÓÃÊÚȨÂëµÇ¼¡£ÏêÇéÇë¿´: http://service.mail.qq.com/cgi-bin/help?subtype=1&&id=28&&no=1001256

什么是授权码,它又是如何设置?

1、什么是授权码?

授权码是QQ邮箱推出的,用于登录第三方客户端的专用密码。
适用于登录以下服务:POP3/IMAP/SMTP/Exchange/CardDAV/CalDAV服务。
温馨提醒:为了你的帐户安全,更改QQ密码以及独立密码会触发授权码过期,需要重新获取新的授权码登录。

2、怎么获取授权码?
先进入设置-》帐户页面找到入口,按照以下流程操作。
(1)点击“开启”(pop3/smtp 服务)

图片17.png

验证:密保

(3)获取授权码


图片18.png

3、在第三方客户端怎么设置?

在第三方客户端的密码框里面输入16位授权码进行验证。(涂改处写入授权码)

图片19.png

代码:

import java.util.Date;
import java.util.Properties;

import javax.mail.Message;
import javax.mail.Session;
import javax.mail.Transport;
import javax.mail.internet.InternetAddress;
import javax.mail.internet.MimeMessage;

public class MsgMailTest {
    public static void main(String[] args) {
        sendMail("xxxxx@qq.com", "xxxx@qq.com", "javaMailTest", "嘿嘿,编程发邮件");
    }

    public static void sendMail(String from, String to, String subject, String msgText) {
        
        Properties props = new Properties();
        props.put("mail.smtp.host", "smtp.qq.com");
        props.put("mail.debug", true);
        props.put("mail.smtp.auth", "true");
        props.put("mail.smtp.port", "587");

        Session session = Session.getInstance(props, null);
        session.setDebug(false);

        try {
            MimeMessage msg = new MimeMessage(session);
            msg.setFrom(new InternetAddress(from));
            InternetAddress[] address = { new InternetAddress(to) };
            msg.setRecipients(Message.RecipientType.TO, address);
            msg.setSubject(subject);
            msg.setSentDate(new Date());
            msg.setText(msgText);
            // xxx邮箱用户名,yyy,邮箱授权密码
            Transport.send(msg, "xxxxxx@qq.com", "授权码");
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

延时发送邮件

import java.util.Date;
import java.util.Timer;
import java.util.TimerTask;

public class DelaySendMail {
        public  static void delaysendMail(){
            Timer timer=new Timer();
            timer.schedule(new TimerTask(){
    @Override
    public void run() {
    System.out.println("准备发送邮件.......");
    MsgMailTest.sendMail("xxxxxxx@qq.com", "xxxxx@qq.com", "Test", "嘿嘿");
    System.out.println("发送邮件完成....");
    }
      },  new Date(new Date().getTime() + 1000*60));
        }
}

需要jar包:
javax.mail.jar

练习

统计当前在线人数,并区分游客和登陆用户
训练考核知识点

Session工作机制
登陆功能原理
监听器描述

操作步骤描述

1.登陆功能以及退出功能已经开发好.直接使用即可.

2.创建监听器并实现ServletContextListener, HttpSessionListener, HttpSessionAttributeListener

3.创建两个集合放置session.其中一个集合放置未登陆的session.另一个集合放置登陆后的session.

4.在servletContext创建时对集合进行初始化.并放入application域(方便在页面取出)

5.每当有session创建时,说明有新的用户访问网站,将session放入游客集合

6.每当有session添加登陆成功标识时,说明有游客登陆了.将session从游客集合中移除,添加到登陆用户集合

7.每当有session移除时说明有登录用户或游客离开了.将session从用户或游客集合中移除

8.在index.jsp中取出游客以及登陆用户集合的数量显示

练习
JSP

<body>
    当前在线游客人数:${onlineNum.size()}<br/>
    当前在线登录人数:${userNum.size() }<br/>
    当前在线总数:${onlineNum.size()+userNum.size() }<br/>
    <a href="${pageContext.request.contextPath }/BeanLoginServlet">用户登录</a>
    <a href="${pageContext.request.contextPath }/LogOutServlet">退出登录</a><br/>
</body>

listerner

@WebListener
public class ListenerTest01 implements ServletContextListener, HttpSessionListener,HttpSessionAttributeListener{
    private Set<HttpSession> onlineNum;
    private Set<HttpSession> userNum;
    ServletContext context;
    public ListenerTest01() {
        // TODO Auto-generated constructor stub
    }
    

    @SuppressWarnings("unchecked")
    public void sessionCreated(HttpSessionEvent se)  { 
        System.out.println("MyListener-------sessionCreated");
//       在监听器中只要判断session创建,在线人数就加一
        //获取里面的在线人数
        onlineNum=(Set<HttpSession>) context.getAttribute("onlineNum");
        onlineNum.add(se.getSession());
        context.setAttribute("onlineNum", onlineNum);
    }

    /**
     * @see ServletRequestListener#requestDestroyed(ServletRequestEvent)
     */
    public void requestDestroyed(ServletRequestEvent arg0)  { 
        System.out.println("MyListener-------requestDestroyed");
    }

    /**
     * @see ServletRequestListener#requestInitialized(ServletRequestEvent)
     */
    public void requestInitialized(ServletRequestEvent arg0)  { 
        System.out.println("MyListener-------requestInitialized");
    }

    /**
     * @see HttpSessionListener#sessionDestroyed(HttpSessionEvent)
     */
    @SuppressWarnings("unchecked")
    public void sessionDestroyed(HttpSessionEvent se)  { 
        System.out.println("MyListener-------sessionDestroyed");
        //获取里面的在线人数减一
        onlineNum=(Set<HttpSession>) context.getAttribute("onlineNum");
        onlineNum.remove(se.getSession());
        context.setAttribute("onlineNum", onlineNum);
    }

    /**
     * @see ServletContextListener#contextDestroyed(ServletContextEvent)
     */
    public void contextDestroyed(ServletContextEvent arg0)  { 
         // TODO Auto-generated method stub
    }

    /**
     * @see ServletContextListener#contextInitialized(ServletContextEvent)
     */
    public void contextInitialized(ServletContextEvent sce)  { 
        System.out.println("MyListener---------contextInitialized");
        //初始化数据
        onlineNum =new HashSet<>();
        userNum =new HashSet<>();
        context= sce.getServletContext();
        context.setAttribute("onlineNum", onlineNum);
        context.setAttribute("userNum", userNum);
    }


    @Override
    public void attributeAdded(HttpSessionBindingEvent arg0) {
        //登录操作
        //游客减一
        onlineNum.remove(arg0.getSession());
        //用户加一
        userNum.add(arg0.getSession());
        context.setAttribute("onlineNum", onlineNum);
        context.setAttribute("userNum", userNum);
    }


    @Override
    public void attributeRemoved(HttpSessionBindingEvent arg0) {
        //登出操作
        //游客加一
        onlineNum.add(arg0.getSession());
        //用户减一
        userNum.remove(arg0.getSession());
        context.setAttribute("onlineNum", onlineNum);
        context.setAttribute("userNum", userNum);
        
    }


    @Override 
    public void attributeReplaced(HttpSessionBindingEvent arg0) {
        // TODO Auto-generated method stub
        
    }   
}

BeanLoginServlet

@WebServlet("/BeanLoginServlet")
public class BeanLoginServlet extends HttpServlet {
    private static final long serialVersionUID = 1L;
       
    /**
     * @see HttpServlet#HttpServlet()
     */
    public BeanLoginServlet() {
        super();
        // TODO Auto-generated constructor stub
    }

    /**
     * @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse response)
     */
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        response.setCharacterEncoding("utf-8");
        response.setContentType("text/html; charset=utf-8");
        //模拟用户登录
        HttpSession session=request.getSession();
        //用户登录成功
        User loginUser=new User();
        session.setAttribute("user", loginUser);
        request.getRequestDispatcher("jsp1/index.jsp").forward(request, response);
    }

    /**
     * @see HttpServlet#doPost(HttpServletRequest request, HttpServletResponse response)
     */
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        // TODO Auto-generated method stub
        doGet(request, response);
    }

}

LogOutServlet

@WebServlet("/LogOutServlet")
public class LogOutServlet extends HttpServlet {
    private static final long serialVersionUID = 1L;
       
    /**
     * @see HttpServlet#HttpServlet()
     */
    public LogOutServlet() {
        super();
        // TODO Auto-generated constructor stub
    }

    /**
     * @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse response)
     */
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        response.setCharacterEncoding("utf-8");
        response.setContentType("text/html; charset=utf-8");
        //模拟用户登录
        HttpSession session=request.getSession();
        //用户登录成功
        session.removeAttribute("user");
        request.getRequestDispatcher("jsp1/index.jsp").forward(request, response);
    }

    /**
     * @see HttpServlet#doPost(HttpServletRequest request, HttpServletResponse response)
     */
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        // TODO Auto-generated method stub
        doGet(request, response);
    }

}

游客访问页面情况

图片20.png

游客登录后页面情况

图片21.png
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 202,607评论 5 476
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,047评论 2 379
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 149,496评论 0 335
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,405评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,400评论 5 364
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,479评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,883评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,535评论 0 256
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,743评论 1 295
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,544评论 2 319
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,612评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,309评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,881评论 3 306
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,891评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,136评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,783评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,316评论 2 342

推荐阅读更多精彩内容