Java Servlet 技术是Java体系中用于开发 Web 应用的底层技术。
Servlet 是运行在 Servlet 容器(如 Tomcat)中的Java程序,而 Servlet 容器或 Servlet 引擎至关于一个 Web 服务器,可是能够产生动态内容,而不只是静态资源。一个 Servlet 是一个 Java 程序,一个 Servlet 应用包含了一个或多个 Servlet,一个 JSP 页面会被翻译并编译成一个 Servlet。
Servlet 应用运行在一个 Servlet 容器中,它没法独立运行。Servlet 容器未来自用户的请求传递给 Servlet 应用,并将 Servlet 应用的响应返回给用户。html
Servlet API 有如下4个Java包:java
Servlet 技术的核心是 Servlet,它是全部 Servlet 类必须直接或间接实现的一个接口。
Servlet 接口定义了Servlet 与 Servlet 容器之间的契约。这个契约归结起来就是,Servlet 容器将 Servlet 类载入内存,并在 Servlet 实例上调用具体的方法。在一个应用程序中,每种 Servlet 类型只能有一个实例。web
用户请求导致 Servlet 容器调用 Servlet 的 service 方法,并传入一个 ServletRequest 实例和一个 ServletResponse 实例。ServletRequest 中封装了当前的HTTP请求,ServletResponse 表示当前用户的HTTP响应。
对于每个应用程序,Servlet 容器还会建立一个 ServletContext 实例。这个对象中封装了上下文(应用程序)的环境详情。每一个上下文只有一个 ServletContext。每一个 Servlet 实例也都有一个封装 Servlet 配置的 ServletConfig。apache
Servlet 接口中定义了如下5个方法:数组
public void init (ServletConfig config) throws ServletException; public ServletConfig getServletConfig(); public void service (ServletRequest req, ServletResponse res) throws ServletException, IOException; public String getServletInfo(); public void destroy();
3个 Servlet 生命周期方法:浏览器
2个非生命周期方法:tomcat
在 eclipse EE + Tomcat 环境下编写一个简单的 Servlet 实例服务器
1. 下载 Tomcat
下载完成后解压压缩包,参考文件夹下的`RUNNIG.txt`配置环境变量。
其中`"CATALINA_HOME"`是必选项,指向 Tomcat 的根目录。
2. 将 eclipse 与 Tomcat 关联
Window->Preferences->Server->Runtime Enviroments 点击 add 选择下载的 Tomcat 版本,next 后能够选择 Tomcat 的名字,路径和 JRE 版本。Finish 完成建立。
Window->Show View->Other 能够选择 Servers 窗口查看 Tomcat,双击能够进一步配置 Tomcat,选择端口号等等。cookie
1. 建立一个 Dynamic Web Project 在这个页面下打勾,eclipse 会为咱们自动建立一个 web.xml 文件。app
2. 右键 Project,配置 Build Path,点击 add Library,选择 Server Runtime,导入 Tomcat 中的 Servlet 类库。
编写 Servlet 类有3种方式:
以实现 Servlet 接口为例,建立 HelloServlet 类
1 package com.JL916; 2 3 import java.io.IOException; 4 import java.io.PrintWriter; 5 6 import javax.servlet.Servlet; 7 import javax.servlet.ServletConfig; 8 import javax.servlet.ServletException; 9 import javax.servlet.ServletRequest; 10 import javax.servlet.ServletResponse; 11 import javax.servlet.annotation.WebServlet; 12 13 @WebServlet(name = "servlet", urlPatterns = {"/hi"}) 14 public class HelloServlet implements Servlet { 15 16 @Override 17 public void destroy() {} 18 19 @Override 20 public ServletConfig getServletConfig() { return null; } 21 22 @Override 23 public String getServletInfo() { return "hello"; } 24 25 @Override 26 public void init(ServletConfig arg0) throws ServletException {} 27 28 @Override 29 public void service(ServletRequest arg0, ServletResponse arg1) throws ServletException, IOException { 30 arg1.setContentType("text/html"); 31 PrintWriter writer = arg1.getWriter(); 32 writer.print("<html><head></head><body>Hello Servlet</body></html>"); 33 } 34 }
配置 Servlet 有两种方式,一种是使用注解配置,即
@WebServlet(name = "servlet", urlPatterns = {"/hi"})
另外一种是在 web.xml 文件的 web-app 元素中添加 servlet 元素 和 servlet-mapping 元素,以下所示:
<servlet> <servlet-name>HelloServlet</servlet-name> <servlet-class>com.JL916.HelloServlet</servlet-class> </servlet> <servlet-mapping> <servlet-name>HelloServlet</servlet-name> <url-pattern>/hi</url-pattern> </servlet-mapping>
注意:url样式必须用一个'/'开头
在浏览器中输入 http://localhost:8080(Tomcat 端口号)/项目名称/(url-pattern)
对于每个HTTP请求,Servlet容器都会建立一个 ServletRequest 实例,并将它传给 Servlet 的 service 方法。ServletRequest 封装了关于这个请求的信息。
主要方法:
public int getContentLength(); // 返回请求主体的字节数 public String getContentType(); // 返回请求主体的MIME类型 public String getParameter(String name); // 返回指定请求参数的值 经常使用于返回表单的值或查询字符串的值 public String getProtocol(); // 返回请求的协议名称和版本
ServletResponse 接口表示一个 Servlet 响应。在调用 Servlet 的 service 方法前,Servlet 容器首先建立一个 ServletResponse,并将它做为第2个参数传给 service 方法。
在 ServletResponse 中定义的方法之一是 getWriter 方法,它返回了一个能够向客户端发送文本的 java.io.PrintWriter。默认状况下,PrintWriter 对象使用 ISO-8859-1 编码。
在发送任何HTML标签前,应该先调用 setContentType 方法,设置响应的内容类型,并将"text/html"做为一个参数传入。
当 Servlet 容器初始化 Servlet 时,Servlet 容器会给 Servlet 的 init 方法传入一个 ServletConfig。
ServletConfig 封装能够经过`@WebServlet`或者部署描述符传给 Servlet 的配置信息。这样,传入的每一条信息就叫一个初始参数。一个初始参数有 key 和 value 两个元件。
为了从 Servlet 内部获取到初始参数的值,要在 Servlet 容器传给 Servlet 的 init 方法的 ServletConfig 中调用 getlnitParameter 方法。
String getInitParameter(String name)
@WebServlet(name = "servlet", urlPatterns = {"/configtest"}, initParams = { @WebInitParam(name = "admin", value = "JL916"), @WebInitParam(name = "email", value = "admin@example.com") })
ServletContext 表示 Servlet 应用程序。每一个 Web 应用程序只有一个上下文。在将一个应用程序同时部署到多个容器的分布式环境中时,每台Java虚拟机只有一个 ServletContext 对象。 经过在 ServletConfig 中调用 getServletContext 方法,能够得到 ServletContext。
有了 ServletContext,就能够共享能够从应用程序中的全部资料处访问到的信息,而且能够动态注册 Web 对象。前者将对象保存在 ServletContext中的一个内部 Map 中。保存在ServletContext 中的对象称做属性。
ServletContext中的下列方法负责处理属性:
public Object getAttribute(String name); public Enumeration<String> getAttributeNames(); public void setAttribute(String name, Object object); public void removeAttribute(String name);
GenericServlet 是一个抽象类,实现了 Servlet,ServletConfig,java.io.Serializable 接口,为 Servlet 接口中的除 service 外的方法提供默认实现。
// 将 config 对象保存起来 public void init(ServletConfig config) throws ServletException { this.config = config; this.init(); } // 子类能够覆盖没有参数的 init() 方法,ServletConfig 仍然由 GenericServlet 实例保存 public void init() throws ServletException { }
javax.servlet.http 中的许多类型覆盖了 javax.servlet 中的类型。
主要类型以下;
HttpServlet 是一个抽象类,继承自 GenericServlet。
HttpServlet 实现了 service 方法,将 ServletRequest 对象和 ServletResponse 对象转换类型,再调用重载的service方法,获取 request 的 method,再分别调用 doXXX 方法,所以无需再覆盖 service 方法,只要覆盖经常使用的 doGet 方法和 doPost 方法便可。
@Override public void service(ServletRequest req, ServletResponse res) throws ServletException, IOException { HttpServletRequest request; HttpServletResponse response; if (!(req instanceof HttpServletRequest && res instanceof HttpServletResponse)) { throw new ServletException("non-HTTP request or response"); } request = (HttpServletRequest) req; response = (HttpServletResponse) res; service(request, response); } protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { String method = req.getMethod(); if (method.equals(METHOD_GET)) { // ... doGet(req, resp); } else if (method.equals(METHOD_HEAD)) { // ... doHead(req, resp); } else if (method.equals(METHOD_POST)) { doPost(req, resp); } else if (method.equals(METHOD_PUT)) { doPut(req, resp); } else if (method.equals(METHOD_DELETE)) { doDelete(req, resp); } else if (method.equals(METHOD_OPTIONS)) { doOptions(req,resp); } else if (method.equals(METHOD_TRACE)) { doTrace(req,resp); } else { // Note that this means NO servlet supports whatever // method was requested, anywhere on this server. // ... resp.sendError(HttpServletResponse.SC_NOT_IMPLEMENTED, errMsg); } }
HttpServletRequest 继承自 ServletRequest,新增部分方法:
public String getMethod(); // 返回生成这个请求的HTTP方法名称 public String getQueryString(); // 返回请求URL中的查询字符串 public HttpSession getSession(); // 返回与这个请求相关的会话对象 若是没有 将建立一个 public Cookie[] getCookies(); // 返回Cookie对象数组
HttpServletResponse 继承自 ServletResponse,新增部分方法:
public void addCookie(Cookie cookie); // 添加一个Cookie public void sendRedirect(String location) throws IOException; // 发送一条响应码 将浏览器跳转到指定位置
使用部署描述符,若是须要修改配置值,如Servlet路径,则不须要从新编译Servlet类。
此外,能够将初始参数传给一个Servlet,而且不须要从新编译Servlet类,就能够对它们进行编辑。
部署描述符还容许覆盖在 Servlet 标注中定义的值。Servlet 上的 @WebServlet 注解若是同时也在部署描述符中进行声明,那么它将不起做用。
参考资料:《Spring MVC 学习指南》 Paul Deck 著