网络通信和IOJAVA学习Java知识点大全

Servlet第六篇【Session介绍、API、生命周期、应用

2018-02-04  本文已影响94人  Java3y

什么是Session

Session 是另一种记录浏览器状态的机制。不同的是Cookie保存在浏览器中,Session保存在服务器中。用户使用浏览器访问服务器的时候,服务器把用户的信息以某种的形式记录在服务器,这就是Session

如果说Cookie是检查用户身上的”通行证“来确认用户的身份,那么Session就是通过检查服务器上的”客户明细表“来确认用户的身份的。Session相当于在服务器中建立了一份“客户明细表”。

为什么要使用Session技术?

Session比Cookie使用方便,Session可以解决Cookie解决不了的事情【Session可以存储对象,Cookie只能存储字符串。】。

Session API


Session作为域对象

从上面的API看出,Session有着request和ServletContext类似的方法。其实Session也是一个域对象。Session作为一种记录浏览器状态的机制,只要Session对象没有被销毁,Servlet之间就可以通过Session对象实现通讯


        //得到Session对象
        HttpSession httpSession = request.getSession();

        //设置Session属性
        httpSession.setAttribute("name", "看完博客就要点赞!!");

        //获取到从Servlet4的Session存进去的值
        HttpSession httpSession = request.getSession();
        String value = (String) httpSession.getAttribute("name");
        System.out.println(value);
image

Session的生命周期和有效期


            <session-config>
                <session-timeout>20</session-timeout>
            </session-config>   
image

            <session-config>
                <session-timeout>20</session-timeout>
            </session-config>   

        //设置Session最长超时时间为60秒,这里的单位是秒
        httpSession.setMaxInactiveInterval(60);

        System.out.println(httpSession.getMaxInactiveInterval());
image image

使用Session完成简单的购物功能


        response.setContentType("text/html;charset=UTF-8");
        PrintWriter printWriter = response.getWriter();

        printWriter.write("网页上所有的书籍:" + "<br/>");

        //拿到数据库所有的书
        LinkedHashMap<String, Book> linkedHashMap = DB.getAll();
        Set<Map.Entry<String, Book>> entry = linkedHashMap.entrySet();

        //显示所有的书到网页上
        for (Map.Entry<String, Book> stringBookEntry : entry) {

            Book book = stringBookEntry.getValue();

            String url = "/ouzicheng/Servlet6?id=" + book.getId();
            printWriter.write(book.getName());
            printWriter.write("<a href='" + url + "'>购买</a>");
            printWriter.write("<br/>");
        }

        //得到用户想买书籍的id
        String id = request.getParameter("id");

        //根据书籍的id找到用户想买的书
        Book book = (Book) DB.getAll().get(id);

        //获取到Session对象
        HttpSession httpSession = request.getSession();

        //由于用户可能想买多本书的,所以我们用一个容器装着书籍
        List list = (List) httpSession.getAttribute("list");
        if (list == null) {

            list = new ArrayList();

            //设置Session属性
            httpSession.setAttribute("list",list);
        }
        //把书籍加入到list集合中
        list.add(book);

        //得到用户想买书籍的id
        String id = request.getParameter("id");

        //根据书籍的id找到用户想买的书
        Book book = (Book) DB.getAll().get(id);

        //获取到Session对象
        HttpSession httpSession = request.getSession();

        //创建List集合
        List list = new ArrayList();
        list.add(book);

        httpSession.setAttribute("list", list);

        //得到用户想买书籍的id
        String id = request.getParameter("id");

        //根据书籍的id找到用户想买的书
        Book book = (Book) DB.getAll().get(id);

        //获取到Session对象
        HttpSession httpSession = request.getSession();

        //由于用户可能想买多本书的,所以我们用一个容器装着书籍
        List list = (List) httpSession.getAttribute("list");
        if (list == null) {

            list = new ArrayList();

            //设置Session属性
            httpSession.setAttribute("list",list);
        }
        //把书籍加入到list集合中
        list.add(book);

        String url = "/ouzicheng/Servlet7";
        response.sendRedirect(url);

        //要得到用户购买过哪些书籍,得到Session的属性遍历即可
        HttpSession httpSession = request.getSession();
        List<Book> list = (List) httpSession.getAttribute("list");

        if (list == null || list.size() == 0) {
            printWriter.write("对不起,你还没有买过任何商品");

        } else {
            printWriter.write("您购买过以下商品:");
            printWriter.write("<br/>");
            for (Book book : list) {
                printWriter.write(book.getName());
                printWriter.write("<br/>");
            }
        }
