servlet

Servlet底层实现和生命周期

servlet是一个接口,GenericServlet实现了servlet中的四个方法,service方法除外。目的是让子类实现。其中,有获取参数,Servlet名字,配置,上下文等方法。

当浏览器发来请求报文的时候,servlet先调用init方法对servlet实例初始化,然后可以在service方法中处理请求和响应。

/*
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
 *
 * Copyright (c) 1997-2010 Oracle and/or its affiliates. All rights reserved.
 *
 * The contents of this file are subject to the terms of either the GNU
 * General Public License Version 2 only ("GPL") or the Common Development
 * and Distribution License("CDDL") (collectively, the "License").  You
 * may not use this file except in compliance with the License.  You can
 * obtain a copy of the License at
 * https://glassfish.dev.java.net/public/CDDL+GPL_1_1.html
 * or packager/legal/LICENSE.txt.  See the License for the specific
 * language governing permissions and limitations under the License.
 *
 * When distributing the software, include this License Header Notice in each
 * file and include the License file at packager/legal/LICENSE.txt.
 *
 * GPL Classpath Exception:
 * Oracle designates this particular file as subject to the "Classpath"
 * exception as provided by Oracle in the GPL Version 2 section of the License
 * file that accompanied this code.
 *
 * Modifications:
 * If applicable, add the following below the License Header, with the fields
 * enclosed by brackets [] replaced by your own identifying information:
 * "Portions Copyright [year] [name of copyright owner]"
 *
 * Contributor(s):
 * If you wish your version of this file to be governed by only the CDDL or
 * only the GPL Version 2, indicate your decision by adding "[Contributor]
 * elects to include this software in this distribution under the [CDDL or GPL
 * Version 2] license."  If you don't indicate a single choice of license, a
 * recipient has the option to distribute your version of this file under
 * either the CDDL, the GPL Version 2 or to extend the choice of license to
 * its licensees as provided above.  However, if you add GPL Version 2 code
 * and therefore, elected the GPL Version 2 license, then the option applies
 * only if the new code is made subject to such option by the copyright
 * holder.
 *
 *
 * This file incorporates work covered by the following copyright and
 * permission notice:
 *
 * Copyright 2004 The Apache Software Foundation
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package javax.servlet;

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

/**
 *
 * Defines a generic, protocol-independent
 * servlet. To write an HTTP servlet for use on the
 * Web, extend {@link javax.servlet.http.HttpServlet} instead.
 *
 * <p><code>GenericServlet</code> implements the <code>Servlet</code>
 * and <code>ServletConfig</code> interfaces. <code>GenericServlet</code>
 * may be directly extended by a servlet, although it's more common to extend
 * a protocol-specific subclass such as <code>HttpServlet</code>.
 *
 * <p><code>GenericServlet</code> makes writing servlets
 * easier. It provides simple versions of the lifecycle methods 
 * <code>init</code> and <code>destroy</code> and of the methods 
 * in the <code>ServletConfig</code> interface. <code>GenericServlet</code>
 * also implements the <code>log</code> method, declared in the
 * <code>ServletContext</code> interface. 
 *
 * <p>To write a generic servlet, you need only
 * override the abstract <code>service</code> method. 
 *
 *
 * @author 	Various
 */

 
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;
    

    /**
     *
     * Does nothing. All of the servlet initialization
     * is done by one of the <code>init</code> methods.
     *
     */
    public GenericServlet() { }
    
    
    /**
     * Called by the servlet container to indicate to a servlet that the
     * servlet is being taken out of service.  See {@link Servlet#destroy}.
     *
     * 
     */
    public void destroy() {
    }
    
    
    /**
     * Returns a <code>String</code> containing the value of the named
     * initialization parameter, or <code>null</code> if the parameter does
     * not exist.  See {@link ServletConfig#getInitParameter}.
     *
     * <p>This method is supplied for convenience. It gets the 
     * value of the named parameter from the servlet's 
     * <code>ServletConfig</code> object.
     *
     * @param name 		a <code>String</code> specifying the name 
     *				of the initialization parameter
     *
     * @return String 		a <code>String</code> containing the value
     *				of the initialization parameter
     *
     */ 
    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);
    }
    
    
   /**
    * Returns the names of the servlet's initialization parameters 
    * as an <code>Enumeration</code> of <code>String</code> objects,
    * or an empty <code>Enumeration</code> if the servlet has no
    * initialization parameters.  See {@link
    * ServletConfig#getInitParameterNames}.
    *
    * <p>This method is supplied for convenience. It gets the 
    * parameter names from the servlet's <code>ServletConfig</code> object. 
    *
    *
    * @return Enumeration 	an enumeration of <code>String</code>
    *				objects containing the names of 
    *				the servlet's initialization parameters
    */
    public Enumeration<String> getInitParameterNames() {
        ServletConfig sc = getServletConfig();
        if (sc == null) {
            throw new IllegalStateException(
                lStrings.getString("err.servlet_config_not_initialized"));
        }

        return sc.getInitParameterNames();
    }   
     

    /**
     * Returns this servlet's {@link ServletConfig} object.
     *
     * @return ServletConfig 	the <code>ServletConfig</code> object
     *				that initialized this servlet
     */    
    public ServletConfig getServletConfig() {
	return config;
    }
 
    
    /**
     * Returns a reference to the {@link ServletContext} in which this servlet
     * is running.  See {@link ServletConfig#getServletContext}.
     *
     * <p>This method is supplied for convenience. It gets the 
     * context from the servlet's <code>ServletConfig</code> object.
     *
     *
     * @return ServletContext 	the <code>ServletContext</code> object
     *				passed to this servlet by the <code>init</code>
     *				method
     */
    public ServletContext getServletContext() {
        ServletConfig sc = getServletConfig();
        if (sc == null) {
            throw new IllegalStateException(
                lStrings.getString("err.servlet_config_not_initialized"));
        }

        return sc.getServletContext();
    }


    /**
     * Returns information about the servlet, such as 
     * author, version, and copyright. 
     * By default, this method returns an empty string.  Override this method
     * to have it return a meaningful value.  See {@link
     * Servlet#getServletInfo}.
     *
     *
     * @return String 		information about this servlet, by default an
     * 				empty string
     */    
    public String getServletInfo() {
	return "";
    }


    /**
     * Called by the servlet container to indicate to a servlet that the
     * servlet is being placed into service.  See {@link Servlet#init}.
     *
     * <p>This implementation stores the {@link ServletConfig}
     * object it receives from the servlet container for later use.
     * When overriding this form of the method, call 
     * <code>super.init(config)</code>.
     *
     * @param config 			the <code>ServletConfig</code> object
     *					that contains configutation
     *					information for this servlet
     *
     * @exception ServletException 	if an exception occurs that
     *					interrupts the servlet's normal
     *					operation
     * 
     * @see 				UnavailableException
     */
    public void init(ServletConfig config) throws ServletException {
	this.config = config;
	this.init();
    }


    /**
     * A convenience method which can be overridden so that there's no need
     * to call <code>super.init(config)</code>.
     *
     * <p>Instead of overriding {@link #init(ServletConfig)}, simply override
     * this method and it will be called by
     * <code>GenericServlet.init(ServletConfig config)</code>.
     * The <code>ServletConfig</code> object can still be retrieved via {@link
     * #getServletConfig}. 
     *
     * @exception ServletException 	if an exception occurs that
     *					interrupts the servlet's
     *					normal operation
     */
    public void init() throws ServletException {

    }
    

    /**
     * Writes the specified message to a servlet log file, prepended by the
     * servlet's name.  See {@link ServletContext#log(String)}.
     *
     * @param msg 	a <code>String</code> specifying
     *			the message to be written to the log file
     */     
    public void log(String msg) {
	getServletContext().log(getServletName() + ": "+ msg);
    }
   
   
    /**
     * Writes an explanatory message and a stack trace
     * for a given <code>Throwable</code> exception
     * to the servlet log file, prepended by the servlet's name.
     * See {@link ServletContext#log(String, Throwable)}.
     *
     *
     * @param message 		a <code>String</code> that describes
     *				the error or exception
     *
     * @param t			the <code>java.lang.Throwable</code> error
     * 				or exception
     */   
    public void log(String message, Throwable t) {
	getServletContext().log(getServletName() + ": " + message, t);
    }
    
    
    /**
     * Called by the servlet container to allow the servlet to respond to
     * a request.  See {@link Servlet#service}.
     * 
     * <p>This method is declared abstract so subclasses, such as 
     * <code>HttpServlet</code>, must override it.
     *
     * @param req 	the <code>ServletRequest</code> object
     *			that contains the client's request
     *
     * @param res 	the <code>ServletResponse</code> object
     *			that will contain the servlet's response
     *
     * @exception ServletException 	if an exception occurs that
     *					interferes with the servlet's
     *					normal operation occurred
     *
     * @exception IOException 		if an input or output
     *					exception occurs
     */

    public abstract void service(ServletRequest req, ServletResponse res)
	throws ServletException, IOException;
    

    /**
     * Returns the name of this servlet instance.
     * See {@link ServletConfig#getServletName}.
     *
     * @return          the name of this servlet instance
     */
    public String getServletName() {
        ServletConfig sc = getServletConfig();
        if (sc == null) {
            throw new IllegalStateException(
                lStrings.getString("err.servlet_config_not_initialized"));
        }

        return sc.getServletName();
    }
}

