今日内容
1.会话技术
* Cookie
* Session
2.JSP:入门学习
一、会话技术
1.会话:一次会话保函多次请求和响应。
* 一次会话:浏览器第一次给服务器资源发送请求,会话建立,直到有一方断开为止。
2.功能:在一次会话的范围内的多次请求间,共享数据
HTTP协议是无状态的,每一对请求和响应和其他请求和响应都是相互独立的,它们之间不能
进行数据的交流。
3.方式:
1.客户端会话技术:Cookie
* 把数据存到客户端浏览器。
2.服务器端会话技术:Session
* 把数据存到服务器端。
1.1 Cookie : 小饼干
1.概念:客户端会话技术,将数据保存到客户端。
2.快速入门:
* 使用步骤:
1.创建Cookie对象,绑定数据
* new Cookie(String name, String value)
2.服务器发送Cookie对象给浏览器,浏览器获取Cookie
* HtttpServletRequest接口中的方法:addCookie(Cookie cookie)
* 浏览器拿到带着Cookie的响应后,下一次的请求会自动带着Cookie。
3.服务器获取Cookie,拿到数据
* 服务器收到带Cookie的请求,从HttpServletRequest中获取其中的Cookie。
* Cookie[] getCookies()
* 整个过程是针对一个浏览器。
3.实现原理:
无论是发送Cookie对象也好还是获取Cookie对象也好,最终它们的体现形式都是以HTTP
协议在进行数据的交互。那么一定是底层通过HTTP协议的请求和响应来完成的。
首先浏览器发送了第一次请求,请求CookieDemo1的资源。然后服务器会做出响应,响应
中含有Cookie对象且Cookie对象中绑定这msg=hello这样一对信息。
response对象会生成一个响应头set-cookie:msg=hello。
浏览器收到一个set-cookie响应头,会自动的将该响应头携带的数据msg=hello保存到
客户端浏览器本地。并且下一次在此发送请求时会将该数据带着。
第二次请求时该数据会被放到请求头里面:cookie:msg=hello。服务器可以用封装好的
API来获取该数据。
4. Cookie的细节
1.一次可否发送多个Cookie?
* 可以创建多个Cookie对象,使用多个resp.addCookie()方法发送即可
2.Cookie在浏览器中保存多长时间?
1.默认情况下,Cookie是存在浏览器内存中,当浏览器关闭后,Cookie数据被销毁。
2.设置Cookie的生命周期,使之持久化存储:Cookie对象中的方法
* setMaxAge(int seconds)
1.正数:将Cookie数据写到硬盘的文件中,持久化存储。Cookie的存活时间。
如果传参数30,意味着30s后Cookie将自动删除。
2.负数:默认值,存在浏览器内存中,当浏览器关闭后,Cookie数据被销毁。
3.0:表示删除Cookie信息。
3.Cookie是存字符串的,new Cookie(String name, String value),那么能否存中文呢?
* 在tomcat8之前 cookie不能直接存储中文数据
* 需要将中文数据转码--一般采用URL编码。
* tomcat8之后,可以直接存储中文数据。
* 但是特殊字符还是不支持:比如[space]空格(ASCII--32),建议使用URL编码存储,
URL解码解析。
4.Cookie在同一个服务器下,不同的web项目下能否共享?
1. 假设在一个tomcat服务器中,部署了多个web项目,那么在这些web中cookie能否共享?
* 默认情况下不能共享。
* setPath(String path):设置cookie的获取功能。
默认情况下,设置的是当前项目下的虚拟目录。
```
Cookie c1 = new Cookie("msg", "你好");
c1.setPath("/day0507_cookie")
resp.addCookie(c1);
```
意味着只有在day0507_cookie项目下的资源才能够获取cookie。
* 如果要共享:c1.setPath("/"):
意味着在当前的服务器的根路径下面的所有项目都可以访问这个cookie。
2.不同的tomcat服务器间cookie能否共享?
* setDomain(String path):如果设置一级域名相同,那么多个服务器之间cookie
可以共享。
* 如:setDomain(".baidu.com"),那么tieba.baidu.com和news.baidu.com中的cookie
可以共享。
5.Cookie的特点和作用
1.cookie存储在客户端浏览器(没有那么安全)
2.浏览器对于单个Cookie的大小(4kb)有限制,以及对同一个域名下的总cookie数量(20)
也有限制。
* 作用:
1.cookie一般用于存储少量的不太敏感的数据。
2.在不登录的情况下,完成服务器对客户端的身份识别。
把你对百度首页进行的设置以cookie的形式存到浏览器中,那么下一次你再访问
百度首页(因为是带着这个cookie访问),百度服务器就可以拿到这个cookie信息,
来完成你上一次对它的设置。
6.案例:记住上一次访问时间
1.案例需求:
1. 访问一个Servlet,如果是第一次访问,则提示:您好,欢迎您首次访问。
2. 如果不是第一次访问,则提示:欢迎回来,您上次访问时间为:显示时间字符串
2.分析:
1.可以采用cookie完成
2.在服务器中的servlet判断是否有一个名为lastTime的cookie
1.有:不是第一次访问
* 响应数据:欢迎回来,您上次访问时间为:2020年xx月xx日xx:xx:xx
* 写会cookie:lastTime-2020年xx月xx日xx:xx:xx
2.没有:是第一次访问
* 响应数据:您好,欢迎您首次访问。
* 写会cookie:lastTime-2020年xx月xx日xx:xx:xx
* 详见CookieTest
二、JSP
1.概念:
* Java Server Pages: java服务器端页面
* 可以理解为:一个特殊的页面,其中既可以直接定义html标签,又可以定义java代码。
* 用于简化书写的。
展示一个页面一般会有动态的资源和静态的资源,动态的资源时java代码生成的,
静态资源时html/css/js等标签元素显示的。但是在一个Servlet资源中,该如何展示显示
这些资源?我们只能用java代码,resp.getWrite().wirte()往页面上去响应这些动态的数
据和静态的标签。效果如下:
```
resp.getWrite().wirte("
<html>
<head>
<title>$Title$</title>
</head>
<body>
<h1>hi~ jsp</h1>
</body>
</html>
")
```
显然这里如果页面复杂的话,要写一大堆,非常的麻烦。所以如果有一个页面静态资
源可以在里面直接写标签,动态资源可以直接写java代码。两种语言在该页面都可以直接
定义。那么这种页面就有了应用的范围。
可以大大减少程序员开发的复杂度。所以JSP就是用于简化书写的。
2.原理
* JSP本质上就是一个Servlet
* 当服务器中有一个JSP的页面index.jsp,我们通过浏览器来请求这个资源页面,请求的路径:
localhost/day0507_cookie_session/index.jsp。
* 服务器收到这个请求会做出这些事情:
1.首先服务器解析请求消息:找是否有index.jsp资源。(没有:404)
2.找到后,会将index.jsp转成index.java文件
3.编译index.java文件,生成index.class文件
4.由index.class来提供访问。
* 真正上是由index.class为客户端做出响应。
* 思考:这个字节码文件index.class能够被浏览器访问到,那么这个字节码文件是什么?
一定是一个Servlet,只有Servlet才能被外界访问到。一个java类要想被外界访问到,那
么必须是一个Servlet。
所以:JSP本质上就是一个Servlet
* 验证JSP本质上就是一个Servlet:
打开项目的配置目录:
C:\Users\13099\.IntelliJIdea2019.3\system\tomcat\Tomcat_8_5_31_day0507_cookie&session_2
在最开始该目录下没有work文件夹。
访问index.jsp页面:
发现在该目录下自动生成一个work文件夹,这个目录和在tomcat目录下的work目录
一样。放我们运行时产生的文件。
打开work\Catalina\localhost\day0507_cookie_session\org\apache\jsp:
里面有两个文件:
index_jsp.class
index_jsp.java
就是index.jsp对应生成的java/class文件。
那么这个index_jsp.java是不是一个Servlet呢?打开index_jsp.java:
public final class index_jsp extends org.apache.jasper.runtime.HttpJspBase
这个类继承了:org.apache.jasper.runtime.HttpJspBase
查看tomcat源码:
public abstract class HttpJspBase extends HttpServlet
发现HttpJspBase extends HttpServlet
* 所以可以验证JSP本质上就是一个Servlet
3. JSP的脚本:JSP定义java代码的方式
```
<%
System.out.println("hello jsp");
%>
```
java代码必须写在<% %>里面,否则不能生效,这个区域就称为JSP脚本。
1.<% 代码 %> :定义的java代码在index_jsp.java中的jspService()方法中。jspService()
方法中可以定义什么,该脚本中就可以定义什么。
2.<%! 代码 %>:定义的java代码在index_jsp.java类中的成员位置。(成员变量/代码块)
3.<%= 代码 %>:定义的java代码会输出到页面上,输出语句中可以定义什么,该脚本就可以
定义什么。
```
<%
System.out.println("hello jsp");
int i = 5;
%>
<%!
int i = 3;
%>
<%=
i
%>
```
对应到:index_jsp.java类中的位置
```
public final class index_jsp extends org.apache.jasper.runtime.HttpJspBase{
int i = 3;
public void _jspService{
System.out.println("hello jsp");
int i = 5;
}
}
```
4. JSP的内置对象:
* 在Jsp页面中不需要获取和创建,可以直接使用的对象
```
<%
System.out.println("hello jsp");
int i = 5;
String contextPath = request.getContextPath();
out.print(contextPath);
%>
```
如:request和out对象我没有获取就可以直接拿来用,这就被称为内置对象。
* 为什么能这样使用呢?
因为这些代码都会放到index_jsp.java类的public void _jspService{}中执行。
只要_jspService{}方法中对这些对象有申明那么_jspService{}方法就可以使用:
public void _jspService(final javax.servlet.http.HttpServletRequest request,
final javax.servlet.http.HttpServletResponse response){
javax.servlet.jsp.JspWriter out = null;
}
显然request/response/out对象都在该方法中声明了,所以是JSP的内置对象可以直接使用。
* JSP一共有9个内置对象。
* 今天学习三个:
request
response
out:可以将数据输出到页面上(字符输出流对象)。和response.getWrite()类似
* response.getWrite()和out.write()的区别:
out对象定义在哪个位置就会在那个位置输出。
response.getWrite().write()先于out.write()输出。
因为两个流都有缓冲区,将来真正给客户端浏览器作相应之前,tomcat会先找response
的缓冲区,再去找out的缓冲。所以response缓冲区的数据永远在out的缓冲区之前输出。
建议out输出,因为index_jsp.java文件中都是out输出,如果用response可能会打乱布局。
三、Session: 主菜
1.概念:服务器端会话技术,在一次会话的多次请求响应间来共享数据的。将数据保存到服务器端。HttpSession
2.快速入门:request,servetContext都可以共享数据,都是域对象。
HttpSession对象中有这几个个方法
Object getAttribute(String name)
void setAttribute(String name, Object value)
void removeAttribute(String name)
* 步骤:
1.获取HttpSession对象:
HttpSession session = request.getSession();
2.使用HttpSession对象:
Object getAttribute(String name)
void setAttribute(String name, Object value)
void removeAttribute(String name)
* 结论:
HttpSession对象可以在一会的多次请求间共享数据,也只能在一次会话的多次请求间
共享数据。
3.Session的原理
```
public class SessionDemo1 extends HttpServlet {
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//1.获取session对象
HttpSession session = request.getSession();
//2.存储数据
session.setAttribute("msg", "hello session");
}
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
this.doPost(request,response);
}
}
public class SessionDemo2 extends HttpServlet {
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//1.获取session对象
HttpSession session = request.getSession();
//2.获取数据
Object msg = session.getAttribute("msg");
System.out.println(msg);
}
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
this.doPost(request,response);
}
}
```
在SessionDemo1中种Session存储数据SessionDemo2中获取Session的数据,而且在两个类中
都有获取Session的操作:HttpSession session = request.getSession()。
这两次获取的Session的是同一个,那么服务器是怎么保证在一次会话范围呢,多次获取的
Session对象是同一个呢?
具体原理: Session是依赖Cookie的,而Cookie是依赖请求头和响应头的。
1.浏览器发送http://localhost/day0507_cookie_session/sessionDemo1,请求
SessionDemo1资源。
2.在SessionDemo1第一次获取Session时是没有Cookie。服务器会在内存中创建一个新的
Session对象,并且有一个唯一的id=xxxxxx。
3.服务器作响应:发送一个响应头set-cookie:JSESSION=xxxxxx
4.浏览器收到响应:会将cookie信息:set-cookie:JSESSION=xxxxxx存到浏览器本地。
5.浏览器在下次请求服务器时:请求中会带着一个请求头:cookie:JSESSION=xxxxxx。
然后服务器获取cookie信息去查找内存中是否有这样一个session对象,发现存在后,第二次再获取的session对象就是同一个session。
* 结论:Session的实现时依赖于Cookie的。
4.细节:
1.当客户端关闭后,服务器不关闭,两次获取session是否为同一个?
不是同一个,关闭后意味着会话结束,cookie被销毁。
在打开浏览器请求服务器时不带有请求头cookie:JSESSION=xxxxxx。
如果需要相同:则自己手动创建一个cookie在设置最大存活时间,让cookie持久化存储。
```
Cookie c = new Cookie("JSESSIONID", session.getId());
c.setMaxAge(60*60);
response.addCookie(c);
```
2.客户端不关闭,服务器关闭后,两次获取的session是同一个吗?
* 不是同一个
org.apache.catalina.session.StandardSessionFacade@28e0c37
org.apache.catalina.session.StandardSessionFacade@1572dcf1
服务器关闭后,发现两次获取的session是不同的。
* 尽管两次的session对象的地址值是不一样的,但是却可以做到里面的确保数据不丢失。
* session的钝化:序列化
* 在服务器正常关闭之前,将session对象系列化到硬盘上
* session的活化:反序列化
* 在服务器启动后,将session文件转化为内存中的session对象即可。
* 2.1 IDEA不会帮我们做上面两步,但是tomcat帮我们做了。
所以我们将本地的java项目:day0507_cookie_session打成war包放到tomcat的
安装目录webapps中。
然后在bin目录中运行startup.bat启动tomcat后,tomcat就会自动部署war包
中的项目。
浏览器访问http://localhost:8080/day0507_cookie_session/sessionDemo1和
http://localhost:8080/day0507_cookie_session/sessionDemo2。这里没有设置端
口所以是8080。
session被序列化后的文件也放到了work文件夹中。打开work/day0507_cookie_
session文件夹此时里面什么都没有。
正常关闭tomcat后,发现work/day0507_cookie_文件夹中生成一个SESSIONS.ser
文件。这里面放的就是session对象。
------->这就是session的钝化:序列化
再打开tomcat:这个SESSIONS.ser文件将会被服务器自动读取,然后删掉该文件。
------->session的活化:反序列化
结论:所以tomcat通过session的钝化和活化帮我们保存了session对象中的数据。即使
是服务器关闭前后的session。
* 2.2 IDEA当前服务器的配置文件在:
C:\Users\13099\.IntelliJIdea2019.3\system\tomcat\Tomcat_8_5_31_day0507_cookie
&session
IDEA在关闭服务时也会进行session的钝化,将SESSIONS.ser放到该目录下的work
目录中。
但是在IDEA再重新启动服务器时,IDEA会将work目录删掉,然后再创建一个新的work
目录,此时新的work目录下已经没有了SESSIONS.ser文件了。
* 结论IDEA不能实现session的活化。但是我们将来不会再IDEA本地部署项目,而是在tomcat服务器里面,放到webapps目录下面。
3。session什么时候被销毁
1. 服务器关闭
2. HttpSession中有一个方法:
invalidate()方法
3. session有一个默认的失效时间:30min
可以在web.xml中修改:
<session-config>
<session-timeout>30</session-timeout>
</session-config>
5. session的特点
1. session用于存储一次会话的多次请求的数据,存在服务器端
一次会话间的数据可以用session共享。会话域
2. session可以存储任意类型,任意大小的数据。cookie只能是字符串,而且大小有限制。
* session和cookie的区别
1. session存储数据在服务器端,cookie在客户端
2. session没有数据大小限制,cookie有
3. session数据较为安全,cookie相对不安全。
四、案例
案例:验证码
1. 案例需求:
1. 访问带有验证码的登录页面login.jsp
2. 用户输入用户名,密码以及验证码。
* 如果用户名和密码输入有误,跳转登录页面,提示:用户名或密码错误
* 如果验证码输入有误,跳转登录页面,提示:验证码错误
* 如果全部输入正确,则跳转到主页success.jsp,显示:用户名,欢迎您
2. 分析:
3. 代码实现