项目结构:
配置文件
application.properties配置类
spring.jackson.time-zone=GMT+8
# nacos注册中心
spring.cloud.nacos.discovery.server-addr= 127.0.0.1:8848
#mybatis日志
mybatis-plus.configuration.log-impl=org.apache.ibatis.logging.stdout.StdOutImpl
# redis
spring.redis.host=填你的ip地址
spring.redis.port=6379
spring.redis.database= 0
spring.redis.timeout=1800000
spring.redis.password=root123
spring.redis.lettuce.pool.max-active=20
spring.redis.lettuce.pool.max-wait=-1
#最大阻塞等待时间(负数表示没限制)
spring.redis.lettuce.pool.max-idle=5
spring.redis.lettuce.pool.min-idle=0
#最小空闲
application.yml配置文件
spring:
mail:
# 下面这个是QQ邮箱host , 企业邮箱 : smtp.exmail.qq.com
host: smtp.qq.com
# tencent mail port 这个是固定的
port: 465
# 你的QQ邮箱
username: XXXXXXX@qq.com
# 进入邮箱配置后得到的授权码
password: 填你自己的QQ授权码
test-connection: true
properties:
mail:
smtp:
ssl:
enable: true
CV过去注意看看配置类有没有空格。格式对不对。[dog.jpg]
编写SmsController类
@RestController
@RequestMapping("/edusms/sms")
@CrossOrigin
public class SmsController {
@Autowired
JavaMailSenderImpl mailSender;
@Autowired
private RedisTemplate<String,String> redisTemplate; //redis模板
@PostMapping("sendEmail/{DstEmail}")
public R sendEmail(@PathVariable String DstEmail) {
//从redis中获取验证码,如果获取到直接返回
String verCode = redisTemplate.opsForValue().get(DstEmail);
if (!StringUtils.isEmpty(verCode)){
return R.ok();
}
//如果获取不到,进行邮箱发送
//创建邮件消息
SimpleMailMessage message = new SimpleMailMessage();
//发送人邮箱
message.setFrom("XXXXXXX@qq.com");
//接收人邮箱
message.setTo(DstEmail);
message.setSubject("[因特学院]");
verCode = RandomUtil.getSixBitRandom();
message.setText("您好:\n"
+ "\n本次请求的邮件验证码为:" + verCode + ",本验证码 5 分钟内效,请及时输入。(请勿泄露此验证码)\n"
+ "\n如非本人操作,请忽略该邮件。\n(这是一封通过自动发送的邮件,请不要直接回复)");
mailSender.send(message);
//把发送成功的验证码存放到redis里面
//设置有效时间
redisTemplate.opsForValue().set(DstEmail,verCode,5, TimeUnit.MINUTES);
return R.ok();
}
}
这里基本上都是和老师的一致,生成随机数的方式也是用的RandomUtil类
不同的是,controller类的映射类路径和老师的不一致,用邮箱实现方法中设置了一个参数DstEmail,这个意思是接收方邮箱,在后面message.setTo()的时候要用
主启动类
@SpringBootApplication(exclude = DataSourceAutoConfiguration.class)
@ComponentScan("com.czy")
public class SmsApplication {
public static void main(String[] args) {
SpringApplication.run(SmsApplication.class,args);
}
}
这个用QQ邮箱发送短信的功能板块就实现了,配置一下nginx.conf,然后用swagger测一下,没问题了在继续往下进行,编写service_ucenter板块,这个板块使用代码生成器生成,细节要注意
主启动类UcenterApplication
@ComponentScan({"com.czy"})
@SpringBootApplication
@MapperScan("com.czy.educenter.mapper")
public class UcenterApplication {
public static void main(String[] args) {
SpringApplication.run(UcenterApplication.class,args);
}
}
然后UcenterMemberController类
@RestController
@RequestMapping("/educenter/member")
@CrossOrigin
public class UcenterMemberController {
@Autowired
private UcenterMemberService memberService;
//登录
@PostMapping("login")
public R loginUser(@RequestBody UcenterMember member){
//member封装手机号和密码
//调用service方法实现登录
//返回token值,使用jwt生成
String token = memberService.login(member);
return R.ok().data("token",token);
}
//注册
@PostMapping("register")
public R registerUser(@RequestBody RegisterVo registerVo){
memberService.register(registerVo);
return R.ok();
}
//根据token获取用户信息
@GetMapping("getMemberInfo")
public R getMemberInfo(HttpServletRequest request){
//调用jwt工具类的方法,根据request对象获取头像信息,返回用户id
String memberId = JwtUtils.getMemberIdByJwtToken(request);
//查询数据库根据用户id获取用户信息
UcenterMember member = memberService.getById(memberId);
return R.ok().data("userInfo",member);
}
}
然后去service层编写登录和注册的接口
public interface UcenterMemberService extends IService<UcenterMember> {
//登录
String login(UcenterMember member);
//注册
void register(RegisterVo registerVo);
}
然后编写Impl包下的UcenterMemberServiceImpl类
@Service
public class UcenterMemberServiceImpl extends ServiceImpl<UcenterMemberMapper, UcenterMember> implements UcenterMemberService {
@Autowired
private RedisTemplate<String,String> redisTemplate;//把redis里面的验证码取出来,注入redis模板
//登录
@Override
public String login(UcenterMember member) {
//获取登录手机号和密码
String mobile = member.getMobile();
String password = member.getPassword();
//手机号和密码非空判断
if (StringUtils.isEmpty(mobile) || StringUtils.isEmpty(password)){
throw new GuliException(20001,"登录失败");
}
//判断手机号是否正确
QueryWrapper<UcenterMember> wrapper = new QueryWrapper<>();
wrapper.eq("mobile",mobile);
UcenterMember mobileMember = baseMapper.selectOne(wrapper);
//判断查询对象是否为空
if (mobileMember == null){//没有这个手机号
throw new GuliException(20001,"登录失败");
}
//判断密码
/*
* 因为不会吧密码以明文的形式存放到数据库
* 所以采用MD5对密码进行加密
* MD5特点,只能加密,不能解密
* */
if (!MD5.encrypt(password).equals(mobileMember.getPassword())){
throw new GuliException(20001,"登录失败");
}
//判断用户是否禁用
if (mobileMember.getIsDisabled()){
throw new GuliException(20001,"登录失败");
}
//登录成功
//生成token字符串,使用kwt工具类
String jwtToken = JwtUtils.getJwtToken(mobileMember.getId(), mobileMember.getNickname());
return jwtToken;
}
//注册
@Override
public void register(RegisterVo registerVo) {
//获取注册的数据
String code = registerVo.getCode();//验证码
String mobile = registerVo.getMobile();//手机号
String nickname = registerVo.getNickname();//昵称
String password = registerVo.getPassword();//密码
//非空判断
if (StringUtils.isEmpty(mobile) || StringUtils.isEmpty(password)
|| StringUtils.isEmpty(code) || StringUtils.isEmpty(nickname)){
throw new GuliException(20001,"注册失败");
}
//验证码判断
//获取redis验证码
String redisCode = redisTemplate.opsForValue().get(mobile);
if (!code.equals(redisCode)){
throw new GuliException(20001,"注册失败,验证码错误或时间过期");
}
//判断用户名是否重复,表里面存在相同手机号不能进行添加
QueryWrapper<UcenterMember> wrapperName = new QueryWrapper<>();
wrapperName.eq("nickname",nickname);
Integer countName = baseMapper.selectCount(wrapperName);
if (countName > 0){
throw new GuliException(20001,"注册失败,用户名重复");
}
//判断手机号是否重复,表里面存在相同手机号不能进行添加
/*QueryWrapper<UcenterMember> wrapper = new QueryWrapper<>();
wrapper.eq("mobile",mobile);
Integer count = baseMapper.selectCount(wrapper);
if (count > 0){
throw new GuliException(20001,"注册失败,邮箱重复");
}*/
//数据添加到数据库
UcenterMember member = new UcenterMember();
member.setMobile(mobile);
member.setNickname(nickname);
member.setPassword(MD5.encrypt(password));
member.setIsDisabled(false);//用户不禁用
member.setAvatar("http://edu-czy1010.oss-cn-beijing.aliyuncs.com/2022/04/3085dc57d612cb46f59139298025f0d32cfile.png");
baseMapper.insert(member);
}
}
要记得写VO下的RegisterVo类和UcenterMember类
RegisterVo
@Data
public class RegisterVo {
@ApiModelProperty(value = "昵称")
private String nickname;
@ApiModelProperty(value = "手机号")
private String mobile;
@ApiModelProperty(value = "密码")
private String password;
@ApiModelProperty(value = "验证码")
private String code;
}
UcenterMember
@Data
@EqualsAndHashCode(callSuper = false)
@Accessors(chain = true)
@ApiModel(value="UcenterMember对象", description="会员表")
public class UcenterMember implements Serializable {
private static final long serialVersionUID = 1L;
@ApiModelProperty(value = "会员id")
@TableId(value = "id", type = IdType.ID_WORKER_STR)
private String id;
@ApiModelProperty(value = "微信openid")
private String openid;
@ApiModelProperty(value = "手机号")
private String mobile;
@ApiModelProperty(value = "密码")
private String password;
@ApiModelProperty(value = "昵称")
private String nickname;
@ApiModelProperty(value = "性别 1 女,2 男")
private Integer sex;
@ApiModelProperty(value = "年龄")
private Integer age;
@ApiModelProperty(value = "用户头像")
private String avatar;
@ApiModelProperty(value = "用户签名")
private String sign;
@ApiModelProperty(value = "是否禁用 1(true)已禁用, 0(false)未禁用")
private Boolean isDisabled;
@ApiModelProperty(value = "逻辑删除 1(true)已删除, 0(false)未删除")
private Boolean isDeleted;
@ApiModelProperty(value = "创建时间")
@TableField(fill = FieldFill.INSERT)
private Date gmtCreate;
@ApiModelProperty(value = "更新时间")
@TableField(fill = FieldFill.INSERT_UPDATE)
private Date gmtModified;
}
这样两个微服务板块就完成了,可以用swagger先发验证码在登录一下,如果没问题就开始前端页面
导入资源,修改配置文件nuxt-swiper-plugin.js
import Vue from 'vue'
import VueAwesomeSwiper from '../node_modules/vue-awesome-swiper/dist/ssr'
import VueQriously from 'vue-qriously'
import ElementUI from 'element-ui' //element-ui的全部组件
import 'element-ui/lib/theme-chalk/index.css' //element-ui的css
Vue.use(ElementUI) //使用elementUI
Vue.use(VueQriously)
Vue.use(VueAwesomeSwiper)
整合注册页面
1.在layout文件夹创建登录注册布局页面sign.vue
<template>
<div class="sign">
<!--标题-->
<div class="logo">
<img src="~/assets/img/logo.png" alt="logo" />
</div>
<!--表单-->
<nuxt />
</div>
</template>
修改登录和注册的超链接地址
修改layout.vue
<li id="no-login">
<a href="/login" title="登录">
<em class="icon18 login-icon"> </em>
<span class="vam ml5">登录</span>
</a>
|
<a href="/register" title="注册">
<span class="vam ml5">注册</span>
</a>
</li>
创建注册页面
在pages文件夹下建立register.vue
<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() {
registerApi.registerMember(this.params)
.then(response => {
//提示注册成功
this.$message({
type: 'success',
message: "注册成功"
})
//跳转登录页面
this.$router.push({path:'/login'})
})
},
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);
},
//通过输入手机号发送验证码
getCodeFun() {
registerApi.sendCode(this.params.mobile)
.then(response => {
this.sending = false
//调用倒计时的方法
this.timeDown()
})
},
checkPhone (rule, value, callback) {
//debugger
if (!(/[1-9]\d{7,10}@qq\.com$/.test(value))) {
return callback(new Error('手机号码格式不正确'))
}
return callback()
}
}
}
</script>
其中自定义规则时,之前是手机号的正则表达式,我们要改成QQ邮箱的正则表达式
[1-9]\d{7,10}@qq\.com
登录页面
login.vue
.<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";
export default {
layout: "sign",
data() {
return {
user: {
//封装用于登录的用户对象
mobile: "",
password: "",
},
//用于获取接口传来的token中的对象
loginInfo: {},
};
},
methods: {
checkPhone(rule, value, callback) {
//debugger
if (!(/[1-9]\d{7,10}@qq\.com$/.test(value))) {
return callback(new Error("QQ邮箱格式不正确"));
}
return callback();
},
},
};
</script>
<style>
.el-form-item__error {
z-index: 9999999;
}
</style>
在api文件夹下编写login.js和register.js
register.js
import request from '@/utils/request'
export default {
//根据手机号(没有阿里云,用QQ邮箱替代)发验证码
sendCode(phone) {
return request({
url: `/edusms/sms/sendEmail/${phone}`,
method: 'post'
})
},
//注册的方法
registerMember(fromItem) {
return request({
url: `/educenter/member/register`,
method: 'post',
data: fromItem
})
}
}
login.js
import request from '@/utils/request'
export default {
//登录
submitLogin(userInfo) {
return request({
url: `/serviceUcenter/ucenter-member/login`,
method: 'post',
data: userInfo
})
},
//根据token获取用户信息
getLoginInfo() {
return request({
url: `/serviceUcenter/ucenter-member/getUserInfoForJwt/`,
method: 'get',
// headers: {'token': cookie.get('guli_token')}
})
//headers: {'token': cookie.get('guli_token')}
}
}
最后检查一下login.vue和register.vu引入资源的路径写对了没
然后测试一下注册功能就行了