day05

1.Cookie的由来

浏览器端的会话技术——保存数据技术
显示上次登录用户名这个功能,如何实现?
1 上一次登录的时候,肯定将用户名记录下来
2 肯定是在服务器处理登录的时候,将用户名记录下来
3 那么这个数据到底存在哪里了呢?

cookie.png

2.1Cookie快速入门

在哪里创建cookie对象?
创建Servlet。

图片1.png
1 如何创建Cookie对象?查询构造函数
图片2.png
2 在哪里创建Cookie对象?根据之前的分析,记住用户名的动作发生在服务器端,所以在服务器创建Cookie
Cookie cookie =new Cookie("username","xiaowang");
3 如何将cookie发送给浏览器?给浏览器发出响应的是response对象,将cookie交给response发送

Response API:


图片3.png

代码操作:

response.addCookie(cookie);
4 如何在浏览器查看cookie(第二种查看cookie的方式)?

如何打开谷歌浏览器查看cookie?
设置-高级-内容设置-cookie

那么接下来,记录在cookie中的数据,服务器如何使用?
1 浏览器将cookie发送给服务器需要我们有特别的操作吗?不需要,发送http请求,从来都是服务器操作,跟我们没关系
2 浏览器自动发送cookie给服务器,服务器如何获取到这个cookie?通过request对象获取

Request API:


图片4.png
Cookie [] cookies =request.getCookies();
if(cookies!=null){
    for(Cookie ck:cookies){
         if(ck.getName().equals("time")){
              response.getWriter().write(ck.getValue());
        }
    }
}

2.2Cookie的生命周期

问题1: cookie可以记录数据,但是数据需要一直记录永远不删除吗?
答:数据不删除,数据量越来越大,影响存储空间,数据量越大网络传输cookie慢,服务器解析cookie,也是效率不高。

问题2:那么如何删除cookie数据?
答:我们在服务器创建cookie给浏览器,但是我们无法操作浏览器,因此,在cookie创建的时候设置cookie的生存时间,时间一到自动去死

如果不设置过期时间,默认是多少?
答:浏览会话结束时——浏览器关闭的时候
Cookie API:

图片5.png
//设置生存时间,单位秒
cookie.setMaxAge(30);

2.3Cookie的路径设置

cookie认路
有配置默认的路径


图片6.png

结论:setPath方法可以设置当前目录和旗下子目录servlet都获取cookie,一般setPath(“/”),表示当前项目所有目录都可以获取cookie
一般路径不去设置,或者,设置为“/”;

2.3.1删除Cookie

删除cookie其实是发送一个新的cookie,设置生成时间为0,而且设置数据为空字符或则null,通过response对象发送之后,会,覆盖之前的cookie
注意,删除cookie时,path必须一致,否则不会删除
指的是: 服务器通知浏览器 删除自己管理的cookie.

1、将cookie的name(key)保持一致,value 设置为 "";
cookie = new Cookie("username","")
2、设置存活时间为0,
cookie.setMaxAge(0)
3、路径要发送cookie时保持一致,没有路径不需要设置。
cookie.setPath("/");
4、将cookie发送给浏览器。
response.addCookie(cookie)

需求:服务器让浏览器删除缓存中的cookie:

package cn.igeek.web.servlet;
import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
/**
 * Servlet implementation class CookieServlet
 */
@WebServlet("/jsp/CookieServlet")
public class CookieServlet extends HttpServlet {
    private static final long serialVersionUID = 1L;    
    /**
     * @see HttpServlet#HttpServlet()
     */
    public CookieServlet() {
        super();
        // TODO Auto-generated constructor stub
    }
    /**
     * @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse response)
     */
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        //调用构造函数,创建Cookie对象
        //删除cookie,就是用一个空数据cookie,覆盖前一个cookie
        Cookie cookie =new Cookie("username","xiaowang");
        //设置生成时间,单位秒
        //设置为0,表示删除
        cookie.setMaxAge(0);
        //设置cookie的访问路径,项目跟目录
        cookie.setPath("/");
        //通过响应对象将cookie发送给浏览器
        response.addCookie(cookie);
    }
    /**
     * @see HttpServlet#doPost(HttpServletRequest request, HttpServletResponse response)
     */
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        // TODO Auto-generated method stub
        doGet(request, response);
    }
}

