cookie

目录

一、会话技术

二、Cookie

1.创建Cookie

2.使用response响应Cookie给客户端(浏览器)

3. 获取Cookie

三、Cookie的原理解析

1. 基本实现原理

(1)响应头:set—cookie

(2)请求头:cookie

(3)Cookie过期时间

四、cookie细节

五、session

六、session使用

1. 服务器端会话跟踪技术:

2. 常用的API:

3. session原理

4. session细节

七、session与cookie区别

八、 用户登录注册案例

用户登录

记住密码

用户注册

图形验证码


一、会话技术

1. 会话:一次会话中包含多次请求和响应。
	* 一次会话:浏览器第一次给服务器资源发送请求,会话建立,直到有一方断开为止
2. 功能:在一次会话的范围内的多次请求间,共享数据
3. 方式:
	1. 客户端会话技术:Cookie
	2. 服务器端会话技术:Session

1.用户打开同一个浏览器,访问到我们的web服务器的资源建立会话,对方断开连接该会话才会结束,在一次会话中可以包含多次请求和响应。通俗易懂的理解:一种维护浏览器状态的方法,服务器需要识别多次请求是否来自于一个浏览器,以便于在同一次会话的多次请求间共享数据。

2.这是因为http协议是无状态的,每次浏览器向服务器请求时,没有绑定会话信息服务器都会认为该请求是为新请求,没有任何记忆功能,所以我们需要会话跟踪技术实现会话内数据共享。

3. 会话技术实现方式    

(1)客户端会话跟踪技术:Cookie      

(2)服务端会话跟踪技术:Session

(3)token或者jwt----新的

二、Cookie

Cookie:客户端会话技术,将数据保存到客户端,以后每次请求都携带Cookie数据进行访问

Cookie 数据存放在浏览器端(客户端)

Cookie的特点:
    1. cookie存储数据在客户端浏览器
    2. 浏览器对于单个cookie 的大小有限制(4kb) 以及 对同一个域名下的总cookie数量也有限制(20个)

      * 作用:
        1. cookie一般用于存出少量的不太敏感的数据
        2. 在不登录的情况下,完成服务器对客户端的身份识别

1.创建Cookie

Cookie cookie = new Cookie("key","value");

2.使用response响应Cookie给客户端(浏览器)

response.addCookie(cookie);

3. 获取Cookie

获取客户端携带的所有Cookie,使用request对象

Cookie[] cookies = request.getCookies();
cookie.getName();
cookie.getValue();
@WebServlet("/addCookieServlet")
public class AddCookieServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        Cookie cookie = new Cookie("mayikt", "yushengjun");
        resp.addCookie(cookie);
    }
}
@WebServlet("/getCookieServlet")
public class GetCookieServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        Cookie[] cookies = req.getCookies();
        for (int i = 0; i < cookies.length; i++) {
            Cookie cookie = cookies[i];
            System.out.println("key:" + cookie.getName() + "," +cookie.getValue());
        }
    }
}

注意:在没有清理浏览器缓存的情况下,重启tomcat服务器,cookie数据不会丢失

三、Cookie的原理解析

1. 基本实现原理

Cookie实现是基于HTTP协议的

(1)响应头:set—cookie

客户端(浏览器端)发送请求达到服务器端,服务器端会创建cookie,会将该cookie数据

返回给客户端,在响应头中设置 set—cookie value cookie数据。

(2)请求头:cookie

同一个浏览器发送请求时,在请求中设置该cookie数据 存放在请求头中。

cookie value

(3)Cookie过期时间

setMaxAge(int seconds):设置Cookie存活时间

  a.正数:将Cookie写入浏览器所在的电脑硬盘,持久化存储,到期自动删除 

  b.负数:默认值,Cookie存储在浏览器内存中,当浏览器关闭,内存释放,则Cookie被销毁。

  c.零:删除对应Cookie

四、cookie细节

    1. 一次可不可以发送多个cookie?

        * 可以
        * 可以创建多个Cookie对象,使用response调用多次addCookie方法发送cookie即可。

    2. cookie在浏览器中保存多长时间?

        (1) 默认情况下,当浏览器关闭后,Cookie数据被销毁

         (2) 持久化存储:

            * setMaxAge(int seconds)
                a. 正数:将Cookie数据写到硬盘的文件中。持久化存储。并指定cookie存活时间,时间到后,cookie文件自动失效
                b. 负数:默认值
                c. 零:删除cookie信息

    3. cookie能不能存中文?

        * 在tomcat 8 之前 cookie中不能直接存储中文数据。
            * 需要将中文数据转码---一般采用URL编码(%E3)
        * 在tomcat 8 之后,cookie支持中文数据。特殊字符还是不支持,建议使用URL编码存储,URL解码解析

    4. cookie共享问题?

        假设在一个tomcat服务器中,部署了多个web项目,那么在这些web项目中cookie能不能共享?
            * 默认情况下cookie不能共享

            * setPath(String path):设置cookie的获取范围。默认情况下,设置当前的虚拟目录
                * 如果要共享,则可以将path设置为"/"

