Tomcat 与 Java Web开发技术详解(第三版) 第四章 Servlet技术(上)笔记

第四章 Servlet技术(上)

Servlet中的常用对象:

  • 请求对象(ServletRequest和HttpServletRequest):Servlet从该对象中获取来自客户的信息。
  • 响应对象(ServletResponse和HttpServletResponse):Servlet通过该对象来生成响应结果。
  • Servelt配置对象(ServletConfig):当容器初始化一个Servlet对象时,会像Servlet提供一个ServletConfig对象,Servlet通过该对象来获取初始化参数以及ServletContext对象。
  • Servlet上下文对象(ServletContext):Servlet通过该对象来访问容器为当前web应用提供的各种资源。

4.1 Servlet API

在这里插入图片描述

4.1.1 Servlet接口

Servlet API的核心接口是javax.servlet.Servlet接口。所有的Servlet类都必须实现这个接口。在Servlet接口中定义可5个方法,其中3个方法由Servlet容器来调用,容器会在Servlet的生命周期的不同时期调用特定的方法。

  1. init(ServletConfig config) 方法:该方法负责初始化Servelt对象。容器在创建好Servelt对象后,就会调用该方法。
  2. service(ServletRequest req, ServletResponse res)方法:负责响应客户的请求,为客户提供响应的服务。容器接收到客户要求访问特定Servlet对象的请求时,就会调用该Servlet对象的service()方法。
  3. destroy()方法:负责释放对象占用的资源。当Servlet的生命周期结束时,容器会调用此方法。
  4. getServletConfig():返回一个ServletConfig对象,该对象中包含了Servlet的初始化参数信息。
  5. gerServletInfo():返回一个字符串,该字符串包含了Servlet的创建者、版本和版本权等信息。
    void init(ServletConfig var1) throws ServletException;
    ServletConfig getServletConfig();
    void service(ServletRequest var1, ServletResponse var2) throws ServletException, IOException;
    String getServletInfo();
    void destroy();

在这里插入图片描述

4.1.2 GenericServlet抽象类

GenericServlet抽象类为Servlet接口提供了通用实现。它与任何网络应用层协议无关,GenericServlet除了实现了Servlet接口,还实现了ServletConfig接口和Serializable接口。


package javax.servlet;

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

