JSP&Servlet学习笔记02

第二章 编写和设置Servlet

  第一个servlet程序

package cc.openhome;

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("/hello.view")
public class HelloServlet extends HttpServlet /* 继承HttpServlet */ {
    private static final long serialVersionUID = 1L;

    public HelloServlet() {
    }

    // 重写doGet()方法
    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        // 设置响应内容类型
        response.setContentType("text/html;charset=utf-8");
        // 取得响应输出对象
        PrintWriter out = response.getWriter();
        // 取得请求参数
        String name = request.getParameter("name");
        
        out.println("<html>");
        out.println("<head>");
        out.println("<title>Hello Servlet</title>");
        out.println("</head>");
        out.println("<body>");
        out.println("<h1> Hello! " + name + " !<h1>");
        out.println("</body>");
        out.println("</html>");
        out.close();
    }
}
View Code

注意到HelloServlet.java中import语句区段:

import javax.servlet.ServletException;

import javax.servlet.annotation.WebServlet;

import javax.servlet.http.HttpServlet;

import javax.servlet.http.HttpServletRequest;

import javax.servlet.http.HttpServletResponse;

  如果要编译HelloServlet.java,则类路径(classpaht)中必须包括servletAPI的相关类,即tomcat目录的lib子包中的servlet-api.jar。 假设HelloServlet.java位于src目录下,并放置于对应包的目录中,则可以像如下这样进行编译

javac -classpath d:\apache-tomcat-7.0.54-windows-x64\apache-tomcat-7.0.54\lib\servlet-api.jar -d  ./classes src/cc/openhome/HelloServlet.java

 

为什么要在继承HttpServlet之后重新定义doGet()? 又为什么HTTP请求为Get时会自动调用doGet()? 

从上图中我们可以发现,实现Servlet接口的类是GenerciServlet类,它还实现了ServletConfig接口,将容器调用init()方法时传入的ServletConfig实例封装起来,而service()方法直接表示为abstract而没有任何实现。并且GenericServlet并没有规范任何有关HTTP的相关方法,而是由它继承它的HttpServlet来定义。在最初定义Servlet时,并不限定它只能用于HTTP,所以并没有将HTTP相关服务流程定义在GenericServlet之中,而是定义在HttpServlet的service方法中。当请求到来时,容器会调用Servlet的service()方法,可以看到,HttpServlet的service()中定义的就是判断HTTP请求的方式,再分别调用doGet()、doPost()等方法,所以若想针对GET、POST等方法进行处理,才会需要在继承HttpServlet之后,重新定义相对应的doGet()、doPost()方法

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

2.2 使用@WebServlet

  编写好Servlet之后,接下来要高斯Web容器有关这个Servlet的一些信息。在Servlet3.0中,可以使用标注(Annotation)来告知容器哪些Servlet会提供服务以及额外信息。例如在HelloServlet.java中的

@WebServlet("/hello.view")

public class HelloServlet extends HttpServlet{

只要在Servlet上设置@WebServlet标注,容器就会自动读取当中的信息,上面的@WebServlet告诉容器,如果请求的URL时"/hello.view",则由HelloServlet的实例提供服务。可以使用@WebServlet提供更多的信息。

如 @WebServlet(

    name="Hello",

    urlPattern={"/hello.view"},

    loadOnStartup=1

  )

  该注解告知容器,HelloServlet这个Servlet的名称是Hello,这是由name属性决定的,而如果客户端请求的url是/hello.view, 则由具Hello名称的Servlet来处理,这是由rulPattern属性决定的。

2.2.3 文件的组织与部署

  Web容器要求应用程序部署时,要按照下图结构进行组织

WEB-INF : 这个目录名称是固定的,而且一定是位于应用程序的根目录下,放置在WEB-INF中的文件,对外界来说是封闭的,也就是客户端无法使用HTTP的任何方式直接访问到WEB-INF中的文件或目录。如有需要访问,则必须通过Servlet/JSP的请求转发方式(Forward)。

web.xml:这是web应用程序部署描述文件,一定是放在WEB-INF根目录下,名称一定是web.xml。

lib:放置jar文件的目录,一定放在WEB-INF根目录下,名称必须是lib

classes:放置编译后.class文件的目录,一定是放在WEB-INF目录下,名称一定是classes,编译过后的类文件,必须有包名称相符的目录结构。

2.3  进阶部署设置

2.3.1 URL模式设置

  一个请求URI实际上由三个部分组成的:

    requestURI = contextPath + servletPath + pathInfo

    1. 环境路径:

      URI该路径可以使用HttpServletRequest的getRequestURI()来取得这项信息,其中contextPath是环境路径(ContextPath),是容器用来决定挑选哪个Web应用程序的依据,不同服务器该路径可能不同

      contextPath可以由HttpServletRequest的getContextPath()来取得环境路径。如果应用程序环境路径与Web服务器环境根路径相同,则应用程序环境路径为空字符串,如果不是,则应用程序环境路径以"/"开头,不包括"/"结尾。

    2. Servlet路径

       该部分指的是Servlet路径(Servlet path),不包括路径信息(PathInfo)与请求参数,Servlet路径直接对应至URL模式信息,可用HttpServletRequest的getServletPath()获得,以"/"开头,但是"/*"与“”的URL模式比对而来的请求除外,在/*与“”的情况下,getServletPath()取得的Servlet路径是空字符串。例如某个请求时根据/hello.do对应至某个Servlet,则getServletPath()取得的ServletPath就是/hello.do/ 如果通过/servlet/*对应的,则getServletPath()取得的Servlet路径就是/servlet,但如果时通过/*或“”对应的,取得的就是空字符串

    3. 路径信息

      路径信息指的是不包括请求参数、环境路径以及Servlet路径之外的路径信息,可以通过HttpServletRequest的getPathInfo()来取得。如果没有额外的路径信息,则为null,预设Servlet、完全匹配的情况下,getPathInfo()就会取得null,如果由额外信息,则是以"/开头的字符串"

package cc.openhome;

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("/servlet/*")
public class PathServlet extends HttpServlet {
    private static final long serialVersionUID = 1L;

    public PathServlet() {
        super();
    }

    protected void doGet(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        PrintWriter out = response.getWriter();
        out.println("<html>");
        out.println("<head>");
        out.println("<title>Servlet Pattern</title>");
        out.println("</head>");
        out.println("<body>");
        out.println(request.getRequestURI() + "<br>");
        out.println(request.getContextPath() + "<br>");
        out.println(request.getServletPath() + "<br>");
        out.println(request.getPathInfo());
        out.println("</body>");
        out.println("</html>");
    }

    protected void doPost(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        doGet(request, response);
    }

}
View Code

 

上面代码的运行结果入下

/FirstServlet/servlet/*
/FirstServlet
/servlet
/* 

posted @ 2018-12-13 22:29  llyanhuo  阅读(263)  评论(0)    收藏  举报