当前位置: 首页 > news >正文

JavaWeb学习笔记(十二)--Session案例

1. 利用session完成用户登录

实现步骤:

  1. 实现两个页面,首页、登录页面
  2. 实现登录、退出的Servlet,LoginServlet、LoginOutServlet
  3. 实现一个用户类
  4. 实现一个DB类,模拟数据库提供用户的信息

目录结构:

 

首页index.jsp:

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
  <head>
    <title>首页</title>
  </head>
  <body>
  <%--EL表达式,用于获取当前登录的用户--%>
  欢迎您:${user.username}
  <a href="/login.html">登录</a> <a href="/LogoutServlet">退出登录</a>
  </body>
</html>

登录页面login.html:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>登录</title>
</head>
<body>
<form action="/LoginServlet" method="post">
    用户名:<input type="text" name="username"><br>
    密码:<input type="password" name="password"><br>
    <input type="submit" value="提交">
</form>

</body>
</html>

登录Servlet:

package com.servlet;

import com.db.DB;
import com.domain.User;

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;
import java.util.List;

@WebServlet(name = "LoginServlet")
public class LoginServlet extends HttpServlet {
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        doGet(request, response);
    }

    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        String username = request.getParameter("username");
        String password = request.getParameter("password");
        List<User> users = DB.getUsers();
        for (User user : users) {
            if (username.equals(user.getUsername())
                    && password.equals(user.getPassword())) {
                // 将当前用户存储在session中,可以在首页中使用EL表达式获取当前登录的用户名
                request.getSession().setAttribute("user", user);
                response.sendRedirect("/index.jsp");
                return;
            }
        }
        request.setCharacterEncoding("utf-8");
        response.setContentType("text/html;charset=utf-8");
        PrintWriter out = response.getWriter();
        out.write("用户名或密码错误");

    }
}

退出Servlet:

package com.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 javax.servlet.http.HttpSession;
import java.io.IOException;

@WebServlet(name = "LogoutServlet")
public class LogoutServlet extends HttpServlet {
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        doGet(request, response);
    }

    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        HttpSession session = request.getSession(false);
        if (session != null) {
            session.removeAttribute("user");

        }
        response.sendRedirect("/index.jsp");
        return;
    }
}

用户类:

package com.domain;

public class User {
    private String username;
    private String password;

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

    public String getUsername() {
        return username;
    }

    public void setUsername(String username) {
        this.username = username;
    }

    public String getPassword() {
        return password;
    }

    public void setPassword(String password) {
        this.password = password;
    }
}

模拟数据库:

package com.db;

import com.domain.User;

import java.util.ArrayList;
import java.util.List;

/**
 * 模拟数据库
 */
public class DB {
    private static List<User> users = new ArrayList<>();
    static {
        users.add(new User("aaa", "123"));
        users.add(new User("bbb", "123"));
        users.add(new User("ccc", "123"));
    }
    public static List<User> getUsers() {
        return users;
    }
}

web.xml:

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
         version="4.0">
    <servlet>
        <servlet-name>LoginServlet</servlet-name>
        <servlet-class>com.servlet.LoginServlet</servlet-class>
    </servlet>
    <servlet-mapping>
        <servlet-name>LoginServlet</servlet-name>
        <url-pattern>/LoginServlet</url-pattern>
    </servlet-mapping>

    <servlet>
        <servlet-name>LogoutServlet</servlet-name>
        <servlet-class>com.servlet.LogoutServlet</servlet-class>
    </servlet>
    <servlet-mapping>
        <servlet-name>LogoutServlet</servlet-name>
        <url-pattern>/LogoutServlet</url-pattern>
    </servlet-mapping>
</web-app>

实现效果:

 2. 利用Session防止表单重复提交

表单重复提交3种方式:

  1. 多次点击提交
  2. 提交后再次刷新页面,重复提交
  3. 提交后返回,重新提交

 

