Java EE之Servlet

1.创建Servlet类

Servlet在Java EE API规范中的定义:
Servlet是一个运行在Web服务器中的Java小程序。Servlet将会接收和响应来自Web客户端的请求,使用HTTP(超文本传输协议)进行通信。
Servlet是所有Web应用程序的核心类。
运行应用程序的Web容器将会有一个或多个内建的Servlet。这些Servlet将用于处理JavaServer Pages、显示目录列表和访问静态资源。

所有的Servlet都实现了javax.serlvet.Servlet接口,但通常不是直接实现的。Servlet只是一个简单接口,它包含了初始化并销毁Servlet和处理请求的方法。

在大多数情况下,Servlet都继承自javax.servlet.GenericServlet。GenericServlet仍然是一个不依赖于具体协议的Servlet,它只包含了一个抽象的service方法。
作为响应HTTP请求的java.servlet.http.HttpServlet,它继承了GenericServlet,并实现了只接受HTTP请求的service方法。然后,它提供了响应每种HTTP方法类型的方法的空实现。

HttpServlet的方法接受的是javax.servlet.http.HttpServletRequestjavax.servlet.http.HttpServletResponse参数,而不是javax.servlet.ServletRequestjavax.servlet.ServletResponse,这样它就可以轻松访问Servlet服务所处理的请求中的HTTP特定的特性。

package com.wrox;

import javax.servlet.http.HttpServlet;

public class HelloServlet extends HttpServlet
{

}
//为了可以编译该代码,需要将Java EE Servlet API库添加到编译类路径上。

任何未重写的HTTP Servlet方法都将返回一个HTTP状态405作为响应。如果一个Servlet不处理任何请求,当然它就是无用的。

//重写doGet()方法
package com.wrox;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

@SuppressWarnings("serial")
public class HelloServlet extends HttpServlet
{
    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException
    {
        //下面没有调用PringtWriter的close方法。一般来说,在Java中只需要关闭自己创建
        //的资源即可。Web容器创建了该资源,所以它也会负责关闭该资源。
        response.getWriter().println("Hello, World!");
    }
}

注意,不需要担心任何原生HTTP请求或响应的细节。Web容器将会处理请求的解释,并从套接字(socket)中读取请求头和参数。在Servlet的方法返回之后,Web容器还将格式化响应头和主体,并写回套接字中。
使用初始化方法和销毁方法

    @Override
    public void init() throws ServletException
    {
        System.out.println("Servlet " + this.getServletName() + " has started.");
    }

    @Override
    public void destroy()
    {
        System.out.println("Servlet " + this.getServletName() + " has stopped.");
    }

GenericServlet实现了javax.servlet.Servlet接口中的init(ServletConfig config)方法,所以不需要在自己的init方法实现中调用super.init(servletConfig)

可以使用init方法读取属性文件,或者使用JDBC连接数据库。init方法将在Servlet启动时调用。
如果将Servlet配置为在Web应用程序部署和启动时自动启动,那么它的init方法也将会被调用。否则,init方法将在第一次请求访问它接收的Servlet时调用。
同样地,destroy在Servlet不再接受请求之后立即调用。这通常发生在Web应用程序被停止或卸载,或者Web容器关闭时。总是应该使用destroy方法清理Servlet持有的资源。

2.配置可部署的Servlet

部署描述符将指示Web容器如何部署应用程序。尤其是它定义了应用程序中所有的监听器、Servlet和过滤器,以及应用程序所应使用的设置。

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee
                             http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd"
         version="3.1">

    <display-name>Hello World Application</display-name>

    <servlet>
        <servlet-name>helloServlet</servlet-name>
        <servlet-class>com.wrox.HelloServlet</servlet-class>
    </servlet>

    <servlet-mapping>
        <servlet-name>helloServlet</servlet-name>
        <url-pattern>/greeting</url-pattern>
    </servlet-mapping>

</web-app>

上面的配置中<servlet><servlet-mapping>标签内的<servlet-name>标签应该一致。Web容器通过这种方式关联这两个配置。
可以将多个URL映射到相同的Servlet:

    <servlet-mapping>
        <servlet-name>helloServlet</servlet-name>
        <url-pattern>/greeting</url-pattern>
        <url-pattern>/salutation</url-pattern>
        <url-pattern>/wazzup</url-pattern>
    </servlet-mapping>

下面的<load-on-startup>1</load-on-startup>指示Web容器在应用程序启动之后立即启动Servlet。如果多个Servlet配置都包含了该标签,它们将按照标签内的值的大小顺序启动。如果两个或多个Servlet的<load-on-startup>配置相同,那么将按照它们在描述符文件中的出现顺序启动。

    <servlet>
        <servlet-name>helloServlet</servlet-name>
        <servlet-class>com.wrox.HelloServlet</servlet-class>
        <load-on-startup>1</load-on-startup>
    </servlet>

3.了解doGet、doPost和其他方法

3.1 在service方法执行的过程中