image

Session的实现原理


        //得到Session对象
        HttpSession httpSession = request.getSession();

        //设置Session属性
        httpSession.setAttribute("name", "看完博客就要点赞!!");

        String value = (String) request.getSession().getAttribute("name");

        printWriter.write(value);
image image image image image

浏览器禁用了Cookie,Session还能用吗?

上面说了Session是依靠Cookie来识别用户浏览器的。如果我的用户浏览器禁用了Cookie了呢?绝大多数的手机浏览器都不支持Cookie,那我的Session怎么办?

image image image image image image

        String url = "/ouzicheng/Servlet7";

        response.sendRedirect(response.encodeURL(url));
image image

Session禁用Cookie

注意:该配置只是让服务器不能自动维护名为jsessionid的Cookie,并不能阻止Cookie的读写。


Session案例

使用Session完成用户简单登陆


    private String username = null;
    private String password = null;

    public User() {
    }

    public User(String username, String password) {
        this.username = username;
        this.password = password;
    }

    ....各种set、get方法

    private static List<User> list = new ArrayList<>();

    //装载些数据进数据库
    static {

        list.add(new User("aaa","111"));
        list.add(new User("bbb","222"));
        list.add(new User("ccc","333"));
    }

    //通过用户名和密码查找用户
    public static User find(String username, String password) {

        for (User user : list) {
            if (user.getUsername().equals(username) && user.getPassword().equals(password)) {

                return user;
            }
        }

        return null;
    }

<form action="/ouzicheng/LoginServlet" method="post">
    用户名:<input type="text" name="username"><br/>
    密码:<input type="password" name="password"><br/>
    <input type="submit" value="提交">

</form>


        String username = request.getParameter("username");
        String password = request.getParameter("password");

        User user = UserDB.find(username, password);

        //如果找不到,就是用户名或密码出错了。
        if (user == null) {
            response.getWriter().write("you can't login");
            return;
        }

        //标记着该用户已经登陆了!
        HttpSession httpSession = request.getSession();
        httpSession.setAttribute("user", user);

        //跳转到其他页面,告诉用户成功登陆了。
        response.sendRedirect(response.encodeURL("index.jsp"));
image image image image

利用Session防止表单重复提交


<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>表单提交</title>

    <script type="text/javascript">

        //定义一个全局标识量:是否已经提交过表单数据
        var isCommitted = false;

        function doSubmit() {

            //false表示的是没有提交过,于是就可以让表单提交给Servlet
            if(isCommitted==false) {

                isCommitted = true;
                return true;
            }else {
                return false;
            }
        }
    </script>
</head>
<body>

<form action="/ouzicheng/Servlet7" onsubmit="return doSubmit()">

    用户名:<input type="text" name="username">
    <input type="submit" value="提交">
</form>

</body>
</html>
image

    <script type="text/javascript">
        function doSubmit() {
            var button = document.getElementById("button");

            button.disabled = disabled;

            return true;
        }
    </script>

image

/*
* 产生随机数就应该用一个对象来生成,这样可以避免随机数的重复。
* 所以设计成单例
* */
public class TokenProcessor {

    private TokenProcessor() {
    }

    private final static TokenProcessor TOKEN_PROCESSOR = new TokenProcessor();

    public static TokenProcessor getInstance() {
        return TOKEN_PROCESSOR;
    }

    public static String makeToken() {

        //这个随机生成出来的Token的长度是不确定的
        String token = String.valueOf(System.currentTimeMillis() + new Random().nextInt(99999999));

        try {
            //我们想要随机数的长度一致,就要获取到数据指纹
            MessageDigest messageDigest = MessageDigest.getInstance("md5");
            byte[] md5 = messageDigest.digest(token.getBytes());

            //如果我们直接 return  new String(md5)出去,得到的随机数会乱码。
            //因为随机数是任意的01010101010,在转换成字符串的时候,会查gb2312的码表,gb2312码表不一定支持该二进制数据,得到的就是乱码

            //于是乎经过base64编码成了明文的数据
            BASE64Encoder base64Encoder = new BASE64Encoder();
            return base64Encoder.encode(md5);

        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
        }

        return null;

    }

}


        //生出随机数
        TokenProcessor tokenProcessor = TokenProcessor.getInstance();
        String token = tokenProcessor.makeToken();

        //将随机数存进Session中
        request.getSession().setAttribute("token", token);

        //跳转到显示页面
        request.getRequestDispatcher("/login.jsp").forward(request, response);


