什么是会话
会话过程中要解决的一些问题?
Cookie
Session
Cookie API
Cookie 细节
Cookie 应用
PrintWriter out = response.getWriter();
out.write("您上次访问时间是:");
//1.获取用户上次访问的时间,显示
Cookie cookies[] = request.getCookies();
for(int i=0;cookies!=null && i<cookies.length;i++){
Cookie cookie = cookies[i];
if(cookie.getName().equals("lastAccessTime")){
long time = Long.parseLong(cookie.getValue());
Date date = new Date(time);
out.write(date.toLocaleString());
}
}
//2.把本次的时间以cookie的形式回写给客户机 (lastAccessTime)
Cookie cookie = new Cookie("lastAccessTime",System.currentTimeMillis()+"");
cookie.setMaxAge(7*24*60*60);
response.addCookie(cookie);
商品列表servlet,显示网站商品列表,并根据浏览器带过来的cookie显示用户历史浏览记录
PrintWriter out = response.getWriter();
//1.显示网站所有商品
out.print("本网站有如下书籍:
");
Map<String,Book> map = DB.getMap();
for(Map.Entry<String, Book> entry : map.entrySet()){
Book book = entry.getValue();
out.print(""+book.getName()+"
");
}
out.print("您曾经看过如下商品:
");
//2.显示用户曾经浏览过的商品 // bookHistory
Cookie cookie = null;
Cookie cookies[] = request.getCookies();
for(int i=0;cookies!=null && i<cookies.length;i++){
if(cookies[i].getName().equals("bookHistory")){
cookie = cookies[i];
}
}
if(cookie!=null){
//找到了bookHistory这个cookie
String bookHistory = cookie.getValue(); //4_6_1
String ids[] = bookHistory.split("\\_");
for(String id: ids){
Book book = (Book) DB.getMap().get(id);
out.print(book.getName() + "
");
}
}
商品详情servlet,根据request携带的商品id显示商品详情,并且将这个id放入用户浏览历史的cookie中
PrintWriter out = response.getWriter();
//1.根据用户带过来的id值,显示相应商品的信息
out.print("您想看的书的详细信息为:
");
String id = request.getParameter("id");
Book book = (Book) DB.getMap().get(id);
out.print(book.getId() + "
");
out.print(book.getName() + "
");
out.print(book.getAuthor() + "
");
//2.以cookie的形式回写该商品的id号给浏览器
String bookHistory = makeCookie(book.getId(),request);
Cookie cookie = new Cookie("bookHistory",bookHistory);
cookie.setMaxAge(10000);
response.addCookie(cookie);
根据用户本次浏览的商品信息构建代表用户浏览量历史的cookie
//根据用户原来看过的书,以及现在看的书的id,构建新的cookie值
private String makeCookie(String id, HttpServletRequest request) {
//1.得到用户曾经看过的书
String bookHistory = null;
Cookie cookies[] = request.getCookies();
for(int i=0;cookies!=null && i<cookies.length;i++){
if(cookies[i].getName().equals("bookHistory")){
bookHistory = cookies[i].getValue();
}
}
if(bookHistory==null){
bookHistory = id;
return bookHistory;
}
//bookHistory=1_2_5 代表用户曾经看一些书,接着程序要得到用户曾经看过什么书
String ids[] = bookHistory.split("_");
//为了检测数组中是否包含当前id,我们应该把数据转成集合,并且还要转成链表结构的集合
LinkedList<String> idList = new LinkedList(Arrays.asList(ids));
if(idList.contains(id)){
idList.remove(id);
}else{
if(idList.size()>=3){
idList.removeLast();
}
}
idList.addFirst(id);
StringBuffer sb = new StringBuffer();
for(String lid: idList){ //1_2_3_
sb.append(lid + "_");
}
return sb.deleteCharAt(sb.length()-1).toString();
}
session实现原理
上图中session是通过cookie实现的,浏览器每次访问服务器时在cookie中携带Jsessionid,服务器根据Jsessionid去获取该浏览器对应的session。
禁用Cookie后的session实现原理
浏览器禁用cookie后,为了保证session的正常使用,服务器端重写网页上所有的URL地址,使得网页上所有URL地址后面带上用户的sessionid,重写后的URL地址类似于www.baidu.com;jsessionid=1354646546。request.getSession方法内部会从用户携带的cookie和url地址中查找用户的sessionid,返回用户的session。
URL重写api
1.response. encodeRedirectURL(java.lang.String url)
用于对sendRedirect方法后的url地址进行重写。
2.response. encodeURL(java.lang.String url)
用于对表单action和超链接的url地址进行重写
示例主页的两个链接都被重写,因此即使浏览器禁用cookie,该示例功能也不受影响
1.WelcomeServlet重写网页url
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
response.setCharacterEncoding("UTF-8");
response.setContentType("text/html;charset=UTF-8");
PrintWriter out=response.getWriter();
request.getSession();
String url1=response.encodeURL("/day07/SessionDemo1");
String url2=response.encodeURL("/day07/SessionDemo2");
out.print("把洗衣机加入购物车 ");
out.print("购买 ");
}
2.用户点击“把洗衣机加入购物车”访问SessionDemo1,因为用户访问的url被重写成day07/SessionDemo1;jesessionid=xxxxx,因此即使浏览器禁用cookie,SessionDemo1也能取得用户的session
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// 浏览器的请求第一次访问到这行代码的时候,服务器为该浏览器创建session对象
HttpSession session=request.getSession();
String sessionid=session.getId();
session.setAttribute("name", "洗衣机");
}
3.用户点击“购买”访问SessionDemo2,因为用户访问的url被重写成day07/SessionDemo2;jesessionid=xxxxx,因此即使浏览器禁用cookie,SessionDemo2也能取得用户的session
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
response.setCharacterEncoding("UTF-8");
response.setContentType("text/html;charset=UTF-8");
PrintWriter out=response.getWriter();
HttpSession session=request.getSession();
String product=(String) session.getAttribute("name");
out.write("您购买的商品是:"+product);
}
session应用
FormServlet生成令牌并保存在用户session中,将请求转发给form.jsp
public class FormServlet extends HttpServlet {
private static final long serialVersionUID = 1L;
public FormServlet() {
super();
}
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//产生令牌
TokenProcessor tp=TokenProcessor.getInstance();
String token=tp.generateToken();
//将令牌保存在session中
request.getSession().setAttribute("token", token);
//转发请求到form.jsp
request.getRequestDispatcher("form.jsp").forward(request, response);
}
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
doGet(request, response);
}
}
class TokenProcessor{ //令牌
private TokenProcessor(){
super();
}
private static final TokenProcessor instance=new TokenProcessor();
public static TokenProcessor getInstance(){
return instance;
}
public String generateToken() {
//产生随机数
String token=System.currentTimeMillis()+new Random().nextInt()+"";
//产生数据指纹(摘要)
try {
MessageDigest md = MessageDigest.getInstance("md5");
byte[] md5=md.digest(token.getBytes());
//base64编码
BASE64Encoder encoder=new BASE64Encoder();
return encoder.encode(md5);
} catch (NoSuchAlgorithmException e) {
throw new RuntimeException(e);
}
}
}
form.jsp负责显示带有令牌的表单
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
<title>Insert title heretitle>
<script type="text/javascript">
function doSubmit(){
var button=document.getElementById("submit");
button.disabled='disabled';
return true;
}
script>
head>
<body>
<form action="/day07/DoFormServlet" method="post">
<input type="hidden" name="token" value="${token}" onsubmit="return doSubmit()">
用户名:<input type="text" name="username">
<input type="submit" value="提交">
form>
body>
html>
表单提交后由DoFormServlet来处理
public class DoFormServlet extends HttpServlet {
private static final long serialVersionUID = 1L;
public DoFormServlet() {
super();
}
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
boolean b = isTokenValid(request);
if(!b){
System.out.println("请不要重复提交");
return;
}
request.getSession().removeAttribute("token");
System.out.println("向数据库中注册一个用户");
}
//判断表单号是否有效
private boolean isTokenValid(HttpServletRequest request) {
String client_token=request.getParameter("token");
if(client_token==null){
return false;
}
String server_token=(String) request.getSession(false).getAttribute("token");
if(server_token==null){
return false;
}
if(!client_token.equals(server_token)){
return false;
}
return true;
}
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
doGet(request, response);
}
}