Java Servlet(一)

纸上得来终觉浅

1 什么是Servlet和Servlet容器?

Servlet就是运行服务端的java小程序,侠义上它是一个接口Servlet,广义上指所有实现了该接口的类;

Servlet容器就是能够运行Servlet、JSP、Filter等的软件环境,可以创建Servlet并且调用其相关生命周期方法,如Tomcat

2 Servlet接口

2.1 当我们继承该接口时,发现它包含了五个方法,如下:

public class HelloServlet implements Servlet{
	/*Servlet关闭时要执行的方法,整个Servlet生命周期只执行一次*/
	@Override
	public void destroy() {
	}
	/*获得Servlet的配置信息
	 * 一般在init方法之后就可以获得 
	 */
	@Override
	public ServletConfig getServletConfig() {
		return null;
	}
	/*获得Servlet的作者信息*/
	@Override
	public String getServletInfo() {
		return null;
	}
	/*Servlet第一次运行时要执行的方法,整个生命周期只执行一次
	 *ServletConfig是Servlet的一些配置信息 
	 */
	@Override
	public void init(ServletConfig arg0) throws ServletException {
	}
	/*每次调用Servlet时执行的方法*/
	@Override
	public void service(ServletRequest arg0, ServletResponse arg1) throws ServletException, IOException {
	}
}

2.2 有一个已经存在的类,GenericServlet,它继承了Servlet,ServletConfig,Serializable接口;

上面已经说了Servlet接口,下面说一下ServletConfig接口,它的方法如下:

<pre name="code" class="java">public interface ServletConfig {
    /*获取Servlet的名字*/
    public String getServletName();
    /*获取Servlet的上下文信息*/
    public ServletContext getServletContext();
    /*获得Servlet的初始化参数对应的值*/
    public String getInitParameter(String name);
    /*获得Servlet所有的初始化参数*/
    public Enumeration<String> getInitParameterNames();
}

 还有一个接口是序列化接口,前面已经说了,它是用来实现序列化的。 

GenericServlet类的实现如下:

public abstract class GenericServlet implements Servlet, ServletConfig,
        java.io.Serializable {
    private static final long serialVersionUID = 1L;
    private transient ServletConfig config;
    public GenericServlet() {
    }
    @Override
    public void destroy() {
    }
    @Override
    public String getInitParameter(String name) {
        return getServletConfig().getInitParameter(name);
    }
    @Override
    public Enumeration<String> getInitParameterNames() {
        return getServletConfig().getInitParameterNames();
    }
    @Override
    public ServletConfig getServletConfig() {
        return config;
    }
    @Override
    public ServletContext getServletContext() {
        return getServletConfig().getServletContext();
    }
    @Override
    public String getServletInfo() {
        return "";
    }
    @Override
    public void init(ServletConfig config) throws ServletException {
        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);
    }
    @Override
    public abstract void service(ServletRequest req, ServletResponse res)
            throws ServletException, IOException;
    @Override
    public String getServletName() {
        return config.getServletName();
    }
}
已经实现了获得ServletConfig,获得ServletContext,获得初始化参数等,所以使用时,直接继承这个类,只需要重写service方法即可,用起来很方便。

2.3 既然有了GenericServlet这个不错的方法,就可以继承然后重写service即可,但是如果我们要获得Http的相关信息,就要把servletrequest转化为httpServletRequest,而且如果要根据http的请求不同,做不同的处理,还要根据请求的方法进行判断; 我们每次写Servlet都会遇到这些问题;

现在有一个类HttpServlet,继承了GenericServlet,并且做了更多的事情,解决了刚刚提到的那些问题:

它在进行service处理的时候,先进行请求和回应的类型转换:

    public void service(ServletRequest req, ServletResponse res)
        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");
        }
        service(request, response);
    }
然后根据请求方法的类型,调用不同的处理方法:

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

所以只需要重写doGet,doPost,doHead方法即可;

3.所以在写Servlet的时候,只需要继承httpServlet就可以了,如果想在初始化或者关闭Servlet等方法中进行一些操作,直接重写就可以了;

3.1下面是一个例子:

Web.xml:

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd" id="WebApp_ID" version="3.0">
  <display-name>roadArchitectWeb</display-name>