<form action="/ouzicheng/Servlet7" >

    用户名:<input type="text" name="username">
    <input type="submit" value="提交" id="button">

    <%--使用EL表达式取出session中的Token--%>
    <input type="hidden" name="token" value="${token}" >

</form>


        String serverValue = (String) request.getSession().getAttribute("token");
        String clientValue = request.getParameter("token");

        if (serverValue != null && clientValue != null && serverValue.equals(clientValue)) {

            System.out.println("处理请求");

            //清除Session域对象数据
            request.getSession().removeAttribute("token");

        }else {

            System.out.println("请不要重复提交数据!");
        }
image

实现原理是非常简单的:


一次性校验码

        //在内存中生成图片
        BufferedImage bufferedImage = new BufferedImage(80, 20, BufferedImage.TYPE_INT_RGB);

        //获取到这张图片
        Graphics2D graphics2D = (Graphics2D) bufferedImage.getGraphics();

        //设置背景色为白色
        graphics2D.setColor(Color.white);
        graphics2D.fillRect(0, 0, 80, 20);

        //设置图片的字体和颜色
        graphics2D.setFont(new Font(null, Font.BOLD, 20));
        graphics2D.setColor(Color.BLUE);

        //生成随机数
        String randomNum = makeNum();

        //往这张图片上写数据,横坐标是0,纵坐标是20
        graphics2D.drawString(randomNum, 0, 20);

        //将随机数存进Session域中
        request.getSession().setAttribute("randomNum", randomNum);

        //控制浏览器不缓存该图片
        response.setHeader("Expires", "-1");
        response.setHeader("Cache-Control", "no-cache");
        response.setHeader("Pragma", "no-cache");

        //通知浏览器以图片的方式打开
        response.setHeader("Content-type", "image/jpeg");

        //把图片写给浏览器
        ImageIO.write(bufferedImage, "jpg", response.getOutputStream());

    private String makeNum() {

        Random random = new Random();

        //生成0-6位的随机数
        int num = random.nextInt(999999);

        //验证码的数位全都要6位数,于是将该随机数转换成字符串,不够位数就添加
        String randomNum = String.valueOf(num);

        //使用StringBuffer来拼凑字符串
        StringBuffer stringBuffer = new StringBuffer();
        for (int i = 0; i < 6 - randomNum.length(); i++) {
            stringBuffer.append("0");
        }

        return stringBuffer.append(randomNum).toString();

    }

<form action="/ouzicheng/Login2Servlet">

    用户名:<input type="text" name="username"><br>
    密码:<input type="password" name="password"><br>
    验证码:<input type="text" name="randomNum">
    <img src="/ouzicheng/ImageServlet" ><br><br>

    <input type="submit" value="提交">

</form>

        //获取用户输入验证码的数据
        String client_randomNum = request.getParameter("randomNum");

        //获取Session中的数据
        String session_randomNum = (String) request.getSession().getAttribute("randomNum");

        //判断他俩数据是否相等,用户是否有输入验证码,Session中是否为空
        if (client_randomNum == null || session_randomNum == null || !client_randomNum.equals(session_randomNum)) {
            System.out.println("验证码错误了!!!");
            return ;
        }

        //下面就是验证用户名和密码...................
image image

对于校验码实现思路是这样子的:

Session和Cookie的区别


Cookie和Session共同使用


        Cookie cookie = new Cookie("JSESSIONID",session.getId());
        cookie.setMaxAge(30*60);
        cookie.setPath("/ouzicheng/");
        response.addCookie(cookie);

image

如果文章有错的地方欢迎指正,大家互相交流。习惯在微信看技术文章的同学,可以关注微信公众号:Java3y

上一篇 下一篇

猜你喜欢

热点阅读