public abstract class GenericServlet 
    implements Servlet, ServletConfig, java.io.Serializable
{
    private static final String LSTRING_FILE = "javax.servlet.LocalStrings";
    private static ResourceBundle lStrings =
        ResourceBundle.getBundle(LSTRING_FILE);

    private transient ServletConfig config;
    
    public GenericServlet() { }
    
 
    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 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 {
    //是当前Servlet对象与传入进来的ServletConfig对象关联
	this.config = config;
	this.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 req, ServletResponse res)
	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()方法,init(ServletConfig config)方法会调用此方法。对于GenericServlet类的子类,如果希望覆盖父类的初始化行为,有两种方法:

  1. 覆盖父类的不带参数的init()方法。
public void init(){
//子类的具体初始化行为
....
}
  1. 覆盖父类的带参数的init(ServletConfig config)方法。如果当前Servlet对象与ServletConfig对象关联,应该在方法中先调用super.init(ServletConfig config)方法:
public void init(ServletConfig config){
	super.init();//调用父类的init(config)方法。
	//子类的具体初始化行为
	....
}

GenericServlet类没有实现Servlet接口中的service()方法,service()方法是GenericServlet中的唯一的抽象方法,它的子类必须实现它,从而为特定的客户端提供具体的请求服务。
GenericServlet实现了ServletConfig中的所有方法。

4.1.3 HttpServlet类

HttpServlet是GenericServlet的子类。为Servlet提供了与HTTP协议相关的通用实现。即HTTPservlet对象适合运行在与客户端采用了HTTP协议的Servlet容器或Web服务器中。

package javax.servlet.http;

import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
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 final ResourceBundle lStrings = ResourceBundle.getBundle("javax.servlet.http.LocalStrings");

    public HttpServlet() {
    }

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

    }

    protected long getLastModified(HttpServletRequest req) {
        return -1L;
    }

    protected void doHead(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        if (DispatcherType.INCLUDE.equals(req.getDispatcherType())) {
            this.doGet(req, resp);
        } else {
            NoBodyResponse response = new NoBodyResponse(resp);
            this.doGet(req, response);
            response.setContentLength();
        }

    }

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

    }

    private static Method[] getAllDeclaredMethods(Class<?> c) {
        if (c.equals(HttpServlet.class)) {
            return null;
        } else {
            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(this.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;
        Class clazz = null;

        try {
            clazz = Class.forName("org.apache.catalina.connector.RequestFacade");
            Method getAllowTrace = clazz.getMethod("getAllowTrace", (Class[])null);
            ALLOW_TRACE = (Boolean)getAllowTrace.invoke(req, (Object[])null);
        } catch (NoSuchMethodException | SecurityException | IllegalAccessException | IllegalArgumentException | InvocationTargetException | ClassNotFoundException var14) {
        }

        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 = "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";
        StringBuilder buffer = (new StringBuilder("TRACE ")).append(req.getRequestURI()).append(" ").append(req.getProtocol());
        Enumeration reqHeaderEnum = req.getHeaderNames();

        while(reqHeaderEnum.hasMoreElements()) {
            String headerName = (String)reqHeaderEnum.nextElement();
            buffer.append(CRLF).append(headerName).append(": ").append(req.getHeader(headerName));
        }

        buffer.append(CRLF);
        int responseLength = buffer.length();
        resp.setContentType("message/http");
        resp.setContentLength(responseLength);
        ServletOutputStream out = resp.getOutputStream();
        out.print(buffer.toString());
        out.close();
    }

    protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        String method = req.getMethod();
        long lastModified;
        if (method.equals("GET")) {
            lastModified = this.getLastModified(req);
            if (lastModified == -1L) {
                this.doGet(req, resp);
            } else {
                long ifModifiedSince;
                try {
                    ifModifiedSince = req.getDateHeader("If-Modified-Since");
                } catch (IllegalArgumentException var9) {
                    ifModifiedSince = -1L;
                }

                if (ifModifiedSince < lastModified / 1000L * 1000L) {
                    this.maybeSetLastModified(resp, lastModified);
                    this.doGet(req, resp);
                } else {
                    resp.setStatus(304);
                }
            }
        } else if (method.equals("HEAD")) {
            lastModified = this.getLastModified(req);
            this.maybeSetLastModified(resp, lastModified);
            this.doHead(req, resp);
        } else if (method.equals("POST")) {
            this.doPost(req, resp);
        } else if (method.equals("PUT")) {
            this.doPut(req, resp);
        } else if (method.equals("DELETE")) {
            this.doDelete(req, resp);
        } else if (method.equals("OPTIONS")) {
            this.doOptions(req, resp);
        } else if (method.equals("TRACE")) {
            this.doTrace(req, resp);
        } else {
            String errMsg = lStrings.getString("http.method_not_implemented");
            Object[] errArgs = new Object[]{method};
            errMsg = MessageFormat.format(errMsg, errArgs);
            resp.sendError(501, errMsg);
        }

    }

    private void maybeSetLastModified(HttpServletResponse resp, long lastModified) {
        if (!resp.containsHeader("Last-Modified")) {
            if (lastModified >= 0L) {
                resp.setDateHeader("Last-Modified", lastModified);
            }

        }
    }

    public void service(ServletRequest req, ServletResponse res) throws ServletException, IOException {
        HttpServletRequest request;
        HttpServletResponse response;
        try {
            request = (HttpServletRequest)req;
            response = (HttpServletResponse)res;
        } catch (ClassCastException var6) {
            throw new ServletException("non-HTTP request or response");
        }

        this.service(request, response);
    }
}

HttpServlet类为每一种请求凡是都提供了相应的服务方法,如doGet()、doPost()、doPut()等doXXX()方法。
HttpServlet实现了Servlet接口中的service(ServletRequest req, ServletResponse res)方法,该方法实际调用的是它的重载方法。

  public void service(ServletRequest req, ServletResponse res) throws ServletException, IOException {
        HttpServletRequest request;
        HttpServletResponse response;
        try {
            request = (HttpServletRequest)req;
            response = (HttpServletResponse)res;
        } catch (ClassCastException var6) {
            throw new ServletException("non-HTTP request or response");
        }
		//service(ServletRequest req, ServletResponse res)重载方法service(HttpServletRequest req, HttpServletResponse resp)
        this.service(request, response);
    }

service(HttpServletRequest req, HttpServletResponse resp)方法会根据请求方式的不同调用相应的doXXX()方法。

4.1.4 ServletRequest接口

