天道不一定酬所有勤
但是,天道只酬勤

[译]Java Servlet初级知识

GitHub 24k Star 的Java工程师成神之路,不来了解一下吗!

本文由HollisChuang 翻译自 Java Servlet Tutorial with Examples for Beginners . 原作者:Pankaj Kumar

在上一篇文章中,我们了解了Java Web应用程序和Web应用程序中的核心概念,如Web服务器,Web客户端,HTML,HTTP和Web容器以及如何使用Servlet和Jsp创建web应用程序。同时分别使用servlet和jsp创建了可以在tomcat中运行的web应用程序。

这篇文章将主要介绍更多关于setvlet的细节,如servlet中的核心api、servlet3.0中的注解、servlet的生命周期。最后再创建一个简单的servlet应用程序实现登录功能。

Servlet概述

Servlet是在Java中创建web应用程序的J2ee 服务端技术。javax.servletjavax.servlet.http包中提供了编写servlet的接口和类。

所有的servlet都要实现javax.servlet.Servlet接口。该接口中定义了一个Servlet生命周期中的所有方法。如果要实现一个通用的Servlet,可以通过继承Java Servlet API中提供的GenericServlet类。HttpServlet类中提供了用于处理http请求的doGet()doPost()等方法。

多数情况下,web应用程序都使用http协议,所以,我们多数时候都通过继承HttpServlet类来实现自己的Servlet。

通用网关接口(CGI)

在Servlet API产生之前,CGI技术用于创建动态web应用程序。CGI技术有许多缺点,如为每个请求创建单独的进程、依赖于平台代码(C、C++)、内存消耗大和性能低等。

CGI 和 Servlet 对比