五、session

1. 概念:服务器端会话技术,在一次会话的多次请求间共享数据,将数据保存在服务器端的对象中。HttpSession

2. 快速入门:

    (1)获取HttpSession对象:
        HttpSession session = request.getSession();

   (2)使用HttpSession对象:
        Object getAttribute(String name)  
        void setAttribute(String name, Object value)
        void removeAttribute(String name)  

3. 原理
    * Session的实现是依赖于Cookie的。

六、session使用

1.session用于存储一次会话的多次请求的数据,存在服务器端;

2.session可以存储任意类型,任意大小的数据。

1. 服务器端会话跟踪技术:

   将数据保存在服务器端,底层基于cookie实现封装

2. 常用的API:

(1)void session.setAttribute(k,v) session存入值 key=name,value 'yushengjun'

(2)Object session.getAttribute(k) 获取到session中的值

(3)void removeAttribute(k) 删除我们的session

3. session原理

(1)当我们客户端发送请求达到服务器端时创建session,会得到一个sessionid,在将该

sessionid 响应在响应头<sessionid >

(2)客户端(浏览器)接受响应头中的sessionid ,会将该sessionid的值 存放在浏览器中。

session本质上就是基于cookie实现封装的。

(3)使用同一个浏览器发送请求时,访问通一个服务器端,会在请求头中设定该sessionid 的值,服务器端就会从请求头中获取到该sessionid 查找对应session。

session 数据存放在服务器端 cookie将数据存放在本地。

4. session细节

(1)当客户端关闭后,服务器不关闭的话,再次打开客户端访问服务器端两次获取Session是否为同一个?

        在默认情况下,不是同一个。因为客户端关闭后,cookie对象被销毁,客户端请求服务器会创建新的session。

          如果需要两个Session相同,则可以创建一个Cookie对象,key为:JSESSIONID,设置一下最大存活时间,让Cookie持久化保存Session的ID,就可以实现客户端关闭,两次获取Session就是同一个。

Cookie c = new Cookie("JSESSIONID",session.getId());
	    c.setMaxAge(60*60); //1个小时有效期
	    response.addCookie(c);

(2)客户端不关闭,服务器关闭后的话,两次获取的Session是否是同一个?

        不是,因为同样服务器关闭后session对象会被销毁。

        如果想确保数据不丢失,可以使session钝化,即在服务器正常关闭之前,将session对象序列化到硬盘上。下次在服务器启动后,将session文件反序列化转化为内存中的session对象即可。

0D202066E021E4F4FB978F1647C0D742

tomcat自动完成以下工作:

1.session的钝化:在服务器正常关闭之前,将session对象系列化到硬盘上。

2.session的活化: 在服务器启动后,将session文件转化为内存中的session对象即可。
session什么时候被销毁?

1.服务器关闭;

2.session对象调用invalidate() ;

3.session默认失效时间 30分钟。

七、session与cookie区别

session与Cookie的区别:

1.session存储数据在服务器端,Cookie在客户端;

2.session没有数据大小限制,Cookie有数据大小限制;

3.session数据安全,Cookie相对不安全。

八、 用户登录注册案例

用户登录

使用session保存用户会话信息。

数据库访问层

public class MayikUsertDao {
    
    /**
    * 用户登录成功之后 该方法返回 用户登录成功之后对象
    */
    public MayiktUserEntity login(String userName, String userPwd) {
        try {
            Connection connection = MayiktJdbcUtils.getConnection();
            String loginSql = "select  * from  mayikt_users where userName=? and userPwd=?;";
            PreparedStatement preparedStatement = connection.prepareStatement(loginSql);
            preparedStatement.setString(1, userName);
            preparedStatement.setString(2, userPwd);
            ResultSet resultSet = preparedStatement.executeQuery();
            if (!resultSet.next()) {  // 查询不到用户数据
                return null;
            }
            // 将db中数据 返回给客户端 查询到数据
            Integer id = resultSet.getInt(1);
            String dbUserName = resultSet.getString(2);
            String dbUserPwd = resultSet.getString(3);
            MayiktUserEntity mayiktUserEntity = new MayiktUserEntity(id, dbUserName, dbUserPwd);
            return mayiktUserEntity;
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
        
    }
}

业务逻辑层

public class MayikUsertService {
    private MayikUsertDao mayikUsertDao = new MayikUsertDao();

