2.监听器
(1)什么是监听器
servlet规范当中定义的一种特殊的组件,用于
监听容器产生的事件并进行相应的处理。
注:
主要有两大类事件:
1)生命周期相关的事件:容器创建了或者销毁了
request,session,servlet上下文时产生的
事件。
2)绑订数据相关的事件:request,session,servlet
上下文执行了setAttribute,removeAttribute
产生的事件。
(2)如何写监听器?
step1. 写一个java类,实现相应的监听器接口。
注:要依据监听的事件类型,选择实现相应的接口,
比如,要监听session的创建和销毁,应该实现
HttpSessionListener接口。
step2. 在接口方法中,实现监听处理逻辑。
step3. 配置监听器。 web.xml
2.servlet线程安全问题
(1)为什么说servlet会有线程安全问题?
a.容器只会创建一个servlet实例。
b.容器收到一个请求,就会启动一个线程来处理
该请求。
如果有多个线程同时访问某个servlet实例,比如,
都去修改该实例的属性,就有可能产生线程安全问题。
(2)如何解决?
将有可能产生线程安全问题的代码使用
synchronized来加锁。
注:
a.使用synchronized加锁对性能会有一些
影响。
b.尽量避免修改属性。
3. jsp基础
(1)jsp是什么?
sun公司制订的一种服务器端的动态页面技术规范。
(2)如何写jsp?
step1.添加一个以.jsp为后缀的文件。
step2.在该文件里面,可以添加如下内容:
1)html (css,js)
直接写
2)java代码
a. java代码片断
<% java代码 %>
b. jsp表达式
<%= java表达式 %>
c. jsp声明 (a1.jsp)
<%! 声明一些变量或者方法 %>
3)指令
a.什么是指令?
通知容器,在将jsp转换成servlet时做一些
额外的处理,比如导包。
b.语法
<%@ 指令名 属性=值 %>
c.page指令
contentType属性:设置 response.setContentType方法的参数值。
pageEncoding属性:设置jsp页面的编码。
import属性:导包。
session属性:缺省值是true,如果值是false,
则session隐含对象不能用了。(a2.jsp)
errorPage属性: 指定一个异常处理页面。
注:当jsp运行时发生了异常,容器会调用
指定的异常处理页面。(a3.jsp)
isErrorPage属性:缺省值是false,如果值为
true,则可以使用exception隐含对象。
(a4.jsp)
d.include指令
告诉容器,在将jsp转换成servlet时,将
file属性指定的文件的内容,插入到该指令
所在的位置。
e.taglib指令
导入jsp标签。
注:jsp标签可以用来替换jsp当中的java代码。
4)隐含对象
a.什么是隐含对象?
直接可以使用的对象。
b.为什么可以直接使用这些隐含对象?
容器会自动添加获得这些对象的代码。
c.有哪些隐含对象?
out,request,response
session
application
pageContext
pageContext是什么?
容器会为每一个jsp实例创建唯一的
一个符合PageContext接口要求的
对象,一般称之为page上下文。
pageContext的特点?
唯一性:一个jsp实例对应一个page
上下文。
持久性: 只要jsp实例还在,那么
page上下文就一直存在。
pageContext的作用?
作用1:绑订数据。(a6.jsp,a7.jsp)
注:绑订到page上下文上的
数据,只有对应的jsp实例
能够访问。
作用2: 通过该对象,找到其它所有
隐含对象。
exception (只有当isErrorPage属性值为
true时,才能使用)。
config (ServletConfig) a5.jsp
page (jsp实例本身)
注:jsp先转换成servlet,然后实例化,
jsp实例指的就是这个对应的servlet
实例。
5)注释 (a8.jsp)
a. <!-- 注释的内容 -->
如果注释的内容是java代码,java代码会执行。
b. <%-- 注释的内容 --%>
如果注释的内容是java代码,java代码不会执行。
(3)jsp是如何执行的?
step1.容器要将jsp转换成servlet。
html ----> service方法,使用out.write输 出。
<% %> ---> service方法,照搬。
<%= %> ---> service方法,使用out.print 输出。
<%! %> ----> 增加新的属性和方法。
step2.执行该servlet。
在web包下面建个CountListener.java
package web;
import javax.servlet.ServletContext;
import javax.servlet.http.HttpSession;
import javax.servlet.http.HttpSessionEvent;
import javax.servlet.http.HttpSessionListener;
public class CountListener
implements HttpSessionListener{
/**
* session对象创建之后,容器会调用
* 此方法。
* 注:
* HttpSessionEvent:事件对象。
*/
public void sessionCreated(
HttpSessionEvent arg0) {
System.out.println("sessionCreated");
HttpSession session =
arg0.getSession();
ServletContext sctx =
session.getServletContext();
Integer count =
(Integer)sctx.getAttribute(
"count");
if(count == null){
//第一个用户
count = 1;
}else{
count ++;
}
sctx.setAttribute("count", count);
}
/**
* session对象销毁之后,容器会调用
* 此方法。
*/
public void sessionDestroyed(
HttpSessionEvent arg0) {
System.out.println("sessionDestroyed");
HttpSession session =
arg0.getSession();
ServletContext sctx =
session.getServletContext();
Integer count =
(Integer)sctx.getAttribute(
"count");
count --;
sctx.setAttribute("count", count);
}
}
在建一个项目,在web包里面在写一个java类:
SomeServlet.java
package web;
import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
public class SomeServlet extends HttpServlet {
private static final long serialVersionUID = 1L;
private int count = 0;
protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
synchronized(this){
count ++;
try {
Thread.sleep(800);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(
Thread.currentThread()
.getName() + " " + count);
}
}
}