业务点梳理:前后分离下的登录和注册----------------SpringCloud+Nuxt
一、后端API------restful风格
1、注册接口(发短信接口+插入用户信息并且校验的接口
注册没有什么特别的地方,和我以前用SSM,SpringBoot做的注册差不多
短信服务:https://www.cnblogs.com/mangoubiubiu/p/13973098.html
用户中心:
Controller
//注册 @PostMapping("register") public R register(@RequestBody RegisterVo registerVo){ memberService.register(registerVo); return R.ok(); }
Service
public void register(RegisterVo registerVo) { //获取注册的code String code =registerVo.getCode(); String mobile =registerVo.getMobile(); String nickname =registerVo.getNickname(); String pwd =registerVo.getPassword(); //非空判断 if(StringUtils.isEmpty(mobile) || StringUtils.isEmpty(pwd) || StringUtils.isEmpty(code) || StringUtils.isEmpty(nickname)){ throw new GuiLiException(20001,"登录失败"); } //判断code //从redis取验证码 String redisCode=redisTemplate.opsForValue().get(mobile); if(!code.equals(redisCode)){ throw new GuiLiException(20001,"注册失败"); } //判断手机号是否重复 QueryWrapper<UcenterMember> queryWrapper=new QueryWrapper<>(); queryWrapper.eq("mobile",mobile); Integer count= baseMapper.selectCount(queryWrapper); //表示有相同 if(count >0 ){ throw new GuiLiException(20001,"注册失败"); } UcenterMember member=new UcenterMember(); member.setMobile(mobile); member.setNickname(nickname); member.setPassword(MD5.encrypt(pwd)); member.setAvatar(""); member.setIsDeleted(false); baseMapper.insert(member); }
2、登录接口(生成token--------解析token)
什么是登录,以前将用户信息存在session中,能从session中取到user信息就是登录,现在是看请求头中有无token
生成token:
controller
//登录 @PostMapping("login") public R login(@RequestBody UcenterMember ucenterMember){ //调用service方法实现登录 //返回token值 使用jwt生成 String token= memberService.login(ucenterMember); return R.ok().data("token",token); }
service:
@Override public String login(UcenterMember ucenterMember) { //获取登录手机号和密码 String mobile=ucenterMember.getMobile(); String pwd=ucenterMember.getPassword(); //手机号和密码非空判断 if(StringUtils.isEmpty(mobile) || StringUtils.isEmpty(pwd)){ throw new GuiLiException(20001,"登录失败"); } //判断手机号是否正确 QueryWrapper<UcenterMember> queryWrapper=new QueryWrapper<>(); queryWrapper.eq("mobile",mobile); //根据手机号查这个数据 是否存在 UcenterMember mMember = baseMapper.selectOne(queryWrapper); //判断查出来对象是否为空 if(mMember==null){ throw new GuiLiException(20001,"该用户不存在"); } //判断密码是否正确 //如果密码不正确 //存到数据库里的密码是做了 MD5加密了的 //所以用户输人的密码 先要进行加密在来和数据库里的比对 if(!MD5.encrypt(pwd).equals(mMember.getPassword())){ throw new GuiLiException(20001,"密码错误"); } //判断用户是否被禁用 if(mMember.getIsDisabled()){ throw new GuiLiException(20001,"登录失败"); } //登录成功 //生成token字符串 使用工具类 String jwtToken= JwtUtils.getJwtToken(mMember.getId(),mMember.getNickname()); return jwtToken; }
JWT工具类:https://www.cnblogs.com/mangoubiubiu/p/13956626.html这里有
解析token
//根据token获取用户信息 @GetMapping("getMemberInfo") public R getMemberInfo(HttpServletRequest request){ String menberId=JwtUtils.getMemberIdByJwtToken(request); //查询数据库 根据用户id获取用户信息 UcenterMember member= memberService.getById(menberId); return R.ok().data("member",member); }
二、前端页面调用
1、注册页面
定义调用api的js
import request from '@/utils/request'
export default {
//根据手机号码发送短信
getMobile(mobile){
return request({
url: `/edumsm/msm/send/${mobile}`,
method: 'get'
})
},
//用户注册
submitRegister(formItem) {
return request({
url: `/educenter/ucenter-member/register`,
method: 'post',
data: formItem
})
}
}
这里的关键点有2个
一个是用js的setInterval()方法实现倒计时
一个就是对用户输入的信息 进行聚焦事件,失去焦点事件校验
当然这里框架自己做好了 只需要照着写就完事了
<template> <div class="main"> <div class="title"> <a href="/login">登录</a> <span>·</span> <a class="active" href="/register">注册</a> </div> <div class="sign-up-container"> <el-form ref="userForm" :model="params"> <el-form-item class="input-prepend restyle" prop="nickname" :rules="[{ required: true, message: '请输入你的昵称', trigger: 'blur' }]"> <div> <el-input type="text" placeholder="你的昵称" v-model="params.nickname"/> <i class="iconfont icon-user"/> </div> </el-form-item> <el-form-item class="input-prepend restyle no-radius" prop="mobile" :rules="[{ required: true, message: '请输入手机号码', trigger: 'blur' },{validator: checkPhone, trigger: 'blur'}]"> <div> <el-input type="text" placeholder="手机号" v-model="params.mobile"/> <i class="iconfont icon-phone"/> </div> </el-form-item> <el-form-item class="input-prepend restyle no-radius" prop="code" :rules="[{ required: true, message: '请输入验证码', trigger: 'blur' }]"> <div style="width: 100%;display: block;float: left;position: relative"> <el-input type="text" placeholder="验证码" v-model="params.code"/> <i class="iconfont icon-phone"/> </div> <div class="btn" style="position:absolute;right: 0;top: 6px;width: 40%;"> <a href="javascript:" type="button" @click="getCodeFun()" :value="codeTest" style="border: none;background-color: none">{{codeTest}}</a> </div> </el-form-item> <el-form-item class="input-prepend" prop="password" :rules="[{ required: true, message: '请输入密码', trigger: 'blur' }]"> <div> <el-input type="password" placeholder="设置密码" v-model="params.password"/> <i class="iconfont icon-password"/> </div> </el-form-item> <div class="btn"> <input type="button" class="sign-up-button" value="注册" @click="submitRegister()"> </div> <p class="sign-up-msg"> 点击 “注册” 即表示您同意并愿意遵守简书 <br> <a target="_blank" href="http://www.jianshu.com/p/c44d171298ce">用户协议</a> 和 <a target="_blank" href="http://www.jianshu.com/p/2ov8x3">隐私政策</a> 。 </p> </el-form> <!-- 更多注册方式 --> <div class="more-sign"> <h6>社交帐号直接注册</h6> <ul> <li><a id="weixin" class="weixin" target="_blank" href="http://huaan.free.idcfengye.com/api/ucenter/wx/login"><i class="iconfont icon-weixin"/></a></li> <li><a id="qq" class="qq" target="_blank" href="#"><i class="iconfont icon-qq"/></a></li> </ul> </div> </div> </div> </template> <script> import '~/assets/css/sign.css' import '~/assets/css/iconfont.css' import registerApi from '@/api/register' export default { layout: 'sign', data() { return { params: {//封装注册输入的数据 mobile: '', code: '',//验证码 nickname: '', password: '' }, sending: true, //是否发送验证码 second: 60, //倒计时间 codeTest: '获取验证码' } }, methods: { //注册提交的方法 submitRegister(){ console.log(this.params) registerApi.submitRegister(this.params) .then(response=>{ console.log(response.data.data) //提示信息 this.$message({ type: 'success', message: "注册成功" }) //跳转到登录页面 this.$router.push({path: '/login'}) }) }, //通过输入的手机号调接口 getCodeFun(){ registerApi.getMobile(this.params.mobile) .then(response=>{ this.sending=false //提示信息 this.$message({ type: 'success', message: "短信发送成功请注意查收" }) //倒计时 this.timeDown() }) }, timeDown() { let result = setInterval(() => { --this.second; this.codeTest = this.second if (this.second < 1) { clearInterval(result); this.sending = true; //this.disabled = false; this.second = 60; this.codeTest = "获取验证码" } }, 1000); }, checkPhone(rule, value, callback) { if (!(/^1[34578]\d{9}$/.test(value))) { return callback(new Error('手机号码格式不正确')) } return callback() } } } </script>
2、登录页面
下载js-cookie插件
npm install js-cookie
api
import request from '@/utils/request'
export default {
//根据token值获取用户信息
getLoginUserInfo(){
return request({
url: `/educenter/ucenter-member/getMemberInfo`,
method: 'get'
})
},
//登录
submitLogin(userInfo) {
return request({
url: `/educenter/ucenter-member/login`,
method: 'post',
data: userInfo
})
}
}
这里的关键点 是先要将登录后从后端返回的token信息 存到cookie里面,然后加一个请求拦截,看cookie里是否有token 有拦截所有的axios请求 并在请求的后面带上token信息
,然后需要再请求后端解析token 返回用户信息存cookie里面 以便于前端页面进行数据展示
<template> <div class="main"> <div class="title"> <a class="active" href="/login">登录</a> <span>·</span> <a href="/register">注册</a> </div> <div class="sign-up-container"> <el-form ref="userForm" :model="user"> <el-form-item class="input-prepend restyle" prop="mobile" :rules="[{ required: true, message: '请输入手机号码', trigger: 'blur' },{validator: checkPhone, trigger: 'blur'}]"> <div > <el-input type="text" placeholder="手机号" v-model="user.mobile"/> <i class="iconfont icon-phone" /> </div> </el-form-item> <el-form-item class="input-prepend" prop="password" :rules="[{ required: true, message: '请输入密码', trigger: 'blur' }]"> <div> <el-input type="password" placeholder="密码" v-model="user.password"/> <i class="iconfont icon-password"/> </div> </el-form-item> <div class="btn"> <input type="button" class="sign-in-button" value="登录" @click="submitLogin()"> </div> </el-form> <!-- 更多登录方式 --> <div class="more-sign"> <h6>社交帐号登录</h6> <ul> <li><a id="weixin" class="weixin" target="_blank" href="http://qy.free.idcfengye.com/api/ucenter/weixinLogin/login"><i class="iconfont icon-weixin"/></a></li> <li><a id="qq" class="qq" target="_blank" href="#"><i class="iconfont icon-qq"/></a></li> </ul> </div> </div> </div> </template> <script> import '~/assets/css/sign.css' import '~/assets/css/iconfont.css' import cookie from 'js-cookie' import loginApi from '@/api/login' export default { layout: 'sign', data () { return { user:{ mobile:'', password:'' }, loginInfo:{} } }, methods: { submitLogin(){ loginApi.submitLogin(this.user) .then(response=>{ //获取token //将用户信息记录cookie cookie.set('guli_token',response.data.data.token, { domain: 'localhost' }) //获取用户信息 loginApi.getLoginUserInfo() .then(response=>{ this.loginInfo = response.data.data.member //获取返回的用户信息,放到cookie中 cookie.set('guli_ucenter', this.loginInfo, { domain: 'localhost' }) //跳转页面 window.location.href = "/"; }) }) }, checkPhone(rule, value, callback) { if (!(/^1[34578]\d{9}$/.test(value))) { return callback(new Error('手机号码格式不正确')) } return callback() } } } </script> <style> .el-form-item__error{ z-index: 9999999; } </style>
修改request.js
import axios from 'axios'
//import { MessageBox, Message } from 'element-ui'
import cookie from 'js-cookie'
// 创建axios实例
const service = axios.create({
//baseURL: 'http://qy.free.idcfengye.com/api', // api 的 base_url
//baseURL: 'http://localhost:8210', // api 的 base_url
baseURL: 'http://localhost:9001',
timeout: 15000 // 请求超时时间
})
// http request 拦截器
service.interceptors.request.use(
config => {
//debugger
//判断cookie里是否有值
if (cookie.get('guli_token')) {
config.headers['token'] = cookie.get('guli_token');
}
return config
},
err => {
return Promise.reject(err);
})
/*
// http response 拦截器
service.interceptors.response.use(
response => {
//debugger
if (response.data.code == 28004) {
console.log("response.data.resultCode是28004")
// 返回 错误代码-1 清除ticket信息并跳转到登录页面
//debugger
window.location.href="/login"
return
}else{
if (response.data.code !== 20000) {
//25000:订单支付中,不做任何提示
if(response.data.code != 25000) {
Message({
message: response.data.message || 'error',
type: 'error',
duration: 5 * 1000
})
}
} else {
return response;
}
}
},
error => {
return Promise.reject(error.response) // 返回接口返回的错误信息
});*/
export default service