首页 > 代码库 > Servlet&JSP学习笔记:第一个Servlet程序

Servlet&JSP学习笔记:第一个Servlet程序

第一个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。

 

Servlet&JSP学习笔记:第一个Servlet程序