servlet技术


 初学JavaWeb开发,请远离各种框架,从Servlet开始。

        Web框架是开发者在使用某种语言编写Web应用服务端是关于架构的最佳实践。很多Web框架是从实际的Web项目抽取出来的,仅和Web的请求和响应处理有关,形成一个基础,在开发别的应用项目的时候则可以从这个剥离出来的基础做起,让开发者更关注具体的业务问题,而不是Web的请求和响应的控制。
        框架很多,但套路基本类似,帮你隐藏很多关于HTTP协议细节内容,专注功能开发。
        但对于一个初学者来说,过早的接触框架往往事倍功半!同样一个问题,换一种框架你可能需要从头开始研究。
        所以,作为Java Web技术的核心基础,Servlet的工作原理是必须掌握的,也是成为一名合格的Java Web技术开发人员的基本要求。
 
一、Servlet简介

1.servlet技术框架

servlet技术

        Servlet是Server与Applet的缩写,是服务端小程序的意思。是SUN公司提供的一门用于开发动态Web资源的技术。目前最新版本为3.1。
        Servlet本质上也是Java类,但要遵循Servlet规范进行编写,没有main()方法,它的创建、使用、销毁都由Servlet容器进行管理(如Tomcat)。
        Servlet是和HTTP协议是紧密联系的,其可以处理HTTP协议相关的所有内容。这也是Servlet应用广泛的原因之一。
        提供了Servlet功能的服务器,叫做Servlet容器,其常见容器有很多,如Tomcat, Jetty, resin, Oracle Application server, WebLogic Server, Glassfish, Websphere, JBoss等。

