一.会话技术
1.1 什么是会话
从浏览器和服务器建立连接开始,一直到浏览器关闭的整个过程就是一次会话
1.2 为什么要使用会话技术
HTTP是无状态协议,协议中不能够存储数据; 比如: 不能把登陆状态保存在协议里面;
Request 和 ServletContext 也可以存储信息, 那么为什么要使用会话, 作用域不同;
1.3 会话技术的分类
1.3.1 客户端的会话技术 Cookie
客户端会话技术, 它是服务器存放在浏览器的一小份数据, 浏览器以后每次访问该服务器的时候都会将这小份数据携带到服务器;
1.3.2 服务端的会话技术 Session
服务端会话技术, 将一次会话信息保存到服务器;
二.Cookie
2.1 Cookie 的流程
1.浏览器A 第一次向服务端 ServletA 发起请求,服务端将此次请求所携带的数据以 Cookie 的形式响应给浏览器;
2.浏览器A 如果浏览器A没有关闭, 第二次或更多次向服务端 ServletB 发起请求,会将之前的 Cookie 一并发送给服务端;
3.服务端 ServletB 或者其它的Servlet 可以从 Cookie 中取出浏览器A 第一次发起请求时所携带的数据;
2.2 Cookie 的使用
先后访问 ServletCookie01, ServletCookie02, ServletCookei03
/**
* Cookie的使用步骤:
* 1. 创建cookie,存储键值对
* 2. 设置cookie
* 2.1 设置 cookie 的有效期 (Cookie的默认有效期是一次会话)
* cookie.setMaxAge(-1); (默认是一会话)
* cookie.setMaxAge(正整数);
* cookie.setMaxAge(0); (删除cookie)
* 2.2 设置 cookie 的有效路径 (Cookie的默认有效路径是所有服务器的项目)
* setPath(路径),要求路径需要使用绝对路径表示,一般我们会设置为"当前项目"
* 3. 将cookie添加到response中
*
* 怎么样才能删除浏览器中的 cookie:
* 1. 如果 cookie 的有效期是一次会话,那么关闭浏览器 cookie 就删除了
* 2. 如果 cookie 的有效期不是一次会话,我们需要清除浏览器缓存才能删除 cookie
* 3. 怎么用代码删除 cookie:
* 使用代码往客户端存储一个同名、同 path 的 cookie,但是有效期为 0
*/
@WebServlet("/01")
public class ServletCookie01 extends HttpServlet {
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
doGet(req, resp);
}
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
req.setCharacterEncoding("UTF-8");
resp.setContentType("text/html;charset=UTF-8");
// Cookie 存储中文需要使用 URLEncoder 进行编码
String strCookie = URLEncoder.encode("一代大神", "UTF-8");
// 创建 Cookie 对象,存储键值对
Cookie cookie = new Cookie("username", strCookie);
// 设置 cookie 有效期
cookie.setMaxAge(60*60*24*7);
// 设置 cookie 的有效路径
// request.getContextPath() 获取项目的部署路径
cookie.setPath(req.getContextPath()+"/02");
// 将 cookie 添加到 response 中
resp.addCookie(cookie);
}
}
@WebServlet("/02")
public class ServletCookie02 extends HttpServlet {
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
doGet(req, resp);
}
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
req.setCharacterEncoding("UTF-8");
resp.setContentType("text/html;charset=UTF-8");
// 不止一个 cookie 对象 需要遍历
Cookie[] cookies = req.getCookies();
for (Cookie cookie : cookies) {
// 通过匹配 cookie 的 name 找到之前存入的 value 值
if (cookie.getName().equals("username")) {
//取出 (通过utf-8解码)
String decodeStr = URLDecoder.decode(cookie.getValue(), "UTF-8");
System.out.println("decodeStr= " + decodeStr);
}
}
}
}
@WebServlet("/03")
public class ServletCookie03 extends HttpServlet {
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
doGet(req, resp);
}
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
req.setCharacterEncoding("UTF-8");
resp.setContentType("text/html;charset=UTF-8");
// 不止一个 cookie 对象 需要遍历
Cookie[] cookies = req.getCookies();
for (Cookie cookie : cookies) {
// 通过匹配 cookie 的 name 找到之前存入的 value 值
if (cookie.getName().equals("username")) {
//取出 (通过utf-8解码)
String decodeStr = URLDecoder.decode(cookie.getValue(), "UTF-8");
System.out.println("decodeStr= " + decodeStr);
}
}
}
}
2.3 Cookie 的销毁
默认有效期, 会在浏览器关闭时销毁;
浏览器清除缓存;
-
往浏览器存储一个同名同路径, 并且时长限制为 0 的Cookie;
@WebServlet("/03") public class ServletCookie03 extends HttpServlet { protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { doGet(req, resp); } protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { req.setCharacterEncoding("UTF-8"); resp.setContentType("text/html;charset=UTF-8"); // Cookie 存储中文需要使用 URLEncoder 进行编码 String strCookie = URLEncoder.encode("一代大神", "UTF-8"); // 创建 Cookie 对象,存储键值对 Cookie cookie = new Cookie("username", strCookie); // 设置 cookie 有效期 cookie.setMaxAge(0); // 设置 cookie 的有效路径 // request.getContextPath() 获取项目的部署路径 cookie.setPath(req.getContextPath()+"/02"); // 将 cookie 添加到 response 中 resp.addCookie(cookie); } }
2.4 Cookie 的应用场景
记住用户名
自动登录
保存电影的播放进度
-
保存上次访问的时间
@WebServlet("/lastTime") public class ServletRememberLastTime extends HttpServlet { protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { doGet(req, resp); } protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { req.setCharacterEncoding("UTF-8"); resp.setContentType("text/html;charset=UTF-8"); // 获取请求中的 cookie String lastTime = null; Cookie[] cookies = req.getCookies(); if (cookies != null && cookies.length > 0) { for (Cookie cookie : cookies) { if (cookie.getName().equals("lastTime")) { lastTime = cookie.getValue(); } } } // 获取当前时间 SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); String formatTime = dateFormat.format(new Date()); if (lastTime == null || lastTime.length() == 0) { resp.getWriter().write(formatTime); } else { lastTime = URLDecoder.decode(lastTime, "UTF-8"); resp.getWriter().write(lastTime); } // 将获取到的当前时间存入 Cookie String encodeStr = URLEncoder.encode(formatTime, "UTF-8"); Cookie cookie = new Cookie("lastTime", encodeStr); resp.addCookie(cookie); } }
三.Session
3.1 Session 的流程
1.浏览器A 第一次向服务端 ServletA 发起请求,服务端将此次请求所携带的数据保存在服务端的 Session 对象中;
2.浏览器A 第二次向服务端 ServletB 发起请求;
3.服务端 ServletB 可以从服务端的 Session 对象中取出第一次请求时所携带的数据;
3.2 Session 的使用
先访问 ServletSession01, 再访问 ServletSession02;
@WebServlet("/ServletSession01")
public class ServletSession01 extends HttpServlet {
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
doGet(req, resp);
}
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
req.setCharacterEncoding("UTF-8");
resp.setContentType("text/html;charset=UTF-8");
HttpSession session = req.getSession();
session.setAttribute("username","二代大神");
}
}
@WebServlet("/ServletSession02")
public class ServletSession02 extends HttpServlet {
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
doGet(req, resp);
}
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
req.setCharacterEncoding("UTF-8");
resp.setContentType("text/html;charset=UTF-8");
Object username = req.getSession().getAttribute("username");
System.out.println("username = " + username);
}
}
3.3 Session 的销毁
默认是闲置30分钟就会销毁;
-
服务器异常关闭;
-
如果是正常关闭服务器
目录查看
C:\Users\用户名\.IntelliJIdea2017.2\system\tomcat\_sz61\work\Catalina\localhost
-
Session 的钝化
把内存中的session序列化保存到硬盘上
-
Session 的活化
从硬盘上读取序列化的session到内存中形成一个session对象
-
手动调用 Session 对象的 invalidate()方法
3.4 Session 的原理
Session 是基于 Cookie的;
1.浏览器A 第一次向服务端 ServletA 发起请求;
2.然后服务端第一次调用 request.getSession();
3.此时服务端会先从浏览器传送的 Cookie 中寻找 JSESSIONID;
如果没有找到,则会创建一个 Session 对象并生成一个 JSESSIONID 写到 Cookie 中,然后响应给浏览器;
如果找到了JSESSIONID, 则会通过这个 JSESSIONID 去寻找对应的 Session 对象;
如果这个 JSESSIONID 对应的 Session 对象已经被销毁了,则会重复上述创建过程;
4.如果此次会话正常,那么浏览器A 第二次以后向服务器发送的请求,服务端都可以拿到同一个 Session 对象去取出相应的数据;
浏览器关闭了, session使用不了, 是session销毁了吗?
session 没有销毁.
session 基于cookie, sessionId 保存到 cookie 里面的, 默认情况下 cookie 是会话级别, 浏览器关闭了 cookie 就是消失了,也就是说 sessionId 消失了, 从而找不到对应的 session 对象了, 就不能使用了;
解决:自己获得 sessionId, 自己写给浏览器设置 Cookie 的有效时长, 这个 Cookie 的key必须是JSESSIONID
3.5 Session 的应用场景
- 验证码存储
- 用户登录态的存储
四.域对象的对比
4.1 Cookie 与 Session的对比
- Cookie 是保存在浏览器上的, 而 Session 是保存在服务端;
- Cookie 只能存储字符串, 并且所带的字符串中不可以有空格, 如果字符串中带有中文需要使的 URLEncoder 重新编码, 新版; Session 可以存储基本数据类型,引用数据类型;
- Cookie 有大小限制, Session原则上没有;
4.2 Cookie,Session与其它域对象的对比
域对象 | 创建 | 销毁 | 作用范围 | 应用场景 |
---|---|---|---|---|
ServletContext | 服务器启动 | 服务器正常关闭/项目从服务器移除 | 整个项目 | 记录网站访问次数,聊天室 |
HttpSession | 没有JSESSIONID这个cookie的时候,调 用request.getSession()方法 | session过期(默认闲置30分钟),或者调用session对象的 invalidate()方法,或者服务器异常关闭 | 会话(多次请求) | 验证码校验, 保存用户登录状态等 |
Cookie | new 出来 | 与 Cookie 设置的有效时长有关, 同样可以设置删除Cookie | 会话(多次请求) | 记住用户名, 自动登录, 保存电影的播放进度, 保存上次访问的时间 |
HttpServletRequest | 来了请求 | 响应这个请求(或者请求已经接收了) | 一次请求 | servletA和jsp (servletB)之间数据传递(转发的时候存数据) |
五.JSP入门
5.1 什么是JSP
全称是Java Server Page(Java服务器页面),其本质是Servlet;
JSP与Servlet一样,都是SUN公司定义的用于开发动态Web资源的技术;
JSP = Html+Java+Jsp(内置对象,指令,动作标签等)特有的内容
5.2 为什么要使用JSP
为了简化代码,Servlet在展示页面(比如要动态的向页面输入一个表格)的时候,相当的繁琐; Sun公司为了解决这个问题,参照Asp开发了一套动态网页技术Jsp;
5.3 JSP的三种Java脚本
通过 JSP 的 Java 脚本, 可以在里面写 Java 代码;
类型 | 翻译成Servlet对应的部分 | 注意 |
---|---|---|
<%...%>:Java程序片段 | 翻译成Service()方法里面的内容, 局部的 | |
<%=...%>:输出表达式 | 翻译成Service()方法里面的内容,相当于调用out.print() | 输出表达式不能以;结尾 |
<%!...%>:声明成员变量(肯定不用) | 翻译成Servlet类里面的内容 |
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
JSP学习
<%--
1.Jsp的注释
1.1 Html的注释
1.2 Java的注释
1.3 Jsp自己的注释
2.能过脚本在JSP中编写Java代码
2.1 <%%>角本,这种角本在 Jsp 解析之后,运行的 service() 方法中;
2.2 <%=%>角本,这种用于往浏览器页面输出一个java变量,其实就是调用输出流对象的print方法向浏览器输出"="后面的数据;
2.3 <%!%>角本,这种角本用于定义成员变量和成员函数,这种脚本在翻译成java文件之后,是运行在 service() 方法外面的;
--%>
<%
int num = 0;
String username = "二代大神
";
sayHello();
// jsp的内置对象
response.getWriter().write("你今天快乐吗?
");
%>
username = <%=username%>
password = <%=password%>
<%!
public String password = "三代大神
";
public void sayHello() {
System.out.println("你今天快乐吗?");
}
%>
5.4 JSP的执行原理
JSP角本会被翻译(通过默认的JspServlet,JSP引擎)成Servlet(.Java文件),并编译成.class文件;
执行流程:
1.第一次访问.jsp文件是时候,服务器收到请求,JspServlet会去查找这个文件;
2.然后,服务器会将这个.jsp文件转换成.java文件;
3.编译.java文件,生成.class文件;
4.服务器运行.class文件,生成动态内容;
5.最后服务器将这些生成的动态内容,响应给浏览器;
<%%> 翻译成了service()方法里面的局部内容;
<%=%> 翻译成了service()方法里面的 out.print();
<%!%> 翻译成了servlet类里面的全局内容;
六.EL表达式
6.1 什么是EL表达式
全称是 Expression Language: 表达式语言, JSP 2.0之后内置在 JSP 里面;
其语法格式为 ${el表达式};
6.2 为什么要使用EL表达式
为了使 JSP 写起来更加简单, 取值 (取的域对象里面存的值) 更加简单(代替脚本 <% %>); 目的肯定是为了简化代码, 但是感觉上并没有简化多少;
1.获取数据. 获取的是 域( request,session, ServletContext ) 对象中存储的数据;
2.EL执行运算;
6.3 EL表达式的使用
6.3.1 获了简单数据类型的数据
语法格式为:
${applicationScope.key}
${sessionScope.key}
${requestScope.key}
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
Jsp_EL表达式学习
<%
// application 对象就是 ServletContext 对象
application.setAttribute("username", "一代大神");
session.setAttribute("username", "二代大神");
request.setAttribute("username", "三代大神");
%>
<%-- 显示 application 中获取到的username= ${applicationScope.username}
--%>
<%-- 显示 session 中获取到的username= ${sessionScope.username}
--%>
<%-- 显示 request 中获取到的username= ${requestScope.username} --%>
<%-- 获取域对象中存的值可以写key值,如果key值相同的话,则会取范围最小的那一个,
但是一般key值不会相同;
--%>
显示 application 中获取到的username= ${username}
显示 session 中获取到的username= ${username}
显示 request 中获取到的username= ${username}
6.3.2 获取复杂类型的数据
获取数组
其语法格式为: ${对象名[index]}
获取list
其语法格式为: ${对象名[index]}
获取map
其语法格式为: ${对象名.key}或者${对象名."key"}
获取bean
其语法格式为: ${对象名.key}或者${对象名."key"}
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
EL获取复杂类型的数据
<%
String[] elStrings = {"一代大神", "一代二神", "一代三神"};
request.setAttribute("elStrings", elStrings);
ArrayList list = new ArrayList();
list.add("一代四神");
list.add("一代五神");
list.add("一代六神");
request.setAttribute("list", list);
HashMap map = new HashMap();
map.put("一代七神", "一代七神");
map.put("一代八神", "一代八神");
map.put("一代九神", "一代九神");
request.setAttribute("map", map);
User user = new User("shaShen","shaShen");
request.setAttribute("user",user);
%>
<%-- 在EL表达式中,只要是根据下标取数据都可以写成 [index] --%>
取出存放在request对象中数组的第2个元素 = ${elStrings[1]}
取出存放在request对象中list的第2个元素 = ${list[1]}
<%-- 在el表达式中,只要是根据对应的属性的get方法去获取数据都可以写成 .key 或者 ["key"]
但是好像不能有特殊字符像"_"或者"-"这样的都不可以,可以有中文;
--%>
取出存放在request对象中map中的key为"一代八神"的元素 =${map.一代八神}
取出存放在request对象中map中的key为"一代九神"的元素 =${map["一代九神"]}
取出存放在request对象中user对象的username值 = ${user.username}
取出存放在request对象中user对象的password值 = ${user["password"]}
6.3.3 EL执行运算
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
EL执行运算
<%
//el表达式中的empty可以判断一个字符串是否为空字符串,一个对象是否为null,一个集合的长度是否为0
ArrayList list = new ArrayList();
list.add("张三丰");
request.setAttribute("list", list);
request.setAttribute("msg", "requestValue");
User user = new User();
request.setAttribute("u", user);
%>
判断域对象中的list集合的长度是否为0: ${empty list}
判断域对象中的msg字符串是否为空字符串: ${empty msg}
判断域对象中的user是否为null : ${empty u}
判断域对象中的msg的值是否等于requestValue : ${msg.equals("requestValue")}
判断域对象中的msg的值是否等于requestValue : ${msg==("requestValue")}
6.3.4 EL获取 Cookie 中的数据
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
EL执行运算
<%-- Jsp里面是内置的Session对象,则可以通过Cookie对象获取JESSIONID的值 --%>
<%
Cookie[] cookies = request.getCookies();
String sessionID = null;
for (Cookie cookie : cookies) {
if (cookie.getName().equals("JSESSIONID")) {
sessionID = cookie.getValue();
}
}
%>
使用原始方式获取Cookie中的JSESSIONID值为<%=sessionID%>
<%--
${cookie}表示获取这次请求中的所有cookie对象
${cookie.JSESSIONID}表示获取名为"JSESSIONID"的cookie对象
${cookie.JSESSIONID.value}表示获取名为"JSESSIONID"的cookie对象的value
--%>
使用EL方式获取Cookie中的JSESSIONID值为${cookie.JSESSIONID.value}
七.JSTL标签库
7.1 什么是JSTL标签库
JSTL全称JSP Standard Tab Library, JSP标准标签库是一个不断完善的开放源代码的JSP标签库; 通过这些标签库可以简化在JSP页面上操作数据的代码, 比如遍历数据, 判断数据等;
JSTL不是内置的, 需要导包, 并且添加标答库类别:
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
7.2 JSTL标签库的使用
if标签
choose 标签
forEach 标签
1.begin属性:从哪个下标开始遍历,如果不写默认是从0开始
2.end属性:到哪个下标结束遍历,如果不写默认是到集合/数据的最后一个元素
3.step属性:表示遍历时候的步长,默认步长是1
4.var属性:表示将遍历的结果存放进域对象时候的key
5.item属性:指定要遍历的对象
forEach 标签的 varStatus 属性
状态属性:
1.index 下标
2.count 计数
3.current 当前元素的值
4.first 是否是第一个元素
5.last 是否是最后一个元素
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
JSP标签学习
<%
// 往标签中存入age
request.setAttribute("age", 19);
request.setAttribute("course", "PHP");
ArrayList list = new ArrayList();
list.add("张三");
list.add("李四");
list.add("王五");
list.add("赵六");
list.add("田七");
request.setAttribute("list", list);
%>
<%-- 判断age是否大于等于18,如果大于等于18则输出:已成年,否则输出未成年 --%>
<%-- 第一种方式:三目运算符--%>
${age>=18?"1.已成年":"未成年"}
<%-- 第二种方式:if标签 --%>
2.已成年
未成年
<%-- choose标签 --%>
学习Java
学习C
学习拍黄片
学习,学个屁!
<%-- foreach标签 --%>
<%-- 输出 0-9 --%>
${i}
<%-- 输出 list 中的数据 --%>
${username}
<%-- 以表格的形式输入 list 中的数据,测试 varStatus 状态属性--%>
begin 开始
end 结否
step 自增或自减数
count 第几个元素
current 当前元素
first 是否是首位元素
last 是否是末位元素
index 当前元素下标
${vars.begin}
${vars.end}
${vars.step}
${vars.count}
${vars.current}
${vars.first}
${vars.last}
${vars.index}