Servlet(三)----会话跟踪技术

会话跟踪技术

  1. 什么是会话
    会话是指一个终端用户(服务器)与交互系统(客户端)进行通讯的过程。

  2. 什么是会话跟踪
    对同一个用户对服务器的连续的请求和接受响应的监视。(将用户与同一用户发出的不同请求之间关联,为了数据共享)

  3. 为什么需要会话跟踪
    浏览器与服务器之间的通信是通过HTTP协议进行通信的,而HTTP协议是”无状态”的协议,它不能保存客户的信息,即一次响应完成之后连接就断开了,下一次的请求需要重新连接,这样就需要判断是否是同一个用户,所以才应会话跟踪技术来实现这种要求

  4. 四种会话跟踪技术
    a) URL重写:
    URL(统一资源定位符)是Web上特定页面的地址,URL地址重写的原理是将该用户Session的id信息重写 到URL地址中,以便在服务器端进行识别不同的用户。URL重写能够在客户端停用cookies或者不支持cookies的时候仍然能够发挥作用。
    DemoBServlet.java

package servlet;

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.net.URLDecoder;

@WebServlet("/B")
public class DemoBServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        String name = req.getParameter("name");//URL重写
        System.out.println(name);
        name = URLDecoder.decode(name,"utf-8");
        System.out.println(name);
    }
}

EncodeUtil.java

package util;

import java.net.URLDecoder;
import java.net.URLEncoder;

public class EncodeUtil {
    //转码
    public static String encodingString(String str){
        try{
            str = URLEncoder.encode(str,"utf-8");
        }catch(Exception e){
            System.out.println(e.getMessage());
        }
        return str;
    }
    //解码
    public static String decodeString(String str){
        try{
            str = URLDecoder.decode(str,"utf-8");
        }catch(Exception e){
            System.out.println(e.getMessage());
        }
        return str;
    }

    public static void main(String[] args) {
        String str = encodingString("你好");
        System.out.println(str);
        str = decodeString(str);
        System.out.println(str);
    }
}

b.jsp

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>Title</title>
    <script>
        function funA(){
            var val = document.getElementById("name").value;
            alert(val);
            val = encodeURI(val);
            alert(val);
            val = encodeURI(val);//浏览器解码一次,不再编码一次的话输出到控制台就是两次中文
            alert(val);
            location.href = "B?name="+val;
        }
    </script>
</head>
<body>
    <input type="text" id="name"/>
    <button onclick="funA()">发送</button>
</body>
</html>

web.xml

<!DOCTYPE web-app PUBLIC
 "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
 "http://java.sun.com/dtd/web-app_2_3.dtd" >

<web-app>
  <display-name>Archetype Created Web Application</display-name>
  <welcome-file-list>
    <welcome-file>b.jsp</welcome-file>
  </welcome-file-list>
</web-app>

b) 隐藏表单域:
将会话ID添加到HTML表单元素中提交到服务器,此表单元素并不在客户端显示,浏览时看不到,源代码中有。
DemoAServlet.java

package servlet;

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.net.URLDecoder;
@WebServlet("/A")
//隐藏域表单
/*
a1提交表单时,a2如果不接收a1的数据并转发出去的话,在a2中想显示a1的东西
,就不会显示,必须将a1发送过来的东西也接收了并发送出去。
 */
public class DemoAServlet extends HttpServlet {
    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        String name = req.getParameter("name");
        System.out.println(name);
    }
}

a1.jsp

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>Title</title>
</head>
<body>
    <form action="a2.jsp" method="post">
        <input type="text" name="name" placeholder="请输入姓名"/>
        <button>姓名</button>
    </form>
</body>
</html>

a2.jsp

<%@ page contentType="text/html;charset=UTF-8" language="java" isELIgnored="false" %>//注意要将siELIgnored属性设置成false 才能使用el表达式
<html>
<head>
    <title>Title</title>
</head>
<body>
    ${param.name}:${param.content}
    <hr/>
    <form action="a2.jsp" method="post">
        <input type="text" name="content" placeholder="请输入内容"/>
        <input type="hidden" name="name" value="${param.name}"/><!--不再次转发的话会读不到-->
        <button>发送</button>
    </form>
</body>
</html>

web.xml

<!DOCTYPE web-app PUBLIC
 "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
 "http://java.sun.com/dtd/web-app_2_3.dtd" >

<web-app>
  <display-name>Archetype Created Web Application</display-name>
  <welcome-file-list>
    <welcome-file>a1.jsp</welcome-file>
  </welcome-file-list>
</web-app>

