java web 项目登陆的验证码生成以及更改

时间:2022-12-30 19:06:05

web项目的登陆页面,经常会遇到输入验证码的情况。以前总觉得会很复杂,但是仔细做了一个项目后,发觉原理很简单的。就是在后台指定验证码的所有字符总集合,然后用random随机获取这个总集合中的几个字符作为验证码。验证码生成后再用awt为这几个字符加上噪点,生成图片通过BufferedImage类传到前台img的src中即可。

首先,我们要生成验证码的字符:

/**
* @param length
* 验证码长度
* @param level
* 验证码难度
* @param isCanRepeat
* 能否出现重复字符
* @return String 验证码
*
*/
public static String getSecurityCode(int length, SecurityCodeLevel level,
Boolean isCanRepeat) {
// 字符集合,除掉容易混淆的字母o和数字0、字母l和数字1
char[] codes = { '1', '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', 'I', 'J', 'K', 'L', 'M', 'N',
'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z' };
// 根据难度筛选产生验证码的字符集合
if (level == SecurityCodeLevel.Simple) {
codes = Arrays.copyOfRange(codes, 0, 9);
}
// 获取字符集合的长度
int n = codes.length;

// 当验证码位数大于字符集合长度且不允许重复时抛出运行时异常
if (length > n && isCanRepeat == false) {
throw new RuntimeException(String.format(
"调用SecurityCode.getSecurityCode(%1$s,%2$s,%3$s)出现异常,"
+ "当isCanRepeat为%3$s时,传入参数%1$s不能大于%4$s", length,
level, isCanRepeat, n));
}

// 存放抽取出的验证码
char[] result = new char[length];
// 允许重复
if (isCanRepeat) {
for (int i = 0; i < result.length; i++) {
result[i] = codes[(int) (Math.random() * n)];
}
} else {// 不允许重复
for (int i = 0; i < result.length; i++) {
int r = (int) (Math.random() * n);
result[i] = codes[r];
// 必须确保不会再次抽取到那个字符,因为所有抽取的字符必须不相同。所以把已经选中的字符从codes中去除
codes[r] = codes[--n];
}
}
return String.valueOf(result);
}

然后就是生成噪点,加上验证码字符,产生图片传人前台


/**
*
* @param securityCode 随机产生的验证码
* @returnimage 产生的图片流
*/
public static BufferedImage createImg(String securityCode){
//验证码长度
int codeLength=securityCode.length();
//字体大小
int fSize = 15;
int fWidth = fSize + 1;
//图片宽度
int width = codeLength * fWidth + 6 ;
//图片高度
int height = fSize * 2 + 1;

//图片
BufferedImage image=new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
Graphics g=image.createGraphics();

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

//设置边框颜色
g.setColor(Color.LIGHT_GRAY);
//边框字体样式
g.setFont(new Font("Arial", Font.BOLD, height - 2));
//绘制边框
g.drawRect(0, 0, width - 1, height -1);


//绘制噪点
Random rand = new Random();
//设置噪点颜色
g.setColor(Color.LIGHT_GRAY);
for(int i = 0;i < codeLength * 6;i++){
int x = rand.nextInt(width);
int y = rand.nextInt(height);
//绘制1*1大小的矩形
g.drawRect(x, y, 1, 1);
}

//绘制验证码
int codeY = height - 10;
//设置字体颜色和样式
g.setColor(new Color(19,148,246));
g.setFont(new Font("Georgia", Font.BOLD, fSize));
for(int i = 0; i < codeLength;i++){
g.drawString(String.valueOf(securityCode.charAt(i)), i * 16 + 5, codeY);
}
//关闭资源
g.dispose();

return image;
}
/**
* 返回验证码图片的流格式
* @param securityCode 验证码
* @return ByteArrayInputStream 图片流
*/
public static ByteArrayInputStream getImageAsInputStream(String securityCode){

BufferedImage image = createImg(securityCode);
return convertImageToStream(image);
}

/**
* 将BufferedImage转换成ByteArrayInputStream
* @param image 图片
* @return ByteArrayInputStream 流
*/
private static ByteArrayInputStream convertImageToStream(BufferedImage image){

ByteArrayInputStream inputStream = null;
ByteArrayOutputStream bos = new ByteArrayOutputStream();
JPEGImageEncoder jpeg = JPEGCodec.createJPEGEncoder(bos);
try {
jpeg.encode(image);
byte[] bts = bos.toByteArray();
inputStream = new ByteArrayInputStream(bts);
} catch (ImageFormatException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
return inputStream;
}

这样,验证码图片就生成了,就只剩下在前台调用服务,为img的src赋值了,这里以jsp+struts2为例:

//jsp页面展示 
<div class="col-md-8" style="margin:0px;padding:0px;">
<span style="white-space:pre"></span><span class="block input-icon input-icon-right"> 
<span style="white-space:pre"></span><input type="text" class="form-control" name="securityCode" id="securityCode" check-type='required' placeholder="验证码" /><span style="white-space:pre"></span><i class="icon-lock"></i> 
<span style="white-space:pre"></span></span></div><span style="white-space:pre"></span><div class="col-md-4">
//点击看不清,重新生成验证码图片 注意<span style="font-family: Arial, Helvetica, sans-serif;">src="securityCodeAction"直接调用action生成验证码图片<span style="white-space:pre"></span><img src="securityCodeAction" id="securityImg"<span style="white-space:pre"></span>style="cursor:hand;" alt="看不清,换一张" /><span style="white-space:pre"></span></div>

//页面初始化load方法,加载验证码图片
$(function(){
//初始化bootstrap验证框架
//$("#loginForm").validation();

//点击看不清,生成新的验证码
$('#securityImg').on('click',function(){
$(this).attr('src','securityCodeAction?timestamp='+new Date().getTime());
});
});
样式是用的bootstrap的 可以改成自己的css样式