目录
实验预习报告
一、实验目的
二、实验原理
三、实验预习内容
实验报告
一、实验目的
二、实验要求
三、实验内容与步骤
实验预习报告
一、实验目的
1. 了解Web服务器对客户会话跟踪的各种方法;
2. 重点掌握使用HttpSession对象跟踪会话的方法;
3. 掌握使用Cookie技术跟踪会话的方法;
4. 了解URL重写和隐藏表单域的方法。
二、实验原理
HTTP协议是无状态的协议。在很多情况下,Web服务器必须能够跟踪客户的状态。比如,对于一个购物网站,在一个时刻可能有多个客户购物,Web服务器必须能够区分不同的客户。一般情况下,Web服务器为每个客户配置了虚拟的购物车(ShoppingCart)。当某个客户请求将一个商品放入购物车时,Web服务器必须根据发出请求的客户的身份,找到该客户的购物车,然后把商品放入其中。
Web服务器跟踪客户的状态通常有4种方法:
(1)使用HttpSession对象管理会话;(2)使用持久的Cookie对象;(3)使用URL重写机制;(4)使用隐藏的表单域。
三、实验预习内容
1. 什么是会话,一个会话的生产周期从什么时候,到什么时候结束?
会话:是客户与服务器之间的不中断的请求-响应序列。
开始:当一个未知的客户向web应用程序发送第一个请求时就开始了一个会话。
结束:当客户结束会话或服务器在一定时限内没有接到客户任何请求时,会话结束。
2. 服务器是如何识别管理属于某一个特定客户的会话的?
一个客户对应一个会话,服务器能够识别出请求来自于哪个客户的会话。
3. 什么是Cookie,它的作用是什么?Cookie会给客户端带来安全隐患吗?
Cookie:是客户访问Web服务器时,服务器在客户端用户硬盘上存放的信息,好像是服务器送给客户的“点心”。Cookie实际上是一小段的文本信息。
作用:可以在客户端上保存用户数据,起到简单的缓存和用户身份识别等作用;保存用户的登陆状态,用户进行登陆,成功登陆后,服务器生成特定的cookie返回给客户端,客户端下次访问该域名下的任何页面,将该cookie的信息发送给服务器,服务器经过检验,来判断用户是否登陆;记录用户的行为。
安全问题:客户可能认为Cookie会带来安全问题,因此禁用Cookie。事实上,Cookie并不会造成严重的安全威胁。Cookie永远不会以任何方式执行,因此也不会带来病毒或攻击你的系统。另外,由于浏览器一般只允许存放300个Cookie,每个站点的Cookie最多存放20个,每个Cookie的大小限制为4 KB,因此Cookie不会塞满你的硬盘,更不会被用作“拒绝服务”攻击手段。
4. 如何使用隐藏表单域传递会话信息,一般用在什么情况下?
在HTML页面中,可以使用下面代码实现隐藏的表单域:
<input type="hidden" name="session" value="a1234">;
当表单提交时,浏览器将指定的名称和值包含在GET或POST的数据中。这个隐藏域可以用来存储有关会话的信息。
实验报告
一、实验目的
1. 了解Web服务器对客户会话跟踪的各种方法;
2. 重点掌握使用HttpSession对象跟踪会话的方法;
3. 掌握使用Cookie技术跟踪会话的方法;
4. 了解URL重写和隐藏表单域的方法。
二、实验要求
1. 实验前进行预习,完成实验预习报告;
2.按照每一项实验内容进行上机实践与编程,将程序源代码和运行结果图附在实验报告中实验内容对应的部分。
3. 实验预习报告和实验报告打印装订在一起。
4. 将每一次实验的源代码按目录组织保存并压缩,按照老师指定的要求进行提交。代码保存方式如:exp04表示实验四的Web项目的名称,其下保存各项实验内容的源文件及相关资源,将整个exp04文件夹进行压缩后命名为班级-姓名-实验04,如计171-张三-实验04。
三、实验内容与步骤
1. 使用HttpSession对象管理会话。在名为exp04的Web项目下,创建一个名为ShowSessionInfo的Servlet,显示当前客户的会话ID、会话创建时间、最近一次访问会话的时间、该客户访问会话次数等信息,运行的结果要求如下图所示。
配置pom.xml依赖:
pom.xml:
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>org.example</groupId>
<artifactId>exp04</artifactId>
<version>1.0-SNAPSHOT</version>
<packaging>war</packaging>
<name>exp04 Maven Webapp</name>
<!-- FIXME change it to the project's website -->
<url>http://www.example.com</url>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<maven.compiler.source>1.7</maven.compiler.source>
<maven.compiler.target>1.7</maven.compiler.target>
</properties>
<dependencies>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<!-- servlet 版本和 tomcat 版本有对应关系,切记 -->
<version>3.1.0</version>
<!-- 这个意思是我们只在开发阶段需要这个依赖,部署到 tomcat 上时就不需要了 -->
<scope>provided</scope>
</dependency>
<!-- https://mvnrepository.com/artifact/com.fasterxml.jackson.core/jackson-databind -->
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.14.1</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.projectlombok/lombok -->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.24</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.31</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.11</version>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<finalName>exp04</finalName>
<pluginManagement><!-- lock down plugins versions to avoid using Maven defaults (may be moved to parent pom) -->
<plugins>
<plugin>
<artifactId>maven-clean-plugin</artifactId>
<version>3.1.0</version>
</plugin>
<!-- see http://maven.apache.org/ref/current/maven-core/default-bindings.html#Plugin_bindings_for_war_packaging -->
<plugin>
<artifactId>maven-resources-plugin</artifactId>
<version>3.0.2</version>
</plugin>
<plugin>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.8.0</version>
</plugin>
<plugin>
<artifactId>maven-surefire-plugin</artifactId>
<version>2.22.1</version>
</plugin>
<plugin>
<artifactId>maven-war-plugin</artifactId>
<version>3.2.2</version>
</plugin>
<plugin>
<artifactId>maven-install-plugin</artifactId>
<version>2.5.2</version>
</plugin>
<plugin>
<artifactId>maven-deploy-plugin</artifactId>
<version>2.8.2</version>
</plugin>
</plugins>
</pluginManagement>
</build>
</project>
ShowSessionInfo:
import java.io.IOException;
import java.io.PrintWriter;
import java.sql.Date;
import javax.servlet.ServletException;
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;
@WebServlet(name = "ShowSessionInfo",value = "/ShowSessionInfo")
public class ShowSessionInfo extends HttpServlet {
@Override
public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
response.setContentType("text/html;charset=gb2312");
HttpSession session = request.getSession(true);
String heading = null;
String info="Information about your session";
Integer accessCount = (Integer) session.getAttribute("accessCount");
if(accessCount==null)
{
accessCount = new Integer(1);
heading = "Welcome,enter this page first time! ";
}
else
{
heading = "Welcome Back! ";
accessCount = accessCount+1;
}
session.setAttribute("accessCount",accessCount);
PrintWriter out = response.getWriter();
out.println("<HTML>");
out.println(" <BODY><center>");
out.println("<h2>"+heading + "</h2>" +"<h3>" +info+"</h3>");
out.println("<table border='0'>");
out.println("<tr bgcolor=\"ffad0\"><td><b>Info Type</b><td><b>Value</b>\n");
out.println("<tr><td>ID:<td>"+session.getId()+"\n");
out.println("<tr><td>Creation Time:<td>");
out.println(""+new Date(session.getCreationTime())+"\n");
out.println("<tr><td>Time of last access:<td>");
out.println(""+new Date(session.getLastAccessedTime())+"\n");
out.println("<tr><td>Access number:<td>"+accessCount+"\n");
out.println("</table>");
out.println(" </center> </BODY>");
out.println("</HTML>");
}
}
2. 使用HttpSession会话对象设计一个GuessNumberServlet.java,实现简单的猜数游戏:
doget()方法显示当前会话的相关信息,产生一个1-100的随机数并保存到session作用域中,显示表单让用户输入所猜数字,表单以post方式提交给该servlet本身进行处理。
dopost()方法中将用户输入的数字和session中保存的随机数进行比较,如果用户猜的结果正确,强制结束会话,通过超链接可以在此请求该Servlet重新开始一轮猜数游戏;如果结果错误,显示错误提示信息和猜数表单,允许用户重新猜数。
GuessNumberServlet:
import java.io.*;
import javax.servlet.*;
import javax.servlet.http.*;
import javax.servlet.annotation.WebServlet;
@WebServlet(name = "GuessNumberServlet",value = "/GuessNumberServlet")
public class GuessNumberServlet extends HttpServlet{
public void doGet(HttpServletRequest request,
HttpServletResponse response)
throws ServletException, IOException {
int magic = (int)(Math.random()*101);
HttpSession session = request.getSession();
// 将随机生成的数存储到会话对象中
session.setAttribute("num",new Integer(magic));
response.setContentType("text/html;charset=utf-8");
PrintWriter out = response.getWriter();
out.println("<html><body>");
out.println("猜数字:有一个0到100之间的数字,猜猜看是多少?");
out.println("<form action='GuessNumberServlet' method='post'>");
out.println("<input type='text' name='guess' />");
out.println("<input type='submit' value='确定'/>");
out.println("</form>");
out.println("</body></html>");
}
public void doPost(HttpServletRequest request,
HttpServletResponse response)
throws ServletException, IOException {
// 得到用户猜的数
int guess = Integer.parseInt(request.getParameter("guess"));
HttpSession session = request.getSession();
// 从会话对象中取出随机生成的数
int magic = (Integer)session.getAttribute("num");
response.setContentType("text/html;charset=utf-8");
PrintWriter out = response.getWriter();
out.println("<html><body>");
if(guess==magic){
session.invalidate(); // 销毁会话对象
out.println("祝贺你,答对了!");
out.println("<a href = 'GuessNumberServlet'>再猜一次.</a>");
}else if(guess>magic){
out.println("太大了! 请重新猜~");
}else{
out.println("太小了! 请重新猜~");
}
out.println("<form action='GuessNumberServlet' method='post'>");
out.println("<input type='text' name='guess' />");
out.println("<input type='submit' value='确定'/>");
out.println("</form>");
out.println("</body></html>");
}
}
3. 编写一个CheckUserServlet,通过Cookie实现自动登录的功能。当用户以get方式请求该Servlet时,判断来自请求的cookie中是否包含用户的登录名和口令,如果有判断是否合法,如果通过验证显示欢迎信息;否则显示登录表单让用户重新填写用户名和口令,表单提交以post方式请求CheckUserServlet进行处理,如果用户登录成功并且勾选了“自动登录”,则提示登录成功,并向客户端发送cookie信息保存用户名和口令,否则提示登录失败,并在浏览器端显示登录表单让用户重新登录。
CheckUserServlet:
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.Locale;
@WebServlet("/CheckUserServlet")
public class CheckUserServlet extends HttpServlet {
String message =null;
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
response.setContentType("text/html;charset=UTF-8");
String value1 = "",value2="";
Cookie cookie =null;
Cookie[] cookies = request.getCookies();
if(cookies!=null){
for(int i=0;i<cookies.length;i++){
cookie = cookies[i];
if(cookie.getName().equals("username")){
value1 = cookie.getValue();
}
if(cookie.getName().equals("password")){
value2 = cookie.getValue();
}
}
if (value1.equals("scx")&&value2.equals("12345")){
message = "欢迎您!"+value1+"再次登录该页面!";
request.getSession().setAttribute("message",message);
response.sendRedirect("welcome.jsp");
}else {
response.sendRedirect("login.jsp");
}
}else {
response.sendRedirect("login.jsp");
}
}
public void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
response.setContentType("text/html;charset=UTF-8");
String username = request.getParameter("username").trim();
String password = request.getParameter("password").trim();
if (!username.equals("scx")||!password.equals("12345")){
message = "用户名或口令不正确,请重试!";
request.getSession().setAttribute("message",message);
response.sendRedirect("login.jsp");
}else {
//如果用户选中了“自动登录”复选框,向浏览器发送连个Cookie
if ((request.getParameter("check")!=null) && (request.getParameter("check").equals("check"))){
Cookie nameCookie = new Cookie("username",username);
Cookie pswdCookie = new Cookie("password",password);
nameCookie.setMaxAge(60*60);
pswdCookie.setMaxAge(60*60);
response.addCookie(nameCookie);
response.addCookie(pswdCookie);
}
message ="你已成功登录!";
request.getSession().setAttribute("message",message);
response.sendRedirect("welcome.jsp");
}
}
}
login.jsp:
<%@ page contentType="text/html;charset=UTF-8" language="java" isELIgnored="false"%>
<html>
<head>
<title>login</title>
</head>
<body>
${sessionScope.message}<br>
<form action="CheckUserServlet" method="post">
请输入用户名和口令:<br>
用户名:<input type="text" name="username"/><br>
口令:<input type="password" name="password"/><br>
<input type="checkbox" name="check" value="check"/>自动登录<br>
<input type="submit" value="提交"/>
<input type="reset" value="重置"/>
</form>
</body>
</html>
welcome.jsp:
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>welcome</title>
</head>
<body>
<h1>欢迎你</h1>
</body>
</html>
4. 编写HomeServlet.java,对通过超链接请求的两个URL进行重写,在浏览器中禁用Cookie后,servlet运行效果要求如下图所示。
HomeServlet:
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;
@WebServlet("/HomeServlet")
public class HomeServlet extends HttpServlet {
public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
response.setContentType("text/html;charset=utf-8");
//HttpSession session=request.getSession();
PrintWriter out = response.getWriter();
String url1 = response.encodeURL("GuessNumberServlet");
String url2 = response.encodeURL("CheckUserServlet");
out.println("<HTML>");
out.println(" <HEAD><TITLE>A Servlet</TITLE></HEAD>");
out.println(" <BODY>");
out.print(" A test page showing two URLs:<br> ");
out.println("<a href=\"" + url1 + "\">View GuessNumber Servlet</a><br>");
out.println("<a href=\""+ url2 + "\">View CheckUser Servlet</a><br>");
out.println(" </BODY>");
out.println("</HTML>");
}
}
四、思考题
1. 如何理解会话失效与超时?如何通过程序设置最大失效时间?如何通过Web应用程序部署描述文件设置最大超时时间?二者有什么区别?
答:当用户在一个指定的期限内处于不活动状态时,就将用户的会话终止,会话失效,超过设定时间终止是会话超时。public void setMaxInactiveInterval(int Interval)设置最大失效时间。在部署文件中下中设置最大超时时间。一个是通过编程方式设置,一个是在部署时就已设置。
2. 能否通过客户机的IP地址实现会话跟踪?
答:容器不能使用客户的IP地址唯一标识客户。因为是通过局域网访问Internet尽管在局域网中每个客户有一个IP地址,但对于服务器来说,客户的实际IP地址是路由器的IP地址,所以该局域网的所有客户的IP地址都相同。
3. 假如开发的Web应用程序是假设客户支持Cookie的,但应用程序部署后,你发现大多数客户禁用了Cookie,这对应用程序有何影响?如何修改它?
答:来自网站的所有Cookie都被阻止,并且计算机上现有的Cookie不能被网站读取。可在Internet选项中设置。