Java EE入门教程系列第四章Servlet(三)——会话跟踪

4.3 会话跟踪

4.3.1 Cookie

HTTP协议是一个无状态的协议,无状态也就是说,如果此时的状态是连接的,下一刻状态就可能是断开的,状态是不稳定的。

Cookie是在HTTP协议下,服务器或脚本可以维护客户工作站信息的一种方式。Cookie是由web服务器保存在用户浏览器(客户端)上的小文本文件,可以包含有关用户的信息。无论何时用户链接到服务器,web站点都可以访问Cookie信息。

目前Cookie有些是临时的,有些是持续的。临时的只在浏览器上保存一段时间,一旦超过规定时间就会被系统清除。持续的Cookie保存在用户的Cookie文件中,下一次用户返回时,仍然可以对它进行调用。有些用户会担心这样会造成信息泄露,其实网站以外的用户无法跨过网站来获得Cookie信息,Cookie的存在还是大有作用的。

Cookie类的方法列表:

举例:Cookie.java判断本地是否存在一个指定名称的cookie,没有则创建这个cookie并显示出来

package cy.servlet;

import java.io.IOException;

import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
/**
 * Servlet implementation class Cookie
 */
@WebServlet("/Cookie")
public class Cookie extends HttpServlet {
	private static final long serialVersionUID = 1L;
       
    /**
     * @see HttpServlet#HttpServlet()
     */
    public Cookie() {
        super();
        // TODO Auto-generated constructor stub
    }

	/**
	 * @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse response)
	 */
	protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		// TODO Auto-generated method stub
		response.setContentType("text/html;charset=UTF-8");
		javax.servlet.http.Cookie cookie=null;
	   javax.servlet.http.Cookie[] cookies=request.getCookies();
		boolean newCookie=false;
		if(cookies!=null) {
			for(int i=0;i<cookies.length;i++) {
				if(cookies[i].getName().equals("cyCookie")) {
					cookie=cookies[i];
				}
			}
		}
		if(cookie==null) {
			newCookie=true;
			int maxAge=5;
			cookie=new  javax.servlet.http.Cookie("cyCookie","first");
			//设置Cookie路径
			cookie.setPath(request.getContextPath());
			cookie.setMaxAge(maxAge);
			response.addCookie(cookie);
		}
		response.setContentType("text/html;charset=UTF-8");
		java.io.PrintWriter out=response.getWriter();
		out.println("<html>");
		out.println("<head>");
		out.println("<title></title>");
		out.println("</head>");
		out.println("<body>");
		out.println("Cookie的值为:"+cookie.getValue()+"<br>");
		if(newCookie) {
			out.println("<br>这里的信息只有第一次运行可以看到!<br>");
			out.println("Cookie的生命周期为:"+cookie.getMaxAge()+"<br>");
			out.println("Cookie的名字为:"+cookie.getName()+"<br>");
			out.println("Cookie的路径为:"+cookie.getPath()+"<br>");
		}
		out.println("</body>");
		out.println("</html>");
	}

	/**
	 * @see HttpServlet#doPost(HttpServletRequest request, HttpServletResponse response)
	 */
	protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		// TODO Auto-generated method stub
		doGet(request, response);
	}

}

其中setMaxAge()方法是设置Cookie的有效期,这里的单位是秒。在上面的例子中,浏览器运行结果为:

如果在5秒内刷新页面就会发现界面内容少了一些:

5秒后再刷新,页面又变成初次运行的结果。

4.3.2 URL参数传递与重写

我们可以随便在浏览器上搜索某个事物,会发现很多情况下浏览器地址栏除了显示正常的网页地址外,总会在后面跟一个?或!。这里就使用了URL参数传递的技术。

这个技术和前面介绍的cookie都是一种保持状态传递信息的技术。由于cookie技术是把上网信息保存在客户端的硬盘中,有一定安全隐患,URL传递参数就成为一种很好地替代。

不同开发平台,写法有所差异,在Java EE平台的语法形式为:

http://www.npumd.edu.cn/file.htm?id=12345&pw=6669

?代表要在URL后面加入的参数,如果是多个参数,则用&连接。这些参数传递到相关文件后,可通过request.getParameter()方法获取。

举例:传参文件 SetParam.java

package cy.servlet;

import java.io.IOException;
import java.io.PrintWriter;

import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

/**
 * Servlet implementation class SetParam
 */
@WebServlet("/SetParam")
public class SetParam extends HttpServlet {
	private static final long serialVersionUID = 1L;
       
    /**
     * @see HttpServlet#HttpServlet()
     */
    public SetParam() {
        super();
        // TODO Auto-generated constructor stub
    }

