Java如何实现验证码验证功能呢?日常生活中,验证码随处可见,他可以在一定程度上保护账号安全,那么他是怎么实现的呢?
Java实现验证码验证功能其实非常简单:用到了一个Graphics类在画板上绘制字母,随机选取一定数量的字母随机生成,然后在画板上随机生成几条干扰线。
首先,写一个验证码生成帮助类,用来绘制随机字母:
import java.awt.Color
import java.awt.Font
import java.awt.Graphics
import java.awt.image.BufferedImage
import java.io.IOException
import java.io.OutputStream
import java.util.Random
import javax.imageio.ImageIO
public final class GraphicHelper {
/**
* 以字符串形式返回生成的验证码,同时输出一个图片
*
* @param width
* 图片的宽度
* @param height
* 图片的高度
* @param imgType
* 图片的类型
* @param output
* 图片的输出流(图片将输出到这个流中)
* @return 返回所生成的验证码(字符串)
*/
public static String create(final int width, final int height, final String imgType, OutputStream output) {
StringBuffer sb = new StringBuffer()
Random random = new Random()
BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB)
Graphics graphic = image.getGraphics()
graphic.setColor(Color.getColor("F8F8F8"))
graphic.fillRect(0, 0, width, height)
Color[] colors = new Color[] { Color.BLUE, Color.GRAY, Color.GREEN, Color.RED, Color.BLACK, Color.ORANGE,
Color.CYAN }
// 在 "画板"上生成干扰线条 ( 50 是线条个数)
for (int i = 0 i < 50 i++) {
graphic.setColor(colors[random.nextInt(colors.length)])
final int x = random.nextInt(width)
final int y = random.nextInt(height)
final int w = random.nextInt(20)
final int h = random.nextInt(20)
final int signA = random.nextBoolean() ? 1 : -1
final int signB = random.nextBoolean() ? 1 : -1
graphic.drawLine(x, y, x + w * signA, y + h * signB)
}
// 在 "画板"上绘制字母
graphic.setFont(new Font("Comic Sans MS", Font.BOLD, 30))
for (int i = 0 i < 6 i++) {
final int temp = random.nextInt(26) + 97
String s = String.valueOf((char) temp)
sb.append(s)
graphic.setColor(colors[random.nextInt(colors.length)])
graphic.drawString(s, i * (width / 6), height - (height / 3))
}
graphic.dispose()
try {
ImageIO.write(image, imgType, output)
} catch (IOException e) {
e.printStackTrace()
}
return sb.toString()
}
}
接着,创建一个servlet,用来固定图片大小,以及处理验证码的使用场景,以及捕获页面生成的验证码(捕获到的二维码与用户输入的验证码一致才能通过)。
import java.io.OutputStream
import javax.servlet.ServletException
import javax.servlet.annotation.WebServlet
import javax.servlet.http.HttpServlet
import javax.servlet.http.HttpServletRequest
import javax.servlet.http.HttpServletResponse
import javax.servlet.http.HttpSession
@WebServlet(urlPatterns = "/verify/regist.do" )
public class VerifyCodeServlet extends HttpServlet {
private static final long serialVersionUID = 3398560501558431737L
@Override
protected void service(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
// 获得 当前请求 对应的 会话对象
HttpSession session = request.getSession()
// 从请求中获得 URI ( 统一资源标识符 )
String uri = request.getRequestURI()
System.out.println("hello : " + uri)
final int width = 180 // 图片宽度
final int height = 40 // 图片高度
final String imgType = "jpeg" // 指定图片格式 (不是指MIME类型)
final OutputStream output = response.getOutputStream() // 获得可以向客户端返回图片的输出流
// (字节流)
// 创建验证码图片并返回图片上的字符串
String code = GraphicHelper.create(width, height, imgType, output)
System.out.println("验证码内容: " + code)
// 建立 uri 和 相应的 验证码 的关联 ( 存储到当前会话对象的属性中 )
session.setAttribute(uri, code)
System.out.println(session.getAttribute(uri))
}
}
接着写一个HTML注册页面用来检验一下:
<html>
<head>
<meta charset="UTF-8">
<title>注册</title>
<link rel="stylesheet" href="styles/general.css">
<link rel="stylesheet" href="styles/cell.css">
<link rel="stylesheet" href="styles/form.css">
<script type="text/javascript" src="js/ref.js"></script>
<style type="text/css" >
.logo-container {
margin-top: 50px
}
.logo-container img {
width: 100px
}
.message-container {
height: 80px
}
.link-container {
height: 40px
line-height: 40px
}
.link-container a {
text-decoration: none
}
</style>
</head>
<body>
<div class="container form-container">
<form action="/wendao/regist.do" method="post">
<div class="form"> <!-- 注册表单开始 -->
<div class="form-row">
<span class="cell-1">
<i class="fa fa-user"></i>
</span>
<span class="cell-11" style="text-align: left">
<input type="text" name="username" placeholder="请输入用户名">
</span>
</div>
<div class="form-row">
<span class="cell-1">
<i class="fa fa-key"></i>
</span>
<span class="cell-11" style="text-align: left">
<input type="password" name="password" placeholder="请输入密码">
</span>
</div>
<div class="form-row">
<span class="cell-1">
<i class="fa fa-keyboard-o"></i>
</span>
<span class="cell-11" style="text-align: left">
<input type="password" name="confirm" placeholder="请确认密码">
</span>
</div>
<div class="form-row">
<span class="cell-7">
<input type="text" name="verifyCode" placeholder="请输入验证码">
</span>
<span class="cell-5" style="text-align: center">
<img src="/demo/verify/regist.do" onclick="myRefersh(this)">
</span>
</div>
<div class="form-row" style="border: none">
<span class="cell-6" style="text-align: left">
<input type="reset" value="重置">
</span>
<span class="cell-6" style="text-align:right">
<input type="submit" value="注册">
</span>
</div>
</div> <!-- 注册表单结束 -->
</form>
</div>
</body>
</html>
效果如下图:
在控制台接收到的图片中验证码的变化如下:
当点击刷新页面的时候,验证码也会随着变化,但我们看不清验证码时,只要点击验证码就会刷新,这样局部的刷新可以用JavaScript来实现。
在<img
src="/demo/verify/regist.do">中,添加一个问号和一串后缀数字,当刷新时让后缀数字不断改变,那么形成的验证码也会不断变化,我们可以采用的一种办法是后缀数字用date代替,date获取本机时间,时间是随时变的,这样就保证了刷新验证码可以随时变化。
代码如下:
function myRefersh( e ) {
const source = e.src // 获得原来的 src 中的内容
//console.log( "source : " + source )
var index = source.indexOf( "?" ) // 从 source 中寻找 ? 第一次出现的位置 (如果不存在则返回 -1 )
//console.log( "index : " + index )
if( index > -1 ) { // 如果找到了 ? 就进入内部
var s = source.substring( 0 , index ) // 从 source 中截取 index 之前的内容 ( index 以及 index 之后的内容都被舍弃 )
//console.log( "s : " + s )
var date = new Date() // 创建一个 Date 对象的 一个 实例
var time = date.getTime() // 从 新创建的 Date 对象的实例中获得该时间对应毫秒值
e.src = s + "?time=" + time // 将 加了 尾巴 的 地址 重新放入到 src 上
//console.log( e.src )
} else {
var date = new Date()
e.src = source + "?time=" + date.getTime()
}
}
如回答不详细可追问
CSS是Cascading Style Sheet 的缩写。译作「层叠样式表单」。是用于(增强)控制网页样式并允许将样式信息与网页内容分离的一种标记性语言。你可能对CSS这个名词比较陌生,实际上无论你用Internet Explorer还是
Netscape Navigator在网上冲浪,几乎随时都在与CSS打交道,在网上没有使用过CSS的网页可能不好找。不管你用什么工
具软件制作网页,都有在有意无意地使用CSS。用好CSS能使你的网页更加简炼,为什么同样内容的网页,有的人做出来有
几十KB,而高手做出来只有十几KB,CSS在其中的作用是不言而喻的。我把我在使用CSS中的一些小经验以及一些网友来信
提问的问题整理出来,供诸位参考。
1、CSS在网页制作中一般有三种方式的用法,那么具体在使用时该采用哪种用法?
当有多个网页要用到的CSS,采用外连CSS文件的方式,这样网页的代码大大减少,修改起来非常方便;只在单个网页
中使用的CSS,采用文档头部方式;只有在一个网页一、两个地方才用到的CSS,采用行内插入方式。
2、CSS的三种用法在一个网页中要以混用吗?
三种用法可以混用,且不会造成混乱。这就是它为什么称之为“层叠样式表”的原因,浏览器在显示网页时是这样处
理的:先检查有没有行内插入式CSS,有就执行了,针对本句的其它CSS就不去管它了;其次检查头部方式的CSS,有就执行
了;在前两者都没有的情况下再检查外连文件方式的CSS。因此可看出,三种CSS的执行优先级是:行内插入式、头部方
式、外连文件方式。
3、在Dreamweaver3中如何使外部文件式CSS?
在Dreamweaver3中使用外连文件式CSS并没有特殊要求,同样是用记事本创建一个*.css文件,在网页的<head>与
</head>之间加上一句这样的代码:<link rel="stylesheet" href="在这里填上你的CSS文件地址(相对路径+文件
名)" type="text/css">就行了。
4、如何用Dreamweaver3快速创建CSS外连式文件?
对于一个初接触CSS的网页设计人员来讲,要用记事之类的编辑器,去创建一个CSS外连式文件是相当困难的。由于
Dreamweaver3对CSS支持的很好,用它来帮助就轻松多了。具体可以这样操作:
1)先在纸上写好在网站的网页中可能要用到的格名称,然后在Dreamweaver3的编辑窗中调出CSS面板,一个一个地定
义,并在一个空白页上适当地写一点相关内容,边定义边试用,效果不满意,立即修改;
2)全部定义好后,再用记事本创建一个空的CSS外连式文件,把在<head>与</head>之间的那段定义好的CSS复制
到CSS文件中去,就大功告成了。整个过程就是点鼠标,方便吧?
5、在Dreamweaver3中采用行内插入式CSS要手动写代码吗?
不用!先用CSS面板定义好要用的CSS,然后,在要插入CSS的标记插入:style="",再把你刚才定义的CSS从<head>
后面拖到这个双引号中来,把花括号以外的部分删去就行了。
6、在方档头部方式和外连文件方式的CSS中都有“<!--”和“-->”,好象没什么用,不要可以吗?
这一对东东的作用是为了不引起低版本浏览器的错误。如果某个执行此页面的浏览器不支持CSS,它将忽略其中的内
容。虽然现在使用不支持CSS浏览器的人已很少了,由于互联网上几乎什么可能都会发生,所以还是留着为妙。
7、如何给一部分文字加背景色?
给文字加上不同颜色,在DW3中只要在属性面板上选取文字的颜色就行了,非常方便,但要给部分文字加不同的背景色
却没有相应的功能,我们可以先做一个定义背景色的CSS(如:bgstyle),在DW3中点几下鼠就完成了。如一个定义淡黄色
背景的CSS是这样的:
<style type="text/css">
<!--
.bgstyle { background: #FFFFCC}
-->
</style>
在要用时选取那段文字,再在CSS面板上点一下“bgstyle”就行了。
8、如何给部分文字加背景图像?
与加背景色操作类似,中是在背景在选择加载图象就是了,一个定义好的加背景图象的CSS例子的代码是这样的:
<style type="text/css">
<!--
.imgbgstyle { background-image: url(/logo.gif)}
-->
</style>
在要用时选取那段文字,再在CSS面板上点一下“imgbgstyle”就行了。
9、如何使页面的背景在文字“滚动”时背景图案静止不动?
要使背景图案不随文字“滚动”的CSS是这样的:
<style type="text/css">
<!--
BODY { background: purple url(/bg.jpg)
background-repeat:repeat-y
background-attachment:fixed
}
-->
</style>
10、如何定义字间距?
在DW3中CSS的属性定义对话框(style Definition for .style1)的“Block”上的“letter spaceing”属性定义的就
是字间距,它指的是每一个字符之间的额外间距,经长度为单位,正负值均可,当取负值时产生字符挤在一起的效果。下
面代码是一个定义好的字间距CSS例子:
<style type="text/css">
<!--
.style1 { letter-spacing: 3px}
-->
</style>
11、如何给文字加上划线、下划线、删除线和闪烁?
在DW3中CSS的属性定义对话框(style Definition for .style1)的“Type”上的“decoration”属性定义的就是这些
内容,要注意的是闪烁属性有些版本的浏览器不支持,少用为好。下面是一个定义好上述效果的CSS例子:
<style type="text/css">
<!--
.style1 { text-decoration: underline overline line-through blink}
-->
</style>
其中: “underline”是定义下划线;“overline ”是定义上划线;“ line-through”定义的是删除线;“blink”
定义的是文字闪烁。
12、如何使网页具有“首行缩进”功能?
由于DW3输入空格不方便,利用“首行缩进”将弥补这个不足。在DW3中CSS的属性定义对话框(style Definition
for .style1)的“Block”上的“text-indent”属性定义的就是“首行缩进”,所谓“首行”是指每段内容的第一行,也
就是直接按回车键就形成了一个新的段落。缩进最好以“em”(字符)为单位,比如:汉字编排要求每段开始缩进两个汉
字,设置好的CSS如下所示:
<style type="text/css">
<!--
.style1 { text-indent: 2em}
-->
</style>
在DW3要注意:在DW3中CSS的属性定义对话框(style Definition for .style1)的“Block”上的“text-indent”右
面的缩进单位选择框中“ems”指的就是“em”。
13、在用表格进行排版时,能使某一方向上的内容离开表格线一点吗?
可以!在DW3中CSS的属性定义对话框(style Definition for .style1)的“Box”上的“margin”定义的就是内容离
开边缘的距离,分别可定义四个方向:“top”“bottom”“left”“right”。下面就是定义在左边离开“10px”的CSS例
子代码:
<style type="text/css">
<!--
.style1 { margin: 0px 0px 0px 10px}
-->
</style>
14、能给某部分内容加边框吗?
用CSS可以给某部分内容加边框,在DW3中CSS的属性定义对话框(style Definition for .style1)的“Border”定义
的就是边框线,“top”“bottom”“left”“right”四边可分别定义线的粗细和颜色,这些定义好后不要忘记在下面的
“style”中定义线型,否则将看不边框线,因为默认的线型是“none”。下面是一个定义了上边框为:蓝色细线;左边框
为:绿色中粗线的CSS例子:
<style type="text/css">
<!--
.style1 { border: solidborder-width: thin 0px 0px mediumborder-color: #0000FF black black #00FF00}
-->
呵呵,这个程序没有问题imagettftext($im,20,0,3,25,$font,"comic.ttf",$str)
这里需要一个comic.ttf字体文件,必须放在那个php程序同目录下
你是不是没有这个字体文件
如果没有,可以到系统的C:\Windows\Fonts目录下拷贝一个(拷个几百KB大小的就足够用了)
我试了你的程序,生成的图片效果不是很好,我以前写了一个,给你参考下把,虽然也是修改的网上的:
<?
//获取验证码图片模块
session_start()
//记得去掉下面注释
if (!isset($_GET["sid"])||$_GET["sid"]==""||$_GET["sid"]!=session_id())die()
Header("Content-type:image/png")
//定义header,声明图片文件,最好是png,无版权之扰
//生成新的四位整数验证码
//session_id($_GET["sid"])
//开启session
$authnum_session = ''
$str = 'ABCDEFGHIJKMNPQRSTUVWXYZ1234567890'
//定义用来显示在图片上的数字和字母
$l = strlen($str)
//得到字串的长度
//循环随机抽取四位前面定义的字母和数字
for ($i=1$i<=4$i++)
{
$num=rand(0,$l-1)
//每次随机抽取一位数字从第一个字到该字串最大长度,
//减1是因为截取字符是从0开始起算这样34字符任意都有可能排在其中
$authnum_session.= $str[$num]
//将通过数字得来的字符连起来一共是四位
}
$_SESSION["checkCode"]=$authnum_session
//用session来做验证也不错注册session,名称为authnum_session,
//其它页面只要包含了该图片
//即可以通过$_SESSION["checkCode"]来调用
//生成验证码图片,
//srand((double)microtime()*1000000)
mt_srand()
$im = imagecreate(100,40)//图片宽与高
//主要用到黑白灰三种色
$black = ImageColorAllocate($im, mt_rand(0,245),mt_rand(0,200),mt_rand(0,200))
$white = ImageColorAllocate($im, 255,255,255)
$gray = ImageColorAllocate($im, 200,200,200)
//将四位整数验证码绘入图片
imagefill($im,168,30,$gray)
//如不用干扰线,注释就行了
$li = ImageColorAllocate($im, 220,220,220)
for ($i=0$i<0$i++)
{//加入3条干扰线也可以不要视情况而定,因为可能影响用户输入
imageline($im,mt_rand(0,30),mt_rand(0,41),mt_rand(80,90),mt_rand(0,41),$li)
} //字符在图片的位置
//imagestring($im, 5, 8, 2, $authnum_session, $white)
// Set the enviroment variable for GD
putenv('GDFONTPATH=' . realpath('.'))
// Name the font to be used (note the lack of the .ttf extension)
//$font = 'mvboli'
//$font = imageloadfont("mvboli.ttf")
//imagestring($im,$font, 8, 2, $authnum_session, $white)
//imagettftext ( $im,20.0, 0, 0, 30, $white,"FELIXTI.TTF", $authnum_session )
for ($i=0$i<4$i++)
{
imagettftext ( $im,20.0, mt_rand(0,40)-20, $i*25+3, 30, $white,"FELIXTI.TTF", substr($authnum_session,$i,1) )
}
for ($i=0$i<90$i++) //加入干扰象素
{
imagesetpixel($im, mt_rand()%100-2 , mt_rand()%40-2 , $gray)
}
ImagePNG($im)
ImageDestroy($im)
?>
同样这行代码需要一个字体文件,你可以把它改成你拷过来的的字体文件名
imagettftext ( $im,20.0, mt_rand(0,40)-20, $i*25+3, 30, $white,"FELIXTI.TTF", substr($authnum_session,$i,1) )