service方法的实现是非常复杂的,而且随着Web容器的不同,service方法的实现也会随之变化。
扩展HttpServlet的优点在于我们不需要担心其中的任何细节问题。
通过使用HttpServlet在各种不同方法中定义的HttpServletRequestHttpServletResponse参数,我们可以读取由客户端发送的参数、接受通过表单上传的文件、读取包含在请求正文中的原始数据、读取请求头和操作响应头,并将响应正文返回到客户端。

3.2 使用HttpServletRequest

HttpServletRequest接口是对ServletRequest的扩展。
HttpServletRequest最重要的功能是从客户端发送的请求中获取参数,请求参数有两种不同的形式:

  • 查询参数(URI参数)
  • application/x-www-form-urlencodedmultipart/form-data编码的请求正文
public interface ServletRequest {
    //...
    //getParameter方法将返回参数的单个值,如果参数有多个值,就返回第一个值。
    public String getParameter(String name);
    
    //getParameterNames方法返回所有可用参数的名字的枚举。
    public Enumeration<String> getParameterNames();
    
    //getParameterValues方法返回参数的值的数组,如果参数只有一个值,就返回只有一个元素的数组。
    public String[] getParameterValues(String name);
    
    //getParameterMap方法返回一个包含了所有参数名值对的 java.util.Map<String, String[]>
    public Map<String, String[]> getParameterMap();
    //...
}

有几个方法可用于帮助决定HTTP请求内容的类型、长度和编码。
方法getContentType将返回请求的MIME(多用途互联网邮件扩展)内容类型,例如 application/x-www-form-urlencodedapplication/jsontext/plainapplication/zip等。
MIME内容类型描述了数据的类型。
方法getContentLength返回请求正文的长度,以字节为单位。
方法getCharacterEncoding将返回请求内容的字符编码。

public interface HttpServletRequest extends ServletRequest {
    //...   
    //返回客户端用于创建请求的完整URL,包含协议(http或https)、服务器名称、端口号和服务器路径,但不包括查询字符串
    public StringBuffer getRequestURL();
    
    //它只返回URL中的服务器路径部分
    public String getRequestURI();
    
    //它只返回用于匹配Servlet映射的URL部分
    public String getServletPath();
    
    //返回指定名字的头数据
    public String getHeader(String name);
    
    //返回请求头中所有头数据的名字的枚举
    public Enumeration<String> getHeaderNames();
    
    //如果有某个特定的头的值一直是数字,那么可以调用该方法返回一个数字。
    public int getIntHeader(String name);
    
    //对于可以表示有效时间戳的头数据,该方法将返回一个Unix时间戳。
    public long getDateHeader(String name);
    //...
}

3.3 使用HttpServletResponse

HttpServletResponse接口继承了ServletResponse,HttpServletResponse可以设置响应头、编写响应正文、重定向请求、设置HTTP状态码以及将Cookies返回到客户端等任务。
方法getOutputStream将返回一个javax.servlet.ServletOutputStream,而方法getWriter将返回一个java.io.PrintWriter,通过它们都可以向响应中输出数据。
在向响应正文中输出数据时,可能需要设置内容类型或编码格式。可以通过setContentTypesetCharacterEncoding方法进行设置。如果计划在使用getWriter时调用setContentTypesetCharacterEncoding,那么必须在getWriter之前调用setContentTypesetCharacterEncoding,因为这样的getWriter方法返回的writer才能获得正确的字符编码设置。在getWriter调用之后调用的setContentTypesetCharacterEncoding将被忽略。
如果在调用getWriter之前未调用setContentTypesetCharacterEncoding,返回的writer将使用容器的默认编码。

方法sendRedirect将客户端重定向至另一个URL。

4.使用参数和接受表单提交

@WebServlet(
        name = "helloServlet",
        urlPatterns = {"/greeting", "/salutation", "/wazzup"},
        loadOnStartup = 1
)
public class HelloServlet extends HttpServlet
{
    private static final String DEFAULT_USER = "Guest";

    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException
    {
        //获取名为"user"的参数
        String user = request.getParameter("user");
        if(user == null)
            user = HelloServlet.DEFAULT_USER;

        //将响应的内容类型设置为text/html,将字符编码设置为UTF-8
        response.setContentType("text/html");
        response.setCharacterEncoding("UTF-8");

        //从响应中获得一个PrintWriter,并输出一个兼容于HTML5的文档
        PrintWriter writer = response.getWriter();
        writer.append("<!DOCTYPE html>\r\n")
              .append("<html>\r\n")
              .append("    <head>\r\n")
              .append("        <title>Hello User Application</title>\r\n")
              .append("    </head>\r\n")
              .append("    <body>\r\n")
              .append("        Hello, ").append(user).append("!<br/><br/>\r\n")
              .append("        <form action=\"greeting\" method=\"POST\">\r\n")
              .append("            Enter your name:<br/>\r\n")
              .append("            <input type=\"text\" name=\"user\"/><br/>\r\n")
              .append("            <input type=\"submit\" value=\"Submit\"/>\r\n")
              .append("        </form>\r\n")
              .append("    </body>\r\n")
              .append("</html>\r\n");
    }

