Cookie&&&Session&&JSP

Cookie

会话介绍

  • 会话:客户端浏览器和服务器之间的多次请求和响应
  • 为了实现一些功能,浏览器和服务器之间可能会产生多次请求和响应,从浏览器访问服务器开始,到访问服务器结束(浏览器关闭,到了过期时间)。这期间产生的多次请求和响应加在一起就称之为浏览器之间的一次会话
  • 在会话过程中产生的一些数据,可以通过会话技术(Cookie和Session)保存

Cookie介绍

  • Cookie:客户端会话管理技术,把要共享的数据保存到客户端。每次请求时,把会话消息带到服务端,从而实现多次请求的数据共享
  • 作用:可以保存客户端访问网站的相关内容,从而保证每次访问时先从本地缓存中获取,以此提高效率

Cookie属性

属性名称 属性作用 是否重要
name cookie的名称 必要属性
value cookie的值(不能是中文) 必要属性
path cookie的路径 重要
domain cookie的域名 重要
maxAge cookie的生存时间。 重要
version cookie的版本号。 不重要
comment cookie的说明。 不重要
private static final long serialVersionUID = -6454587001725327448L;
private static final String TSPECIALS;
private static final String LSTRING_FILE = "javax.servlet.http.LocalStrings";
private static ResourceBundle lStrings = ResourceBundle.getBundle("javax.servlet.http.LocalStrings");
private String name;
private String value;
private String comment;
private String domain;
private int maxAge = -1;
private String path;
private boolean secure;
private int version = 0;
private boolean isHttpOnly = false;

Cookie方法

方法名 作用
Cookie(String name, String value) 构造方法创建对象
属性对相应的set和get方法 赋值和获取值

Cookie添加和获取

  • 添加:HttpServletResponse

    返回值 方法名 说明
    void addCookie(Cookie cookie) 向客户端添加Cookie
  • 获取:HttpServletRequest

    返回值 方法名 说明
    Cookie[] getCookies() 获取所有的Cookie

Cookie的使用

  • 通过Cookie记录最后的访问时间,并在浏览器上显示出来
  • 实现步骤
    1. 通过响应对象写出一个提示信息
    2. 构建Cookie对象,指定name和value
    3. 设置Cookie最大存活时间
    4. 通过响应对象将Cookie对象添加到客户端
    5. 通过请求对象获取Cookie对象
    6. 将Cookie对象中的访问时间写出
//1. 通过响应对象写出一个提示信息
response.setContentType("text/html;charset=UTF-8");
PrintWriter pw = response.getWriter();
pw.write("欢迎访问本网站,最后访问时间为:<br>");
//2. 构建Cookie对象,指定name和value
Cookie cookie = new Cookie("time", System.currentTimeMillis() + "");
//3. 设置Cookie最大存活时间
cookie.setMaxAge(60*60);
//4. 通过响应对象将Cookie对象添加到客户端
response.addCookie(cookie);
//5. 通过请求对象获取Cookie对象
Cookie[] cookies = request.getCookies();
for (Cookie c : cookies) {
    if (c.getName().equals("time")){
        //6. 将Cookie对象中的访问时间写出
        String value = c.getValue();
        SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        String s = dateFormat.format(new Date(Long.parseLong(value)));
        pw.write(s);
    }
}

Cookie的细节

  • Cookie有大小,个数限制。每个网站最多只能存20个cookie,且大小不能超过4kb。同时,所有网站的cookie总数不超过300个。

  • 当删除Cookie时,设置maxAge值为0。当不设置maxAge时,使用的是浏览器的内存,当关闭浏览器之后,cookie将丢失。设置了此值,就会保存成缓存文件(值必须是大于0的,以秒为单位)。

  • 名称限制

