監(jiān)聽器和郵箱服務(wù)
第1章 監(jiān)聽器介紹
監(jiān)聽器:監(jiān)聽事件源彪置,根據(jù)事件源上發(fā)生事件拄踪,做出相應(yīng)的處理。
1.2 監(jiān)聽機(jī)制相關(guān)概念
事件源:發(fā)生事件的源頭拳魁,監(jiān)聽器需要監(jiān)聽的對象惶桐。
事件:事件源上發(fā)生的動作,監(jiān)聽器監(jiān)聽的內(nèi)容。
監(jiān)聽器:負(fù)責(zé)監(jiān)聽事件源的對象姚糊。
第2章 web監(jiān)聽器介紹
2.1 javaweb監(jiān)聽器介紹
JavaWEB中的監(jiān)聽器主要監(jiān)聽JavaWEB中的request贿衍、session、ServletContext對象的各種變化救恨。
主要監(jiān)聽的任務(wù):
監(jiān)聽request贸辈、ServletContext 、session對象的創(chuàng)建和銷毀 (練習(xí))
ServletRequestListener
ServletContextListener
HttpSessionListener
監(jiān)聽request肠槽、session擎淤、ServletContext 對象存放的數(shù)據(jù)變化情況(練習(xí))
ServletContextAttributeListener
HttpSessionAttributeListener
ServletRequestAttributeListener
監(jiān)聽session中保存的JavaBean的狀態(tài)
HttpSessionBindingListener
2.2 javaweb監(jiān)聽器創(chuàng)建步驟(示例:ServletRequestListener)
2.2.1 需要定義一個類實(shí)現(xiàn)對應(yīng)的監(jiān)聽器接口
ServletRequestListener定義(API截圖):
@WebListener
public class MyServletRequestListener implements ServletRequestListener{
@Override
//監(jiān)聽request對象銷毀的方法
public void requestDestroyed(ServletRequestEvent sre) {
System.out.println("MyServletRequestListener.....requestDestroyed....");
}
@Override
//監(jiān)聽request對象初始化的方法
public void requestInitialized(ServletRequestEvent sre) {
System.out.println("MyServletRequestListener.....requestInitialized....");
}
}
2.2.2 配置監(jiān)聽器對象
注意:當(dāng)服務(wù)器加載項(xiàng)目的時候,會讀取web.xml文件中l(wèi)istener標(biāo)簽秸仙,那么服務(wù)器會自動創(chuàng)建監(jiān)聽器對象嘴拢,并且自動調(diào)用其方法
自動調(diào)用其方法,也是通過反射調(diào)用(因?yàn)樗姆椒Q和參數(shù)是固定的)
監(jiān)聽器的小結(jié):
1)創(chuàng)建一個類筋栋,實(shí)現(xiàn)監(jiān)聽器接口
2)在監(jiān)聽器對象的方法中炊汤,書寫相關(guān)的代碼
3)在web.xml中配置當(dāng)前監(jiān)聽器。省略
2.3 ServletContext創(chuàng)建銷毀監(jiān)聽
ServletContextListener定義(API截圖):
代碼演示:
@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....");
}
}
監(jiān)聽servletcontext對象初始化截圖:
監(jiān)聽servletcontext對象銷毀截圖:
2.4 ServletContextListener案例:定時任務(wù)
需求:項(xiàng)目啟動時弊攘,獲取服務(wù)器時間(new Date())抢腐,每一秒鐘更新一次,打印在控制臺
思路:
1)監(jiān)控項(xiàng)目的啟動(使用ServletContextListener來監(jiān)聽ServletContext對象的初始化)
1)獲取服務(wù)器時間:new Date()襟交;
2)每一秒更新一次:定時器Timer
4)給定時器設(shè)置定時任務(wù)
Timer:定時器 任務(wù)調(diào)度的對象
timeTask:定時器的任務(wù)(類)
delay:從什么時候開始執(zhí)行迈倍,立即執(zhí)行設(shè)置為:0
period :間隔多少時間重復(fù)執(zhí)行,毫秒值捣域,1秒=1000毫秒
TimerTask:定時器的任務(wù)(類)
Run方法中應(yīng)該寫我們的定時任務(wù):每一秒鐘更新一次時間啼染,打印在控制臺上
代碼實(shí)現(xiàn):
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對象監(jiān)聽session的創(chuàng)建與銷毀監(jiān)聽
HttpSessionListener定義(API截圖):
代碼演示:
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....");
}
}
2.6 案例——統(tǒng)計在線人數(shù)
需求:統(tǒng)計當(dāng)前訪問網(wǎng)站的人數(shù)有多少人?
問題:什么時候我們可以知道用戶訪問了網(wǎng)站焕梅?
只要用戶訪問了我們的網(wǎng)站迹鹅,session一定會創(chuàng)建。只要用戶離開贞言,點(diǎn)退出(注銷)斜棚,session就銷毀。
思路:
只要判斷session創(chuàng)建该窗,在線人數(shù)就加一
只要判斷session銷毀弟蚀,在線人數(shù)就減一
在線人數(shù)的數(shù)據(jù),要存在哪里酗失?
答:ServletContext對象中义钉,所有應(yīng)用程序范圍都可以獲取,所有訪問當(dāng)前網(wǎng)站的用戶规肴,都應(yīng)該可以看到在線人數(shù)
總思路:
1 現(xiàn)在項(xiàng)目啟動的時候捶闸,初始化在線人數(shù)0夜畴,保存在ServletContext
2 監(jiān)聽到session創(chuàng)建數(shù)據(jù)加一
3 監(jiān)聽到session銷毀數(shù)據(jù)減一
4 在頁面展示數(shù)據(jù)
代碼實(shí)現(xiàn):
@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");
// 在監(jiān)聽器中只要判斷session創(chuàng)建,在線人數(shù)就加一
ServletContext context = se.getSession().getServletContext();
//獲取里面的在線人數(shù)
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");
// 在監(jiān)聽器中只要判斷session銷毀鉴嗤,在線人數(shù)就減去一
ServletContext context = se.getSession().getServletContext();
//獲取里面的在線人數(shù)
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
當(dāng)前在線人數(shù):${onlineNum }
第3章 屬性變化的監(jiān)聽
主要是監(jiān)聽使用setAttribute斩启、removeAttribute方法。
ServletContextAttributeListener 專門用于監(jiān)聽ServletContext對象中的屬性的變化情況
HttpSessionAttributeListener 專門用于監(jiān)聽session對象中的屬性的變化情況
ServletRequestAttributeListener 專門用于監(jiān)聽request對象中的屬性的變化情況
它們中的的監(jiān)聽 添加 醉锅、刪除 、 修改的方法名稱全部一致:
代碼演示:
Jsp:
<%
session.setAttribute("name", "毛爺爺");
session.setAttribute("name", "鄧爺爺");
session.removeAttribute("name");
%>
監(jiān)聽器:
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...");
}
}
結(jié)果:
第4章 Session中的bean(JavaBean)監(jiān)聽
當(dāng)我們給Session中保存一個Java對象的時候发绢,或者把Java對象從Session中移除的時候會觸發(fā)專門用來監(jiān)聽Session中對象變化的監(jiān)聽器中的方法硬耍。擁有這個方法的對象——HttpSessionBindingListener接口
屬性監(jiān)聽和bean監(jiān)聽的區(qū)別:
屬性監(jiān)聽:是對三個容器中的任何屬性(包括對象和不是對象的數(shù)據(jù),基本類型數(shù)據(jù))的變化边酒,進(jìn)行監(jiān)聽
Bean監(jiān)聽:它只監(jiān)聽javabean對象往session中保存和session中移出的過程经柴。
由于HttpSessionBindingListener是用來監(jiān)聽某個JavaBean對象的綁定(存入session容器)和解綁(從session容器中移除)的,所以這個監(jiān)聽器的實(shí)現(xiàn)類必須是被操作的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");
%>
效果:
Bean監(jiān)聽需求:
在線人數(shù)墩朦,根據(jù)session創(chuàng)建和銷毀坯认,來做人數(shù)的增減。
在線會員統(tǒng)計:
1)User類實(shí)現(xiàn)bean監(jiān)聽接口
2)每次監(jiān)聽到loginUser對象被綁定到session中的時候氓涣,會員人數(shù)加一
3)每次監(jiān)聽到loginUser對象被解綁的時候牛哺,會員人數(shù)減一
總結(jié):
1 熟悉監(jiān)聽器相關(guān)的概念(事件源 事件 監(jiān)聽器)
2 掌握監(jiān)聽器的創(chuàng)建步驟
3 完成筆記中兩個案例(定時任務(wù) 在線人數(shù))
服務(wù)器的啟動時間動態(tài)獲取如何做?
第5章 電子郵件學(xué)習(xí)
5.1 一劳吠、電子郵件運(yùn)行機(jī)制引润?
平時生活中寫信:
用戶1——————》郵局——————————》郵局——————》用戶2
5.1.1 錯誤的常識:
5.1.2 正確的原理:
今天的郵件服務(wù)器邏輯:
6.使用外網(wǎng)服務(wù)器(QQ)發(fā)送郵件
獲取QQ郵箱服務(wù)器地址:
修改服務(wù)器地址:
props.put("mail.smtp.host", "smtp.qq.com");
錯誤:需要認(rèn)證信息
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 !
添加認(rèn)證:
在javamail-samples,找到紅框內(nèi)容痒玩,查看代碼:
在集合多添加了一行用戶認(rèn)證:
代碼添加:認(rèn)證
報錯:認(rèn)證需要用戶名和密碼:
javax.mail.AuthenticationFailedException: failed to connect, no password specified?
填上用戶名和密碼淳附,繼續(xù)報錯:設(shè)置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
添加端口,繼續(xù)報錯:需要授權(quán)碼(使用第三方客戶端登錄QQ郵箱)蠢古,根據(jù)網(wǎng)址提示操作
javax.mail.AuthenticationFailedException: 535 Error: ??ê1ó?êúè¨??μ????£?ê?é???′: http://service.mail.qq.com/cgi-bin/help?subtype=1&&id=28&&no=1001256
什么是授權(quán)碼奴曙,它又是如何設(shè)置?
1草讶、什么是授權(quán)碼洽糟?
授權(quán)碼是QQ郵箱推出的,用于登錄第三方客戶端的專用密碼到涂。
適用于登錄以下服務(wù):POP3/IMAP/SMTP/Exchange/CardDAV/CalDAV服務(wù)脊框。
溫馨提醒:為了你的帳戶安全,更改QQ密碼以及獨(dú)立密碼會觸發(fā)授權(quán)碼過期践啄,需要重新獲取新的授權(quán)碼登錄浇雹。
2、怎么獲取授權(quán)碼屿讽?
先進(jìn)入設(shè)置-》帳戶頁面找到入口昭灵,按照以下流程操作吠裆。
(1)點(diǎn)擊“開啟”(pop3/smtp 服務(wù))
驗(yàn)證:密保
(3)獲取授權(quán)碼
3、在第三方客戶端怎么設(shè)置烂完?
在第三方客戶端的密碼框里面輸入16位授權(quán)碼進(jìn)行驗(yàn)證试疙。(涂改處寫入授權(quán)碼)
代碼:
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", "嘿嘿,編程發(fā)郵件");
}
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抠蚣,郵箱授權(quán)密碼
Transport.send(msg, "xxxxxx@qq.com", "授權(quán)碼");
} catch (Exception e) {
e.printStackTrace();
}
}
}
延時發(fā)送郵件
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("準(zhǔn)備發(fā)送郵件.......");
MsgMailTest.sendMail("xxxxxxx@qq.com", "xxxxx@qq.com", "Test", "嘿嘿");
System.out.println("發(fā)送郵件完成....");
}
}, new Date(new Date().getTime() + 1000*60));
}
}
需要jar包:
javax.mail.jar
練習(xí)
統(tǒng)計當(dāng)前在線人數(shù),并區(qū)分游客和登陸用戶
訓(xùn)練考核知識點(diǎn)
Session工作機(jī)制
登陸功能原理
監(jiān)聽器描述
操作步驟描述
1.登陸功能以及退出功能已經(jīng)開發(fā)好.直接使用即可.
2.創(chuàng)建監(jiān)聽器并實(shí)現(xiàn)ServletContextListener, HttpSessionListener, HttpSessionAttributeListener
3.創(chuàng)建兩個集合放置session.其中一個集合放置未登陸的session.另一個集合放置登陸后的session.
4.在servletContext創(chuàng)建時對集合進(jìn)行初始化.并放入application域(方便在頁面取出)
5.每當(dāng)有session創(chuàng)建時,說明有新的用戶訪問網(wǎng)站,將session放入游客集合
6.每當(dāng)有session添加登陸成功標(biāo)識時,說明有游客登陸了.將session從游客集合中移除,添加到登陸用戶集合
7.每當(dāng)有session移除時說明有登錄用戶或游客離開了.將session從用戶或游客集合中移除
8.在index.jsp中取出游客以及登陸用戶集合的數(shù)量顯示
練習(xí)
JSP
<body>
當(dāng)前在線游客人數(shù):${onlineNum.size()}<br/>
當(dāng)前在線登錄人數(shù):${userNum.size() }<br/>
當(dāng)前在線總數(shù):${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");
// 在監(jiān)聽器中只要判斷session創(chuàng)建祝旷,在線人數(shù)就加一
//獲取里面的在線人數(shù)
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");
//獲取里面的在線人數(shù)減一
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");
//初始化數(shù)據(jù)
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);
}
}
游客訪問頁面情況
游客登錄后頁面情況