2.4cookie案例一:显示用户上次访问的时间

当用户访问某些web应用的时候,经常会显示出上次的访问时间。
例如:QQ登录成功后,会显示用户上次的登录时间。
画图分析:

图.png
package cn.igeek.web.servlet;
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.Date;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
/**
 * Servlet implementation class CServlet
 */
@WebServlet("/jsp/CServlet")
public class CServlet extends HttpServlet {
    private static final long serialVersionUID = 1L;      
    /**
     * @see HttpServlet#HttpServlet()
     */
    public CServlet() {
        super();
        // TODO Auto-generated constructor stub
    }
    /**
     * @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse response)
     */
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        //显示用户上次访问的时间
        //分两次请求
        //第一次将访问时间,保持到cookie
        request.setCharacterEncoding("utf-8");
        SimpleDateFormat sdf =new SimpleDateFormat("yyyy-MM-dd--HH:mm:ss");
        //定义一个Cookie,保存用户名
        Cookie cookie =new Cookie ("time",sdf.format(new Date()));
        cookie.setMaxAge(60*60);
        cookie.setPath("/");
        System.out.println(cookie);
        //通过response进行响应,将cookie回送给浏览器
        response.addCookie(cookie);     
        //获取cookie
        Cookie [] cookies =request.getCookies();
        if(cookies!=null){
            for(Cookie ck:cookies){
                if(ck.getName().equals("time")){
                    response.getWriter().write(ck.getValue());
                }
            }
        }
    }
    /**
     * @see HttpServlet#doPost(HttpServletRequest request, HttpServletResponse response)
     */
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        // TODO Auto-generated method stub
        doGet(request, response);
    }
}
1111.png

第3章Session(服务器端的会话技术)

技术:session,在服务器端保存用户的数据。(注意:session技术,还是依赖cookie技术)
会话:从第一次请求服务器开始,一直到关闭浏览器,这一段操作,称之为:会话。相当于平时打电话。

3.1什么是session?

1 session是服务器开辟的一个用来存储数据的空间
2 服务器为每个浏览器单独开辟一个session
3 服务器根据浏览器发送过来的cookie,来确认当前浏览器使用哪个session

补充说明:
在WEB开发中,服务器可以为每个用户浏览器创建一个会话对象(session对象),注意:一个浏览器独占一个session对象(默认情况下)。因此,在需要保存用户数据时,服务器程序可以把用户数据写到用户浏览器独占的session中,当用户使用浏览器访问其它程序时,其它程序可以从用户的session中取出该用户的数据,为用户服务。

Session和Cookie的主要区别在于:
Cookie是把用户的数据写给用户的浏览器。
Session技术把用户的数据写到用户独占的session中(服务器端)。
Session对象由服务器创建,开发人员可以调用request对象的getSession方法得到session对象。

1.png

3.2Session的快速入门

3.2.1获取Session对象

学习第一步:获取session对象


图片7.png

提供了一个容器,将多次请求中的数据,可以都存储在这个容器中
没有构造方法,只能通过get方法获得

图片8.png

如果这个函数参数为true和前面的getSession(),效果一致,如果参数为false,并且,以前没有Session对象,那么返回null。

图片9.png
HttpSession session =request.getSession();
System.out.println(session);

补充说明:
Session是基于用户的请求,而把用户的重要信息在服务器端针对这个用户(浏览器)创建了一个容器。

而这个Session容器是由web服务器(tomcat)帮助我们创建的,在程序中我们只能去获取到这个容器,然后给容器添加数据或者取出数据,或者删除数据,而我们是不能创建这个容器对象。

