servlet 实践
基础
当Servlet引擎收到一个请求,它将请求所有的细节汇编到一个HttpServletRequest对象。细节包括请求头部、URI、查询字符串和任意发送的参数等等。类似地,它初始化一个处理响应头部和响应输出流的HttpServletResponse对象,然后调用Servlet的service()方法(如果servlet是一个JSP,则为_jspService()方法),向其传递两个对象的引用。
ServletRequest对象被Servlet引擎创建.充做客户端和请求信息的包容器。它包含远程系统的标识、请求参数和与请求相关的任意输人流。类似地,ServletResponse对象向Servlet提供与其返回到初始请求器的结果进行进信的方式。它包含打开一个输出流的方法和指定内容类型和长度的方法。
只有通过注册名来访问Servlet才能取到在web.xml中设置的Servlet初始化参数,在浏览直接使用servlet/….+Servlet类名来访问Servlet是取不到的。
在发送任何文档内容到客户机之前,应该设置状态代码。必须在PrintWriter实际返回任何内容之前设置响应头。
Servlet必须实现Servlet接口,大多数Servlet通过继承GenericServlet或者HttpServlet来实现这个接口。GenericServlet的子类必须实现service()方法;HttpServlet的service()方法负责所有的doXxx()方法的调用。HttpServlet的子类只需要实现doXxx()方法。
避免使用SingelThreadModel接口。大多数使用SingelThreadModel的Servlet都可以采用同步方法或扩展资源池来更好的实现。
POST数据只能被读一次。如果POST数据已经被getReader()或者getInputStream()方法读过了,则这些信息不能被再次读取。
URL映射
|
说明 |
明确映射 |
不包括通配符 例如:/hello.html |
路径前缀映射 |
以/开头以*结尾 例如:/lite/* |
扩展名映射 |
以*开头 例如:*.jsp |
默认映射 |
/ 如果没有其它的Servlet可以匹配URL,则使用该Servlet |
共享信息
请求作用域是javax.servlet.http.HttpServletRequest的各个属性的一种抽象,从Servlet中的request参数代表该作用域;jsp中的request内置对象代表该作用域。
会话作用域是javax.servlet.http.HttpSession的各个属性的一种抽象,从Servlet中调用的request.getSession()方法得到该作用域;jsp中的session对象代表该作用域。
应用程序作用域是javax.servlet.ServletContext的各个属性的一种抽象,从Servlet中调用getServletConfig().getServletContext()方法得到该作用域(getServletConfig().有时候可以省略);Jsp中的application内置对象代表该作用域。
这三个类都提供了 setAttribute() ;getAttribute() ;removeAttribute() 方法。
会话追踪
cookie是Web服务器发送到浏览器的少量文本信息,该浏览器稍后再访问相同的站点或域时原样不动的返回这些信息。通过让服务器读取它以前发送到浏览器的信息,服务器可以向访问者提供许多方便。
设置cookie
Cookie userCookie = new Cookie("name", "huxiaogang"); userCookie.setMaxAge(60*60*24*365); // 1年 response.addCookie(userCookie);
注意:Cookie的名和Cookie的值都不应该包含空格和以下的字符: [ ] ( ) = , " / ? @ : ; |
读取cookie
对HttpServletRequest调用getCookies()方法,将返回Cookie对象的一个数组,如果此请求未包含Cookie,则返回null。
Cookie[] cookies = request.getCookies(); if(cookies == null){ ...... }else{ Cookie cookie; for(int i = 0; i < cookies.length; i++){ cookie = cookies[i]; out.println(cookie.getName() + cookie.getValue()); } } |
会话跟踪机制
使用cookie
Servlet引擎管理着一个会话表,每一个会话使用一个唯一的字符串(会话关键字)来进行识别。要根据一个请求来建立一个新的会话,就要建立一个HttpSession对象和一个会话关键字并存储在会话表中。用响应信息将会话关键字发送给客户,客户在将其和进一步的请求一起发回,这样服务器就可以识别客户重新找到与客户关联的HttpSession对象了。
一旦服务器端准备开始跟踪会话,服务器端的Servlet会调用getSession(),这会导致在HTTP响应中包含一个会话Cookie:
HTTP/1.0 200 OK
Set-Cookie: SessionKey="12345"; Version="1"
会话关键字也会包含在窗口的ACTION URL中,因为服务器不知道客户是否会接受这个Cookie。我们假设客户接受了Cookie并且正确登陆,那么客户发送的这个请求中会包含会话关键字两次:
POST /servlet/Login$SessionKey=12345 HTTP/1.0
Cookie: $Version="1"; SessionKey="12345"
现在服务器知道客户接受了Cookie,服务器不会在URL中编码会话关键字了,也不会发送Set-Cookie头了。客户以后发送的请求中都回包含同一个会话关键字:
GET /servlet/OtherServlet HTTP/1.0
Cookie: $Version="1" ; SessionKey="12345"
当客户要退出会话,服务器调用HttpSession对象的invalideate()方法来删除这个会话后:
HTTP/1.0 200 OK
Set-Cookie: SessionKey=""; Version="1"; Max-Age=0
那么客户再发出的请求中都不会再包含会话关键字,这样就成为了无状态的了。
如果会话超时,那么服务器端保存的会话对象会失效,即使客户依然像以前一样在请求中包含Cookie信息:
GET /servlet/OtherFourServlet HTTP/1.0
Cookie: $Version="1" ; SessionKey="12345"
该请求也不再作为会话的一部分来考虑了。依然成为无状态的了。
使用URL重写
客户机将额外的数据附加到标识该会话的每个URL之后,且服务器把该标识符与关于会话所存储的数据相关联。
String originalURL = someURL;
String encodedURL = response.encodeURL(originalURL);
out.println("<A HREF = \""+endodedURL+"\">...</A>");
String originalURL = someURL;
String encodedURL = response.encodeRedirectURL(originalURL);
response.sendRedirect(encodedURL);
使用隐藏域
如果应用由一系列使用Submit按钮进行导航的Html窗体组成,会话ID可被存储为一隐藏域,并通过request.getParameter()进行检索。显然,只有窗体均为动态生成的时候,此方法才有效。如果要进行会话跟踪,窗体就必须由类似CGI、Servlet或Jsp服务器进程创建的动态生成的Web页面
线程概念
Web服务器本身就是使用线程的例子,一个简单的Web服务器操作如下:
1)创建一个ServerSocket,调用其accept()方法等待HTTP客户端请求。
2)取得accept()方法返回的客户端Socket对象,启动一个单独的线程处理其请求。
3)返回到步骤1,在上—请求正被其他线程处理的同时接受更多的请求。
(注:以上转载出处不明)
Servlet 的生命周期
(1) 加载和实例化
Servlet 容器装载和实例化一个 Servlet。创建出该 Servlet 类的一个实例。
(2) 初始化
在 Servlet 实例化完成之后,容器负责调用该 Servlet 实例的 init() 方法,在处理用户请求之前,来做一些额外的初始化工作。
(3) 处理请求
当 Servlet 容器接收到一个 Servlet 请求时,便运行与之对应的 Servlet 实例的 service() 方法,service() 方法再派遣运行与请求相对应的
doXX(doGet,doPost) 方法来处理用户请求。
(4) 销毁
当 Servlet 容器决定将一个 Servlet 从服务器中移除时 ( 如 Servlet 文件被更新 ),便调用该 Servlet 实例的 destroy() 方法,在销毁该 Servlet 实例之前,
来做一些其他的工作。
其中,(1)(2)(4) 在 Servlet 的整个生命周期中只会被执行一次。
(转载JSP/Servlet 工作原理)http://www.blogjava.net/fancydeepin/archive/2013/09/30/fan_servlet.html
Servlet 实例
//HelloWorldServlet .java
1 package com.lewis.servlet; 2 3 import javax.servlet.http.HttpServlet; 4 import javax.servlet.http.HttpServletRequest; 5 import javax.servlet.http.HttpServletResponse; 6 import javax.servlet.ServletConfig; 7 import javax.servlet.ServletException; 8 9 import java.io.IOException; 10 import java.io.PrintWriter; 11 12 public class HelloWorldServlet extends HttpServlet { 13 public void doGet(HttpServletRequest request, HttpServletResponse response) 14 throws ServletException, IOException { 15 16 //取一个参数的值1 17 ServletConfig config = getServletConfig(); 18 String value1 = config.getInitParameter("parameter1"); 19 20 response.setContentType("text/html; charset=utf-8"); 21 22 PrintWriter out = response.getWriter(); 23 24 out.println("<html>"); 25 out.println("<head>"); 26 out.println("<title>SimpleServlet</title>"); 27 out.println("</head>"); 28 out.println("<body>"); 29 out.println("<p>Hello, World!</p>"); 30 out.println("<p>Hello, this is my first servlet!</p>"); 31 out.println("<p>parameter: "+value1+"</p>"); 32 out.println("</body>"); 33 out.println("</html>"); 34 } 35 }
备注:response.setContentType(MIME) (http://blog.sina.com.cn/s/blog_a03d702f010143tw.html)
//web.xml
1 <?xml version="1.0" encoding="UTF-8"?> 2 <web-app version="3.0" 3 xmlns="http://java.sun.com/xml/ns/javaee" 4 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 5 xsi:schemaLocation="http://java.sun.com/xml/ns/javaee 6 http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"> 7 <display-name></display-name> 8 <welcome-file-list> 9 <welcome-file>index.jsp</welcome-file> 10 </welcome-file-list> 11 <display-name>My Web Application</display-name> 12 <servlet> 13 <servlet-name>helloWorldServlet</servlet-name> 14 <servlet-class>com.lewis.servlet.HelloWorldServlet</servlet-class> 15 <init-param> 16 <param-name>parameter1</param-name> 17 <param-value>First Parameter Value</param-value> 18 </init-param><!-- --> 19 </servlet> 20 <servlet-mapping> 21 <servlet-name>helloWorldServlet</servlet-name> 22 <url-pattern>/hello</url-pattern> 23 </servlet-mapping> 24 <description> 25 A application for test. 26 </description> 27 </web-app>