    public MayiktUserEntity login(String userName, String userPwd) {
        return mayikUsertDao.login(userName, userPwd);
    }
}

视图层

@WebServlet("/login")
public class LoginServlet extends HttpServlet {
    private MayikUsertService mayikUsertService = new MayikUsertService();

    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        // 转发login页面
        req.getRequestDispatcher("login.jsp").forward(req, resp);
    }

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        // 点击登录的时候 获取到用户的参数
        String userName = req.getParameter("userName");
        if (StringUtils.isEmpty(userName)) {
            //转发到错误页面
            req.setAttribute("errorMsg", "用户名称不能够是为空!");
            req.getRequestDispatcher("error.jsp").forward(req, resp);
            return;
        }
        String userPwd = req.getParameter("userPwd");
        // 参数验证
        if (StringUtils.isEmpty(userPwd)) {
            //转发到错误页面
            req.setAttribute("errorMsg", "userPwd不能够是为空!");
            req.getRequestDispatcher("error.jsp").forward(req, resp);
            return;
        }
        // 在调用业务逻辑层
        MayiktUserEntity mayiktUserEntity = mayikUsertService.login(userName, userPwd);
        if (mayiktUserEntity == null) {
            // 用户名称或者密码错误!
            req.setAttribute("errorMsg", "用户名称或者是密码错误!");
            req.getRequestDispatcher("login.jsp").forward(req, resp);
            return;
        }
        // 能够db中查询到对象 登录成功了  将用户数据存放在session中
        HttpSession session = req.getSession();
        session.setAttribute("user", mayiktUserEntity);
        // 在转发到首页(重定向到首页)
//        req.getRequestDispatcher("index.jsp").forward(req, resp);
        resp.sendRedirect("index.jsp");
    }
}

<%--
  Created by IntelliJ IDEA.
  User: mayikt
  Date: 2022/6/6
  Time: 17:12
  To change this template use File | Settings | File Templates.
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<!DOCTYPE html>
<html>
<head>
    <title>登录测试页面</title>
    <form action="/mayikt_session_war_exploded/login" method="post">
        <label>用户名: </label><input type="text" name="userName"/><br>
        <label>密&nbsp码&nbsp: </label><input type="password" name="userPwd"/><br>
        ${errorMsg}
        <input type="submit" value="登录 "/>
    </form>

</head>
</html>

相关配置文件

driverClass=com.mysql.cj.jdbc.Driver
url=jdbc:mysql://127.0.0.1:3306/mayikt?serverTimezone=GMT%2B8
user=root
password=root

记住密码

思路:

用户登录成功之后,会将用户的名称和密码 写入在cookie中,

当我们用户下次登录时,会直接从cookie中获取到数据 回显到

login.jsp中 这样的话就不需要用户重复的数据用户名称和密码。

改造servlet

@WebServlet("/login")
public class LoginServlet extends HttpServlet {
    private MayikUsertService mayikUsertService = new MayikUsertService();

    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        // 转发login页面
        req.getRequestDispatcher("login.jsp").forward(req, resp);
    }

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        // 点击登录的时候 获取到用户的参数
        String userName = req.getParameter("userName");
        if (StringUtils.isEmpty(userName)) {
            //转发到错误页面
            req.setAttribute("errorMsg", "用户名称不能够是为空!");
            req.getRequestDispatcher("error.jsp").forward(req, resp);
            return;
        }
        String userPwd = req.getParameter("userPwd");
        // 参数验证
        if (StringUtils.isEmpty(userPwd)) {
            //转发到错误页面
            req.setAttribute("errorMsg", "userPwd不能够是为空!");
            req.getRequestDispatcher("error.jsp").forward(req, resp);
            return;
        }
        // 在调用业务逻辑层
        MayiktUserEntity mayiktUserEntity = mayikUsertService.login(userName, userPwd);
        if (mayiktUserEntity == null) {
            // 用户名称或者密码错误!
            req.setAttribute("errorMsg", "用户名称或者是密码错误!");
            req.getRequestDispatcher("login.jsp").forward(req, resp);
            return;
        }
        // 判断用户是否记住密码
        String rememberPassword = req.getParameter("rememberPassword");
        if ("on".equals(rememberPassword)) {
            // 如果有记住密码则 将密码保存在cookie中
            Cookie userNameCookie = new Cookie("userName", userName);
            Cookie userPwdCookie = new Cookie("userPwd", userPwd);
            resp.addCookie(userNameCookie);
            resp.addCookie(userPwdCookie);
        }
        // 能够db中查询到对象 登录成功了  将用户数据存放在session中
        HttpSession session = req.getSession();
        session.setAttribute("user", mayiktUserEntity);
        // 在转发到首页(重定向到首页)
