服务器之家:专注于VPS、云服务器配置技术及软件下载分享
分类导航

PHP教程|ASP.NET教程|Java教程|ASP教程|编程技术|正则表达式|C/C++|IOS|C#|Swift|Android|VB|R语言|JavaScript|易语言|vb.net|

服务器之家 - 编程语言 - Java教程 - Java实现动态验证码生成

Java实现动态验证码生成

2022-11-17 13:05Keson Z Java教程

这篇文章主要为大家详细介绍了Java实现动态验证码生成,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下

本文实例为大家分享了Java动态验证码生成的具体代码,供大家参考,具体内容如下

说明:今天给大家来带来一个自动生成验证码的处理方法。验证码的出现有效减少了注入灌水以及破解密码等恶意操作,提高了系统运行的流畅性,保护了系统用户的隐私安全,具体实现方法如下:

1.首先我们先编写一个专门的验证码生成工具类,该工具类代码如下:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
package com.ordering.util;
 
import java.awt.Color;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.image.BufferedImage;
import java.util.Random;
 
/**
 * 验证码生成器
 * @author 诺坎普10号
 * @date 2020-2-25
 */
public class CpachaUtil {
    
    /**
     * 验证码来源
     */
    final private char[] code = {
        '2', '3', '4', '5', '6', '7', '8', '9',
        'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j',
        'k', 'm', 'n', 'p', 'q', 'r', 's', 't', 'u', 'v'
        'w', 'x', 'y', 'z', 'A', 'B', 'C', 'D', 'E', 'F',
        'G', 'H', 'J', 'K', 'L', 'M', 'N', 'P', 'Q', 'R',
        'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z'
    };
    /**
     * 字体
     */
    final private String[] fontNames = new String[]{
            "黑体", "宋体", "Courier", "Arial"
            "Verdana", "Times", "Tahoma", "Georgia"};
    /**
     * 字体样式
     */
    final private int[] fontStyles = new int[]{
            Font.BOLD, Font.ITALIC|Font.BOLD
    };
    
    /**
     * 验证码长度
     * 默认4个字符
     */
    private int vcodeLen = 4;
    /**
     * 验证码图片字体大小
     * 默认17
     */
    private int fontsize = 21;
    /**
     * 验证码图片宽度
     */
    private int width = (fontsize+1)*vcodeLen+10;
    /**
     * 验证码图片高度
     */
    private int height = fontsize+12;
    /**
     * 干扰线条数
     * 默认3条
     */
    private int disturbline = 3;
    
    
    public CpachaUtil(){}
    
    /**
     * 指定验证码长度
     * @param vcodeLen 验证码长度
     */
    public CpachaUtil(int vcodeLen) {
        this.vcodeLen = vcodeLen;
        this.width = (fontsize+1)*vcodeLen+10;
    }
    
    /**
     * 指定验证码长度、图片宽度、高度
     * @param vcodeLen
     * @param width
     * @param height
     */
    public CpachaUtil(int vcodeLen,int width,int height) {
        this.vcodeLen = vcodeLen;
        this.width = width;
        this.height = height;
    }
    
