##1、ServletRequest
对于每个Http请求,Servlet容器会创建一个ServletRequest实例,并将它传给Servlet的Service方法,ServletRequest封装关于这个请求的信息
##2、ServletResponse
表示一个Servlet响应,在调用Servlet的Service方法之前,Servlet容器会首先创建一个ServletResponse,作为第二个参数传入Service方法,ServletResponse隐藏了向浏览器发送响应的复杂过程
在ServletResponse定义的方法里有getWriter方法,它返回了一个可以向客户端发送文本的PrintWriter。
##3、ServletConfig
Servlet容器初始化时会给init方法传入一个ServletConfig,ServletConfig封装了可以通过@WebServlet或部署描述符传给Servlet的配置信息,这样传入的每一条信息叫做一个初始化参数,一个初始化参数有key和value,可以通过调用ServletConfig的getInitParameter方法获取。
下面是ServletConfig的例子
@WebServlet(name = "ServletConfigDemo", urlPatterns = { "/ServletConfigDemo" }, initParams = {
@WebInitParam(name = "admin", value = "Harry Taciak"),
@WebInitParam(name = "email", value = "xxx@qq.com") }
)
public class ServletConfigDemo implements Servlet {
private transient ServletConfig servletConfig;
@Override
public void destroy() {
// TODO Auto-generated method stub
}
@Override
public ServletConfig getServletConfig() {
// TODO Auto-generated method stub
return servletConfig;
}
@Override
public String getServletInfo() {
// TODO Auto-generated method stub
return "ServletConfig demo";
}
@Override
public void init(ServletConfig servletConfig) throws ServletException {
// TODO Auto-generated method stub
this.servletConfig = servletConfig;
}
@Override
public void service(ServletRequest request, ServletResponse response)
throws ServletException, IOException {
// TODO Auto-generated method stub
ServletConfig servletConfig = getServletConfig();
String admin = servletConfig.getInitParameter("admin");
String email = servletConfig.getInitParameter("email");
response.setContentType("text/html");
PrintWriter writer = response.getWriter();
writer.print("<html><head></head><body>" + "Admin:" + admin
+ "<br/>Email:" + email + "</body></html>");
}
}
运行结果
##4、ServletContext
每个Web应用程序只有一个上下文,在将程序同时部署到多个容器的分布式环境中,每台Java虚拟机上的Web应用都会有一个ServletContext对象
通过在ServletConfig中调用getServletContext方法,来获取ServletContext,得到后就可以共享从应用程序中的所有资料访问到的信息,而且还可以动态注册Web对象
##5、GenericServlet
抽象类GenericServlet让上面的ServletConfigDemo的代码更简单,GenericServlet实现了Servlet和ServletConfig接口,并完成了init()方法的ServletConfig赋值,还实现了Serlvet的所有方法提供默认的实现
@WebServlet(name = "GenericServletDemo", urlPatterns = { "/GenericServletDemo" }, initParams = {
@WebInitParam(name = "admin", value = "jyx"),
@WebInitParam(name = "email", value = "xxx@qq.com") })
public class GenericServletDemo extends GenericServlet {
private static final long serialVersionUID=62500890L;
@Override
public void service(ServletRequest request, ServletResponse response)
throws ServletException, IOException {
ServletConfig servletConfig=getServletConfig();
String admin=servletConfig.getInitParameter("admin");
String email=servletConfig.getInitParameter("email");
response.setContentType("text/html");
PrintWriter writer = response.getWriter();
writer.print("<html><head></head><body>" + "Admin:" + admin
+ "<br/>Email:" + email + "</body></html>");
}
}
运行结果
效果一样,但代码变简洁了
##会话管理
###1、URL重写
URL重写是一种会话跟踪技术,它将一个或多个token添加到URL的查询字符串中,每个token通常是key=value形式,如
@WebServlet(name = "Top2Servlet", urlPatterns = { "/top10" })
public class Top2Servlet extends HttpServlet {
private List<String> LondonAttrs;
private List<String> ParisAttrs;
@Override
public void init() throws ServletException {
LondonAttrs = new ArrayList<String>(10);
ParisAttrs = new ArrayList<String>(10);
LondonAttrs.add("London eye");
LondonAttrs.add("2012 park");
LondonAttrs.add("London eye");
LondonAttrs.add("2012 park");
LondonAttrs.add("London eye");
LondonAttrs.add("2012 park");
LondonAttrs.add("London eye");
LondonAttrs.add("2012 park");
LondonAttrs.add("London eye");
LondonAttrs.add("2012 park");
ParisAttrs.add("Notre Dame");
ParisAttrs.add("Musee d");
ParisAttrs.add("Notre Dame");
ParisAttrs.add("Musee d");
ParisAttrs.add("Notre Dame");
ParisAttrs.add("Musee d");
ParisAttrs.add("Notre Dame");
ParisAttrs.add("Musee d");
ParisAttrs.add("Notre Dame");
ParisAttrs.add("Musee d");
}
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
String city = req.getParameter("city");
if (city != null && (city.equals("london") || city.equals("paris"))) {
showAttractions(req, resp, city);
} else {
showMainPage(req, resp);
}
}
private void showMainPage(HttpServletRequest req, HttpServletResponse resp)
throws IOException {
resp.setContentType("text/html");
PrintWriter write = resp.getWriter();
write.print("<html><head>" + "<title>Top 10</title>" + "</head><body>"
+ "please select city:"
+ "<br/><a href='?city=london'>London</a>"
+ "<br/><a href='?city=paris'>Paris</a>" + "</body></html>");
}
private void showAttractions(HttpServletRequest req,
HttpServletResponse resp, String city) throws IOException {
int page = 1;
String pageParameter = req.getParameter("page");
if (pageParameter != null) {
page = Integer.parseInt(pageParameter);
if (page > 2) {
page = 1;
}
}
List<String> attrs = null;
if (city.equals("london")) {
attrs = LondonAttrs;
} else if (city.equals("paris")) {
attrs = ParisAttrs;
}
resp.setContentType("text/html");
PrintWriter write = resp.getWriter();
write.println("<html><head>" + "<title>top 10 result</title>"
+ "</html></head>");
write.println("<a href='top2'>Select city</a>");
write.println("</hr> page"+ page+"<hr/>");
int start=page*5-5;
for(int i=start;i<start+5;i++){
write.println(attrs.get(i)+"<br/>");
}
write.println("<hr style='Color:blue'/>"+
"<a href ='?city="+city+"&page=1'>page 1</a>"
);
write.println(
" <a href ='?city="+city+"&page=2'>page 2</a>"
);
write.println("</body></html>");
}
}
##Session
本实例说明了如何使用 HttpSession 对象获取 session 会话创建时间和最后访问时间。如果不存在 session 会话,我们将通过请求创建一个新的 session 会话。
/**
* Created by 在云端 on 2017/6/9.
*/
@WebServlet(name="MyServletSession", urlPatterns = { "/MyServletSession" })
public class MyServletSession extends HttpServlet {
/*
如果你修改了此类, 要修改此值。否则以前用老版本的类序列化的类恢复时会出错。为了在反序列化时,确保类版本的兼容性,
最好在每个要序列化的类中加入private static final long serialVersionUID这个属性,具体数值自己定义。
*/
private static final long serialVersionUID = 1L;
@Override
protected void doGet(HttpServletRequest request,
HttpServletResponse response) throws ServletException, IOException {
//如果不存在session会话,则创建一个session对象
HttpSession session = request.getSession(true);
//获取session创建时间
Date createTime = new Date(session.getCreationTime());
//获取该网页的最后一次访问时间
Date lastAccessTime = new Date(session.getLastAccessedTime());
//设置日期输出的格式
SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
String title = "Servlet Session";
Integer visitCount = new Integer(0);
String visitCountkey = new String("visitCount");
String userIDKey = new String("userID");
String userID = new String("Runoob");
//检查网页是否有新的访问者
if (session.isNew()) {
title = "Servlet Session";
session.setAttribute(userIDKey, userID);
} else {
visitCount = (Integer) session.getAttribute(visitCountkey);
visitCount = visitCount + 1;
userID = (String) session.getAttribute(userIDKey);
}
session.setAttribute(visitCountkey, visitCount);
//设置响应内容类型
response.setContentType("text/html;charset=UTF-8");
PrintWriter out = response.getWriter();
String docType = "<!DOCTYPE html>\n";
out.println(docType +
"<html>\n" +
"<head><title>" + title + "</title></head>\n" +
"<body bgcolor=\"#f0f0f0\">\n" +
"<h1 align=\"center\">" + title + "</h1>\n" +
"<h2 align=\"center\">Session 信息</h2>\n" +
"<table border=\"1\" align=\"center\">\n" +
"<tr bgcolor=\"#949494\">\n" +
" <th>Session 信息</th><th>值</th></tr>\n" +
"<tr>\n" +
" <td>id</td>\n" +
" <td>" + session.getId() + "</td></tr>\n" +
"<tr>\n" +
" <td>创建时间</td>\n" +
" <td>" + df.format(createTime) +
" </td></tr>\n" +
"<tr>\n" +
" <td>最后访问时间</td>\n" +
" <td>" + df.format(lastAccessTime) +
" </td></tr>\n" +
"<tr>\n" +
" <td>用户 ID</td>\n" +
" <td>" + userID +
" </td></tr>\n" +
"<tr>\n" +
" <td>访问统计:</td>\n" +
" <td>" + visitCount + "</td></tr>\n" +
"</table>\n" +
"</body></html>");
}
}
##Servlet Context监听器
ServletContext,是一个全局的储存信息的空间,服务器开始,其就存在,服务器关闭,其才释放。request,一个用户可有多个;session,一个用户一个;而servletContext,所有用户共用一个。所以,为了节省空间,提高效率,ServletContext中,要放必须的、重要的、所有用户需要共享的线程又是安全的一些信息
ServletContext的监听器接口有两个:ServletContextListener和ServletContextAttributeListener
(1)ServletContextListener
ServletContextListener能对ServletContext的创建和销毁做出响应
/*
*
*/
@WebListener
public class AppListener implements ServletContextListener {
//销毁ServletContext时调用
@Override
public void contextDestroyed(ServletContextEvent arg0) {
// TODO Auto-generated method stub
}
//创建ServletContext时调用
@Override
public void contextInitialized(ServletContextEvent ace) {
ServletContext ServletContext = ace.getServletContext();
Map<String, String> countries = new HashMap<String, String>();
countries.put("ca", "Canada");
countries.put("us", "United States");
//设置ServletContext属性
ServletContext.setAttribute("countries", countries);
}
}
注意要添加jstl包
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>
<html>
<head>
<title>Country List</title>
</head>
<body>
<c:forEach items="${countries}" var="country">
<li>${country.value}</li>
</c:forEach>
</body>
</html>
(2)ServletContextAttributeListener
//实现这个接口会收到web 应用中的servlet context属性链修改的通知
public interface ServletContextAttributeListener extends EventListener {
/** Notification that a new attribute was added to the servlet context. Called after the attribute is added.*/
//一个属性被添加给servlet context之前会通知
public void attributeAdded(ServletContextAttributeEvent scab);
/** Notification that an existing attribute has been removed from the servlet context. Called after the attribute is removed.*/
//属性被删除之后通知
public void attributeRemoved(ServletContextAttributeEvent scab);
/** Notification that an attribute on the servlet context has been replaced. Called after the attribute is replaced. */
//属性被替换后通知
public void attributeReplaced(ServletContextAttributeEvent scab);
}
##Session Listener
(1)HttpSessionListener
同样销毁和创建时会调用它两个方法sessionDestroyed()、sessionCreated()
@WebListener
public class SessionListener implements HttpSessionListener,ServletContextListener{
@Override
public void sessionCreated(HttpSessionEvent se) {
HttpSession session=se.getSession();
ServletContext servletContext=session.getServletContext();
AtomicInteger userCounter=(AtomicInteger) servletContext.getAttribute("userCounter");
int userCount=userCounter.incrementAndGet();
System.out.println("userCount incremented to :"+userCount);
}
@Override
public void sessionDestroyed(HttpSessionEvent se) {
HttpSession session=se.getSession();
ServletContext servletContext=session.getServletContext();
AtomicInteger userCounter=(AtomicInteger) servletContext.getAttribute("userCounter");
int userCount=userCounter.decrementAndGet();
System.out.println("--------userCount decremented to:"+userCount);
}
@Override
public void contextDestroyed(ServletContextEvent se) {
}
@Override
public void contextInitialized(ServletContextEvent arg0) {
ServletContext servletContext=arg0.getServletContext();
servletContext.setAttribute("userCounter", new AtomicInteger());
}
}
这个监听器用来统计HttpSession的数量,也就不同浏览器访问的个数,它使用AtomicInteger对象来统计,并且将这个对象保存成ServletContext范围的属性,每当有个HttpSession被创建,这个AtomicInteger对象就加一,每当有个HttpSession被销毁,这个AtomicInteger对象就减一,使用AtomicInteger是为了保证同步进行加减
访问http://jyx:8080/ServletDemo/countries.jsp效果
注意不同的浏览器访问才加1
**(2)HttpSessionBindingListener **
当有属性绑定或者解绑定到HttpSession时,这个监听器就会被调用
public class Product implements HttpSessionBindingListener {
private String id;
private String name;
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public double getPrice() {
return price;
}
public void setPrice(double price) {
this.price = price;
}
private double price;
@Override
public void valueBound(HttpSessionBindingEvent event) {
String attributeName = event.getName();
System.out.println(attributeName + " valueBound");
}
@Override
public void valueUnbound(HttpSessionBindingEvent event) {
String attributeName = event.getName();
System.out.println(attributeName + " valueUnBound");
}
}
##ServletRequest Listener
ServletRequestListener会监听ServletRequest 的创建和销毁
public class PerfStatListener implements ServletRequestListener{
@Override
public void requestDestroyed(ServletRequestEvent arg0) {
ServletRequest servletRequest=arg0.getServletRequest();
Long start=(Long) servletRequest.getAttribute("start");
Long end=System.nanoTime();
//将servletRequest强制转换为HttpServletRequest
HttpServletRequest httpServletRequest=(HttpServletRequest) servletRequest;
String uri=httpServletRequest.getRequestURI();
System.out.println("time taken to execute "+uri+
":"+((end-start)/1000)+"micoseconds");
}
@Override
public void requestInitialized(ServletRequestEvent arg0) {
ServletRequest servletRequest=arg0.getServletRequest();
//java中System.nanoTime()返回的是纳秒
servletRequest.setAttribute("start", System.nanoTime());
}
}
总结
这些监听器分为三类:application范围、session范围和request范围,可以通过两种方法注册监听器,在实现类使用@WebListener注解或者在部署描述文件中增加listener元素