javaweb教程 servlet第二部分

Cookie

cookie基本概念

概念
cookie是保存在浏览器客户端的简单的文本文件,用于存储web服务器下发的简单数据。不超过4K大小,每个应用不超过200条cookie键值对。浏览器每次访问web应用,都会把该应用对应的cookie记录全部带上。如果是自己实现的http客户端,需要自己去实现。

场景
cookie相当于理发店的会员卡ID,客户每次去理发店,给前台人员报出会员卡ID,后台人员根据这个会员卡ID,去柜子里面查找对应的会员卡信息,比如柜子某一页记录页对应这个会员卡ID,记录页面上记录了办卡人姓名,年龄,充值了多少钱等。

组成

  • key-value :
    设置Cookie的名称和值,用于http请求时,提交给服务器调端该用户的信息。
  • Expires :
    设置Cookie的生存事件。Cookie分为持久型和会话型,如果不设置expires,则cookie为会话型,存储于内存之中,浏览器关闭则消失;如果将expires设置为负数,则表示浏览器端收到cookie之后,直接丢弃;如果将expires设置为0,则表示浏览器端如果存储有该cookie,删除原有cookie,当然新的也不会进行存储;如果expires设置为正数,则cookie会持久性,浏览器关闭的时候,不会消失,时间到了就自动删除。
  • Path :
    定义web站点上可以访问该cookie的目录,用于不同的访问path,传递不同的cookie,减少cookie的携带量。
  • Domian :
    指定可以访问该cookie的web站点或者域。允许一个子域设置或者访问父域的cookie。(比如单点登录的cookie共享)
  • Secure :
    指定是否使用https协议发送cookie。
  • HttpOnly :
    用于防止客户端js通过Document.cookie属性访问cookie,但是部分浏览器未遵守此规定。且大多数浏览器允许通过XMLHTTP对象读取HTTP响应头中的Set-Cookie头。



HTTP请求与响应中cookie存在的形式

  • HTTP请求的cookie的形式。一个’cookie’字段。
    在这里插入图片描述

  • HTTP响应中的cookie的形式。多个’Set-Cookie’字段。
    在这里插入图片描述



cookie的前后端使用

cookie的后端使用

  • 创建cookie,并且设置到响应头传给浏览器
#每一个key-value,都对应一个Cookie实例。
#创建cookie,并设置key-value
Cookie cookie = new Cookie("username", "meng"); 
//设置过期时间Expires
response.setMaxAge(10000);
//设置path
response.setPath("/test");
//添加到响应头,http发送响应请求的时候会返回给浏览器
response.addCookie(cookie);

Cookie cookie2 = new Cookie("password", "123456");
response.addCookie(cookie2);
  • 获取cookie(浏览器每次http请求默认携带该web所有的cookie)
    请求体HttpServletRequest只有cookie的key-value,没有其他属性,如path,expires等
Cookie[] cookieList = request.getCookies();
for( Cookie cookie : cookieList ){
	System.out.println(  key + " : "+ value);
}
  • 修改cookie
    如果要修改浏览器中存储的cookie,只需要发送同名key就行,浏览器会保证key的唯一,用新value覆盖就value。
#浏览器接收到已经存储的key-value, 则直接覆盖。
#对于服务器而言,修改浏览器的cookie操作与新增一样。
Cookie cookie2 = new Cookie("password", "1234567890");
response.addCookie(cookie2);
  • 删除cookie
    当浏览器接收到expires为0的cookie时,会根据key去查找已存储的cookie,如果存在,则删除。当然expires为0的cookie也不会被保存。
Cookie cookie2 = new Cookie("password", "1234567890");
cookie2.setMaxAge(0);
response.addCookie(cookie2);

cookie不能使用中文以及加密处理

cookie不能存储中文问题处理

  • 编码存储cookie中的中文
Cookie cookie = new Cookie("password3", URLEncoder.encode("这就是中文", "UTF-8"));
cookie.setPath("/test");
cookie.setMaxAge(10000);
cookie.setHttpOnly(true);
resp.addCookie(cookie);
  • 编码获取cookie中的中文