//        req.getRequestDispatcher("index.jsp").forward(req, resp);
        resp.sendRedirect("index.jsp");
    }
}

改造jsp

<%--
  Created by IntelliJ IDEA.
  User: mayikt
  Date: 2022/6/6
  Time: 17:12
  To change this template use File | Settings | File Templates.
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<!DOCTYPE html>
<html>
<head>
    <title>登录测试页面</title>
    <form action="/mayikt_session_war_exploded/login" method="post">
        <label>用户名: </label><input type="text" name="userName" value="${cookie.userName.value}"/><br>
        <label>密&nbsp码&nbsp: </label><input type="password" name="userPwd" value="${cookie.userPwd.value}"/><br>
        <label>记住密码: </label><input type="checkbox" name="rememberPassword"/><br>
        ${errorMsg}
        <input type="submit" value="登录 "/>
    </form>

</head>
</html>

用户注册

数据库访问层

public class MayikUsertDao {
    
    /**
    * 用户登录成功之后 该方法返回 用户登录成功之后对象
    */
    public MayiktUserEntity login(String userName, String userPwd) {
        ResultSet resultSet = null;
        PreparedStatement preparedStatement = null;
        Connection connection = null;
        try {
            connection = MayiktJdbcUtils.getConnection();
            String loginSql = "select  * from  mayikt_users where userName=? and userPwd=?;";
            preparedStatement = connection.prepareStatement(loginSql);
            preparedStatement.setString(1, userName);
            preparedStatement.setString(2, userPwd);
            resultSet = preparedStatement.executeQuery();
            if (!resultSet.next()) {  // 查询不到用户数据
                return null;
            }
            // 将db中数据 返回给客户端 查询到数据
            Integer id = resultSet.getInt(1);
            String dbUserName = resultSet.getString(2);
            String dbUserPwd = resultSet.getString(3);
            MayiktUserEntity mayiktUserEntity = new MayiktUserEntity(id, dbUserName, dbUserPwd);
            return mayiktUserEntity;
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        } finally {
            MayiktJdbcUtils.closeConnection(resultSet, preparedStatement, connection);
        }
    }
    
    public MayiktUserEntity findByUserName(String userName) {
        ResultSet resultSet = null;
        PreparedStatement preparedStatement = null;
        Connection connection = null;
        try {
            connection = MayiktJdbcUtils.getConnection();
            String loginSql = "select  * from  mayikt_users where userName=?";
            preparedStatement = connection.prepareStatement(loginSql);
            preparedStatement.setString(1, userName);
            resultSet = preparedStatement.executeQuery();
            if (!resultSet.next()) {  // 查询不到用户数据
                return null;
            }
            // 将db中数据 返回给客户端 查询到数据
            Integer id = resultSet.getInt(1);
            String dbUserName = resultSet.getString(2);
            String dbUserPwd = resultSet.getString(3);
            MayiktUserEntity mayiktUserEntity = new MayiktUserEntity(id, dbUserName, dbUserPwd);
            return mayiktUserEntity;
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        } finally {
            MayiktJdbcUtils.closeConnection(resultSet, preparedStatement, connection);
        }
    }
    
    public int register(String userName, String userPwd) {
        Connection connection = null;
        PreparedStatement preparedStatement = null;
        try {
            connection = MayiktJdbcUtils.getConnection();
            // sql语句写的操作 ----加上事务
            MayiktJdbcUtils.beginTransaction(connection); // 开启事务
            String insertSql = "INSERT INTO `mayikt`.`mayikt_users` (`id`, `userName`, `userPwd`) VALUES (null, ?, ?);";
            preparedStatement = connection.prepareStatement(insertSql);
            preparedStatement.setString(1, userName);
            preparedStatement.setString(2, userPwd);
            int result = preparedStatement.executeUpdate();
            // 代码执行没有问题的情况下 则会提交数据
            MayiktJdbcUtils.commitTransaction(connection); // 提交事务
            return result;
        } catch (Exception e) {
            // 程序代码报错之后 是需要回滚事务
            e.printStackTrace();
            MayiktJdbcUtils.rollBackTransaction(connection);// 回滚事务
            return 0;
        } finally {
            MayiktJdbcUtils.closeConnection(preparedStatement, connection);
        }
        
    }
}

业务逻辑层

    public int register(String userName, String userPwd) {
        return mayikUsertDao.register(userName, userPwd);
    }

    public MayiktUserEntity findByUserName(String userName) {
        return mayikUsertDao.findByUserName(userName);
    }

