@WebServlet("/validateCode")
public class ValidateServlet extends HttpServlet {
private static final int WIDTH = 120;
private static final int HEIGHT = 40;
private static final int VALIDATE_CODE_LENGTH = 4;
@Override
protected void service(HttpServletRequest req, HttpServletResponse res) throws ServletException, IOException {
//0.生成随机字符串
String validateCode = RandomUtils.randomString(VALIDATE_CODE_LENGTH);
//1.准备一个基于内存的画板对象
BufferedImage image = new BufferedImage(WIDTH, HEIGHT, BufferedImage.TYPE_INT_RGB);
//2.获取画笔对象
Graphics g = image.getGraphics();
//3.给画板添加背景色
//(1)设置画笔颜色
g.setColor(AwtUtils.randomColor());
//(2)为矩形填充颜色
g.fillRect(0, 0, WIDTH, HEIGHT);
//4.绘制随机字符串
//(1)为画笔设置颜色
g.setColor(AwtUtils.randomColor());
//(2)设置字体
g.setFont(new Font("", Font.BOLD, 24));
//(3)画字符串
g.drawString(validateCode, 30, 30);
//5.画干扰线(噪音线)
for (int i = 1; i <= 10; i++) {
//(1)设置颜色
g.setColor(AwtUtils.randomColor());
//(2)画线
AwtUtils.drawRandomLine(g, WIDTH, HEIGHT);
}
//5.画干扰点(噪音点)
for (int i = 1; i <= 50; i++) {
//(1)设置颜色
g.setColor(AwtUtils.randomColor());
//(2)画点
AwtUtils.drawRandomPoint(g, WIDTH, HEIGHT);
}
//将内存画板上的内容写出到浏览器客户端
//(1)将消息类型设置为通过png图片的格式
res.setContentType("image/png");
//(2)将内存画板的内容拷贝到响应流中
ImageIO.write(image, "png", res.getOutputStream());
}
}
public class AwtUtils {
private AwtUtils() {
}
/**
* 用于返回一个随机的颜色
* @return
*/
public static Color randomColor() {
Random r = new Random();
return new Color(r.nextInt(256), r.nextInt(256), r.nextInt(256));
}
/**
* 绘制随机线条
* @param maxX
* @param maxY
*/
public static void drawRandomLine(Graphics g, int maxX, int maxY) {
Random r = new Random();
g.drawLine(r.nextInt(maxX), r.nextInt(maxY), r.nextInt(maxX), r.nextInt(maxY));
}
/**
* 绘制随机点
* @param maxX
* @param maxY
*/
public static void drawRandomPoint(Graphics g, int maxX, int maxY) {
Random r = new Random();
int x = r.nextInt(maxX);
int y = r.nextInt(maxY);
g.drawLine(x, y, x, y);
}
}
public class RandomUtils {
private RandomUtils() {
}
/**
* 随机验证码
* @param length 验证码的长度
* @return
*/
public static String randomString(int length) {
String str = "3456789abcdefghjkmnpqrstuvwxy";
Random r = new Random();
String result = "";
for (int i = 1; i <= length; i++) {
result += str.charAt(r.nextInt(str.length()));
}
return result;
}
}
前端页面:
<head>
<meta charset="utf-8">
<title></title>
</head>
<body>
<form id="login-form">
<p>
用户名:<input type="text" name="userName" />
</p>
<p>
密码:<input type="password" name="pwd" />
</p>
<p>
验证码:<input type="text" name="validateCode" /> <img id="validateCodeImage"/>
</p>
<p>
<button id="login" type="button">登录</button>
</p>
</form>
</body>
<script type="text/javascript" src="js/jquery1.9.1.js"></script>
<script type="text/javascript" src="js/common.js"></script>
<script>
//页面刚加载的时候为其生成验证码
var $img=$("#validateCodeImage");
$img.prop("src",serverPath+"/validateCode");
//点击验证码图片的时候要能够切换验证码
$img.on("click",function(){
//默认情况下,第一次访问验证码以后,浏览器会基于缓存机制将当前验证码访问路径对应的结果进行缓存
//如果第二次使用相同的路径访问,则此时浏览器不会重新向服务端发送请求,而是直接从缓存中获取之前缓存的结果
//这样就算修改了图片的src,图片也不会进行变化,此时需要通过一定的手段“欺骗”浏览器,在访问验证码对应的
//Servlet的时候让浏览器觉得每次使用的访问路径是不一样的,一般可以在地址栏中带一个随机参数或时间戳
$img.prop("src",serverPath+"/validateCode?_r="+new Date().getTime());
});
</script>
最终效果