c) Cookie:
Cookie是Web服务器发送给客户端的一小段信息,客户端请求时可以读取该信息发送到服务器端,进而进行用户的识别。对于客户端的每次请求,服务器都会将Cookie发送到客户端,在客户端可以进行保存,以便下次使用。 服务器创建保存于浏览器端,不可跨域名性,大小及数量有限。客户端可以采用两种方式来保存这个Cookie对象,一种方式是 保存在 客户端内存中,称为临时Cookie,浏览器关闭后 这个Cookie对象将消失。另外一种方式是保存在 客户机的磁盘上,称为永久Cookie。以后客户端只要访问该网站,就会将这个Cookie再次发送到服务器上,前提是 这个Cookie在有效期内。 这样就实现了对客户的跟踪。
Cookie是可以被禁止的。
DemoCServlet.java

package servlet;

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;

@WebServlet("/C")
public class DemoCServlet extends HttpServlet {
    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        req.setCharacterEncoding("utf-8");//设置请求的编码集
        String name = req.getParameter("name");
        String pass = req.getParameter("pass");
        String is = req.getParameter("is");
        if ("admin".equalsIgnoreCase(name)&&"a123".equals(pass)){
            if (is!=null){//选中记住密码
                Cookie names = new Cookie("USER_NAME",name);
                names.setMaxAge(60*60*24);
                resp.addCookie(names);
                Cookie passes = new Cookie("USER_PASS",pass);
                passes.setMaxAge(60*60*24);
                resp.addCookie(passes);
            }
            resp.sendRedirect("index.jsp");
        }else{
            resp.sendRedirect("c.jsp?error=1");
        }
    }
}

c.jsp

<%@ page contentType="text/html;charset=UTF-8" language="java" isELIgnored="false" %>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<html>
<head>
    <title>Title</title>
</head>
<body>
<c:if test="${param.error==1}">
    你的账号或密码错误!
</c:if>
<form method="post" action="C">
    <table border="1">
        <tr>
            <th>账号</th>
            <td><input type="text" name="name" value="${cookie.USER_NAME.value}"/></td>
        </tr>
        <tr>
            <th>密码</th>
            <td><input type="password" name="pass" value="${cookie.USER_PASS.value}"/></td>
        </tr>
        <tr>
            <th colspan="2"><input type="checkbox" name="is" value="1"/>是否记住密码</th>
        </tr>
        <tr>
            <th colspan="2"><button>登录</button></th>
        </tr>
    </table>
</form>
</body>
</html>
<!--
顺便复习下value属性的知识:
input 标签的 value 属性的作用是由 input 标签的 type 属性的值决定的
当 type 的取值为 button、reset、submit 中的其中一个时,此时 value 属性的值表示的是按钮上显示的文本
当 type 的取值为 text、password、hidden 中的其中一个时,此时 value 属性的值表示的是输入框中显示的初始值,
此初始值可以更改,并且在提交表单时,value 属性的值会发送给服务器(既是初始值,也是提交给服务器的值)
当 type 的取值为 checkbox、radio 中的其中一个时,此时 value 属性的值表示的是提交给服务器的值
当 type 的取值为 image 时,点击它提交表单后,会将用户的点击位置相对于图像左上角的 x 坐标和 y 坐标提交给服务器

checkbox 型的 input 标签的不足之处在于:提交表单时,只有处于勾选状态的复选框的数据值才会发送给服务器。也就是说,
如果没有任何一个复选框被选中,那么服务器就不会收到与其相关的数据项
当设置 input 标签的 type 属性值为checkbox 或者 radio 时,必须同时设置 input 标签的 value 属性
当 type="file" 时,不能使用 value 属性
-->

d) session:
每一个用户都有一个不同的session,各个用户之间是不能共享的,是每个用户所独享的,在session中可以存放信息。 保存在服务器端。需要解决多台服务器间共享问题。如果Session内容过于复杂,当大量客户访问服务器时可能会导致内存溢出。因此,Session里的信息应该尽量精简。
在服务器端会创建一个session对象,产生一个sessionID来标识这个session对象,然后将这个sessionID放入到Cookie中发送到客户端,下一次访问时,sessionID会发送到服务器,在服务器端进行识别不同的用户。
Session是依赖Cookie的,如果Cookie被禁用,那么session也将失效。
GoodsServlet.java

package servlet;

import bean.GoodsInfo;
import biz.GoodsBiz;

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;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

//goods?type=findAll
@WebServlet("/goods")
public class GoodsServlet extends HttpServlet {
    private GoodsBiz gb = new GoodsBiz();

    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        //送过来的参数
        String types = req.getParameter("type");
        if ("findAll".equals(types)){
            findAllGoods(req, resp);
        }else if("addgwc".equals(types)){
            addGwc(req,resp);
        }
    }

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        doGet(req,resp);
    }

    private void findAllGoods(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException{
        //获取list集合
        List<GoodsInfo> list = gb.findAllGoods();
        //将集合放入到session容器中
        req.getSession().setAttribute("GOODS_LIST",list);
        //跳转页面
        resp.sendRedirect("index.jsp");
    }

    protected void addGwc(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        String[] ids = req.getParameterValues("id");
        HttpSession session = req.getSession();
        List<GoodsInfo> gwcList;
        if (session.getAttribute("GWC_LIST")==null){
            gwcList = new ArrayList<>();
        }else{
            gwcList = (List<GoodsInfo>)session.getAttribute("GWC_LIST");
        }
        for (int i = 0; i < ids.length; i++) {
            int id = Integer.parseInt(ids[i]);
            GoodsInfo gi = gb.findGoodsById(id);
            //如果gi在gwcList中存在,则数量加一,否则将gi放入gwcList
            int index = gwcList.indexOf(gi);
            if (index == -1){
                gwcList.add(gi);
            }else{
                GoodsInfo g = gwcList.get(index);
                g.setGoodsNum(g.getGoodsNum()+1);
            }
        }
        session.setAttribute("GWC_LIST",gwcList);
        resp.sendRedirect("index.jsp");
    }
}