视图层

@WebServlet("/register")
public class RegisterServlet extends HttpServlet {
    private MayikUsertService mayikUsertService = new MayikUsertService();

    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        // 转发到register.jsp
        req.getRequestDispatcher("register.jsp").forward(req, resp);
    }

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        // 转发到注册插入数据
        // 点击注册的时候 获取到用户的参数
        String userName = req.getParameter("userName");
        if (StringUtils.isEmpty(userName)) {
            //转发到错误页面
            req.setAttribute("errorMsg", "用户名称不能够是为空!");
            req.getRequestDispatcher("register.jsp").forward(req, resp);
            return;
        }
        String userPwd = req.getParameter("userPwd");
        // 参数验证
        if (StringUtils.isEmpty(userPwd)) {
            //转发到错误页面
            req.setAttribute("errorMsg", "userPwd不能够是为空!");
            req.getRequestDispatcher("register.jsp").forward(req, resp);
            return;
        }
        // 用户注册之前根据用户名称查询该用户是否存在如果不存在的情况下才可以注册 如果存在的话就无法注册
        MayiktUserEntity dbMayiktUserEntity = mayikUsertService.findByUserName(userName);
        if (dbMayiktUserEntity != null) {
            req.setAttribute("errorMsg", "该用户" + userName + ",在数据库中存在无法重复注册!");
            req.getRequestDispatcher("register.jsp").forward(req, resp);
            return;
        }
        //用户数据注册
        int register = mayikUsertService.register(userName, userPwd);
        if (register <= 0) {
            // 注册失败了   //转发到错误页面
            req.setAttribute("errorMsg", "注册失败!");
            req.getRequestDispatcher("register.jsp").forward(req, resp);
            return;
        }
        // 注册成功之后就直接重定向到登录请求
        resp.sendRedirect("login");
    }
}
<%--
  Created by IntelliJ IDEA.
  User: mayikt
  Date: 2022/6/6
  Time: 17:12
  To change this template use File | Settings | File Templates.
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<!DOCTYPE html>
<html>
<head>
    <title>注册页面</title>
    <form action="/mayikt_session_war_exploded/register" method="post">
        <label>用户名: </label><input type="text" name="userName"/><br>
        <label>密&nbsp&nbsp&nbsp码: </label><input type="password" name="userPwd"/><br>
        <span style="color: red">${errorMsg}</span>
        <input type="submit" value="注册"/>
    </form>

</head>
</html>

图形验证码

图形底层实现原理

java支持根据内容生成图片

abcd 企业实际开发中图形验证码工具类 底层细节我们自己去开发的

1.生成图形验证码内容 abch

2.调用java的api 将我们的该内容 生成一张图片abch

3.将该形验证码内容 abch 存放在session中

用户点击注册时:获取用户输入的图形验证码和session中验证码比对 如果一致的情况下

则开始做注册流程。

图形验证码工具类

/**
 * 工具类,生成随机验证码
 */
public class RandomValidateCode {
    public static final String MAYIKT_RANDOMVALIDATECODE = "RandomValidateCode";// 放到session中的key
    private Random random = new Random();
    private String randString = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";//随机产生的字符串
    private int width = 100;// 图片宽度
    private int height = 26;// 图片高度
    private int lineSize = 40;// 干扰线数量
    private int stringNum = 4;// 随机产生的字符数量

    /*
     * 获得字体
     */
    private Font getFont() {
        return new Font("Fixedsys", Font.CENTER_BASELINE, 18);
    }

    /*
     * 获得颜色
     */
    private Color getRandColor(int fc, int bc) {
        if (fc > 255)
            fc = 255;
        if (bc > 255)
            bc = 255;
        int r = fc + random.nextInt(bc - fc - 16);
        int g = fc + random.nextInt(bc - fc - 14);
        int b = fc + random.nextInt(bc - fc - 18);
        return new Color(r, g, b);
    }

