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(); } }
注意到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); } }
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); } }
上面代码的运行结果入下
/FirstServlet/servlet/*
/FirstServlet
/servlet
/*

浙公网安备 33010602011771号