1 Session的其它特性及Cookie的介绍
Servlet中存在两种会话跟踪机制Cookie HttpSession。
1.1 Session的其它特性
HttpSession是一种安全级别较高的会话跟踪机制,这种会话机制依靠Cookie维持。用户通过request.getSession()来拿取或创建一个新的session,如果当前已经存在session了,则拿取已经存在的session;不存在则创建新的session。
创建或者拿取session之后,用户可以通过setAttribute(String,Object)向session中赋值,之后可以通过getAttribute(String)来拿取值。
session默认的最大不活动周期为1800s,可以在创建session时定义最大不活动周期。从创建开始即开始倒计时,当1800s之后用户没有再次提交请求则session销毁,内部的参数也随之消亡,如果用户再次提交请求,则倒计时重置。session这种会话跟踪机制由WEB服务器提供,支持中文。
-
HttpSession何时会销毁
- 超过最大不活动周期(存在误差,比定义或默认的实际的时间要久一些)
- 直接调用session.invalidate()直接调用此方法立刻销毁当前的session(removeAttribute()是删除内部某一对键值对,而invalidate()是直接销毁这一个session)
- 关闭浏览器销毁
注意其实并不是立刻销毁了session而是当我们再次打开浏览器时,WEB服务器会再次分配一个新的session给用户,原先的session再也没法拿取了。 - 关闭服务器销毁
-
HttpSession会话跟踪机制与Cookie有关系吗?如果有请说出为什么两者有联系?有何种联系?如果Cookie禁用如何维持session?
HttpSession会话跟踪机制依靠Cookie维持,Cookie是客户端浏览器提供的一种安全性较低的会话跟踪机制,保存在用户本地,不支持中文。
具体来说Cookie机制采用的是在客户端保持状态的方案,而HttpSession机制采用的是在服务器端保持状态的方案,由于服务器端保持状态的方案在客户端也需要保存一个标识,所以HttpSession机制可能需要借助于Cookie机制来达到保存标识的目的。
当用户调用request.getSession()时,WEB服务器首先从Cookie中拿取sessionid,如果无法拿取,则创建一个新的session且为这个session分配一个sessionid,分配完之后将这个sessionid放置到当前的Cookie。
如果Cookie被禁用,则session失效。如果cookie被禁用可以使用重写URL的方式继续维持session。
创建Cookie
Cookie cookie = new Cookie(String,String);
通过setMaxAge(时间以s为单位)设置Cookie保存时间,设置保存时间之后用户只要不删除cookie文件,则到期之前cookie一直保留在本地。
用户调用request.getSession()时,WEB服务器创建新的session并将sessionid放置当前Cookie的过程:
Cookie cookie = new Cookie(“jsessionid”,“56453213576865”);
跳转到目的地之后,当用户再次调用request.getSession(),WEB服务器可以从Cookie当中拿取sessionid,从而拿取绑定的session,因为sessionid一致,所以拿取的session也是同一个session。
(简要介绍Cookie,后面会学到。)
1.2 编写测试
WebRoot/index.html
<!DOCTYPE html>
<html>
<head>
<title>用户登录</title>
<meta charset="utf-8" />
</head>
<body>
<div id="container">
<h3>用户登录</h3>
<hr />
<form action="servlet/TestSession1" method="post">
<label for="nameid">用户姓名:</label>
<input type="text" name="name" id="nameid"
style="width:138px" required placeholder="请输入用户名" />
<br />
<label for="passid">用户密码:</label>
<input type="password" name="pass" id="passid"
style="width:138px" required placeholder="请输入用户密码" />
<br />
<input type="submit" value="提交" />
<input type="reset" value="取消" />
</form>
<a href="servlet/TestSession2">以游客身份登录</a>
</div>
</body>
</html>
src/servlet/TestSession1.java
package com.test.servlet;
import java.io.IOException;
import java.io.PrintWriter;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
public class TestSession1 extends HttpServlet {
public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
response.setContentType("text/html;charset=utf-8");
request.setCharacterEncoding("utf-8");
PrintWriter out = response.getWriter();
//拿取提交过来的用户名和密码
String name = request.getParameter("name");
String pass = request.getParameter("pass");
if(name.trim().equals("eric") && pass.trim().equals("12345")){
//创建一个新的session
HttpSession session = request.getSession();
//session一般用来封装权限信息
session.setAttribute("n",name);
session.setAttribute("p",pass);
//拿取session的sessionid,这个id是一个32位的随机码,类似我们的
//身份证号,是session唯一身份标识
System.out.println("跳转之前session的id是:"
+session.getId());
//设置session的最大不活动周期
session.setMaxInactiveInterval(800);
// request.getContextPath()、application.getContextPath()都是拿取 /工程名
response.sendRedirect("/项目名/servlet/TestSession2");
return;
}
out.println("<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01 Transitional//EN\">");
out.println("<HTML>");
out.println(" <HEAD><TITLE>登录失败</TITLE></HEAD>");
out.println(" <BODY>");
out.println("数据库中查无此人,请您先注册<hr/>");
out.println(" </BODY>");
out.println("</HTML>");
out.flush();
out.close();
}
}
src/servlet/TestSession2.java
package com.test.servlet;
import java.io.IOException;
import java.io.PrintWriter;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
public class TestSession2 extends HttpServlet {
public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
response.setContentType("text/html;charset=utf-8");
request.setCharacterEncoding("utf-8");
PrintWriter out = response.getWriter();
//拿取已经存在的session
HttpSession session = request.getSession();
//打印sessionid
System.out.println("跳转之后的Sessionid是:" + session.getId());
//拿取用户名和密码
String name = (String)session.getAttribute("n");
String pass = (String)session.getAttribute("p");
if(name != null && pass != null){
//当登录成功后退进入游客身份访问时,如果不删除属性,
//会导致以游客访问依然会登录到系统中
session.removeAttribute("n");
session.removeAttribute("p");
out.println("<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01 Transitional//EN\">");
out.println("<HTML>");
out.println(" <HEAD><TITLE>高级会员区</TITLE></HEAD>");
out.println(" <BODY>");
out.println("欢迎您回来" + name + "<hr />");
out.println(" </BODY>");
out.println("</HTML>");
out.flush();
out.close();
return;
}
out.println("<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01 Transitional//EN\">");
out.println("<HTML>");
out.println(" <HEAD><TITLE>游客游览区</TITLE></HEAD>");
out.println(" <BODY>");
out.println("这里是游客游览区,登录后获取更多内容<hr/>");
out.println(" </BODY>");
out.println("</HTML>");
out.flush();
out.close();
}
}
效果图:
登录后
退出重新进入游客区
输入密码错误
控制台信息,显示跳转前后为同一个session
2 JSP初学
JSP(Java Server Pages,Java服务器页面)。其实就是HTML + Java的组合,实际上是一个Servlet类,写入JSP文件的HTML代码由字符流输入到Java中,将字符流写入响应中返回给客户端。只是它由WEB容器创建,我们只需要、也只能定义这个类的成员变量、成员方法和Service()成员方法内部内容。JSP页面由WEB容器自动生成Servlet类并编译,相当于一个模板。
当JSP中的getAttribute值获取为空时,报500错。
2.1 JSP执行顺序
比前面只用Servlet类时多了一个JSP文件转换的过程。
2.2 引入Java代码的三种方式、JSP三种基本标签的介绍
index.jsp
<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
<!DOCTYPE HTML>
<html>
<head>
<title>引入Java代码的三种方式</title>
</head>
<body>
<!--
此种注释仅仅用来注释页面的标签,不能用来注释书写的Java代码
-->
<%--
在JSP中必须使用这种注释方式来注释Java代码与标签
--%>
<h3>2019年你的愿望是什么?</h3>
<hr />
<%--
1):标签中带“!”且语句末尾有“;”
生成的代码在service()外,服务器servlet类的成员
--%>
<%! String str1 = "我是写在带!的里面的字符串"; %>
<%--
2):标签中不带“!”且语句末尾有“;”
生成的代码在service()内,作为service()的局部变量
--%>
<% String str2 = "我是写在不带!的里面的字符串"; %>
<%--
3):表达式的输出方式,语句末尾没有“;”
生成在service()内,直接输出值
--%>
<%=str1 %>
<%=str2 %>
<hr />
<%!
int count = 10;
public Integer getCount(){
count++;
return count;
}
public Object getNull(){
return null;
}
%>
<% if(count%2==0){ %>
<label style="color:red"><%=count %></label>
<%}else{ %>
<label style="color:blue"><%=count %></label>
<%} %>
<%
int count = 50;
count++;
%>
<%--
尖括号在HTML/Jsp中无法使用,只能使用转义符
--%>
<br />
看看这里的效果是---------><%=count %>
<br />
再看看这里的效果---------><%=getCount() %>
<br />
最后看看这里的效果---------><%=getNull() %>
</body>
</html>
查看Jsp在服务器端是如何转化的,部署到服务器后,服务器中对应的目录在这里:
打开即看到刚才我们写在Jsp页面中的代码:
效果图:
2.3 三种指令标签
指令元素,凡是称之为指令元素的一般在%后面添加一个@符号。
2.3.1 include指令
引入外部页面到本页面,此时两个页面的变量可以数据共享。file属性值为引入的外部页面的地址。
include2.jsp
<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<title>2)include指令元素</title>
</head>
<body>
<%
String str1 = "我是include指令元素的主页赋值!";
%>
<%---
include
此处include表示引入一个外部页面
--%>
<%@ include file="data2.jsp" %>
<%=str2 %>
</body>
</html>
data2.jsp
<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<title></title>
</head>
<body>
<%=str1 %>
<%
String str2 = "我是辅页赋值";
%>
</body>
</html>
效果图:
2.3.2 page指令(12个参数)
- language:当前页面使用何种脚本信息,一般为Java
- import:当前页面导包信息,多个包用逗号隔开
- pageEncoding:当前页面转换编码,默认iso-8859-1,这个编码方式不能书写中文造成乱码,更改为gbk或者utf-8才可以书写中文
- isELIgnored:是否忽略EL表达式,如果为true,则禁用EL表达式,当EL表达式原文本输出,可以试着声明这个办法
- contentType:设置软编码(部分)相当于Servlet中的response.setContentType(“text/html;charset=utf-8”);
一般再配合<% request.setCharacterEncoding(“编码”);%> - errorPage:当前页面如果出现异常,则自动跳转到哪个页面,值定义为出现错误时跳转的页面。这是错误友好化的一种解决方案
- isErrorPage:当前页面是否开启exception内置对象, 默认false不开启,这个false与errorPage无关,为false也能跳转错误页面
- buffer:表示页面的缓存,默认8kb的内容保存在本地,比如百度的首页不联网也能开,就是有缓存的作用
- autoFlush:当前页面是否支持自动刷新机制,默认不支持,用于聊天室、图文直播这种需要定时刷新页面的情况
- session:默认是true,如果更改为false,则当前页面默认不创建session。源码中session,每次加载时session已默认被创建好了一个,所以JSP页面在加载时已有session对象,可以选择关闭
- isThreadSafe:当前页面线程是否安全,如果为true则单实例多线程,易出现并发问题;更改为false,则底层实现SingleThreadModel接口,线程安全但效率低下,默认为true。注意,这个值与实际的情况相反
- info:表示嵌套在页面中的一段信息,一般设置作者的签名等,通过getServletInfo()取出
page3.jsp
<%@ page
language="java"
import="java.util.*"
pageEncoding="UTF-8"
session="true"
isELIgnored="false"
contentType="text/html; charset=utf-8"
info="自定义"
buffer="8kb"
autoFlush="false"
isThreadSafe="true"
errorPage="error.jsp"
isErrorPage="false"
%>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<title>page指令元素</title>
</head>
<body>
<%--
这里造一个NullPointerException错误
--%>
<%
String str = null;
System.out.println(str.length());
%>
</body>
</html>
error.jsp
<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<title>My JSP 'error.jsp' starting page</title>
</head>
<body>
这里是错误友好化跳转页面
</body>
</html>
当开启page3.jsp时,会因为页面的NullPointerException跳转到error.jsp页面。
2.3.3 taglib指令
引入指定的标签库。其中uri表示指定该标签库的存放位置;prefix表示指定该标签库的引用前缀。比如:<%@ taglib prefix=“c” uri=“http://java.sun.com/jsp/jstl/core”%>,使用JSTL标签库,后面会学到。
2.4 JSP九个内置对象(了解,至少知道对象名)
-
request对象(范围)
客户端的请求信息被封装在request对象中,通过它才能了解到客户的需求,然后做出响应。它是HttpServletRequest类的实例。object getAttribute(String name) 返回指定属性的属性值 Enumeration getAttributeNames() 返回所有可用属性名的枚举 String getCharacterEncoding() 返回字符编码方式 int getContentLength() 返回请求体的长度(以字节数) String getContentType() 得到请求体的MIME类型 ServletInputStream getInputStream() 得到请求体中一行的二进制流 String getParameter(String name) 返回name指定参数的参数值 Enumeration getParameterNames() 返回可用参数名的枚举 Sring[] getParameterValues(String name) 返回包含参数name的所有值的数组 String getProtocol() 返回请求用的协议类型及版本号 String getScheme() 返回请求用的计划名,如:http.https及ftp等 String getServerName() 返回接受请求的服务器主机名 int getServerPort() 返回服务器接受此请求所用的端口号 BufferedReader getReader() 返回解码过了的请求体 String getRemoteAddr() 返回发送此请求的客户端IP地址 String getRemoteHost() 返回发送此请求的客户端主机名 void setAttribute(String key,Object obj) 设置属性的属性值 String getRealPath(String path) 返回一虚拟路径的真实路径 String getContextPath() 拿取/工程名
-
response对象
response对象包含了响应客户请求的有关信息,但在JSP中很少直接用到它。它是HttpServletResponse类的实例。String getCharacterEncoding() 返回响应用的是何种字符编码 ServletOutputStream getOutputStream() 返回响应的一个二进制输出流 PrintWriter getWriter() 返回可以向客户端输出字符的一个对象 void setContentLength(int len) 设置响应头长度 void setContentType(String type) 设置响应的MIME类型 sendRedirect(java.lang.String location) 重新定向客户端的请求
-
session对象(范围)
session对象指的是客户端与服务器的一次会话,从客户连到服务器的一个WebApplication开始,直到客户端与服务器断开连接为止。它是HttpSession类的实例.long getCreationTime() 返回SESSION创建时间 public String getId() 返回SESSION创建时JSP引擎为它设的惟一ID号 long getLastAccessedTime() 返回此SESSION里客户端最近一次请求时间 int getMaxInactiveInterval() 返回两次请求间隔多长时间此SESSION被取消(ms) String[] getValueNames() 返回一个包含此SESSION中所有可用属性的数组 void invalidate() 取消SESSION,使SESSION不可用 boolean isNew() 返回服务器创建的一个SESSION,客户端是否已经加入 oid removeValue(String name) 删除SESSION中指定的属性 void setMaxInactiveInterval() 设置两次请求间隔多长时间此SESSION被取消(ms)
-
out对象
out对象是JspWriter类的实例,是向客户端输出内容常用的对象void clear() 清除缓冲区的内容 void clearBuffer() 清除缓冲区的当前内容 void flush() 清空流 int getBufferSize() 返回缓冲区以字节数的大小,如不设缓冲区则为0 int getRemaining() 返回缓冲区还剩余多少可用 boolean isAutoFlush() 返回缓冲区满时,是自动清空还是抛出异常 void close() 关闭输出流
-
page对象
page对象就是指向当前JSP页面本身,有点象类中的this指针,它是java.lang.Object类的实例class getClass 返回此Object的类 int hashCode() 返回此Object的hash码 boolean equals(Object obj) 判断此Object是否与指定的Object对象相等 void copy(Object obj) 把此Object拷贝到指定的Object对象中 Object clone() 克隆此Object对象 String toString() 把此Object对象转换成String类的对象 void notify() 唤醒一个等待的线程 void notifyAll() 唤醒所有等待的线程 void wait(int timeout) 使一个线程处于等待直到timeout结束或被唤醒 void wait() 使一个线程处于等待直到被唤醒 void enterMonitor() 对Object加锁 void exitMonitor() 对Object开锁
-
application对象(范围)
application对象实现了用户间数据的共享,可存放全局变量。它开始于服务器的启动,直到服务器的关闭,在此期间,此对象将一直存在;这样在用户 的前后连接或不同用户之间的连接中,可以对此对象的同一属性进行操作;在任何地方对此对象属性的操作,都将影响到其他用户对此的访问。服务器的启动和关闭 决定了application对象的生命。它是ServletContext类的实例。Object getAttribute(String name) 返回给定名的属性值 Enumeration getAttributeNames() 返回所有可用属性名的枚举 void setAttribute(String name,Object obj) 设定属性的属性值 void removeAttribute(String name) 删除一属性及其属性值 String getServerInfo() 返回JSP(SERVLET)引擎名及版本号 String getRealPath(String path) 返回一虚拟路径的真实路径 ServletContext getContext(String uripath) 返回指定WebApplication的application对象 int getMajorVersion() 返回服务器支持的Servlet API的最大版本号 int getMinorVersion() 返回服务器支持的Servlet API的最大版本号 String getMimeType(String file) 返回指定文件的MIME类型 URL getResource(String path) 返回指定资源(文件及目录)的URL路径 InputStream getResourceAsStream(String path) 返回指定资源的输入流 RequestDispatcher getRequestDispatcher(String uripath) 返回指定资源的RequestDispatcher对象 Servlet getServlet(String name) 返回指定名的Servlet Enumeration getServlets() 返回所有Servlet的枚举 Enumeration getServletNames() 返回所有Servlet名的枚举 void log(String msg) 把指定消息写入Servlet的日志文件 void log(Exception exception,String msg) 把指定异常的栈轨迹及错误消息写入Servlet的日志文件 void log(String msg,Throwable throwable) 把栈轨迹及给出的Throwable异常的说明信息 写入Servlet的日志文件
-
exception对象
exception对象是一个异常对象,当一个页面在运行过程中发生了异常,就产生这个对象。如果一个JSP页面要应用此对象,就必须把isErrorPage设为true,否则无法编译。他实际上是java.lang.Throwable的对象String getMessage() 返回描述异常的消息 String toString() 返回关于异常的简短描述消息 void printStackTrace() 显示异常及其栈轨迹 Throwable FillInStackTrace() 重写异常的执行栈轨迹
-
pageContext对象(范围)
pageContext对象提供了对JSP页面内所有的对象及名字空间的访问,也就是说他可以访问到本页所在的SESSION,也可以取本页面所在的application的某一属性值,他相当于页面中所有功能的集大成者,它的本类名也叫pageContext。JspWriter getOut() 返回当前客户端响应被使用的JspWriter流(out) HttpSession getSession() 返回当前页中的HttpSession对象(session) Object getPage() 返回当前页的Object对象(page) ServletRequest getRequest() 返回当前页的ServletRequest对象(request) ServletResponse getResponse() 返回当前页的ServletResponse对象(response) Exception getException() 返回当前页的Exception对象(exception) ServletConfig getServletConfig() 返回当前页的ServletConfig对象(config) ServletContext getServletContext() 返回当前页的ServletContext对象(application) void setAttribute(String name,Object attribute) 设置属性及属性值 void setAttribute(String name,Object obj,int scope) 在指定范围内设置属性及属性值 public Object getAttribute(String name) 取属性的值 Object getAttribute(String name,int scope) 在指定范围内取属性的值 public Object findAttribute(String name) 寻找一属性,返回起属性值或NULL void removeAttribute(String name) 删除某属性 void removeAttribute(String name,int scope) 在指定范围删除某属性 int getAttributeScope(String name) 返回某属性的作用范围 Enumeration getAttributeNamesInScope(int scope) 返回指定范围内可用的属性名枚举 void release() 释放pageContext所占用的资源 void forward(String relativeUrlPath) 使当前页面重导到另一页面 void include(String relativeUrlPath) 在当前位置包含另一文件
-
config对象
config对象是在一个Servlet初始化时,JSP引擎向它传递信息用的,此信息包括Servlet初始化时所要用到的参数(通过属性名和属性值构成)以及服务器的有关信息(通过传递一个ServletContext对象)