Servlet技术的诞生克服了很多CGI技术的缺点:

  • Servlet在处理时间、内存利用率等方面表现更好。因为servlet使用多线程技术,为每个请求创建一个新线程。这自然就比为每个请求创建新进程的CGI技术要快很多,并且节省内存资源。

  • Servlet是平台无关的,使用Servlet开发的web应用程序可以运行在任何标准的web容器中,如Tomcat、JBoss、Glassfish服务器。同样可以在任何操作系统中,如Windows、Linux、Unix、Solaris、Mac等。

  • Servlet是健壮的,因为servlet容器负责管理servlet的生命周期,我们不需要担心内存泄漏、安全、垃圾收集等问题。

  • Servlet易维护的,并且学习曲线小。因为在使用Servlet的时候我们只需要关注业务逻辑就可以了。

  • Servlet API的层次结构

    javax.servlet.Servlet是Servlet Api的最上层接口。还有一些其他的接口和类是我们在使用servlet的时候需要关注的。在Servlet 3.0规范中,建议使用的注解我们也需要了解。

    在本节中,我们将学习重要Servlet API接口,类和注释。下面的图显示了servlet API层次结构。

    servlet api

    Servlet 接口

    javax.servlet.Servlet 是Servlet Api的最上层接口,Servlet接口定义了一系列servlet的生命周期方法(init、service、destory等)。所有的Servlet类都需要继承这个接口。该接口中定义了以下方法:

    public abstract void init(ServletConfig paramServletConfig) throws ServletException – 该方法由servlet容器调用,用于初始化servlet以及servlet配置参数。在init()方法执行之前,servlet是无法处理用户请求的。在servlet生命周期中该方法只会被调用一次,他会使servlet类不同区别于普通的java对象。我们可以扩展该方法来初始化资源,如万博manbext手机版连接、socket连接等。

    public abstract ServletConfig getServletConfig() – 该方法返回一个servlet配置对象,其中包含servlet中所有初始化参数和启动配置。我们可以用这个方法来获取servlet的初始化参数,这些参数一般被定义在web.xml或servlet 3的注解中。后面会介绍ServletConfig接口。

    public abstract void service(ServletRequest req, ServletResponse res) throws ServletException, IOException – 该方法负责处理客户端请求。当servlet容器收到客户端请求时,它会创建一个新线程并执行service()方法,并把request 和 response作为参数传递给该方法。servlet通常运行在多线程环境中,所以开发人员应该使用同步来保证访问共享资源的线程安全性问题。

    public abstract String getServletInfo() – 这个方法返回包含servlet信息的字符串,比如它的作者、版本和版权。返回的字符串应该是纯文本,不能有标记符号。

    public abstract void destroy() – 这个方法在整个servlet生命周期中只会被调用一次来关闭所有资源。有点像Java中的finalize方法。

    ServletConfig 接口

    javax.servlet.ServletConfig用于给servlet传递配置信息(译者注:描述Servlet本身的相关配置信息)。每个servlet都有属于它自己的ServletConfig对象,该对象由servlet容器负责实例化。可以在web.xml中提供初始化参数,当然在servlet3.0中可以使用注解。我们可以使用getServletConfig()方法来获取ServletConfig的对象。

    ServletConfig接口中主要方法:

    public abstract ServletContext getServletContext() – 该方法返回servlet的ServletContext对象。在下一节中我们将介绍ServletContext接口。

    public abstract Enumeration getInitParameterNames() – 该方法返回servlet中所有初始化参数的名字的枚举。如果没有初始化参数定义,该方法将返回空枚举。

    public abstract String getInitParameter(String paramString) – 这种方法可以通过名字来获取特定的初始化参数值。如果参数的名称不存在,则返回null。

    ServletContext 接口

    javax.servlet.ServletContext接口用于描述应用程序的相关信息。ServletContext是一个独立的对象,可用于web应用程序中所有的servlet。当我们想要一些初始化的参数可用于web应用程序中多个或全部servlet时,我们可以使用ServletContext对象并且在web.xml中使用<context-param>标签定义参数。我们可以通过ServletConfig 中的 getServletContext()方法得到ServletContext对象。

    ServletContext接口中的主要方法:

    public abstract ServletContext getContext(String uripath) – 这个方法返回指定的uripath的ServletContext对象,如果uripath不可用或不可见则返回null。

    public abstract URL getResource(String path) throws MalformedURLException – 返回的一个代表某个资源的URL对象。资源可以是本地文件系统、远程文件系统、万博manbext手机版,甚至是不知道如何获取资源的具体细节的远程网络站点。

    public abstract InputStream getResourceAsStream(String path) – 这个方法返回给定的资源路径的一个输入流对象。如果没有找到返回null。

    public abstract RequestDispatcher getRequestDispatcher(String urlpath) – 这个方法一般被用于获得对于另外一个servlet的引用。获取到RequestDispatcher对象之后,就可以通过他把一个请求转发出去(forward或者include)。

    public abstract void log(String msg) – 该方法用于把指定的消息字符串写入servlet日志文件中。

    public abstract Object getAttribute(String name) – 按照指定的name返回对象属性。可以使用public abstract Enumeration getAttributeNames()活的所有对象属性的枚举。

    public abstract void setAttribute(String paramString, Object paramObject) – 该方法用于在应用的范围内设置属性。该属性可以被可以访问当前ServletContext的所有servle获取到。可以使用public abstract void removeAttribute(String paramString)删除一个属性。

    String getInitParameter(String name) – 该方法用于返回在web.xml中定义的初始化参数的值。如果指定的name在web.xml中并没有匹配到,则返回null。可以使用Enumeration getInitParameterNames()得到所有初始化参数的名称的枚举。

    boolean setInitParameter(String paramString1, String paramString2) – 可以使用该方法设置应用中的初始化参数。

    ServletRequest 接口

    ServletRequest接口是用来向servlet提供客户端请求信息。每一个客户端请求到达Servlet容器的时候,他都会创建一个ServletRequest对象,并将其传递对应的servlet的service()方法。

    ServletRequest接口中的主要方法:

    Object getAttribute(String name) – 返回指定的参数名对应的属性值。如果对应的参数不存在则返回null。我们可以使用getAttributeNames()方法来获取请求中的所有属性名称的枚举。接口中同样提供了设置值和删除值的方法。

    String getParameter(String name) – 以字符串的形式返回请求参数值。我们可以使用getParameterNames()方法来获取请求参数名称的枚举。

    String getServerName() – 返回服务器的主机名

    int getServerPort() – 返回服务器监听的端口号。

    ServletRequest的子接口HttpServletRequest中还包含了一些和session、cookies等相关的方法。

    译者注:该接口中提供了getAttribute和getParameter两个方法,都是用于获取参数(属性)值的,那么这两个方法有什么区别呢?或者说Attribute和Parameter的区别是什么呢?

    答:

    来源不同

    参数(parameter)是从客户端(浏览器)中由用户提供的,若是GET方法是从URL中 提供的,若是POST方法是从请求体(request body)中提供的;

    属性(attribute)是服务器端的组件(JSP或者Servlet)利用requst.setAttribute()设置的.

    操作不同

    参数(parameter)的值只能读取不能修改,读取可以使用request.getParameter()读取;

    属性(attribute)的值既可以读取亦可以修改,读取可以使用request.setAttribute(),设置可使用request.getAttribute()

    数据类型不同

    参数(parameter)不管前台传来的值语义是什么,在服务器获取时都以String类型看待,并且客户端的参数值只能是简单类型的值,不能是复杂类型,比如一个对象。

    属性(attribute)的值可以是任意一个Object类型。

    ServletResponse 接口

    servlet使用ServletResponse向客户端发送响应。和每ServletRequest类似,一个客户端请求到达Servlet容器的时候,他都会创建一个ServletResponse对象,并将其传递对应的servlet的service()方法。最终,该response对象用于给客户端生成html响应。

    ServletResponse接口中的主要方法:

    void addCookie(Cookie cookie) – 向响应中添加cookie

    void addHeader(String name, String value) – 设置响应头

    String encodeURL(java.lang.String url) – 通过重写Url的方式支持session,在Url中增加sessionId,如果不需要重写,直接返回该url

    String getHeader(String name) – 返回指定的头信息。

    void sendRedirect(String location)–重定向到指定的地址

    void setStatus(int sc) – 设置响应的状态码

    RequestDispatcher 接口

    RequestDispatcher 接口用于把一个请求转发给同一个servlet上下文中的其他的资源(Html、jsp、servlet)来处理。也可以用它来把另一个资源的内容包含到响应中。此接口用于同一个servlet上下文中的servlet相互沟通。

    RequestDispatcher 接口的主要方法: void forward(ServletRequest request, ServletResponse response) – 把一个servlet的请求转发到服务器上的其他资源中(Html、jsp、servlet)。

    void include(ServletRequest request, ServletResponse response) – 把另一个资源的内容包含到当前响应中。

    译者注:forward和include的区别:

    如果使用forward跳转,forward语句后面的response输出则不会执行,会跳转到forward指定的servlet中去执行。

    用include来跳转,则include的servlet执行完后,再返回到原来的servlet执行forward语句后面的response的输出。

    在servlet中可以使用getRequestDispatcher(String path)来获取一个RequestDispatcher。路径必须以/开头,并且是针对于当前context的根路径的相对地址。

    GenericServlet 类

    GenericServlet是一个实现类Servlet, ServletConfig 和 Serializable 的抽象类。他提供了Servlet生命周期中的主要方法以及ServletConfig中的方法的默认实现。当我们定义自己的servlet的时候,只要继承了该方法,我们只需要重写我们关注的方法就可以了,其他的不关注的方法都可以使用其默认实现。该类中定义的大部分方法都是让用户更放方便的使用Servlet和ServletConfig接口中定义的常用方法。

    GenericServlet 类中有一个重要的方法——无参数的init方法。如果我们必须在处理请求之前初始化一些资源,那么可以重写该方法。

    HTTPServlet 类

    HTTPServlet 类是GenericServlet类的子类,主要为基于HTTP创建的web应用程序提供了一些支持。其中定义了一些可重写HTTP方法。

    doGet(), 用于处理get请求 doPost(), 用于处理post请求 doPut(), 用于处理put请求 doDelete(), 用于处理delete请求

    Servlets属性(Attributes)

    Servlet属性用于servlet之间的沟通,可以在web应用程序中设置、获取甚至删除属性值。servlet属性有三种范围:request、session、application

    ServletRequest, HttpSession 和 ServletContext接口为request、session和application范围提供了get/set/remove的方法。

    Servlet 3中的注解

    在servlet 3之前,所以的servlet映射和初始化参数都是定义在web.xml文件中的,随着应用中的servlet数量增多,这种方式就很难维护。

    servlet 3中使用支持使用java注解来定义servlet、filter、listener以及初始化参数。

    servlet 3 中主要的注解:

    WebServlet – 可以在servlet类中使用该注解来定义初始化参数、loadOnStartup的值、description信息和url匹配模式(pattern)等。该注解的属性中 vlaue 或者 urlPatterns 通常是必需的,且二者不能共存。该注释声明的类必须继承HttpServlet。

    WebInitParam – 该注解用于给servlet 或者 filter定义初始化参数(包括name,value和description)。可以在 WebFilter 或者 WebServlet中使用该注解。

    WebFilter – 该注解用于声明一个servlet过滤器。使用该注解声明的类必须实现javax.servlet.Filter接口。

    WebListener – 该注解用于声明一个事件监听器。

    后续文章会更多的介绍servlet 监听器和过滤器。在本文中,我们的学习重点是Servlet API的接口和类。

    使用Servlet实现登录的例子

    现在我们准备创建一个有登录功能的servlet实例,在这个例子中,我会使用简单的HTML、jsp和servlet来进行用户的权限校验。我们将用到ServletContext的初始化参数、属性,ServletConfig的初始化参数、RequestDispatcher的include()方法和response的sendRedirect()等方法。

    这个Web项目的代码结构应该如下图所示。这里使用Eclipse+Tomcat进行开发及运行。创建项目的过程参见Java Web应用程序初级知识

    path

    这是登录页面的代码。我们会把它配置在web.xml 的中<welcome-file-list>标签下。这样,我们一访问这个应用就能跳转到该页面。

    login.html

    <!DOCTYPE html>
    <html>
    <head>
    <meta charset="US-ASCII">
    <title>Login Page</title>
    </head>
    <body>
    
    <form action="LoginServlet" method="post">
    
    Username: <input type="text" name="user">
    <br>
    Password: <input type="password" name="pwd">
    <br>
    <input type="submit" value="Login">
    </form>
    </body>
    </html>
    

    如果用户登录成功,用户将会在一个新的jsp页面中看到登录成功的提示信息。该jsp页面的代码如下:

    LoginSuccess.jsp

    <%@ page language="java" contentType="text/html; charset=US-ASCII"
        pageEncoding="US-ASCII"%>
    <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
    <html>
    <head>
    <meta http-equiv="Content-Type" content="text/html; charset=US-ASCII">
    <title>Login Success Page</title>
    </head>
    <body>
    <h3>Hi Pankaj, Login successful.</h3>
    <a href="mphjo.iunm">Login Page</a>
    </body>
    </html>
    

    下面是web.xml文件的配置,其中包含了servlet的初始化、参数、以及欢迎页的配置。

    web.xml

    <?xml version="1.0" encoding="utf-8"?>
    <web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd" id="WebApp_ID" version="3.0">
      <display-name>LoginExample</display-name>
      <welcome-file-list>
        <welcome-file>login.html</welcome-file>
      </welcome-file-list>
    
      <context-param>
      <param-name>dbURL</param-name>
      <param-value>jdbc:mysql://localhost/mysql_db</param-value>
      </context-param>
      <context-param>
      <param-name>dbUser</param-name>
      <param-value>mysql_user</param-value>
      </context-param>
      <context-param>
      <param-name>dbUserPwd</param-name>
      <param-value>mysql_pwd</param-value>
      </context-param>
    </web-app>
    

    下面则是Servlet类,他的主要功能就是做用户登录校验。主要关注其中关于Servlet以及ServletConfig的注解的使用。

    LoginServlet.java

    package com.journaldev.servlet;
    
    import java.io.IOException;
    import java.io.PrintWriter;
    
    import javax.servlet.RequestDispatcher;
    import javax.servlet.ServletException;
    import javax.servlet.annotation.WebInitParam;
    import javax.servlet.annotation.WebServlet;
    import javax.servlet.http.HttpServlet;
    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpServletResponse;
    
    /**
     * Servlet implementation class LoginServlet
     */
    @WebServlet(
            description = "Login Servlet", 
            urlPatterns = { "/LoginServlet" }, 
            initParams = { 
                    @WebInitParam(name = "user", value = "Pankaj"), 
                    @WebInitParam(name = "password", value = "journaldev")
            })
    public class LoginServlet extends HttpServlet {
        private static final long serialVersionUID = 1L;
    
    
        public void init() throws ServletException {
            //we can create DB connection resource here and set it to Servlet context
            if(getServletContext().getInitParameter("dbURL").equals("jdbc:mysql://localhost/mysql_db") &&
                    getServletContext().getInitParameter("dbUser").equals("mysql_user") &&
                    getServletContext().getInitParameter("dbUserPwd").equals("mysql_pwd"))
            getServletContext().setAttribute("DB_Success", "True");
            else throw new ServletException("DB Connection error");
        }
    
    
        protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
    
            //get request parameters for userID and password
            String user = request.getParameter("user");
            String pwd = request.getParameter("pwd");
    
            //get servlet config init params
            String userID = getServletConfig().getInitParameter("user");
            String password = getServletConfig().getInitParameter("password");
            //logging example
            log("User="+user+"::password="+pwd);
    
            if(userID.equals(user) && password.equals(pwd)){
                response.sendRedirect("LoginSuccess.jsp");
            }else{
                RequestDispatcher rd = getServletContext().getRequestDispatcher("/login.html");
                PrintWriter out= response.getWriter();
                out.println("<font color=red>Either user name or password is wrong.</font>");
                rd.include(request, response);
    
            }
    
        }
    
    }
    

    下面是页面展示,包括登录成功及失败两种情况。 login login-success login-fail

    Servlet的初级教程就介绍到这里了,下一篇文章会介绍session管理、Servlet过滤器和监听器。

    [wpdm_package id=’1214′]

    (全文完)

    扫描二维码,关注作者微信公众号
    赞(1)
    如未加特殊说明,此网站文章均为原创,转载必须注明出处。HollisChuang's Blog » [译]Java Servlet初级知识
    分享到: 更多 (0)

    评论 1

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址
    1. #1

      这是个印度阿三的网站,内容不怎么样。

      海外蓝天7年前 (2016-03-03)回复

    HollisChuang's Blog

    联系我关于我
  • 微信咨询
    关注微信:themebetter
    复制微信号
  • 去评论
    去评论
  • 回顶
    回顶部