Java Servlet学习笔记——2. ServletRequest、ServletResponse、ServletConfig、ServletContext与Http Servlets - Go语言中文社区

Java Servlet学习笔记——2. ServletRequest、ServletResponse、ServletConfig、ServletContext与Http Servlets


写在前面

在第一篇博客没有说的是,主要学习教程是《Servlet、JSP和Spring MVC初学指南》,只是感觉光看书没有记住,所以简单的做一下博客整理一下。

这篇博客的目的也是主要整理一下Servlet中的主要的类的常用方法与使用方法。见下:

ServletRequest

对于每一个HTTP请求, Servlet容器都会创建一个ServletRequest实例, 并将它传给Servlet的Service方法。ServletRequest封装了关于这个请求的信息。

ServletRequest接口中常用方法如下:

  1. public int getContentLength():返回请求主体的字节数。 如果不知道字节长度, 这个方法就会返回−1。
  2. public java.lang.String getContentType():返回请求主体的MIME类型, 如果不知道类型, 则返回null。
  3. public java.lang.String getParameter(java.lang.String name):返回指定请求参数的值。
  4. public java.lang.String getProtocol():返回这个HTTP请求的协议名称和版本。

其中,getParameter是在ServletRequest中最常用的方法。该方法通常用于返回HTML表单域的值。

getParameter也可以用于获取查询字符串的值。 例如, 利用下面的URI调用Servlet:

http://domain/context/servletName?id=123

用下面这个语句, 可以通过Servlet内部获取id值:

String id = request.getParameter("id");

注意, 如果该参数不存在, getParameter将返回null。

除了getParameter外, 还可以使用getParameterNames、 getParameterMap和getParameterValues获取表单域名、 值以及查询字符串。 这些方法的使用范例请可以参考后续“Http Servlets”小节。

ServletResponse

javax.servlet.ServletResponse接口表示一个Servlet响应。 在调用Servlet的Service方法前, Servlet容器首先创建一个ServletResponse, 并将它作为第二个参数传给Service方法。 ServletResponse隐藏了向浏览器发送响应的复杂过程。

在ServletResponse中定义的方法之一是getWriter方法, 它返回了一个可以向客户端发送文本的java.io.PrintWriter。 默认情况下, PrintWriter对象使用ISO-8859-1编码。

还有一个方法可以用来向浏览器发送输出, 它就是getOutputStream。 但这个方法是用于发送二进制数据的, 因此, 大多数情况使用的是getWriter, 而不是getOutputStream。我之前就是使用这个来向浏览器传递图片。

在发送任何HTML标签前, 应该先调用setContentType()方法, 设置响应的内容类型, 并将“text/html”作为一个参数传入。 这是在告诉浏览器,内容类型为HTML。 在没有内容类型的情况下, 大多数浏览器会默认将响应渲染成HTML。 但是, 如果没有设置响应内容类型, 有些浏器就会将HTML标签显示为普通文本。

在向客户端发送响应时, 大多数时候是将它作为HTML发送。 因此, 你必须非常熟悉HTML。

ServletConfig

ServletConfig代表当前Servlet在web.xml中的配置信息

当Servlet容器初始化Servlet时, Servlet容器会给Servlet的init方法传入一个ServletConfig。 ServletConfig封装可以通过@WebServlet或者部署描述符传给Servlet的配置信息。 这样传入的每一条信息就叫一个初始参数。 一个初始参数有key和value两个元件。

为了从Servlet内部获取到初始参数的值, 要在Servlet容器传给Servlet的init方法的ServletConfig中调用getInitParameter方法。

java.lang.String getInitParameter(java.lang.String name)

此外、getInitParameterNames方法则是返回所有初始参数名称的一个Enumeration:

java.util.Enumeration<java.lang.String> getInitParameterNames()

ServletConfig还提供了另一个很有用的方法:getServletContext。 利用这个方法可以从Servlet内部获取ServletContext。

下面有一个Servlet程序用来演示如何利用@WebServlet给Servlet传入初始属性,并通过getServletConfig()方法来获得ServletConfig,并显示:

package app01a;

import java.io.IOException;
import java.io.PrintWriter;
import javax.servlet.Servlet;
import javax.servlet.ServletConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.annotation.WebInitParam;
import javax.servlet.annotation.WebServlet;

@WebServlet(name="ServletConfigDemoServlet", urlPatterns= {"/servletConfigDemo"}, 
            initParams = {
                    @WebInitParam(name="admin", value="Harry Taciak"),
                    @WebInitParam(name="email", value="admin@example.com")
                }
            )
public class ServletConfigDemoServlet implements Servlet {

    private transient ServletConfig servletConfig;

