手机验证码、图片验证码的实现
手机验证码
第一步:网上找一个第三方短信接口平台,大多数这样的平台都会有免费试用的通知短信。我这里用的是秒滴科技,注册个账号,赠送200条短信,足够项目练手使用了。
第二步:去用户中心查看TOKEN(ACCOUNT SID和AUTH TOKEN的值很重要,后面写代码要用到)。
第三步:查看API文档,这里要用到官方提供的接口。
第四步:在配置管理里面新建模板,模板审核通过后即可启用。
第五步:引入jar包,该功能只用了一个jar包
第六步:编写代码
首先是jsp界面,这里我把整个页面都copy下来了,页面功能只有手机验证码和图片验证码。
<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
<%
String path = request.getContextPath();
String basePath = request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+path+"/";
%>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<base href="<%=basePath%>">
<meta charset="UTF-8">
<title>test</title>
<link rel="stylesheet" href="css/bootstrap.min.css"/>
<link rel="stylesheet" href="css/bootstrap-datetimepicker.min.css"/>
<script type="text/javascript" src="js/jquery-3.2.1.min.js"></script>
<script type="text/javascript" src="js/bootstrap.min.js"></script>
<style type="text/css">
#login{ width:450px; height:100px; margin:50px auto;}
#btn{ margin-left:100px; margin-top:-25px; width: 120px;height: 25px; font-size: 11px; }
body{ background-color: #ecfcf9;}
</style>
</head>
<!-- 图片验证码 -->
<script src="js/gVerify.js"></script>
<script>
$(function(){
var verifyCode = new GVerify("v_container");
document.getElementById("code_input").onblur = function(){
var res = verifyCode.validate(document.getElementById("code_input").value);
if(res){
alert("验证正确");
}else{
alert("验证码错误");
}
}
})
</script>
<!-- 发送短信验证码倒计时-->
<script type="text/javascript">
var InterValObj; //timer变量,控制时间
var count = 30; //间隔函数,1秒执行
var curCount;//当前剩余秒数
function sendMessage(){curCount = count;
$("#btn").attr("disabled", "true");
$("#btn").val(curCount + "秒后可重新发送");
InterValObj = window.setInterval(SetRemainTime, 1000); //启动计时器,1秒执行一次请求后台发送验证码 TODO
}
//timer处理函数
function SetRemainTime() {
if (curCount == 0) {
window.clearInterval(InterValObj);//停止计时器
$("#btn").removeAttr("disabled");//启用按钮
$("#btn").val("重新发送验证码");
}
else {
curCount--;
$("#btn").val(curCount + "秒后可重新发送");
}
}
</script>
<body>
<div class="container">
<div id="login">
<form class="form-horizontal" role="form">
<div class="form-group">
<label class="col-sm-2 control-label">验证码</label>
<div class="col-sm-5">
<input type="text" class="form-control" id="code_input" placeholder="请输入验证码" required autofocus>
<span id="v_container"></span>
</div>
</div>
<div class="form-group" style="position: relative;top:50px;">
<label class="col-sm-2 control-label">手机号</label>
<div class="col-sm-5">
<input type="text" class="form-control" id="phone" name="phone" placeholder="请输入您的手机号" required autofocus>
</div>
</div>
<div class="form-group" style="position: relative;top:50px;">
<label class="col-sm-2 control-label">验证码</label>
<div class="col-sm-3">
<input type="code" class="form-control" id="code" name="code" placeholder="验证码" required>
<input class="btn btn-default" id="btn" name="btn" value="发送验证码" onclick="sendMessage()" />
</div>
</div>
<div class="form-group" style="position: relative;top:50px;">
<div class="col-sm-offset-2 col-sm-10">
<button type="button" class="btn btn-info" id="lo">验证</button>
</div>
</div>
</form>
</div>
</div>
</body>
<!-- 发送短信验证码并验证 -->
<script type="text/javascript">
var sms="";
$("#btn").click(function(){
var phone=$("#phone").val();
if(phone!="")
{
$.ajax({
url:"http://localhost:8866/TestCode/sendSMS.do",
type:"post",
data:{"phone":phone},
dataType:"json",
success:function(result){
if(result.status==1){
sms=result.data;
}
}
});
}else{
alert("请输入手机号");
return false;
}
});
$("#lo").click(function(){
var code=$("#code").val();
if(code==""){
alert("请输入验证码");
}else{
if(sms==code){
window.location.href="http://localhost:8866/TestCode/jsp/success.jsp";
}else{
alert("验证码错误");
};
};
});
</script>
</html>
其次是发送短信的核心代码部分
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.net.HttpURLConnection;
import java.net.URL;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.text.SimpleDateFormat;
import java.util.Date;
import org.json.JSONObject;
public class GetMessageCode {
private static final String QUERY_PATH="https://api.miaodiyun.com/20150822/industrySMS/sendSMS";
private static final String ACCOUNT_SID="上面提到的ACCOUNT SID";
private static final String AUTH_TOKEN="上面提到的AUTH TOKEN";
//根据相应的手机号发送验证码
public static String getCode(String phone){
String rod=smsCode();
String timestamp=getTimestamp();
String sig=getMD5(ACCOUNT_SID,AUTH_TOKEN,timestamp);
String tamp="【xxxx】尊敬的用户,您的验证码为"+rod+",如非本人操作请忽略此短信。";//这里一定要与新建模板中的短信内容一致,一个空格都不能多,否者短信打死都发不过去哦
OutputStreamWriter out=null;
BufferedReader br=null;
StringBuilder result=new StringBuilder();
try {
URL url=new URL(QUERY_PATH);
HttpURLConnection connection=(HttpURLConnection) url.openConnection();
connection.setRequestMethod("POST");
connection.setDoInput(true);//设置是否允许数据写入
connection.setDoOutput(true);//设置是否允许参数数据输出
connection.setConnectTimeout(5000);//设置链接响应时间
connection.setReadTimeout(10000);//设置参数读取时间
connection.setRequestProperty("Content-type","application/x-www-form-urlencoded");
//提交请求
out=new OutputStreamWriter(connection.getOutputStream(),"UTF-8");
String args=getQueryArgs(ACCOUNT_SID, tamp, phone, timestamp, sig, "JSON");
out.write(args);
out.flush();
//读取返回参数
br=new BufferedReader(new InputStreamReader(connection.getInputStream(),"UTF-8"));
String temp="";
while((temp=br.readLine())!=null){
result.append(temp);
}
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
JSONObject json=new JSONObject(result.toString());
String respCode=json.getString("respCode");
String defaultRespCode="00000";
if(defaultRespCode.equals(respCode)){
return rod;
}else{
return defaultRespCode;
}
}
//定义一个请求参数拼接方法
public static String getQueryArgs(String accountSid,String smsContent,String to,String timestamp,String sig,String respDataType){
return "accountSid="+accountSid+"&smsContent="+smsContent+"&to="+to+"×tamp="+timestamp+"&sig="+sig+"&respDataType="+respDataType;
}
//获取时间戳
public static String getTimestamp(){
return new SimpleDateFormat("yyyyMMddHHmmss").format(new Date());
}
//sing签名
public static String getMD5(String sid,String token,String timestamp){
StringBuilder result=new StringBuilder();
String source=sid+token+timestamp;
//获取某个类的实例
try {
MessageDigest digest=MessageDigest.getInstance("MD5");
//要进行加密的东西
byte[] bytes=digest.digest(source.getBytes());
for(byte b:bytes){
String hex=Integer.toHexString(b&0xff);
if(hex.length()==1){
result.append("0"+hex);
}else{
result.append(hex);
}
}
} catch (NoSuchAlgorithmException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return result.toString();
}
//创建验证码
public static String smsCode(){
String random=(int)((Math.random()*9+1)*100000)+"";
return random;
}
}
接着是controller层
@Controller
public class CodeController {
@Resource
private ReturnContant returnContant;
/**
* 根据获取到的手机号发送验证码
* @param request
* @param phone 获取的手机号码
* @return
*/
@RequestMapping(value="/sendSMS.do",method=RequestMethod.POST)
public @ResponseBody ReturnContant sendSMS(HttpServletRequest request,String phone){
//根据获取到的手机号发送验证码
String code=GetMessageCode.getCode(phone);
returnContant.setStatus(1);
returnContant.setData(code);
return returnContant;
}
}
这里的ReturnContant是供ajax使用的封装类
@Component
public class ReturnContant implements Serializable{
/**
*
*/
private static final long serialVersionUID = 1L;
private int status;
private String msg;
private Object data;
public int getStatus() {
return status;
}
public void setStatus(int status) {
this.status = status;
}
public String getMsg() {
return msg;
}
public void setMsg(String msg) {
this.msg = msg;
}
public Object getData() {
return data;
}
public void setData(Object data) {
this.data = data;
}
}
到这里手机验证码就可以发送成功了,下面上图
最后就是验证手机验证码正确与否了,可详见上面的jsp页面。
图片验证码
这个利用的是jquery插件,上面的就是jsp界面引入了gVerify.js,里面的具体代码如下:
!(function(window, document) {
function GVerify(options) { //创建一个图形验证码对象,接收options对象为参数
this.options = { //默认options参数值
id: "", //容器Id
canvasId: "verifyCanvas", //canvas的ID
width: "100", //默认canvas宽度
height: "40", //默认canvas高度
type: "blend", //图形验证码默认类型blend:数字字母混合类型、number:纯数字、letter:纯字母
code: ""
}
if(Object.prototype.toString.call(options) == "[object Object]"){//判断传入参数类型
for(var i in options) { //根据传入的参数,修改默认参数值
this.options[i] = options[i];
}
}else{
this.options.id = options;
}
this.options.numArr = "0,1,2,3,4,5,6,7,8,9".split(",");
this.options.letterArr = getAllLetter();
this._init();
this.refresh();
}
GVerify.prototype = {
/**版本号**/
version: '1.0.0',
/**初始化方法**/
_init: function() {
var con = document.getElementById(this.options.id);
var canvas = document.createElement("canvas");
this.options.width = con.offsetWidth > 0 ? con.offsetWidth : "100";
this.options.height = con.offsetHeight > 0 ? con.offsetHeight : "40";
canvas.id = this.options.canvasId;
canvas.width = this.options.width;
canvas.height = this.options.height;
canvas.style.cursor = "pointer";
canvas.innerHTML = "您的浏览器版本不支持canvas";
con.appendChild(canvas);
var parent = this;
canvas.onclick = function(){
parent.refresh();
}
},
/**生成验证码**/
refresh: function() {
this.options.code = "";
var canvas = document.getElementById(this.options.canvasId);
if(canvas.getContext) {
var ctx = canvas.getContext('2d');
}else{
return;
}
ctx.textBaseline = "middle";
ctx.fillStyle = randomColor(180, 240);
ctx.fillRect(0, 0, this.options.width, this.options.height);
if(this.options.type == "blend") { //判断验证码类型
var txtArr = this.options.numArr.concat(this.options.letterArr);
} else if(this.options.type == "number") {
var txtArr = this.options.numArr;
} else {
var txtArr = this.options.letterArr;
}
for(var i = 1; i <= 4; i++) {
var txt = txtArr[randomNum(0, txtArr.length)];
this.options.code += txt;
ctx.font = randomNum(this.options.height/2, this.options.height) + 'px SimHei'; //随机生成字体大小
ctx.fillStyle = randomColor(50, 160); //随机生成字体颜色
ctx.shadowOffsetX = randomNum(-3, 3);
ctx.shadowOffsetY = randomNum(-3, 3);
ctx.shadowBlur = randomNum(-3, 3);
ctx.shadowColor = "rgba(0, 0, 0, 0.3)";
var x = this.options.width / 5 * i;
var y = this.options.height / 2;
var deg = randomNum(-30, 30);
/**设置旋转角度和坐标原点**/
ctx.translate(x, y);
ctx.rotate(deg * Math.PI / 180);
ctx.fillText(txt, 0, 0);
/**恢复旋转角度和坐标原点**/
ctx.rotate(-deg * Math.PI / 180);
ctx.translate(-x, -y);
}
/**绘制干扰线**//*
for(var i = 0; i < 4; i++) {
ctx.strokeStyle = randomColor(40, 180);
ctx.beginPath();
ctx.moveTo(randomNum(0, this.options.width), randomNum(0, this.options.height));
ctx.lineTo(randomNum(0, this.options.width), randomNum(0, this.options.height));
ctx.stroke();
}*/
/**绘制干扰点**/
for(var i = 0; i < this.options.width/4; i++) {
ctx.fillStyle = randomColor(0, 255);
ctx.beginPath();
ctx.arc(randomNum(0, this.options.width), randomNum(0, this.options.height), 1, 0, 2 * Math.PI);
ctx.fill();
}
},
/**验证验证码**/
validate: function(code){
var code = code.toLowerCase();
var v_code = this.options.code.toLowerCase();
console.log(v_code);
if(code == v_code){
return true;
}else{
this.refresh();
return false;
}
}
}
/**生成字母数组**/
function getAllLetter() {
var letterStr = "a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,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,O,P,Q,R,S,T,U,V,W,X,Y,Z";
return letterStr.split(",");
}
/**生成一个随机数**/
function randomNum(min, max) {
return Math.floor(Math.random() * (max - min) + min);
}
/**生成一个随机色**/
function randomColor(min, max) {
var r = randomNum(min, max);
var g = randomNum(min, max);
var b = randomNum(min, max);
return "rgb(" + r + "," + g + "," + b + ")";
}
window.GVerify = GVerify;
})(window, document);