2,jsp与servlet的区别
servlet技术

 
二、Servlet工作原理解析
servlet技术

        1、一个HTTP请求的执行过程:
           客户端发出请求http://localhost:8080/xxx
           根据Web.xml文件的配置,找到<url-pattern>对应的<servlet-mapping>
           读取<servlet-mapping>中<servlet-name>的值
           找到<servlet-name>对应的<servlet-class>
           找到该class并加载执行该class
        2、Servlet的执行过程
           Servlet程序有Web服务器调用,当收到请求后,
           检查是否已装载并创建了该Servlet对象,如果没有则加载创建
           调用Servlet的init()方法初始化实例
           调用service()方法,处理请求并返回响应结果
           在服务器被停止或重启之前,调用destroy()方法释放资源
        3、Servlet接口实现类
           SUN公司定义了两个实现类,GenerricServlet和HttpServlet,其中后者是前者的子类,它在原有基础上添加了一些HTTP协议处理方法,它比GenerricServlet功能更强大,所以我们一般将自己的类继承自HttpServlet,并重写doGet方法和doPost方法,不需要重写Service方法。
         4、Servlet的一些细节
               4.1、由于客户端是通过URL地址访问web服务器中的资源,所以Servlet程序弱项被外界访问,必须把Servlet程序映射到一个URL地址上,这个工作在web.xml文件中使用<servlet>元素和<servlet-mapping>元素完成(在Servlet3.0规范的新特性中,该功能可以使用注解完成,不要求必须使用web.xml,只用注解更简单,该特性会在后文进行详细讲解)。
                    <servlet>元素用于注册Servlet,它包含两个主要的子元素:<servlet-name>和<servlet-class>,分别用于设置Servlet的注册名称和Servlet的完整类名(包+类)。
                    <servlet-mapping>元素用于映射一个已注册的Servlet的一个对外访问路径,它包含两个子元素:<servlet-name>和<url-pattern>,分别用于指定Servlet的注册名称和Servlet的对外访问路径(相对路径)。
  1. servlet技术
    <web-app>
        <servlet>
            <servlet-name>AnyName</servlet-name><!--自定义的逻辑名-->
            <servlet-class>HelloServlet</servlet-class><!--Servlet对应类的全类名-->
        </servlet>
        <servlet-mapping>
            <servlet-name>AnyName</servlet-name><!--上面定义的逻辑名-->
            <url-pattern>/demo/hello.html</url-pattern><!--匹配的URL-->
        </servlet-mapping>
    </web-app>
    servlet技术

                 4.2、同一个Servlet可以被映射到多个URL上,即多个<servlet-mapping>元素的<servlet-name>子元素的设置值可以是同一个Servlet的注册名。

                  在Servlet映射到的URL中也可以使用*通配符,但是只能有两种固定的格式
                  一种是“*.扩展名”。
                  另一种是以(/)开头并以(/*)结尾。
  1. servlet技术
    <!--方式一用于匹配所有某一扩展名的文件-->
    <servlet-mapping>
        <servlet-name>AnyName</servlet-name>
        <url-pattern>*.do</url-pattern>
    </servlet-mapping>
    <!--方式二用于匹配某一文件夹下的所有文件-->
    <servlet-mapping>
        <servlet-name>AnyName</servlet-name>
        <url-pattern>/action/*</url-pattern>
    </servlet-mapping>
    servlet技术

                       两个特点:可以精确匹配,就用精确匹配,最后使用范围最宽泛的匹配

                                 /* 的优先级高于 *.扩展名 会先匹配
             4.3、如果某个Servlet的映射路径只有一个(/),那么这个Servlet就成为当前Web应用程序的缺省Servlet。
                    凡是在web.xml文件中找不到匹配的<servlet-mapping>元素的URL,它们的请求访问都将交给缺省Servlet处理,也就是说,缺省Servlet用于处理所有其他Servlet都不处理的访问请求。
                    在tomcat的安装目录/conf/web.xml中,注册了一个名称org.apache.catalina.servlets.DefaultServlet的Servlet,并将这个Servlet设置为缺省Servlet。
                    当访问Tomcat服务器中的某个静态HTML文件或图片等资源时,实际上是在访问这个缺省Servlet。
servlet技术
          5、Servlet的生命周期
              Servlet没有main()方法,不能独立运行,它的运行完全由Servlet引擎来控制和调度。
              针对客户端的多次Servlet请求,通常情况下,服务器只会在第一次请求的时候创建一个Servlet实例对象,并驻留在内存中,为后续的其他请求服务,直至web容器退出,Servlet实例对象才会销毁。
              在Servlet的整个生命周期内,Servlet的init()方法只被调用一次,而对于每一个请求都会调用一次Servlet的service()方法service根据请求方式调用doGet或doPost方法
              如果在<servlet>元素中配置了一个<load-on-startup>元素,那么WEB应用程序在启动时,就会装载并创建实例对象、以及调用Servlet实例对象的init()方法。可以在启动的时候为整个WEB应用创建一些必要的的资源或连接。但如果所有的Servlet都启动加载,则会大大增加服务器负担,而且有些Servlet永远也不会被客户访问到,白白浪费资源,所以从性能角度,应合理利用该特性。
servlet技术
<servlet>
    <servlet-name>invoker</servlet-name>
    <servlet-class>
            org.apache.catalina.servlets.InvokerServlet
    </servlet-class>
    <load-on-startup>2</load-on-startup><!--数字表示启动加载的优先级,大于0-->
</servlet>
servlet技术

          6、ServletConfig对象

                在Servlet的配置文件中,可以使用一个或对个<init-param>标签为Servlet配置一些初始化参数。
                当Servlet配置了初始化参数后,web容器在创建Servlet实例对象时,会自动将这些初始化参数封装到ServletConfig对象中,并在调用Servlet的init方法时,将ServletConfig对象传似给Servlet,开发者可以通过ServletConfig对象得到初始化参数信息。
           7、ServletContext对象
                WEB容器在启动时,它会为每个WEB应用程序都创建一个对应的Servlet对象,它代表当前web应用。
                ServletConfig对象中维护了ServletContext对象的引用,开发者在编写Servlet是,可以通过ServletConfig.getServletContext方法获得该对象。
                由于一个WEB应用中的所有Servlet共享同一个ServletContext对象,因此Servlet对象之间可以通过ServletContext对象来实现通讯。ServletContext对象通常也被称之为Context域对象
                 多个Servlet通过ServletContext对象实现数据共享。要确保注意线程安全。
                 可以通过ServletContext对象获取WEB应用的初始化参数。
                 可以实现Servlet的转发。getRequestDispatcher()方法
          8、Servlet常用容器Tomcat(左图:Tomcat容器;右图:Servlet的执行流程)
              servlet技术  servlet技术
          9、Servlet体系结构(接口)
               servlet技术
servlet技术

servlet技术
             从上图可以看出Servlet规范是基于这几个类运转的,与Servlet主动关联的是三个类:ServletConfig、ServletRequest、ServletResponse。这三个类都是通过容器传递给Servlet的。
             ServletConfig接口中的方法都是为了获取这个Servlet的一些配置属性,而这些配置属性可能在Servlet运行时被用到。
             ServletContext就是这些配置属性的上下文环境。
 
三、Servlet中的Session与Cookie
           Servlet能够给我们提供两部分数据,一个是在Servlet初始化时调用init方法设置的ServletConfig,它基本包含了Servlet本身和Servlet所运行的Servlet容器中的基本信息。另一个是ServletRequest提供的这次请求的HTTP协议信息,这部分需要很清楚HTTP协议。
           Session与Cookie的作用都是为了保持访问用户与后端服务器的交互状态,各有优缺点然而具有讽刺意味的是它们优点和它们的使用场景又是矛盾的,例如使用 Cookie 来传递信息时,随着 Cookie 个数的增多和访问量的增加,它占用的网络带宽也很大,试想假如 Cookie 占用 200 个字节,如果一天的 PV 有几亿的时候,它要占用多少带宽。所以大访问量的时候希望用 Session,但是 Session 的致命弱点是不容易在多台服务器之间共享,所以这也限制了 Session 的使用。

           Session正常工作的实现方式:

               基于URL Path Parameter,默认支持
               基于Cookie,若不修改Context中的cookie标识,默认支持
               基于SSL,默认不支持,只有connector.getAttribute("SSLEnabled")为true时才支持。
 
四、Servlet中的Listener

(可以实现在线人数的监视)

        整个Tomcat服务器中Listener使用的非常广泛,它是基于观察者模式的,Listener的设计对开发Servlet应用程序提供了一种快捷的手段,能够方便的从另一个纵向唯独控制程序和数据,目前Servlet中提供了5中两类事件的观察者接口,他们分别是:4个EventListener类型的,ServletContextAttributeListener、ServletRequestAttributeListener、ServletRequestListener、HttpSessionAttributeListener 和 2 个 LifecycleListeners 类型的,ServletContextListener、HttpSessionListener。
           它们基本上涵盖了整个Servlet生命周期中,你感兴趣的每种事件,这些Listener的实现类可以配置在web.xml中的<listener>标签中,当然也可以在应用程序中动态添加Listener,但是ServletContextListener在容器启动之后就不能再添加新的,因为它监听的事件已经不会再出现。掌握这些Listener的使用,能够让我们的程序设计的更加灵活。
 
五、Servlet3.0新特性注解
        前面介绍过Servlet3.0提供了注解(annotation),使得不再需要在web.xml文件中进行Servlet的部署描述。
        开发者可以使用@WebServlet注解将一个继承于javax.servlet.http.HttpServlet的类标注为可以处理用户请求的Servlet。   
  @WebServlet注解的相关属性
NO. 属性名 描述
1 asyncSupported 声明Servlet是否支持异步操作模式
2 description Servlet的描述信息
3 displayName Servlet的显示名称
3 initParams Servlet的初始化参数
5 name Servlet的名称
6 urlPatterns Servlet的访问URL
7 value Servlet的访问URL

         Servlet的访问URL是Servlet的必选属性,可以选择使用urlPatterns或者value定义。


第二部分:

一、Servlet之Request
        Web服务器会对收到的每一次客户端http请求分别创建一个用于代表请求的request对象和代表响应的response对象。要获取客户端提交的数据需通过request,要想容器输出数据需通过response。
        1、HttpServletRequest
           HttpServletRequest对象代表客户端的请求,当客户端通过HTTP协议访问服务器时,HTTP请求头中的所有信息都封装在这个对象中,开发人员通过这个对象的方法可以得到客户的相关信息。
        2、Request常用方法(参考官方API)
            获得客户机信息:
                 getRequestURL,返回客户端发出请求时的完整URL
                 getRequestURI, 返回请求行中的资源名部分
                 getQueryString, 返回请求行中的查询字符串,通常为?后边携带的参数信息
                 getRemoteAddr, 返回客户端IP地址
                 getRemoteHost, 返回客户端的主机名
                 getRemotePort, 返回客户端的网络端口号
                 getLocalAddr, 返回Web服务器的IP地址
                 getLocalName, 返回Web服务器的主机名
                 getMethod, 返回客户端的请求方式(get/post)
             获得客户机请求头:
                 getHeader() 
                 getHeaders()
                 getHeaderNames()
             获得客户机请求参数:
                 getParameter()
                 getParameterValues()
                 getParameterNames
        3、Request请求参数的中文乱码问题
              一般浏览器使用什么编码,则传送的数据就以什么编码,但有许多Web浏览器不发送带有“content-type”头信息的字符编码限定符,而由读取http请求的代码类决定自读的编码方式。
              默认情况下,如果客户端请求未定义编码限定符,容器(如Tomcat)会用“ISO-8859-1”去创建request reader 和解析post数据。
              注意:自从Tomcat5.x开始,GET和POST方法提交的信息,Tomcat采用了不同的方式来处理编码,对于POST请求,Tomcat会仍然使用request.setCharacterEncoding方法所设置的编码来处理,如果未设置,则使用默认的"ISO-8859-1"编码。而对GET请求,并不会考虑使用request.setCharacterEncoding方法设置编码,而会永远使用“ISO-8859-1”编码。        
              所以,一般的解决方式为:
                    POST方式:在最开始设置request.setCharacterEncoding("UTF-8")
                    GET方式: new String(username.getBytes("ISO-8859-1"),"UTF-8")
                    修改Tomcat的配置可以解决URL中中文编码问题:<Connector URIEncoding="UTF-8"/>
          4、转发和包含
                 一个Servlet对象无法获得另一个Servlet对象的引用,如果需要多个Servlet组件共同协作(数据传递),只能使用Servlet规范提供的请求转发和包含这两种方式:
                  请求转发:Servlet(源组件)先对客户请求最初一些预处理操作,然后把请求转发给其他web组件(目标组件)来完成包括生成响应结果在内的后续操作。
                  包含: Servlet(源组件)把其他web组件(目标组件)生成的响应结果包含到自身的响应结果中。
                  两者共同点:
                         源组件和目标组件处理的都是同一个酷虎请求,源组件和目标组件共享同一个ServletRequest和ServletResponse对象。
                         目标组件可以为Servlet、JSP、HTML文档等
                         都依赖javax.servlet.RequestDispatcher接口。
           5、RequestDispatcher请求分发器
                     它包含两个方法:
                       forward():把请求转发给目标组件
                       include():包含目标组件的响应结果
                     得到RequestDispatcher对象
                         1、ServletContext对象的getRequestDispatcher(String path1)。path1必须用绝对路径,即以‘/’开头,若用相对路径会抛出IllegalArgumentException异常
                         2、ServletRequest对象的getRequestDispatcher(String path2)。 path2可以用绝对路径也可以用相对路径。
                     如果使用forward()方法,只会返回目标组件的响应结果,所以不应该在源组件中提交响应结果,而且,如果在源组件调用了Response的flush或close方法,会抛出IllegalStateException异常
                     如果使用include()方法,则源组件与目标组件的输出都会被添加到响应结果中,在目标组件对响应头做的修改会被忽略
           6、请求范围
                     web应用范围内的共享数据作为ServletContext对象的属性而存在,只要共享ServletContext对象也就共享了其属性。
                     请求范围内的共享数据作为ServletRequest对象的属性而存在,只要共享了ServletRequest对象,也就共享了其数据。
 
二、Servlet之Response
          1、HttpServletResponse
             HttpServletResponse对象代表服务器的响应,这个对象中封装了向客户端发送数据、发送响应头,发送响应状态码的方法。
          2、Response常用方法
             setStatus();设置状态码
             setHeader();设置响应头
             getWriter();返回一个响应的打印流
             getOutputStream();返回一个响应的字节输出流
             注意:getWriter与getOutputStream两个方法相互排斥,调用了其中一个方法后就不能再调用另一个,否侧会抛出异常,Servlet引擎会检查输出流是否关闭,并调用close方法,所以不需要自己关闭。
          3、Response中的中文问题
             通过设置响应头告知客户端编码方式:response.setHeader("Content-Type","text/html;charset=UTF-8")
             通过meta标签模拟请求头::out.write("<meta http-equiv='Content-Type' content='text/html; charset=utf-8' />".getBytes())
             通过直接方法:response.setContentType("text/html;charset=UTF-8");这条语句的作用是将自己的编码设置为UTF-8,并告诉浏览器使用UTF-8解码
          4、Response常见应用
              控制浏览器定时刷新:response.setHeader("Refresh","2");也可以定时刷新到某一个URL
              控制浏览器缓存当前文档:
response.addDateHeader("Expires",System.currentTimeMillis()+1000*60*60);//缓存一小时,对于一些不怎么变化的数据,利用缓存能减轻服务器的负担
              请求重定向:response.sendRedirect(location);
              重定向特点:
                 Servlet源组件生成的响应结果不会被发送到客户端,response.sendRedirect(location)方法一律返回状态码为302的响应结果。
                 如果源组件在进行重定向之前,已经提交了响应结果,会抛出IllegalStateException异常,所以,不应该在元组件中提交响应结果。
                 Servlet源组件重定向语句后面的代码也会执行。
                 源组件和目标组件不共享一个ServletRequest对象。
                 对于response.sendRedirect(location)方法的参数,如果以"/"开头,表示相当于当前服务器根路径的URL。以"http://"开头,表示一个完整路径。
                 目标组件不必是同一个服务器上的同一个web应用的组件,它可以是任意一个有效的网页。
 
三、Cookie&Session
        1、什么是会话:     
            用户开一个浏览器,点击对个超链接,访问服务器多个Web资源,然后关闭浏览器,整个过程称之为一个会话(有时长限制)。
            每个用户在使用浏览器与服务器进行会话的过程中,不可避免各自会产生一些数据,程序要想办法为每个用户保存这些数据。
        2、保存会话数据的两种技术:
              Cookie(小甜点):Cookie是客户端技术,程序把每个用户的数据以cookie的形式写给用户各自的浏览器。当用户使用浏览器再去访问服务器中的Web资源时,就会带着各自的数据去。这样,web资源处理的就是用户各自的数据了。
              HttpSession:Session是服务器端技术,利用这个技术,服务器在运行时可以为每一个用户的浏览器 创建一个其独享的HttpSession对象,由于session为用户浏览器独享,所以用户在访问服务器的web资源时,可以把各自的数据放在各自的session中,当用户再去访问服务器中的其他web资源是,其他web资源在从用户各自的session中取出数据为用户服务。
        3、Cookie API
            javax.servlet.http.Cookie类用于创建一个Cookie,response接口中定义了一个addCookie方法,它用于在其响应头中增加一个相应的Set-Cookie头字段。同样,request接口中也定义了一个个头Cookie方法,它用于获取客户端提交的Cookie。Cookie类的方法:
          public Cookie(String name,String value);
          setValue与getValue方法
          setMaxAge与getMaxAge方法
          setPath与getPath方法
          setDomain与getDomain方法
          getName方法
          由于Cookie保存在客户端,所有,给不给传Cookie是由浏览器决定的,取决于MYURL.startWith(domain+path)完全匹配。domain是主机名加端口号,path是从第一个"/"开始的文件路径。
          cookie.setPath("/");可以让该cookie在同一个服务器下的多个项目共享。
        4、Cookie细节
            一个Cookie只能表示一种信息,它至少患有一个标识该信息的名称(name)和设置值(value)。
            一个Web应用可以给一个浏览器发送多个Cookie;一个浏览器也可以存储多个Web网站的Cookie。
            每个浏览器有自己默认的存放Cookie个数,并限制每个站点存放Cookie的个数,每个Cookie的大小限制为4kb。
            如果创建了一个cookie,并将它发送到浏览器,默认情况下它是一个会话级别的cookie(即存储在浏览器的内存中),用户退出浏览器之后即被删除,若希望浏览器将该cookie存储在磁盘上,则需要使用maxAge,并给出一个以秒为单位的时间。将最大时效设为0则是命令浏览器删除该cookie。
            注意,删除cookie是,path必须一致,否则不会删除。   
        5、Session       
            在web开发中,服务器可以为每个用户浏览器创建一个会话对象(Session对象),把用户数据写到用户浏览器独占的Session中,当前用户使一个浏览器独占一个Session对象。因此,需要保存用户数据时,服务器程序可以用Session保存,统一浏览器可以从用户的Session中取出该用户的数据,为用户服务。
            Session对象有服务器创建,开发人员可以调用request对象的getSession方法得到Session对象。
            浏览器第一次请求时,服务器会在响应头中加入Set-Cookie: JSESSIONID=022841F4A201530430481C66F0D29FB8; Path=/Day28ServletResponse/; HttpOnly。当浏览器下次请求时会携带这个Session的唯一标识,Cookie: JSESSIONID=022841F4A201530430481C66F0D29FB8。服务器就之后是同一个用户的行为了。
            服务器内存中的每个Session都有一个32位的id作为唯一标识,Tomcat为每个Session默认的生存时间为30分中。
         6、浏览器禁用Cookie之后的Session处理
             浏览器禁用Cookie之后,就无法再请求中携带JSESSIONID内容,所以导致服务器共享出问题。Java提供URL重写方案:
             response.encodeRedirectURL(url);对sendRedirect方法的URL地址进行重写。
             response.encodeURL(url);对表单action和超链接的url地址进行重写。
             如果用户浏览器没有禁用Cookie,重写方法什么也不做;如果用户浏览器禁用了Cookie,则重写方法在每个URL地址中携带JSESSIONID,服务器保证了一个用户的每一个请求行为携带SessionID,从而保证Session的作用。
             Session的invalidate()方法使Session立刻失效。
             可以在项目的web.xml中配置Session失效时间。
 
 
四、Servlet高级特性--过滤器
servlet技术
        1、过滤器概述:
         过滤器是Servlet2.3规范新增的功能,也是Servlet容器管理的对象,其结构同Servlet很类似,比如init()方法,destory()方法, 但是功能不同,过滤器主要是在源数据与目的数据之间起过滤作用的中间组件。
        2、过滤器链
         在一个Web应用中,可以一次编写多个过滤器,这些过滤器组合起来,称为一个过滤器链,其执行顺序为注册顺序,先注册的会先执行
        3、编码转换过滤器
          在JavaWeb开发中,初学者经常会遇到java乱码的问题,统一字符编码,是解决乱码问题非常有效的手段,在Web开发中,可以使用过滤器对请求中的参数信息进行编码转换。
servlet技术
        4、权限校验过滤器(清楚整个处理流程)
           根据不同的权限,用户分别能够访问不同的页面。