    @Override
    public ServletConfig getServletConfig() {
        return servletConfig;
    }

    @Override
    public void init(ServletConfig servletConfig) throws ServletException {
        this.servletConfig = servletConfig;
    }

    @Override
    public void service(ServletRequest request, ServletResponse response) 
            throws ServletException, IOException {

        ServletConfig servletConfig = getServletConfig();
        String admin = servletConfig.getInitParameter("admin");
        String email = servletConfig.getInitParameter("email");
        response.setContentType("text/html");
        PrintWriter writer = response.getWriter();
        writer.print("<html><head></head><body>" +"Admin:" + admin +"<br/>Email:" + email +"</body></html>");
    }

    @Override
    public String getServletInfo() {
        return "ServletConfig demo";
    }

    @Override
    public void destroy() {

    }
}

在@WebServlet的initParams属性中, 给Servlet传入了两个初始参数(admin和email),利用下面这个URL, 可以调用ServletConfigDemoServlet:

http://localhost:8080/app01a/servletConfigDemo

这里写图片描述

需要注意的是设置ServletConfig属性另一种方法是, 在部署描述符中传入初始参数。 在这里使用部署描述符, 比使用@WebServlet更容易, 因为部署描述符是一个文本文件, 不需要重新编译Servlet类, 就可以对它进行编辑。这里应该说的就是web.xml配置文件。

ServletContext

ServletContext表示Servlet应用程序。 每个Web应用程序只有一个上下文。 在将一个应用程序同时部署到多个容器的分布式环境中, 每台Java虚拟机上的Web应用都会有一个ServletContext对象。

通过在ServletConfig中调用getServletContext方法,可以获得ServletContext。

有了ServletContext, 就可以共享从应用程序中的所有资料处访问到的信息, 并且可以动态注册Web对象。前者将对象保存在ServletContext中的一个内部Map中。保存在ServletContext中的对象被称作属性。

ServletContext中的下列方法负责处理属性:

  • java.lang.Object getAttribute(java.lang.String name)
  • java.util.Enumeration< java.lang.String > getAttributeNames()
  • void setAttribute(java.lang.String name, java.lang.Object object)
  • void removeAttribute(java.lang.String name)

GenericServlet

之前的例子必须给Servlet中的所有方法都提供实现, 即便其中有一些根本就没有包含任何代码。 此外, 还需要将ServletConfig对象保存到类级变量中。

GenericServlet抽象类的出现。 本着尽可能使代码简单的原则, GenericServlet实现了Servlet和ServletConfig接口, 并完成以下任务:

  • 将init方法中的ServletConfig赋给一个类级变量, 以便可以通过调用getServletConfig获取。
  • 为Servlet接口中的所有方法提供默认的实现。
  • 提供方法, 包围ServletConfig中的方法。

GenericServlet通过将ServletConfig赋给init方法中的类级变量servletConfig, 来保存ServletConfig。 下面就是GenericServlet中的init实现:

public void init(ServletConfig servletConfig) throws ServletException {
    this.servletConfig = servletConfig;
    this.init();
}

但是, 如果在类中覆盖了这个方法, 就会调用Servlet中的init方法, 并且还必须调用super.init(servletConfig)来保存ServletConfig。 为了避免上述麻烦,GenericServlet提供了第二个init方法, 它不带参数。 这个方法是在ServletConfig被赋给servletConfig后, 由第一个init方法调用:

public void init() throws ServletException {

}    

以上可以在GenericServlet的Java源代码中找到。
后面实现GenericServletDemoServlet类是对上一个例子中ServletConfigDemoServlet类的改写。 注意, 这个新的Servlet扩展了GenericServlet, 而不是实现Servlet。代码如下:

package app01a;

import java.io.IOException;
import java.io.PrintWriter;
import javax.servlet.GenericServlet;
import javax.servlet.ServletConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.annotation.WebInitParam;
import javax.servlet.annotation.WebServlet;

@WebServlet(name="GenericServletDemoServlet", urlPatterns= {"/generic"},
            initParams= {@WebInitParam(name="admin", value="Harry Taciak"),
                         @WebInitParam(name="email", value="admin@example.com")
            }
)
public class GenericServletDemoServlet extends GenericServlet{
    private static final long serialVersionID = 62500890L;

    @Override
    public void service(ServletRequest request, ServletResponse response)
            throws ServletException, IOException {

        ServletConfig servletConfig = getServletConfig();
        String admin = servletConfig.getInitParameter("admin");
        String email = servletConfig.getInitParameter("email");
        response.setContentType("text/html");
        PrintWriter writer = response.getWriter();
        writer.print("<html><head></head><body>" +"Admin:" + admin +"<br/>Email:" + email +"</body></html>");

    }
}

