Servlet学习
来源:互联网 发布:kanahei知乎 编辑:程序博客网 时间:2024/06/10 04:45
一.Servlet概述
1.1 什么是Servlet
- Java servlet 是运行在 Web 或应用服务器上的程序,作为在来自 Web 浏览器或其他 HTTP 客户机的请求和在HTTP 服务器上的数据库或应用程序的中间层。
- Java Servlet 是运行在 Web 服务器上的 Java 类,在 Web 服务器上有一个支持 Java Servlet 规范的解释器。
- Servlet 可以使用 javax.servlet 和 javax.servlet.http 包来创建。它们是 Java 企业版的一个标准部分,也是支持大型开发项目的 Java 类库的扩展版。
- 就像任何其他 Java 类一样,Java Servlet 可以创建和编译。可以使用 JDK 的 Java 编译器或其他任何当前编译器来编译 Servlet。
1.2 Servlet架构
1.3 Servlet任务
1.3.1 处理前
- 读取由客户端(浏览器)发送的显式数据。这包括网页上的 HTML 表单,或者也可以是来自自定义的 HTTP 客户端程序的表单。
- 读取由客户端(浏览器)发送的隐式 HTTP 请求数据。这包括 cookies、媒体类型和浏览器能理解的压缩格式等等。
1.3.2 处理时
- 处理数据并生成结果。这个过程可能需要访问数据库,执行 RMI 或 CORBA 调用,调用 Web 服务,或者直接计算响应
1.3.3 处理后
- 发送显式数据(即文档)到客户端(浏览器)。该文档可以以多种多样的格式被发送,包括文本文件(HTML 或 XML)、二进制文件(GIF 图像)、Excel 等
- 发送隐式的 HTTP 响应到客户端(浏览器)。这包括告诉浏览器或其他客户端被返回的文档类型(例如 HTML),设置 cookies 和缓存参数,以及其他类似的任务
二.Servlet生命周期
Servlet 生命周期可被定义为从创建直到毁灭的整个过程。以下是 Servlet 遵循的过程:
- 初始化阶段 - 调用init()方法
- 响应客户请求阶段 - 调用service()方法
- 终止阶段 - 调用destroy()方法
2.1 init()
init ()方法被设计成只调用一次。它在第一次创建 servlet 时被调用,在后续每次用户请求时不再调用。因此,它用于一次性初始化
2.1.1 何时初始化
有两种情况Servlet容器会加载Servlet实现类,该Servlet类的无参构造函数运行,初始化该Servlet
- 当用户第一次调用对应于该 servlet 的 URL 时,servlet 被创建
- 在web.xml中配置该Servlet的<load-on-startup>属性,Servlet容器启动时加载该Servlet,<load-on-startup>1</load-on-startup>表示servlet容器启动时就加载该servlet
2.1.2 何时调用
- 在第一次创建 Servlet 实例时被调用,在后续每次用户请求时不再调用。
- 该servlet实例创建后,并在该Servlet实例能为客户请求提供服务之前,servlet容器要对servlet调用init().
- 可以重写javax.servlet.GenericServlet.java中的init()方法,添加一些自定义初始化代码。
2.2.1 调用次数
- init ()方法只能调用一次,它在第一次创建 servlet 时被调用
2.1.4 为什么只有一个init()
构造函数难道不足以初始化servlet吗?在init()方法中会放什么代码?
- 其实构造函数只是使servlet实现类成为一个普通的对象,而不是一个servlet,要想成为一个servlet,对象必须具备一些"servlett特性"。如能够记录事件日志、得到其他资源的引用、保存其他servlet的属性、能够使用ServletContext引用从容器得到信息等
- init()方法使servlet可以访问ServletConfig和ServletContext对象,servlet需要从这些对象获取servlet配置和web应用的信息
2.2 service()
service() 方法是执行实际任务的主要方法。Servlet 容器(即 web 服务器)调用 service() 方法来处理来自客户端(浏览器)的请求,并将格式化的响应写回到客户端
2.2.1 何时调用
- 每次服务器接收到一个 servlet 请求时,服务器会创建一个新的线程,或从线程池分配一个线程,生成一对新的请求对象ServletRequest和响应对象ServletResponse
- 调用该servlet的service(ServletRequest,ServletResponse)方法,参数为容器创建的请求和响应对象。
- service方法从ServletRequest对象获得客户请求信息
- service() 方法检查 HTTP 请求类型(GET、POST、PUT、DELETE 等),并在适当的时候调用 doGet、doPost、doPut、doDelete 等方法 ,处理该请求
- 通过ServletResponse对象向客户返回响应信息
2.2.2 调用次数
- 每次服务器接收到一个 servlet 请求时,服务器会产生一个新的线程并调用服务
2.2.3 需要重写吗
- service() 方法由servlet容器调用,且 service 方法在适当的时候调用 doGet、doPost、doPut、doDelete 等。所以对 service() 方法你什么都不需要做
- 只是根据接收到的来自客户端的请求类型来重写 doGet() 或 doPost()
public void service(ServletRequest req, ServletResponse res) throws ServletException, IOException { HttpServletRequest request; HttpServletResponse response; try { request = (HttpServletRequest)req; response = (HttpServletResponse)res; } catch (ClassCastException e) { throw new ServletException("non-HTTP request or response"); } service(request, response); } protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { String method = req.getMethod(); if (method.equals("GET")) { long lastModified = getLastModified(req); if (lastModified == -1L) { doGet(req, resp); } else { long ifModifiedSince = req.getDateHeader("If-Modified-Since"); if (ifModifiedSince < lastModified / 1000L * 1000L) { maybeSetLastModified(resp, lastModified); doGet(req, resp); } else { resp.setStatus(304); } } } else if (method.equals("HEAD")) { long lastModified = getLastModified(req); maybeSetLastModified(resp, lastModified); doHead(req, resp); } else if (method.equals("POST")) { doPost(req, resp); } else if (method.equals("PUT")) { doPut(req, resp); } else if (method.equals("DELETE")) { doDelete(req, resp); } else if (method.equals("OPTIONS")) { doOptions(req, resp); } else if (method.equals("TRACE")) { doTrace(req, resp); } else { String errMsg = lStrings.getString("http.method_not_implemented"); Object[] errArgs = new Object[1]; errArgs[0] = method; errMsg = MessageFormat.format(errMsg, errArgs); resp.sendError(501, errMsg); } }
2.3 destroy()
destroy() 方法只在 servlet 生命周期结束时被调用一次 ,在调用 destroy() 方法之后,servlet 对象被标记用于垃圾回收
2.3.1 何时调用
- 当WEB应用被终止
- 或Servlet容器终止运行
- 或Servlet容器重新装载Servlet新实例时
2.3.2 调用次数
- destroy() 方法只在 servlet 生命周期结束时被调用一次
2.3.3 调用目的
调用Servlet的destroy()方法,在destroy()方法中可以释放掉Servlet所占用的资源
- 关闭数据库连接
- 停止后台线程
- 将 cookie 列表或点击计数器写入磁盘,并执行其他类似的清理活动
三.创建Servlet实例
直接实现servlet接口来编写Servlet很不方便,需要实现的方法太多,在JDK中javax.servlet.*,javax.servlet.http.*包下提供了对servlet的支持。
编写Servlet时直接继承HttpServlet,并覆盖需要的方法即可,一般覆盖doGet()和doPost()方法
package com.study.servlet; import java.io.IOException; import javax.servlet.ServletException; import javax.servlet.http.Cookie; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; /** * 一个Servlet实现类 */ public class TestServlet extends HttpServlet { private static final long serialVersionUID = 1L; public TestServlet() { super(); } /** * 以get方式访问页面时执行此方法 */ protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { response.sendRedirect("test.jsp"); } /** * 以get方式访问页面时执行此方法 */ protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { doGet(request, response); } }
四.Servlet配置
光有Servlet类还不行,web容器必须知道浏览器怎么访问这个Servlet,也就是需要在web.xml配置Servlet的类文件与访问方式
<servlet> <description>Servlet配置</description> <display-name>TestServlet</display-name> <servlet-name>TestServlet</servlet-name> <servlet-class>com.study.servlet.TestServlet</servlet-class> <init-param> <description>编码</description> <param-name>encoding</param-name> <param-value>utf-8</param-value> </init-param> </servlet> <servlet-mapping> <servlet-name>TestServlet</servlet-name> <url-pattern>/test.do</url-pattern> </servlet-mapping>
4.1 <servlet>标签
4.1.1 <display-name>
- 必需标签
- 可以任意取字符串值,但必须保证该名称在web.xml中唯一,该名称供其它的标签使用:<servlet-mapping>、<filter>等
4.1.2 <serlet-name>
- servlet实现类的完整路径:com.study.servlet.TestServlet
- 通过类路径找到对应的servlet类文件
4.1.3 可选标签
- <init-param> : 配置一个初始化的参数,包括一个参数名称(<param-name>)和一个参数值(<param-value>)
- Servlet中使用getServletContext().getInitParam(String paramName)方法来获取配置的初始化参数。
- <load-on-startup> : 配置该servlet的加载方式。可选值为0和1.
- 如果配置为1,tomcat会在启动时就加载该servlet
- 如果配置为0,tomcat会在第一次请求该servlet时才加载该servlet
- Spring、Struts等框架中会使用该参数来预加载框架中核心的Servlet
4.2 <servlet-mapping>标签
配置好<servlet>后还需要配置<servlet-mapping>,即配置该Servlet的访问方式,访问方式使用<servlet-mapping>配置,
4.2.1 <servlet-name>
跟<servlet>中的<servlet-name>对应,指明采用该访问方式的Servlet的名称
4.2.2 <servlet-mapping>
以"/"开头,"/"表示上下文路径,如:
<servlet-mapping> <servlet-name>TestServlet</servlet-name> <url-pattern>/test.do</url-pattern> </servlet-mapping>
- <url-pattern>中允许使用通配符"*"、“?”,“*”表示任意长度的字符串。
- 从JDK 5起,<servlet-mapping>中可以配置多个<url-pattern>,如
<servlet-mapping> <servlet-name>TestServlet</servlet-name> <url-pattern>/test.do</url-pattern> <url-pattern>/test.html</url-pattern> <url-pattern>/test.jsp</url-pattern> <url-pattern>/test.php</url-pattern> <url-pattern>/test.asp</url-pattern> </servlet-mapping>
这可以实现隐藏编程语言的母的,客户无法从url上知道该程序是用php或asp或其他语言写的。
五.访问
5.1 创建界面
test.jsp:
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%> <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> <title>欢迎</title> </head> <body> Hello World! </body> </html>
5.2 创建Servlet
5.3 访问路径
http://localhost:8080/servlet2/test.do
六.Servlet类结构
6.1 类结构
6.2 Servlet接口
package javax.servlet;import java.io.IOException;public abstract interface Servlet {/** * 仅执行一次 */public abstract void init(ServletConfig paramServletConfig) throws ServletException;public abstract ServletConfig getServletConfig();/** * 每次请求容器都会创建一个线程,调用service() */public abstract void service(ServletRequest paramServletRequest, ServletResponse paramServletResponse) throws ServletException, IOException;public abstract String getServletInfo();/** * 结束servlet生命 */public abstract void destroy();}/* Location: D:\...\apache-tomcat-6.0.20\lib\servlet-api.jar * Qualified Name: javax.servlet.Servlet * Java Class Version: 5 (49.0) * JD-Core Version: 0.5.3 */
6.3 GenericServlet抽象类
package javax.servlet; import java.io.IOException;import java.io.Serializable;import java.util.Enumeration; public abstract class GenericServlet implements Servlet, ServletConfig, Serializable {// servlet配置对象private transient ServletConfig config;// 仅调用一次public void init(ServletConfig config) throws ServletException {this.config = config;init();} // 可以被重写,执行一些初始化代码public void init() throws ServletException {}// 每次请求到来,容器创建一个线程,调用此方法 public abstract void service(ServletRequest paramServletRequest, ServletResponse paramServletResponse) throws ServletException, IOException;public void destroy() {} /** * 根据name获取servlet在web.xml中初始化配置属性 */public String getInitParameter(String name) {return getServletConfig().getInitParameter(name);} public Enumeration getInitParameterNames() {return getServletConfig().getInitParameterNames();} public ServletConfig getServletConfig() {return this.config;} /** * 获取servlet容器上下文对象 */public ServletContext getServletContext() {return getServletConfig().getServletContext();} public String getServletInfo() {return ;} public void log(String msg) {getServletContext().log(getServletName() + ": " + msg);} public void log(String message, Throwable t) {getServletContext().log(getServletName() + ": " + message, t);} public String getServletName() {return this.config.getServletName();}}/* Location: D:\.....\apache-tomcat-6.0.20\lib\servlet-api.jar * Qualified Name: javax.servlet.GenericServlet * Java Class Version: 5 (49.0) * JD-Core Version: 0.5.3 */
6.4 HttpServlet抽象类
package javax.servlet.http;import java.io.IOException;import java.io.Serializable;import java.lang.reflect.Method;import java.text.MessageFormat;import java.util.Enumeration;import java.util.ResourceBundle;import javax.servlet.GenericServlet;import javax.servlet.ServletException;import javax.servlet.ServletOutputStream;import javax.servlet.ServletRequest;import javax.servlet.ServletResponse;/** * 一般Servlet实现类继承此类,重写doGet()和doPost()方法 */public abstract class HttpServlet extends GenericServlet implements Serializable {private static final String METHOD_DELETE = "DELETE";private static final String METHOD_HEAD = "HEAD";private static final String METHOD_GET = "GET"; // get方法private static final String METHOD_OPTIONS = "OPTIONS";private static final String METHOD_POST = "POST"; // post方法private static final String METHOD_PUT = "PUT";private static final String METHOD_TRACE = "TRACE";private static final String HEADER_IFMODSINCE = "If-Modified-Since";private static final String HEADER_LASTMOD = "Last-Modified";private static final String LSTRING_FILE = "javax.servlet.http.LocalStrings";private static ResourceBundle lStrings = ResourceBundle.getBundle("javax.servlet.http.LocalStrings");// 每次请求,容器创建一个线程,调用此方法public void service(ServletRequest req, ServletResponse res) throws ServletException, IOException {HttpServletRequest request;HttpServletResponse response;try {request = (HttpServletRequest)req;response = (HttpServletResponse)res;} catch (ClassCastException e) {throw new ServletException("non-HTTP request or response");}service(request, response);}// 不应该重写此方法,根据method调用对应方法protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {String method = req.getMethod();if (method.equals("GET")) {// 获取上次请求时间long lastModified = getLastModified(req);if (lastModified == -1L) {// 为负表示再次请求该页面,更新doGet(req, resp);} else {// 从请求头中获取long ifModifiedSince = req.getDateHeader("If-Modified-Since");if (ifModifiedSince < lastModified / 1000L * 1000L) {maybeSetLastModified(resp, lastModified);doGet(req, resp);} else {// 不更新页面,返回状态码304resp.setStatus(304);}}} else if (method.equals("HEAD")) {long lastModified = getLastModified(req);maybeSetLastModified(resp, lastModified);doHead(req, resp);} else if (method.equals("POST")) {doPost(req, resp);} else if (method.equals("PUT")) {doPut(req, resp);} else if (method.equals("DELETE")) {doDelete(req, resp);} else if (method.equals("OPTIONS")) {doOptions(req, resp);} else if (method.equals("TRACE")) {doTrace(req, resp);} else {String errMsg = lStrings.getString("http.method_not_implemented");Object[] errArgs = new Object[1];errArgs[0] = method;errMsg = MessageFormat.format(errMsg, errArgs);resp.sendError(501, errMsg);}}protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {String protocol = req.getProtocol();String msg = lStrings.getString("http.method_post_not_supported");if (protocol.endsWith("1.1"))resp.sendError(405, msg);elseresp.sendError(400, msg);}protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {String protocol = req.getProtocol();String msg = lStrings.getString("http.method_get_not_supported");if (protocol.endsWith("1.1"))resp.sendError(405, msg);elseresp.sendError(400, msg);}/** * 一般情况下,浏览器都会缓存已经访问过的页面内容,getLastModified方法的返回值可以影响浏览器如何处理和利用缓存内容 * 可以重写此方法 * 返回值为负表示再次请求该页面 */protected long getLastModified(HttpServletRequest req) {return -1L;}protected void doHead(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {NoBodyResponse response = new NoBodyResponse(resp);doGet(req, response);response.setContentLength();}protected void doPut(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {String protocol = req.getProtocol();String msg = lStrings.getString("http.method_put_not_supported");if (protocol.endsWith("1.1"))resp.sendError(405, msg);elseresp.sendError(400, msg);}protected void doDelete(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {String protocol = req.getProtocol();String msg = lStrings.getString("http.method_delete_not_supported");if (protocol.endsWith("1.1"))resp.sendError(405, msg);elseresp.sendError(400, msg);}private static Method[] getAllDeclaredMethods(Class c) {if (c.equals(HttpServlet.class)) {return null;}Method[] parentMethods = getAllDeclaredMethods(c.getSuperclass());Method[] thisMethods = c.getDeclaredMethods();if ((parentMethods != null) && (parentMethods.length > 0)) {Method[] allMethods = new Method[parentMethods.length + thisMethods.length];System.arraycopy(parentMethods, 0, allMethods, 0, parentMethods.length);System.arraycopy(thisMethods, 0, allMethods, parentMethods.length, thisMethods.length);thisMethods = allMethods;}return thisMethods;}protected void doOptions(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {Method[] methods = getAllDeclaredMethods(super.getClass());boolean ALLOW_GET = false;boolean ALLOW_HEAD = false;boolean ALLOW_POST = false;boolean ALLOW_PUT = false;boolean ALLOW_DELETE = false;boolean ALLOW_TRACE = true;boolean ALLOW_OPTIONS = true;for (int i = 0; i < methods.length; ++i) {Method m = methods[i];if (m.getName().equals("doGet")) {ALLOW_GET = true;ALLOW_HEAD = true;}if (m.getName().equals("doPost"))ALLOW_POST = true;if (m.getName().equals("doPut"))ALLOW_PUT = true;if (m.getName().equals("doDelete")) {ALLOW_DELETE = true;}}String allow = null;if ((ALLOW_GET) && (allow == null)) allow = "GET";if (ALLOW_HEAD)if (allow == null) allow = "HEAD";else allow = allow + ", HEAD";if (ALLOW_POST)if (allow == null) allow = "POST";else allow = allow + ", POST";if (ALLOW_PUT)if (allow == null) allow = "PUT";else allow = allow + ", PUT";if (ALLOW_DELETE)if (allow == null) allow = "DELETE";else allow = allow + ", DELETE";if (ALLOW_TRACE)if (allow == null) allow = "TRACE";else allow = allow + ", TRACE";if (ALLOW_OPTIONS) {if (allow == null) allow = "OPTIONS";else allow = allow + ", OPTIONS";}resp.setHeader("Allow", allow);}protected void doTrace(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {String CRLF = "\r\n";String responseString = "TRACE " + req.getRequestURI() + " " + req.getProtocol();Enumeration reqHeaderEnum = req.getHeaderNames();while (reqHeaderEnum.hasMoreElements()) {String headerName = (String)reqHeaderEnum.nextElement();responseString = responseString + CRLF + headerName + ": " + req.getHeader(headerName);}responseString = responseString + CRLF;int responseLength = responseString.length();resp.setContentType("message/http");resp.setContentLength(responseLength);ServletOutputStream out = resp.getOutputStream();out.print(responseString);out.close();}private void maybeSetLastModified(HttpServletResponse resp, long lastModified) {if (resp.containsHeader("Last-Modified"))return;if (lastModified >= 0L)resp.setDateHeader("Last-Modified", lastModified);}}/* Location: D:\...\apache-tomcat-6.0.20\lib\servlet-api.jar * Qualified Name: javax.servlet.http.HttpServlet * Java Class Version: 5 (49.0) * JD-Core Version: 0.5.3 */
阅读全文
0 0
- servlet学习
- Servlet学习
- Servlet学习
- Servlet学习
- Servlet学习
- servlet学习
- Servlet学习
- servlet 学习
- servlet学习
- Servlet学习
- 学习servlet
- Servlet学习
- servlet学习
- Servlet学习
- Servlet学习
- Servlet学习
- Servlet学习
- Servlet学习
- 错误小计
- Android控件postDelayed用法,View自带的定时器
- linux系统查看日志的几种方法
- 搜索 问题 D: 神奇密码锁
- CodeForces
- Servlet学习
- 简单算法整理
- XA协议
- 链表
- idea部署tomcat启动成功后访问一直提示404
- SQL逆向工程生成代码 2种方法可以根据Id 取到 Item对象
- C++中的 菱形继承
- L1-015. 跟奥巴马一起画方块
- 基于集群的单点登录(SSO)系统设计