Cookie[] cookies =  req.getCookies();
if ( cookies != null ){
for ( Cookie cookie : cookies ){
      System.out.println(cookie.getName() +" : "+ cookie.getPath() + " : "+ URLDecoder.decode(cookie.getValue(),"utf-8"));
   }
}

cookie对于重要内容的加密处理

以后实际项目中有使用再添加。。。


cookie的前端使用

判断cookie是否开启

#BOM navigator对象提供的属性
if ( !navigator.cookieEnabled ){
     console.log("cookie被禁止");
}

关于使用cookie进行存取来判断cookie是否开启,容易误判

  • cookie的httpOnly属性,用于告诉浏览器cookie不允许被js代码存取,但是有部分浏览器不允许读,但是允许写。所以导致cookie虽然开启可用,但是通过cookie进行存取判断cookie是没有开启的。

获取cookie

  • document.cookie是获取所有cookie键值对。
  • #document.cookie只能获取到path为"/“下的cookie,其他的获取不到。测试过程中,有两条cookie,一条没设置path(“username”:“meng”),一条设置path为”/test" (”password“,:“123456”), 虽然我访问的网页为 http://localhost:8080/test/index.html,但是js获取的cookie只显示(“username”:“mengze”),没有(“password”:“123456”)。但是在请求该网页的请求头中看到了这两条cookie。
var cookie = document.cookie;
console.log(cookie)

修改cookie

  • document.cookie=xxx 是以追加的形式添加cookie,如果不是同名key,那么不会覆盖之前的cookie内容,而是追加。当然,如果是同名key,那么就是覆盖了。
console.log(document.cookie);
document.cookie = "username1=meng123;expires=30000;path=/";
console.log(document.cookie);

增加cookie

  • 增加与修改类似,同名key就直接覆盖,不同名的key就追加。
document.cookie = "username1=meng123;expires=30000;path=/";

删除cookie

  • 使用chrome测试cookie删除,无效。

XMLHttpRequest在setRequestHeader设置cookie无效

request.setRequestHeader("cookie", "name: 111");


关于cookie相关的安全问题与防御





HttpSession

什么是session?

如果只是用cookie来证明用户身份,那么cookie需要存储大量的信息,且这些信息还不一定安全可靠。Session是另一种记录用户状态的机制。不同于cookie保存在客户端浏览器中,而是保存在服务器中。通过在浏览器中保存一个cookie(“JSESSIONID”,“xxxxxx”)来作为一个用户标识,然后在服务器中获取SESSIONID对应的Session,然后从session拿去之前存储的用户信息。




创建session

servlet中创建session

#调用无参的或者参数为truegetSession(),如果当前用户对应的session不存在,那么就创建一个新session。如果存在session,就返回原有的session。可以通过session.isNew()判断session是新建的,还是旧的。

#调用参数为falsegetSession(),如果当前用户对应的session不存在,那么就返回false。如果存在session,就返回原有的session。

httpServletRequest.getSession(); //相当于参数为true。
httpservletRequest.getSession(Boolean);

jsp中创建session

  • jsp页面默认开启session,也就是说只要访问了该页面,就会创建session。




会话控制流程

  • 用户访问服务器时 未携带JSESSIONID="xxxxx"的cookie , 此时如果存在getSession(),或者getSession(true), 或者访问的jsp页面开启了session。那么就会创建对应该用户的httpSession,并且将sessionID通过cookie形式发送给浏览器,并且以 JSESSIONID="xxxx"形式存在。
  • 用户访问服务器时 携带JSESSIONID="xxxxx"的cookie, 那么服务器如果能找到session(当然如果session有效期过了,那么也需要重新创建session),则直接返回存在的session。在JESSIONID-Session能对应的情形下,永远是同一个session对象。