ServletRequest接口表示来自客户端的请求,当Servlet容器接收到请求时,容器先解析客户端的原始数据,把它包装成一个ServletRequest对象。当容器调用servive()方法时,就会把ServletRequest对象作为参数传给service()方法。
ServletRequest接口提供了一些读取客户端请求数据的方法。

  • getContentLength()返回请求正文的长度。如果请求正文的长度未知,放回-1。
  • getContentType():获得请求正文的MIME类型,类型未知返回null。
  • getInputStream():返回用于读取请求正文的输入流。
  • getLocalAddr():返回服务器端的IP地址。
  • getLocalName():返回服务器端的主机名。
  • getLocalPort():返回服务器端的端口。
  • getParameter(String name):根据给定的请求参数名返回来自客户端请求中的匹配的参数值。
  • getProtocol():返回通信协议的名称及版本。
  • getReader():返回用于读取字符串形式的请求正文的BufferReader对象。
  • getRemoteAddr():客户端IP。
  • getRemoteHost():客户端主机名。
  • getRemotePort():返回客户端的FTP端口号。

用于在请求范围类存取共享数据的方法:

  • setAttribute(String name , Object object):保存一个属性,name属性名,object属性值。
  • getAttribute(String name):根据属性名获取属性值。
  • removeAttribute(String name):在请求范围内根据属性名删除某个属性。

4.1.5 ServletResponse接口

ServletResponse接口中有关响应结果的方法:

  • setCharaterEnconding(String charset):设置响应正文的字符集,默认为ISO-8859-1。
  • setContentLength(int len):设置响应正文的长度。
  • setContentType(String type):设置响应正文的MIME类型。
  • getCharaterEncoding:返回响应正文的字符编码。
  • setBufferSize(int size):设置用于存放响应正文的缓冲区大小。
  • getBufferSzie():获取用于存放响应正文的缓冲区大小。
  • reset():清空缓冲区的正文数据,并且清空响应状态代码以及响应头。
  • restBuffer():清空缓冲区的正文数据,但不清空响应状态代码以及响应头。
  • flushBuffer():强制性的把缓冲区的响应正文数据发送给客户端。
  • isCommitted():返回值为boolean,如果为true,表示缓冲区的数据已提交给客户。
  • getOubtputStream():返回一个ServeltOutputStream对象,Servlet用它来输出二进制正文数据。

4.1.7 HttpServletResponse 接口

HttpServletResponse提供与HTTP协议相关的方法:

  • addHeader(String name, String value):添加响应头。
  • sendError(int src):向客户端发送一个代表错误的HTTP响应状态代码。
  • sendError(int src, String msg):发送错误代码,并发送错误消息。
  • setHeader(String name, String value):设置响应头。
  • setStatus(int src):设置HTTP响应状态代码。
  • addCookie(Cookie cookie):向HTTP响应中加入一个Cookie。

4.1.8 ServletConfig 接口

当Servlet容器初始化一个Servlet对象时,会为Servelt对象创建一个ServletConfig对象,ServeltConfig包含了Servlet的初始化信息。

//Servelt的实现类GernericServlet中的init方法
 public void init(ServletConfig config) throws ServletException {
	this.config = config;
	this.init();
    }

ServletConfig接口中定义的方法:

	/**返回serlve的名字*/
	String getServletName();
	/**返回一个ServletContext对象*/
    ServletContext getServletContext();
	/**根据参数名返回初始化参数值*/
    String getInitParameter(String var1);
	/**Enumeration中包含了所有的初始换参数对象*/
    Enumeration<String> getInitParameterNames();

HttpServlet类继承了GenericServlet,而GenericServlet实现了ServeltConfig接口,所以在HttpServlet或GenericServlet类中及其子类中都类直接调用ServeltConfig接口的方法。

4.1.9 ServletContext 接口

ServeltContext 是Servelt与Servlet容器之间进行通信的接口。Servelt容器在启动Web应用时,会为它创建一个ServeltContext对象。一个Web应用中只有唯一的一个ServeltContext对象。
ServletContext提供的方法可以分为以下几种类型:
(1)用于Web应用范围内存取共享数据的方法。

  • setAttribute(String name, Object object):设置一个属性。
  • getAttribute(String name):根据属性名获取属性值。
  • getAttributeNames():返回一个Enumeration对象,该对象包含了所有存在ServletContext中的属性名。
  • removeAttribute(String name):根据属性名删除一个属性。

(2)访问当前Web应用的资源。

  • getContextPath():返回当前Web应用的URL入口。
  • getInitParameter(String name):根据参数名返回初始化参数。
  • getParameterNames():返回一个Enumeration对象,该对象包含了所有Web应用范围内的所有初始化参数名。
  • getServletContextName():返回web应用的名字。web.xml中<display-name>的值。
  • getRequestDispatcher():返回一个用于向其他Web组件转发请求的RequestDispatcher对象。