Cookie的名称只能包含ASCCI码表中的字母、数字字符。不能包含逗号,分号,空格。不能以$开头。Cookie的值不支持中文

  • 访问路径限制

    取自第一次访问资源路径前缀,只要以这个前缀为开头(包括子路径),则获取的到,反之获取不到。

    默认路径:取自第一次访问的路径前缀。只要以这个路径开头就能访问到

    设置路径:setPath()方法设置指定路径

    1)需求说明

    创建一个Cookie,设置Cookie的path,通过不同的路径访问,从而查看请求携带Cookie的情况。

    2)案例目的

    通过此案例的讲解,同学们可以清晰的描述出,客户浏览器何时带cookie到服务器端,何时不带。

    3)案例步骤

    第一步:创建JavaWeb工程

    沿用第一个案例中的工程即可。

    第二步:编写Servlet

    /**
     * Cookie的路径问题
     * 前期准备:
     * 	1.在demo1中写一个cookie到客户端
     *  2.在demo2和demo3中分别去获取cookie
     *  	demo1的Servlet映射是   /servlet/PathQuestionDemo1
     *  	demo2的Servlet映射是   /servlet/PathQuestionDemo2
     *  	demo3的Servlet映射是   /PathQuestionDemo3
     *
     *
     */
    public class PathQuestionDemo1 extends HttpServlet {
    
    	public void doGet(HttpServletRequest request, HttpServletResponse response)
    			throws ServletException, IOException {
    		//1.创建一个Cookie
    		Cookie cookie = new Cookie("pathquestion","CookiePathQuestion");
    		//2.设置cookie的最大存活时间
    		cookie.setMaxAge(Integer.MAX_VALUE);
    		//3.把cookie发送到客户端
    		response.addCookie(cookie);//setHeader("Set-Cookie","cookie的值")
    	}
    
    	public void doPost(HttpServletRequest request, HttpServletResponse response)
    			throws ServletException, IOException {
    		doGet(request, response);
    	}
    }
    
    
    /**
     * 获取Cookie,名称是pathquestion
     */
    public class PathQuestionDemo2 extends HttpServlet {
    
    	public void doGet(HttpServletRequest request, HttpServletResponse response)
    			throws ServletException, IOException {
    		//1.获取所有的cookie
    		Cookie[] cs = request.getCookies();
    		//2.遍历cookie的数组
    		for(int i=0;cs!=null && i<cs.length;i++){
    			if("pathquestion".equals(cs[i].getName())){
    				//找到了我们想要的cookie,输出cookie的值
    				response.getWriter().write(cs[i].getValue());
    				return;
    			}
    		}
    	}
    
    	public void doPost(HttpServletRequest request, HttpServletResponse response)
    			throws ServletException, IOException {
    		doGet(request, response);
    	}
    }
    
    /**
     * 获取Cookie,名称是pathquestion
     */
    public class PathQuestionDemo3 extends HttpServlet {
    
    	public void doGet(HttpServletRequest request, HttpServletResponse response)
    			throws ServletException, IOException {
    		//1.获取所有的cookie
    		Cookie[] cs = request.getCookies();
    		//2.遍历cookie的数组
    		for(int i=0;cs!=null && i<cs.length;i++){
    			if("pathquestion".equals(cs[i].getName())){
    				//找到了我们想要的cookie,输出cookie的值
    				response.getWriter().write(cs[i].getValue());
    				return;
    			}
    		}
    	}
    
    	public void doPost(HttpServletRequest request, HttpServletResponse response)
    			throws ServletException, IOException {
    		doGet(request, response);
    	}
    }
    

    第三步:配置Servlet

    <!--配置Cookie路径问题案例的Servlet-->
    <servlet>
        <servlet-name>PathQuestionDemo1</servlet-name>
        <servlet-class>com.itheima.web.servlet.pathquestion.PathQuestionDemo1</servlet-class>
    </servlet>
    <servlet-mapping>
        <servlet-name>PathQuestionDemo1</servlet-name>
        <url-pattern>/servlet/PathQuestionDemo1</url-pattern>
    </servlet-mapping>
    
    <servlet>
        <servlet-name>PathQuestionDemo2</servlet-name>
        <servlet-class>com.itheima.web.servlet.pathquestion.PathQuestionDemo2</servlet-class>
    </servlet>
    <servlet-mapping>
        <servlet-name>PathQuestionDemo2</servlet-name>
        <url-pattern>/servlet/PathQuestionDemo2</url-pattern>
    </servlet-mapping>
    
    <servlet>
        <servlet-name>PathQuestionDemo3</servlet-name>
        <servlet-class>com.itheima.web.servlet.pathquestion.PathQuestionDemo3</servlet-class>
    </servlet>
    <servlet-mapping>
        <servlet-name>PathQuestionDemo3</servlet-name>
        <url-pattern>/PathQuestionDemo3</url-pattern>
    </servlet-mapping>
    

    第四步:部署工程

    4)测试结果

    通过分别运行PathQuestionDemo1,2和3这3个Servlet,我们发现由demo1写Cookie,在demo2中可以取到,但是到了demo3中就无法获取了,如下图所示:

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

5)路径问题的分析及总结

