基于Servlet的验证码登陆demo

验证码技术在web项目中是十分常见的技术,它可以防止:恶意破解密码、刷票、论坛灌水,某个黑客对某一个特定注册用户用特定程序暴力破解方式进行不断的登录尝试等,本文利用比较简易的方式实现了这个功能。

1.准备工作

这里采用的maven构建的Java web项目,所以需要先安装servlet容器,使得我们的web项目有运行环境;至于使用maven构建Java web项目,这里就不演示了。

1.1 安装tomcat

tomcat在Java领域是比较常见的web应用服务器,同时也是一个很好的servlet容器。这里就使用tomcat作为web项目的运行环境。

1.官网下载tomcat安装包
访问tomcat官网,选择合适的版本下载,这里我就选择tomcat 8, 下载地址:tomcat官网
在这里插入图片描述
2.将下载的压缩包解压到目标文件夹中
这里给一个小建议,像这种下载的第三方工具软件最好放在同一个文件夹中,便于管理,这里我就放在了devTools文件夹下。

解压
tar -zxvf apache-tomcat-8.5.78.tar.gz

在这里插入图片描述

3.配置环境变量

vim .bash_profile
添加
export T2_HOME=/Users/xuzhi/devTools/apache-tomcat-8.5.78
export PATH=$PATH:$T2_HOME/bin

使用如下命令使该文件生效

source .bash_profile

在这里插入图片描述
4.启动与停止tomcat

startup.sh

shutdown.sh

在这里插入图片描述
在浏览器里输入:http://localhost:8080,出现如下画面即代表启动成功。
在这里插入图片描述
不同的系统,安装过程会有细微的差别,Mac和Linux基本一样,Windows系统会有些许差别,但是大体过程是一样的。

2.构建Java web项目

这里使用maven构建Java web项目,具体的过程这里就不具体演示了,出现如下画面就表示构建成功了。
在这里插入图片描述
启动项目,检查项目是否能正常运行;这也是一个好习惯,先确保项目正确构建了,然后再开始写代码,将一些基础错误消灭在开始,不至于之后出现各种错误而不知所措。

先在idea中集成tomcat环境,然后部署项目,启动项目。
在这里插入图片描述
在这里插入图片描述

在这里插入图片描述
在这里插入图片描述
添加一个tomcat server,出现如下画面表示项目部署成功。
在这里插入图片描述
在这里插入图片描述
在idea中启动项目,然后在浏览器里输入:http://localhost:8080,出现如下画面即代表项目构建没有任何问题。
在这里插入图片描述
在这里插入图片描述
好了,到现在项目构建成功,idea中集成tomcat也成功了,项目部署也成功了。这里插个题外话,如果使用Spring Boot项目,会方便不少的。但是基础知识也是需要学习和练习的,所以这里使用了比较基础的Java Web项目结构。

3.项目结构

本demo的项目结构如下图所示,这也是一个标准的Java Web项目结构。
在这里插入图片描述

4.实战开始

做了这么多,才只是把基本工作做完,这里才是正式开始实战了。

4.1 添加依赖

本demo只需要添加servlet依赖即可。
pom.xml

<dependency>
	<groupId>javax.servlet</groupId>
    <artifactId>javax.servlet-api</artifactId>
    <version>4.0.1</version>
    <scope>provided</scope>
</dependency>

4.2 创建Captcha类

package com.picacho.common;

import javax.imageio.ImageIO;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.*;
import java.util.Random;

/**
 * 验证码生成器
 */
public class Captcha {
    private int width = 240;
    private int height = 100;

    // 验证码字符个数
    private int codeNum = 4;
    // 验证码干扰线个数
    private int lineNum = 20;
    // 验证码字符串
    private String code = null;
    // 设置图片缓存
    private BufferedImage bufferedImg = null;

    private char[] codeQue = {'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I',
            'J', 'K', 'M', 'N', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X',
            'Y', 'Z', '2', '3', '4', '5', '6', '7', '8', '9'};

    // 生成随机数
    private Random random = new Random();

    /**
     * 无参构造器
     */
    public Captcha(){
        this.createCode();
    }
    /**
     * 有参构造器
     */
    public Captcha(int width, int height){
        this.width = width;
        this.height = height;
        this.createCode();
    }

    /**
     * 有参构造器2
     */
    public Captcha(int width, int height, int codeNum, int lineNum){
        this.width = width;
        this.height = height;
        this.codeNum = codeNum;
        this.lineNum = lineNum;
        this.createCode();
    }

    public String getCode(){
        return code;
    }

    public void write(OutputStream os) throws IOException {
        ImageIO.write(bufferedImg,"png", os);
        os.close();
    }

