Servlet(五)
一、什么是Servlet
Servlet是Java定义的接口规范,由Web厂商(如Tomcat)实现,提供其实现。也就是我们常用的Web容器。其他的Web容器还有如weblogic、JBoss。
Servlet接口的定义,就是为了规范网络编程中的信息交互和方式。
- Servlet是一种Web服务器端编程技术,是实现了特殊接口的Java类。
- 由支持Servlet的Web服务器调用和运行。
- 一个Servlet负责对应的一个或一组url访问请求,并返回相应的响应内容。
再说下JavaEE,JavaEE平台构架于JavaSE平台上,JavaEE平台提供一组API和运行环境来开发和运行大规模的、多层次的、可扩展的、可靠的、安全的网络应用程序。简而言之,JavaEE=JVM(虚拟机)+API+网络应用程序。可理解为是具有JVM和一组特定API的编写网络应用程序的平台。
(JavaSE的API提供Java编程语言的核心功能,定义了Java语言的一切(基本类型、对象、更高级的用于网络和安全的数据库的类、GUI、XML解析的类。除了核心的API,JavaSE平台由一个虚拟机、开发工具和其他类库及通常被Java应用程序使用的工具箱组成。))
Servlet是J2EE规范中的一种,主要是为了扩展java作为web服务的功能,J2EE从92年到的J2EE 1.2到现在JavaEE8从12个规范到现在20多个规范,越来越完善他的作用就是为java程序提供一个统一的web应用规范,方便程序员统一的使用这种规范来编写程序,应用容器可以使用提供的规范来实现自己的特性。比如tomcat的代码和jetty的代码就不一祥 是吧,但作为程序员你只需要了解servlet规范就可以从request中取值,你可以操作session等等。 不用在意应用服务器底层的实现的差别而影响你的开发当然你也可以自己写一个http服务器,自己定义一套API,比如你在底层接受到一个http请求后,你把这个http请求的header、cookie和param等封装成一个MyRequest.class。然后你要得到,你在你的MyServlet中从MyRequest对象中拿到param请求参数,校验成功后雲要返还给浏览器一 个HTTP response。其中必须要有一个session ,所以你往cookie中写了一个字段, LAOZIDESESSIONID=878361839QWQWEQEQE,同时把这个 sessionid 放在了自己的内存中。下 —次浏览器再访问你就会带上这个LAOZIDESESSIONID这个cookie ,你就知道他原来已经访问过 了,而且上一次访问的数据你都有(在第一次保存在内存中)比如tomcat你可以<Context sessionCookieName"heshilaozidesessionid" >
讲了这么多废话,总结来说Servlet就是一群人来制走java应用中使用web时的各种规范,统一接 口,其他内部实现由厂商自己实现,tomcat、jetty、jboss等等应运而生。面向接口编程!!很熟悉吧关于他如何工作的:一个http请求到来,容器将请求封装成servlet中的request对象,在request中你可以得到所有的http信息,然后你可以取出来操作,最后你再把数据封装成servlet的response对象,应用容器将respose对象解析之后封装成一个http response。
参看链接https://www.zhihu.com/question/21416727
二、为什么要用Servlet
我的理解,就是为了统一规范。才在JavaEE中,定义了Servlet接口规范。Servelet主要针对Web应用程序。
我们只是利用Servet进行一个调用作用,并不是实现功能。
三、Servlet的工作原理
根据笔记整理,简单介绍Tomcat容器里,Servlet的工作流程。
Servlet的生命周期:
载入==》初始化==》执行==》销毁
1、载入
载入即加载一个Servlet类。Servlet实例化是Tomcat自动完成的(通过反射)。
Servlet采用的是懒汉式单例模式。Tomcat默认为懒汉式。即在有请求时,访问Servlet,Tomcat才会对Servlet进行实例化,然后调用init()方法进行初始化,然后执行Service方法,最后进行销毁。
2、初始化
初始化即将实例化的Servlet加入到服务器列表当中,init()方法只会被调用一次,一旦多次调用,即是初始化了多个Servlet,与单实例多线程也是矛盾的。(初始化的是实例化后的Servlet)。
3、执行
一旦init方法完美执行,则Service方法会被调用,每增加一个新的请求,就会调用一次Service方法。
4、销毁
当Servlet退出服务的时候,destory()方法就是被调用。destory()是被动执行的,只有在servlet被销毁时,才会执行。
注:可以通过在web.xml中添加配置信息:在<Servlet>中添加:<load-on-startup>标签。
让Servlet在加载时,即还没有访问时,就进行实例化。
四、Servlet三大作用域
4.1 三大作用域
作用域:存储属性值,便于页面跳转之间的数据(值)传递,共享数据的一种传递。
Servlet中常用来存储数据的三大作用域:按照使用范围从小到大排列为: HttpServletRequest、HttpSession、ServletContext三个作用域,下边详细介绍这三个作用域。
1、HttpServletRequest作用域:
存入数据的方法request.setAttribute("User",user);(这里是把user放入到request作用域中,key是User,value是user),此作用域保存的数据只是针对一次请求。使用该对象保存数据,一次请求内数据有效。请求转发是属于一次请求的,所以放在此作用域中的数据,在一个页面转发多个页面数据都是有效的。
- 作用域创建时间:客户端向服务器发送一次请求时创建。
- 销毁时间:服务器为这次请求作出响应之后,销毁request。
2、HttpSession作用域:
针对一次会话,使用该对象保存数据,数据保存在服务器上,一次会话(多个请求)内数据有效,如果关闭一次浏览器,结束这次回话,再次打开的时候session就失效了;但是并没有销毁,销毁由过期时间决定。
- 创建时间:服务器第一次调用getSession()方法的时候,服务器创建session对象。
- 销毁时间:销毁有三种情况:
- 服务器非正常关闭(正常关闭时:Session被序列化);
- Session过期,xml文件配置默认时间是30分钟。
- 手动调用Session的invalidate的方法。
3、SevletContext作用域:
接口上下文环境每一个虚拟机只有一个该项目作用域为该项目,服务器不关闭,不会改变。
针对一个web应用。一个web应用只有一个SevletContext对象,使用该对象保存的数据在整个web应用中都有效。
- 创建时间:服务器启动的时候。
- 销毁时间:服务器关闭的时候或者项目移除的时候。
关于servletContext WEB容器在启动时,它会为每个WEB应用程序都创建一个对应的ServletContext对象,它代表当前web应用。ServletConfig对象中维护了ServletContext对象的引用,开发人员在编写servlet时,可以通过ServletConfig.getServletContext方法获得ServletContext对象。由于一个WEB应用中的所有Servlet共享同一个ServletContext对象,因此Servlet对象之间可以通过ServletContext对象来实现通讯。ServletContext对象通常也被称为context域对象。
多个Servlet通过ServletContext对象实现数据共享。
获取WEB应用的初始化参数。在web.xml文件中配置需要初始化的参数信息。
4、注意
如果数据保存在request对象中,一般使用请求转发,来获取。因为请求转发是只有一次请求的。但是如果是重定向,因为重定向是多次请求,所以不能使用request中的数据,可以使用session或context中的。
5、三个作用域通用API:
存放数据:setAttribute(name,value)
获取数据:getAttribute(name);
删除数据:removeAttribute(name);*/
参看链接:https://www.cnblogs.com/xianyao/p/10793478.html介绍servlet三大作用域与jsp的四大作用域和九大内置对象。
4.2 session、cookie、过滤器、拦截器、监听器简略
从过滤器、拦截器与监听器开始说起:
4.2.1 过滤器
1、过滤器是请求到达目标资源(Servlet和Jsp)之前的预处理程序。
2、过滤器是响应离开了目标资源后的后处理程序。
3、过滤器运行在服务器端。
4、可以定义多个过滤器,每个过滤器完成一个任务。请求或响应可以依次经过多个过滤器。
5、使用场景:相同相似的代码出现在项目的多个位置,导致添加多次、修改多次,删除多次,不利于项目的维护,可以将相同、相似的代码提取出来。例如:中文乱码的处理、权限验证、字符替换、事务处理、记录日志、压缩与解压缩。
6、过滤器执行的顺序是在web.xml中的filer-mapping的配置顺序。
7、Filter技术只对Post请求起作用。
8、过滤器不仅要开发,还要进行在web.xml配置(设置哪些请求经过哪些过滤器)。
- 开发一个过滤器必须实现java定义好的javax.servlet.Filter接口
- web.xml中的配置<filter>
<filter> <filter-name>AuthFilter</filter-name> <filter-class>cn.bjsxt.sscs.filter.AuthFilter</filter-class> </filter> <filter-mapping> <filter-name>AuthFilter</filter-name> <url-pattern>/servlet/*</url-pattern> <url-pattern>*.jsp</url-pattern> <url-pattern>*.html</url-pattern> </filter-mapping>
3.测试
4.方法
doFilter(ServletRequest, ServletResponse, FilterChain):这是一个完成过滤行为的方法。这同样是上游过滤器调用的方法。引入的FilterChain对象提供了后续过滤器所要调用的信息。如果该过滤器是过滤器链中的最后一个过滤器,则将请求交给被请求资源。也可以直接给客户端返回响应信息。
init(FilterConfig):由Web容器来调用完成过滤器的初始化工作。它保证了在第一次doFilter()调用前由容器调用。您能获取在 web.xml 文件中指定的初始化参数。
destroy():由Web容器来调用来释放资源,doFilter()中的所有活动都被该实例终止后,调用该方法。
5.指定该过滤器关联的URL样式。url-pattern主要有四种匹配方式:
(a)精确匹配,就是填写jap或Servlet等需要过滤的请求的具体地址,例如:/Filter/TestFilter
(b)扩展匹配,由“*”号和扩展名组成,例如*.jsp
(c)路径前缀匹配,包含一个目录和一个/* 例如:/Servlet/*指的是对Servlet目录下的所有资源进行过滤
(d)全部匹配,使用/*,指的是对所以资源都过滤
9、Filter流程总述:
请求发起时,Web容器先判断是否存在过滤器和这个请求的资源相关,如果有存在关联就把请求交给过滤器去处理,在过滤器中可以对请求的内容做出改变,然后再将请求转交给被请求的资源。当被请求的资源做出响应时,Web容器同样会将响应先转发给过滤器,在过滤器中可以对响应做出处理然后再将响应发送给客户端。在这整个过程中客户端和目标资源是不知道过滤器的存在的。
过滤器对请求做了两次(对request和response)过滤,其实Filter是对请求中的Request和Response进行了拦截。
拦截到了进行处理,处理完后再返回到其原来的调用流程上去。这点体现了责任链模式。
在一个Web应用程序中可以配置多个过滤器,从而形成过滤器链。在请求资源时,过滤器链中的过滤器依次对请求作出处理。在接受到响应时再按照相反的顺序对响应作出处理。多个过滤器的执行顺序是按照web.xml中filter(<filter-mapping>)的配置的上下顺序来决定的。
10、使用Filter的好处:
在Filter执行的整个过程中客户端和目标资源是不知道过滤器的存在的。Filter提供的是一种声明式的服务,即在不用在原程序上做任何修改,只需要编写Filter,原程序想用Filter,只需要在XML文件中声明一下即可。他具有可插拔的能力,用的时候配上web.XML,不用的时候只需要修改web.xml,对整个系统没有影响,这种声明式的服务非常方便,也非常强大。
其次,使用Filter进行控制业务也非常方便,比如验证用户是否登录,是否有操作权限,判断Session,字符集等,放到Filter里,可以省去大量重复的代码和繁琐的控制。
11、转发是服务器内部的跳转,不经过过滤器,需要配置才能进行过滤。
forward跳转到main.jsp url不变,因此过滤器只过滤一次/index.jsp的访问; 当然这是针对dispatcher类型是默认的REQUEST而言,如果将dispatcher类型改为FORWARD,那么即使url不变,也可以过滤Forward跳转行为。
<filter-mapping> <filter-name>EncodingFilter</filter-name> <url-pattern>/servlet/*</url-pattern> <dispatcher>REQUEST</dispatcher> <dispatcher>FORWARD</dispatcher> </filter-mapping>
4.2.2拦截器
4.2.3监听器
1、定义
2、用处
什么用呢?百度下,很多。
web监听器的用途
1,统计在线人数和在线用户,也是监听器的主要用途之一
2,系统启动时加载初始化信息,包括一些缓存,功能的定时器
3,统计网站访问量,每次请求都可通过request来获取
4,跟Spring结合,做相关的操作
3、分类
监听器一共有八种(分类的别看了,头晕)记住242,按作用域范围的个数。
3.1 按监听的对象划分:
servlet2.4规范定义的事件有三种-------->和servlet中三大作用域(HttpServletRequest、HttpSession、ServletContext)是对应的:
1.用于监听应用程序环境对象(ServletContext)的事件监听器(2)
2.用于监听用户会话对象(HttpSession)的事件监听器(4)
3.用于监听请求消息对象(ServletRequest)的事件监听器(2)
3.2 按监听的事件类项划分
1.用于监听域对象自身的创建和销毁的事件监听器(3)
2.用于监听域对象中的属性的增加和删除的事件监听器(3)
3.用于监听绑定到HttpSession域中的某个对象的状态的事件监听器(2)
监听域对象本身的创建与销毁(3个)均有两个方法
ServletRequestListener,HttpSessionListener,ServletContextListener
监听域对象中属性的增、删、改的监听器(3个)均有3个方法
ServletContextAttributeListener,HttpSessionAttributeListener,ServletRequestAttributeListener
以上两类监听器必须在web.xm中注册才可以
感知型监听器(2个):监听自己何时被绑到session,何时解绑了;何时被钝化了,何时被活化了
HttpSessionBindingListener实现该接口的类能检测自己何时被绑定和解绑
HttpSessionActivationListener实现该接口的类能监测自己何时随着HttpSession一起活化和钝化。
钝化:序列化到硬盘上;活化:反序列化到内存中。
该类监听器不需要再web.xml中注册,但是需要相应的类实现对应接口
3.3 用法浅析
那么作为初学者的我,简单看了下,现在就会看请求的产生和销毁,一个session会话的产生和销毁,application道理也一样吧。
说下怎么用吧,这才是要掌握的,三步:实现监听器的接口,配置监听器,测试监听器。
第一步:定义监听器,实现监听器的接口
创建一个实现类,就是你自己建了一个监听器,里面实现接口的的方法。拿HttpSessionListener来说吧,就两个方法,创建和销毁的方法,你可以在里面敲自己想要的代码,不是实现你想要的功能,信息。当然了,里面的代码会在session对象创建和销毁时执行,毕竟你就是来监听人家这个的嘛。
第二步:配置监听器
在web.xml中 <listener> <listener-class>cn.bjsxt.sscs.listener.SettionTestListener</listener-class> </listener>
简单吧,就一句话。
感觉吧,就是告诉服务器来实现这个监听吧,不然250似的杵个实现类在那里,谁来用你啊。
第三步:测试监听器
这里说下session吧,我在自己测试监听它时,只监听到了创建时的代码,没监听到销毁时的代码,就又看了看session的创建和销毁。
<session-config> <session-timeout>1</session-timeout> </session-config>
这个在web.xml里配置,什么意思呢,你创建完session后一分钟不在操作,session就过期啦!!!
4.2.4 session
1、定义
Session会话是客户端唯一的一个标识ID,是在客户端与服务器建立连接时产生的。HttpSession技术,即将http状态信息保存在服务器端的技术。session的id由cookie管理,而cookie是存放在客户端的。
2、生命周期
我们知道Session是JSP的九大内置对象(也叫隐含对象)中的一个,它的作用是可以保存当前用户的状态信息,初学它的时候,认为Session的生命周期是从打开一个浏览器窗口发送请求到关闭浏览器窗口,但其实这种说法是不正确的!下面就具体的去解释:
当用户第一次访问Web应用中支持Session的某个网页时,就会开始一个新的Session,那么接下来当用户浏览这个Web应用的不同网页时,始终处于一个Session中。
再详细些:
当一个Session开始时,Servlet容器会创建一个HttpSession对象,那么在HttpSession对象中,可以存放用户状态的信息Servlet容器为HttpSession对象分配一个唯一标识符即Sessionid,Servlet容器把Sessionid作为一种Cookie保存在客户端的 *浏览器* 中用户每次发出Http请求时,Servlet容器会从HttpServletRequest对象中取出Sessionid,然后根据这个Sessionid找到相应的HttpSession对象,从而获取用户的状态信息以上就是Session的运行机制,但是还没有提到Session的生命周期,再往下了解!
其实让Session结束生命周期,有以下两种办法:
一个是Session.invalidate()方法,不过这个方法在实际的开发中,并不推荐,可能在强制注销用户的时候会使用;
一个是当前用户和服务器的交互时间超过默认时间后,Session会失效。
我们知道Session是存在于服务器端的,当把浏览器关闭时,浏览器并没有向服务器发送任何请求来关闭Session,自然Session也不会被销毁,但是可以做一点努力,在所有的客户端页面里使用js的window.onclose来监视浏览器的关闭动作,然后向服务器发送一个请求来关闭Session,但是这种做法在实际的开发中也是不推荐使用的,最正常的办法就是不去管它,让它等到默认的时间后,自动销毁。
那么为什么当我们关闭浏览器后,就再也访问不到之前的session了呢?
其实之前的Session一直都在服务器端,而当我们关闭浏览器时,此时的Cookie是存在于浏览器的进程中的,当浏览器关闭时,Cookie也就不存在了。
其实Cookie有两种:
一种是存在于浏览器的进程中;
一种是存在于硬盘上;
而session的Cookie是存在于浏览器的进程中,那么这种Cookie我们称为会话Cookie,当我们重新打开浏览器窗口时,之前的Cookie中存放的Sessionid已经不存在了,此时服务器从HttpServletRequest对象中没有检查到sessionid,服务器会再发送一个新的存有Sessionid的Cookie到客户端的浏览器中,此时对应的是一个新的会话,而服务器上原先的session等到它的默认时间到之后,便会自动销毁。
3、是否为同一个session
当在同一个浏览器中同时打开多个标签,发送同一个请求或不同的请求,仍是同一个session;
当不在同一个窗口中打开相同的浏览器时,发送请求,仍是同一个session;
当使用不同的浏览器时,发送请求,即使发送相同的请求,是不同的session;
当把当前某个浏览器的窗口全关闭,再打开,发起相同的请求时,就是本文所阐述的,是不同的session,但是它和session的生命周期是没有关系的。
4、如果用户一直在访问网页,session会不会过期呢?
如果一直在访问是不会过期的。只有一段时间内不操作,才会过期(前期是设置了过期时间);
5、 当浏览器关闭时,Session就被销毁了?
并没有,在自然状态下,销毁只跟它的生命周期相关。
6、销毁
session失效时间设置
一、java代码 <!--优先级是最高的--> request.getSession().setMaxInactiveInterval(1800);/*秒为单位,1800= 60*30 即30分种 调用invalidate()方法直接销毁session.invalidate(); 二、web.xml <session-config> <!--分钟为单位--> <session-timeout>30</session-timeout> </session-config> <servlet> <!--秒为单位--> <servlet-name>Example</servlet-name> <servlet-class>com.*.*.Example</servlet-class> <init-param> <param-name>timeout</param-name> <param-value>600</param-value> </init-param> </servlet> 三、web服务器resin.conf,tomcat,<!--优先级是最低的--> <session-config> <!--分钟为单位--> <session-timeout>30</session-timeout> <enable-url-rewriting>false</enable-url-rewriting> </session-config> tomcat的web.xml中默认设置的session过期时间为30分钟。
优先级: 1 > 2 > 3 */
4.2.5 cookie
参看链接自己博文关于cookie的详解。https://www.cnblogs.com/szrs/p/14373813.html
4.2.6 博文链接
关于session、cookie、过滤器、拦截器在“网络编程(一)”中有单独的博文介绍,链接:
session与cookie简介及区别:https://www.cnblogs.com/szrs/p/14375542.html
过滤器、拦截器简介与区别:https://www.cnblogs.com/szrs/p/14404357.html
关于拦截器的代码层次的简单应用在“分布式相关”里,介绍spring的应用时有简单说明,详见链接:https://www.cnblogs.com/szrs/p/12157083.html
五、转发与重定向
5.1 转发
1、转发是发生在服务器内部的资源跳转;
2、转发在地址栏中只会保存第一次访问的路径地址;
3、请求转发,无论转发多少次,都是同一个请求,因此携带的参数会随着请求的转发而转发。
5.2重定向
1、重定向是多次请求;第一次请求返回状态码302,代表请求会被重定向,第二次请求返回200状态码,表示发生了正常的请求与响应。
2、使用重定向无法获取上一次请求携带的参数。
3、重定向地址栏地址会随着新的请求发生改变。
4、重定向既可以访问服务器内部资源,也可以访问外部资源。
5、使用重定向时,path路径不可以加/,/表示当前服务器的根路径,而不是当前部署的项目的根路径。
5.3 转发与重定向的区别
1、转发是在一个服务器应用不同的jsp间跳转;
2、重定向可以在两个服务器间进行跳转。
详见链接:对转发与重定向的详细说明:https://www.cnblogs.com/zhangshuaivole/p/12463000.html
在所有的矛盾中,要优先解决主要矛盾,其他矛盾也就迎刃而解。
不要做个笨蛋,为失去的郁郁寡欢,聪明的人,已经找到了解决问题的办法,或正在寻找。