    /**
     * 生成验证码图片
     * @param vcode 要画的验证码
     * @param drawline 是否画干扰线
     * @return
     */
    public BufferedImage generatorVCodeImage(String vcode, boolean drawline){
        //创建验证码图片
        BufferedImage vcodeImage = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
        Graphics g = vcodeImage.getGraphics();
        //填充背景色
        g.setColor(new Color(246, 240, 250));
        g.fillRect(0, 0, width, height);
        if(drawline){
            drawDisturbLine(g);
        }
        //用于生成伪随机数
        Random ran = new Random();
        //在图片上画验证码
        for(int i = 0;i < vcode.length();i++){
            //设置字体
            g.setFont(new Font(fontNames[ran.nextInt(fontNames.length)], fontStyles[ran.nextInt(fontStyles.length)], fontsize));
            //随机生成颜色
            g.setColor(getRandomColor());
            //画验证码
            g.drawString(vcode.charAt(i)+"", i*fontsize+10, fontsize+5);
        }
        //释放此图形的上下文以及它使用的所有系统资源
        g.dispose();
        
        return vcodeImage;
    }
    /**
     * 获得旋转字体的验证码图片
     * @param vcode
     * @param drawline 是否画干扰线
     * @return
     */
    public BufferedImage generatorRotateVCodeImage(String vcode, boolean drawline){
        //创建验证码图片
        BufferedImage rotateVcodeImage = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
        Graphics2D g2d = rotateVcodeImage.createGraphics();
        //填充背景色
        g2d.setColor(new Color(246, 240, 250));
        g2d.fillRect(0, 0, width, height);
        if(drawline){
            drawDisturbLine(g2d);
        }
        //在图片上画验证码
        for(int i = 0;i < vcode.length();i++){
            BufferedImage rotateImage = getRotateImage(vcode.charAt(i));
            g2d.drawImage(rotateImage, null, (int) (this.height * 0.7) * i, 0);
        }
        g2d.dispose();
        return rotateVcodeImage;
    }
    /**
     * 生成验证码
     * @return 验证码
     */
    public String generatorVCode(){
        int len = code.length;
        Random ran = new Random();
        StringBuffer sb = new StringBuffer();
        for(int i = 0;i < vcodeLen;i++){
            int index = ran.nextInt(len);
            sb.append(code[index]);
        }
        return sb.toString();
    }
    /**
     * 为验证码图片画一些干扰线
     * @param g 
     */
    private void drawDisturbLine(Graphics g){
        Random ran = new Random();
        for(int i = 0;i < disturbline;i++){
            int x1 = ran.nextInt(width);
            int y1 = ran.nextInt(height);
            int x2 = ran.nextInt(width);
            int y2 = ran.nextInt(height);
            g.setColor(getRandomColor());
            //画干扰线
            g.drawLine(x1, y1, x2, y2);
        }
    }
    /**
     * 获取一张旋转的图片
     * @param c 要画的字符
     * @return
     */
    private BufferedImage getRotateImage(char c){
        BufferedImage rotateImage = new BufferedImage(height, height, BufferedImage.TYPE_INT_ARGB);
        Graphics2D g2d = rotateImage.createGraphics();
        //设置透明度为0
        g2d.setColor(new Color(255, 255, 255, 0));
        g2d.fillRect(0, 0, height, height);
        Random ran = new Random();
        g2d.setFont(new Font(fontNames[ran.nextInt(fontNames.length)], fontStyles[ran.nextInt(fontStyles.length)], fontsize));
        g2d.setColor(getRandomColor());
        double theta = getTheta();
        //旋转图片
        g2d.rotate(theta, height/2, height/2);
        g2d.drawString(Character.toString(c), (height-fontsize)/2, fontsize+5);
        g2d.dispose();
        
        return rotateImage;
    }
    /**
     * @return 返回一个随机颜色
     */
    private Color getRandomColor(){
        Random ran = new Random();
        return new Color(ran.nextInt(220), ran.nextInt(220), ran.nextInt(220)); 
    }
    /**
     * @return 角度
     */
    private double getTheta(){
        return ((int) (Math.random()*1000) % 2 == 0 ? -1 : 1)*Math.random();
    }
 
    /**
     * @return 验证码字符个数
     */
    public int getVcodeLen() {
        return vcodeLen;
    }
    /**
     * 设置验证码字符个数
     * @param vcodeLen
     */
    public void setVcodeLen(int vcodeLen) {
        this.width = (fontsize+3)*vcodeLen+10;
        this.vcodeLen = vcodeLen;
    }
    /**
     * @return 字体大小
     */
    public int getFontsize() {
        return fontsize;
    }
    /**
     * 设置字体大小
     * @param fontsize
     */
    public void setFontsize(int fontsize) {
        this.width = (fontsize+3)*vcodeLen+10;
        this.height = fontsize+15;
        this.fontsize = fontsize;
    }
    /**
     * @return 图片宽度
     */
    public int getWidth() {
        return width;
    }
    /**
     * 设置图片宽度
     * @param width
     */
    public void setWidth(int width) {
        this.width = width;
    }
    /**
     * @return 图片高度
     */
    public int getHeight() {
        return height;
    }
    /**
     * 设置图片高度
     * @param height 
     */
    public void setHeight(int height) {
        this.height = height;
    }
    /**
     * @return 干扰线条数
     */
    public int getDisturbline() {
        return disturbline;
    }
    /**
     * 设置干扰线条数
     * @param disturbline
     */
    public void setDisturbline(int disturbline) {
        this.disturbline = disturbline;
    }
    
}