    /**
     * 生成验证码字符串
     */
    public void createCode(){
        int codeX = 0;
        int fontHeight = 0;
        // 字体高度
        fontHeight = height - 20;
        codeX = width / (codeNum + 3);

        // 图像buffer
        bufferedImg = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
        Graphics2D g = bufferedImg.createGraphics();

        // 填充背景为白色
        g.setColor(Color.WHITE);
        g.fillRect(0 , 0, width, height);

        // 创建字体
        ImgFontByte imgFont = new ImgFontByte();
        Font font = imgFont.getFont(fontHeight);
        g.setFont(font);

        // 绘制干扰线
        for(int i = 0; i < lineNum; i++){
            int xp = getRandomNumber(width/2);
            int yp = getRandomNumber(height/2);
            int xd = xp + getRandomNumber(width*10);
            int yd = yp + getRandomNumber(height*10);
            g.setColor(getRandomColor());
            g.drawLine(xp, yp, xd, yd);
        }

        StringBuffer randomCode = new StringBuffer();
        // 在字符队列中,产生随机验证码字符
        for(int i = 0; i < codeNum; i++){
            String strRand = String.valueOf(codeQue[random.nextInt(codeQue.length)]);
            // 设置字体随机颜色
            g.setColor(getRandomColor());
            // 设置字体位置尽量在图片中间
            g.drawString(strRand, (i+1)*codeX, getRandomNumber(height/2)+50);
            randomCode.append(strRand);
        }
        code = randomCode.toString();
    }

    /**
     * 获取随机数
     */
    private int getRandomNumber(int number){
        return random.nextInt(number);
    }

    /**
     * 获取随机颜色
     */
    private Color getRandomColor(){
        int r = getRandomNumber(255);
        int g = getRandomNumber(255);
        int b = getRandomNumber(255);
        return  new Color(r, g, b);
    }

    /**
     * 字体样式内部类
     */
   class ImgFontByte{
        /**
         * 获取字体
         * @param fontHeight
         * @return
         */
        public Font getFont(int fontHeight){
            try{
                Font baseFont = Font.createFont(Font.TRUETYPE_FONT, new ByteArrayInputStream(hex2byte(getFontByteStr())));
                return baseFont.deriveFont(Font.PLAIN, fontHeight);
            }catch (Exception e){
                return new Font("Arial", Font.PLAIN, fontHeight);
            }
        }

        /**
         * 将字符串转化为字节数组
         */
        private byte[] hex2byte(String str){
            if(str == null){
                return null;
            }
            str = str.trim();
            int len = str.length();
            if(len == 0 || len % 2 == 1){
                return null;
            }
            byte[] b = new byte[len/2];
            try{
                for(int i = 0; i < str.length(); i += 2){
                    b[i / 2] = (byte)Integer.decode("0x" + str.substring(i, i+2)).intValue();
                }
                return b;
            }catch (Exception e){
                return null;
            }
        }

        /**
         * 获取HexString.txt文件的内容
         */
        private String getFontByteStr(){
            // 获取类路径
            String path = this.getClass().getClassLoader().getResource("").getPath();
            // /Users/xuzhi/java-projects/java-projects-captcha-demo/target/classes/
            String pathName = path + "HexString.txt";
            File file = new File(pathName);
            String tempStr = null;
            BufferedReader reader = null;
            try {
                reader = new BufferedReader(new FileReader(file));
                tempStr = reader.readLine();
            } catch (Exception e) {
                e.printStackTrace();
            }finally {
                if(reader != null){
                    try {
                        reader.close();
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
            }
            return tempStr;
        }


    }

}

4.3 创建CaptchaServlet类

public class CaptchaServlet extends HttpServlet {

    @Override
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        // 设置图片格式
        response.setContentType("image/jpeg");
        // 禁止图片缓存
        response.setHeader("Pragma", "no-cache");
        response.setHeader("Cache-Control", "no-cache");
        // 在代理服务器端防止缓冲
        response.setDateHeader("Expires", 0);

        Captcha captcha = new Captcha();
        // 将验证码添加到session
        request.getSession().setAttribute("captcha", captcha.getCode());

        captcha.write(response.getOutputStream());
    }

    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException{
        this.doPost(request, response);
    }
}

4.4 创建LoginServlet类

public class LoginServlet extends HttpServlet {
    
