欢迎访问悦橙教程(wld5.com),关注java教程。悦橙教程  java问答|  每日更新
页面导航 : > > 文章正文

JavaWeb中的Servlet概述,javawebservlet概述

来源: javaer 分享于  点击 7561 次 点评:15

JavaWeb中的Servlet概述,javawebservlet概述


首先说一下Servlet是什么?

Java Servlet实际上是一个java类,Java Servlet实际上是一个java类,Java Servlet实际上是一个java类,重要的事说三遍。

只不过这个类必须运行在具有JavaServlet规范解释器的Web服务器上(例如Tomcat)

在这些支持规范解释器的服务器(例如Tomcat)上,一般都具有一个Servlet容器,当一个web请求到达服务器时,这个请求就会被委派到这个Servlet容器中,成为Servlet容器的管理对象,即这个Servlet对象就是当前浏览器的http请求(暂且这样理解,通俗易懂)

实际上:Java Servlet是运行在Web服务器(Tomcat之类)上的程序,作为web浏览器(或其他Http客户端的请求)和Tomcat服务器(Http服务器)上的数据库或应用程序之间的中间层,使用Servlet,不但可以收集网页表单的用户输入,也可以将数据库中的记录展示到网页上。

还是不明白Servlet是什么的,请直接跳到下面的代码实例去学习,从其代码层面理解,至于其生命周期,service方法可以先不了解。

Servlet能做什么:

1.读取浏览器发送的显示数据,表单等

2.读取浏览器发送的隐式数据,例如Cookies等

3.发送显示数据到浏览器

4.发送隐式的Http响应到浏览器,例如Cookies等

Servlet的生命周期:

当Http请求被委派到Servlet容器时,Servlet容器就会创建Servlet,创建该Servlet时,容器会调用Init方法。

注意,后续相同的http请求不会再创建Servlet,也不会再调用init方法(因为此时Servlet容器中已经存在了)

容器在调用init方法时,会简单的创建/加载一些数据,这些数据随着Servlet的存在而存在。

service() 方法:

service() 方法是执行实际任务的主要方法。 

Web 服务器调用 service() 方法来处理来自客户端(浏览器)的请求,并把格式化的响应写回给客户端。

每次服务器接收到一个 Servlet 请求时,服务器会产生一个新的线程并调用服务。

service() 方法检查 HTTP 请求类型(GET、POST、PUT、DELETE 等),并在适当的时候调用 doGet、doPost、doPut,doDelete 等方法。

service() 方法也是由容器调用,所以不用对 service() 方法做任何动作。

只需要根据来自客户端的请求类型来重写 doGet() 或 doPost() 即可。

doget(),doPost()方法

doGet() 方法:请求中不指定表单,

doPost() 方法:请求中指定表单。

比如说在浏览器的某个页面中有两个提交按钮,

按钮1提交的内容中有表单,那么你就需要使用dopost方法,进而再做一些处理。

按钮2提交的内容中无表单,那么你就需要使用doget方法,进而再做一些处理。

destroy() 方法

destroy() 方法只会被调用一次,在 Servlet 生命周期结束时被调用。

destroy() 方法可以让您的 Servlet 关闭数据库连接、停止后台线程、把 Cookie 列表或点击计数器写入到磁盘,并执行其他类似的清理活动。

在调用 destroy() 方法之后,servlet 对象被标记为垃圾回收。


代码实例:

Servlet 是服务 HTTP 请求并实现 javax.servlet.Servlet 接口的 Java 类,下面的代码是web中常用的HttpServlet.

Web 应用程序开发人员通常编写 Servlet 来扩展 javax.servlet.http.HttpServlet,并实现 Servlet 接口的抽象类专门用来处理 HTTP 请求。

// 导入必需的 java 库
import java.io.*;
import javax.servlet.*;
import javax.servlet.http.*;

// 扩展 HttpServlet 类
public class HelloWorld extends HttpServlet {
 
  private String message;

  public void init() throws ServletException
  {
      // 执行必需的初始化
      message = "Hello World";
  }

  public void doGet(HttpServletRequest request,
                    HttpServletResponse response)
            throws ServletException, IOException
  {
      // 设置响应内容类型
      response.setContentType("text/html");

      // 实际的逻辑是在这里
      PrintWriter out = response.getWriter();
      out.println("<h1>" + message + "</h1>");
  }
  