#
HttpSession session = req.getSession(false);
if ( session == null ){
     //session没有创建,创建session
}else {
     //session存在,可以直接使用
}
//一般是在登录的时候创建httpSession
HttpSession session =  req.getSession();
if ( session.isNew() ){
    //表明session是新建的,并没有存储任何数据。
}else {
    //表明session是旧的。
}




管理session有效时间

获取session的有效时间

//查看session的有效时间, 以秒钟为单位
long  timeout =  session.getMaxInactiveInterval();
System.out.println(timeout);

tomcat中session默认的有效时间与修改

#tomcat默认时间为1800秒,可以去tomcat中的conf目录的we'b.xml中看到。
#也可以在自己项目中的we'b.xml中配置
<session-config>
    <session-timeout>30</session-timeout>  #这个时间单位是分钟。
</session-config>

代码形式修改session的有效时间

//设置session的有效时间
session.setMaxInactiveInterval(10);

强制session失效(一般用于登出)

  • session.invalidate()函数,会清空当前session中所有存储的对象,并且会将该session设置为无效。下次有该session对应的JESSIONID传过来时,不会再获取到该session。
session.invalidate();




关于浏览器禁用cookie之后的处理 --> url重写

如果cookie不可存取,那么浏览器就不会在http请求时自动携带jsessionid。这个时候,可以在URL上携带jsessionid。一样能被tomcat解析到。

原理:

  • 针对前后端分离的网站或者APP,只要将sessionID存储在本地,然后手动设置请求头的cookie就行。对于网页的ajax设置cookie失效的情形,采用在URL上携带( ;jsessionid=xxxxxxx )就行。
#在URL上携带( ;jsessionid=xxxxxxx ), 也能让tomcat获取到jessionid,并且获取到对应的session。

http://localhost:8081/test/hello;jsessionid=DEF0234640EA834D79038F6FE66E8A0C

URL重定向处理

#非重定向的url处理(一般是动态网页处理<a>, <form>等上面的请求URL)
String uri = "otherServlet";
uri = response.encodeURL(uri);
out.println("<a href='" + uri + "'>跳转</a>到otherServlet");
#重定向的URL处理
String url = request.getCotnextPaht() + "/otherServlet";
uri = response.encodeRedirectURL(uri);
response.sendfRedirect(uri);



关于JSESSIONID,HttpSession的创建时机

JSESSIONID就是tomcat获取用户对应HttpSession的cookie。

HttpSession创建时间

  • tomcat中HttpSession是在 servlet中调用 httpServletRequest.getSession() 或者 httpServletRequest.getSession(true), 或者JSP中配置了开启session时创建。
  • 有些网站在用户还没登录就创建很多HttpSession的原因,一般就是JSP页面默认开启的session,导致用户还未登录就创建了session。
  • 当然,这里要说的就是,服务器不是在启动时就创建HttpSession的,而是在需要的时候(比如调用getSession方法)。
  • 另外,session对应的JSESSIONID也不是第一次访问web站点就会返回给浏览器的。是在httpSession创建之后的那次服务器响应返回后,带给浏览器的。

JSESSIONID创建时间

  • 浏览器cookie中存的JSESSIONID,并不是第一次访问网页的时候就返回并存储的。而是当服务器当为该用户创建了对应的httpSession实例的时候,响应头中’Set-Cookie’中携带的。(也就是说会员卡并不是你第一次去店里就创建的,而是当你愿意办理的时候才办理的,然后在办理了会员卡之后,下次再来的时候,你才有卡号可以出示,以及能查到你对应的会员卡以及详细信息。)




关闭服务器保持session

钝化与活化

  • 现象
    服务器关闭后重新启动,只要浏览器没关,还是能获取session里面的内容。

  • 钝化
    服务器关闭以后,会将session对象序列化保存在磁盘中。可以在tomcat的work/当前项目下观察到SESSION.SER文件。

  • 活化
    服务器再次启动时,把之前的序列化号的文件加载进来,就会再次加载之前保存的session。(SESSION.SER包含了session域中所有内容)。当然, 如果session存储的对象没有实现序列化接口,将不会被序列化保存。