    @Override
    protected void doPost(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException
    {
        //接收表单提交,将请求委托给doGet方法。
        this.doGet(request, response);
    }

    //...

接受多值参数的例子:

@WebServlet(
        name = "multiValueParameterServlet",
        urlPatterns = {"/checkboxes"}
)
public class MultiValueParameterServlet extends HttpServlet
{
    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException
    {
        response.setContentType("text/html");
        response.setCharacterEncoding("UTF-8");

        PrintWriter writer = response.getWriter();
        writer.append("<!DOCTYPE html>\r\n")
              .append("<html>\r\n")
              .append("    <head>\r\n")
              .append("        <title>Hello User Application</title>\r\n")
              .append("    </head>\r\n")
              .append("    <body>\r\n")
              .append("        <form action=\"checkboxes\" method=\"POST\">\r\n")
              .append("Select the fruits you like to eat:<br/>\r\n")
              .append("<input type=\"checkbox\" name=\"fruit\" value=\"Banana\"/>")
              .append(" Banana<br/>\r\n")
              .append("<input type=\"checkbox\" name=\"fruit\" value=\"Apple\"/>")
              .append(" Apple<br/>\r\n")
              .append("<input type=\"checkbox\" name=\"fruit\" value=\"Orange\"/>")
              .append(" Orange<br/>\r\n")
              .append("<input type=\"checkbox\" name=\"fruit\" value=\"Guava\"/>")
              .append(" Guava<br/>\r\n")
              .append("<input type=\"checkbox\" name=\"fruit\" value=\"Kiwi\"/>")
              .append(" Kiwi<br/>\r\n")
              .append("<input type=\"submit\" value=\"Submit\"/>\r\n")
              .append("        </form>")
              .append("    </body>\r\n")
              .append("</html>\r\n");
    }

    @Override
    protected void doPost(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException
    {
        String[] fruits = request.getParameterValues("fruit");

        response.setContentType("text/html");
        response.setCharacterEncoding("UTF-8");

        PrintWriter writer = response.getWriter();
        writer.append("<!DOCTYPE html>\r\n")
              .append("<html>\r\n")
              .append("    <head>\r\n")
              .append("        <title>Hello User Application</title>\r\n")
              .append("    </head>\r\n")
              .append("    <body>\r\n")
              .append("        <h2>Your Selections</h2>\r\n");

        if(fruits == null)
            writer.append("        You did not select any fruits.\r\n");
        else
        {
            writer.append("        <ul>\r\n");
            for(String fruit : fruits)
            {
                writer.append("        <li>").append(fruit).append("</li>\r\n");
            }
            writer.append("        </ul>\r\n");
        }

        writer.append("    </body>\r\n")
              .append("</html>\r\n");
    }
}

5.使用初始化参数配置应用程序

5.1 使用上下文初始化参数

在部署描述符中添加上下文初始化参数:

    <context-param>
        <param-name>settingOne</param-name>
        <param-value>foo</param-value>
    </context-param>
    <context-param>
        <param-name>settingTwo</param-name>
        <param-value>bar</param-value>
    </context-param>

在Servlet代码的任何地方都可以轻松获得和使用这些参数。

@WebServlet(
        name = "contextParameterServlet",
        urlPatterns = {"/contextParameters"}
)
public class ContextParameterServlet extends HttpServlet
{
    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException
    {
        ServletContext c = this.getServletContext();
        PrintWriter writer = response.getWriter();

        writer.append("settingOne: ").append(c.getInitParameter("settingOne"))
              .append(", settingTwo: ").append(c.getInitParameter("settingTwo"));
    }
}

应用程序中的所有Servlet都将共享这些初始化参数。在所有的Servlet中它们的值都是相同的。有时需要使某个设置只作用于某一个Servlet,那么就需要使用Servlet初始化参数。

5.2 使用Servlet初始化参数

public class ServletParameterServlet extends HttpServlet
{
    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException
    {
        //从ServletConfig对象中获取初始化参数
        ServletConfig c = this.getServletConfig();
        PrintWriter writer = response.getWriter();

        writer.append("database: ").append(c.getInitParameter("database"))
              .append(", server: ").append(c.getInitParameter("server"));
    }
}

部署描述符中的配置:

    <servlet>
        <servlet-name>servletParameterServlet</servlet-name>
        <servlet-class>com.wrox.ServletParameterServlet</servlet-class>
        <init-param>
            <param-name>database</param-name>
            <param-value>CustomerSupport</param-value>
        </init-param>
        <init-param>
            <param-name>server</param-name>
            <param-value>10.0.12.5</param-value>
        </init-param>
    </servlet>
    <servlet-mapping>
        <servlet-name>servletParameterServlet</servlet-name>
        <url-pattern>/servletParameters</url-pattern>
    </servlet-mapping>

猜你喜欢

转载自www.cnblogs.com/gzhjj/p/9132380.html