reg.ftl
<div class="formRow">
<input type="text" id="random" name="random" placeholder="短信验证码">
<button type="button" id="getCode" class="btn_code">获取验证码</button>
</div>
JS
/* ---------------- 验证用户名为手机号 ---------------- */
<span style="white-space:pre"> </span>function validation(tel){
<span style="white-space:pre"> </span> reg=/^1[3|4|5|7|8]\d{9}$/;
<span style="white-space:pre"> </span> return reg.test(tel);
<span style="white-space:pre"> </span>}
/* ---------------- jquery init ---------------- */
$(function(){
//点击获取验证码
$('.btn_code').on('click',function(){
$.ajax({
type:"post",
url:"${path}/reg/chickout",
data:$("#validation-form").serialize(),
success:function(data){
// 验证电话号码
var tel = $('#username').val();
if(tel=="" || !validation(tel)){
common.alert({content:'请输入正确的手机号码'});
return false;
}
if(data.code==500){
common.alert({content:data.msg});
return false;
}else{
<span style="color:#ff6666;">//获取验证码
getCode(tel);</span>
//启动计时器
timeOut();
}
<span style="white-space:pre"> </span>}
<span style="white-space:pre"> </span>})
});
/* ---------------- 获取验证码 ---------------- */
<span style="white-space:pre"> </span>function getCode(tel){
<span style="white-space:pre"> </span>$.ajax({
<span style="white-space:pre"> </span>type:"post",
<span style="white-space:pre"> </span>dataType:"json",
<span style="white-space:pre"> </span>data:{
<span style="white-space:pre"> </span>"username":tel
<span style="white-space:pre"> </span>},
<span style="white-space:pre"> </span><span style="color:#ff6666;">url:"${path}/message/reg",</span>
<span style="white-space:pre"> </span>success:function(data){
<span style="white-space:pre"> </span>if('200' == data.code){
<span style="white-space:pre"> </span>common.alert({content:'验证码已发送,请注意查收'});
<span style="white-space:pre"> </span>}else if('300' == data.code){
<span style="white-space:pre"> </span>$('#random').val(data.result);
<span style="white-space:pre"> </span>//common.alert({content:'短信接口被停用'});
<span style="white-space:pre"> </span>}else{
<span style="white-space:pre"> </span>common.alert({content:data.msg});
<span style="white-space:pre"> </span>}
<span style="white-space:pre"> </span>},error: function(XMLHttpRequest, textStatus, errorThrown) {
<span style="white-space:pre"> </span>common.alert({content:'网络异常'});
<span style="white-space:pre"> </span>}
<span style="white-space:pre"> </span>})
<span style="white-space:pre"> </span>}
RegController
/**
* 电脑端注册
* @author CHAN
*/
@Controller
@RequestMapping(value="/reg")
public class RegController extends BaseController {
Logger logger = Logger.getLogger(RegController.class);
@Autowired
private IMemberService memberService;
@Autowired
private IMemberLocationRecordService recordService;
@Autowired
private RedisService redisService;
/**
* 注册页面
*/
@RequestMapping(method = RequestMethod.GET)
public String reg(){
return "reg";
}
/**
* 注册
*/
@RequestMapping(method=RequestMethod.POST)
@ResponseBody
public ResultObject doReg(Member member,String random,RedirectAttributes redirectAttributes,HttpServletRequest request){
try {
/** -------- redis获取验证码 -------- **/
String randomInRedis = redisService.get("redis_login_"+member.getUsername());
if(!randomInRedis.equals(random)){
return new ResultObject("500", "短信验证码错误", null);
}
/** -------- 会员注册-------- **/
ResultObject rs = memberService.register(member);
/** -------- 会员登陆-------- **/
SSOToken st = new SSOToken(request);
st.setId(member.getId());
st.setType(1);
st.setData(member.getUsername());
//记住密码,设置 cookie 时长 1 周 = 604800 秒 【动态设置 maxAge 实现记住密码功能】
if ( "on".equals(request.getParameter("rememberMe")) ) {
request.setAttribute(SSOConfig.SSO_COOKIE_MAXAGE, 604800);
}
SSOHelper.setSSOCookie(request, response, st, true);
//记录地理位置
recordService.saveMemberLocationRecord(member,new Corporation(corpid),request);
return rs;
} catch (Exception e) {
logger.error("注册出错", e);
return new ResultObject("500", "注册出错", null);
}
}
@RequestMapping(value="/chickout",method=RequestMethod.POST)
@ResponseBody
public ResultObject chickout(Member member,String random,RedirectAttributes redirectAttributes,HttpServletRequest request,HttpSession session){
try {
/** -------- 检查用户名-------- **/
Member temp = memberService.findMemberByUsername(member.getUsername());
if(temp!=null){
return new ResultObject("500", "该手机号码已被注册", null);
}
//判断验证码
String code = (String) session.getAttribute("captcha");
String summitCode = request.getParameter("captcha");
if(StringUtils.isBlank(summitCode) || !StringUtils.equals(code.toLowerCase(), summitCode.toLowerCase())){
return new ResultObject("500", "验证码错误", "");
}
return new ResultObject("200", "手机号和图像验证码确认无误", null);
} catch (Exception e) {
logger.error("注册出错", e);
return new ResultObject("500", "注册出错", null);
}
}
/**
* 判断账号是否唯一
* true表示唯一
*/
@RequestMapping(value="/unique/username",method = RequestMethod.POST)
@ResponseBody
public boolean unique(String username){
try{
return memberService.unique(username);
}catch(Exception e){
logger.error("判断账号是否唯一,username="+username, e);
return false;
}
}
}
MessageController
/**
* 短消息控制器
*
* @author CHAN
*
*/
@Controller
@RequestMapping(value="/message")
public class MessageController extends BaseController {
Logger logger = LoggerFactory.getLogger(MessageController.class);
@Autowired
private IMessageChannelService messageChannelService;
@Autowired
private RedisService redisService;
<span style="color:#ff6666;">/**
* v1.0 注册验证码 2015-12-24 CHAN
*/
@RequestMapping(value="/reg",method=RequestMethod.POST)
@ResponseBody
public ResultObject sendMessage(@RequestParam String username){
try {
/** -------- 验证码生成 -------- **/
String random = RandomStringUtils.random(6, "0123456789");
/** -------- 将手机号,验证码存储到redis -------- **/
redisService.set("redis_login_"+username, random, 1200);//60s 20min
/** -------- 发送消息 -------- **/
Map<String, String> map = new HashMap<String, String>();
map.put("code", random);
ResultObject rs = messageChannelService.send(corpid, MessageTemplateEnum.VERIFYCODE.getValue(),
username, map);
return rs;
} catch (Exception e) {
logger.error("发送登陆验证码失败", e);
return new ResultObject("500", "发送登陆验证码失败", null);
}
}</span>
/**
* v1.0 修改密码验证码 2015-12-24 CHAN
*/
@RequestMapping(value="/forgetPassword",method=RequestMethod.POST)
@ResponseBody
public ResultObject sendMessageP(@RequestParam String username){
try {
/** -------- 验证码生成 -------- **/
String random = RandomStringUtils.random(6, "0123456789");
/** -------- 将手机号,验证码存储到redis -------- **/
redisService.set("redis_login_"+username, random, 300);//60s 5min
/** -------- 发送消息 -------- **/
Map<String, String> map = new HashMap<String, String>();
map.put("code", random);
ResultObject rs = messageChannelService.send(corpid, MessageTemplateEnum.VERIFYCODE.getValue(),
username, map);
return rs;
} catch (Exception e) {
logger.error("发送修改密码验证码失败", e);
return new ResultObject("500", "发送修改密码验证码失败", null);
}
}
}
@SuppressWarnings(value="all")
public interface IMessageChannelService extends IBaseService<MessageChannel>{
<span style="color:#cc33cc;">/** 查询当前企业的短信通道 */
public MessageChannel findMessageChannelByCorpId(Long corpid) throws Exception;</span>
<span style="color:#6633ff;">/** 短信接口请求 */
public ResultObject request(Long corpid,Integer templateTypeId,String action,String mobile,Map map) throws Exception;</span>
<span style="color:#ff6666;">/** 短信接口发送 */
public ResultObject send(Long corpid,Integer templateTypeId,String mobile,Map map) throws Exception;</span>
}
@SuppressWarnings(value="all")
@Component
public class MessageChannelServiceImpl extends BaseServiceImpl<MessageChannel> implements IMessageChannelService {
Logger logger = Logger.getLogger(MessageChannelServiceImpl.class);
@Autowired
private MessageChannelDao messageChannelDao;
@Autowired
private MessageRecordDao messageRecordDao;
@Autowired
private MessageTemplateDao messageTemplateDao;
@Autowired
private IMessageRecordService messageRecordService;
<span style="color:#cc33cc;">/** 查询当前企业的短信通道 */
@Override
public MessageChannel findMessageChannelByCorpId(Long corpid) throws Exception {
return messageChannelDao.findByCorpId(corpid);
}</span>
<span style="color:#3366ff;">/**
* 功能:短信请求
* create by chan on 2016-08-16
* @param corpid 企业id
* @param templateTypeId 短信模板类型
* @param action 动作
* @param mobile 手机号码
* @param map 短信模板参数
* @return
*/
@Override
public ResultObject request(Long corpid, Integer templateTypeId, String action, String mobile, Map map) throws Exception {
</span><span style="color:#cc33cc;">/** -------- 判断短信通道情况 --------*/
MessageChannel channel = findMessageChannelByCorpId(corpid);
if(channel.getStatus()==StatusEnum.STOP.getValue()){
return new ResultObject("300", "短信接口已停用",map.get("code"));
}
boolean isMinimumInterval = messageRecordService.isMinimumInterval(corpid, mobile);
if(isMinimumInterval){
return new ResultObject("301", "您发送短信过于频繁,请稍后点击发送",null);
}
boolean isReachWaringLine = messageRecordService.isReachWaringLine(corpid);
if(isReachWaringLine){
return new ResultObject("302", "超出日均最大短信数量",null);
}</span><span style="color:#3366ff;">
/** -------- 组织参数 --------*/
String url = channel.getUrl();
String userid = channel.getUserid();
String account = channel.getAccount();
String password = channel.getPassword();
String extno = channel.getExtno();
</span><span style="color:#999900;">//根据短信类型,查询出短信模板
String templateContent = messageTemplateDao.findByCorpIdAndType(corpid,templateTypeId).getContent();
StringBuffer cnt = new StringBuffer();
//根据短信模板,生成对应的短信记录
cnt.append("【").append(channel.getSign()).append("】").append(replaceTemplate(templateContent, map));
</span><span style="color:#3366ff;">
/** -------- 使用Httpclient发送请求参数 --------*/
HttpClient client = new HttpClient();
PostMethod post = new PostMethod(url);
try {
/*-------- 设置请求接口和参数 -------- */
post.addRequestHeader("Content-Type","application/x-www-form-urlencoded;charset=utf-8");// 在头文件中设置转码
NameValuePair[] data = {
new NameValuePair("action", action),
new NameValuePair("userid", userid),
new NameValuePair("account", account),
new NameValuePair("password", password),
new NameValuePair("mobile", mobile),
new NameValuePair("content", cnt.toString()),
new NameValuePair("extno", extno)
};
post.setRequestBody(data);
/* -------- 发送请求 -------- **/
client.executeMethod(post);
/* -------- 返回状态 -------- **/
// 返回状态
int statusCode = post.getStatusCode();
System.out.println("statusCode:" + statusCode);
// 返回头信息
// Header[] headers = post.getResponseHeaders();
// for (Header h : headers) {
// System.out.println(h.toString());
// }
/** -------- 处理结果--------*/
// 返回信息 {"smsid":"9EF0A9EC94139CDC57F812D0CFB314DA","code":"0"} 表示成功
//xml string->map
String result = new String(post.getResponseBody(),"UTF-8");
System.out.println(result);
Map<String,String> xmlobj = parseXml(result);
String returnstatus = xmlobj.get("returnstatus");
String message = xmlobj.get("message");
String remainpoint = xmlobj.get("remainpoint");
if (!returnstatus.equals("Success")){
return new ResultObject("500", "短信http通讯错误", null);
}
if(!message.equals("ok")){
return new ResultObject("500", "短信接口错误 :"+message, null);
}
//新增短信记录
MessageRecord record = new MessageRecord(mobile, cnt.toString());
record.setCorp(channel.getCorp());
record.setCreateTime(new Date());
record.setReturnstatus(returnstatus);
record.setMessage(message);
messageRecordDao.save(record);
//修改短信通道剩余条数
channel.setRemainpoint(Integer.parseInt(remainpoint));
messageChannelDao.save(channel);
return new ResultObject("200", "短信发送成功,注意查收", null);
} catch (Exception e) {
logger.error("短信接口错误", e);
return new ResultObject("500", "短信接口错误", null);
} finally {
// 释放链接
post.releaseConnection();
}
}</span>
<span style="color:#ff6666;">/** 短信接口发送 */
@Override
public ResultObject send(Long corpid,Integer templateTypeId,String mobile,Map map) throws Exception{
return request(corpid, templateTypeId, "send", mobile, map);
}
</span> public static Map<String,String> parseXml(String text) throws Exception{
Map<String,String> map = new HashMap<String, String>();
Document document = DocumentHelper.parseText(text);
//得到xml根元素
Element root = document.getRootElement();
List<Element> elements = root.elements();
for (Element element : elements) {
map.put(element.getName(), element.getText());
}
return map;
}
public static String generateString(String str,List<Object> list){
StringBuilder sb = new StringBuilder();
int i=0;
for(String temp : str.split("_")){
sb.append(temp);
if(i<list.size())
sb.append(list.get(i));
i++;
}
return sb.toString();
}
public static String replaceTemplate(String template,Map<String,String> map){
for (String key:map.keySet()) {
System.out.println("#"+key+"#");
template = template.replace("#"+key+"#", map.get(key));
}
return template;
}
public static Double formatString(String str){
Double db = Double.valueOf(str);
db=((int)(db*100))/100.0;
return db;
}
public static void main(String[] args) {
Map<String,String> map = new HashMap<String, String>();
map.put("code1", "aaa");
map.put("code2", "bbb");
String template= "#code1#,wcnm,#code2#";
template = replaceTemplate(template, map);
System.out.println(template);
}
// public static void main(String[] args) {
// //String result = "{\"smsid\":\"9EF0A9EC94139CDC57F812D0CFB314DA\",\"code\":\"0\"}";
// String result = "{\"code\":\"-1000\"}";
// JSONObject jsonobj = JSON.parseObject(result);
// int code = jsonobj.getInteger("code");
// String smsid = jsonobj.getString("smsid");
// System.out.println(code);
// System.out.println(smsid==null);
//
// String str = "尊敬的客户,您的账户_于_年_月_日成功充值,人民币_元。 回T退订.";
String str1 = "您的手机验证码为:_,请在5分钟内完有效。如非本人操作请忽略本短信。回T退订.";
// List<Object> list = new ArrayList<Object>();
// list.add("account");
// list.add("year");
// list.add("month");
// list.add("day");
// list.add(874198);
// System.out.println(generateString(str, list));
// }
}
IMessageRecordService
public interface IMessageRecordService extends IBaseService<MessageRecord> {
//计算当前时间和最新一条短信记录的时间差,单位是秒
public int calculateInterval(Long corpid, String mobile) throws Exception;
<span style="color:#cc33cc;">//判断是否,在发送最小间隔内
public boolean isMinimumInterval(Long corpid, String mobile) throws Exception;
//判断是否,达到预警线
public boolean isReachWaringLine(Long corpid) throws Exception;</span>
}
MessageRecordServiceImpl
@Component
public class MessageRecordServiceImpl extends BaseServiceImpl<MessageRecord> implements IMessageRecordService {
@Autowired
private MessageRecordDao recordDao;
@Autowired
private MessageChannelDao messageChannelDao;
/** ------------------------------- 扩展 ------------------------------*/
/**
* 计算当前时间和最新一条短信记录的时间差
* -1 表示没有任何一条记录
*/
public int calculateInterval(Long corpid, String mobile) throws Exception{
MessageRecord latestRecord = recordDao.findTopByCorpIdAndMobileOrderByCreateTimeDesc(corpid, mobile);
if(latestRecord==null){
return -1;
}
DateTime start = new DateTime(latestRecord.getCreateTime());
DateTime end = new DateTime();
int diff = Seconds.secondsBetween(start,end).getSeconds();
return diff;
}
<span style="color:#cc33cc;">/**
* 判断是否在发送最小间隔内 60s
* ps:短信通道是否停用,交给控制器处理
*/
@Override
public boolean isMinimumInterval(Long corpid, String mobile) throws Exception{
//短信通道
MessageChannel channel = messageChannelDao.findByCorpId(corpid);
//获得发送最小间隔时间,当前时间和最新一条短信记录的时间差
int minimumInterval = channel.getMinimumInterval();
int diff = calculateInterval(corpid, mobile);
System.out.println("最小间隔diff="+diff);
return (diff>=0 && diff<=minimumInterval)?true:false;
}</span>
<span style="color:#cc33cc;">/**
* 判断是否,达到预警线
*/
@Override
public boolean isReachWaringLine(Long corpid) throws Exception{
//获取警戒线,每日最大发送短信数量
MessageChannel channel = messageChannelDao.findByCorpId(corpid);
long warningLine = channel.getWarningLine().longValue();
Collection<SearchFilter> filters = new ArrayList<SearchFilter>();
filters.add(new SearchFilter("corp.id", Operator.EQ, corpid));
filters.add(new SearchFilter("createTime", Operator.GE, new DateTime().toString("yyyy-MM-dd")));
filters.add(new SearchFilter("createTime", Operator.LE, new DateTime().toString("yyyy-MM-dd")));
Specification<MessageRecord> spec = DynamicSpecifications.bySearchFilter(filters, MessageRecord.class);
long sendCount = recordDao.count(spec);
return (sendCount>warningLine)?true:false;
}</span>
}
MessageChannelDao
@Repository
public interface MessageChannelDao extends BaseRepository<MessageChannel, Long>, JpaSpecificationExecutor<MessageChannel> {
<span style="color:#cc33cc;">MessageChannel findByCorpId(Long corpid);</span>
}
MessageTemplateDao
@Repository
public interface MessageTemplateDao extends BaseRepository<MessageTemplate, Long>, JpaSpecificationExecutor<MessageTemplate>{
<span style="color:#009900;">MessageTemplate findByCorpIdAndType(Long corpid,Integer type);</span>
}
MessageTemplateEnum
public enum MessageTemplateEnum {
VERIFYCODE(1,"发送验证码"),ORDER_SUCCESS(2,"下单成功"),PAY_SUCCESS(3,"订单支付"),DELIVERY_SUCCESS(4,"订单发货");
private int value;
private String comment;
private MessageTemplateEnum(int value, String comment) {
this.value = value;
this.comment = comment;
}
public int getValue() {
return value;
}
public void setValue(int value) {
this.value = value;
}
public String getComment() {
return comment;
}
public void setComment(String comment) {
this.comment = comment;
}
public static MessageTemplateEnum get(int value){
for (MessageTemplateEnum o:MessageTemplateEnum.values()) {
if(o.value ==value){
return o;
}
}
return null;
}
}