关闭浏览器保持session

  • session创建时,默认30分钟有效时间。同时,返回的sessionid没有设置expires,也就说,是会话型cookie,浏览器关闭该jsessionid就会消失。
  • 可以采用以下方式来创建持久性的关于JSESSIONID的cookie。
#手动获取sessionid,然后创建cookie('jsessionid', sessionid),然后设置expires,这样浏览器中的JESSIONID内容的cookie就是持久性的了。

HttpSession session = request.getSession();
String id = session.getId();
Cookie cookie = new Cookie('jsessionid', id);
cookie.setMaxAge(60*60*24);
response.addCookie(cookie);




session实例–用户的登入登出

#登录 -- 将用户信息存放到session中
resp.setContentType("text/json;charset=utf-8");
//登录处理
String username = req.getParameter("username");
String password = req.getParameter("password");
if( "meng".equals(username) && password.equals("123456")){
    //账号密码正确,则登录成功
     HttpSession session = req.getSession();
     session.setAttribute("username", username);
     resp.getWriter().write("登录成功");

}else {
    resp.getWriter().write("登录失败");
}


#登出 -- 将用户信息移除session,且作废该session。
resp.setContentType("text/json;charset=utf-8");
HttpSession session =  req.getSession(false);
if ( session != null ){
    session.invalidate();
}
resp.getWriter().write("退出成功");

Filter

Filter的基本概念

Filter是web服务器的三大组件(Servlet, Filter, Listener)之一.用于用户请求在到达servlet之前, 以及服务器响应到达浏览器之前。进行请求拦截或者功能增强,或者响应增强。

Filter的使用

web.xml中配置Filter

<filter>
    <filter-name>filterB</filter-name>
    <filter-class>com.mz.BFilter</filter-class>
</filter>
<filter-mapping>
    <filter-name>filterB</filter-name>
    <url-pattern>/hello</url-pattern>
    <dispatcher>REQUEST</dispatcher>
    <dispatcher>FORWARD</dispatcher>
</filter-mapping>

实现Filter接口

public class HelloFilter  implements Filter {

    private FilterConfig filterConfig;

    public void init(FilterConfig filterConfig) throws ServletException {
        this.filterConfig = filterConfig;
    }

    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {

       String uri =  ((HttpServletRequest) servletRequest).getRequestURI();
       if ( uri.endsWith(".jsp") ){
           System.out.println("拦截此次请求");
       }else {
           filterChain.doFilter(servletRequest, servletResponse);
       }

    }

    public void destroy() {

    }
}

Filter的执行流程/原理

在执行Servlet的前后,进行了请求拦截,就响应拦截处理。
在这里插入图片描述
作用:

  • Filter可以在请求到达目标资源(JSP、Servlet、Html、CSS)之前拦截请求,并作相应处理。
  • Filter可以放行请求,使请求到达目标资源。
  • Filter可以在响应到达浏览器之前做一些处理。

Filter的生命周期

单例多线程形式存在。

  • Servlet容器启动,Filter就创建并且初始化。在容器中以单例多线程形式存在。
  • 每次用户请求都执行doFilter方法。
  • Servlet容器停止后,Filter销毁。

urlpattern的配置

1、精确匹配

  • 要拦截的资源的详细路径。需要请求路径的字符串完全相等。比如/a.jsp; /b/c.jsp;

