java生成图片验证码(字母 | 运算 | 汉字)_java 生成图片验证码(包含全是字母、加减乘除、中文)3种方法-程序员宅基地

技术标签: java  

java生成图片验证码(字母|运算|汉字)

 

 

1.先看下以下效果图,ui请勿参考

 

2.后台工具类代码

package com.ljm.verification.util;


import java.awt.Color;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.image.BufferedImage;
import java.util.Random;

import javax.imageio.ImageIO;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;

/**
 * @author lijunming
 * @date 2018/10/26 2:57 PM
 */
public class RandomValidateCode {
    private static int width = 135;// 图片宽
    private static int height = 28;// 图片高
    private static int lineSize = 40;// 干扰线数量
    private static Random random = new Random();

    /**
     * 设置验证码字体
     *
     * @return 字体
     */
    private static Font getFont() {
        return new Font("Fixedsys", Font.CENTER_BASELINE, 18);
    }

    /**
     * 设置验证码颜色
     *
     * @param fc
     * @param bc
     * @return rgb值
     */
    private static 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);
    }

    /**
     * 生成随机验证码,绘制成图片,并且写入结果
     *
     * @param request
     * @param response
     */
    public static 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, 45)); //图片上字的大小
        g.setColor(getRandColor(110, 133));
        // 绘制干扰线
        for (int i = 0; i <= lineSize; i++) {
            drowLine(g);
        }
        // 绘制随机验证吗
        String randomString = getValidate();
        //把生成的验证码存入session,并且1分钟超时失效
        session.setAttribute("verification", result);
        session.setMaxInactiveInterval(60);
        String[] arr = randomString.toString().split("");
        for (int i = 1; i <= arr.length; i++) {
            drowString(g, arr[i - 1], i);
        }
        g.dispose();
        try {
            // 将内存中的图片通过流动形式输出到客户端
            ImageIO.write(image, "JPEG", response.getOutputStream());
        } catch (Exception e) {
            e.printStackTrace();
        }

    }

    /**
     * 绘制图片
     */
    private static String drowString(Graphics g, String randomString, int i) {
        int j = 15;
        if (result instanceof Integer) {
            j = 11;
        }
        g.setFont(getFont());
        g.setColor(new Color(random.nextInt(101), random.nextInt(111), random
                .nextInt(121)));
        g.translate(random.nextInt(3), random.nextInt(3));
        g.translate(random.nextInt(3), random.nextInt(3));
        g.drawString(randomString, j * i, 12);
        return randomString;
    }

    /**
     * 绘制干扰线
     */
    private static 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 static Object result;

    /**
     * 生成字母验证码
     * @return 验证码的内容
     */
    public static String createAB() {
        String[] abc = new String[]{"a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m", "n", "q", "r", "s", "t", "u", "v", "o", "p", "w", "x", "z", "y", "A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "Q", "R", "S", "T", "U", "V", "O", "P", "W", "X", "Y", "Z"};
        Random rd = new Random();
        int index = rd.nextInt(abc.length);
        String one = abc[index];
        index = rd.nextInt(abc.length);
        String two = abc[index];
        index = rd.nextInt(abc.length);
        String three = abc[index];
        index = rd.nextInt(abc.length);
        String four = abc[index];
        result = one + two + three + four;
        String str = one + two + three + four;
        return str;
    }

    /**
     * 生成加减乘除算法验证码
     * 由于2位数的 乘除对某些人算起来麻烦
     * 有兴趣的可以扩展乘法和除法
     * @return 验证码的内容
     */
    public static String createNumber() {
        String fu[] = new String[]{"+", "-", "*", "/"};
        Random rd = new Random();
        int i = rd.nextInt(2);
        int num1 = rd.nextInt(100);
        int num2 = rd.nextInt(100);
        if (i == 0) {
            result = num1 + num2;
        } else {
            //循环保证永远不会出现减法结果是负数
            while (num1 < num2) {
                num1 = rd.nextInt(100);
            }
            result = num1 - num2;
        }
        String str = num1 + fu[i] + num2 + "=";
        return str;
    }

    /**
     * 生产汉字验证吗
     * @return 验证码的内容
     */
    public static String createChinese() {
        String chinese[] = new String[]{
                "勿", "忘", "初", "心", "方", "得", "始", "终", "认", "真", "切", "怂", "从", "一", "而", "终", "英", "雄", "联", "盟"
        };
        Random rd = new Random();
        int index = rd.nextInt(chinese.length);
        String one = chinese[index];
        index = rd.nextInt(chinese.length);
        String two = chinese[index];
        index = rd.nextInt(chinese.length);
        String three = chinese[index];
        index = rd.nextInt(chinese.length);
        String four = chinese[index];
        result = one + two + three + four;
        String str = one + two + three + four;
        return str;
    }

    /**
     * 随机调用验证码
     */
    public static String getValidate() {
        Random rd = new Random();
        int i = rd.nextInt(4);
        if (i == 1) {
            return createAB();
        } else if (i == 2) {
            return createChinese();
        }
        return createNumber();
    }
}

