package com.iamberry.app.service; import static com.iamberry.app.config.ImberryConfig.SMS_PASSWORD; import static com.iamberry.app.config.ImberryConfig.SMS_TEXT; import static com.iamberry.app.config.ImberryConfig.SMS_URL; import static com.iamberry.app.config.ImberryConfig.SMS_USERNAME; import java.text.MessageFormat; import java.util.ArrayList; import java.util.Date; import java.util.HashMap; import java.util.List; import java.util.Map; import org.apache.commons.lang3.StringUtils; import org.apache.http.HttpEntity; import org.apache.http.NameValuePair; import org.apache.http.client.entity.UrlEncodedFormEntity; import org.apache.http.client.methods.CloseableHttpResponse; import org.apache.http.client.methods.HttpPost; import org.apache.http.impl.client.CloseableHttpClient; import org.apache.http.impl.client.HttpClients; import org.apache.http.message.BasicNameValuePair; import org.apache.http.util.EntityUtils; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import com.iamberry.app.core.entity.CodeValid; import com.iamberry.app.face.CodeService; import com.iamberry.app.mapper.CodeMapper; import com.iamberry.app.tool.util.Result; import com.iamberry.app.ulitity.Utility; import com.iamberry.wechat.tools.ResponseJson; import com.thoughtworks.xstream.XStream; import com.thoughtworks.xstream.io.xml.StaxDriver; /** * @company 深圳爱贝源科技有限公司 * @website www.iamberry.com * @author 献 * @tel 18271840547 * @date 2016年11月1日 * @explain 验证码业务实现类 */ @Service public class CodeServiceImpl implements CodeService { @Autowired private CodeMapper codeMapper; @Override public ResponseJson sendCode(String phone, int codeScenario) { // TODO Auto-generated method stub // 第一步,判断使用通道,如果是+86开头,优先使用国内通道,否则默认使用国外通道 ResponseJson json = new ResponseJson(); if (StringUtils.isEmpty(phone)) { json.setReturnCode(404); json.addResponseKeyValue("Phone Empty!"); return json; } // 第二步,如果是国内,判断是否存在 CodeValid codeValid = codeMapper.getLast(phone); // 通道是否是中国的 boolean IS_CHANNEL_ZH = false; if (StringUtils.indexOf(phone, "+") != -1) { if (StringUtils.startsWith(phone, "+86")) { IS_CHANNEL_ZH = true; } } else { IS_CHANNEL_ZH = true; } // 判断通道 Date now = new Date(); if (IS_CHANNEL_ZH && codeValid != null) { // ** 切换通道需求:每次请求验证码,如果上一次验证码在一分钟以后,三分钟以内没有使用,那么切换通道 **// if (now.getTime() <= (codeValid.getCodeValidDate().getTime()) && (now.getTime() - 60000) >= codeValid.getCodeSendDate().getTime() && codeValid.getCodeUse() == 2 && codeValid.getCodeScenario() == codeScenario) { // 如果等待三分钟后,那么切换通道,暂时不切换 // IS_CHANNEL_ZH = false; } } // 获取验证码 String code = Utility.getRandomCode(4); json = sendCMS(phone, code, IS_CHANNEL_ZH ? 1 : 2); if (json.getReturnCode() != 200) { json = sendCMS(phone, code, IS_CHANNEL_ZH ? 1 : 2); } // 保存发送记录 codeValid = new CodeValid(); codeValid.setCodeChannel(IS_CHANNEL_ZH ? 1 : 2); codeValid.setCodeMsg(json.getReturnMsg().get("returnMsg").toString()); codeValid.setCodePhone(phone); codeValid.setCodeScenario(codeScenario); codeValid.setCodeSendDate(now); codeValid.setCodeValidDate(new Date(now.getTime() + 180000)); codeValid.setCodeStatus(json.getReturnCode() == 200 ? 3 : 4); codeValid.setCodeUse(2); codeValid.setCodeValue(Integer.parseInt(code)); codeMapper.save(codeValid); return json; } /** * @param phone 手机号码 * @param code 短信验证码 * @param channel 通道 1:主通道;2:备用通道(国外的电话通通使用此) * @return */ private ResponseJson sendCMS(String phone, String code, int channel) { // 国内号码 ResponseJson json = new ResponseJson(); json.setReturnCode(500); String result = null; try { if (channel == 1) { // 使用主通道 result = sendZHCMS(phone, code); } else { // 使用备用通道 result = sendOtherCMS(phone, code); } } catch (Exception e) { result = e.getMessage(); } if (StringUtils.equals(result, "SUCCESS")) { json.setReturnCode(200); } json.addResponseKeyValue(result); return json; } private String sendOtherCMS(String phone, String code) { System.out.println("使用备用通道,发送验证码成功!" + code); return "SUCCESS"; } private String sendZHCMS(String phone, String code) throws Exception { CloseableHttpClient client = HttpClients.createDefault(); Map params = new HashMap(); CloseableHttpResponse response = null; params.put("username", SMS_USERNAME); params.put("password", SMS_PASSWORD); params.put("mobile", phone); params.put("content", MessageFormat.format(SMS_TEXT, code)); HttpPost method = new HttpPost(SMS_URL); if (params != null) { List paramList = new ArrayList(); for (Map.Entry param : params.entrySet()) { NameValuePair pair = new BasicNameValuePair(param.getKey(), param.getValue()); paramList.add(pair); } method.setEntity(new UrlEncodedFormEntity(paramList, "UTF-8")); } response = client.execute(method); HttpEntity entity = response.getEntity(); if (entity != null) { String result = EntityUtils.toString(entity); XStream xs = new XStream(new StaxDriver()); xs.alias("result", Result.class); Result object = (Result)xs.fromXML(result); response.close(); if (0 == object.getResultcode()) { return "SUCCESS"; } else { return object.getResultcode() + ":" + object.getErrordescription(); } } return null; } @Override public ResponseJson validCode(String phone, String code, int codeScenario) { ResponseJson json = new ResponseJson(); // 校验 CodeValid codeValid = codeMapper.getLast(phone); if (codeValid == null) { // 操作有误 json.setReturnCode(404); json.addResponseKeyValue("Wrong operation, No send record"); return json; } Date now = new Date(); if (now.getTime() >= codeValid.getCodeValidDate().getTime()) { // 验证码无效 json.setReturnCode(403); json.addResponseKeyValue("Verification code is invalid"); return json; } // 验证码是否使用 1:已经使用;2:未使用 if (codeValid.getCodeUse().intValue() == 1) { // 验证码无效 json.setReturnCode(402); json.addResponseKeyValue("Verification code has been used"); return json; } // 必须 验证码正确,并且场景正确 if (!(codeValid.getCodeValue() == (Integer.parseInt(code)) && codeScenario == codeValid.getCodeScenario())) { // 验证码错误 json.setReturnCode(405); json.addResponseKeyValue("Verification code error"); return json; } // 只要校验成功,表示本次验证码已使用 codeMapper.update(codeValid.getCodeId()); json.setReturnCode(200); json.addResponseKeyValue("SUCCESS"); return json; } }