3.2.2在Session中存取删数据(重点)

存数据

//setAttribute(String name,Object value)
session.setAttribute("username", "wang");

取数据

session.getAttribute("username");

删数据

session.getAttribute("username");

eg:

public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        //演示获取session对象(容器,用来保存数据)
        HttpSession session = request.getSession();
        //org.apache.catalina.session.StandardSessionFacade@4838bd9d : 这个是httpsession接口的实现类,这个类由tomcat实现
        System.out.println(session);
        //设置数据的方法
        session.setAttribute("addr", "法国");
        //获取数据的方法
        String addr = (String)session.getAttribute("addr");
        System.out.println(addr);
        //删除数据的方法
        session.removeAttribute("addr");
        String addr1 = (String)session.getAttribute("addr");
        System.out.println(addr1);
    }

3.2.3记录sessionid的cookie

通过谷歌浏览器的工具查看,SessionId的cookie:
这个cookie明显是服务器创建的,那么是在哪里创建的呢?
测试前先清空cookie数据!
创建记录sessionid的cookie由tomcat中:ApplicationSessionCookieConfig


图片29.png

3.3测试:关闭浏览器之后,session对象,还是同一个吗?

第一次访问:
org.apache.catalina.session.StandardSessionFacade@5e7eb260
关闭浏览器,再次访问:
org.apache.catalina.session.StandardSessionFacade@4107e577
问题:为什么,关闭浏览器之后,session对象就换了一个?

结论:关闭浏览器之后,重新访问项目,被分配一个新的session对象,原因——用来寻找session对象的cookie已经不存在了,随着浏览器关闭消失了。

需求:关闭浏览器之后,还要之前的session,如何实现呢?

解决方案:自己创建一个cookie,要求被浏览器持久化保存起来(setMaxAge(10000))放便后期使用
代码演示自己手动持久化cookie:
要使用的API:


图片30.png

获取session的id

public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        HttpSession session = request.getSession();
        System.out.println(session);
        //自己创建一个cookie,要求被浏览器持久化保存起来(setMaxAge(10000))放便后期使用
        Cookie cookie = new Cookie("JSESSIONID", session.getId());
        //活的久一点
        //cookie.setMaxAge(10000);
        cookie.setPath("/");
        response.addCookie(cookie);
    }

效果:
org.apache.catalina.session.StandardSessionFacade@9fd589a
org.apache.catalina.session.StandardSessionFacade@9fd589a
两次结果一致,cookie持久化,方便获取上一次session对象

总结:session容器的获取全部依赖于cookie,服务器自动解析cookie,根据cookie中jsessionid,获取指定的容器对象。

一般情况下,关闭浏览器之后,再次访问,是无法获取到Session中的数据的。
因此在服务器针对当前用户的第一次请求创建的唯一的Session容器对象,而在给这次请求的之后,服务器需要给用户响应数据,在响应的时候,服务器把当前Session容器对象的JSESSIONID以Cookie的形式发送给了浏览器。而这个Cookie并没有设置有效时间,那么这个Cookie就属于临时Cookie,在关闭浏览器之后,再次打开浏览器的时候,上次的Cookie已经消失了,用户虽然拿同一个浏览器访问服务器,可是这时没有JSESSIONID,服务器端的Session容器依然存在,但是没有JSESSIONID,服务器内部无法获取到这个session对象
把包含了JSESSIONID的Cookie在客户端持久化。

3.4禁用Cookie后Session追踪

如何禁用cookie演示:演示谷歌浏览器禁用cookie
设置-隐私设置和安全性-内容设置-Cookie-off
测试,禁用cookie之后的效果:

刚才操作的都是浏览器,没有操作服务器,所以,

