简介

  1. Java Servlet 是运行在 Web 服务器或应用服务器上的程序,它是作为来自 Web 浏览器或其他 HTTP 客户端的请求和 HTTP 服务器上的数据库或应用程序之间的中间层。使用 Servlet,您可以收集来自网页表单的用户输入,呈现来自数据库或者其他源的记录,还可以动态创建网页。
  2. Servlet的任务
  • 读取客户端(浏览器)发送的显式的数据。这包括网页上的 HTML 表单,或者也可以是来自 applet 或自定义的 HTTP 客户端程序的表单。
  • 读取客户端(浏览器)发送的隐式的 HTTP 请求数据。这包括 cookies、媒体类型和浏览器能理解的压缩格式等等。
  • 处理数据并生成结果。这个过程可能需要访问数据库,执行 RMI 或 CORBA 调用,调用 Web 服务,或者直接计算得出对应的响应。
  • 发送显式的数据(即文档)到客户端(浏览器)。该文档的格式可以是多种多样的,包括文本文件(HTML 或 XML)、二进制文件(GIF 图像)、Excel 等。
  • 发送隐式的 HTTP 响应到客户端(浏览器)。这包括告诉浏览器或其他客户端被返回的文档类型(例如 HTML),设置 cookies 和缓存参数,以及其他类似的任务。
  1. Servlet的生命周期
  • Servlet 初始化后调用 init () 方法。
  • Servlet 调用 service() 方法来处理客户端的请求。
  • Servlet 销毁前调用 destroy() 方法。
  • 最后,Servlet 是由 JVM 的垃圾回收器进行垃圾回收的。
  1. servlet 浏览器访问路径配置有个小问题:

1)java 类里的注解 —— @WebServlet(“/HelloServlet”) 对应浏览器路径:
http://localhost:8080/TomcatTest/HelloServlet
2)配置文件(web.xml)里对应的浏览器访问路径:
http://localhost:8080/TomcatTest/TomcatTest/HelloServlet
这两种配一个就好了,不然路径重名的话反而会让tomcat启动不了。
早期的Servlet需要在web.xml中配置映射路径,但最新Servlet版本只需要通过注解就可以完成映射。

  1. # web.xml
  2. <web-app>
  3. <servlet>
  4. <servlet-name>HelloWorld</servlet-name>
  5. <servlet-class>HelloWorld</servlet-class>
  6. </servlet>
  7. <servlet-mapping>
  8. <servlet-name>HelloWorld</servlet-name>
  9. <url-pattern>/HelloServlet</url-pattern>
  10. </servlet-mapping>
  11. </web-app>
  1. 浏览器发出的HTTP请求总是由Web Server先接收,然后,根据Servlet配置的映射,不同的路径转发到不同的Servlet:

