Java 后端 (一)servlet

2018-06-18 03:46:43来源:未知 阅读 ()

新老客户大回馈,云服务器低至5折

一、什么是Servlet

  Servlet(Server Applet)是Java Servlet的简称,称为小服务程序或服务连接器,用Java编写的服务器端程序,主要功能在于交互式地浏览和修改数据,生成动态Web内容。

  狭义的Servlet是指Java语言实现的一个接口,广义的Servlet是指任何实现了这个Servlet接口的类,一般情况下,人们将Servlet理解为后者。Servlet运行于支持Java的应用服务器中。从原理上讲,Servlet可以响应任何类型的请求,但绝大多数情况下Servlet只用来扩展基于HTTP协议的Web服务器。

——百科

  简单说就是服务器上一个处理请求的程序,也可以认为是一切服务器端后台开发的起点。

  浏览器-服务器的模式有着如下的流程:

    用户通过浏览器访问一个地址 -> 浏览器产生http请求发送到服务器 -> 服务器容器程序接收请求并启动一个线程并调用一个Servlet来处理请求。剩下的工作就由Servlet完成。

二、Servlet的功能

  

  Servlet及相应的类都存在于javax.Servlet包和javax.Servlet.http包中。

  Servlet包括5个方法:

  /**
   * Servlet容器在初始化Servlet时调用,因此只调用一次
   * 其中参数ServletConfig config 来自于Servlet容器
   */
  public void init(ServletConfig config) throws ServletException;

 

  /**
   *  获取Servlet的配置信息,用于后续操作
   */
  public ServletConfig getServletConfig();

 

    /**
     * 核心方法,每当有请求时,Servlet容器都会调用Servlet的Service方法来进行处理
* 两个参数是由Servlet容器封装的请求和响应对象
*/ public void service(ServletRequest req, ServletResponse res) throws ServletException, IOException;

 

  /**
   * 获取Servlet信息,如作者之类的,没什么用,通用实现时直接返回“”
   */
  public String getServletInfo();

 

    /**
     * Servlet容器移除Servlet时调用,通常发生在容器关闭时
* 可以用来释放连接或者存储数据到数据库等操作
*/ public void destroy();

 

三、Servlet实现——HttpServlet

  Servlet自身只是一个接口,其中使用的各种ServletConfig、ServletRequest等都是接口,如果要直接使用Servlet进行操作需要许多操作。而在javax.Servlet.http包中,给出了Servlet对应的http版本的实现。其中最主要的就是HttpServlet类。

  

  GenericServlet直接实现了Servlet接口,但是并没有添加太多的内容,只实现了一些获取配置信息的方法。而HttpServlet主要实现了Service方法。

/**
 * 根据http方法的不同,调用不同的方法进行处理
 */    
