HTTP的无状态性是其一个重要的特征,指的是HTTP协议本身并不保留客户端与服务器交互的历史信息,换而言之,即每次的HTTP请求都是独立的,服务器在处理每一个请求时都不会记住前一个请求的状态
E.g:假设A用户在一个Web超市添加的一个商品到购物车中,等到再次购买时,服务器已经无法分别判断购买行为是属于用户A还是其他用户
就是由于HTTP请求的无状态性,服务器无法识别其请求的上文状态,因此人们就开发了新的技术来解决HTTP无状态性带来的状态丢失问题,也就是我们接下来要讲解的
Cookie
与Session
也借鉴了创造者@测试开发喵
Cookie原意为”饼干”,是由W3C组织提出的.目前的主流浏览器
IE,Google,Edge,Firefox
等等都支持了Cookie技术
鉴于HTTP请求协议是一个无状态的请求协议,服务器单从网络连接上无法得知客户的身份.于是前辈们就想出了一个方法:给客户端们都颁发一个通行证,这样每次发起请求后都要携带自己的通行证.于是乎服务器就可以从通行证上确认用户的身份了
response
向客户端浏览器发送一个Cookie.客户端的浏览器会把Cookie保存→当此浏览器再次申请服务器时,浏览器会将请求的网站连同Cookie一起提交给服务器→浏览器会检查该Cookie,以此来辨别用户的状态,服务器也可以根据需求修改Cookie中的内容JavaScript
访问,有利于防止跨站脚本攻击Java中将Cookie操作封装到
javax.servlet.http.Cookie
类中,
new Cookie(String name, String value)
:设置Cookie的名称与值
username,language,
等等属 性 名 | 描 述 |
---|---|
String name |
该Cookie的名称。Cookie一旦创建,名称便不可更改 |
String value |
该Cookie的值。如果值为Unicode字符,需要为字符编码。如果值为二进制数据,则需要使用BASE64编码 |
int maxAge |
该Cookie失效的时间,单位秒。如果为正数,则该Cookie在maxAge秒之后失效。如果为负数,该Cookie为临时Cookie,关闭浏览器即失效,浏览器也不会以任何形式保存该Cookie。如果为0,表示删除该Cookie。默认为–1 |
boolean secure |
该Cookie是否仅被使用安全协议传输。安全协议。安全协议有HTTPS,SSL等,在网络上传输数据之前先将数据加密。默认为false |
String path |
该Cookie的使用路径。如果设置为“/sessionWeb/”,则只有contextPath为“/sessionWeb”的程序可以访问该Cookie。如果设置为“/”,则本域名下contextPath都可以访问该Cookie。注意最后一个字符必须为“/” |
String domain |
可以访问该Cookie的域名。如果设置为“.google.com”,则所有以“google.com”结尾的域名都可以访问该Cookie。注意第一个字符必须为“.” |
String comment |
该Cookie的用处说明。浏览器显示Cookie信息的时候显示该说明 |
int version |
该Cookie使用的版本号。0表示遵循Netscape的Cookie规范,1表示遵循W3C的RFC 2109规范 |
Cookie的maxAge决定着Cookie的有效期,单位为秒(second),Cookie中的
getMaxAge()
与setMaxAge(int maxAge)
可以用来读写maxAge
属性
maxAge
为正数,则表示该Cookie会在maxAge秒后失效,浏览器会将maxAge为正数的Cookie持久化,即写入到对应的Cookie文件中.无论客户关闭了浏览器还是电脑,只要在maxAge之内,访问相应的网站仍然有效, Cookie cookie = new Cookie("username","张三");//新建cookie
cookie.setMaxAge(Integer.MAX_VALUE);//设置生命时间为无限
resp.addCookie(cookie);//响应到客户端
//此方法添加的cookie信息永远生效
maxAge
为负数时则表示此cookie只在该浏览器窗口以及期子窗口生效,关闭浏览器即失效,maxAge
为负数的Cookie为临时Cookie,不会被持久化,即不会被写入到文件中,Cookie信息只保留在浏览器的内存中,Cookie的默认值为-1,即默认为会话CookiemaxAge
为0时则表示,删除该Cookie.Cookie的机制没有提供删除Cookie的方法,因此可以提供设置maxAge
为0的方法即时失效,实现删除Cookie的效果,失效的Cookie会被浏览器从文件或内存中清除 Cookie cookie = new Cookie("username","李四");//创建cookie
cookie.setMaxAge(0);//设置为0,即时失效
resp.addCookie(cookie);//相应到客户端
value,maxAge
之外的属性,例如name,path,domian
等等都要和原先的Cookie一致才能完成修改Cookie的不可跨域名性表示的是:Cookie通常只能由创建它的域名所访问,这意味着一个域名下的Cookie不能被另一个域名下的Cookie访问
提供设置Domain
属性是实现不可跨域名性:
Domian
设置为:.example.com
时,则该Cookie不仅可以在example.com域名上被访问,也可以在sub.example
上被访问 @Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
Cookie cookie = new Cookie("username","李四");//创建cookie
cookie.setMaxAge(Integer.MAX_VALUE);
cookie.setHttpOnly(true);//不可被JavaScript访问
cookie.setSecure(true);//设置只能提供Http发送
cookie.setDomain(".example.com");//cookie可以被example.com及其子域名访问
resp.addCookie(cookie);//相应到客户端
}
Session
也是一种解决HTTP请求无状态性的技术,Session是服务器使用的一种记录客户端状态的机制,相比Cookie来说,Session更加简单,但增加了服务器的存储压力
Session是一种服务器端的机制,服务器使用一种哈希表的结构存储Session信息
session id
若包含一个session id
则说明已经为该客户端创建过session,服务器会按照session id
检索出来直接使用,若检索不到则新建一个;若不包含 session id
,则为此客户端新建一个session id
并生成相应的session id
→新建的session id会包含在cookie中随响应一起返回到客户端中保存与Cookie一致的是 Session的值也是以
key-value
的形式存在的,Java中把将Session的操作封装到javax.servlet.http.Session
类中
HttpSession getSession()
方法可以获取当前用户的Session,若该用户的Session不存在则返回null
getSession()
方法 HttpSession getSession(boolean create);
当create为true时,该方法会新建一个Session,再讲Session返回public class myServletTest extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
HttpSession session = req.getSession();
HttpSession session1 = req.getSession(true);
}
}
方 法 名 | 描 述 |
---|---|
void setAttribute(String attribute, Object value) |
设置Session属性。value参数可以为任何Java Object。通常为Java Bean。value信息不宜过大 |
String getAttribute(String attribute) |
返回Session属性 |
Enumeration getAttributeNames() |
返回Session中存在的属性名 |
void removeAttribute(String attribute) |
移除Session属性 |
String getId() |
返回Session的ID。该ID由服务器自动创建,不会重复 |
long getCreationTime() |
返回Session的创建日期。返回类型为long,常被转化为Date类型,例如:Date createTime = new Date(session.get CreationTime()) |
long getLastAccessedTime() |
返回Session的最后活跃时间。返回类型为long |
int getMaxInactiveInterval() |
返回Session的超时时间。单位为秒。超过该时间没有访问,服务器认为该Session失效 |
void setMaxInactiveInterval(int second) |
设置Session的超时时间。单位为秒 |
void putValue(String attribute, Object value) |
不推荐的方法。已经被setAttribute(String attribute, Object Value)替代 |
Object getValue(String attribute) |
不被推荐的方法。已经被getAttribute(String attr)替代 |
boolean isNew() |
返回该Session是否是新创建的 |
void invalidate() |
使该Session失效 |
Session实现的原理与Cookie有关
当服务器创建了Session对象后,首先将其存入服务器内存,并把Session的唯一标识session id以Cookie的形式写回客户端本地文件中(键名为JSESSIONID,值为该session的id)
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
HttpSession session = req.getSession();
Cookie cookie = new Cookie("JSESSIONID",session.getId());
cookie.setMaxAge(60*60);
resp.addCookie(cookie);
}
Session的存储结构
Session是以Map数据结构存储的key值为session id;value值为Session对象
protected Map<String, Session> sessions = new ConcurrentHashMap<>();
Session与Cookie的区别
HttpOnly
,和Secure
属性来提高安全性Filter过滤器是
Servlet
技术中最实用的部分,Web开发人员通过Filter技术管理Web服务器的所有资源,如JSP,Servlet,HTML
等等,主要用于对客户请求进行预处理
Filter
有两种配置方法,一种是在web.xml
文件中配置,第二种是使用注释的方法配置(Java Servlet 3.0 及以上版本)
借鉴作者@coderland
<filter>
<filter-name>myFilter01</filter-name>//设置filter名称
<filter-class>com.mashang.web.myFilter01</filter-class>
//指定用于指定过滤器的完整类路径
</filter>
<filter-mapping>//设置Filter负责拦截的资源
<filter-name>myFilter01</filter-name>//需和filter-name一致
<url-pattern>/ *</url-pattern>//设置filter拦截的路径 URL结构
</filter-mapping>
Filter
实现类,顶部使用@WebFilter()
进行注释String filterName() default "";
:指定Filter名称String[] urlPatterns() default {};
:指定Filter拦截的URL,使用/*
表示所有URL都会经过此Filter
由于urlPatterns
以字符串数组存在,因此可以一次配置多条路径,例如
@WebFilter(filterName = "MyFilter", urlPatterns = {"/secure/*", "/admin/*"})
@WebInitParam注释可用于在@WebFilter中配置参数初始值
WebInitParam[] initParams() default {};
:是@WebFilter中的参数类别,默认为空值,表示没有被初始化
name
:参数名称;value
:参数值@WebFilter(filterName = "myFilter01",urlPatterns = "/*",
initParams ={
@WebInitParam(name = "encoding",value = "UTF-8")
//将其中的encoding 属性配置为UTF-8,来实现编码统一
}
)
public class myFilter01 implements Filter { }
Filter是Java的一个接口,其有一个简单的生命周期,
void init(FilterConfig config)
init()
方法完成初始化工作,读取web.xml
文件,Filter对象只会创建一次,因此init()
方法只会执行一次,FilterConfig
是 Java Servlet API 中的一个接口,它提供了获取 Filter
配置信息的方法,在下文我们会展开讲解void doFilter(ServletRequest serReq, ServletResponse** **serResp, FilterChain filterChain)**
doFilter()
方法FilterChain
:Filter链,在开发中会编写多个Filter,FilterChain
是Filter的集合,如果调用了FilterChain对象的doFilter方法,则web服务器会检查FilterChain对象中是否还有filter,如果有,则调用第2个filter,如果没有,则调用目标资源void destroy()
当Filter被初始化时,FilterConfig对象会被传递给
init()
方法,在init()
中通过FilterConfig,可以回去Filter的名称,初始化参数,及相关的ServletContext
String getFilterName():
返回Filter的名称
String getIntiParameter(String name)
:获取指定名称的初始参数的值,若没找到对应的初始化参数则返回null
Enumeration<String> getInitParameterNames()
:返回所有初始化参数名称,
ServletContext getServletContext()
:返回与Filter关联的ServletContext
对象,ServletContext对象提供了整个Web应用程序的访问
public void init(FilterConfig filterConfig) throws ServletException {
//获取FilterConfig中的所有参数名
Enumeration<String> initParameterNames = filterConfig.getInitParameterNames();
while (initParameterNames.hasMoreElements())
{
String name = initParameterNames.nextElement();
System.out.println("param"+":"+name);
}
ServletContext servletContext = filterConfig.getServletContext();
servletContext.setAttribute("name","value");
}
@WebFilter(urlPatterns = "/*")
public class myFilter01 implements Filter {
private String characterEncoding=null;
@Override
public void init(FilterConfig fC) throws ServletException {
//在初始定义中获取characterEncoding
//若为非空,encoding也是非空 则直接获取 encoding的值
if (fC != null && fC.getInitParameter("encoding") !=null
&& ! fC.getInitParameter("encoding").equals(""))
{
characterEncoding=fC.getInitParameter("encoding");
}
else{
characterEncoding="UTF-8";//否则置为utf8
}
}
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
//将Servlet转换为HttpServlet用于处理HTTP请求响应
HttpServletRequest req = (HttpServletRequest) servletRequest;
HttpServletResponse resp = (HttpServletResponse) servletResponse;
//拦截所有请求进行统一编号
//指定request和response的编号
req.setCharacterEncoding(characterEncoding);
//将response数据响应为utf8
resp.setCharacterEncoding(characterEncoding);
//告诉浏览器输出内容为HTML格式,
resp.setContentType("text/html;charset="+characterEncoding);
filterChain.doFilter(req,resp);//将请求和响应传递给下一个 Filter 或目标资源
}
Listener 监听器与Servlet 程序,Filter 过滤器共称JavaWeb的三大组件,Listener作用
application,session,request
三个对象中,Listener用于监听特点的时事件,然后回调函数,并做出相应的反应,Listner主要分为三个大类:ServletContext 监听,Session监听,Request 监听;Listener本质是个接口
ServletContext监听是由
ServletContextListener
和ServletContextAttributeListener
接口实现的,
对整个Servlet上下文进行监听(创建或销毁)
public void contextInitialized(ServletContextEvent sce);
:执行初始化任务,如加载缓存等等public void contextDestroyed(ServletContextEvent sce);
:停止时执行清除任务,释放资源,关闭连接等等public ServletContext getServletContext();
:取得一个ServletContext(application)对象对Servlet上下文属性的监听(增删改属性)
public void attributeAdded(ServletContextAttributeEvent scab);
:向ServletContext中添加属性public void attributeRemoved(ServletContextAttributeEvent scab);
:删除ServletContext中的属性public void attributeRepalced(ServletContextAttributeEvent scab);
:替换SevletContext中的属性,(重复设置无效果)public String getName();
:获取属性名public Object getValue();
:获取属性的值于
ServletContext
类似,Session也分为两种接口,分别为HttpSessionListener
和HttpSessionAttributeListener
对Session整体状态的监听
public void sessionCreated(HttpSessionEvent se);
:创建Sessionpublic void sessionDestroyed(HttpSessionEvent se);
:销毁Sessionpublic HttpSession getSession();
:取得当前操作的session对Session属性的监听
public void attributeAdded(HttpSessionBindingEvent se);
:添加属性到HttpSession
中public void attributeRemoved(HttpSessionBindingEvent se);
:将一个属性从HttpSession
中删除public void attributeReplaced(HttpSessionBindingEvent se);
:替换HttpSession
中的属性public String getName();
:取得属性的名public Object getValue();
:取得属性的值public HttpSession getSession();:
取得当前的sessionRequest监听分为
ServletRequestListener
和ServletRequestAttributeListener
public void requestInitialized(ServletRequestEvent sre);
:request初始化public void requestDestroyed(ServletRequestEvent sre);
:request销毁public ServletRequest getServletRequest();
:取得一个ServletRequest对象public ServletContext getServletContext();
:取得一个ServletContext(application)对象public void attributeAdded(ServletRequestAttributeEvent srae);
:往当前ServletRequest
对象中增加属性public void attributeRemoved(ServletRequestAttributeEvent srae);
往当前ServletRequest
对象中删除属性public void attributeReplaced(ServletRequestAttributeEvent srae);
属性替换(第二次设置同一属性)public String getName();
:得到属性名称public Object getValue();
:取得属性的值web.xm配置
原理于Servlet,Filter大同小异,不展开讲解
<listener>
<listener-class>com.listener.class</listener-class>
</listener>
注释@WebListener
@WebListener
注释即可@WebListener
public class myListener01 implements HttpSessionAttributeListener {}
@WebListener
public class myListener01 implements HttpSessionListener {
@Override
public void sessionCreated(HttpSessionEvent event) {
//使用Session获取ServletContext对象
ServletContext app = event.getSession().getServletContext();
//获取Servlet中的count属性
int count = (int) app.getAttribute("onLineCount");
count++;//每次创建一个Session Count就会+1 用来计数
app.setAttribute("onLineCount",count);
int maxOnLineCount= (int) app.getAttribute("maxOnLineCount");
//若count>maxOnLineCount 则将maxOnLineCount更新为count的值
if (count>maxOnLineCount)
{
app.setAttribute("maxOnLineCount",count);
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
app.setAttribute("date",sdf.format(new Date()));
}
}
@Override
public void sessionDestroyed(HttpSessionEvent event) {
//结束会话后会删除Session 即减少一位客户 count--
ServletContext app = event.getSession().getServletContext();
int count = (int)app.getAttribute("count");
count--;
app.setAttribute("count", count);
}
}