问题:
demo2和demo3谁能取到cookie?
答案:
demo2能取到,demo3取不到
分析:
首先,我们要知道如何确定一个cookie?
那就是使用cookie的三个属性组合:domain+path+name
这里面,同一个应用的domain是一样的,在我们的案例中都是localhost。
​ 并且,我们取的都是同一个cookie,所以name也是一样的,都是pathquestion。
​ 那么,不一样的只能是path了。但是我们没有设置过cookie的path属性,这就表明path是有默认值的。
接下来,我们打开这个cookie来看一看,在ie浏览器访问一次PathQuestionDemo1这个Servlet:

Cookie中的内容:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-AmkELgNE-1643352794313)(/Users/heroma/Downloads/03.JavaWeb核心/04-Cookie&Session&JSP/笔记/assets/Cookie文件介绍.png)]

我们是通过demo1写的cookie,demo1的访问路径是: http://localhost:8080/servlet/PathQuestionDemo1
通过比较两个路径:请求资源地址和cookie的path,可以看出:cookie的path默认值是:请求资源URI,没有资源的部分(在我们的案例中,就是没有PathQuestionDemo1)。

客户端什么时候带cookie到服务器,什么时候不带?
​ 就是看请求资源URI和cookie的path比较。

请求资源URI.startWith(cookie的path) 如果返回的是true就带,如果返回的是false就不带。

​ 简单的说: 就是看谁的地址更精细

​ 比如:Cookie的path: /国家 /省份 /城市

	 	 请求资源URI	:   	  /国家			/省份														  不带
	 	 请求资源URI   :	   /国家			/省份			/城市			/区县				带

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-hemPbo6V-1643352794314)(/Users/heroma/Downloads/03.JavaWeb核心/04-Cookie&Session&JSP/笔记/assets/案例2-4.png)]

在我们的案例中:

访问URL URI部分 Cookie的Path 是否携带Cookie 能否取到Cookie
PathQuestionDemo2 /servlet/PathQuestionDemo2 /servlet/ 能取到
PathQuestionDemo3 /PathQuestionDemo3 /servlet/ 不带

Session

HttpSession

  • 服务器端会话管理技术,本质也是采用客户端会话管理技术。只不过在客户端保存的是一个特殊标识,从而共享的数据保存到了服务器端的内存对象中。每次请求时,会将特殊标识带到服务器端,根据这个标识来找到对应的内存空间,从而实现数据共享。是Servlet规范中四大域对象之一的会话对象
  • 作用:可以实现数据共享

HttpSession常用方法

返回值 方法名 说明
void setAttribute(String var1, Object var2); 设置共享数据
Object getAttribute(String var1) 获取共享数据
void removeValue(String var1) 移除共享数据
String getId() 获取唯一标识名称
void invalidate() 让session立即失效

HttpSession的获取

  • 获取HttpSession是通过HttpServletRequest接口中的两个方法获取的
返回值 方法名 说明
HttpSession getSession() 获取HttpSession对象
HttpSession getSession(boolean create) 获取HttpSession对象,未获取带是否自动创建

在这里插入图片描述

HttpSession的使用

  • 需求说明
    • 通过第一个Servlet设置共享数据用户名,并在第二个Servlet获取到
  • 最终目的
    • 掌握HttpSession的基本使用,如何获取和使用
  • 实现步骤
    1. 在第一个servlet中获取请求的用户名
    2. 获取HttpSession
    3. 将用户名设置到共享数据中
    4. 在第二个servlet中获取HttpSession对象
    5. 获取共享数据用户名
    6. 将获取到用户名响应给客户端浏览器
package com.example.reqresp_test;

import java.io.*;
import java.text.SimpleDateFormat;
import java.util.Date;
import javax.servlet.http.*;
import javax.servlet.annotation.*;

@WebServlet(value = "/1")
public class HelloServlet extends HttpServlet {
    private String message;

    public void init() {
        message = "Hello World!";
    }

    public void doGet(HttpServletRequest request, HttpServletResponse response) throws IOException {
        //1. 在第一个servlet中获取请求的用户名
        String username = request.getParameter("username");
        //2. 获取HttpSession
        HttpSession session = request.getSession();
        System.out.println(session);
        System.out.println(session.getId());
        //3. 将用户名设置到共享数据中
        session.setAttribute("username", username);
        //4. 在第二个servlet中获取HttpSession对象
        //5. 获取共享数据用户名
        //6. 将获取到用户名响应给客户端浏览器


    }

    public void destroy() {
    }
}
package com.example.reqresp_test;

import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.io.IOException;

@WebServlet(value = "/2")
public class servlet02 extends HttpServlet {
    private String message;

    public void init() {
        message = "Hello World!";
    }