protected void service(HttpServletRequest req,HttpServletResponse resp)
    throws ServletException, IOException
    {
    String method = req.getMethod();
   //GET方法,做了上次访问内容是否修改的判断
if (method.equals(METHOD_GET)) { long lastModified = getLastModified(req); if (lastModified == -1) { doGet(req, resp); } else { long ifModifiedSince = req.getDateHeader(HEADER_IFMODSINCE); if (ifModifiedSince < (lastModified / 1000 * 1000)) { // If the servlet mod time is later, call doGet() // Round down to the nearest second for a proper compare // A ifModifiedSince of -1 will always be less maybeSetLastModified(resp, lastModified); doGet(req, resp); } else { resp.setStatus(HttpServletResponse.SC_NOT_MODIFIED); } }    //HEAD方法 } else if (method.equals(METHOD_HEAD)) { long lastModified = getLastModified(req); maybeSetLastModified(resp, lastModified); doHead(req, resp);    //POST方法 } else if (method.equals(METHOD_POST)) { doPost(req, resp); //PUT方法 } else if (method.equals(METHOD_PUT)) { doPut(req, resp); //DELETE方法 } else if (method.equals(METHOD_DELETE)) { doDelete(req, resp); //OPTIONS方法 } else if (method.equals(METHOD_OPTIONS)) { doOptions(req,resp); //TRACE方法 } else if (method.equals(METHOD_TRACE)) { doTrace(req,resp); } else { //方法异常返回错误信息 String errMsg = lStrings.getString("http.method_not_implemented"); Object[] errArgs = new Object[1]; errArgs[0] = method; errMsg = MessageFormat.format(errMsg, errArgs); resp.sendError(HttpServletResponse.SC_NOT_IMPLEMENTED, errMsg); } }

  因此,在开发自己的Servlet时,可以只覆写相应的doxxx方法,无需自己处理service。而HttpServlet中提供的doxxx方法默认实现的是提示错误信息,因此,在覆写时不需使用super.doxxx()方法。

    protected void doGet(HttpServletRequest req, HttpServletResponse resp)
    throws ServletException, IOException
    {
    String protocol = req.getProtocol();
    String msg = lStrings.getString("http.method_get_not_supported");
    if (protocol.endsWith("1.1")) {
        resp.sendError(HttpServletResponse.SC_METHOD_NOT_ALLOWED, msg);
    } else {
        resp.sendError(HttpServletResponse.SC_BAD_REQUEST, msg);
    }
    }

四、其他设置

  除了编写自己的Servlet继承HttpServlet之外,开发时还需要在web.xml中向Servlet容器注册自己写的Servlet。

<servlet> 
      <servlet-name>MyServlet </servlet-name>      //这里是servlet 的名字,自己定义的 
      <servlet-class>Servlet </servlet-class>      //这里是servlet的位置。包名.类名 
</servlet> 
<servlet-mapping> 
      <servlet-name>MyServlet </servlet-name>      //这里跟 上面的;servlet-name 必须一样 
      <url-pattern>/abc </url-pattern>            //这里 在地址输入访问的时候输入的,自己定义 
</servlet-mapping>

 

五、cookie

  cookie是服务器端向浏览器发送的内容,浏览器会将其保存在客户端本地,通常用来实现免登录等功能。浏览器会在每次http请求时将cookie的内容添加到请求头中。

 1、cookie的设置

  cookie的使用比较简单,在HttpServletResponse类中有一个addCookie方法,重复调用就可以设置多个cookie

    /**
     * 将cookie添加到response中,可以多次调用以添加多个cookie
     */
    public void addCookie(Cookie cookie);

  而cookie属性设置则通过Cookie类实现,其构造方法明确说明了cookie可以设置的类型,通过getName()和set/getValue()方法可以对名称和值进行操作。

    /**
     * 通过键值对构造cookie
     * cookie的键也就是名字只能包含ASCII,不能包含逗号,引号,空格或以$符号开头
     * cookie的名字一旦创建不能改变
     */
    public Cookie(String name, String value) {
    if (!isToken(name)
        || name.equalsIgnoreCase("Comment")    // 描述信息
        || name.equalsIgnoreCase("Discard")    // Java中无此属性
        || name.equalsIgnoreCase("Domain")
        || name.equalsIgnoreCase("Expires")    // (old cookies)
        || name.equalsIgnoreCase("Max-Age")    // cookie最大存在时间,以秒为单位
        || name.equalsIgnoreCase("Path")    //使cookie对此目录下的所有文件可见
        || name.equalsIgnoreCase("Secure")
        || name.equalsIgnoreCase("Version")
        || name.startsWith("$")
        ) {
        String errMsg = lStrings.getString("err.cookie_name_is_token");
        Object[] errArgs = new Object[1];
        errArgs[0] = name;
        errMsg = MessageFormat.format(errMsg, errArgs);
        throw new IllegalArgumentException(errMsg);
    }

    this.name = name;
    this.value = value;
    }

  可以看到cookie的名称不能设置为以上八个和$开头的字符串,这八个名字是Cookie类的保留属性,具体含义见注释。其中Max-Age属性设为0时表示删除此cookie,因此,在response中没有提供另外的删除cookie方法。

    2、获取Cookie

  要获取Cookies可以调用request中的getCookies方法

    /**
     * Cookie为空时返回NULL
     */
    public Cookie[] getCookies();

 

六、session

  由于Http无状态连接的特点,每次对服务器的连接都是独立的,用户在稍早之前做的操作如登录等都不会在新的请求中呈现出来。因此,需要一种机制来记录用户信息以便为用户持续提供服务。上面说的Cookie是一种选择,浏览器会将相应的信息附加到Http请求中,此时就可以查看之前保存的用户信息。

  但是以此种方式使用Cookie存在一些风险:

  • Cookie保存在客户端,以文件的形式保存。用户可以分析cookie文件的到相应的信息,从而欺骗服务器
  • 浏览器可能会禁用cookie,同时也会限制cookie的数目

  因此,需要另外一种技术,将用户的信息保存到服务器,用户只需要在Http中提供一个标识,服务器即可通过这个标识来读取存储在服务器上的用户信息。这就是Session

    1、Session的操作

  session由request对象的getSession(true)和getSession()方法提供。

    /**
     *
     * 返回绑定在当前请求的Session,create可以控制在没有Session时
     * 是否创建新的Session,为false且没有Session时返回null
     */
    public HttpSession getSession(boolean create);

    /**
     * 
     * 即getSession(true);
     */

    public HttpSession getSession();

  对session的操作有HttpSession类提供。主要包含以下方法:

    /**
     *
     * 未找到名称时返回null
     */
    public Object getAttribute(String name);

    /**
     *
     * 返回枚举类型的名称列表
     */    
    public Enumeration getAttributeNames();

    /**
     *  向session绑定对象,若有重名,则之前的对象会被覆盖
     *
     *  如果绑定的对象实现了HttpSessionBindingListener,则容器会
     *  调用对象的valueBound方法来通知该对象,这可以用来检测
     *  session是否失效。同时容器会唤醒所有的
     *  HttpSessionAttributeListener,实现了此接口的类会监听
     *  session属性改变的消息 
     *
     * 可以通过传递null删除session中的这一属性
     */ 
    public void setAttribute(String name, Object value);

    /**
     *
     *  移除session中的相应属性,同样会通知实现了
     *  HttpSessionBindingListener接口的类,调用其
     *  valueUnbound方法,同时通知实现
     *  HttpSessionAttributeListener接口的类
     * 
     */
    public void removeAttribute(String name);

    2、session的管理

  session由服务器容器进行创建,通过上文说的标识即sessionId来标记每一个session。

  sessionId由容器生成,每次Http连接服务器都会检查是否在header中携带有包含sessionId的cookie。若没有,则会生成sessionId,然后通过cookie回传给客户端,之后客户端就可以通过在cookie中设置sessionId来表明身份了。若有,则根据sessionId查找对应的信息,保存到Session中。

  然而,若浏览器禁用了cookie,服务器将无法收到sessionId,因此服务器会在每次Http访问时生成一个新的sessionId。此时可以使用url重写在服务器端为所有的链接添加sessionId,即使用response.encodeURL(url)和response.encodeRedirectURL(url)进行处理,该方法会在url之后添加;jsessioinId以便服务器能够得到sessionId。对于纯静态页面,目前我还没有找到比较好的方法处理这种问题。

  session会在持续时间结束后失效,setMaxInacticeInterval(int interval)可以以秒为单位设置超时时间,getMaxInacticeInterval()可以获取超时时间。为了监听session超时事件,可以在属性类中实现HttpSessionBindingListener接口,容器会在session创建和session失效时调用相应的方法。

  session存在于servletContext之中,而不同的项目其servletContext不同,此时就需要通过配置文件将servletContext连通或者使用数据库实现。

标签:

版权申明:本站文章部分自网络,如有侵权,请联系:west999com@outlook.com
特别注意:本站所有转载文章言论不代表本站观点,本站所提供的摄影照片,插画,设计作品,如需使用,请与原作者联系,版权归原作者所有

上一篇:Spring Boot项目构建

下一篇:Spring-Blog:个人博客(一)-Mybatis 读写分离