服务器依然会将cookie传递到浏览器:
效果:本地浏览器并不会将cookie保存下来
没cookie了,那么我们的session怎么办?
每次都在重新创建session!!!!!
现状:每次请求都创建新的session对象,不能完成多次请求数据集中到一个session中

解决方案:
一定要让我们每次请求,可以获取到同一个session!!!!!

以前cookie自动帮助我们,发送数据给服务器,现在,自己自力更生,手动在链接地址上拼接请求参数(jsessionid=XXXX)
测试以上方案:

public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {

        //第一次请求的时候,创建session对象
        HttpSession session = request.getSession();
        System.out.println(session);
        
        //为了后期,还能使用同一个session,设置一个链接,在链接中,拼接请求参数(jsessionid=XXXX)
        
        response.setContentType("text/html;charset=utf-8");
        //拼接参数,使用的是分号,不是问号。
        //使用API,简化拼接sessionid的操作
        String encodeURL = response.encodeURL("/SessionServlet3");
        String encodeRedirectURL = response.encodeRedirectURL("/SessionServlet3");
        System.out.println("encodeURL==="+encodeURL);
        System.out.println("encodeRedirectURL==="+encodeRedirectURL);
        //String a = "<a href=\"/day16/SessionServlet3;jsessionid="+session.getId()+"\">点击</a>";
        String a = "<a href='"+encodeURL+"'>点击</a>";
        response.getWriter().write(a);
    }

效果:
org.apache.catalina.session.StandardSessionFacade@2276ef6589a
org.apache.catalina.session.StandardSessionFacade@2276ef6589a

这个操作比较繁琐,有没有简便的方法?

有response对象有更好的方法:


图片31.png

人话:将路径添加jsessionid作为请求参数,如果,cookie数据没有禁用,那么,不做任何操作。

用于对表单action和超链接的url地址进行重写

在response对象中的提供的encodeURL方法它只能对页面上的超链接或者是form表单中的action中的路径进行重写(拼接JSESSIONID)。
如果我们使用的重定向技术,这时必须使用下面方法完成:
用于对sendRedirect方法后的url地址进行重写。


图片32.png

附:这两个方法是效果是一致的,在设置要转换的路径为空字符串的时候,encodeRedirectURL方法没有任何效果,encodeURL会继续拼接参数

总结:其实就是在路径后面拼接了 Session的唯一标识 JSESSIONID。

3.5Session的生命周期(面试)

使用session存取数据,必须在session对象存活的时候,才可以使用,因此,学习session生命周期(什么时候生,什么时候死)

Session对象的创建时间:
当第一次调用request.getSession()的时候创建session容器.
如果第一次访问jsp页面,也会创建session容器

Session的销毁时间:
1、(自动死亡)Session在服务器的存活时间。Session对象在服务器内部有默认的存活的时间。一般默认是30分钟。如果在30分钟内,用户没有再对当前这个服务器中的资源进行任何的访问操作,这时只要时间到达30分钟,服务器会自动的销毁这个session。
Session的存活时间我们可以在当前这个项目的web.xml中配置:

图片33.png

2、 在程序执行中,手动销毁session容器, 使用 session.invalidate()(重点)

图片34.png

人话:销毁session对象,只是让这个对象无效,下次在来访问,给一个新的session对象。

两次调用同一个servlet测试,有销毁方法,获取到不同的session对象


图片35.png

3、不正常关闭服务器。直接点击控制台的红点,强制关闭tomcat
如果是正常关闭服务器,这时服务器内部会使用IO流中的序列化技术把这个Session对象保存在tomcat/work目录下面。
Session文件:


图片36.png

3.5.1Session应用:登陆验证码

什么是登陆验证吗?

防止黑客暴力破解用户的密码的一种技术。

什么是暴力破解用户的密码?


图片37.png

黑客这样的暴力破解,有什么办法解决呢?验证码

图片38.png

需求:在登录的时候,加上验证码校验