使用js表单提交后,让提交按钮灰化,可以解决第一种重复提交方式,第二、三种方式需要在服务器中处理。

服务端防止表单重复提交的方式:
表单提交的时候带一个随机数(令牌),在服务器端也存储这个随机数,在服务器看这个表单有没有提交过,如果没有提交过(随机数相同)则提交,然后服务器端把这个随机数删除掉,在提交的时候服务端就没有了,就阻止提交。

项目完整目录结构:

 

首页:

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
  <title>首页</title>
</head>
<body>
<a href="/FormServlet">注册</a>
</body>
</html>

表单页,使用js处理,表单提交后,使提交按钮灰化:

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>表单提交</title>
</head>
<body>
<form action="/DoFormServlet" method="post" onsubmit="return doSubmit()">
    <input type="hidden" name="token" value="${token}">
    用户名:<input type="text" name="username"><br>
    <input id="submit" type="submit">
</form>

</body>
<script>
    function doSubmit() {
        document.getElementById("submit").disabled = "disabled";
        return true;
    }
</script>
</html>

令牌生成器:

package com.util;

import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.Base64;
import java.util.Random;

/**
 * 令牌发生器,为了保证是唯一的,使用单例模式
 * 1. 构造方法私有
 * 2. 自己创建一个实例
 * 3. 暴露一个方法,允许外部获取创建的对象
 */
public class TokenProcessor {
    private static final TokenProcessor instance = new TokenProcessor();
    private TokenProcessor() {
    }
    public static TokenProcessor getInstance() {
        return instance;
    }
    public String generateToke() {
        // 这个生成的随机数,长度不固定
        String token = System.currentTimeMillis() + new Random().nextInt() + "";
        try {
            // 得到数据摘要,128位(16字节)
            MessageDigest md = MessageDigest.getInstance("md5");
            // 任意的二进制字节数组,如果直接转化成字符串的话,可能会出现乱码
            byte[] md5 = md.digest(token.getBytes());

            // 使用base64编码
            Base64.Encoder encoder = Base64.getEncoder();
            return encoder.encodeToString(md5);

        } catch (NoSuchAlgorithmException e) {
            throw new RuntimeException(e);
        }
    }

}

生成表单:

package com.servlet;

import com.util.TokenProcessor;

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;

// 产生表单,转发到JSP
@WebServlet(name = "FormServlet")
public class FormServlet extends HttpServlet {
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        doGet(request,response);
    }

    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {

        String token = TokenProcessor.getInstance().generateToke();
        request.getSession().setAttribute("token", token);
        request.getRequestDispatcher("/form.jsp").forward(request, response);
    }
}

表单校验:

package com.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;

@WebServlet(name = "DoFormServlet")
public class DoFormServlet extends HttpServlet {
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        doGet(request, response);
    }

    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        try {
            Thread.sleep(1000 * 3);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        if (!isTokenVailed(request)) {
            System.out.println("请不要重复提交");
            return;
        }
        System.out.println("向数据库中插入数据");

    }

    private boolean isTokenVailed(HttpServletRequest request) {
        String clientToken = request.getParameter("token");
        if (clientToken == null) {
            return false;
        }
        String serviceToke = (String) request.getSession().getAttribute("token");
        if (serviceToke == null || !serviceToke.equals(clientToken)) {
            return false;
        }
        request.getSession().removeAttribute("token");
        return true;
    }
}

web.xml:

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
         version="4.0">
    
    <servlet>
        <servlet-name>FormServlet</servlet-name>
        <servlet-class>com.servlet.FormServlet</servlet-class>
    </servlet>
    <servlet-mapping>
        <servlet-name>FormServlet</servlet-name>
        <url-pattern>/FormServlet</url-pattern>
    </servlet-mapping>
    
    <servlet>
        <servlet-name>DoFormServlet</servlet-name>
        <servlet-class>com.servlet.DoFormServlet</servlet-class>
    </servlet>
    <servlet-mapping>
        <servlet-name>DoFormServlet</servlet-name>
        <url-pattern>/DoFormServlet</url-pattern>
    </servlet-mapping>
