7、Cookie、Session
7.1 会话
会话:用户打开了一个浏览器,点击了很多超链接,访问了多个web资源,关闭浏览器,这个过程可以称之为会话。
有状态会话:一个同学来过教室,下次再来教室,我们会知道这个同学曾经来过,称之为有状态会话。
一个网站如何证明你来过了?
客户端 服务端
- 服务端给客户端一个信件,客户端下次访问客户端带上信件就可以了;cookie
- 服务端登记你来过了,下次来的时候来匹配你;session
7.2 保存会话的两种技术
cookie
- 客户端技术(响应,请求)
session
- 服务端技术,利用这个技术,可以保存用户的会话信息。我们可以把信息或数据放在Session中!
常见场景:网站登录之后,你下次不同再登录,第二次访问直接可以上去。
7.3 Cookie
- 从请求中拿到cookie信息
- 服务器响应给客户端cookie
Cookie[] cookies = req.getCookies(); // 获得Cookie
cookie.getName(); // 获得cookie中的key
cookie.getValue() // 获得cookie中的value
new Cookie("lastLoginTime", System.currentTimeMillis()+""); // 新建一个cookie
cookie.setMaxAge(24*60*60); // 设置cookie的有效期
resp.addCookie(cookie); // 响应给客户端一个cookie
cookie:一般会保存在本地的用户目录下 appdata;
一个网站cookie是否存在上限?
- 一个Cookie只能保存一个信息;
- 一个web站点可以浏览器发送多个Cookie,最多存放20个Cookie;
- Cookie大小有限制4kB
- 300个Cookie浏览器的上限
删除Cookie:
- 不设置有效期,关闭浏览器,自动失效;
- 设置有效期时间为0;
编码解码:
URLEncoder.encode("王木木","utf-8");
URLDecoder.decode(cookie.getValue(),"utf-8");
7.4 Session(重点)
什么是Session:
- 服务器会给每一个用户(浏览器)
- 一个Session独占一个浏览器,只要浏览器没有关闭,这个Session就存在
- 用户登录之后,整个网站都可以访问! --> 保存用户的信息,保存购物车的信息
Session与Cookie的区别:
- Cookie是把用户的数据写给用户的浏览器,浏览器保存
- Session把用户的数据写到用户独占的Session中,服务端保存(保存重要的信息,减少服务器资源的浪费)
- Session对象由服务器创建
使用场景:
- 保存一个登录用户的信息
- 购物车信息
- 在整个网站中经常使用的数据,我们将它保存在Session中
使用Session:
public class SessionDemo01 extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
// 解决乱码问题
req.setCharacterEncoding("UTF-8");
resp.setCharacterEncoding("UTF-8");
resp.setContentType("text/html;charset=utf-8");
// 得到Session
HttpSession session = req.getSession();
// 给Session存东西
session.setAttribute("name",new Person("王木木",18));
// 获取Session的ID
String sessionId = session.getId();
// 判断Session是不是新创建的
if (session.isNew()) {
resp.getWriter().write("session 创建成功,ID:" + sessionId);
} else {
resp.getWriter().write("session已经在服务器中存在了,ID" + sessionId);
}
// Session创建的时候做了什么事情:
//Cookie cookie = new Cookie("JSESSIONID",sessionId);
//resp.addCookie(cookie);
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
doGet(req, resp);
}
}
// 得到Session
HttpSession session = req.getSession();
Person person = (Person) session.getAttribute("name");
System.out.println(person.toString());
HttpSession session = req.getSession();
session.removeAttribute("name");
// 手动注销session
session.invalidate();
会话自动过期:web.xml配置
<!--设置Session默认的失效时间-->
<session-config>
<!--15分钟后,Session自动失效,以分钟为单位-->
<session-timeout>15</session-timeout>
</session-config>
8、JSP
8.1 什么是JSP
Java Server Pages:Java服务端页面,也和Servlet一样,用于动态Web技术!
最大的特点:
- 写JSP就像是写HTML
- 区别
- HTML只给用户提供静态的数据
- JSP页面中可以嵌入Java代码,为用户提供动态数据
8.2 JSP原理
思路:JSP到底怎么执行的?
-
代码层面没有任何问题
-
服务器内部工作
Tomcat中有一个work目录
IDEA中使用Tomcat的会在IDEA的Tomcat中生成一个work目录
我电脑的地址:C:\Users\won_j\.IntelliJIdea2019.3\system\tomcat\Unnamed_javaweb-session-cookie\work\Catalina\localhost\ROOT\org\apache\jsp
发现页面转变成了Java程序!
浏览器向服务器发送请求,不管访问什么资源,其实都是在访问Servlet!
JSP最终也会被转换成为一个Java类。
JSP本质上就是一个Servlet!
打开index_jsp.java
public final class index_jsp extends org.apache.jasper.runtime.HttpJspBase
implements org.apache.jasper.runtime.JspSourceDependent,
org.apache.jasper.runtime.JspSourceImports
发现有继承HttpJspBase
,进入HttpJspBase
类,发现
public abstract class HttpJspBase extends HttpServlet implements HttpJspPage
进一步分析index_jsp.java
// 初始化
public void _jspInit() {
}
// 销毁
public void _jspDestroy() {
}
// JSPService
public void _jspService(HttpServletRequest request, HttpServletResponse response)
-
判断请求
if (!javax.servlet.DispatcherType.ERROR.equals(request.getDispatcherType())) { final java.lang.String _jspx_method = request.getMethod(); if ("OPTIONS".equals(_jspx_method)) { response.setHeader("Allow","GET, HEAD, POST, OPTIONS"); return; } if (!"GET".equals(_jspx_method) && !"POST".equals(_jspx_method) && !"HEAD".equals(_jspx_method)) { response.setHeader("Allow","GET, HEAD, POST, OPTIONS"); response.sendError(HttpServletResponse.SC_METHOD_NOT_ALLOWED, "JSP 只允许 GET、POST 或 HEAD。Jasper 还允许 OPTIONS"); return; } }
-
内置一些对象
final javax.servlet.jsp.PageContext pageContext; // 页面上下文 javax.servlet.http.HttpSession session = null; // session final javax.servlet.ServletContext application; // applicationContext final javax.servlet.ServletConfig config; // config javax.servlet.jsp.JspWriter out = null; // out final java.lang.Object page = this; // page HttpServletRequest request // 请求 HttpServletResponse response // 响应
-
输出页面前增加的代码
response.setContentType("text/html"); // 设置响应的页面类型 pageContext = _jspxFactory.getPageContext(this, request, response, null, true, 8192, true); _jspx_page_context = pageContext; application = pageContext.getServletContext(); config = pageContext.getServletConfig(); session = pageContext.getSession(); out = pageContext.getOut(); _jspx_out = out;
-
以上的这些个对象,我们可以在JSP页面中直接使用!
在hello.jsp中,设置变量name并输出到页面上:
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>Title</title>
</head>
<body>
<%
String name = "wonjack";
%>
name:<%=name%>
</body>
</html>
在访问这个页面之前,并没有存在相应的两个文件。
当访问之后,打开hello_jsp.java文件,发现:
out.write("\r\n");
out.write("<html>\r\n");
out.write("<head>\r\n");
out.write(" <title>Title</title>\r\n");
out.write("</head>\r\n");
out.write("<body>\r\n");
String name = "wonjack";
out.write("\r\n");
out.write("\r\n");
out.write("name:");
out.print(name); // 对于变量的输出,用了out.print()
out.write("\r\n");
out.write("</body>\r\n");
out.write("</html>\r\n");
在JSP页面中:
只要是Java代码,就会原封不动的输出;
如果是HTML代码,就会被转换为:
out.write("<html>\r\n");
这样的格式,输出到前端!
8.3 JSP基础语法
任何语言都有自己的语法,Java中有。JSP作为java技术的一种应用,它拥有一些自己扩充的语法(了解,知道即可),Java所有语法都支持!
JSP表达式
<%--JSP表达式
作用:用来将程序的输出,输出到客户端
<%= 变量或者表达式%>
--%>
<%= new java.util.Date()%>
脚本片段
<%--jsp脚本片段--%>
<%
int sum = 0;
for (int i = 1; i <= 100; i++) {
sum += i;
}
out.println("<h1>Sum="+sum+"</h1>");
%>
脚本片段的再实现
<%
int x = 10;
out.println(x);
%>
<p>这是一个JSP文档</p>
<%
int y = 2;
out.println(y);
%>
<hr>
<%--在代码中嵌入HTML元素--%>
<%
for (int i = 0; i < 5; i++) {
%>
<h1>hello,u meet!<%=i%></h1>
<%
}
%>
JSP声明
8.4 JSP指令
修改了web.xml
文件,必须要重启Tomcat!
<%@ page args…… %>
<%--定制错误页面--%>
<%@ page errorPage="error/500.jsp" %>
<%--显式地声明这是一个错误页面--%>
<%@ page isErrorPage="true" %>
<%@ page pageEncoding="UTF-8" %>
<%-- @include会将两个页面合二为一 --%>
<%@ include file="common/header.jsp"%>
<h1>网页主体</h1>
<%@ include file="common/footer.jsp"%>
<hr>
<%--JSP标签
jsp:include:拼接页面,本质上还是三个
一般用这个,灵活性更高
--%>
<jsp:include page="/common/header.jsp"/>
<h1>网页主体</h1>
<jsp:include page="/common/footer.jsp"/>
8.5 九大内置对象
- PageContext
- Request 存东西
- Response 存东西
- Session 存东西
- Application【ServletContext】 存东西
- Config【ServletConfig】
- Out
- Page,不同了解
- Exception
pageDemo01.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>Title</title>
</head>
<body>
<%--内置对象--%>
<%
pageContext.setAttribute("name1","王木1号"); // 保存的作用域只在一个页面中有效
request.setAttribute("name2","王木2号"); // 保存的数据只在一次请求中有效,请求转发会携带这个数据
session.setAttribute("name3","王木3号"); // 保存的数据只在一次会话中有效,从打开浏览器到关闭浏览器
application.setAttribute("name4","王木4号"); // 保存的数据只在服务器中有效,从打开服务器到关闭服务器
%>
<%--脚本片段中的代码,会被原封不动生成到_jsp.java
要求:这里面的代码:必须保证Java语法的正确性
--%>
<%
// pageContext取出,我们通过寻找的方式来
// 从底层到高层(作用域)
String name1 = (String) pageContext.findAttribute("name1");
String name2 = (String) pageContext.findAttribute("name2");
String name3 = (String) pageContext.findAttribute("name3");
String name4 = (String) pageContext.findAttribute("name4");
String name5 = (String) pageContext.findAttribute("name5"); // 不存在
%>
<%--使用EL表达式输出 ${} --%>
<h1>取出的值为:</h1>
<h3>${name1}</h3>
<h3>${name2}</h3>
<h3>${name3}</h3>
<h3>${name4}</h3>
<%--如果不存在则不在页面上输出--%>
<h3>${name5}</h3>
<%--如果不存在,则输出null--%>
<h3><%=name5%></h3>
</body>
</html>
输出:
pageDemo02.jsp
直接去取pageDemo01.jsp
中的数据:
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>Title</title>
</head>
<body>
<%--脚本片段中的代码,会被原封不动生成到_jsp.java
要求:这里面的代码:必须保证Java语法的正确性
--%>
<%
// pageContext取出,我们通过寻找的方式来
// 从底层到高层(作用域):page -> request -> session -> application
String name1 = (String) pageContext.findAttribute("name1");
String name2 = (String) pageContext.findAttribute("name2");
String name3 = (String) pageContext.findAttribute("name3");
String name4 = (String) pageContext.findAttribute("name4");
String name5 = (String) pageContext.findAttribute("name5"); // 不存在
%>
<%--使用EL表达式输出 ${} --%>
<h1>取出的值为:</h1>
<h3>${name1}</h3>
<h3>${name2}</h3>
<h3>${name3}</h3>
<h3>${name4}</h3>
<%--如果不存在则不在页面上输出--%>
<h3>${name5}</h3>
<%--如果不存在,则输出null--%>
<h3><%=name5%></h3>
</body>
</html>
输出:
request:客户端向服务器发送请求,产生的数据,用户看完就没用了,比如:新闻,用户看完就没用的!
session:客户端向服务器发送请求,产生的数据,用户用完一会儿还有用,比如:购物车;
application:客户端向服务器发送请求,产生的数据,一个用户用完了,其他用户还可能使用,比如:聊天数据;
当pageDemo01.jsp
中添加:
pageContext.forward("/pageDemo02.jsp");
访问pageDemo01.jsp
,会有:
原因如下:
request.setAttribute("name2","王木2号"); // 保存的数据只在一次请求中有效,请求转发会携带这个数据
8.6 JSP 标签、JSTL标签、EL表达式
<!--JSTL表达式的依赖-->
<dependency>
<groupId>javax.servlet.jsp.jstl</groupId>
<artifactId>jstl-api</artifactId>
<version>1.2</version>
</dependency>
<!--standard标签库-->
<dependency>
<groupId>taglibs</groupId>
<artifactId>standard</artifactId>
<version>1.1.2</version>
</dependency>
EL表达式:${}(Expression Language) 是为了使JSP写起来更加简单。表达式语言的灵感来自于 ECMAScript 和 XPath 表达式语言,它提供了在 JSP 中简化表达式的方法,让Jsp的代码更加简化。
- 获取数据
- 执行运算
- 获取文本开发的常用对象
- 调用Java方法
JSP标签
<%--jsp:include--%>
<%--
http://localhost:8080/jsptag.jsp?name=jackwon&age=18
--%>
<jsp:forward page="/jsptag2.jsp">
<jsp:param name="name" value="jackwon"/>
<jsp:param name="age" value="18"/>
</jsp:forward>
JSTL表达式
JSTL标签库的使用就是为了弥补HTML标签的不足;它自定义许多标签,可以供我们使用,标签的功能和Java代码一样!
格式化标签
SQL标签
XML标签
核心标签(掌握部分)
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
JSTL标签库使用步骤
- 引入对应的taglib
- 使用其中的方法
- 在Tomcat也需要引入JSTL的包,否则会报错:JSTL解析错误
c:if
<body>
<h4>if测试</h4>
<hr>
<form action="coreif.jsp" method="get">
<%--
EL表达式获取表单中的数据
${param.参数名}
--%>
<input type="text" name="username" value="${param.username}">
<input type="submit" value="登录">
</form>
<%--判断如果提交的用户名是管理员,则登录成功--%>
<%--<%--%>
<%-- if (request.getParameter("username").equals("admin")) {--%>
<%-- out.print("登录成功");--%>
<%-- }--%>
<%--%>--%>
<c:if test="${param.username=='admin'}" var="isAdmin">
<c:out value="管理员欢迎您!"/>
</c:if>
<%--自闭和标签--%>
<c:out value="${isAdmin}"/>
</body>
c:choose c:when
<body>
<%--定义了一个变量score,值为85--%>
<c:set var="score" value="85"/>
<c:choose>
<c:when test="${score>=90}">你的成绩为优秀</c:when>
<c:when test="${score>=80}">你的成绩为良好</c:when>
<c:when test="${score>=70}">你的成绩为一般</c:when>
<c:when test="${score<=80}">你的成绩为及格</c:when>
</c:choose>
</body>
c:foreach
<%--
var,每一次遍历出来的变量
items,要遍历的对象
begin,哪里开始
end,到哪里
step,步长
--%>
<c:forEach var="people" items="${list}">
<c:out value="${people}"/><br>
</c:forEach>
<hr>
<c:forEach var="people" items="${list}" begin="1" end="3" step="2">
<c:out value="${people}"/><br/>
</c:forEach>