(3)访问Servelt容器中的其他Web应用。

  • getContext(String uripath):根据指定参数的URI返回当前容器中其他Web应用的ServletContext对象。

(4)访问Servlet容器相关信息。

  • getMajorVersion():Java Servlet API的主版本号。
  • getMinorVersion():Java Servlet API的次版本号。
  • getServletInfo():Servlet容器的版本和名字。

(5)访问服务器端的文件系统资源。

  • getRealPath(String path):根据参数指定的虚拟路径,返回文件系统中的一个真实路径。
  • getResource(String path):返回一个映射到参数指定的路径URL。
  • getResourceAsStream(String path):返回一个用于读取参数指定的文件输入流。

(6)输出日志。

  • log(String msg):向Servlet的日志文件中写日志。
  • log(String message, Throwable throwable):向Servlet日志文件中写错误日志及异常的堆栈信息。

4.2 Java Web 应用的生命周期

Java Web应用的生命周期是由Servlet容器控制的。分为3各阶段。

  • 启动阶段:加载Web应用有关的数据,创建ServletContext对象,对Filter和一些Servlet组件初始化。
  • 运行时阶段:为客户提供服务。
  • 终止阶段:释放Web应用说占用的各种资源。

4.2.1 启动阶段

Servlet容器在启动web应用时:
(1)把web.xml文件中的数据加载到内存中。
(2)为Java Web 应用创建ServletContext对象。
(3)对所有的Filter进行初始化。
(4)对需要在Web应用启动时就需要初始化的Servlet进行初始化。

4.2.2 运行时阶段

为客户提供相应的服务。

4.2.3 终止阶段

Servlet容器在终止Java Web应用时,会完成以下操作:
(1)销毁应用中所有处于运行状态的Servlet。
(2)销毁处于运行状态的Filter。
(3)销毁所有与应用相关的对象。如ServletContext等。

4.3 Servlet的生命周期

Java Web应用的生命周期由Servlet容器控制,而Servlet作为Java Web应用的核心组件,其生命周期也是由Servlet容器控制。Servelt的生命周期分为三个阶段。

  • 初始化阶段init()。
  • 运行时阶段service()。
  • 销毁阶段destroy()。

4.3.1 初始化阶段

Servlet初始换阶段分为四个步骤:

  1. Servlet容器加载Servlet类,把他的class文件中的数据存到内存中。
  2. Servlet容器创建ServletConfig对象。
  3. Servlet容器创建Servlet对象。
  4. Servlet容器调用Servlet的init(ServletConfig config)方法。

4.3.2 运行时阶段

Servlet可以随时响应客户端的请求。当Servlet容器接收到访问特定Servlet客户的请求时,Servlet容器创建针对这个请求的ServeltRequest对象和ServeltResponse对象,然后调用该Servlet对象的service()方法。service()方法通过ServletRequest对象获取客户的请求信息并处理,通过ServletResponse对象生成响应结果。

当Servlet容器把Servlet生成的响应结果发送给客户后,Servlet容器就会销毁ServletReqeuest对象和Response对象。

4.3.3 销毁阶段

当Web应用被终止时,Servlet容器会先调用Web应用中所有Servlet的destory()方法,然后再销毁这些Servlet。

4.4 ServletContext 与 Web应用范围

ServletContext与Web应用具有同样的生命周期,因为Servlet容器在启动Web应用时,就会创建一个唯一的ServletContext对象,当Servlet容器终止一个Web应用时就会销毁ServletContext对象。
ServletContext是被Web应用中的所有Servlet共享的,所以在Web应用范围内可以用ServeltContext来存取共享数据。

4.1.1 在Web应用范围内存放共享数据的范例

package mypack;
public class Counter{
  private int count; //计数值
  public Counter(){
    this(0);
  }
  public Counter(int count){
    this.count=count;
  }
  public void setCount(int count){
    this.count=count;
  }
  public int getCount(){
    return count;
  }
  
  public void add(int step){
    count+=step;
  }
}

package mypack;
import java.io.*;
import javax.servlet.*;
import javax.servlet.http.*;

