谷粒学院 Day12.登录页面模式、整合JWT、整合QQ邮箱、用户登录注册接口【后端】、用户登录注册【前端】

项目结构:

配置文件

 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">&nbsp;</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引入资源的路径写对了没

然后测试一下注册功能就行了

  • 2
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值