    @Override
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException{
        request.setCharacterEncoding("UTF-8");
        
        response.setCharacterEncoding("UTF-8");
        response.setHeader("Content-type", "text/html;charset=UTF-8");
        
        // 从session中获取验证码
        String captcha = (String)request.getSession().getAttribute("captcha");
        // 从表单中获取用户名密码
        String username = request.getParameter("username");
        String password = request.getParameter("password");
        PrintWriter printWriter = response.getWriter();
        // 判断验证码是否正确
        if(!request.getParameter("captcha").equals(captcha.toLowerCase())){
            printWriter.write("验证码错误");
            return;
        }
        // 模拟密码验证
        if("admin".equals(username) && "123456".equals(password)){
            printWriter.write("登陆成功");
        }else{
            printWriter.write("登陆失败");
        }
    }
    
    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException{
        this.doPost(request, response);
    }
}

4.5 配置web.xml

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee"
         xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
         version="2.5">
  <servlet>
    <servlet-name>captchaServlet</servlet-name>
    <servlet-class>com.picacho.servlet.CaptchaServlet</servlet-class>
  </servlet>
  <servlet-mapping>
    <servlet-name>captchaServlet</servlet-name>
    <url-pattern>/captchaServlet</url-pattern>
  </servlet-mapping>
  <servlet>
    <servlet-name>loginServlet</servlet-name>
    <servlet-class>com.picacho.servlet.LoginServlet</servlet-class>
  </servlet>
  <servlet-mapping>
    <servlet-name>loginServlet</servlet-name>
    <url-pattern>/loginServlet</url-pattern>
  </servlet-mapping>
  <welcome-file-list>
    <welcome-file>Captcha.html</welcome-file>
  </welcome-file-list>

</web-app>

4.6 创建Captcha.html页面

<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8" />
    <title>Captcha</title>
    <style>
        #img {
            width: 120px;
            height: 60px;
        }
        label {
            display: inline-block;
            width: 70px;
            text-align: right;
        }
    </style>
</head>
<body>
<form action="/loginServlet" method="post">
    <label>用户名:</label><input name="username" />
    <br />
    <label>密码:</label><input name="password" type="password" />
    <br />
    <label>验证码:</label><input name="captcha" />
    <br />
    <img id="img" src="/captchaServlet" />
    <a onclick="refresh()" href="javascript:void(0);">看不清楚?</a>
    <button type="submit">登录</button>
</form>
</body>
<script>
    function refresh() {
        document.getElementById('img').src =
            '/captchaServlet?random=' + Math.random();
    }
</script>
</html>

4.7 验证效果

启动项目,在浏览器输入http://localhost:8080/captcha.html,出现如下画面表示成功。
在这里插入图片描述
输入用户名与密码:damin 123456 进行验证。
在这里插入图片描述
在这里插入图片描述
到这里这个demo案例就基本完工了。这里我们是自己完成了验证码的生成,实际上可以采用开源的工具完成这项功能,下面我们就用开源工具完成上面的案例。

5.补充

5.1 添加依赖

<!-- 验证码 -->
<dependency>
	<groupId>com.github.whvcse</groupId>
    <artifactId>easy-captcha</artifactId>
    <version>1.6.2</version>
</dependency>

5.2 实战

public class CaptchaServlet1 extends HttpServlet {

    @Override
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        response.setHeader("Cache-Control", "no-store");
        response.setHeader("Pragma", "no-cache");
        response.setDateHeader("Expires", 0);
        response.setContentType("image/gif");

        // 设置三个参数, 宽, 高, 位数
        GifCaptcha captcha = new GifCaptcha(75, 30, 4);
        // 设置类型 数字和字母混合
        captcha.setCharType(Captcha.TYPE_DEFAULT);
        // 设置字体
        captcha.setCharType(Captcha.FONT_9);

        // 将验证码输入session中
        request.getSession().setAttribute("captcha", captcha.text().toLowerCase());
        // 输出图片流
        captcha.out(response.getOutputStream());
    }

    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException{
        this.doPost(request, response);
    }
}
public class LoginServlet1 extends HttpServlet {
    @Override
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        request.setCharacterEncoding("UTF-8");

        response.setCharacterEncoding("UTF-8");
        response.setHeader("Content-type", "text/html;charset=UTF-8");

        // 从session中获取验证码
        HttpSession captchaSession = request.getSession();
        String captcha = captchaSession.getAttribute("captcha") + "";

        // 从表单中获取用户名密码
        String username = request.getParameter("username");
        String password = request.getParameter("password");
        PrintWriter printWriter = response.getWriter();
        // 判断验证码是否正确
        String captcha1 = request.getParameter("captcha");
        if(!request.getParameter("captcha").equals(captcha.toLowerCase())){
            printWriter.write("验证码错误");
            return;
        }

        // 模拟密码验证
        if("admin".equals(username) && "123456".equals(password)){
            printWriter.write("登陆成功" + captcha);
            // printWriter.write(captcha);
        }else{
            printWriter.write("登陆失败");
        }
    }

    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException{
        this.doPost(request, response);
    }
}
<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8" />
    <title>Captcha</title>
    <style>
        #img {
            width: 120px;
            height: 60px;
        }
        label {
            display: inline-block;
            width: 70px;
            text-align: right;
        }
    </style>
