Servlet和JSP读书笔记(二)

时间:2022-04-14 21:07:21

一. GenericServlet

   1. 前面写的 Servlet和JSP学习笔记(一) 中的实例都是通过实现Servlet接口编写的,这样存在的问题就是:你必须实现Servlet中的所有方法,而不管该方法是否包含有用的

代码。所以,在此基础上Servlet API 为我们提供了GenericServlet 抽象类。

     2. javax.servlet.GenericServlet接口 的源码如下:

package javax.servlet;

import java.io.IOException;
import java.util.Enumeration;


public abstract class GenericServlet implements Servlet, ServletConfig,
        java.io.Serializable {

    private static final long serialVersionUID = 1L;

    private transient ServletConfig config;

public GenericServlet() { // NOOP }   
    
@Override public void destroy() { // NOOP by default }

@Override public String getInitParameter(String name) { return getServletConfig().getInitParameter(name); } @Override public Enumeration<String> getInitParameterNames() { return getServletConfig().getInitParameterNames(); }   /*
      为我们提供了方法获取ServletConfig实例

    */
@Override public ServletConfig getServletConfig() { return config; } @Override public ServletContext getServletContext() { return getServletConfig().getServletContext(); } @Override public String getServletInfo() { return ""; } /*   在此方法中将ServletConfig对象赋值给一个类成员变量,通过getServletConfig()获取该类级成员变量

  */ @Override public void init(ServletConfig config) throws ServletException { this.config = config; this.init(); } public void init() throws ServletException { // NOOP by default } public void log(String msg) { getServletContext().log(getServletName() + ": " + msg); } public void log(String message, Throwable t) { getServletContext().log(getServletName() + ": " + message, t); } @Override public abstract void service(ServletRequest req, ServletResponse res) throws ServletException, IOException;  public String getServletName() { return config.getServletName(); } }

    该抽象类主要做了一下的三件事:

    ①在init方法中将ServletConfig对象赋值给一个类成员变量,通过getServletConfig()获取该类级成员变量。

    ②为Servlet接口中的方法供默认实现。

    ③ 提供方法包装ServletConfig中的方法。

 

  2. GenericServlet示例。

    备注:根据源码个人需求,在继承GenericServlet抽象类时,我们只需要实现service抽象方法就可以了,其他的方法GenericServlet已经帮我们做了处理。

 

    ① 编写Servlet 类

package com.hjj.servlet.two;

import java.io.IOException;
import java.io.PrintWriter;

import javax.servlet.GenericServlet;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;


public class TestGenericServlet extends GenericServlet {

    @Override
    public void service(ServletRequest request, ServletResponse response) throws ServletException, IOException {
        String name = this.getServletConfig().getInitParameter("two");
        response.setContentType("text/html");
        response.setCharacterEncoding("UTF-8");
        PrintWriter pw = response.getWriter();
        pw.print("<html><head><head><title>测试GenericServlet</title><body> hello "+name+"</body></html>");
                
        
    }
        
}

    

    ②因为在之前的实例中我用的是注解的方式进行servlet的配置,所以在这里我使用web.xml进行配置。

 

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE web-app 
PUBLIC "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN" 
"http://java.sun.com/dtd/web-app_2_3.dtd"> 
<web-app> 
    <servlet>
        <servlet-name>testGenericServlet</servlet-name>
        <servlet-class>com.hjj.servlet.two.TestGenericServlet</servlet-class>
        <init-param>
            <param-name>two</param-name>
            <param-value>GenericServlet</param-value>
        </init-param>
    </servlet>
    
    <servlet-mapping>
        <servlet-name>testGenericServlet</servlet-name>
        <url-pattern>/testGenericServlet</url-pattern>
    </servlet-mapping>
    
</web-app> 

  

二. Servlet中的第二个包 javax.servlet.http.* 的主要类型 

    备注:这个包中提供的HttpServlet为我们编写Servlet提供另外一种写法

public abstract class javax.servlet.http.HttpServlet
public interface javax.servlet.http.HttpServletRequest

public interface javax.servlet.http.HttpServletResponse

 

三.  public class javax.servlet.http.HttpServlet

  1. HttpServlet具体信息为:public abstract class HttpServlet extends  GenericServlet implements java.io.Serializable

  2.该类的部分源码如下:

    

package javax.servlet.http; import java.io.IOException; import java.io.OutputStreamWriter; import java.io.PrintWriter; import java.io.UnsupportedEncodingException; import java.lang.reflect.Method; import java.text.MessageFormat; import java.util.Enumeration; import java.util.ResourceBundle; import javax.servlet.DispatcherType; import javax.servlet.GenericServlet; import javax.servlet.ServletException; import javax.servlet.ServletOutputStream; import javax.servlet.ServletRequest; import javax.servlet.ServletResponse; 
public abstract class HttpServlet extends GenericServlet { private static final long serialVersionUID = 1L; 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(LSTRING_FILE); 
    public HttpServlet() { // NOOP
 } 
    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(HttpServletResponse.SC_METHOD_NOT_ALLOWED, msg); } else { resp.sendError(HttpServletResponse.SC_BAD_REQUEST, msg); } } 
    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(HttpServletResponse.SC_METHOD_NOT_ALLOWED, msg); } else { resp.sendError(HttpServletResponse.SC_BAD_REQUEST, msg); } }   //重载的service方法
    protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { String method = req.getMethod(); if (method.equals(METHOD_GET)) { long lastModified = getLastModified(req); if (lastModified == -1) { // servlet doesn't support if-modified-since, no reason // to go through further expensive logic
 doGet(req, resp); } else { long ifModifiedSince; try { ifModifiedSince = req.getDateHeader(HEADER_IFMODSINCE); } catch (IllegalArgumentException iae) { // Invalid date header - proceed as if none was set
                    ifModifiedSince = -1; } if (ifModifiedSince < (lastModified / 1000 * 1000)) { // If the servlet mod time is later, call doGet() // Round down to the nearest second for a proper compare // A ifModifiedSince of -1 will always be less
 maybeSetLastModified(resp, lastModified); doGet(req, resp); } else { resp.setStatus(HttpServletResponse.SC_NOT_MODIFIED); } } } else if (method.equals(METHOD_HEAD)) { long lastModified = getLastModified(req); maybeSetLastModified(resp, lastModified); 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. //  String errMsg = lStrings.getString("http.method_not_implemented"); Object[] errArgs = new Object[1]; errArgs[0] = method; errMsg = MessageFormat.format(errMsg, errArgs); resp.sendError(HttpServletResponse.SC_NOT_IMPLEMENTED, errMsg); } } 
   //重写父类GenericServlet的service  @Override public void service 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"); }

    
 //实际上调用上的还是上面的重载的方法:protected void service(HttpServletRequest req, HttpServletResponse resp)
     service(request, response);
  }
    
    //此处省略部分源码
}

  3. 该类继承了GenericServlet。重写的service方法,传递的参数依然是ServletRequest实例和ServletResponse实例。但是我们可以看到源码,它把ServletRequest和

ServletResponse两个实例分别转化为HttpServletRequest和HttpServletResponse实例。同时实现了重载了一个方法: service(HttpServletRequest req,

HttpServletResponse resp)。并且在参数类型为ServletRequest和ServletResponse的重写方法service 中调用了参数类型为HttpServletRequest 和

HttpServletResponse 的重载方法 service。service重载方法做的事情为:判断请求的类型是GET、POST、HEAD、OPTIONS、PUT、DELETE或者TRACE,然后分别调用相应

的doGet,doPost,doHead,doOptions,doPut,doDelete,doTrace方法。我们常用的请求有GET和POST,因此,我贴上去的源码只有doGet和doPut方法。基于源码的实现,我

们通过继承HttpServlet去编写一个Servlet应用程序时,只需要实现重写doGet()和doPost()方法即可。

 

四. 关于service重载方法传递的两个参数:HttpServletRequest和HttpServletResponse

  1. HttpServletRequest

    ① 具体信息 :public interface extends  ServletRequest 

    ②HttpServletRequest表示HTTP环境中的Servlet请求。

    ③比ServletRequest接口增加的主要方法有: 

public java.lang.String getContextPath() //返回请求Servlet应用程序的URI部分。
public Cookie[] getCookies() //返回一个Cookies数组
public java.lang.String getHeader(java.lang.String name) //返回指定的HTTP 标头的值
public java.lang.String getMethod() // 返回发出这条请求的HTTP方法的名称
public java.lang.String getQueryString()//返回请求Servlet应用的URL中的查询字符串
public HttpSession getSession(boolean create) //返回与这个请求有关的session对象。如果没找到,且create为true,则创建新的session
public HttpSession getSession() //返回与这个请求有关的session对象,如果没有则创建新的session并且返回

 

  2. HttpServletResponse

    ①具体信息:public interface HttpServletResponse extends ServletResponse

    ②HttpServletResponse表示HTTP环境下的Servlet响应。

    ③声明的部分方法: 

public void addCookie(Cookie cookie)           //给当前的响应对象添加cookie

public void sendRedirect(java.lang.String location) throws java.io.IOException // 将浏览器重定向到指定位置
public void addHeader(java.lang.String name, java.lang.String value ) // 给当前的响应添加标头

 

 五. 采用继承HttpServlet编写Servlet小示例。

    1. 通过继承HttpServlet实现编写一个Servlet应用程序。
      
package com.hjj.servlet.two;

import java.io.IOException;
import java.io.PrintWriter;

import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
@WebServlet(name="testHttpServlet",urlPatterns="/testHttpServlet")
public class TestHttpServlet extends HttpServlet{
    
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
            System.out.println("我是 doGet 方法,我被调用了");
            response.setContentType("text/html");
            response.setCharacterEncoding("UTF-8");
            
            PrintWriter pw = response.getWriter();
            pw.println("<html><head></head><title>测试HttpServlet</title><body><center>");
            pw.println("<center><h1>提交数据</h1></center>" );
            pw.println("<form method='post' action='testHttpServlet'>");
            pw.println("<p>姓名<input name='name' type='text '/></p>");
            pw.println("<p><input value='提交' type='submit'/></p>");
            pw.println("</form></center></body></html>");
    }

    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
            System.out.println("我是 doPost 方法,我被调用了");
            response.setContentType("text/html");
            response.setCharacterEncoding("UTF-8");
            
            String name = request.getParameter("name");
            
            PrintWriter pw = response.getWriter();
            pw.println("<html><head></head><title>测试提交数据</title><body>");
            pw.println("<center><h1>");
            pw.println("get提交的表单的值为:"+name);
            pw.println("</h1></center></body></html>");
    }
}

    2. 在浏览器中输入url:http://localhost:8080/one/testHttpServlet

      页面显示:

      Servlet和JSP读书笔记(二)

      控制台打印:

            我是 doGet 方法,我被调用了

   3. 在上一个页面的表单中输入值

      Servlet和JSP读书笔记(二)u

    提交后页面显示:

      Servlet和JSP读书笔记(二)

    控制台打印:

          我是 doPost 方法,我被调用了

 

  

        

service