    public void doGet(HttpServletRequest request, HttpServletResponse response) throws IOException {
//        //1. 在第一个servlet中获取请求的用户名
//        String username = request.getParameter("username");
//        //2. 获取HttpSession
//        HttpSession session = request.getSession();
          System.out.println(session);
          System.out.println(session.getId());
//        //3. 将用户名设置到共享数据中
//        session.setAttribute("username", username);
        //4. 在第二个servlet中获取HttpSession对象
        HttpSession session = request.getSession();
        //5. 获取共享数据用户名
        Object username = session.getAttribute("username");
        //6. 将获取到用户名响应给客户端浏览器
        response.getWriter().write(username + "");

    }

    public void destroy() {
    }
}

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-vTvFts65-1643352794315)(/Users/heroma/Library/Application Support/typora-user-images/image-20220128123059868.png)]

HttpSession细节

  • 唯一标识的查看

在这里插入图片描述

  • Cookie的禁用

    • 弹框提示,告诉用户,大部分网站采用的解决方式(推荐)
    • 自己拼接,将JSESSIONID拼接到访问的资源路径,通过encodeURL()方法重写地址(不推荐)
  • 钝化和活化

    • 钝化:把长时间不用,但还不到过期时间的HttpSession进行序列化,写到磁盘上。

    • 活化:相反的状态

    • 何时钝化

      第一种情况:当访问量很大时,服务器会根据getLastAccessTime来进行排序,对长时间不用,但是还没到过期时间的HttpSession进行持久化。

      第二种情况:当服务器进行重启的时候,为了保持客户HttpSession中的数据,也要对HttpSession进行持久化

      注: HttpSession的持久化由服务器来负责管理,我们不用关心。 只有实现了序列化接口的类才能被序列化,否则不行。

JSP

JSP介绍

  • JSP(Java Server Page):是一种网页技术标准
  • JSP和Servlet一样,也是sun公司推出的一套开发动态web资源的技术,称为JSP/Servlet规范。JSP的本质其实就是一个Servlet。JSP部署在服务器上,可以处理客户端发送的请求,并根据请求内容动态的生成HTML,XML或者其他格式文档的web网页,然后在响应给客户端

JSP和HTML以及Servlet的使用场景

类别 适用场景
HTML 只能开发静态资源,不能包含java代码,无法添加动态数据。
Servlet 写java代码,可以输出页面内容,但是很不方便,开发效率极低。
JSP 它包括了HTML的展示技术,同时具备Servlet输出动态资源的能力。但是不适合作为控制器来用。
CSS 美化页面
JavaScript 给网页添加一些动态效果

JSP快速入门

  1. 创建一个web项目

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-RpLNuFdp-1643352794317)(/Users/heroma/Library/Application Support/typora-user-images/image-20220128125952221.png)]

  2. 在web目录下创建一个index.jsp的文件

    <%@ page contentType="text/html; charset=UTF-8" pageEncoding="UTF-8" %>
    <!DOCTYPE html>
    <html>
    <head>
        <title>JSP - Hello World</title>
    </head>
    <body>
    <h1><%= "Hello World!" %>
    </h1>
    <br/>
    <a href="hello-servlet">Hello Servlet</a>
    </body>
    </html>
    
  3. 在文件中写一个超链接:Hello Servlet

  4. 部署并启动项目

  5. 通过浏览器测试 、

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-z2gUTZQl-1643352794317)(/Users/heroma/Library/Application Support/typora-user-images/image-20220128130411048.png)]

JSP执行过程

JSP就是一个Servlet。是一个特殊的Servlet。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-CKkpmHTX-1643352794318)(/Users/heroma/Library/Application Support/typora-user-images/image-20220128134424269.png)]

JSP的原理:

​ 客户端提交请求

​ ——Tomcat服务器解析请求地址

​ ——找到JSP页面

​ ——Tomcat将JSP页面翻译成Servlet的java文件

​ ——将翻译好的.java文件编译成.class文件

​ ——返回到客户浏览器上。

JSP文件内容介绍

  • 生成的java文件目录

当我们打开index.jsp翻译的java文件看到的就是public final class index_jsp extends org.apache.jasper.runtime.HttpJspBase类的声明,然后我们在Tomcat的源码中找到类的声明,如下图:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-g5wu5Fkv-1643352794318)(/Users/heroma/Downloads/03.JavaWeb核心/04-Cookie&Session&JSP/笔记/assets/Tomcat中的HttpJspBase类声明.png)]

这张图一出场,就表明我们写的JSP它本质就是一个HttpServlet了。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Ep7EsEIi-1643352794319)(/Users/heroma/Downloads/03.JavaWeb核心/04-Cookie&Session&JSP/笔记/assets/jsp的本质说明.png)]