HttpServlet继承了GenericServlet,增加了doGet,doPost,doOptions等等do方法。在其service方法中对请求类型进行了细分,由各种do方法分别处理不同的请求类型。

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 = req.getDateHeader(HEADER_IFMODSINCE);
                if (ifModifiedSince < lastModified) {
                    // 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);
        }
    }
    

生命周期

创建

servlet实例默认在这个地址第一次被访问的时候创建。

也可以在服务器启动的时候创建,在xml文件中设置其在服务器启动之后创建。

<load-on-startup>在servlet标签中。

<load-on-startup>1</load-on-startup>标签中的数字越小越先被创建。

初始化

实例创建之后默认先调用init()方法,所以可以在init方法中进行初始化操作。

 String username = getServletConfig().getInitParameter("username");
String password = getServletConfig().getInitParameter("password");
//

执行

由于servlet在服务器启动的时候就创建,而且是单例,每个@Webservlet对应一个实例。因此这也是线程不安全的。

销毁

在服务器正常关闭时会调用destroy方法销毁所有servlet实例。

获取信息

获取参数的value或values

String name = req.getParameter("name");
String[] names = req.getParameterValues("name");

获取参数的name

 Enumeration<String> parameterNames = req.getParameterNames();
while (parameterNames.hasMoreElements()){
String s = parameterNames.nextElement();
System.out.println(s);
Enumeration是个接口,类似迭代器

乱码问题

避免乱码的方法:

      doPost中

           req.setCharactorEncoding("utf-8");

           resp.setCharactorEncoding("utf-8");

                          +

           resp.setContentType("text/plain; charset = utf-8");   或者

            resp.setContentType("text/html; charset = utf-8");   或者

             resp.setContentType("application; charset = utf-8");

内部跳转

 RequestDispatcher requestDispatcher = req.getRequestDispatcher("/路径");
        requestDispatcher.forward(req,resp);

路径可以是html页面,也能是另一个servlet。

重定向

resp.sendRedirect("/路径");

响应对象调用此方法可以重定向。过程是把新的路径(可以是html也可以是servlet)发送给浏览器,浏览器重新访问新地址。

服务器内部跳转:
使用request完成
跳转的本质是在服务器内部把请求和响应进行转发,转发给下一个指定的资源
如果request中有数据,在跳转到的下一个资源中是可以拿到这个数据,因为只有一个request请求
对象
由于服务器跳转是把请求和响应在服务器内部中进行转发,所以浏览器的地址栏中的地址是不受影
响的,始终还是第一次发出请求的地址,其实浏览器根本就不知道服务器内部的请求转发情况
在设置跳转的资源地址的时候,路径的前面一般要加上/,例如  String path = "/hello.html";
 
客户端重定向:
使用response完成
重定向的本质是把新的资源路径返回给浏览器,让浏览器向这个新地址发送一个新请求
此处是利用了响应的状态码302和响应头信息中的Location字段来完成
如果request中有数据,重定向后在新的资源中是拿不到这个数据的,因为重定向会发出新的请求,
但是数据在上一个老的请求中
由于重定向让浏览器发出新的请求,所以浏览器地址栏中的地址会变成新请求的地址
在设置重定向的资源地址的时候,路径的前面一般不加/
例如, String path = "hello.html";
但是如果一定要加/的话,那么还需要额外加上一个项目名
例如, String path = "/servlet/hello.html";
同时也可以动态获取项目: req.getContextPath()
例如, String path = req.getContextPath()+"/hello.html"

上下文

       //通过request对象获取ServletContext对象
        ServletContext servletContext = getServletContext();

        String contextPath = servletContext.getContextPath();
        System.out.println("contextPath = "+contextPath);

        String realPath = servletContext.getRealPath("/Test");
        System.out.println("realPath = "+realPath);

req.getServletContext().getContextPath()获取上下文路径。

req.getServletContext().getRealtPath()获取真实路径。

路径问题

改变路径的方式:

  1.在html的<a href=""/>中直接修改

             这是相对路径。同级目录直接  href = “文件名“,退回上级目录是   ../     。

   2.在head中添加base标签

            <base  href = "..."/>

             此时再在此页面跳转时,默认路径就是base中的路径。

    3.项目部署后,在server.xml文件中,可以更改Context标签中的path标签。

Servlet中三个范围对象

request: 生存于一次请求中

session:  默认伴生于打开浏览器的第一次请求,默认生存时间三十分钟,可以设置时长。

application:  生存于整个服务器开启时间。

获取方式:

request对象默认在第一次访问服务器时创建。也就是service方法参数中的HttpRequest

HttpSession session = req.getSession();
ServletContext application = req.getServletContext();

所有三个对象都能用  .setAtrribute(key,value)设置属性值。

getAttribute()获取属性,removeAttribute()删除属性。

Cookie

浏览器第一次向服务器发送请求时,会携带cookie信息于请求头中。

服务器接收到访问请求,session对象被创建,session对象的id会保存在cookie中,在response中发送回浏览器。这样,下次浏览器进行访问的时候,由于携带了cookie信息,知道对应的session的id,就能和唯一的session匹配上。

new Cookie(String , String)指定key和Value,

resp.addCookie(cookie名);可以将cookie添加到响应中。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值