2.然后在页面端定义一个显示验证码的控件,再写一个js函数来对后台动态生成验证码方法进行调用,主要代码如下:

?
1
2
3
4
5
6
7
8
9
<div class="login-center-input-text">验证码</div>
<img id="cpacha-img" title="点击切换验证码" style="cursor:pointer;" src="get_cpacha?vl=4&w=150&h=40&type=loginCpacha" width="110px" height="30px" onclick="changeCpacha()">
</div>
 
<script type="text/javascript">
function changeCpacha(){
        $("#cpacha-img").attr("src",'get_cpacha?vl=4&w=150&h=40&type=loginCpacha&t=' + new Date().getTime());
    }
</script>

3.控制器中代码如下:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
/**
     * 本系统所有的验证码均采用此方法
    
     * @param vcodeLen
     * @param width
     * @param height
     * @param cpachaType:用来区别验证码的类型,传入字符串
     * @param request
     * @param response
     */
    @RequestMapping(value = "/get_cpacha", method = RequestMethod.GET)
    public void generateCpacha(@RequestParam(name = "vl", required = false, defaultValue = "4") Integer vcodeLen,
            @RequestParam(name = "w", required = false, defaultValue = "100") Integer width,
            @RequestParam(name = "h", required = false, defaultValue = "30") Integer height,
            @RequestParam(name = "type", required = true, defaultValue = "loginCpacha") String cpachaType,
            HttpServletRequest request, HttpServletResponse response) {
        //根据页面传入的验证码长度、图片宽度以及图片长度来实例化验证码实体
        CpachaUtil cpachaUtil = new CpachaUtil(vcodeLen, width, height);
        //生成验证码
        String generatorVCode = cpachaUtil.generatorVCode();
        //把验证码存入session
        request.getSession().setAttribute(cpachaType, generatorVCode);
        //根据验证码生成相应的验证码图片
        BufferedImage generatorRotateVCodeImage = cpachaUtil.generatorRotateVCodeImage(generatorVCode, true);
        try {
            ImageIO.write(generatorRotateVCodeImage, "gif", response.getOutputStream());
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }

4.实现效果如下图所示:

Java实现动态验证码生成

5.控制器验证码验证部分如下图所示:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
//若验证码为空
if (StringUtils.isEmpty(cpacha)) {
            ret.put("type", "error");
            ret.put("msg", "请填写验证码!");
            return ret;
        }
        //获取保存在session中的登录验证码对象
        Object loginCpacha = request.getSession().getAttribute("loginCpacha");
        //若登录验证码实体对象为空
        if (loginCpacha == null) {
            ret.put("type", "error");
            ret.put("msg", "会话超时,请刷新页面!");
            return ret;
        }
        //若输入的验证码转化成大写之后不等于转换成大写的session中保存的验证码
        if (!cpacha.toUpperCase().equals(loginCpacha.toString().toUpperCase())) {
            ret.put("type", "error");
            ret.put("msg", "验证码错误!");
            //实例化日志信息实体
            OrderingLog orderingLog = new OrderingLog("用户名为" + user.getOuUsername() + "的用户登录时输入验证码错误!", new Date());
            //添加日志信息
            logService.addLog(orderingLog);
            return ret;
        }

注意:

只有当你把当前系统时间传入该验证码生成工具类中,才能实现点击验证码图片,实时自动替换验证码,如下图所示:

Java实现动态验证码生成

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持服务器之家。

原文链接:https://blog.csdn.net/weixin_44009447/article/details/105667939

延伸 · 阅读

精彩推荐