Servlet&JSP学习笔记:第一个Servlet程序
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 { 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(); } }
范例中继承了 HttpServlet,并重新定义了doGet()方法,当浏览器 GET 方法发送请求时,会调用此方法。
-
在doGet()方法上可以看到 HttpServletRequest 与 HttpServletResponse两个参数,容器接收到客户端的 HTTP 请求后,会收集 HTTP 请求中的信息,并分别创建代表请求与响应的 Java 对象,而后在调用 doGet() 时将这两个对象当作参数传入。可以从 HttpServletRequest 对象中取得有关的 HTTP 请求相关信息,在范例中是通过 HttpServletRequest 的 getParameter()并指定请求参数名称,来取得用户发送的请求参数。
-
由于 HttpServletResponse 对象代表对客户端的响应,因此可以通过其 setContentType()设置正确的内容类型。上面的例子是告诉浏览器,返回的响应要以text/html解析,而采取的字符编码是 UTF-8。接着使用 getWriter()方法取得代表响应输出的 PrintWriter对象,通过 PrintWriter 的 println()方法来对浏览器输出响应的文字信息,在范例中是输出 HTML 以及根据用户说声 Hello!
范例中继承了 HttpServlet,并重新定义了doGet()方法,当浏览器 GET 方法发送请求时,会调用此方法。
进一步思考:为什么要在继承 HttpServlet 之后重新定义 doGet()?有为什么 HTTP 请求为 GET 时会自动调用 doGet()?首先来看范例中看到的相关API架构图:
-
首先看到 Servlet 接口,它定义了 Servlet 应当有的基本行为。例如,与 Servlet 生命周期相关的 init()、destroy()方法,提供服务时所要使用到的 service()方法等。
-
实现 Servlet 接口的的类是 GenericServlet类,它实现了ServletConfig接口,将容器调用 init()方法是所传入的 ServletConfig 实例封装起来,而 service() 方法直接标示为 abstract 而没有任何的实现。
-
GenericServlet 并没有规范任何有关 HTTP 的相关方法,而是 由继承它的 HttpServlet 来定义。在最初定义 Servlet 时,并不限定它只能用于 HTTP,所以并没有将 HTTP 相关服务流程定义在 GenericServlet 之中,而是定义在 HttpServlet 的 service() 方法中。
HttpServlet 的 service() 方法中的流程大致如下:
protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { String method = req.getMethod(); if (method.equals(METHOD_GET)) { // 略... doGet(req, resp); // 略... } else if (method.equals(METHOD_HEAD)) { // 略... doHead(req, resp); } else if (method.equals(METHOD_POST)) { // 略... doPost(req, resp); } else if (method.equals(METHOD_PUT)) { // 略... } }
当请求来到时,容器会调用 Servlet 的 service() 方法。可以看到,HttpServlet 的 service()中定义的,基本上就是判断 HTTP 请求的方式,再分别调用 doGet()、doPost()等方法,所以若想针对 GET、POST等方法进行处理,才会只需要继承 HttpServlet 之后,重新定义相对应的 doGet()、doPost()方法。
使用WebServlet
在Servlet 3.0中可以使用标注(Annotation)来告知容器哪些 Servlet 会提供服务以及额外的信息。例如:
@WebServlet("/hello.view") public class HelloServlet extends HttpServlet {
只要在 Servlet 上设置 @WebServlet标注,容器就会自动读取当中的信息。上面的信息告诉容器,如果请求的URL是"/hello.view",则由 HttpServlet 的实例提供服务。
可以使用@WebServlet提供更多的信息。
@WebServlet { name="Hello", urlPatterns={"/hello.view"}, loadOnStartup=1 } public class HelloServlet extends HttpServlet {
上面的 @WebServlet 是告知容器,HttpServlet 这个 Servlet 的名称是 Hello,由 name 属性指定。如果客户请求的URL 是/hello.view,则由具有 Hello 名称的 Servlet 来处理,这有 urlPattern 来指定。如果没有设置属性,则默认值为 Servlet 的类完整名称。
应用程序启动后,并没有创建所有的 Servlet 实例。容器会在首次请求需要某个 Servlet 服务时,才将对应的 Servlet 类实例化、进行初始化操作,然后处理请求。这意味着第一次请求时必须等待 Servlet 类实例化、初始化动作。
如果希望应用程序启动时,就先将 Servlet 类载入、实例化并做好初始化动作,则可以使用loadOnStartup 设置。设置大于 0 的值(默认值为-1),表示启动应用程序后就要初始化 Servlet(而不是实例化几个 Servlet )。较小的数值先初始化。如果有多个 Servlet 在设置loadOnStartup时使用了相同的数字,则容器实现厂商自行决定载入哪个 Servlet。
郑重声明:本站内容如果来自互联网及其他传播媒体,其版权均属原媒体及文章作者所有。转载目的在于传递更多信息及用于网络分享,并不代表本站赞同其观点和对其真实性负责,也不构成任何其他建议。