	/**
	 * @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse response)
	 */
	protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		// TODO Auto-generated method stub
		response.setContentType("text/html;charset=UTF-8");
		PrintWriter out=response.getWriter();
		try {
			String uname="Hedy";
			String uage="19";
			String encodedUrl=response.encodeURL(((HttpServletRequest) request).getContextPath()+
					"/PlayerInfo?name="+uname+"&age="+uage);
			out.println("<html");
			out.println("<head>");
			out.println("<title></title>");
			out.println("</head>");
			out.println("<body>");
			out.println("查看信息请点击<a href=\""+encodedUrl+"\">这里</a>");
			out.println("</body>");
			out.println("</html");
		}finally {
			out.close();
		}
	}

	/**
	 * @see HttpServlet#doPost(HttpServletRequest request, HttpServletResponse response)
	 */
	protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		// TODO Auto-generated method stub
		doGet(request, response);
	}

}

接收文件PlayerInfo.java

package cy.servlet;

import java.io.IOException;
import java.io.PrintWriter;

import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

/**
 * Servlet implementation class PlayerInfo
 */
@WebServlet("/PlayerInfo")
public class PlayerInfo extends HttpServlet {
	private static final long serialVersionUID = 1L;
       
    /**
     * @see HttpServlet#HttpServlet()
     */
    public PlayerInfo() {
        super();
        // TODO Auto-generated constructor stub
    }

	/**
	 * @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse response)
	 */
	protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		// TODO Auto-generated method stub
		response.setContentType("text/html;charset=UTF-8");
		request.setCharacterEncoding("UTF-8");
		PrintWriter out=response.getWriter();
		try {
		
			out.println("<html");
			out.println("<head>");
			out.println("<title></title>");
			out.println("</head>");
			out.println("<body>");
			out.println("名字:"+request.getParameter("name"));
			out.println("年龄:"+request.getParameter("age"));
			out.println("</body>");
			out.println("</html");
		}finally {
			out.close();
		}
	}

	/**
	 * @see HttpServlet#doPost(HttpServletRequest request, HttpServletResponse response)
	 */
	protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		// TODO Auto-generated method stub
		doGet(request, response);
	}

}

截图:

虽然我们在实际上网过程中看到了?,但是后面的内容似乎都看不太懂,这是因为Java EE给出了一种名为URL重写的技术。这个技术不是传递参数,而是获得一个进入的URL请求,然后把它重新写成网站可以处理的另一个URL。例如将/PlayerInfo.java?id=100111重写为/PlayerInfo.html。

URL重写的好处:
1)方便用户访问,同时屏蔽了一些重要信息

2)可以把动态的页面变成静态的,有利于搜索引擎的识别抓取

3)提高重用性。例如,系统更改了后端控制程序访问的方法,而通过URL重写定义的前端地址可以不用改,这样就提高了网站的移植性。

4.3.3 Session

Session是一个高级接口,是建立在上面两个技术之上的。它针对会话跟踪的底层实现机制,对用户是透明的。Session可以连续跨越多个用户的连接,通过HttpServletRequest的getSession()方法可以获取HttpSession对象:

HttpSession session=request.getSession();

使用Session来存储会话信息的步骤如下:

1)获取一个HttpSession的对象资源

2)判断是否存在指定的Session属性,如果存在则获取这个属性的值,不存在则创建这个属性

3)使用这个session对象的属性

4)如果不再需要这个对象,手动停止他或者什么都不做,等待系统自动回收

举例:Session.java 

package cy.servlet;

import java.io.IOException;
import java.io.PrintWriter;
import java.util.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;

/**
 * Servlet implementation class SetParam
 */
@WebServlet("/SetParam")
public class Session extends HttpServlet {
	private static final long serialVersionUID = 1L;
       
    /**
     * @see HttpServlet#HttpServlet()
     */
    public Session() {
        super();
        // TODO Auto-generated constructor stub
    }

	/**
	 * @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse response)
	 */
	protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		// TODO Auto-generated method stub
		response.setContentType("text/html;charset=UTF-8");
		PrintWriter out=response.getWriter();
		HttpSession session=request.getSession();
		Date crtTime=new Date(session.getCreationTime());//创建对象的时间
		Date lastAccessTime=new Date(session.getLastAccessedTime());//上次访问session的时间
		Integer visitCount=new Integer(0);//统计访问次数
		String visitCountKey=new String("visitCount");
		String userIDKey=new String("userID");
		String userID=new String("ABCD");
		if(session.isNew()) {
			//为空会自动创建一个session对象
			session.setAttribute(userIDKey, userID);
			
		}
		else {
			visitCount=(Integer)session.getAttribute(visitCountKey);
			if(visitCount!=null) {
				visitCount+=1;
			}
			if(session.getAttribute(userIDKey)!=null) {
				userID=(String)session.getAttribute(userIDKey);
			}
		}
		session.setAttribute(visitCountKey, visitCount);
		response.setContentType("text/html;charset=UTF-8");
		try {
			
			out.println("<html");
			out.println("<head>");
			out.println("<title></title>");
			out.println("</head>");
			out.println("<body>");
			out.println("<table border='1' align='center'>");
			out.println("<tr><th>session</th><th>value</th></tr>");
			out.println("<tr><td>id</td><td>"+session.getId()+"</td></tr>");
			out.println("<tr><td>creation time</td><td>"+crtTime+"</td></tr>");
			out.println("<tr><td>last access time</td><td>"+lastAccessTime+"</td></tr>");
			out.println("<tr><td>User ID</td><td>"+userID+"</td></tr>");
			out.println("<tr><td>number of visit</td><td>"+visitCount+"</td></tr>");
			out.println("</body>");
			out.println("</html");
		}finally {
			out.close();
		}
	}

	/**
	 * @see HttpServlet#doPost(HttpServletRequest request, HttpServletResponse response)
	 */
	protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		// TODO Auto-generated method stub
		doGet(request, response);
	}

}

