[Servlet与Jsp学习指南]
*学习此servlet前,需要下载servlet-api.jar,MyEclipse中需要自带javaEE3.0版本的才可以使用注解访问servlet
1.1、Servlet API概述
Javax.servlet 包含定义Servlet与Servlet容器之间契约的类和接口
Javax.servlet.http 包含定义http servlet与servlet容器之间契约的类和接口
Javax.servlet.annotation 包含对servlet、filter和listener进行标注的注解。它还为标注元件指定元数据。
Javax.servlet.descriptor 包含为web应用程序的配置信息提供编程式访问的类型。
Servlet技术的核心是Servlet接口,这是所有Servlet类都必须直接或者间接实现的一个接口。用户的请求会引发Servlet容器调用一个servlet的service方法,并给这个方法传入一个ServletRequest实例和一个ServletResponse实例。
1.2、Servlet
Servlet接口定义了以下5个方法。
Void init(ServletConfig config) throws ServletException
Void service(ServletRequest request,ServletResponse response) throws ServletException,Java.io.IOException
Void destroy()
java.lang.String getServletInfo()
ServletConfig getServletConfig()
Init、service和destroy方法属于Servlet声明周期方法。Servlet容器将根据以下原则调用这三个方法。
1. Init。第一次请求Servlet时,Servlet容器就会调用这个方法。在后续的请求中,将不再调用该方法。可以利用这个方法来编写一些应用程序初始化相关的代码。在调用这个方法时,Servlet容器会传递一个ServletConfig。一般来说,会将ServletConfig赋给一个类级变量,以便Servlet类中的其他方法也可以使用这个对象。
2. Service。每次请求Servlet时,Servlet容器都会调用这个方法。必须在这里编写要Servlet完成的相应代码,第一次请求Servlet时,Servlet容器会调用init方法和service方法,对于后续请求,则只调用service方法。
3. Destroy。要销毁Servlet时,Servlet容器就会调用这个方法。它通常发生在卸载应用程序,或者关闭Servlet容器的时候。一般来说,可以在这个方法中编写一些资源清理相关的代码。
Servlet中的另外两个方法是非声明周期方法:getServletInfo和getServletConfig。
1. getServletInfo。该方法返回Servlet的描述,可以返回可能有用的任意字符串,甚至是null。
2. getServletConfig。该方法返回由Servlet容器传给init方法的ServletConfig。但是,为了让getServletConfig返回非null值,你肯定已经为传给init方法的ServletConfig赋给了一个类级变量。
*必须注意个一点是线程安全性。一个应用程序中的所有用户将共用一个Servlet实例,因此不建议使用类级变量,除非他们是只读的,或者是java.util.concurrent.atomic包中的成员。
1.3、编写基础的Servlet应用程序
- package servlet;
-
- import java.io.IOException;
- import java.io.PrintWriter;
-
- import javax.servlet.Servlet;
- import javax.servlet.ServletConfig;
- import javax.servlet.ServletException;
- import javax.servlet.ServletRequest;
- import javax.servlet.ServletResponse;
- import javax.servlet.annotation.WebServlet;
- @WebServlet(name="MyServlet",urlPatterns={"/my"})
- public class MyServlet implements Servlet{
- private transient ServletConfig servletConfig ;
-
- @Override
- public void destroy() {
-
-
- }
-
- @Override
- public ServletConfig getServletConfig() {
-
- return servletConfig;
- }
-
- @Override
- public String getServletInfo() {
-
- return "My Servlet";
- }
-
- @Override
- public void init(ServletConfig servletConfig) throws ServletException {
-
- this.servletConfig = servletConfig ;
- }
-
- @Override
- public void service(ServletRequest req, ServletResponse res)
- throws ServletException, IOException {
-
- String servletName = servletConfig.getServletName() ;
- res.setContentType("text/html");
- PrintWriter writer = res.getWriter() ;
- writer.print("<html><head></head><body>Hello from " + servletName + "</body></html>") ;
- }
-
- }
1.4、ServletRequest
对于每一个HTTP请求,Servlet容器都会创建一个serveltRequest实例,并将它传给Servlet的service方法。ServletRequest封装有关请求的信息。
下面是ServletRequest接口中的方法。
Public int getContentLength()
返回请求主体中的字节数。如果不知道字节的长度,该方法将返回-1。
Public java.lang.String getContentType()
返回请求主体MIME类型,如果不知道类型,则返回null。
Public java.lang.String getParameter(java.lang.String name)
返回指定请求参数的值
Public java.lang.String getProtocol()
返回这个HTTP请求的协议名称和版本号
getParameter是ServletRequest中最常用的方法。该方法通常用来返回一个HTML表单域的值。
getParameter也可以用来获取查询字符串的值。例如:如果利用下面这个URI调用一个servlet:
http://domain/context/servletName?id=123
将可以在Servlet中利用下面这个语句来获取id的值
String id = request.getParameter(“id”) ;
注意,如果该参数不存在,那么getParameter将返回null。
1.5、ServletResponse
ServletResponse中定义的其中一个方法是getWriter方法,它返回可以将文本传给客户端的java.io.PrintWriter。在默认情况下,PrintWriter对象采用ISO-8859-1编码。
1.6、ServletConfig
为了从一个Servlet内部获取某个初始参数的值,应该在由Servlet容器传给Servlet的init方法的ServletConfig中调用getInitParameter方法。getInitParameter方法的签名如下:
java.lang.getInitParameter(java.lang.String name) ;
此外,getInitParameterNames方法则是返回所有初始化参数名称的一个Enumeration:
java.util.Enumeration<java.lang.String> getInitParameterNames()
除了这2个方法外,ServletConfig还提供了另一个很有用的方法:getServletContext。可以利用这个方法从Servlet内部获取ServletContext。
- package servlet;
-
- import java.io.IOException;
- import java.io.PrintWriter;
-
- import javax.servlet.Servlet;
- import javax.servlet.ServletConfig;
- import javax.servlet.ServletException;
- import javax.servlet.ServletRequest;
- import javax.servlet.ServletResponse;
- import javax.servlet.annotation.WebInitParam;
- import javax.servlet.annotation.WebServlet;
- @WebServlet(name="ServletConfigDemoServlet",
- urlPatterns={"/servletConfigDemo"},
- initParams={
- @WebInitParam(name="admin",value="Benjamin"),
- @WebInitParam(name="email",value="whx449261417@sina.com")
- }
- )
- public class ServletConfigDemoServlet implements Servlet{
- private transient ServletConfig servletConfig ;
- @Override
- public void destroy() {
- }
-
- @Override
- public ServletConfig getServletConfig() {
-
- return servletConfig;
- }
-
- @Override
- public String getServletInfo() {
-
- return "servletConfig demo";
- }
-
- @Override
- public void init(ServletConfig servletConfig) throws ServletException {
-
- this.servletConfig = servletConfig ;
- }
-
- @Override
- public void service(ServletRequest req, ServletResponse res)
- throws ServletException, IOException {
- ServletConfig servletConfig = getServletConfig() ;
- String admin = servletConfig.getInitParameter("admin") ;
- String email = servletConfig.getInitParameter("email") ;
- res.setContentType("text/html");
- PrintWriter writer = res.getWriter() ;
- writer.print("<html><head></head><body>Admin:"+admin+"<br/>Email:"+email+"</body></html>") ;
- }
-
- }
1.7、ServletContext
ServletContext标识Servlet应用程序。每个Web应用程序只有一个context。在分布式环境中,一个应用程序同时部署到多个容器中,并且每台java虚拟机都有一个ServletConfig对象。
在ServletConfig中调用getServletContext方法可以获得ServletContext。
1.8、GenericServlet
GenericServlet通过在init方法中将ServletConfig对象赋给一个类级变量servlet-config,实现对ServletConfig的保存。下面是GeneericServlet的源代码:
- package javax.servlet;
-
- import java.io.IOException;
- import java.io.Serializable;
- import java.util.Enumeration;
- import java.util.ResourceBundle;
-
- public abstract class GenericServlet
- implements Servlet, ServletConfig, Serializable
- {
- private static final String LSTRING_FILE = "javax.servlet.LocalStrings";
- private static ResourceBundle lStrings = ResourceBundle.getBundle("javax.servlet.LocalStrings");
- private transient ServletConfig config;
-
- public void destroy()
- {
- }
-
- public String getInitParameter(String name)
- {
- ServletConfig sc = getServletConfig();
- if (sc == null) {
- throw new IllegalStateException(lStrings.getString("err.servlet_config_not_initialized"));
- }
-
- return sc.getInitParameter(name);
- }
-
- public Enumeration<String> getInitParameterNames()
- {
- ServletConfig sc = getServletConfig();
- if (sc == null) {
- throw new IllegalStateException(lStrings.getString("err.servlet_config_not_initialized"));
- }
-
- return sc.getInitParameterNames();
- }
-
- public ServletConfig getServletConfig()
- {
- return this.config;
- }
-
- public ServletContext getServletContext()
- {
- ServletConfig sc = getServletConfig();
- if (sc == null) {
- throw new IllegalStateException(lStrings.getString("err.servlet_config_not_initialized"));
- }
-
- return sc.getServletContext();
- }
-
- public String getServletInfo()
- {
- return "";
- }
-
- public void init(ServletConfig config)
- throws ServletException
- {
- this.config = config;
- init();
- }
-
- public void init()
- throws ServletException
- {
- }
-
- public void log(String msg)
- {
- getServletContext().log(getServletName() + ": " + msg);
- }
-
- public void log(String message, Throwable t)
- {
- getServletContext().log(getServletName() + ": " + message, t);
- }
-
- public abstract void service(ServletRequest paramServletRequest, ServletResponse paramServletResponse)
- throws ServletException, IOException;
-
- public String getServletName()
- {
- ServletConfig sc = getServletConfig();
- if (sc == null) {
- throw new IllegalStateException(lStrings.getString("err.servlet_config_not_initialized"));
- }
-
- return sc.getServletName();
- }
- }
大家考虑一下为什么GenericServlet中有两个init方法?
GenericServlet通过在init方法中将ServletConfig对象赋给一个类级变量servletConfig,实现对ServletConfig的保存。
但是如果在类中覆盖了这个方法,则调用servlet中的init方法,并且必须调用super.init(servletConfig)来保存ServletConfig。为了避免这么做,GenericServlet又另外提供了一个init方法,它不带参数。当把ServletConfig赋给servletConfig之后,这个方法就会被第一个init方法调用,从而不影响servletConfig的创建。
1.9、HTTP Servlet
1.9.1 HttpServlet
HttpServlet类覆盖javax.servlet.GenericServlet类,在使用HttpServlet时,还要使用HttpServletRequest和HttpServletResponse对象,它们分别标识Servlet请求和Servlet响应。HttpServletRequest接口集成javax.servlet.ServletRequest,HttpServletResponse继承javax.servlet.ServletResponse。
这个新的service方法与javax.servlet.Servlet中的区别在于,前者接受的是HttpServletRequest和HttpServletResponse,而不是ServletRequest和ServletResponse。
原始的service方法将请求和响应对象进行向下转换,分别从Servlet容器转换成HttpServletRequest和HttpServletResponse,并调用新的service方法。
HttpServlet中新的service方法会查看通常用来发送琴秋(通过调用request.getMethod)的Http方法,并调用以下某个方法(doGet、doPost、doHead、doPut、doTrace、doOptions和doDelete)。
总之,HttpServlet中有两项特性是GenericServlet所没有的:
1、不覆盖service方法,而是覆盖doGet、doPost,或者两者都覆盖调。
2、将用HttpServletRequest和HttpServletResponse代替ServletRequest和ServletResponse
1.9.2 HttpServletRequest
HttpServletRequest表示HTTP环境中的Servlet请求。它集成javax.servlet.ServletRequest接口,并增加了几个方法,例如:
Java.lang.String getContextPath()
返回表示请求context的请求URI部分。
Cookie[] getCookies()
返回一个Cookie对象数组
java.lang.String getHeader(java.lang.String name)
返回指定HTTP标头的值
java.lang.String getMethod()
返回发出这条请求的HTTP方法的名称
java.lang.String getQueryString()
返回请求URL中的查询字符串
HttpSession getSession()
返回与这个请求有关的session对象。如果没有找到,则创建新的session对象。
HttpSession getSession(boolean create)
返回与这个请求有关的session对象。如果没有找到,并且create参数为true,那么将创建新的session对象。如果为false,返回空
1.9.3 HttpServletResponse
HttpServletResponse表示HTTP环境下的Servlet响应。下面是其中定义的部分方法:
Void addCookie(Cookie cookie)
给这个响应对象添加cookie
Void addHeader(java.lang.String name,java.lang.String value)
给这个响应对象添加标头
Void sendRedirect(java.lang.String location)
发送响应代号,将浏览器重定向到指定的位置
1.10、处理HTML表单
1.11使用部署描述符(配置文件)
- package app01c;
-
- import java.io.IOException;
- import java.io.PrintWriter;
-
- import javax.servlet.ServletException;
- import javax.servlet.http.HttpServlet;
- import javax.servlet.http.HttpServletRequest;
- import javax.servlet.http.HttpServletResponse;
-
- @SuppressWarnings("serial")
- public class SimpleServlet extends HttpServlet{
- @Override
- protected void doGet(HttpServletRequest req, HttpServletResponse resp)
- throws ServletException, IOException {
- resp.setContentType("text/html") ;
- PrintWriter writer = resp.getWriter() ;
- writer.print("<html><head></head><body>Simple Servlet</body></html>") ;
- }
- }
- package app01c;
-
- import java.io.IOException;
- import java.io.PrintWriter;
-
- import javax.servlet.ServletException;
- import javax.servlet.http.HttpServlet;
- import javax.servlet.http.HttpServletRequest;
- import javax.servlet.http.HttpServletResponse;
-
- @SuppressWarnings("serial")
- public class WelcomeServlet extends HttpServlet{
- @Override
- protected void doGet(HttpServletRequest req, HttpServletResponse resp)
- throws ServletException, IOException {
- resp.setContentType("text/html") ;
- PrintWriter writer = resp.getWriter() ;
- writer.print("<html><head></head><body>Welcome</body></html>") ;
- }
- }
- <?xml version="1.0" encoding="UTF-8"?>
- <web-app version="2.5"
- xmlns="http://java.sun.com/xml/ns/javaee"
- xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
- xsi:schemaLocation="http:
- http:
- <welcome-file-list>
- <welcome-file>index.jsp</welcome-file>
- </welcome-file-list>
- <servlet>
- <servlet-name>ss</servlet-name>
- <servlet-class>app01c.SimpleServlet</servlet-class>
- <load-on-startup>10</load-on-startup>
- </servlet>
- <servlet-mapping>
- <servlet-name>ss</servlet-name>
- <url-pattern>/simple</url-pattern>
- </servlet-mapping>
-
- <servlet>
- <servlet-name>ww</servlet-name>
- <servlet-class>app01c.WelcomeServlet</servlet-class>
- <load-on-startup>20</load-on-startup>
- </servlet>
- <servlet-mapping>
- <servlet-name>ww</servlet-name>
- <url-pattern>/welcome</url-pattern>
- </servlet-mapping>
- </web-app>
这样我们就可以利用下面这些路径去访问它们了:
http://localhost:8080/app01c/simple
http://localhost:8080/app01c/welcome
1.12、小结
Servlet技术是JavaEE技术的组成部分。Servlet容器中运行的所有Servlet,以及容器与Servlet之间的契约,都采用了javax.servlet.Servlet接口的形式。Javax.servlet包也提供了实现Servlet接口的GenericServlet抽象类。这是一个便利类,可以通过扩展它来创建Servlet。但是,大多数现代的Servlet都在HTTP环境中处理请求。因此,将javax.servlet.http.HttpServlet类子类化会更有意义。HttpServlet类本身也是GenericServlet的一个子类。