image.png
映射到/的IndexServlet比较特殊,它实际上会接收所有未匹配的路径,相当于/*

部分函数

HttpServletRequest

  1. HttpServletRequest封装了一个HTTP请求,它实际上是从ServletRequest继承而来。
  2. 我们通过HttpServletRequest提供的接口方法可以拿到HTTP请求的几乎全部信息,常用的方法有:
  • getMethod():返回请求方法,例如,”GET”,”POST”;
  • getRequestURI():返回请求路径,但不包括请求参数,例如,”/hello”;
  • getQueryString():返回请求参数,例如,”name=Bob&a=1&b=2”;
  • getParameter(name):返回请求参数,GET请求从URL读取参数,POST请求从Body中读取参数;
  • getParameterValues():如果参数出现一次以上,则调用该方法,并返回多个值,例如复选框。
  • getParameterNames():如果您想要得到当前请求中的所有参数的完整列表,则调用该方法。
  • getContentType():获取请求Body的类型,例如,”application/x-www-form-urlencoded”;
  • getContextPath():获取当前Webapp挂载的路径,对于ROOT来说,总是返回空字符串””;
  • getCookies():返回请求携带的所有Cookie;
  • getHeader(name):获取指定的Header,对Header名称不区分大小写;
  • getHeaderNames():返回所有Header名称;
  • getInputStream():如果该请求带有HTTP Body,该方法将打开一个输入流用于读取Body;
  • getReader():和getInputStream()类似,但打开的是Reader;
  • getRemoteAddr():返回客户端的IP地址;
  • getScheme():返回协议类型,例如,”http”,”https”;

此外,HttpServletRequest还有两个方法:setAttribute()和getAttribute(),可以给当前HttpServletRequest对象附加多个Key-Value,相当于把HttpServletRequest当作一个Map使用。

HttpServletResponse

  1. HttpServletResponse封装了一个HTTP响应。由于HTTP响应必须先发送Header,再发送Body,所以,操作HttpServletResponse对象时,必须先调用设置Header的方法,最后调用发送Body的方法。
  2. 常用的设置Header的方法有:
  • setStatus(sc):设置响应代码,默认是200;
  • setContentType(type):设置Body的类型,例如,”text/html”;
  • setCharacterEncoding(charset):设置字符编码,例如,”UTF-8”;
  • setHeader(name, value):设置一个Header的值;
  • addCookie(cookie):给响应添加一个Cookie;
  • addHeader(name, value):给响应添加一个Header,因为HTTP协议允许有多个相同的Header;
  1. 写入响应时,需要通过getOutputStream()获取写入流,或者通过getWriter()获取字符流,二者只能获取其中一个。
  2. 写入完毕后调用flush()却是必须的,因为大部分Web服务器都基于HTTP/1.1协议,会复用TCP连接。如果没有调用flush(),将导致缓冲区的内容无法及时发送到客户端。
  3. 对于每个请求,Web服务器会创建唯一的HttpServletRequest和HttpServletResponse实例,因此,HttpServletRequest和HttpServletResponse实例只有在当前处理线程中有效,它们总是局部变量,不存在多线程共享的问题。

    自动刷新页面

  4. 刷新网页的最简单的方式是使用响应对象的方法 setIntHeader()。以下是这种方法的定义:

    1. public void setIntHeader(String header, int headerValue)

    此方法把头信息 “Refresh” 连同一个表示时间间隔的整数值(以秒为单位)发送回浏览器。例如

    1. // 设置刷新自动加载的事件间隔为 5 秒
    2. response.setIntHeader("Refresh", 5);

重定向与转发

重定向Redirect

  1. 重定向是指当浏览器请求一个URL时,服务器返回一个重定向指令,告诉浏览器地址已经变了,麻烦使用新的URL再重新发送新请求。

重定向的目的是当Web应用升级后,如果请求路径发生了变化,可以将原来的路径重定向到新路径,从而避免浏览器请求原路径找不到资源。

  1. 例如,我们已经编写了一个能处理/hello的HelloServlet,如果收到的路径为/hi,希望能重定向到/hello,可以再编写一个RedirectServlet:

    1. @WebServlet(urlPatterns = "/hi")
    2. public class RedirectServlet extends HttpServlet {
    3. protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
    4. // 构造重定向的路径:
    5. String name = req.getParameter("name");
    6. String redirectToUrl = "/hello" + (name == null ? "" : "?name=" + name);
    7. // 发送重定向响应:
    8. resp.sendRedirect(redirectToUrl);
    9. }
    10. }

    如果浏览器发送GET /hi请求,RedirectServlet将处理此请求,并且浏览器的地址栏路径自动更新为/hello。

  2. 重定向有两种:一种是302响应,称为临时重定向,一种是301响应,称为永久重定向。两者的区别是,如果服务器发送301永久重定向响应,浏览器会缓存/hi到/hello这个重定向的关联,下次请求/hi的时候,浏览器就直接发送/hello请求了。
    HttpServletResponse提供了快捷的redirect()方法实现302重定向。如果要实现301永久重定向,可以这么写:

    1. resp.setStatus(HttpServletResponse.SC_MOVED_PERMANENTLY); // 301
    2. resp.setHeader("Location", "/hello");

    转发Forward

  3. Forward是指内部转发。当一个Servlet处理请求的时候,它可以决定自己不继续处理,而是转发给另一个Servlet处理。

  4. 例如,我们已经编写了一个能处理/hello的HelloServlet,继续编写一个能处理/morning的ForwardServlet:

    1. @WebServlet(urlPatterns = "/morning")
    2. public class ForwardServlet extends HttpServlet {
    3. protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
    4. req.getRequestDispatcher("/hello").forward(req, resp);
    5. }
    6. }

    ForwardServlet在收到请求后,它并不自己发送响应,而是把请求和响应都转发给路径为/hello的Servlet,后续请求的处理实际上是由HelloServlet完成的。

  5. 转发和重定向的区别在于,转发是在Web服务器内部完成的,对浏览器来说,它只发出了一个HTTP请求。

    使用Session和Cookie

    Cookie

  6. Cookie 是存储在客户端计算机上的文本文件,并保留了各种跟踪信息。

  7. 通过 Servlet 设置 Cookie

通过 Servlet 设置 Cookie 包括三个步骤:
(1) 创建一个 Cookie 对象:您可以调用带有 cookie 名称和 cookie 值的 Cookie 构造函数,cookie 名称和 cookie 值都是字符串。

Cookie cookie = new Cookie("key","value");

请记住,无论是名字还是值,都不应该包含空格或以下任何字符:
[ ] ( ) = , “ / ? @ : ;
(2) 设置最大生存周期:您可以使用 setMaxAge 方法来指定 cookie 能够保持有效的时间(以秒为单位)。下面将设置一个最长有效期为 24 小时的 cookie。

cookie.setMaxAge(60*60*24);

(3) 发送 Cookie 到 HTTP 响应头:您可以使用 response.addCookie 来添加 HTTP 响应头中的 Cookie,如下所示:

response.addCookie(cookie);
@WebServlet(urlPatterns = "/pref")
public class LanguageServlet extends HttpServlet {

    private static final Set<String> LANGUAGES = Set.of("en", "zh");

    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        String lang = req.getParameter("lang");
        if (LANGUAGES.contains(lang)) {
            // 创建一个新的Cookie:
            Cookie cookie = new Cookie("lang", lang);
            // 该Cookie生效的路径范围:
            cookie.setPath("/");
            // 该Cookie有效期:
            cookie.setMaxAge(8640000); // 8640000秒=100天
            // 将该Cookie添加到响应:
            resp.addCookie(cookie);
        }
        resp.sendRedirect("/");
    }
}
  1. 读取Cookie

要读取 Cookie,需要通过调用 HttpServletRequestgetCookies( ) 方法创建一个 javax.servlet.http.Cookie 对象的数组。然后循环遍历数组,并使用 getName() 和 getValue() 方法来访问每个 cookie 和关联的值。

private String parseLanguageFromCookie(HttpServletRequest req) {
    // 获取请求附带的所有Cookie:
    Cookie[] cookies = req.getCookies();
    // 如果获取到Cookie:
    if (cookies != null) {
        // 循环每个Cookie:
        for (Cookie cookie : cookies) {
            // 如果Cookie名称为lang:
            if (cookie.getName().equals("lang")) {
                // 返回Cookie的值:
                return cookie.getValue();
            }
        }
    }
    // 返回默认值:
    return "en";
}
  1. 删除Cookie

删除 Cookie 是非常简单的。如果您想删除一个 cookie,那么您只需要按照以下三个步骤进行:

  • 读取一个现有的 cookie,并把它存储在 Cookie 对象中。
  • 使用 setMaxAge() 方法设置 cookie 的年龄为零,来删除现有的 cookie。
  • 把这个 cookie 添加到响应头。

    Session

  1. 因为HTTP协议是一个无状态协议,即Web应用程序无法区分收到的两个HTTP请求是否是同一个浏览器发出的。为了跟踪用户状态,服务器可以向浏览器分配一个唯一ID,并以Cookie的形式发送到浏览器,浏览器在后续访问时总是附带此Cookie,这样,服务器就可以识别用户身份。 我们把这种基于唯一ID识别用户身份的机制称为Session。每个用户第一次访问服务器后,会自动获得一个Session ID。如果用户在一段时间内没有访问服务器,那么Session会自动失效,下次即使带着上次分配的Session ID访问,服务器也认为这是一个新用户,会分配新的Session ID。
  2. 创建session

    //创建session
    HttpSession session = request.getSession();
    session.setAttribute("user", name);
    
  3. 删除session会话数据

当您完成了一个用户的 session 会话数据,您有以下几种选择:

  • 移除一个特定的属性:您可以调用 public void removeAttribute(String name) 方法来删除与特定的键相关联的值。
  • 删除整个 session 会话:您可以调用 public void invalidate() 方法来丢弃整个 session 会话。
  • 设置 session 会话过期时间:您可以调用 public void setMaxInactiveInterval(int interval) 方法来单独设置 session 会话超时。
  • 注销用户:如果使用的是支持 servlet 2.4 的服务器,您可以调用 logout 来注销 Web 服务器的客户端,并把属于所有用户的所有 session 会话设置为无效。
  • web.xml 配置:如果您使用的是 Tomcat,除了上述方法,您还可以在 web.xml 文件中配置 session 会话超时,如下所示:
    <session-config>
        <session-timeout>15</session-timeout>   
    </session-config>
    
    上面实例中的超时时间是以分钟为单位,将覆盖 Tomcat 中默认的 30 分钟超时时间。
    在一个 Servlet 中的 getMaxInactiveInterval() 方法会返回 session 会话的超时时间,以秒为单位。所以,如果在 web.xml 中配置 session 会话超时时间为 15 分钟,那么 getMaxInactiveInterval() 会返回 900。