</web-app>

实现效果:

 

附:

base64编码:将3个字节转换成4个字节(24位 -> 32位 )。转换后4个字节每个字节只有6位,所以高位补两个0,取值范围是0--63(2^6-1),然后对每个值进行编码,只需要64个编码字符即可,所以叫base64编码。
传递文件时一般都要指定开始和结束符,在开始和结束符中间的才是传输的数据,如果传递的文件中就包含了结束符,那么文件传送一半就会终止,导致文件缺损。所以一般情况下文件内容都用base64编码,而开始和结束符都不包含在base64编码之内。

转载于:https://www.cnblogs.com/songchj-bear/p/10841761.html

相关文章:

  • 实验:basic验证,组验证
  • 携程、阿里、京东、腾讯iOS春招面试过程以及面试题总结!
  • 003-软件质量模型的6大特性27个子特性(转)
  • 使用SpringSession管理分布式会话时遇到的反序列化问题
  • c语言程序设计第1章
  • 计算机的三大原则
  • Java并发之AQS详解
  • htaccess隐藏index.php,301重定向等等..
  • CF241B Friends
  • Git学习总结——简单易懂的教程
  • 整理收集的一些常用java工具类
  • vue+express+mysql +node项目搭建
  • AGC002 补题小结
  • 现代前端不切图
  • Nginx反向代理后应用程序获取客户端真实IP
  • 【知识碎片】第三方登录弹窗效果
  • canvas 高仿 Apple Watch 表盘
  • ERLANG 网工修炼笔记 ---- UDP
  • Idea+maven+scala构建包并在spark on yarn 运行
  • JavaScript-Array类型
  • LeetCode18.四数之和 JavaScript
  • Rancher-k8s加速安装文档
  • vue总结
  • 解决jsp引用其他项目时出现的 cannot be resolved to a type错误
  • 探索 JS 中的模块化
  • 通过几道题目学习二叉搜索树
  • 学习笔记TF060:图像语音结合,看图说话
  • 一些基于React、Vue、Node.js、MongoDB技术栈的实践项目
  • 深度学习之轻量级神经网络在TWS蓝牙音频处理器上的部署
  • ​configparser --- 配置文件解析器​
  • #include到底该写在哪
  • #多叉树深度遍历_结合深度学习的视频编码方法--帧内预测
  • $(function(){})与(function($){....})(jQuery)的区别
  • (02)Cartographer源码无死角解析-(03) 新数据运行与地图保存、加载地图启动仅定位模式
  • (1)SpringCloud 整合Python
  • (AngularJS)Angular 控制器之间通信初探
  • (C++)栈的链式存储结构(出栈、入栈、判空、遍历、销毁)(数据结构与算法)
  • (done) ROC曲线 和 AUC值 分别是什么?
  • (Redis使用系列) SpirngBoot中关于Redis的值的各种方式的存储与取出 三
  • (附源码)php投票系统 毕业设计 121500
  • (南京观海微电子)——COF介绍
  • ******IT公司面试题汇总+优秀技术博客汇总
  • .NET WebClient 类下载部分文件会错误?可能是解压缩的锅
  • .net 程序 换成 java,NET程序员如何转行为J2EE之java基础上(9)
  • .NetCore项目nginx发布
  • .pop ----remove 删除
  • @RequestMapping用法详解
  • @RequestMapping-占位符映射
  • [Angular 基础] - 指令(directives)
  • [BZOJ2850]巧克力王国
  • [go 反射] 进阶
  • [HackMyVM]靶场Boxing
  • [HDU]2161Primes
  • [Invalid postback or callback argument]昨晚调试程序时出现的问题,MARK一下
  • [JS]数据类型