第一次访问时访问次数为0,再访问几次结果为:

其他文件获取session的方式都是通过getAttribute()方法,但是在此之前一定要先申请获取session对象资源HttpSession session=request.getSession()才可以。

4.3.4 Servlet的上下文

运行在Servlet服务器中的web应用都会有一个全局的、储存信息的对象,这个对象就是Servlet的上下文,可以使同一个web应用中不同资源之间进行信息共享。Javax.Servlet.ServletContext接口就是对上下文对象进行相关操作的,通过它的getServletContext()方法,可以获得当前运行的Servlet的上下文对象。

Servlet可以通过名称将对象属性绑定到上下文,任何绑定到上下文的属性都可以被同一个web应用的其他Servlet使用。获取上下文实例及添加信息的主要方法为:

1)getServletContext():通过ServletConfig接口获得上下文实例,这里的上下文实例对象不是创建一个新的对象,而是去获取每个web应用都唯一对应的上下文对象

2)getInitParameter()、getInitParameterNames():访问web应用的初始化参数和属性

3)setAttribute()、getAttribute():添加并获取上下文对象的信息

4)getAttributeNames()、removeAttribute():获取上下文信息的名称,并移除上下文中保存的信息

举例:GetMessage.java获取上下文信息并在里面保存一个信息

package cy.servlet;

import java.io.IOException;
import java.io.PrintWriter;

import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

/**
 * Servlet implementation class PlayerInfo
 */
@WebServlet("/PlayerInfo")
public class GetMessage extends HttpServlet {
	private static final long serialVersionUID = 1L;
       
    /**
     * @see HttpServlet#HttpServlet()
     */
    public GetMessage() {
        super();
        // TODO Auto-generated constructor stub
    }

	/**
	 * @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse response)
	 */
	protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		// TODO Auto-generated method stub
		response.setContentType("text/html;charset=UTF-8");
		request.setCharacterEncoding("UTF-8");
		PrintWriter out=response.getWriter();
		try {
		  String info="Hedy冲鸭";
		  getServletConfig().getServletContext().setAttribute("Message", info);
			out.println("<html");
			out.println("<head>");
			out.println("<title></title>");
			out.println("</head>");
			out.println("<body>");
			out.println("信息:"+info);
			
			out.println("</body>");
			out.println("</html");
		}finally {
			out.close();
		}
	}

	/**
	 * @see HttpServlet#doPost(HttpServletRequest request, HttpServletResponse response)
	 */
	protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		// TODO Auto-generated method stub
		doGet(request, response);
	}

}

 

运行结果:

ShowMessage.java读取上一个文件的信息

package cy.servlet;

import java.io.IOException;
import java.io.PrintWriter;

import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

/**
 * Servlet implementation class PlayerInfo
 */
@WebServlet("/PlayerInfo")
public class ShowMessage extends HttpServlet {
	private static final long serialVersionUID = 1L;
       
    /**
     * @see HttpServlet#HttpServlet()
     */
    public ShowMessage() {
        super();
        // TODO Auto-generated constructor stub
    }

	/**
	 * @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse response)
	 */
	protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		// TODO Auto-generated method stub
		response.setContentType("text/html;charset=UTF-8");
		request.setCharacterEncoding("UTF-8");
		PrintWriter out=response.getWriter();
		try {
		  String getInfo=(String) getServletContext().getAttribute("Message");
			out.println("<html");
			out.println("<head>");
			out.println("<title></title>");
			out.println("</head>");
			out.println("<body>");
			out.println("读到的信息:"+getInfo);
			
			out.println("</body>");
			out.println("</html");
		}finally {
			out.close();
		}
	}

	/**
	 * @see HttpServlet#doPost(HttpServletRequest request, HttpServletResponse response)
	 */
	protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		// TODO Auto-generated method stub
		doGet(request, response);
	}

}

运行可以发现读到的信息和之前保存的信息是一样的:

通过上面的例子,可以发现上下文对象和session的方式非常相似,但是它们是有区别的,最根本的是它们具有不同的生命周期。

当web服务器开始运行后,这个应用就具备了唯一一个上下文对象,只要这个应用没有停止,这个上下文对象就一直存在。而session,每个用户都可以拥有一个。从适用范围来看,session应该是局部的,与用户有关的信息,上下文对象则是全局的,相对公共、更加安全的信息。

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值