    /**
     * 生成随机图片
     */
    public void getRandcode(HttpServletRequest request, HttpServletResponse response) {
        HttpSession session = request.getSession();
        // BufferedImage类是具有缓冲区的Image类,Image类是用于描述图像信息的类
        BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_BGR);
        Graphics g = image.getGraphics();// 产生Image对象的Graphics对象,该对象可以在图像上进行各种绘制操作
        g.fillRect(0, 0, width, height);
        g.setFont(new Font("Times New Roman", Font.ROMAN_BASELINE, 18));
        g.setColor(getRandColor(110, 133));
        // 绘制干扰线
        for (int i = 0; i <= lineSize; i++) {
            drowLine(g);
        }
        // 绘制随机字符
        String randomString = "";
        for (int i = 1; i <= stringNum; i++) {
            randomString = drowString(g, randomString, i);
        }
        session.removeAttribute(MAYIKT_RANDOMVALIDATECODE);
        session.setAttribute(MAYIKT_RANDOMVALIDATECODE, randomString);
        g.dispose();
        try {
            ImageIO.write(image, "JPEG", response.getOutputStream());// 将内存中的图片通过流动形式输出到客户端
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /*
     * 绘制字符串
     */
    private String drowString(Graphics g, String randomString, int i) {
        g.setFont(getFont());
        g.setColor(new Color(random.nextInt(101), random.nextInt(111), random.nextInt(121)));
        String rand = getRandomString(random.nextInt(randString.length()));
        randomString += rand;
        g.translate(random.nextInt(3), random.nextInt(3));
        g.drawString(rand, 13 * i, 16);
        return randomString;
    }

    /*
     * 绘制干扰线
     */
    private void drowLine(Graphics g) {
        int x = random.nextInt(width);
        int y = random.nextInt(height);
        int xl = random.nextInt(13);
        int yl = random.nextInt(15);
        g.drawLine(x, y, x + xl, y + yl);
    }

    /*
     * 获取随机的字符
     */
    public String getRandomString(int num) {
        return String.valueOf(randString.charAt(num));
    }
}

/**
 * 前台验证码处点击刷新,发送到该servlet的请求,
 * 该servlet调用生成验证码的工具类返回一个图像验证码
 */
@WebServlet(name = "VerifycodeServlet", urlPatterns = "/VerifycodeServlet")
public class VerifycodeServlet extends HttpServlet {
    private static final long serialVersionUID = 1L;