2、路径匹配

  • 拦截指定路径下的所有请求。 比如 /a/*
    /* 表示拦截所有请求。
    /path/* 表示拦截/path路径下的所有请求。
    

3、后缀匹配

  • 拦截所有以xxx后缀结尾的所有请求。
     *.jsp
    

4、错误举例 /page/*.jsp

FilterConfig对象

Filter对象在创建并且初始化时,会调用init(FilterConfig):void方法,并且将该对象传递给Filter对象。 FilterConfig含有web.xml中中配置的初始化参数。以及ServletContext对象。

#web.xml中配置初始化参数
<filter>
    <filter-name>filterB</filter-name>
    <filter-class>com.mz.BFilter</filter-class>
    <init-param>
        <param-name>name</param-name>
        <param-value>meng</param-value>
    </init-param>
    <init-param>
        <param-name>age</param-name>
        <param-value>18</param-value>
    </init-param>
</filter>
<filter-mapping>
    <filter-name>filterB</filter-name>
    <url-pattern>/hello</url-pattern>
    <dispatcher>REQUEST</dispatcher>
    <dispatcher>FORWARD</dispatcher>
</filter-mapping>
#在FilterB中获取配置的初始化参数,以及ServletContext
public class BFilter implements Filter {

    private FilterConfig filterConfig;

    public void init(FilterConfig filterConfig) throws ServletException {
        this.filterConfig = filterConfig;
        ServletContext servletContext = filterConfig.getServletContext();
    }

    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {

        String name = this.filterConfig.getInitParameter("name");
        String age  = this.filterConfig.getInitParameter("age");

        filterChain.doFilter(servletRequest, servletResponse);
    }

    public void destroy() {

    }
}

Filter 根据request参数拦截部分请求

public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {

   String uri =  ((HttpServletRequest) servletRequest).getRequestURI();
   if ( uri.endsWith(".jsp") ){
       System.out.println("拦截此次请求");
       return;
   }
   filterChain.doFilter(servletRequest, servletResponse);
}

Filter中的<dispatcher>

Filter中<dispatcher>有四个取值. 一个Filter可以配置多个<dispatcher>.

  • REQUEST :默认值,表示拦截用户的直接请求。
  • FORWARD :表示请求转发。
  • INCLUDE : 表示拦截包含页面。
  • ERROR :表示拦截web.xml中配置的错误页面。
<filter-mapping>
    <filter-name>filterB</filter-name>
    <url-pattern>/hello</url-pattern>
    <dispatcher>REQUEST</dispatcher>
    <dispatcher>FORWARD</dispatcher>
</filter-mapping>

Filter拦截器链

对于同一个用户请求,可以配置多个Filter拦截器,从而形成拦截器链。用户请求在拦截器链串行执行,处理的顺序是web.xml中对应的Filter的配置顺序;服务器响应在拦截器链中处理的顺序则相反。比如配置了Filter A、B、C,那么用户请求来时,A->B->C, 服务器响应时,C->B->A。
在这里插入图片描述


Filter实例 --> 权限验证

public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {

    HttpServletRequest req = (HttpServletRequest) servletRequest;
    HttpServletResponse resp = (HttpServletResponse) servletResponse;

    servletResponse.setContentType("text/json;charset=utf-8");
    //获取session,如果是存在该用户,就表示已经登录
    //如果不存在session,那么就没有登录
    HttpSession httpSession = req.getSession(false);
    if (httpSession == null){
        resp.getWriter().write("用户没有登录");
        return;
    }else {

         filterChain.doFilter(servletRequest, servletResponse);
    }
}



Listener

Listener的基本概念

概念

  • listener也就是监听器,用于监听一个特定的对象,当被监听的对象变化时,监听的对象会执行一系列动作。

作用

  • 用于三大域对象的创建销毁监听
ServletContextListener  #监听ServletContext的创建与销毁  
HttpSessionListener     #监听Session的创建与失效
ServletRequestListener  #监听ServletRequest的创建于销毁
  • 三大域对象对属性增加、修改、删除监听;
ServletContextAttributeListener #监听ServletContext增加,删除,修改属性
HttpSessionAttributeListener  #监听HttpSession增加,删除,修改属性
ServletRequestAttributeListener #监听ServletRequest增加,删除,修改属性
  • 对某个属性在session中的增加,删除监听。
HttpSessionActivationListener   #监听对象在session中的钝化与活化
HttpSessionBindingListener      #监听对象被添加与删除

生命周期监听器

ServletContextListener
用于监听servletContext容器对象的创建与销毁。用于在用户访问之前,创建或者初始化必要的支持对象。比如spring容器对象的创建。

public class MyServletContextListener implements ServletContextListener {

    public void contextInitialized(ServletContextEvent servletContextEvent) {
        System.out.println("web容器创建");
    }

    public void contextDestroyed(ServletContextEvent servletContextEvent) {
        System.out.println("web容器销毁");
    }
}

HttpSessionListener
用于监听HttpSession对象的创建与失效。 一个HttpSession代表一个用户,所以可以监听用户数量,会员数量,访问量,访问时间等。

  • 关于httpSession的生命周期: httpSession是在调用getSession(),且参数不为false的情形下创建的;httpSession是在有效时间过期,或者强制失效的情况下销毁的。与web服务器的开启关闭没关系。(即使关闭,session也会被钝化,而不是被删除)
public class MySessionListener implements HttpSessionListener {
    public void sessionCreated(HttpSessionEvent httpSessionEvent) {
        System.out.println("有新的session创建");
    }

    public void sessionDestroyed(HttpSessionEvent httpSessionEvent) {
        System.out.println("有session销毁");
    }
}

ServletRequestListener
用于监听ServletRequest(HttpServletRequest)的创建与监听。(请求转发过程中,一直是同一个ServletRequest)

public class MyServletRequestListener implements ServletRequestListener {


    public void requestDestroyed(ServletRequestEvent servletRequestEvent) {

    }

    public void requestInitialized(ServletRequestEvent servletRequestEvent) {

    }
}

属性监听器

ServletContextAttributeListener
监听ServletContext的域中属性的添加,删除,修改。

public class MyServletContextAttributeListener implements ServletContextAttributeListener {


   public void attributeAdded(ServletContextAttributeEvent servletContextAttributeEvent) {

   }

   public void attributeRemoved(ServletContextAttributeEvent servletContextAttributeEvent) {

   }

   public void attributeReplaced(ServletContextAttributeEvent servletContextAttributeEvent) {

   }
}

HttpSessionAttributeListener
用于监听HttpSession域对象中属性的添加,删除,修改。

public class MySessionAttributeListener implements HttpSessionAttributeListener {
    public void attributeAdded(HttpSessionBindingEvent httpSessionBindingEvent) {

    }

    public void attributeRemoved(HttpSessionBindingEvent httpSessionBindingEvent) {

    }

    public void attributeReplaced(HttpSessionBindingEvent httpSessionBindingEvent) {

    }
}

ServletRequestAttributeListener
用于监听ServletRequest(HttpServletRequest)域中的属性增加,删除,修改。

public class MyServletRequestAttributeListener implements ServletRequestAttributeListener {
    public void attributeAdded(ServletRequestAttributeEvent servletRequestAttributeEvent) {

    }

    public void attributeRemoved(ServletRequestAttributeEvent servletRequestAttributeEvent) {

    }

    public void attributeReplaced(ServletRequestAttributeEvent servletRequestAttributeEvent) {

    }
}

session固有监听器

HttpSessionActivationListener 用于添加到session中的属性监听,如果钝化,激活事件发生,则会调用该属性实现的ActivationListener接口的方法。

public class UserInfo implements Serializable, HttpSessionActivationListener {

    public void sessionWillPassivate(HttpSessionEvent httpSessionEvent) {
        System.out.println("session中的userinfo即将钝化");
    }

    public void sessionDidActivate(HttpSessionEvent httpSessionEvent) {
        System.out.println("session中的userinfo已经激活");
    }
}


HttpSessionBindingListener 监听session中某个属性的增加,删除。

public class UserInfo implements Serializable, HttpSessionBindingListener {


    public void valueBound(HttpSessionBindingEvent httpSessionBindingEvent) {
        System.out.println("该属性被添加到了session中");
    }

    public void valueUnbound(HttpSessionBindingEvent httpSessionBindingEvent) {
        System.out.println("该属性从session中移除");
    }
}

发布了58 篇原创文章 · 获赞 34 · 访问量 3万+

猜你喜欢

转载自blog.csdn.net/qq_36723759/article/details/104163582
今日推荐