首页 > 代码库 > Servlet&JSP学习笔记:第一个Servlet程序
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。
Servlet&JSP学习笔记:第一个Servlet程序