一、mvc模式
M(Model)V(View)C(Controller)——架构模式,主要是一种“分层”思想(面向接口编程,package包分的细一点)
- Model(模型)—模型代表一个存取数据的对象或JAVAPOJO.它也可以带有逻辑,在数据变化时更新控制器。
- View(试图)—视图代表模型包含的数据的可视化。
- Controller(控制器)—控制器作用于模型和视图上。它控制数据流向模型对象,并在数据变化时更新视图。它使视图于模型分离开。
- Web浏览器发送HTTP请求到服务端,被Controller(Servlet)获取并进行处理(例如参数解析、请求转发)
- Controller(Servlet)调用核心业务逻辑——Model部分,获得结果
- Controller(Servlet)将逻辑处理结果交给View (JSP),动态输出HTML内容◆动态生成的HTML内容返回到浏览器显示
- 动态生成的HTML内容返回到浏览器显示
- MVC模式在Web开发中的好处是非常明显,它规避了JSP与Servlet各自的短板,Servlet只负责业务逻辑而不会通过out.append()动态生成HTML代码;JSP中也不会充斥着大量的业务代码。这大大提高了代码的可读性和可维护性。
这是由于传统MVC模式中的三个部分没有明确定义、开发层次划分的细化加深和实际开发应用情形的愈加复杂,使得mvc模式的设计需要根据实际情况进行更为精心的理解和设计。所以mvc模式更多的体现在—种划分层次的思想,而不是固定的分包模板。
二、Cookie和Seeion
1、Cookie
Cookie的概念
Cookie是保存在客户端(浏览器)的小文本,保存的位置分两种
(1)Cookie可能保存在客户端浏览器的所占内存,关闭浏览器后,Cookie就不再存在
(2)Cookie也可能保存在客户PC机的硬盘上,设置有效时间,超过有效时间后失效
Cookie的常见应用
简化登录:很多网站在登录时,可以选择多久之内不需要登录,在选择的时间段内,不用登录即可以到欢迎页面。
记录浏览记录:购物网站,每次登录后,会看到曾经浏览过的商品信息。
Cookie的使用
Cookie能够把小文本保存到客户端,在服务器与客户端进行传输。然而,Cookie容易造成信息泄露,另外,客户端可以通过设嚣阻止Cookie,也可能手工清除Cookie,
因此,使用Cookie的原则:
*不用cookie保存对保密性要求高的信息,例如银行卡密码等
*不用cookie实现必要功能,防止cookie被删除后出现错误可以说:cookie用来实现“锦上添花”的功能,也就是说,一旦cookie被禁止或者被删除,应用依然能正常运行
Cookie对象
Servlet API中,存在类Cookie
Cookie cookie=new Cookie("username","qqq");
创建Cookie
- Cookie类中定义了一系列的方法
类型 | 方法名称 | 说明 |
void | setMaxAge(int expiry) | 设置cookie的有效期,以秒为单位,Cookie保存在硬盘上,否则保存在内存中 |
void | setValue(String value) | 在Cookie创建后,对cookie进行赋值获取 |
String | getName() | 获取Cookie的名称 |
String | getValue() | 获取Cookie的值 |
String | getMaxAge() | 获取Cookie的有效时间,以秒为单位 |
保存及获取Cookie
- Cookie要保存到客户端,凡是写到客户端的方法,基本都在响应中。
HttpServletResponse中提供了方法,把Cookie保存到客户端。
response.addCookie(newCookie)
- 再次访问与保存Cookie相同域名的网站时,HTTP协议将把有效时间内的Cookie都发送到服务器,容器将把Cookie封装到请求中。
HttpServletRequest类提供了获取Cookie对象的方法
Cookie[] cookies = request.getCookies();
服务器获取浏览器端保存的Cookie
Cookie的生命周期
问题1:cookie可以记录数据,但是数据需要一直记录永远不删除吗?
答:数据不删除,数据量越来越大,影响存储空间,数据量越大网络传输cookie慢,服务器解析cookie,也是效率不高。
问题2:那么如何删除cookie数据?
答:我们在服务器创建cookie给浏览器,但是我们无法操作浏览器,因此,在cookie创建的时候设置cookie的生存时间,时间—到自动去死
如果不设置过期时间,默认是多少?
答:浏览会话结束时——浏览器关闭的时候
- 设置Cookie生存时间
30秒后,Cookie username-qhc消失
- 设置Cookie访问路径——setPath(String path)
一般路径不去设置,则表示为:/TestWeb,即当前项目下所有路径均可获取该Cookie。当路径设置为:cookie.setPath("");则表示该cookie可在同一应用服务器内共享
当设置该cookie对象访问路径:/TestWeb/demo,(TestWeb项目下demo目录下可访问)其他Servlet不再能访问到该cookie
- 删除Cookie
即服务器通知浏览器,删除指定Cookie。
步骤:删除cookie其实是发送一个新的cookie,覆盖之前的Cookie。
步骤1:设置Cookie并发送到服务端,cookie的key值为username
步骤2:步骤2:将该cookie杀死
Cookie实例
显示用户上次访问的时间
2、Session
Session概述
客户端向服务器端发送请求,服务器端接受请求并生成响应返回给客户端,客户端对服务器端这样一次连续的调用过程,被称为会话(session)。
例如:访问12306网站后,用户可以查询车次、登录用户、购票、支付、退票、改签、看新闻.…..只要这个过程中没有关闭浏览器,同时12306网站服务器也一直正常,就是一次会话。(注意:不同浏览器,不同版本,对会话的支持也有所差别。)
我们使用Session,实现在无连接(HTTP)协议基础之上实现在用户状态管理。Session是服务器为了保存用户状态而创建的一个特殊的对象。它河以存储用户多次请求过程中的数据。
Session将数据存储在服务器端。
Session的典型应用
登录访问控制
某些资源不能直接访问,只对登录用户开放
实现方法:把登录后的信息保存到会话中,访问资源前,先查看会话中的登录信息,如果存在,则允许访问,否则跳转到登录页面。
问题:登录信息能否保存到请求中?
不可以,因为请求的有效范围很小,除了请求转发外,都生成新的请求。而会话有效范围大,在一次会话中,服务器端与一个客户端只维护一个会话对象。
会话API-HttpSessio接口
Servlet API中,定义了HttpSession接口,用来封装会话对象。
HttpSession是接口,不能直接用new创建对象,会话对象是容器创建的,即服务器自己创建,非开发人员手动创建。
如何获取Session对象?
1.在Servlet中,我们使用HttpServletRequest中的方法获得会话对象。
public HttpSession getSession():获取跟当前请求相关的session,如果不存在session,就创建一个新的session对象返回。
public HittpSession getSession(boolean create):如果参数create值为true,与无参的getSession方法等同。如果参数create的值是false,那么如果不存在与当前请求相关的session对象,则返回null,如果存在则直接返回会话对象。
2.JSP文件中使用会话对象的方法
JSP文件中有内置对象session,可以直接调用HttpSession接口中任意方法
HttpSession接口中定义了一系列的方法
返回值类型 | 方法名称 | 说明 |
---|---|---|
void | setAttribute(String key,Object value) | 以key/value的形式保存对象值 |
Object | getAttribute(String key) | 通过key获取对象值 |
void | removeAttribute(String key) | 通过key删除属性 |
int | getMaxInactivelnterval( | 获取session的有效非活动时间,以秒为单位 |
void | setMaxInactivelnterval (int interval ) | 设置session的最大非活动时间,以秒为单位,超时将被销毁。 |
String | getld() | 获取session对象的编号 |
void | invalidate() | 设置session对象失效 |
boolean | isNew() | 判断一个session是不是一个新创建的会话 |
获取Session对象
说明说明Session是基于用户的请求,而把用户的重要信息在服务器端针对这个用户(浏览器)创建了一个容器。
而这个Session容器是由web服务器(tomcat)帮助我们创建的,在程序中我们只能去获取到这个容器,然后给容器添加数据或者取出数据,或者删除数据,而我们是不能创建这个容器对象。
HttpSession接口中定义了三个与属性有关的方法,包括setAttribute以及getAttribute,removeAttribute,分别用来存属性、取属性、删除属性。
会话属性与请求属性区别
主要区别是有效范围不同。请求中的属性只在当前的请求对象中有效。只有通过请求转发时,才能把当前请求对象转发到下一个资源,其他情况都生成新的请求,所以请求属性也不再可用
会话属性在会话对象中有效。客户端与服务器连接后,只要没有关闭浏览器,服务器也没有出现异常,就是一次会话,会话属性就一直有效。
由于会话对象有效时间长,所以安全性相对低,所占资源相对多,因此:请求属性可以解决的问题就用请求,必须用会话的才用会话。
存储数据
会话实现机制
会话由谁创建的?
会话由容器(服务器)创建的。
会话保存在哪里?
会话保存在容器(服务器)中
有若干客户端与服务器连接,服务器会为每个客户端的一次会话创建一个会话对象,而这些会话对象都在容器中,如何区分会话对象与客户端的联系?
多数容器都采用cookie机制实现会话机制
结论:多数容器都使用cookie机制实现会话,也就是说使用cookie来保存客户端与服务器里会话对象之间的对应关系。
使用Cookie实现会话机制的过程
1、当容器创建一个新的HttpSession对象后,即生成一个随机数,称为会话ID,并将ID值封装成一个名字为JSESSIONID的cookie,返回给客户端。
2、调用request.getSession方法获得会话对象时,容器先从request中获取JSESSIONID值,根据JSESSIONID值查找到对应的会话对象,返回使用。
3、如果没有获取到JSESSIONID值,认为当前的请求没有相关联的会话对象,重复步骤1
Sessiqn与key值为JSESSIONID的cookie息息相关,当我们关闭浏览器,再次打开时,Session对象还是同样吗?
结论:当我们关闭浏览器,再次打开时,Session对象不再是同一个
原因:关闭浏览器之后,重新访问项目,会被分配一个新的session对象,这是由于用来寻找原session对象的cookie已经不存在了,因为cookie默认浏览器关闭生命周期结束。
思考:如何使得Session在浏览器关闭后再次得到,还是原来的Session对象?
思路:JSESSIONID值不变,则Session对象可被找到——需要保证JSESSIONID的持久化cookie.setMaxAge(10000);
思考:如何在Cookie禁用的情况下,使得Session机制正常运行?
解决方法:强制把JSESSIONID传递给相关资源即可。
使用URL重写方法,强制把名字为JSESSIONID的Cookie的值添加到URL。
会话生命周期
Session对象的创建时间:
1.当第一次调用request.getSession0时候创建session容器.
2.当第一次访问jsp页面,创建session容器
Session的销毁时间:
1.(自动去死) Session在服务器的存活时间。Session对象在服务器内部有默认的存活的时间。一般默认是30分钟。如果在30分钟内,用户没有再对当前这个服务器中的资源进行任何的访问操作,这时只要时间到达30分钟,服务器会自动的销毁这个session.
2.在程序执行中,手动销毁session容器,使用session.invalidate0
3.不正常关闭服务器。如:强制关闭tomcat。
Session的销毁时间:
1.(自动去死)Session在服务器的存活时间。
通过web.xml可设置Session的存活时间
2.在程序执行中,手动销毁session容器,使用session.invalidate()
当调用Session的销毁方法,则即使浏览器不关闭,两次访问 http://127.0.0.1:8080/TestWeblSessionServlet,得到的Session对象不相同
3.不正常关闭服务器。如:强制关闭tomcat.
如果是正常关闭服务器,这时服务器内部会使用IO流中的序列化技术把这个Session对象保存在tomcat/work目录下面。
- session是在服务器端保存用户信息,Cookie是在客户端保存用户信息
- session中保存的是任意对象,Cookie保存的是字符串session随会话结束而关闭,Cookie可以长期保存在客户端硬盘上,也可以临时保存在浏览器内存中
- Cookie通常用于保存不重要的用户信息,重要的信息使用session保存
三、上下文ServletContext
MyEclipse的每一个Web Project,运行时都部署在Tomcat下,称为一个应用
部署后,启动Tomcat时,Tomcat将为每一个应用创建一个对象,这个对象称为上下文对象
例如,当前的Tomcat中部署了ch01,ch02..... .ch07共7个应用,在启动Tomcat时,将分别为每一个应用创建一个上下文对象
也就是说,一个应用有且只有一个上下文对象,由容器创建,并保存在容器中
作用
上下文对象类似一个全局变量,在整个应用中有效
利用上下文对象,可以实现多个用户之间的数据共享
API
- Servlet API中定义了ServletContext接口,用来封装上下文对象
- 该接口中定义了一系列的方法:
类型 方法名称 说明 void setAttribute(String key,Object value) 以key/value的形式保存对象值 Object getAttribute(String key) 通过key获取对象值 String getlnitParameter(String path) 返回上下文参数的值 String getRealPath(String path) 根据虚拟路径返回实际路径(参看ch02中的使用)
获取对象
- ServletContext是接口,不能直接创建对象。ServletContext对象是容器创建的,可以使用Servlet API中提供的方法获取该对象。
- Servlet类中常用的获取上下文对象的方法
- ServletConfig接口中定义的getServletContext方法
- 由于自定义的Servlet类间接实现了ServletConfig接口,因此可以直接调用getServletContext方法返回ServletContext等象
- JSP文件中使用上下文对象的方法
- JSP文件的内置对象application即上下文对象,可以调用ServletContext接口中的任意方法
参数配置
- 如果在一个应用中的多个Servlet或JSP中都使用的变量,以后还可能被修改,则可以考虑配置成上下文参数,在web.xml的<web-app>下配置:
-
<context-param> <param-name>level</param-name> <param-value>1</param-value> </context-param>
-
- 在ServletContext中定义了getlnitParameter方法可以获得上下文参数的值
- 在Servlet类中
-
ServletContext ctxt=this.getServletContext(); //仅仅测试上下文参数使用,无实际意义 System.out.println("level:"+ctxt.getInitParameter("level");
-
- 在JSP中
-
<% application.getInitParameter("level"); %>
-
- 在Servlet类中
上下文参数与Servlet参数
上下文参数与Servlet参数都可在web.xml中进行配置的
上下文参数在<web-app>下使用<context-param>配置
Servlet参数在<servlet>下使用<init-param>配置
上下文参数在整个上下文中都可以用,任何一个Servlet或JSP都可以使用Servlet参数只能在当前的Servlet中使用
获取Servlet参数的方法在ServletConfig中定义:getInitParameter;而获取上下文参数的方法在ServletContext中定义:getlnitParameter
请求、会话、上下文属性比较
- 在HttpServletRequest、HttpSession、ServletContext中有三个相同的方法,都与属性有关
- 1) public void setAttribute(String name,Object value):该方法用来将对象作为属性存储到相应范围中。
- 2) public Object getAttribute(String name):该方法用来从某范围中获取属性。
- 3) public void removeAttribute(String name):该方法用来从某范围中删除属性。
请求属性
HttpServletRequest提供了上面提到的三个方法,可以将对象作为属性存储到请求中,可以通过名字获取请求对象中的属性,也可以通过名字删除相应的属性。请求对象的生命周期较短,每个线程访问Web组件,都会创建一个新的请求,只有请求转发时才将请求转发到下一资源。所以请求属性不会长期驻留在容器内存中,也不会带来并发访问的问题,能够使用请求属性完成相关功能时,尽量使用请求属性。
会话属性
HttpSession接口中定义了上面提到的三个方法,可以将对象作为属性存储到会话中,可以通过名字获取会话对象中的属性,也可以通过名字删除相应的属性。会话对象在一次会话过程中是一个唯一的对象,生命周期比请求要长。建议在Web应用中,只有当某些对象必须在会话范围内共享,必须使用会话属性时,才考虑使用会话属性。
上下文属性
ServletContext接口提供了上面提到的三个方法,可以将对象作为属性存储到上下文中,可以通过名字获取上下文对象中的属性,也可以通过名字删除相应的属性。上下文对象随着容器启动而创建,只有容器关闭时方销毁,所以生命周期很长。而且一个应用只有一个唯一的上下文对象,因此,不要轻易使用上下文属性,只有当确定某对象必须在上下文范围内共享时,才考虑使用上下文属性。
四、综合实例
五、监听器
监听器
监听器:监听事件源,根据事件源上发生事件,做出相应的处理。
- 监听器用于在服务器端监听一些特定事件的发生,以便用户对发生的事件做出一些处理
- 可以在不修改已有代码的情况下,增加web应用程序生命周期中的事件的跟踪
- Web应用中的某些状态发生改变时会产生相应的事件
- ServletContext、HttpSession、ServletRequest三个作用域对象引发的事件
- 作用域对象中的属性引发的事件
- 监听器可以接收这些事件,以便在事件发生时做出相关处理
六种事件类型
Servlet API中定义了6种事件类型
- ServletContextEvent:该类表示上下文事件,当应用上下文对象发生改变,如创建或销毁上下文对象时,将触发上下文事件。
- ServletContextAttributeEvent:该类表示上下文属性事件,当应用上下文的属性改变,如增加、删除、覆盖上下文中的属性时,将触发上下文属性事件。
- ServletRequestEvent:该类表示请求事件,当请求对象发生改变,如创建或销毁请求对象时,触发请求事件。
- ServletRequestAttributeEvent:该类表示请求属性事件,当请求中的属性改变,如增加、删除、覆盖请求中的属性时,触发请求属性事件。
- HttpSessionEvent:该类表示会话事件,当会话对象发生改变,如创建或销毁会话对象,活化或钝化会话对象时,将触发会话事件。
- HttpSessionBindingEvent:该类表示会话绑定事件,当会话中的属性发生变化时,如增加、删除、覆盖会话中的属性时,将触发会话绑定事件。
监听器——八种监听器接口
Servlet API中定义了8种监听器接口,用来监听不同的事件类型
- ServletContextListener: 上下文监听器,监听ServletContextEvent事件。
- ServletContextAttributeListener:上下文属性监听器,用来监听ServletContextAttribute事件。
- ServletRequestListener:请求监听器,监听ServletRequestEvent事件。
- ServletRequestAttributeListener:请求嘱性监听器,用来监听ServletRequestAttributeEvent事件。
- HttpSessionListener:会话监听器,监听HttpSessionEvent。
- HttpSessionActivationListener:会话活化监听器,监听HttpSessionEvent事件。
- HttpSessionAttributeListener:会话属性监听器,监听HttpSessionAttributeEvent事件。
- HttpSessionBindingListener:会话绑定监听器,监听HttpSessionAttributeEvent事件。
监听器的创建
- 确定要监听的事件,选择合适的监听器接口
- 定义一个实现该接口的类,并实现与响应事件对应的方法
- 在web.xml文件中进行配置
<listener>
<display-name>Onlines Listener</display-name>
<listener-class>com.qhc.listener.OnlinesListener</listener-class>
</listener>
学监听器的创建及使用,需要将监听器接口分为三类进行。
第一类:针对作用域对象引发的事件的监听器
- ServletContextListener
- —contextDestroyed(ServletContextEvent sce)
- —contextInitialized(ServletContextEvent sce)
- HttpSessionListener
- —sessionCreated(HttpSessionEvent se)
- —sessionDestroyed (HttpSessionEvent se)
- ServletRequestListener
- 一requestInitialized(ServletRequestEvent sre)
- —requestDestroyed(ServletRequestEvent sre)
监听器的创建——针对作用域对象的监听器
ServletRequestListener API
1.当web.xml进行对监听器的配置,监听器才可生效。
2.当服务器加载项目的时候,会读取web.xml文件中listener标签,服务器会自动创建监听器对象,并且自动调用其方法(通过反射)。
3.当请求到达服务器,request对象创建,当页面响应完成,请求失效销毁。
4.测试:仅需任选—servlet进行访问即可。
ServletContextListener API
服务器开启,加载项目,服务器创建上下文对象,服务器关闭,上下文对象销毁
HttpSessionListener API
1.实现HttpSessionListener
2.配置自定义的监听器
3.新建session_invalidate.jsp并编写代码
4.访问上述jsp页面
1.当第一次访问jsp页面时,session对象创建
2.当调用session, invalidate)方法时,该session销毁
实例:通过HttpSessionListener监听器实现在线人数的统计
思路:
1.现在项目启动的时候,初始化在线人数0,保存在ServletContext
2监听到session创建数据加—
3监听到session销数据减—
4在页面显示数据
学习监听器的创建及使用,需要将监听器接口分为三类进行。
第三类:HttpSessionBindingListener
—监听session域对象中的java对象的状态(绑定和解绑)
—绑定:将java对象存储到session域对象
—解绑:将java对象从session域对象移除
—该监听器不需要在web.xml中配置