本人为实习生,第一次写博客,写的不好的大家多多谅解
应公司近期需求,需要单独开发一个后台管理系统。
自己按实际业务写了一个登录接口已经实现,时序图如下
源码牵扯业务量太大,这里只放出部分关键实现源码,整合思路可以配合时序图去理解。
Controller层
package com.royalnu.business.login.franchisee.gateway.web;
import java.sql.Timestamp;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import java.util.List;
import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import org.apache.poi.util.StringUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import com.alibaba.druid.util.StringUtils;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.royalnu.common.exception.CommonException;
import com.royalnu.common.security.MD5Utils;
import com.royalnu.common.utils.json.GsonUtil;
import com.royalnu.common.validate.json.JsonSchemaValidator;
import com.royalnu.core.component.cache.redis.service.StringRedisCache;
import com.royalnu.core.module.com.BaseController;
import com.royalnu.business.login.franchisee.api.model.Franchisee;
import com.royalnu.business.login.franchisee.api.service.FranchiseeService;
import com.royalnu.business.login.franchiseeDetailed.api.model.FranchiseeDetailed;
import com.royalnu.business.login.franchiseeDetailed.api.service.FranchiseeDetailedService;
import com.royalnu.business.login.message.api.model.Message;
import com.royalnu.business.login.message.api.service.MessageService;
import com.royalnu.util.FilePath;
import com.royalnu.util.FranchiseeMethodUtils;
import com.royalnu.util.FranchiseeParamUtils;
import com.royalnu.util.InitializationUtil;
import com.royalnu.util.IpUtil;
import com.royalnu.util.RedisKeyPrefixUtil;
import com.royalnu.util.SingleSendSms;
import com.royalnu.util.VerifyCode;
import lombok.extern.log4j.Log4j2;
@Log4j2
@SuppressWarnings("unused")
@RestController
@RequestMapping(value = "/franchisee/login")
public class FranchiseeController extends BaseController<Franchisee> {
@Autowired
private FilePath filePath;
@Resource
private FranchiseeService franchiseeService;
@Resource
private FranchiseeDetailedService franchiseeDetailedService;
@Resource
private MessageService messageService;
@Resource
private StringRedisCache stringRedisCache;
@Autowired
private HttpSession session;
private IpUtil ipUtil = new IpUtil();
// 加盟商登录入口 附手机验证码
@RequestMapping(value = "/dologin", method = RequestMethod.POST)
public String dologin(Franchisee franchisee, HttpServletRequest request,HttpServletResponse response) throws CommonException {
Map<String, Object> data = new HashMap<String, Object>();
Map<String, Object> params = new HashMap<>();
// 验证请求手机号
String codeTelephone = request.getParameter("codeTelephone");
// 验证码
String codeNum = request.getParameter("codeNum");
// 获取ip地址
String UserIp = ipUtil.getIpAddr(request);
// 获取系统当前时间
Timestamp currentTime = new Timestamp(System.currentTimeMillis());
// 模拟前端加密传参
/*String idip = "ww-" + franchisee.getTelephone() + "{xykj}" + UserIp + "+lsw";*/
String idipPassword = request.getParameter("idipPassword");
// 后台解密获取正确参数
if(idipPassword==null||idipPassword.equals("")) {
data.put("code", 2);
data.put("msg", "访问源IP地址非法,请确认");
return GsonUtil.GSON.toJson(data);
}
String idipPassword1 = idipPassword.substring(3, idipPassword.length() - 4).replace("{xykj}", "");
Message message1 = messageService.getNewestMessage(codeTelephone);
Franchisee franchisee1 = franchiseeService.selectByQuery(franchisee);
if (franchisee1 == null) {
data.put("code", 1);
data.put("msg", "账号或密码输入错误");
return GsonUtil.GSON.toJson(data);
} else if (!idipPassword1.equals(franchisee.getTelephone() + UserIp)) {
data.put("code", 2);
data.put("msg", "访问源IP地址非法,请确认");
return GsonUtil.GSON.toJson(data);
}
int count = franchiseeDetailedService.selectTelephoneByCount(franchisee.getTelephone());
if (count <= 0) {
FranchiseeDetailed fd1 = new FranchiseeDetailed();
fd1.setCreateTime(new Date());
fd1.setRealIp(UserIp);
fd1.setFId(franchisee1.getId());
// 插入加盟商详细表记录登录情况
franchiseeDetailedService.insertSelective(fd1);
}
FranchiseeDetailed fd = franchiseeDetailedService.selectByTelephone(franchisee1.getTelephone());
// 判断前端是否接受到参数
if (codeTelephone == null || codeTelephone.equals("") && codeNum == null || codeNum.equals("")) {
// 当天是否获取过验证码,同天IP地址是否发生改变
if (fd != null && fd.getLastTime() != null && fd.getLastTime().getYear() == currentTime.getYear()
&& fd.getLastTime().getMonth() == currentTime.getMonth()
&& fd.getLastTime().getDay() == currentTime.getDay() && UserIp.equals(fd.getRealIp())) {
String token = MD5Utils.md5(franchisee.getUserName()
+ franchisee.getPassword() + System.currentTimeMillis());
fd = franchiseeDetailedService.selectByTelephone(franchisee1.getTelephone());
fd.setRealIp(UserIp);
fd.setFId(franchisee1.getId());
fd.setLastTime(new Date());
fd.setToken(token);
// 插入加盟商详细表记录登录情况
franchiseeDetailedService.updateByPrimaryKeySelective(fd);
//插入cokie,redis
this.getUserCokieRedis(franchisee, response);
data.put("code", 3);
data.put("msg", "登陆成功");
return GsonUtil.GSON.toJson(data);
// 需要重新获取新验证码
} else if (fd == null || fd.getLastTime() == null
|| (fd.getLastTime().getYear() != currentTime.getYear()
|| fd.getLastTime().getMonth() != currentTime.getMonth()
|| fd.getLastTime().getDay() != currentTime.getDay())
|| !UserIp.equals(fd.getRealIp())) {
fd = franchiseeDetailedService.selectByTelephone(franchisee1.getTelephone());
fd.setRealIp(UserIp);
fd.setUpdateTime(new Date());
fd.setFId(franchisee1.getId());
franchiseeDetailedService.updateByPrimaryKeySelective(fd);
data.put("code", 4);
data.put("msg", "系统检测您在一台新的设备或者当天第一次登录,为保障您\r\n" +
"的账户安全,需要进行一次身份核实。");
return GsonUtil.GSON.toJson(data);
} else {
data.put("code", 5);
data.put("msg", "检测到异常");
return GsonUtil.GSON.toJson(data);
}
// 需要验证码登录
} else {
if (message1 == null) {
data.put("code", 6);
data.put("msg", "验证码发送异常,请重新获取验证码");
return GsonUtil.GSON.toJson(data);
} else if (messageService.getCurListCount(params) >= 100) {
data.put("code", 7);
data.put("msg", "验证码获取次数超限,请联系运营人员");
return GsonUtil.GSON.toJson(data);
} else if (!codeNum.equals(message1.getCode())) {
fd = franchiseeDetailedService.selectByTelephone(franchisee1.getTelephone());
fd.setRealIp(UserIp);
fd.setFId(franchisee1.getId());
fd.setUpdateTime(new Date());
// 插入加盟商详细表记录登录情况
franchiseeDetailedService.updateByPrimaryKeySelective(fd);
data.put("code", 8);
data.put("msg", "验证码输入错误");
return GsonUtil.GSON.toJson(data);
} else {
String token = MD5Utils.md5(franchisee.getUserName()
+ franchisee.getPassword() + System.currentTimeMillis());
fd = franchiseeDetailedService.selectByTelephone(franchisee1.getTelephone());
fd.setRealIp(UserIp);
fd.setFId(franchisee1.getId());
fd.setLastTime(new Date());
fd.setToken(token);
// 插入加盟商详细表记录登录情况
franchiseeDetailedService.updateByPrimaryKeySelective(fd);
//插入cokie,redis
this.getUserCokieRedis(franchisee, response);
data.put("code", 3);
data.put("msg", "登陆成功");
return GsonUtil.GSON.toJson(data);
}
}
}
//获取验证码方法
@RequestMapping(value = "/dogetCode", method = RequestMethod.POST)
public String getCode(HttpServletRequest request) throws Exception {
Map<String, Object> data = new HashMap<String, Object>();
// 验证请求手机号
String codeTelephone = request.getParameter("codeTelephone");
// 新增验证码
Message message = new Message();
message.setTelephone(codeTelephone);
// 生成验证码
VerifyCode v = new VerifyCode();
String code = v.productCode();
// 发送验证码
SingleSendSms app = new SingleSendSms();
app.sendMsg(codeTelephone, code);
// 插入消息
message.setCode(code);
message.setCreatetime(new Date());
message.setState(1);
messageService.insertSelective(message);
data.put("code", 5);
data.put("msg", "已经发送验证码,请查收");
return GsonUtil.GSON.toJson(data);
}
//插入cokie,redis
public void getUserCokieRedis(Franchisee franchisee,
HttpServletResponse response) {
Franchisee franchisee1 = franchiseeService.selectByQuery(franchisee);
// 登录名+密码+时间戳进行md5加密生产token
String token = MD5Utils.md5(franchisee1.getUserName()
+ franchisee1.getPassword() + System.currentTimeMillis());
// 发送cookie
FranchiseeMethodUtils.responseCookie(response, franchisee1.getId(),
franchisee1.getUserName(), token);
// 往缓存放置登录token,以便后续所有操作的验证
stringRedisCache.set(FranchiseeParamUtils.REDIS_FRANCHISEE_PREFIX
+ franchisee1.getUserName() + "-" + franchisee1.getId(), token,
FranchiseeParamUtils.REDIS_TIMEOUT_TOKEN,
FranchiseeParamUtils.REDIS_UNIT_TOKEN);
}
}
获取用户IP地址
package com.royalnu.util;
import javax.servlet.http.HttpServletRequest;
import java.net.InetAddress;
import java.net.UnknownHostException;
public class IpUtil {
/**
* 获取登录用户IP地址
*
* @param request
* @return
*/
public static String getIpAddr(HttpServletRequest request) {
String ip = request.getHeader("x-forwarded-for");
if(ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
ip = request.getHeader("Proxy-Client-IP");
}
if(ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
ip = request.getHeader("WL-Proxy-Client-IP");
}
if(ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
ip = request.getRemoteAddr();
if (ip.equals("127.0.0.1")) {
//根据网卡取本机配置的IP
InetAddress inet = null;
try {
inet = InetAddress.getLocalHost();
} catch (UnknownHostException e) {
e.printStackTrace();
}
ip = inet.getHostAddress();
}
}
// 对于通过多个代理的情况,第一个IP为客户端真实IP,多个IP按照','分割
if(ip != null && ip.length() > 15){
if(ip.indexOf(",") > 0){
ip = ip.substring(0, ip.indexOf(","));
}
}
return ip;
}
}
验证码实体类
package com.royalnu.util;
import com.royalnu.core.module.com.Identifiable;
import java.util.Date;
import lombok.Getter;
import lombok.Setter;
@Setter
@Getter
public class Message extends Identifiable {
private static final long serialVersionUID = 1L;
/**
* <pre>
* </pre>
*
*/
private String telephone;
/**
* <pre>
* </pre>
*
*/
private String code;
/**
* <pre>
* </pre>
*
*/
private Date createtime;
/**
* <pre>
* </pre>
*
*/
private String connectId;
/**
* <pre>
* </pre>
*
*/
private Integer state;
/**
* <pre>
* </pre>
*
*/
private String remark;
}
产生随机数(验证码)
package com.royalnu.util;
import java.util.Random;
public class MyRandom {
static Random r = new Random();
static String ssource = "0123456789";
static char[] src = ssource.toCharArray();
//产生随机字符串
private static String randString (int length)
{
char[] buf = new char[length];
int rnd;
for(int i=0;i<length;i++)
{
rnd = Math.abs(r.nextInt()) % src.length;
buf[i] = src[rnd];
}
return new String(buf);
}
//调用该方法,产生随机字符串,
//参数i: 为字符串的长度
public static String runVerifyCode(int i)
{
String VerifyCode = randString(i);
return VerifyCode;
}
public static void main(String[] args) {
MyRandom t=new MyRandom();
System.out.println(t.runVerifyCode(6));
}
}
package com.royalnu.util;
import java.util.Random;
public class VerifyCode {
private int codeCount = 6;
char[] codeSequence = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9' };
public String productCode() {
// 创建一个随机数生成器类
Random random = new Random();
// randomCode用于保存随机产生的验证码,以便用户登录后进行验证。
StringBuffer randomCode = new StringBuffer();
// 随机产生codeCount数字的验证码。
for (int i = 0; i < codeCount; i++) {
// 得到随机产生的验证码数字。
String strRand = String.valueOf(codeSequence[random.nextInt(10)]);
// 将产生的四个随机数组合在一起。
randomCode.append(strRand);
}
return randomCode.toString();
}
public static void main(String[] args) {
VerifyCode v = new VerifyCode();
System.out.println(v.productCode());
}
}
云通信短信API产品(需要pom.xml)
package com.royalnu.util;
import java.util.HashMap;
import java.util.Map;
import java.util.Map.Entry;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.aliyuncs.DefaultAcsClient;
import com.aliyuncs.IAcsClient;
import com.aliyuncs.dysmsapi.model.v20170525.SendSmsRequest;
import com.aliyuncs.dysmsapi.model.v20170525.SendSmsResponse;
import com.aliyuncs.profile.DefaultProfile;
import com.aliyuncs.profile.IClientProfile;
public class SingleSendSms {
// private final static String APP_KEY = "23865664"; // AppKey从控制台获取
// private final static String APP_SECRET =
// "4683eef32debc7e0d9847dc5924e0345"; // AppSecret从控制台获取
// private final static String SIGN_NAME = "创跃网络科技公司"; //
// 签名名称从控制台获取,必须是审核通过的
// private final static String TEMPLATE_CODE = "SMS_72940060"; //
// 模板CODE从控制台获取,必须是审核通过的
// private final static String HOST = "sms.market.alicloudapi.com"; //
// API域名从控制台获取
// 产品名称:云通信短信API产品,开发者无需替换
static final String product = "Dysmsapi";
// 产品域名,开发者无需替换
static final String domain = "dysmsapi.aliyuncs.com";
static final String accessKeyId = "LTAIyH6tgxGSmnXK";
static final String accessKeySecret = "cBmLUp1FyoEVPA7swkwoTXj5fOKzb3";
/*
* 尊敬的${customer},欢迎您使用阿里大鱼短信服务,阿里大鱼将为您提供便捷的通信服务!
*/
private final static String ERRORKEY = "errorMessage"; // 返回错误的key
// @phoneNum: 目标手机号,多个手机号可以逗号分隔;
// @params: 短信模板中的变量,数字必须转换为字符串,如短信模板中变量为${no}",则参数params的值为{"no":"123456"}
public void sendMsg(String phoneNum, String params) throws Exception {
System.setProperty("sun.net.client.defaultConnectTimeout", "10000");
System.setProperty("sun.net.client.defaultReadTimeout", "10000");
// 初始化acsClient,暂不支持region化
IClientProfile profile = DefaultProfile.getProfile("cn-hangzhou",
accessKeyId, accessKeySecret);
DefaultProfile.addEndpoint("cn-hangzhou", "cn-hangzhou", product,
domain);
IAcsClient acsClient = new DefaultAcsClient(profile);
// 组装请求对象-具体描述见控制台-文档部分内容
SendSmsRequest request = new SendSmsRequest();
// 必填:待发送手机号
request.setPhoneNumbers(phoneNum);
// 必填:短信签名-可在短信控制台中找到
request.setSignName("十一分便利店");
// 必填:短信模板-可在短信控制台中找到
request.setTemplateCode("SMS_115680033");
// 可选:模板中的变量替换JSON串,如模板内容为"亲爱的${name},您的验证码为${code}"时,此处的值为
request.setTemplateParam("{\"code\":" + "\"" + params + "\"}");
// 选填-上行短信扩展码(无特殊需求用户请忽略此字段)
// request.setSmsUpExtendCode("90997");
// 可选:outId为提供给业务方扩展字段,最终在短信回执消息中将此值带回给调用者
request.setOutId("yourOutId");
SendSmsResponse sendSmsResponse = acsClient.getAcsResponse(request);
/*
* String path = "/singleSendSms";
*
* Request request = new Request(Method.GET, HttpSchema.HTTP + HOST,
* path, APP_KEY, APP_SECRET, Constants.DEFAULT_TIMEOUT);
*
* // 请求的query Map<String, String> querys = new HashMap<String,
* String>(); querys.put("SignName", SIGN_NAME);
* querys.put("TemplateCode", TEMPLATE_CODE); querys.put("RecNum",
* phoneNum); querys.put("ParamString", params);
* request.setQuerys(querys);
*
* try { Map<String, String> bodymap = new HashMap<String, String>();
* Response response = Client.execute(request); //
* 根据实际业务需要,调整对response的处理 if (null == response) {
* System.out.println("no response"); } else if (200 !=
* response.getStatusCode()) { System.out.println("StatusCode:" +
* response.getStatusCode()); System.out .println("ErrorMessage:" +
* response.getErrorMessage()); System.out.println("RequestId:" +
* response.getRequestId()); } else { bodymap =
* ReadResponseBodyContent(response.getBody()); if (null !=
* bodymap.get(ERRORKEY)) { // 当传入的参数不合法时,返回有错误说明
* System.out.println(JSON.toJSONString(bodymap));
* System.out.println(bodymap.get(ERRORKEY)); } else { //
* 成功返回map,对应的key分别为:message、success等
* System.out.println(JSON.toJSONString(bodymap)); } } } catch
* (Exception e) { System.out.println(e.getMessage()); }
*/
}
private Map<String, String> ReadResponseBodyContent(String body) {
Map<String, String> map = new HashMap<String, String>();
try {
JSONObject jsonObject = JSON.parseObject(body);
if (null != jsonObject) {
for (Entry<String, Object> entry : jsonObject.entrySet()) {
map.put(entry.getKey(), entry.getValue().toString());
}
}
if ("false".equals(map.get("success"))) {
map.put(ERRORKEY, map.get("message"));
}
} catch (Exception e) {
map.put(ERRORKEY, body);
}
return map;
}
public static void main(String agrs[]) throws Exception {
SingleSendSms app = new SingleSendSms();
app.sendMsg("15817219181", "123456");
// app.sendMsg("15018669294", "{'customer':'David'}");
System.out.println("success");
}
}
<!-- 阿里云短信服务 -->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.15</version>
</dependency>
<dependency>
<groupId>com.aliyun</groupId>
<artifactId>aliyun-java-sdk-core</artifactId>
<version>3.2.3</version>
</dependency>
<dependency>
<groupId>com.aliyun</groupId>
<artifactId>aliyun-java-sdk-dysmsapi</artifactId>
<version>1.0.0</version>
</dependency>
<dependency>
<groupId>com.royalnu</groupId>
<artifactId>ms-message</artifactId>
<version>0.0.1-SNAPSHOT</version>
</dependency>