目录
1. 需求分析
手机快速登录功能,就是通过短信验证码的方式进行登录。这种方式相对于用户名密码登录方式,用户不需要记忆自己的密码,只需要通过输入手机号并获取验证码就可以完成登录,是目前比较流行的登录方式。
2. 手机快速登录
2.1 页面调整
登录页面为/pages/login.html
2.1.1 发送验证码
为获取验证码按钮绑定事件,并在事件对应的处理函数中校验手机号,如果手机号输入正确则显示30秒倒计时效果并发送ajax请求,发送短信验证码
<div class="input-row">
<label>手机号</label>
<div class="loginInput">
<input v-model="loginInfo.telephone" id='account' type="text"
placeholder="请输入手机号">
<input id="validateCodeButton"
@click="sendValidateCode()" type="button" style="font-size: 12px"
value="获取验证码">
</div>
</div>
<script>
var vue = new Vue({
el:'#app',
data:{
loginInfo:{}//登录信息
},
methods:{
//发送验证码
sendValidateCode(){
var telephone = this.loginInfo.telephone;
if (!checkTelephone(telephone)) {
this.$message.error('请输入正确的手机号');
return false;
}
validateCodeButton = $("#validateCodeButton")[0];
clock = window.setInterval(doLoop, 1000); //一秒执行一次
axios.
post("/validateCode/send4Login.do?telephone=" + telephone).
then((response) => {
if(!response.data.flag){
//验证码发送失败
this.$message.error('验证码发送失败,请检查手机号输入是否正确');
}
});
}
}
});
</script>
在ValidateCodeController中提供send4Login方法,调用短信服务发送验证码并将验证码保存到redis
//手机快速登录时发送手机验证码
@RequestMapping("/send4Login")
public Result send4Login(String telephone){
Integer code = ValidateCodeUtils.generateValidateCode(6);//生成6位数字验证码
try {
//发送短信
SMSUtils.sendShortMessage(SMSUtils.VALIDATE_CODE,telephone,code.toString());
} catch (ClientException e) {
e.printStackTrace();
//验证码发送失败
return new Result(false, MessageConstant.SEND_VALIDATECODE_FAIL);
}
System.out.println("发送的手机验证码为:" + code);
//将生成的验证码缓存到redis
jedisPool.getResource().setex(telephone+RedisMessageConstant.SENDTYPE_LOGIN,
5 * 60,
code.toString());
//验证码发送成功
return new Result(true,MessageConstant.SEND_VALIDATECODE_SUCCESS);
}
2.1.2 提交登录请求
为登录按钮绑定事件
<div class="btn yes-btn"><a @click="login()" href="#">登录</a></div>
//登录
login(){
var telephone = this.loginInfo.telephone;
if (!checkTelephone(telephone)) {
this.$message.error('请输入正确的手机号');
return false;
}
axios.post("/member/login.do",this.loginInfo).then((response) => {
if(response.data.flag){
//登录成功,跳转到会员页面
window.location.href="member.html";
}else{
//失败,提示失败信息
this.$message.error(response.data.message);
}
});
}
2.2 后台代码
2.2.1 Controller
在health_mobile工程中创建MemberController并提供login方法进行登录检查,处理逻辑为:
1、校验用户输入的短信验证码是否正确,如果验证码错误则登录失败
2、如果验证码正确,则判断当前用户是否为会员,如果不是会员则自动完成会员注册
3、向客户端写入Cookie,内容为用户手机号
4、将会员信息保存到Redis,使用手机号作为key,保存时长为30分钟
session共享,redis
package com.oldlu.controller;
import com.alibaba.fastjson.JSON;
import com.alibaba.dubbo.config.annotation.Reference;
import com.aliyuncs.exceptions.ClientException;
import com.oldlu.constant.MessageConstant;
import com.oldlu.constant.RedisConstant;
import com.oldlu.constant.RedisMessageConstant;
import com.oldlu.entity.Result;
import com.oldlu.pojo.Member;
import com.oldlu.service.MemberService;
import com.oldlu.utils.JedisUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import redis.clients.jedis.JedisPool;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletResponse;
import java.util.Date;
import java.util.Map;
/**
* 会员登录
*/
@RestController
@RequestMapping("/member")
public class MemberController {
@Reference
private MemberService memberService;
@Autowired
private JedisPool jedisPool;
//使用手机号和验证码登录
@RequestMapping("/login")
public Result login(HttpServletResponse response,@RequestBody Map map){
String telephone = (String) map.get("telephone");
String validateCode = (String) map.get("validateCode");
//从Redis中获取缓存的验证码
String codeInRedis =
jedisPool.getResource().get(telephone+RedisMessageConstant.SENDTYPE_LOGIN);
if(codeInRedis == null || !codeInRedis.equals(validateCode)){
//验证码输入错误
return new Result(false,MessageConstant.VALIDATECODE_ERROR);
}else{
//验证码输入正确
//判断当前用户是否为会员
Member member = memberService.findByTelephone(telephone);
if(member == null){
//当前用户不是会员,自动完成注册
member = new Member();
member.setPhoneNumber(telephone);
member.setRegTime(new Date());
memberService.add(member);
}
//登录成功
//写入Cookie,跟踪用户
Cookie cookie = new Cookie("login_member_telephone",telephone);
cookie.setPath("/");//路径
cookie.setMaxAge(60*60*24*30);//有效期30天
response.addCookie(cookie);
//保存会员信息到Redis中
String json = JSON.toJSON(member).toString();
jedisPool.getResource().setex(telephone,60*30,json);
return new Result(true,MessageConstant.LOGIN_SUCCESS);
}
}
}
需求:营销
1. 提供一个链接,链接就是一个接口,获取到一些信息,推广人的信息,链接里面有推广人的用户ID
2. 把推广人的信息,存到cookie里面
3. http://localhost/invite/1234
4. APP 手机端,标识唯一用户
1. MAC地址是唯一 APPID
2.2.2 服务接口
在MemberService服务接口中提供findByTelephone和add方法
public void add(Member member);
public Member findByTelephone(String telephone);
2.2.3 服务实现类
在MemberServiceImpl服务实现类中实现findByTelephone和add方法
//根据手机号查询会员
public Member findByTelephone(String telephone) {
return memberDao.findByTelephone(telephone);
}
//新增会员
public void add(Member member) {
if(member.getPassword() != null){
member.setPassword(MD5Utils.md5(member.getPassword()));
}
memberDao.add(member);
}
2.2.4 Dao接口
在MemberDao接口中声明findByTelephone和add方法
public Member findByTelephone(String telephone);
public void add(Member member);
2.2.5 Mapper映射文件
在MemberDao.xml映射文件中定义SQL语句
<!--新增会员-->
<insert id="add" parameterType="com.itoldlu.pojo.Member">
<selectKey resultType="java.lang.Integer" order="AFTER" keyProperty="id">
SELECT LAST_INSERT_ID()
</selectKey>
insert into t_member
(fileNumber,name,sex,idCard,phoneNumber,regTime,password,email,birthday,remark)
values
(#{fileNumber},#{name},#{sex},#{idCard},#{phoneNumber},#{regTime},#{password},#{email},#{birthday},#{remark})
</insert>
<!--根据手机号查询会员-->
<select id="findByTelephone" parameterType="string" resultType="com.itoldlu.pojo.Member">
select * from t_member where phoneNumber = #{phoneNumber}
</select>
小结
- 登录信息保存在redis中,在访问接口时,将cookie中的telephone携带,来验证redis中的用户信息是否存在,不存在则未登录