  public void destroy()
  {
      // 什么也不做
  }
}

不明白?不明白就要先大致了解Servlet的底层实现,具体看下面。

Servlet的底层实现:

在Servlet编程中我们必须使用到javax.servlet 和 javax.servlet.http这两个包以及其下面的类和接口。

在所有的类和接口中,javax.servlet.servlet 接口最为重要。因为所有的servlet程序都必须实现该接口或者继承实现了该接口的类。

这个接口定义了初始化 servlet 的方法、为请求提供服务的方法和从服务器移除 servlet 的方法。这些方法称为生命周期方法,它们是按以下顺序调用的: 

1.构造 servlet,然后使用 init 方法将其初始化。 

2.处理来自客户端的对 service 方法的所有调用。 

3.从服务中取出 servlet,然后使用 destroy 方法销毁它,最后进行垃圾回收并终止它。 

以下是Servlet的源码,他是一个接口:

package javax.servlet;
import java.io.IOException;
 
public interface Servlet {

    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();

}

再说一下GenericServle:

GenericServlet 实现 Servlet 和 ServletConfig 接口,对这两个接口中的方法进行了简单实现。

GenericServlet 使编写 servlet 变得更容易。它提供生命周期方法 init 和 destroy 的简单版本,以及 ServletConfig 接口中的方法的简单版本。

GenericServlet 还实现 log 方法,在 ServletContext 接口中对此进行了声明。 

要编写一般的 servlet,只需重写抽象 service 方法即可。 

看一下其源码:

public abstract class GenericServlet   
    implements Servlet, ServletConfig, java.io.Serializable  
{  
    //私有变量,保存 init()传入的ServletConfig对象的引用  
    private transient ServletConfig config;  
      
    public GenericServlet() { }  
 
    public void init(ServletConfig config) throws ServletException {  
      this.config = config;  
      this.init();   //调用了无参的 init()方法  
    }  
  
    //无参的init()方法  
    public void init() throws ServletException {  
  
    }  
        
    //空实现了destroy方法  
    public void destroy() { }               
       
    //实现了接口中的getServletConfig方法,返回ServletConfig对象  
    public ServletConfig getServletConfig()   
    {  
       return config;  
    }      
  
    //该方法实现接口<Servlet>中的ServletInfo,默认返回空字符串  
    public String getServletInfo() {  
       return "";  
    }  
     
	//当HttpServlet继承GenericServlet抽象类时需要实现service方法
    public abstract void service(ServletRequest req, ServletResponse res)  
 throws ServletException, IOException;  
      
	//得到ServletContext实例
    public ServletContext getServletContext() {  
       return getServletConfig().getServletContext();  
    }  
      
	//得到servlet的配置参数
    public String getInitParameter(String name) {  
     return getServletConfig().getInitParameter(name);  
    }  
      
	//得到servlet的配置参数名
    public Enumeration getInitParameterNames() {  
       return getServletConfig().getInitParameterNames();  
     
 
    public String getServletName() {  
        return config.getServletName();  
    }  
        
    public void log(String msg) {  
       getServletContext().log(getServletName() + ": "+ msg);  
    }    
        
    public void log(String message, Throwable t) {  
       getServletContext().log(getServletName() + ": " + message, t);  
    }  
}

HttpServlet源码:

在上面的GenericServlet中,已经对Servlet和ServletConfig进行了简单实现,这次我们需要使用http,所以我们需要对上面的实现进一步进行修改。

所以创建了一个HttpServlet抽象类,该类中含有我们需要使用的HttpServletRequest和HttpServletResponse。

这两个对象有必要说一下:

这两个对象都是接口,他们的父类也是接口,分别是ServletRequest和ServletResponse。

Servlet理论上可以处理多种形式的请求响应 ,http只是其中之一 ,所以这里的http开头的接口多了一些针对http协议的方法。

此时,你要明白,httpServlet中的doget和dopost方法中的形参都是tomcat传给他的,都是已经处理过的。

这时候如果你不明白继承了HttpServlet,重写其方法,就能完成你所需的操作,那么你就要去看一些多态的资料的。

这里举一个简单的例子:

假如说HttpServlet是动物类,你创建了一个猫类,即httpServletA,它继承了动物类,那么当你把动物类的方法覆盖掉(doget,dopost等),容器tomcat就会调用猫类的方法,没有猫类的方法就回去调用动物类的方法,这叫向上转型。

而猫类里面的doget和dopost方法里面的参数HttpServletRequest和HttpServletResponse,是怎么将ServletRequest转为HttpServlet的呢?
仔细想一下,HttpServletRequest是接口,ServletRequest也是接口,此时如果创建一个实体类,实现这两个接口,理论上来说向下转型是肯定没有问题的。

因而,转换为HttpServletRequest是没有问题的。

举个例子:假设ServletRequest是动物接口,HttpServletRequest是猫科动物接口,而实现类则为猫

当我们在doGet方法中,我们需要使用到的是猫(上述的实体类),所以用猫科动物这个称呼(调用)猫不会有问题!用动物这个称呼(调用)猫也不会有问题!

至于猫这个实现类是谁去实现的,里面的数据是什么,我们没必要去管它,那是tomcat的事。

我们只需要明白我们经历了什么,要做一些什么。

//继承GenericServlet抽象类
public abstract class HttpServlet extends GenericServlet
    implements Serializable
{
    public HttpServlet()
    {
    }
	
	//get请求,自己的扩展类中需要覆写该方法
    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);
        else
            resp.sendError(400, msg);
    }
	//post请求,自己的扩展类中需要覆写该方法
    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);
        else
            resp.sendError(400, msg);
    }
    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);
        else
            resp.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);
        else
            resp.sendError(400, msg);
    }

    protected void doTrace(HttpServletRequest req, HttpServletResponse resp)
        throws ServletException, IOException
    {
        String CRLF = "\r\n";
        String responseString = (new StringBuilder()).append("TRACE ").append(req.getRequestURI()).append(" ").append(req.getProtocol()).toString();
        for(Enumeration reqHeaderEnum = req.getHeaderNames(); reqHeaderEnum.hasMoreElements();)
        {
            String headerName = (String)reqHeaderEnum.nextElement();
            responseString = (new StringBuilder()).append(responseString).append(CRLF).append(headerName).append(": ").append(req.getHeader(headerName)).toString();
        }
        responseString = (new StringBuilder()).append(responseString).append(CRLF).toString();
        int responseLength = responseString.length();
        resp.setContentType("message/http");
        resp.setContentLength(responseLength);
        ServletOutputStream out = resp.getOutputStream();
        out.print(responseString);
        out.close();
    }
	
	//重载service(ServletRequest req, ServletResponse resp)方法
    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);	//执行doGet方法,所以需要覆写doGet方法
                } 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);	//执行doPost方法,所以需要覆写doPost方法
        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);
        }
    }
   //重要
    public void service(ServletRequest req, ServletResponse res)
        throws ServletException, IOException
    {
        HttpServletRequest request;
        HttpServletResponse response;
		//将请求ServletRequest强转为HttpServletRequest,调用service(HttpServletReqeust req,HttpServletResponse resp)方法
        try
        {
            request = (HttpServletRequest)req;
            response = (HttpServletResponse)res;
        }
        catch(ClassCastException e)
        {
            throw new ServletException("non-HTTP request or response");
        }
        service(request, response); //调用service(HttpServletReqeust req,HttpServletResponse resp)方法
    }
    private static final String METHOD_DELETE = "DELETE";
    private static final String METHOD_HEAD = "HEAD";
    private static final String METHOD_GET = "GET";
    private static final String METHOD_OPTIONS = "OPTIONS";
    private static final String METHOD_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");
}

到这里你一定要明白,我们编写网页时用的Servlet是服务器自动创建的,不是你创建的。

如果你想自己在本机试一下Servlet的创建过程请参考知乎上一篇文章:https://www.zhihu.com/question/21416727

在实现编码中,我们经常用到的就是基于http协议的Servlet实现,因为我们的网页想通过服务器获取一些数据时,必然要使用http协议.

在这个时候,服务器就要将我们原本的可以使用的但不完善支持http协议的Servlet进行扩展,扩展为可以完善支持http协议的Servlet,即HttpServlet。

至此Servlet的基本内容就在这里,更详细的各位可以参考下面的博客:

http://www.cnblogs.com/xdp-gacl/p/3760336.html

http://www.runoob.com/servlet/servlet-life-cycle.html

http://blog.csdn.net/xiaoxing1521025/article/details/8290092


相关文章

    暂无相关文章
相关栏目:

用户点评