public class CounterServlet extends HttpServlet {
  public void doGet(HttpServletRequest request,
    HttpServletResponse response)throws ServletException, IOException {

    //获得ServletContext的引用
    ServletContext context = getServletContext();

    // 从ServletContext中读取counter属性
    Counter counter = (Counter)context.getAttribute("counter");

    // 如果ServletContext中没有counter属性,就创建counter属性
    if ( counter == null ) {
      counter = new Counter(1);
      context.setAttribute("counter", counter);
    }
    
    response.setContentType("text/html;charset=GBK");
    PrintWriter out = response.getWriter();
    out.println("<html><head><title>CounterServlet</TITLE></head>");
    out.println("<body>");
    // 输出当前的counter属性
    out.println("<h1>欢迎光临本站。您是第 " + counter.getCount()+" 位访问者。</h1>");
    out.println("</body></html>");
  
    //将计数器递增1   
    counter.add(1);
    out.close();
  }
}
package mypack;
import java.io.*;
import javax.servlet.*;
import javax.servlet.http.*;

public class CounterClearServlet extends HttpServlet {
  public void doGet(HttpServletRequest request,
    HttpServletResponse response)throws ServletException, IOException {

    //获得ServletContext的引用
    ServletContext context = getServletContext();
    context.removeAttribute("counter");  //删除counter属性
    PrintWriter out=response.getWriter();
    out.println("The counter is removed.");
    out.close();
  }
}

4.4.2 使用ServletContextListener

ServletContextListener接口能够监听ServeltContext对象的生命周期,实际上就是监听Web应用的生命周期。
当Servlet容器启动或终止Web应用时,会触发ServletContextEvent事件。该事件由ServletContextListener来处理。ServletContextListener接口中定义了两个处理ServletContextEvent事件的两个方法:

/**当Servlet容器启动Web应用时调用该方法。调用完该方法后,容器再对Filter初始化,并且对那些在Web应用启动时需要初始化的Servlet进行初始化*/
 public void contextInitialized(ServletContextEvent sce);
 /**容器终止Web应用时调用。在调用之前,会先销毁所有的Servelt和Filter*/
 public void contextDestroyed(ServletContextEvent sce);

4.5 Servlet的服务方法跑出异常

Servlet接口的service()方法完整定义如下:

public void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException;

该方法中抛出两个异常:
ServletException:表示当前Servlet进行常规操作时出现异常。
IOException:进行IO操作时出现异常。

ServletException有一个子类UnavailableException,表示无法访问当前Servelt的异常。

4.6 防止页面被客户端缓存

浏览器能够缓存服务端的网页,需要访问这个网页时直接冲缓存中取,不会去请求访问远程服务器资源。
这种技术只适用于缓存服务器的静态资源及不包含敏感数据的网页。对于其他的资源,服务器往往不希望网页被客户端缓存。如:

  • 网页中包含随时会被更新的内容。
  • 网页中包含敏感数据,如特定的用户账号信息等。

服务器端的HttpServelt可以设置特定的HTTP响应头来禁止客户端缓存网页。

respone.addHeader("Paragma","no-cache");//适用于HTTP/1.0
或
response.setHeader("Cache-Control","no-cache");
或
response.setHeader("Expires","0");

4.7 使用Annotation标注配置Servlet

import javax.servlet.http.HttpServlet;

@WebServlet(name = "annotationServlet", //servlet名字
            urlPatterns = {"/annotation"},//servlet访问路径
        initParams = {@WebInitParam(name = "color",value = "blue"),
        @WebInitParam(name = "size",value = "15")})//初始化参数
public class AnnotationServlet extends HttpServlet {
    ...
}

@WebServlet注解各个属性的用法

属性类型                  描述
nameString指定Servlet的名字,等价于<servlet-name>,如果没有,则默认为类的全限定名
urlPatternsString[]指定一组Servlet的URL匹配模式,<url-patterns>
loadOnStartupint指定Servlet的加载顺序
initParamsWebInitParam[]指定初始化参数
descriptionString描述Servelt,<description>
displayNameString指定Servlet的显示名,<desplay-name>

4.8 处理HTTP请求参数中的中文字符编码

  • 对读取到的请求参数进行字符编码转换
String username = request.getParameter("username");
username = new String(username.getBytes("ISO-8859-1"),"GBK");
  • 对于POST请求,采用如下方式
request.setCharacterEncoding("GBK");
  • 利用ServletContext对象的getRequestCharacterEncoding()和setRequestCharacterEncoding()方法来读取或设置当前Web应用中请求正文数据的字符编码。
  • Tocmat的server.xml配置文件中连接器进行配置。
<Connector port="8080" redirectPort="8443" connectionTimeout="20000" protocol="HTTP/1.1"  URIEncoding="UTF-8"/>
  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值