<script>
function changeCode(){
        document.getElementById("img").src = "/session/checkcode?r="+new Date().getTime();
}
</script>
<body>
<form action="/session/login" method="post">
<table>
    <tr><td>用户名:</td><td><input type="text" name="username"></td></tr>
    <tr><td>密码:</td><td><input type="password" name="password"></td></tr>
    <tr><td>验证码:</td><td><input type="text" name="code"></td></tr>
    <!-- 通过向服务器发送请求,从服务器获取验证码数据 -->
    <tr><td></td><td><img id="img" src="/session/checkcode" onclick="changeCode();"/><a href="javascript:;" onclick="changeCode();">换一换</a></td></tr>
    <tr><td></td><td><input type="submit" value="登陆"></td></tr>
</table>
</form>
</body>

登陆流程分析:


图片39.png

LoginServlet

public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        //用户请求中的验证码获取
        String yanzhengma = request.getParameter("yanzhengma"); 
        //与session中保存的验证码进行校验
        String code_session = (String)request.getSession().getAttribute("code_session");
        if(!code_session.equalsIgnoreCase(yanzhengma)){
            //验证码错误,告诉用户,页面提示
            request.setAttribute("msg", "验证码错误");
    request.getRequestDispatcher("/login.jsp").forward(request, response);
            return;
        }
        //验证码正确,登录逻辑执行
        //获取用户名和密码
        String username = request.getParameter("username");
        String password = request.getParameter("password");
        //调用Service方法,登录用户
        UserService userService = new UserServiceImpl();
        //ctrl+shift+O自动解决一些常见问题,如果解决不了,留着程序员解决
        User loginUser = userService.login(username,password);
        if(loginUser == null){
            request.setAttribute("msg", "用户名或则密码错误");   request.getRequestDispatcher("/login.jsp").forward(request, response);
            return;
        }else{
            //登陆成功,跳转主页
    response.sendRedirect(request.getContextPath());
            //不写return,而且后面,还要可以执行的代码,有可能发送一个错误:response对象已经提交了,无法再次提交
            return;
        }
    }

3.6JavaWEB中三种数据范围(三种容器)

Request ServletContext Session

三个对象都有:setAttribute getAttribute方法,都可以存取数据

回答面试官问题套路:先回答基本概念,返回,跟上使用案例。
问题:什么时候使用request对象,保存数据?
答:一次请求中需要使用的数据,就保存在request。举例:商品数据,就存入请求中。

问题:什么时候使用ServletContext 对象,保存数据?
答:全局使用的数据,整个项目需要使用的数据,就是,要存入ServletContext 。举例:在线人数,存入ServletContext 。

问题:什么时候使用session对象,保存数据?
答:一次会话(多次请求——都发生在一次开启浏览器和关闭浏览器过程中)中需要使用的数据,都存入session。
举例:点餐商品

推荐阅读更多精彩内容

  • 目录Cookie机制什么是CookieCookie的不可跨域名性Unicode编码:保存中文BASE64编码:保存...
    Tomatoro阅读 15,571评论 7 186
  • 会话(Session)跟踪是Web程序中常用的技术,用来跟踪用户的整个会话。常用的会话跟踪技术是Cookie与Se...
    chinariver阅读 4,995评论 1 49
  • 1.会话技术:从浏览器开始访问服务器,到关闭浏览器,这期间发生了许多次请求和响应,这个过程就叫做一次会话。 2.问...
    devstrongzhao阅读 70评论 0 0
  • 努力让今天的自己开心。
    残破的新阅读 52评论 0 0
  • N3-N5 1.大抵(たいてい)【名词・副词】:大抵,大体上,基本上 2.タイプ①【名词・サ变动词】:类型,打字 ...
    安墨一生Ivy阅读 78评论 0 0
  • 当你什么时候会想到孤独?便是当你直面自己内心的时候。 人类往往是逃避的高手,发明出了五彩斑斓的世界让人深陷其中,以...
    梧桐臆想阅读 446评论 0 1