3.Controller

package com.ljm.verification.controller;

import com.ljm.verification.util.RandomValidateCode;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.*;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;

/**
 * @author lijunming
 * @date 2018/10/26 3:57 PM
 */
@Controller
public class TestController {

    /*
     * 去登陆页面
     */
    @GetMapping("/login")
    public String toLogin(){
        return "login";
    }

    /*
     * 登录页面生成验证码
     */
    @RequestMapping(value = "/getVerify.htm")
    public void getVerify(HttpServletRequest request, HttpServletResponse response){
        response.setContentType("image/jpeg");//设置相应类型,告诉浏览器输出的内容为图片
        response.setHeader("Pragma", "No-cache");//设置响应头信息,告诉浏览器不要缓存此内容
        response.setHeader("Cache-Control", "no-cache");
        response.setDateHeader("Expire", 0);
        try {
            RandomValidateCode.getRandcode(request, response);//输出验证码图片方法
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /*
     * 验证输入的验证码是否正确
     */
    @RequestMapping("/checkValidate")
    @ResponseBody
    public String checkValidate(@RequestParam("verification")Object yzm, HttpSession session) throws Exception{
        Object result=session.getAttribute("verification");
        //验证码只有1分钟的有效期,超时返回-1
        if(session.getAttribute("verification")==null){
            return "-1";
        }
        //如果为字母验证码或者    1表示通告,0表示验证失败
        if(result instanceof String){
            if(yzm.toString().toUpperCase().equals(result.toString().toUpperCase())){
                return "1";
            }
            return "0";
            //如果为数字验证码
        }else{
            if(result.toString().equals(yzm)){
                return "1";
            }
        }
        return "0";
    }
}

4.前台页面

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <style type="text/css">
         div{
             text-align: center;
         }
        form{
            margin-top:10%;
        }
    </style>
</head>
<body>
<div >
    <form  action="login"method="post">
        <div id="error"></div>
        账号:<input type="text" name="userName"/><br/>
        密码:<input type="password" name="password" /><br/>
        <img id="yzm" src="getVerify.htm"/> <a href="javascript:replace()">换一张</a><br/>
        验证码<input type="text" name="yzm"/>
        <input type="button" value="登陆" id="login"/>
    </form>
</div>
</body>
<script type="text/javascript" src="jquery-1.8.0.js"></script>
<script type="text/javascript">
    function replace(){
        $("#yzm").attr("src","getVerify.htm?t="+ Math.random());
    }
    $(function(){
        $("#login").click(function(){
            var flags=false;
            var verification=$("[name='yzm']").val();
            $.ajax({
                url:"checkValidate",
                async:false,
                type:"get",
                data:{"verification":verification},
                dataType:"text",
                success:function(flag){
                    if(flag=="-1"){
                        $("#error").html("验证码已超时,请换个","red");
                        flags=true;
                    }else if (flag=="0"){
                        $("#error").html("验证码错误").css("color","red");
                        flags=true;
                    }else{
                        $("#error").html("登陆成功").css("color","green");
                    }
                }
            });
            //如果验证失败则不进后面的登陆
            if(flags){
                return;
            }
        });
    })
</script>
</html>

5.由于小项目,没有用github

百度云下载:https://pan.baidu.com/s/12EwH84ObKKEC0h_n_qssOA 密码:6rtq

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/ming19951224/article/details/83419743

智能推荐

UDP通信_udp虽然是非面向连接的通信,在发送数据之前也需要先调用tcon指令-程序员宅基地

文章浏览阅读532次。代码下载地址:http://download.csdn.net/detail/u011324501/9420980UDP和TCP均指通信协议,那么,既然代表通信协议,UDP和TCP都是建立一个“通道”就可以进行服务端/客户端间的数据收发。它们的区别主要在于:UDP协议是面向非连接(不可靠)的传输协议,也就是不需要与服务端建立连接,就直接将数据发送给服务端,同时,无机制保证这条数据已成功发送给服_udp虽然是非面向连接的通信,在发送数据之前也需要先调用tcon指令

【菜鸟也能玩转OpenGL】OpenGL绘制正方形_ooengl菜鸟-程序员宅基地

文章浏览阅读1.2w次,点赞7次,收藏24次。本系列文章由 莫问 出品,转载请注明出处。文章链接:http://blog.csdn.net/mni2005/article/details/27228111作者:莫问(mni2005) 邮箱:[email protected]_ooengl菜鸟

linux sh脚本无法执行_sh脚本无法直接运行-程序员宅基地

文章浏览阅读1.9k次。linux 执行sh文件_sh脚本无法直接运行

Postgresql: 动态SQL语句中不能使用Select into?_postgres 使用string_agg 不能select into 到另一个字段-程序员宅基地

文章浏览阅读7.9k次。下面是出错的存储过程:CREATE or Replace FUNCTION func_getnextbigid( tablename varchar(240), idname varchar(20) default 'id')RETURNS bigint AS $funcbody$Declare sqlstring varchar(240); currentId bigint;Begin sqlstring:= 'select max("' ||_postgres 使用string_agg 不能select into 到另一个字段

Linux环境下的C语言环境配置及安装技巧-程序员宅基地

文章浏览阅读2.7k次。本地环境设置如果您想要设置 C 语言环境,您需要确保电脑上有以下两款可用的软件,文本编辑器和 C 编译器。文本编辑器这将用于输入您的程序。文本编辑器包括 Windows Notepad、OS Edit command、Brief、Epsilon、EMACS 和 vim/vi。文本编辑器的名称和版本在不同的操作系统上可能会有所不同。例如,Notepad 通常用于 Windows 操作系统上,vim/..._linux .exe需要什么环境 c

开始使用Keepass 管理密码-程序员宅基地

文章浏览阅读149次。其实很早以前就用过KeePass Password Safe ,不过没有贯彻下去 后来管理密码的方式有下面四种: 一是不管,后果是惨痛的,也浪费了更多的时间 用一个txt 文件,不过密码是用助记码写的,防止别人 还有是发一封邮件到gmail 中,gmail中搜索功能不错 最常用的是LastPass,很不错,不过害怕突然有一天这一点云服务不能用...

随便推点

postgre报错:RETURNING “id“ was aborted: ERROR: null value in column “id“ violates not-null constraint_null value in column "id" violates not-null constr-程序员宅基地

文章浏览阅读1.3w次,点赞6次,收藏18次。我在使用 postgre 插入数据的时候报了一个错:RETURNING "id" was aborted: ERROR: null value in column "id" violates not-null constraint表的创建 sql 语句如下:CREATE TABLE city( id int8 PRIMARY KEY NOT NULL , name varchar(30) NOT NULL , gov_area VARCHAR(100) NOT NULL );后来我_null value in column "id" violates not-null constraint

buuctf-misc练习(2)_buuctf在线评的misc-程序员宅基地

文章浏览阅读218次。BUUCTFLSB文件中的秘密wiresharkrarqrzip伪加密ningen被嗅探的能量LSB既然是LSB使用Stegsolve得到二维码,扫一扫即可flag是:flag{1sb_i4_s0_Ea4y}文件中的秘密右键属性详细信息flag是:flag{870c5a72806115cb5439345d8b014396}wireshark给了提示是登录登录方法,就直接过滤搜http.request.method==POSTflag是:flag{ffb7567a1d4f4_buuctf在线评的misc

【vue设计与实现】渲染器 1-渲染器与相应系统的结合&渲染器基本概念_innerhtml和渲染器-程序员宅基地

文章浏览阅读347次。由于首次渲染时已经把oldVnode渲染到container内了,所以再次调用renderer.render函数并尝试渲染newVnode的时候,就不能简单的执行挂载动作了。这里,先暂时将渲染器限定在DOM平台,既然渲染器用来渲染真实DOM元素,那么严格来说,下面的函数就是一个合格的渲染器。渲染器就是用来执行渲染任务的,渲染器不仅能够渲染真是DOM元素,还是框架跨平台能力的关键。关于这里为什么用了一个createRender的函数,其实渲染器和渲染的概念是不同的,这就是响应系统和渲染器之间的关系。..._innerhtml和渲染器

iOS JSON与Object之间的映射 ObjectMapper For Swift_swift json到object-程序员宅基地

文章浏览阅读8.9k次。在实际项目开发过程中,很多时候移动终端设备都要与服务器进行数据交互。两者之间的数据格式通常为 JSON 和 XML。而 JSON 数据格式因其简单、易操作、高效率的特点而被广大开发者所使用。在项目开发中,根据不同的业务我们需要创建不同 Model。在成功接收到从服务器返回过来的数据后,我们可以将 JSON 数据当作一个个的键值对然后进行解析,虽然这也算是一种解决方式,但一定程度上加大开发者的工作量。_swift json到object

Linux svn 导出diff修改文件命令_svn如何批量生成diff-程序员宅基地

文章浏览阅读1.1k次。svn st -q 查看在当前目录下的所有修改过的文件。svn diff ./ 查看文件修改内容svn diff > modify.dff ./ 导出当前目录下的所有修改文件diff文件, modify.diff : 自定义命名文件。就是修改的内容文件。svn diff a...._svn如何批量生成diff

在ROS中使用相机_gazebo相机标定板-程序员宅基地

文章浏览阅读1w次,点赞7次,收藏76次。在机器人中经常使用相机,在导航或者抓取规划时需要解析相机数据,需要理解相机图像的模式和相关的标签以及坐标系。本文介绍ROS中相机坐标的变换、相机标定、使用OpenCV进行简单的图像处理。投影变换到相机坐标相机内部校准标定立体相机标定在ROS中使用OpenCV使用OpenCV寻找彩色像素点查找边缘投影变换到相机坐标将图像与空间坐标相关联的投影变换的必要步骤是..._gazebo相机标定板

推荐文章

热门文章

相关标签