    public void doGet(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        response.setContentType("image/jpeg");//设置相应类型,告诉浏览器输出的内容为图片
        response.setHeader("Pragma", "No-cache");//设置响应头信息,告诉浏览器不要缓存此内容
        //做浏览器兼容
        response.setHeader("Cache-Control", "no-cache");
        response.setDateHeader("Expire", 0);
        RandomValidateCode randomValidateCode = new RandomValidateCode();
        try {
            randomValidateCode.getRandcode(request, response);//输出图片方法
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    public void doPost(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        doGet(request, response);
    }
}

注册jsp加上图形验证码

<%--
  Created by IntelliJ IDEA.
  User: mayikt
  Date: 2022/6/6
  Time: 17:12
  To change this template use File | Settings | File Templates.
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<!DOCTYPE html>
<html>
<head>
    <title>注册页面</title>
    <form action="/mayikt_session_war_exploded/register" method="post">
        <label>用户名: </label><input type="text" name="userName"/><br>
        <label>密&nbsp&nbsp&nbsp码: </label><input type="password" name="userPwd"/><br>
        <label>验证码: </label><input type="text" name="code"/>
        <img id="exchangecode" src="VerifycodeServlet">
        <a id="ecode" href="#">看不清?换一张图片</a><br>
        <span style="color: red">${errorMsg}</span>
        <input type="submit" value="注册"/>
    </form>
    <script type="text/javascript">
        window.onload = function () {
            //获取img标签的对象
            img = document.getElementById("exchangecode");
            img.onclick = function () {
                //加时间戳,避免浏览器缓存
                var date = new Date().getTime()
                img.src = "VerifycodeServlet?" + date;
            }
            //获取a标签的对象
            ec = document.getElementById("ecode");
            ec.onclick = function () {
                //加时间戳
                var date = new Date().getTime()
                img.src = "VerifycodeServlet?" + date;
            }
        }

    </script>
</head>
</html>

注册验证图形验证码

@WebServlet("/register")
public class RegisterServlet extends HttpServlet {
    private MayikUsertService mayikUsertService = new MayikUsertService();

    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        // 转发到register.jsp
        req.getRequestDispatcher("register.jsp").forward(req, resp);
    }

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        // 转发到注册插入数据
        // 点击注册的时候 获取到用户的参数
        String userName = req.getParameter("userName");
        if (StringUtils.isEmpty(userName)) {
            //转发到错误页面
            req.setAttribute("errorMsg", "用户名称不能够是为空!");
            req.getRequestDispatcher("register.jsp").forward(req, resp);
            return;
        }
        String userPwd = req.getParameter("userPwd");
        // 参数验证
        if (StringUtils.isEmpty(userPwd)) {
            //转发到错误页面
            req.setAttribute("errorMsg", "userPwd不能够是为空!");
            req.getRequestDispatcher("register.jsp").forward(req, resp);
            return;
        }
        // 图形验证码  比较 是在 注册之前
        // 比较图形验证码
        String userCode = req.getParameter("code"); // 用户输入的图形验证码
        // 从session中获取图形验证码
        HttpSession session = req.getSession();
        String sessionCode = (String) session.getAttribute(RandomValidateCode.MAYIKT_RANDOMVALIDATECODE);
        if (!sessionCode.equalsIgnoreCase(userCode)) {
            req.setAttribute("errorMsg", "图形验证码不正确,请重新输入!");
            req.getRequestDispatcher("register.jsp").forward(req, resp);
            return;
        }
        // 用户注册之前根据用户名称查询该用户是否存在如果不存在的情况下才可以注册 如果存在的话就无法注册
        MayiktUserEntity dbMayiktUserEntity = mayikUsertService.findByUserName(userName);
        if (dbMayiktUserEntity != null) {
            req.setAttribute("errorMsg", "该用户" + userName + ",在数据库中存在无法重复注册!");
            req.getRequestDispatcher("register.jsp").forward(req, resp);
            return;
        }
        //用户数据注册
        int register = mayikUsertService.register(userName, userPwd);
        if (register <= 0) {
            // 注册失败了   //转发到错误页面
            req.setAttribute("errorMsg", "注册失败!");
            req.getRequestDispatcher("register.jsp").forward(req, resp);
            return;
        }
        // 注册成功之后就直接重定向到登录请求
        resp.sendRedirect("login");
    }
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mfbz.cn/a/47521.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

基于 Graviton2处理器构建容器化基因分析工作负载

概述 相对于基于传统 x86架构的处理器来说&#xff0c;Amazon 设计的基于 ARM 架构的 Graviton 处理器为 EC2中运行的云工作负载提供了更佳的性价比。基于 Graviton2 的实例支持广泛的通用型、突发型、计算优化型、内存优化型、存储优化型和加速计算型工作负载&#xff0c;包括…

数字IC实践项目(7)—CNN加速器的设计和实现(付费项目)

数字IC实践项目&#xff08;7&#xff09;—基于Verilog的CNN加速器&#xff08;付费项目&#xff09; 写在前面的话项目整体框图神经网络框图完整电路框图 项目简介和学习目的软件环境要求 资源占用&板载功耗总结 写在前面的话 项目介绍&#xff1a; 卷积神经网络硬件加速…

【C++ 重要知识点总结】自定义类型-类和结构体

类 类的基本特性 数据抽象和封装继承多态 1 类的构成——抽象 概念 数据抽象是一种依赖于接口和实现的分离的编程技术。类的接口包括用户所能执行的操作&#xff1b;类的实现包括类的数据成员、负责接口实现的函数体以及定义类所需要的的各种私有函数。封装实现了类的接口和实…

数据服务:保障数据安全、提升数据价值的利器

04-08把元数据以及在它基础上的五大应用场景&#xff1a;数据发现&#xff08;数据地图&#xff09;、指标管理、模型设计、数据质量、成本优化&#xff0c;全部讲完。这部分内容对应的就是数据中台OneData 方法论。学完这部分内容&#xff0c;你已了解OneData方法论在企业内部…

【业务功能篇55】Springboot+easyPOI 导入导出

Apache POI是Apache软件基金会的开源项目&#xff0c;POI提供API给Java程序对Microsoft Office格式档案读和写的功能。 Apache POI 代码实现复杂&#xff0c;学习成本较高。 Easypoi 功能如同名字easy,主打的功能就是容易,让一个没见接触过poi的人员 就可以方便的写出Excel导出…

MySQL基础扎实——MySQL中各种数据类型之间的区别

在MySQL中&#xff0c;有各种不同的数据类型可供选择来存储不同类型的数据。下面是一些常见的数据类型以及它们之间的区别&#xff1a; 整数类型&#xff1a; TINYINT&#xff1a;1字节&#xff0c;范围为-128到127或0到255&#xff08;无符号&#xff09;。SMALLINT&#xff1…

项目文档管理的基本指南

项目文档是一种关键的项目管理资源&#xff0c;它可以提供清晰度&#xff0c;保证参与项目的每个人都在同一页面上&#xff0c;从而确保项目按时、按预算完成。 本文将讨论项目文档的重要性、如何在项目中使用项目文档以及选择好合适的项目文档管理软件的技巧。 什么是项目文…

代码随想录算法学习心得 49 | 647.回文子串、516.最长回文子序列...

一、最长回文子序列 链接&#xff1a;力扣 描述&#xff1a;给你一个字符串 s &#xff0c;找出其中最长的回文子序列&#xff0c;并返回该序列的长度。 子序列定义为&#xff1a;不改变剩余字符顺序的情况下&#xff0c;删除某些字符或者不删除任何字符形成的一个序列。 思…

【C++】开源:Boost网络库Asio配置使用

&#x1f60f;★,:.☆(&#xffe3;▽&#xffe3;)/$:.★ &#x1f60f; 这篇文章主要介绍Asio网络库配置使用。 无专精则不能成&#xff0c;无涉猎则不能通。——梁启超 欢迎来到我的博客&#xff0c;一起学习&#xff0c;共同进步。 喜欢的朋友可以关注一下&#xff0c;下次…

Form Generator 扩展子表单组件之表单校验(超详细)

一、form-generator是什么?✨ ⭐️ 🌟 form-generator的作者是这样介绍的:Element UI表单设计及代码生成器,可将生成的代码直接运行在基于Element的vue项目中;也可导出JSON表单,使用配套的解析器将JSON解析成真实的表单。 但目前它提供的组件并不能满足我们在项目中的…

【搜索引擎Solr】Apache Solr 神经搜索

Sease[1] 与 Alessandro Benedetti&#xff08;Apache Lucene/Solr PMC 成员和提交者&#xff09;和 Elia Porciani&#xff08;Sease 研发软件工程师&#xff09;共同为开源社区贡献了 Apache Solr 中神经搜索的第一个里程碑。 它依赖于 Apache Lucene 实现 [2] 进行 K-最近邻…

【Apollo学习笔记】—— Routing模块

Routing模块功能 Apollo的routing模块读取高精地图原始信息&#xff0c;用于根据输入RoutingRequest信息在base_map中选取匹配最近的点作为导航轨迹的起点和终点&#xff0c;读取依据base_map生成的routing_map作为生成topo_graph的&#xff0c;然后通过Astar算法在拓扑图中搜…

SSIS对SQL Server向Mysql数据转发表数据 (一)

开发工具 Visual Stuido 2019 、SSIS、SQL Server 2016、Mysql 8.0.30 1、配置VS2019的添加相应的功能&#xff0c;勾选SQL Server Data Tools,下载就行我用的VS2019版本还需要下载下面几个插件&#xff0c;链接我放在下面了 Microsoft Analysis Services Projects - Visual St…

[linux--->应用层网络通信协议]

文章目录 [TOC](文章目录) 一、应用层通信概念1.协议2.信息接收 二、网络计算器实战应用三、http协议1.基本认识2.宏观理解http3.网站内部跳转4.请求方法5.状态码5.1重定向5.2错误码 6.常见报头7.http会话保持功能8.模拟http协议服务器编程 四、https协议1.加密概念2.加密的作用…

esp32_arduino的开发库安装笔记

1.1 Arduino软件下载与安装 Arduino官网下载地址&#xff1a;https://www.arduino.cc/en/software。 1.2在线安装 选择文件 - 首选项。 在附加开发板管理器网址中添加以下链接中的一个。 (1)Stable release link: https://raw.githubusercontent.com/espressif/arduino-es…

opencv-17 脸部打码及解码

使用掩模和按位运算方式实现的对脸部打码、解码实例 代码如下&#xff1a; import cv2 import numpy as np #读取原始载体图像 lenacv2.imread("lena.png",0) #读取原始载体图像的 shape 值 r,clena.shape masknp.zeros((r,c),dtypenp.uint8) mask[220:400,250:350…

MLagents 多场景并行训练

MLagents多场景并行训练调试总结 摘要 关于Unity MLagents的环境安装已经有了很多的blog和Video&#xff0c;本文针对MLagents的多场景的并行训练&#xff0c;以及在探索过程中出现的问题进行总结。 内容 Unity MLagents 多场景并行训练可以同时设置开多个场景进行并行探索…

账号列表的删除编辑提交

<template><div><plan title"账号列表"><!-- selection-change"handleSelectionChange"添加这个属性就是点击可以得到你想要的value值 --><el-tablestyle"width: 100%":data"list"selection-change"h…

Python 生成随机图片验证码

使用Python生成图片验证码 Python 生成随机图片验证码安装pillow包pillow包生成图片基本用法生成图片验证码 Python 生成随机图片验证码 在写一个Web项目的时候一般要写登录操作&#xff0c;而为了安全起见&#xff0c;现在的登录功能都会加上输入图片验证码这一功能&#xff…

上海VR全景展示,快速了解VR全景拍摄

导语&#xff1a; 随着科技的不断进步&#xff0c;虚拟现实技术的应用日益广泛。在这其中&#xff0c;VR全景图片作为一种数字化助力的全景拍摄方式&#xff0c;正逐渐成为人们关注的焦点。通过数字化技术&#xff0c;VR全景图片能够以360度全方位的视角呈现真实的场景&#x…
最新文章