同时,我们在index_jsp.java文件中找到了输出页面的代码,并且在浏览器端查看源文件,看到的内容是一样的。这也就是说明,我们的浏览器上的内容,在通过jsp展示时,本质都是用out.write()输出出来的。

讲到这里,我们应该清楚的认识到,JSP它是一个特殊的Servlet,主要是用于展示动态数据。它展示的方式是用流把数据输出出来,而我们在使用JSP时,涉及HTML的部分,都与HTML的用法一致,这部分称为jsp中的模板元素,在开发过程中,先写好这些模板元素,因为它们决定了页面的外观。

JSP语法

  • JSP注释

    • <%–注释内容–%>
  • java代码块

    • <% 此处写java代码 %>
  • JSP表达式

    • <%=表达式%>
  • JSP声明

    • <%! 声明的内容 %>

      <%!
      需要注意的是: 写在里面的内容将会被tomcat翻译成全局的属性或者类方法。
      %>

      不加!声明的是局部变量

JSP指令

  • page指令

    • <%@ page contentType="text/html; charset=UTF-8" pageEncoding="UTF-8" %>
      
    属性名 作用
    contentType 响应正文支持的类型和设置编码格式
    language 使用语言,默认是java
    errorPage 当前页面出现异常后,应该转发到哪个页面上
    isErrorPage 是否抓住异常,如果为true则页面中就可以使用异常对象,默认是false
    import 导包import=”java.util.Date
    session 是否产生HttpSession对象,即是否在代码中调用request.getSession()。默认是true。
    buffer JspWriter用于输出JSP内容到页面上的缓存内容的大小。默认8kb。
    pageEncoding 翻译jsp时所用的编码格式
    isELIgnored 是否忽略EL表达式,默认值是false,不忽略。
  • include指令

    • 语法格式:<%@include file="" %>该指令是包含外部页面。
    • 属性:file,以/开头,就代表当前应用。
  • taglib指令

    • 语法格式:<%taglib uri="" prefix=""%>

    • 作用:该指令用于引入外部标签库。html标签和jsp标签不用引入。

    • 属性:

      ​ uri:外部标签的URI地址。

      ​ prefix:使用标签时的前缀。

JSP细节

  • 九大隐式对象

    隐式对象名称 类型 备注
    request javax.servlet.http.HttpServletRequest
    response javax.servlet.http.HttpServletResponse
    session javax.servlet.http.HttpSession Page指令可以控制开关
    application javax.servlet.ServletContext
    page Java.lang.Object 当前jsp对应的servlet引用实例
    config javax.servlet.ServletConfig
    exception java.lang.Throwable page指令有开关
    out javax.servlet.jsp.JspWriter 字符输出流,相当于printwriter
    pageContext javax.servlet.jsp.PageContext 很重要
  • PageContext对象

    • 它是JSP独有的对象,Servlet中没有这个对象。
    • 是四大域对象之一的页面域对象,还可以操作其他三个域对象中的属性
    • 还可以获取其他八个隐式对象
    • 生命周期随着JSP的创建而诞生,随着JSP的结束而消失。每个JSP页面都有一个独立的PageContext。

    常用方法

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-B2dt7Lto-1643352794319)(/Users/heroma/Downloads/03.JavaWeb核心/04-Cookie&Session&JSP/笔记/assets/PageContext方法详解.png)]

  • 四大域对象

    域对象名称 范围 级别 备注
    PageContext 页面范围 最小,只能在当前页面用 因范围太小,开发中用的很少
    ServletRequest 请求范围 一次请求或当期请求转发用 当请求转发之后,再次转发时请求域丢失
    HttpSession 会话范围 多次请求数据共享时使用 多次请求共享数据,但不同的客户端不能共享
    ServletContext 应用范围 最大,整个应用都可以使用 尽量少用,如果对数据有修改需要做同步处理

JSP的最佳事件-MVC模型

  • M(Model):模型。用于封装数据,封装的是数据模型

  • V(View):视图。用于显示数据,动态资源使用jsp页面,静态资源使用HTML页面

  • C(Controller):控制器。用于处理请求和响应,例如servlet

  • Servlet:擅长处理业务逻辑,不擅长输出显示界面。在web开发中多用于控制程序逻辑(流程)。所以我们称之为:控制器。

  • JSP:擅长显示界面,不擅长处理程序逻辑。在web开发中多用于展示动态界面。所以我们称之为:视图。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-0H9KFBC7-1643352794320)(/Users/heroma/Library/Application Support/typora-user-images/image-20220128145118171.png)]

Logo

CSDN联合极客时间,共同打造面向开发者的精品内容学习社区,助力成长!

更多推荐