<!-- 配置和映射 Servlet -->
	<servlet>
		<!-- Servlet 注册的名字 -->
		<servlet-name>helloServlet</servlet-name>
		<!-- Servlet 的全类名 -->
		<servlet-class>roadArchitectWeb.Test.HelloServlet</servlet-class>
		<!-- 配置 Serlvet 的初始化参数。 且节点必须在 load-on-startup 节点的前面 -->
		<init-param>
			<!-- 参数名 -->
			<param-name>user</param-name>
			<!-- 参数值 -->
			<param-value>root</param-value>
		</init-param>
		<init-param>
			<param-name>password</param-name>
			<param-value>123456</param-value>
		</init-param>
<!-- 可以指定 Serlvet 被创建的时机. 若为负数, 则在第一次请求时被创建.若为 0 或正数, 则在当前 WEB 应用被 -->
<!-- Serlvet 容器加载时创建实例, 且数组越小越早被创建.  -->
		<load-on-startup>0</load-on-startup>
	</servlet>
	
	<servlet-mapping>
		<!-- 需要和某一个 servlet 节点的 serlvet-name 子节点的文本节点一致 -->
		<servlet-name>helloServlet</servlet-name>
		<!-- 映射具体的访问路径: / 代表当前 WEB 应用的根目录. -->
		<url-pattern>/hello</url-pattern>
	</servlet-mapping>

</web-app>
HelloServlet:

package roadArchitectWeb.Test;

import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

public class HelloServlet extends HttpServlet{
	private static final long serialVersionUID = 1L;
	@Override
	public void init() throws ServletException {
		System.out.println("HelloServlet.init()");
	}
	@Override
	protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
		System.out.println("HelloServlet.doGet() req.getMethod():"+req.getMethod());
		System.out.println("HelloServlet.doGet() getInitParameter():"+getInitParameter("user"));
		System.out.println("HelloServlet.doGet() getInitParameterNames():"+getInitParameterNames());
		System.out.println("HelloServlet.doGet() getServletName():"+getServletName());
		/*getServletConfig返回ServletConfig对象,这个对象还有很多其他方法*/
		System.out.println("HelloServlet.doGet() getServletConfig().toString():"+getServletConfig().toString());
		/*getServletContext返回ServletContext对象,这个对象也有很多其他方法*/
		System.out.println("HelloServlet.doGet() getServletContext().getContextPath():"+getServletContext().getContextPath());
	}
	@Override
	protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
	System.out.println("HelloServlet.doPost():"+req.getMethod());
	}
	@Override
	public void destroy() {
		System.out.println("HelloServlet.destroy()");
	}
}
3.2 下面梳理下一些规则(Servlet还有Filter等其实没什么东西,都是些规则而已,实践下就可以了)

A:上面的load-on-startup值为0 ,所以在tomcat启动的时候已经开始加载了,如果把它设为-1,则在第一次请求的时候加载,如:


B:同一个Servlet可以被映射到多个URL上,即多个 <servlet-mapping> 元素的<servlet-name>子元素的设置值可以是同一个Servlet的注册名。 

<servlet-mapping>
		<!-- 需要和某一个 servlet 节点的 serlvet-name 子节点的文本节点一致 -->
		<servlet-name>helloServlet</servlet-name>
		<!-- 映射具体的访问路径: / 代表当前 WEB 应用的根目录. -->
		<url-pattern>/hello</url-pattern>
	</servlet-mapping>
	
		<servlet-mapping>
		<!-- 需要和某一个 servlet 节点的 serlvet-name 子节点的文本节点一致 -->
		<servlet-name>helloServlet</servlet-name>
		<!-- 映射具体的访问路径: / 代表当前 WEB 应用的根目录. -->
		<url-pattern>/heihei</url-pattern>
	</servlet-mapping>
那么在请求hello和heihei的时候,执行同样的servlet,结果当然也是一样的;

C:在Servlet映射到的URL中也可以使用 * 通配符,但是只能有两种固定的格式:一种格式是“*.扩展名”,另一种格式是以正斜杠(/)开头并以“/*”结尾。

Servlet的基础部分大概就是这些

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值