实现图片验证码与手机短信验证码:
1、HTML 代码:
<!-- 和验证码一样大小的提示图片:"请输入手机号" -->
<input type="hidden" value="${@cn.mycs.core.util.ToolUtil.url(@cn.mycs.core.constant.CommonConstant.DOMAINS_STATIC)}/2.0.0/images/safeCode.jpg" id="tipImageUrl">
<div class="form-group">
<label for="" class="control-label col-sm-3">联系人手机:</label>
<div class="col-sm-9">
<input maxlength="11" name="phone" placeholder="负责人手机" data="手机号码" warn="请输入11位数的手机号!" data-options="required:true" type="text" class="form-control easyui-validatebox" id="phone2">
<span class="reg_warn" style="color: red;"></span>
</div>
</div>
<div class="form-group">
<label for="" class="control-label col-sm-3">验证码:</label>
<div class="col-sm-9">
<div class="row">
<div class="col-sm-4">
<input name="safeCode" id="safeCode2" maxlength="4" data="验证码" warn="4位字符的验证码!" type="text" data-options="required:true,tipPosition:'left'" class="form-control easyui-validatebox">
</div>
<div class="col-sm-4">
<img class="validate-img" src="${@cn.mycs.core.util.ToolUtil.url(@cn.mycs.core.constant.CommonConstant.DOMAINS_STATIC)}/2.0.0/images/safeCode.jpg" id="validate-img2" />
</div>
</div>
</div>
</div>
<div class="form-group">
<label for="" class="control-label col-sm-3">短信验证码:</label>
<div class="col-sm-9">
<div class="row">
<div class="col-sm-4">
<input name="smsCodeM" maxlength="6" placeholder="6位验证码" data="手机验证码" warn="请输入手机验证码!" type="text" class="form-control easyui-validatebox" />
<span class="reg_warn" style="color: red;"></span>
</div>
<div class="col-sm-8">
<button type="button" class="btn btn-primary" id="big_gray_btn2">发送验证码</button>
</div>
</div>
</div>
</div>
2、js代码:
//手机号输入事件
$("input[name='phone']").keyup(function () {
var _this = $(this), v = _this.val(), obj_safeCode = _this.parent().parent().next("div").find(".validate-img");
if (_this.data("v") != v) {
_this.data("v", v);
/^1\d{10}$/.test(v) ? obj_safeCode.trigger("click") : obj_safeCode.attr("src", $("#tipImageUrl").val());
}
});
//验证码点击事件
$("#validate-img1").click(function () {
var error = $(".reg_error");
for (var i = 0; i < error.length; i++) {
if (error.eq(0 + "").html()=="该手机号已被绑定") {
return;
}
}
var v = $("#phone1").val();
$(this).parent().prev("div").find("input[name='safeCode']").val("");
/^1\d{10}$/.test(v) && $(this).attr("src", _ctx + "/validateCode?refresh=" + Math.random());
});
//发送(手机|邮箱)验证码
$("#big_gray_btn1").click(function () {
var error = $(".reg_error");
for (var i = 0; i < error.length; i++) {
if (error.eq(0 + "").html()=="该手机号已被绑定") {
alert("该手机号已被绑定","error");
return;
}
}
var _this = $(this), txt = _this.text(), div = _this.closest("div");
if (txt == "发送验证码") {
var tel_input = $("#phone1");
var safeCode = $("#safeCode1").val();
var tel_mess = tel_input.parent().nextAll("span").text();
var tel = tel_input.val();
if (tel_mess == "该号码已被绑定") {
alert("请重新输入手机号码", "error");
} else if (!/^[a-zA-Z0-9]{4}$/.test(safeCode)) {
alert("请先输入正确的验证码!", "error");
} else if (/^1\d{10}$/.test(tel)) {
_this.text("请稍候……");
_this.nextAll("span").hide();
$.getJSON(_ctx + "/app/mobileSms?action=send&captchaCode=" + safeCode + "&phone=" + tel + "&" + Math.random(), function (json) {
_this.text(txt);
if (1 != json.code) {
alert(json.message, "error");
if (json.message == "图形验证码错误") {
$("#validate-img1").click();
}
} else {
setT(_this, 180, txt);
div.nextAll("span").text("此手机验证码30分钟内有效").attr({"class": "reg_warn"}).show();
}
});
} else {
div.css("border-color", "#dedede").nextAll("span").text("请先输入正确的手机号!").attr({"class": "reg_warn"});
tel_input.focus().parent().css("border-color", "#f77979").nextAll("span").attr("class", "reg_error");
}
}
});
3、发送短信 控制器 Controller:
package cn.wpg.client.web.controller.persional;
import cn.wpg.core.base.restful.JsonResult;
import cn.wpg.core.constant.MobileProperties;
import cn.wpg.core.support.StrKit;
import cn.wpg.core.util.MobileSmsUtil;
import cn.wpg.server.persistence.redis.RedisService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import javax.servlet.http.HttpServletRequest;
import java.util.Random;
/**
* <p>发送短信 控制器 Controller</p>
* <pre>
* @author Wupeiguo
* @date 2019/06/14 11:42
* </pre>
*/
@Controller
public class MobileSmsController {
private final Logger log = LoggerFactory.getLogger(getClass());
@Autowired
private RedisService redisService;
@RequestMapping("/app/mobileSms")
@ResponseBody
public JsonResult mobileSms(String action, String captchaCode, String phone, HttpServletRequest request) {
if (StrKit.isEmpty(action) || StrKit.isEmpty(phone)) {
log.debug("参数错误");
return JsonResult.error("参数错误");
}
//获取redis 图形验证码做校验
String code = redisService.get("cookiesReplyKey", 8, String.class);
if (StrKit.isEmpty(code)) {
log.debug("请重新获取图形验证码");
return JsonResult.error("请重新获取图形验证码");
} else if (!code.equalsIgnoreCase(captchaCode)) {
log.debug("图形验证码错误");
return JsonResult.error("图形验证码错误");
} else if ("sendCode".equals(action)) {
return sendCode(phone);
}
return JsonResult.success("发送成功");
}
private JsonResult sendCode(String phone) {
log.debug("发送手机验证码");
String key = "smsCode_" + phone;
Object redisCode = redisService.get(key, Object.class);
if (redisCode != null) {
log.info("稍后再试");
return JsonResult.error("稍后再试");
}
//生成随机号码
final String smsCode = getRandomCode();
//发送短信验证码
JsonResult result = MobileSmsUtil.send(MobileProperties.SMS_APPID, phone, MobileProperties.SMS_TEMPLATEID, smsCode, "json");
if (result.getCode() == 1) {
redisService.set(key, smsCode, 120);
log.info("发送短信验证码成功");
return JsonResult.success("发送成功");
} else {
log.info("发送短信验证码失败");
return JsonResult.error("发送失败");
}
}
/***
* 生成随机号码 6位
* @return
*/
private String getRandomCode() {
Random random = new Random();
StringBuilder sb = new StringBuilder();
for (int i = 0; i < 6; i++) {
sb.append(random.nextInt(10));
}
return sb.toString();
}
}
4、发送短信相关的配置 Properties:
package cn.wpg.core.constant;
import cn.wpg.core.util.MD5Util;
import java.util.Base64;
import java.util.Date;
/**
* <p>发送短信相关的配置 Properties</p>
* <pre>
* @author Wupeiguo
* @date 2019/06/14 11:42
* </pre>
*/
public class MobileProperties {
/**
* API请求地址
*/
private static final String SMS_BASE_URL = "https://api.XXX.com/";
/**
* 云之讯REST API版本号。当前版本号为:2014-06-30
*/
private static final String SMS_SOFTVERSION = "2014-06-30";
/**
* 开发者账号ID。由32个英文字母和阿拉伯数字组成的开发者账号唯一标识符。
*/
private static final String SMS_ACCOUNT_SID = "96ea71afc8a76e978cbc13f67a4aa624";
/**
* 开发者账号TOKEN
*/
private static final String SMS_TOKEN = "c59ff426f4c88a2dc0e612a6c860b144";
private static String timestamp;
public static final String SMS_APPID = "5edd47ba7fa84465a90c1d08ac8c9547";
public static final String SMS_TEMPLATEID = "51730";
/**
* @return string
* 验证参数,URL后必须带有sig参数,sig= MD5(账户Id + 账户授权令牌 + 时间戳,共32位)(注:转成大写)
*/
private static String getSigParameter() {
String sig = SMS_ACCOUNT_SID + SMS_TOKEN + timestamp;
sig = MD5Util.encrypt(sig);
return sig.toUpperCase();
}
private static String getTimestamp() {
return format(new Date(), "yyyyMMddHHmmss");
}
public static String getSendSmsUrl() {
timestamp=getTimestamp();
return SMS_BASE_URL + SMS_SOFTVERSION + "/Accounts/" + SMS_ACCOUNT_SID + "/Messages/templateSMS?sig=" + getSigParameter();
}
public static String getAuthorization() {
String data = SMS_ACCOUNT_SID + ":" + timestamp;
return Base64.getEncoder().encodeToString(data.getBytes());
}
/**
* 根据特定格式格式化日期
*
* @param date 被格式化的日期
* @param format 格式
* @return 格式化后的字符串
*/
public static String format(Date date, String format) {
return new SimpleDateFormat(format).format(date);
}
}
5、手机发送短信工具 Util:
package cn.wpg.core.util;
import cn.wpg.core.base.restful.JsonResult;
import cn.wpg.core.constant.MobileProperties;
import com.alibaba.fastjson.JSONObject;
import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.HttpStatus;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.util.EntityUtils;
import java.nio.charset.Charset;
import java.util.HashMap;
import java.util.Map;
/**
* <p>手机发送短信工具 Util</p>
* <pre>
* @author Wupeiguo
* @date 2019/06/14 11:42
* </pre>
*/
public class MobileSmsUtil {
public static JsonResult send(String appId, String phone, String templateId, String smsCode, String type) {
String sendSmsUrl = MobileProperties.getSendSmsUrl();
String body;
if ("json".equals(type)) {
JSONObject json = new JSONObject();
Map<String, String> bodyMap = new HashMap<>(4);
bodyMap.put("appId", appId);
bodyMap.put("templateId", templateId);
bodyMap.put("appId", appId);
bodyMap.put("to", phone);
bodyMap.put("param", smsCode);
json.put("templateSMS", bodyMap);
body = json.toJSONString();
} else if ("xml".equals(type)) {
String bodyXml = "<?xml version='1.0' encoding='UTF-8' standalone='yes'?>" +
"<templateSMS>" +
"<templateId>" + templateId + "</templateId>" +
"<to>" + phone + "</to>" +
"<param>" + smsCode + "</param>" +
"<appId>" + appId + "</appId>" +
"</templateSMS>";
body = bodyXml;
} else {
throw new RuntimeException("只能json或xml,默认为json");
}
String result = doSend(sendSmsUrl, body, type);
return result == null ?JsonResult.error("发送失败"):JsonResult.success(result);
}
private static String doSend(String url, String body, String type) {
String mine;
if ("json".equals(type)) {
mine = "application/json";
} else {
mine = "application/xml";
}
Map<String, String> header = new HashMap<>(3);
header.put("Accept", mine);
header.put("Content-Type", mine + ";charset=utf-8");
header.put("Authorization", MobileProperties.getAuthorization());
return HdoPost(url, body, header);
}
private static String HdoPost(String url, String body, Map<String, String> header) {
HttpClient httpClient;
HttpPost postMethod;
HttpResponse response;
try {
httpClient = HttpClients.createDefault();
//传入URL地址
postMethod = new HttpPost(url);
//设置请求头
if (header != null) {
for (Map.Entry<String, String> entry : header.entrySet()) {
//设置请求头
postMethod.addHeader(entry.getKey(), entry.getValue());
}
}
// 传入请求参数
postMethod.setEntity(new StringEntity(body, Charset.forName("UTF-8")));
// 获取响应
response = httpClient.execute(postMethod);
int statusCode = response.getStatusLine().getStatusCode();
System.out.println("HTTP Status Code:" + statusCode);
if (statusCode != HttpStatus.SC_OK) {
System.out.println("HTTP请求未成功!HTTP Status Code:" + response.getStatusLine());
return null;
}
HttpEntity httpEntity = response.getEntity();
String reponseContent = EntityUtils.toString(httpEntity);
// 释放资源
EntityUtils.consume(httpEntity);
System.out.println("响应内容:" + reponseContent);
} catch (Exception e) {
e.printStackTrace();
}
return "";
}
}
6、MD5加密类(封装jdk自带的md5加密方法):
package cn.wpg.core.util;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
/**
* MD5加密类(封装jdk自带的md5加密方法)
* @author zhangzhc
* @date 2018-06-07 10:57:38
*/
public class MD5Util {
/**
* 安全码
*/
public static final String SECURITY_CODE = "wha3202343222dxssssssswwd";
/**
* md5加密密码
*
* @param source 源数据
* @param salt 盐
* @return String
*/
public static String encryptAndSalt(String source, String salt) {
salt = (salt != null ? salt : "") + SECURITY_CODE;
source = MD5Util.encrypt(source) + salt;
return MD5Util.encrypt(source);
}
/**
* md5加密
*
* @param source 源数据
* @return String
*/
public static String encrypt(String source) {
return encodeMd5(source.getBytes());
}
private static String encodeMd5(byte[] source) {
try {
return encodeHex(MessageDigest.getInstance("MD5").digest(source));
} catch (NoSuchAlgorithmException e) {
throw new IllegalStateException(e.getMessage(), e);
}
}
private static String encodeHex(byte[] bytes) {
StringBuffer buffer = new StringBuffer(bytes.length * 2);
for (int i = 0; i < bytes.length; i++) {
if (((int) bytes[i] & 0xff) < 0x10) {
buffer.append("0");
}
buffer.append(Long.toString((int) bytes[i] & 0xff, 16));
}
return buffer.toString();
}
public static void main(String[] args) {
System.out.println(encrypt("123456"));
}
}
7、备注:
jar包:
com.alibaba.fastjson:
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>${fastjson.version}</version>
</dependency>
org.apache.http:
<dependency>
<groupId>org.apache.activemq</groupId>
<artifactId>activemq-http</artifactId>
</dependency>
结果类 JsonResult:
该操作结果类为自定义类,可以用 Object 类型替代
获取图形验证码:
在《图形验证码》篇