通过调用URL可以调用这个Servlet类。

http://localhost:8080/app01a/generic

运行结果如下:

这里写图片描述

HttpServlet

HttpServlet类覆盖了javax.servlet.GenericServlet类。使用HttpServlet时, 还要借助分别代表Servlet请求和Servlet响应的HttpServletRequest和HttpServletResponse对象。 HttpServletRequest接口扩展javax.servlet.ServletRequest, HttpServletResponse扩展javax.servlet.ServletResponse。

HttpServlet覆盖GenericServlet中的Service方法, 并通过下列签名再添加一个Service方法:

protected void service(HttpServletRequest request, HttpServletResponse response) 
    throws ServletException, java.io.IOException

新Service方法和javax.servlet.Servlet中Service方法之间的区别在于, 前者接受HttpServletRequest和HttpServletResponse, 而不是ServletRequest和ServletResponse。

像往常一样, Servlet容器调用javax.servlet.Servlet中原始的Service方法。 HttpServlet中的编写方法如下:

public void service(ServletRequest req, ServletResponse res) throws ServletException, IOException {
    HttpServletRequest request;
    HttpServletResponse response;
    try {
        request = (HttpServletRequest) req;
        response = (HttpServletResponse) res;
    } catch (ClassCastException e) {
        throw new ServletException("non-HTTP request or response");
    }
    service(request, response);
}

原始的Service方法将Servlet容器的request和response对象分别转换成HttpServletRequest和HttpServletResponse, 并调用新的Service方法。 这种转换总是会成功的, 因为在调用Servlet的Service方法时,Servlet容器总会传入一个HttpServletRequest和一个HttpServletResponse, 预备使用HTTP。 即便正在实现javax.servlet.Servlet, 或者扩展javax.servlet.GenericServlet, 也可以将传给Service方法的servlet request和servlet response分别转换成HttpServletRequest和HttpServletResponse。

HttpServlet中的Service方法会检验用来发送请求的HTTP方法(通过调用request.getMethod) , 并调用以下方法之一: doGet、 doPost、 doHead、 doPut、doTrace、 doOptions和doDelete。 这7种方法中, 每一种方法都表示一个HTTP方法。 doGet和doPost是最常用的。 因此, 不再需要覆盖Service方法了, 只要覆盖doGet或者doPost, 或者覆盖doGet和doPost即可。

总之, HttpServlet有两个特性是GenericServlet所不具备的:

  • 不用覆盖Service方法, 而是覆盖doGet或者doPost,或者覆盖doGet和doPost。 在少数情况下, 还会覆盖以下任意方法: doHead、 doPut、 doTrace、doOptions和doDelete。
  • 使用HttpServletRequest和HttpServletResponse, 而不是ServletRequest和ServletResponse。

HttpServletRequest

HttpServletRequest表示HTTP环境中的Servlet请求。 它扩展javax.servlet.ServletRequest接口, 并添加了几个方法。 新增的部分方法如下:

  • java.lang.String getContextPath():返回表示请求上下文的请求URI部分。
  • Cookie[] getCookies():返回一个Cookie对象数组。
  • java.lang.String getHeader(java.lang.String name):返回指定HTTP标题的值。
  • java.lang.String getMethod():返回生成这个请求的HTTP方法名称。
  • java.lang.String getQueryString():返回请求URL中的查询字符串。
  • HttpSession getSession():返回与这个请求相关的会话对象。 如果没有, 将创建一个新的会话对象。
  • HttpSession getSession(boolean create):返回与这个请求相关的会话对象。 果有, 并且create参数为True, 将创建一个新的会话对象。

HttpServletResponse

HttpServletResponse表示HTTP环境中的Servlet响应。 下面是它里面定义的部分方法:

  • void addCookie(Cookie cookie):给这个响应对象添加一个cookie。
  • void addHeader(java.lang.String name, java.lang.String value):给这个响应对象添加一个header。
  • void sendRedirect(java.lang.String location):发送一条响应码, 将浏览器跳转到指定的位置。

写在后面

这一篇博客整理挺多内容的,其中涉及到HttpServlet部分是我在之前的项目实践中确实用到了的,通过今天的整理,对他们之间的联系有了一定得了解。

版权声明:本文来源CSDN,感谢博主原创文章,遵循 CC 4.0 by-sa 版权协议,转载请附上原文出处链接和本声明。
原文链接:https://blog.csdn.net/zy2317878/article/details/80150125
站方申明:本站部分内容来自社区用户分享,若涉及侵权,请联系站方删除。
  • 发表于 2020-02-13 13:57:22
  • 阅读 ( 943 )
  • 分类:

0 条评论

请先 登录 后评论

官方社群

GO教程

猜你喜欢