</head>
<body>
<form action="/loginServlet1" method="post">
    <label>用户名:</label><input name="username" />
    <br />
    <label>密码:</label><input name="password" type="password" />
    <br />
    <label>验证码:</label><input name="captcha" />
    <br />
    <img id="img" src="/captchaServlet1" />
    <a onclick="refresh()" href="javascript:void(0);">看不清楚?</a>
    <button type="submit">登录</button>
</form>
</body>
<script>
    function refresh() {
        document.getElementById('img').src =
            '/captchaServlet1?random=' + Math.random();
    }
</script>
</html>
<servlet>
    <servlet-name>captchaServlet1</servlet-name>
    <servlet-class>com.picacho.servlet.CaptchaServlet1</servlet-class>
  </servlet>
  <servlet-mapping>
    <servlet-name>captchaServlet1</servlet-name>
    <url-pattern>/captchaServlet1</url-pattern>
  </servlet-mapping>
  <servlet>
    <servlet-name>loginServlet1</servlet-name>
    <servlet-class>com.picacho.servlet.LoginServlet1</servlet-class>
  </servlet>
  <servlet-mapping>
    <servlet-name>loginServlet1</servlet-name>
    <url-pattern>/loginServlet1</url-pattern>
  </servlet-mapping>

5.3 验证结果

在这里插入图片描述
在这里插入图片描述
这里使用了第三方的验证码生成工具替代了前面自己写的验证码生成类;很显然,不用自己造轮子还是要更轻松些。所以既要会造轮子,又要会用轮子,才是我们学习前进的方向。

demo源码下载地址:demo源码

  • 1
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
好的,以下是一个简单的基于servlet登陆界面的实现: 首先,我们需要创建一个 HTML 页面作为登陆界面,包含用户名和密码的输入框以及提交按钮。可以参考以下代码: ```html <!DOCTYPE html> <html> <head> <title>Login Page</title> </head> <body> <h2>Login Page</h2> <form method="post" action="login"> <label for="username">Username:</label> <input type="text" id="username" name="username"><br><br> <label for="password">Password:</label> <input type="password" id="password" name="password"><br><br> <input type="submit" value="Login"> </form> </body> </html> ``` 接下来,我们需要创建一个 Java Servlet 来处理用户提交的表单数据并验证用户身份。可以参考以下代码: ```java import java.io.IOException; import javax.servlet.ServletException; import javax.servlet.annotation.WebServlet; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; @WebServlet("/login") public class LoginServlet extends HttpServlet { private static final long serialVersionUID = 1L; public LoginServlet() { super(); } protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { String username = request.getParameter("username"); String password = request.getParameter("password"); // 进行用户身份验证 if("admin".equals(username) && "admin123".equals(password)) { // 验证成功,重定向到欢迎页面 response.sendRedirect("welcome.jsp"); } else { // 验证失败,返回登陆页面并显示错误信息 request.setAttribute("errorMessage", "Invalid username or password"); request.getRequestDispatcher("login.jsp").forward(request, response); } } } ``` 在上述代码中,我们首先通过 `request.getParameter()` 方法获取到用户提交的用户名和密码。然后,我们进行用户身份验证,如果验证成功,则使用 `response.sendRedirect()` 方法重定向到欢迎页面;如果验证失败,则使用 `request.getRequestDispatcher()` 方法返回到登陆页面并在页面上显示错误信息。 最后,我们需要创建一个欢迎页面作为登陆成功后的页面。可以参考以下代码: ```html <!DOCTYPE html> <html> <head> <title>Welcome Page</title> </head> <body> <h2>Welcome, admin!</h2> <p>You have successfully logged in.</p> </body> </html> ``` 将以上代码保存为 `login.jsp` 和 `welcome.jsp` 文件,并将它们放在 Web 应用程序的根目录下的 `WEB-INF` 文件夹中。接着,我们需要在 `web.xml` 文件中配置 Servlet 和 JSP 页面的映射关系。可以参考以下代码: ```xml <web-app> <servlet> <servlet-name>LoginServlet</servlet-name> <servlet-class>LoginServlet</servlet-class> </servlet> <servlet-mapping> <servlet-name>LoginServlet</servlet-name> <url-pattern>/login</url-pattern> </servlet-mapping> <welcome-file-list> <welcome-file>login.jsp</welcome-file> </welcome-file-list> </web-app> ``` 在上述代码中,我们首先定义了一个名为 `LoginServlet` 的 Servlet,并将它映射到路径 `/login`。然后,在 `welcome-file-list` 中定义了默认的欢迎页面为 `login.jsp`。 现在,我们可以部署和运行这个 Web 应用程序,并通过浏览器访问登陆页面,输入正确的用户名和密码后,将会跳转到欢迎页面。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

picacho_pkq

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值