验证码response

验证码有多种,写法也有多种,有前端写的也有后台写的,不推荐前端写的,因为如果浏览器禁用js,就可以跳过验证码验证。
下面我写的是使用jsp+response制作验证码。(算是原创吧?学来的算是我的吧)
验证码制作步骤:
response:HttpServletResponse 代表服务器对用户响应

  1. 设置页面的响应方式

    response.setContentType("image/jpeg");//将页面的响应方式设置为图片格式
    

    注:响应方式是告诉浏览器用什么格式来响应收到的数据

  2. 去掉页面的缓存

	response.setHeader("Pragma", "No-cache");
	response.setHeader("Cache-Control", "no-cache");
	response.setDateHeader("Expires", 0);
  1. 在Java中创建Image对象,获取画笔,绘画矩形、字符、干扰线。
  2. 获取通向用户浏览器的字节流,向用户的浏览器发送图片,比如验证码。

正式开始。
服务端产生验证码。 code.jsp

<%@page import="javax.imageio.ImageIO"%>
<%@page import="java.util.Random"%>
<%@page import="java.awt.image.BufferedImage"%>
<%@page import="java.awt.*"%>
<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<%
//设置页面不缓存。因为某些浏览器缓存验证码,导致重新打开该页面时总提示验证码过期。
	response.setHeader("Pragma", "No-cache");
	response.setHeader("Cache-Control", "no-cache");
	response.setDateHeader("Expires", 0);
	response.setContentType("image/jpeg");//将页面的响应方式设置为图片格式
	// 在内存中创建图象   
	int width = 60, height = 20; //验证码的宽和高  
	/*定义画布。
	在服务器内存中创建一个Image对象,指定图片的宽度、高度及类型。
	Image是抽象类,不能new,要使用它的父类BufferedImage	参数(宽度,高度,图片的类型)*/
	BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
	//获取图片上面的画笔
	Graphics g = image.getGraphics();
	//使用画笔在图片上面画一个矩形
	g.setColor(new Color(244,226,192));//设置背景的颜色
	g.fillRect(0, 0, width, height);//实心的。坐标为0,0
	String code="";//随机产生4位验证码 
	for(int i=0;i<4;i++){//使4个字符的颜色大小不同
		String s=randomC();
		g.setColor(new Color((int)(Math.random()*255),(int)(Math.random()*255),(int)(Math.random()*255)));//设置画笔的颜色为随机色
		g.setFont(new Font("黑体",0,r.nextInt(10)+10));
		g.drawString(s, i*15, 16);//将字符画上去(设置字符的宽度使得4个字符不会叠在一起)
		code=code+s;
	}
	session.setAttribute("code", code);
	// 随机产生干扰线,使图象中的认证码不易被其它程序探测到
	for(int i=0;i<10;i++){
		g.setColor(new Color((int)(Math.random()*255),(int)(Math.random()*255),(int)(Math.random()*255)));//设置画笔的颜色为随机色
		g.drawLine(r.nextInt(100), r.nextInt(40), r.nextInt(100), r.nextInt(40));
	}
	//将Image对象使用字节流发送给用户的电脑
	ImageIO.write(image, "JPEG", response.getOutputStream());
	//加上下面代码,运行时才不会出现java.lang.IllegalStateException: getOutputStream() has already been called ..........异常  
	response.getOutputStream().flush(); //将流刷新   
	response.getOutputStream().close(); //关闭流  
	response.flushBuffer();
	out.clear();
	out = pageContext.pushBody();
	/* 由于jsp container在处理完成请求后会调用releasePageContet方法释放所用的PageContext object,
	并且同时调用getWriter方法,由于getWriter方法与在jsp页面中使用流相关的getOutputStream方法冲突,所以会造成这种异常 */
%>
<%!
//返回随机字符
Random r=new Random();
public String randomC(){
	String str="";
	int n=r.nextInt(3);//产生0、1、2
	if(n==0){
		str=""+(char)(r.nextInt(26)+97);//小写字母
	}else if(n==1){
		str=""+(char)(r.nextInt(26)+65);//大写字母
	}else{
		str=""+(char)(r.nextInt(10)+48);//数字
	}
	return str;
}

%>


前台接收验证码显示,并且用户点击图片可更换验证码。页面很丑,随便写的只是为了测试程序。 login.jsp
拼接参数写了两种,一种是系统当前时间的毫秒值,另一种是伪随机数

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
<style type="text/css">
	img{
		border:solid 1px red;
		width:80px;
		height:30px;
	}
</style>
<!-- <script type="text/javascript">
	function f_change(img){
		img.src="code.jsp?id="+new Date().getTime();//src=code.jsp点击的地址跟之前是一样的,浏览器懒得存下来。拼接一个参数,使得每次点击的不同。new Date如果用户点击时间间隔过短,不会改变。getTime()毫秒不会一样。
	}
</script> -->
</head>
<body>
	<form action="check.jsp">
		用户名:<input type="text" name="username"><br>
		密码:<input type="password" name="password"><br>
		验证码:<input type="text" name="code" size="4"><img alt="验证码" src="code.jsp" onclick="this.src='code.jsp?id='+Math.random()"><br>
		<input type="submit">
	</form>
</body>
</html>


如果只有前面两个jsp代码,不会出结果:验证码输出正确还是错误。 check.jsp
在服务端产生验证码时将验证码添加到session中,获取用户提交的验证码,进行比较。比较后的结果随意,我这里只是为了测试,并且我写的是忽略大小写。

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>
<%
String userCode=request.getParameter("code");
String imageCode=(String)session.getAttribute("code");
if(userCode.equalsIgnoreCase(imageCode)){
	%>
	<script type="text/javascript">
		alert("验证码正确");
	</script>
	<% 
}else{%>
	<script type="text/javascript">
		alert("验证码错误");
		history.back();
	</script>
<%	
}
%>
</body>
</html>

过程中会报异常:java.lang.IllegalStateException: getOutputStream() has already been called for this response
不要慌,这是正常的。解决的代码上面已经写了哦,但是那几行是套用别人的。
貌似是容器有自动调用response.getWriter(),和response.getOutputStream()相冲突的,所以会出现以上这个异常。但是我还不是很明白为什么会有getWriter()、怎么看产生了getWriter()以及为什么要这么解决。

还可以下载validatecode.jar包,利用验证码工具ValidateCode来实现,只需要指定验证码的宽、高、字符数量、干扰线数量,它就会自己画好随机验证码,效果是一样的。validatecode.jar我找不到在哪里下载,找到的一个竟然还要钱,所以这里就不写了。

如果上方有什么不对的地方敬请指教!我的疑问也希望能有人解答,谢谢。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值