index.jsp

<%@ page language="java" pageEncoding="utf-8" isELIgnored="false" %><!--配置-->
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %><!--c标签-->
<html>
<body>
    <c:if test="${empty sessionScope.GOODS_LIST}">
        <c:redirect url="goods?type=findAll"/>
    </c:if>

<form action="goods?type=addgwc" method="post">
<table border="1" align="center" width="60%">
    <tr>
        <th>选择</th>
        <th>名称</th>
        <th>价格</th>
    </tr>
    <c:forEach var="gi" items="${sessionScope.GOODS_LIST}">
        <tr>
            <td><input type="checkbox" name="id" value="${gi.goodsId}"/></td>
            <td>${gi.goodsName}</td>
            <td>${gi.goodsPrice}</td>
        </tr>
    </c:forEach>
    <tr>
        <td><button>选择添加到购物车</button></td>
        &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
        <td><a href="gwc.jsp">查看购物车</a></td>
    </tr>
</table>
</form>
</body>
</html>

gwc.jsp

<%@ page contentType="text/html;charset=UTF-8" language="java"  isELIgnored="false" %>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<html>
<head>
    <title>Title</title>
</head>
<body>
<table border="1" align="center" width="60%">
    <tr>
        <th>名称</th>
        <th>价格</th>
        <th>数量</th>
    </tr>
    <c:set var="sum" value="0"></c:set>
    <c:forEach var="gi" items="${sessionScope.GWC_LIST}">
        <tr>
            <td>${gi.goodsName}</td>
            <td>${gi.goodsPrice}</td>
            <td>${gi.goodsNum}</td>
        </tr>
        <c:set value="${sum+gi.goodsPrice*gi.goodsNum}" var="sum"></c:set>
    </c:forEach>
    <tr>
        <td colspan="3">
            <a href="index.jsp">返回</a>
            &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
            总价:¥${sum}</td>
    </tr>
</table>
</body>
</html>

GoodsInfoDAO.java

package dao;

import bean.GoodsInfo;
import db.DBManager;

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.Statement;
import java.util.ArrayList;
import java.util.List;

public class GoodsInfoDAO {
    private Connection conn = null;
    private PreparedStatement ps = null;
    private ResultSet rs = null;

    public List<GoodsInfo> findAllGoods(){
        String sql = "select * from goods where goodsState=1";
        List<GoodsInfo> list = new ArrayList<>();
        conn = DBManager.getConnection();
        try{
            ps = conn.prepareStatement(sql);
            rs = ps.executeQuery();
            while(rs.next()){
                GoodsInfo gi = new GoodsInfo();
                gi.setGoodsId(rs.getInt(1));
                gi.setGoodsName(rs.getString(2));
                gi.setGoodsPrice(rs.getDouble(3));
                gi.setGoodsState(rs.getInt(4));
                list.add(gi);
            }
        }catch(Exception e){
            System.out.println(e.getMessage());
        }finally{
            DBManager.close(conn,ps,rs);
        }
        return  list;
    }

    public GoodsInfo findGoodsById(int id){
        GoodsInfo gi = new GoodsInfo();
        String sql = "select * from goods where goodsId = ?";
        conn = DBManager.getConnection();
        try{
            ps = conn.prepareStatement(sql);
            ps.setInt(1,id);
            rs = ps.executeQuery();
            if (rs.next()){
                gi.setGoodsId(rs.getInt(1));
                gi.setGoodsName(rs.getString(2));
                gi.setGoodsPrice(rs.getDouble(3));
                gi.setGoodsState(rs.getInt(4));
            }
        }catch(Exception e){
            System.out.println(e.getMessage());
        }finally{
            DBManager.close(conn,ps,rs);
        }
        return gi;
    }
}

其余包此处省略

  1. Session和Cookie区别:
    1、cookie数据存放在客户的浏览器上,session数据放在服务器上。

2、cookie不是很安全,别人可以分析存放在本地的cookie并进行cookie欺骗,考虑到安全应当使用session。

3、session会在一定时间内保存在服务器上。当访问增多,会比较占用你服务器的性能,考虑到减轻服务器性能方面,应当使用cookie。

4、单个cookie保存的数据不能超过4K,很多浏览器都限制一个站点最多保存20个cookie。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值