SpringBoot+Vue实现邮箱登录注册功能

本文涉及的产品
RDS MySQL Serverless 基础系列,0.5-2RCU 50GB
云数据库 RDS PostgreSQL,高可用系列 2核4GB
RDS MySQL Serverless 高可用系列,价值2615元额度,1个月
简介: SpringBoot+Vue实现邮箱登录注册功能

点击链接查看项目

SpringBoot邮件发送

邮件发送是一个非常常见的功能,注册时的身份认证、重要通知发送等都会用到邮件发送。Sun公司提供了JavaMail用来实现邮件发送,但是配置烦琐,Spring 中提供了JavaMailSender 用来简化邮件配置,Spring Boot则提供了MailSenderAutoConfiguration 对邮件的发送做了进一步简化。

发送前的准备

使用QQ邮箱发送邮件,首先要申请开通POP3/SMTP服务或者IMAP/SMTP服务。SMTP全称为Simple Mail Transfer Protocol,译作简单邮件传输协议,它定义了邮件客户端软件与SMTP服务器之间,以及SMTP服务器与SMTP服务器之间的通信规则。也就是说,aaa@qq.com 用户先将邮件投递到腾讯的SMTP服务器,这个过程就使用了SMTP协议,然后腾讯的SMTP服务器将邮件投递到网易的SMTP服务器,这个过程依然使用了SMTP协议,SMTP服务器就是用来接收邮件的。而POP3全称为Post Office Protocol3,译作邮局协议,它定义了邮件客户端与POP3服务器之间的通信规则。该协议在什么场景下会用到呢?当邮件到达网易的SMTP服务器之后,111@163.com 用户需要登录服务器查看邮件,这个时候就用上该协议了:邮件服务商会为每一个用户提供专门的邮件存储空间,SMTP服务器收到邮件之后,将邮件保存到相应用户的邮件存储空间中,如果用户要读取邮件,就需要通过邮件服务商的POP3邮件服务器来完成。至于IMAP协议,则是对POP3协议的扩展,功能更强,作用类似。

在这里插入图片描述

在这里插入图片描述

后端java代码

UserController控制层代码:

package com.example.demo.controller;

import com.example.demo.entity.User;
import com.example.demo.rest.CodeMsg;
import com.example.demo.rest.Result;
import com.example.demo.service.UserRegistService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;

import javax.validation.Valid;

@RestController
@CrossOrigin
public class UserController {
    @Autowired
    private UserRegistService userRegistService;

    @PostMapping("/sendCode")
    public Object sendCode(@Valid User vo) {
        try {
            return userRegistService.sendCode(vo);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return Result.error(CodeMsg.SERVER_ERROR);
    }

    @PostMapping("/regist")
    public Object startRegist(@RequestParam("username") String username , @RequestParam("code") String code) {
        try {
           return userRegistService.regist(username,code);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return Result.error(CodeMsg.SERVER_ERROR);
    }

    @PostMapping("/updateCode")
    public Object active(@RequestParam("code") String code) {
        try {
            return userRegistService.update(code);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return Result.error(CodeMsg.SERVER_ERROR);
    }

    @PostMapping("/active")
    public Object login(@RequestParam("username") String username, @RequestParam("pwd") String pwd) {

        try {
            return userRegistService.login(username, pwd);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return Result.error(CodeMsg.SERVER_ERROR);
    }
}

UserDao数据连接层代码:

package com.example.demo.dao;

import com.example.demo.entity.ExamScore;
import com.example.demo.entity.User;
import org.apache.ibatis.annotations.Param;

import java.util.List;
import java.util.Map;

public interface UserDao {
    void insert(User vo);

    void update(String code);

    User findByUserName(String userName);

    User findByNameAndPwd(Map<String, String> map);

    void deleteByUserName(String userName);

}

UserEntity实体层代码:

package com.example.demo.entity;


import java.util.Date;

public class User {
    private Integer id;
    private String username;
    private String pwd;
    private Integer jh;
    private Integer scores;
    private String email;
    private String code;
    private Date createdate;

    public Integer getId() {
        return id;
    }

    public void setId(Integer id) {
        this.id = id;
    }

    public String getUsername() {
        return username;
    }

    public void setUsername(String username) {
        this.username = username;
    }

    public String getPwd() {
        return pwd;
    }

    public void setPwd(String pwd) {
        this.pwd = pwd;
    }

    public Integer getScores() {
        return scores;
    }

    public void setScores(Integer scores) {
        this.scores = scores;
    }

    public String getEmail() {
        return email;
    }

    public void setEmail(String email) {
        this.email = email;
    }

    public String getCode() {
        return code;
    }

    public void setCode(String code) {
        this.code = code;
    }

    public Date getCreatedate() {
        return createdate;
    }

    public Integer getJh() {
        return jh;
    }

    public void setJh(Integer jh) {
        this.jh = jh;
    }
    public void setCreatedate(Date createdate) {
        this.createdate = createdate;
    }
    @Override
    public String toString() {
        return "User{" +
                "id=" + id +
                ", username='" + username + '\'' +
                ", pwd='" + pwd + '\'' +
                ", jh=" + jh +
                ", scores=" + scores +
                ", email='" + email + '\'' +
                ", code='" + code + '\'' +
                ", createdate=" + createdate +
                '}';
    }
}

注册操作信息提示以及注册成功或失败时调用函数:

package com.example.demo.rest;

/**
 * @description 错误信息
 * @author dcl
 * @date 2019/12/17
 *
 */
public class CodeMsg {
    
    private int code;
    private String msg;
    
    public static final CodeMsg SUCCESS = new CodeMsg(0, "操作成功");
    
    public static final CodeMsg REGIST_SUCCESS = new CodeMsg(0, "注册成功,点击确定前往登录界面登录");
    
    public static final CodeMsg ACTIVE_SUCCESS = new CodeMsg(0, "用户激活成功");

    public static final CodeMsg REGIST_FALSE = new CodeMsg(-1, "注册失败,验证码错误,请重新输入");

    public static final CodeMsg USEREXISTS = new CodeMsg(500101,"用户已经存在");
    
    public static final CodeMsg USENOTREXISTS = new CodeMsg(500102,"账号或密码错误");
    
    public static final CodeMsg SERVER_ERROR = new CodeMsg(500100,"服务端异常");
    
    //临期管理模块异常
    public CodeMsg(int code,String msg)
    {
        this.code = code;
        this.msg = msg;
    }
    
    public int getCode() {
        return code;
    }
    public String getMsg() {
        return msg;
    }
    
    
}
package com.example.demo.rest;

import com.fasterxml.jackson.databind.annotation.JsonSerialize;


public class Result<T> 
{
    private int code;
    private String msg;
    @JsonSerialize(include= JsonSerialize.Inclusion.NON_NULL)
    private T data;
    
    /**
     * 返回成功时调用
     * @param data
     * @return
     */
    public static <T> Result<T> success(T data)
    {
        return new Result<T>(data);
    }
    
    /**
     * 返回失败时调用
     * @param data
     * @return
     */
    public static <T> Result<T> error(CodeMsg cm)
    {
        return new Result<T>(cm);
    }
    
    private Result(T data){
        this.code = 0;
        this.msg = "操作成功";
        this.data = data;
    }
    
    private Result(CodeMsg cm){
        if(cm == null)
        {
            return;
        }
        this.code = cm.getCode();
        this.msg = cm.getMsg();
    }
    public int getCode() {
        return code;
    }
    public void setCode(int code) {
        this.code = code;
    }
    public String getMsg() {
        return msg;
    }
    public void setMsg(String msg) {
        this.msg = msg;
    }
    public T getData() {
        return data;
    }
    public void setData(T data) {
        this.data = data;
    }
}

service服务接口层:

package com.example.demo.service;


import com.example.demo.entity.ExamScore;
import com.example.demo.entity.User;
import org.springframework.stereotype.Service;

import java.util.List;

@Service
public interface UserRegistService {
    Object sendCode(User vo);

    Object regist(String username,String code);

    Object update(String code);

    Object login(String username, String pwd);
}

serviceImpl服务接口实现层:

package com.example.demo.service.impl;

import com.example.demo.dao.UserDao;
import com.example.demo.entity.User;
import com.example.demo.rest.CodeMsg;
import com.example.demo.rest.Result;
import com.example.demo.service.UserRegistService;
import com.example.demo.util.MailUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.*;


@Service
public class UserRegistServiceImpl implements UserRegistService {

    private Logger logger = LoggerFactory.getLogger(com.example.demo.service.impl.UserRegistServiceImpl.class);

    @Resource
    private UserDao userDao;

    @Override
    public Object sendCode(User vo) {
        //生成 验证码 code
        String code = UUID.randomUUID().toString().replace("-", "").substring(0,6);

        vo.setCode(code);
        vo.setJh(0);
        vo.setScores(0);
        vo.setCreatedate(new Date());

        User findByUserName = userDao.findByUserName(vo.getUsername());

        if (null != findByUserName) {
            logger.error("error:注册用户名:[{}],已存在", vo.getUsername());

            return Result.error(CodeMsg.USEREXISTS);
        }

        userDao.insert(vo);

        try {
            new MailUtil(vo.getEmail(), code).run();
        } catch (Exception e) {
            logger.error("error:发送邮件失败");
            throw new RuntimeException("发送邮件失败");
        }
        try {
            Thread.sleep(47000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        User findByUserName1 = userDao.findByUserName(vo.getUsername());
        if (findByUserName1.getJh() == 0){
            userDao.deleteByUserName(vo.getUsername());
            System.out.println("删除成功");
            return Result.error(CodeMsg.REGIST_FALSE);
        }else {
            return Result.error(CodeMsg.REGIST_SUCCESS);
        }
    }

    @Override
    public Object regist(String username,String code){
        User findByUserName = userDao.findByUserName(username);
        System.out.println(code);
        System.out.println(findByUserName.getCode());
        if(code.equals(findByUserName.getCode())){
            System.out.println("12121212");
            userDao.update(code);
            return CodeMsg.REGIST_SUCCESS;
        }else {
            System.out.println("1111");
            return CodeMsg.REGIST_FALSE;
        }
    }

    @Override
    public Object update(String code) {
        userDao.update(code);
        return Result.error(CodeMsg.ACTIVE_SUCCESS);
    }


    @Override
    public Object login(String username, String pwd) {
        Map<String, String> map = new HashMap<>(3);

        map.put("username", username);
        map.put("pwd", pwd);

        User findByNameAndPwd = userDao.findByNameAndPwd(map);

        if (null == findByNameAndPwd) {
            return Result.error(CodeMsg.USENOTREXISTS);
        }
        return Result.success(null);
    }
}

邮件基本信息配置:

package com.example.demo.util;

import com.sun.mail.util.MailSSLSocketFactory;

import javax.mail.*;
import javax.mail.internet.InternetAddress;
import javax.mail.internet.MimeMessage;
import java.util.Properties;

public class MailUtil {
    private String email;// 收件人邮箱
    private String code;// 激活码

    public MailUtil(String email, String code) {
        this.email = email;
        this.code = code;
    }

    public void run() {
        // 1.创建连接对象javax.mail.Session
        // 2.创建邮件对象 javax.mail.Message
        // 3.发送一封激活邮件
        String from = "xxx@qq.com";// 发件人电子邮箱
        String host = "smtp.qq.com"; // 指定发送邮件的主机smtp.qq.com(QQ)|smtp.163.com(网易)

        Properties properties = System.getProperties();// 获取系统属性

        properties.setProperty("mail.smtp.host", host);// 设置邮件服务器
        properties.setProperty("mail.smtp.auth", "true");// 打开认证

        try {
            //QQ邮箱需要下面这段代码,163邮箱不需要
            MailSSLSocketFactory sf = new MailSSLSocketFactory();
            sf.setTrustAllHosts(true);
            properties.put("mail.smtp.ssl.enable", "true");
            properties.put("mail.smtp.ssl.socketFactory", sf);


            // 1.获取默认session对象
            Session session = Session.getDefaultInstance(properties, new Authenticator() {
                public PasswordAuthentication getPasswordAuthentication() {
                    return new PasswordAuthentication("xxx@qq.com", "授权码"); // 发件人邮箱账号、授权码
                }
            });

            // 2.创建邮件对象
            Message message = new MimeMessage(session);
            // 2.1设置发件人
            message.setFrom(new InternetAddress(from));
            // 2.2设置接收人
            message.addRecipient(Message.RecipientType.TO, new InternetAddress(email));
            // 2.3设置邮件主题
            message.setSubject("账号激活");
            // 2.4设置邮件内容
            String content = "<html><head></head><body><h1>这是一份激活文件</h1><h3>激活码,code="
                    + code + "</href></h3></body></html>";
            message.setContent(content, "text/html;charset=UTF-8");
            // 3.发送邮件
            Transport.send(message);
            System.out.printf("code=" + code);
            System.out.println("邮件成功发送!");
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

Mapper数据库操作实现层:

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.example.demo.dao.UserDao">

    <insert id="insert" parameterType="com.example.demo.entity.User">
        INSERT 
            INTO t_user(USERNAME,PWD,JH,CREATEDATE,EMAIL,CODE,SCORES)
        VALUES
        (
            #{username,jdbcType=VARCHAR},#{pwd,jdbcType=VARCHAR},
            #{jh,jdbcType=INTEGER},#{createdate,jdbcType=TIMESTAMP},
            #{email,jdbcType=VARCHAR},#{code,jdbcType=VARCHAR},#{scores,jdbcType=INTEGER}
        )
    </insert>

    <update id="update" parameterType="java.lang.String">
        UPDATE t_user SET jh = 1 WHERE CODE = #{code}
    </update>

    <update id="updateScores">
        UPDATE t_user SET SCORES = #{scores} WHERE USERNAME = #{username} AND #{scores} > SCORES
    </update>

    <select id="findByUserName" parameterType="java.lang.String" resultType="com.example.demo.entity.User">
        SELECT * FROM t_user WHERE USERNAME = #{username}
    </select>

    <select id="findByNameAndPwd" parameterType="java.util.Map" resultType="com.example.demo.entity.User">
        SELECT * FROM t_user WHERE USERNAME = #{username} and PWD = #{pwd}
    </select>

    <delete id="deleteByUserName" parameterType="java.lang.String">
        DELETE FROM t_user WHERE USERNAME = #{username}
    </delete>

    <select id="showAllByScores" resultType="com.example.demo.entity.User">
        SELECT * FROM t_user ORDER BY SCORES DESC
    </select>

    <insert id="addExamScore" parameterType="com.example.demo.entity.ExamScore">
        insert into exam_scores (score1,score2,score3,score4,sumscore,username) values(#{score1}, #{score2},#{score3},#{score4},#{sumscore},#{username})
    </insert>

    <select id="showAllScoreByUser" resultType="com.example.demo.entity.ExamScore">
        SELECT * FROM exam_scores where username = #{username}
    </select>
</mapper>

数据库配置信息:

server:
  port: 
spring:
  datasource:
    name: 
    url: jdbc:mysql://xxx.xx.xx.xx:xxx/xx?serverTimezone=GMT%2b8
    username: 
    password: 

 # 使用druid数据源
    type: com.alibaba.druid.pool.DruidDataSource
    driver-class-name: com.mysql.cj.jdbc.Driver
    filters: stat
    maxActive: 20
    initialSize: 1
    maxWait: 60000
    minIdle: 1
    timeBetweenEvictionRunsMillis: 60000
    minEvictableIdleTimeMillis: 300000
    validationQuery: select 'x'
    testWhileIdle: true
    testOnBorrow: false
    testOnReturn: false
    poolPreparedStatements: true
    maxOpenPreparedStatements: 20
## 该配置节点为独立的节点
mybatis:
  mapper-locations: classpath:mapper/*Mapper.xml #注意:一定要对应mapper映射xml文件的所在路径
  type-aliases-package: com.example.demo.entity # 注意:对应实体类的路径

前端Vue代码

登录:

<template>
   <div class="loginMainDiv">
     <headerr></headerr>
     <div class="top_div"></div>
     <div style="background: rgb(255, 255, 255); margin: -120px auto auto; border: 1px solid rgb(231, 231, 231); border-image: none; width: 400px; height: 224px; text-align: center;">
       <div style="width: 165px; height: 96px; position: absolute;">
         <div class="tou"></div>
         <div class="initial_left_hand" id="left_hand"></div>
         <div class="initial_right_hand" id="right_hand"></div>
       </div>
       <p style="padding: 30px 0px 10px; position: relative;"><span
         class="u_logo"></span> <input id="loginName" class="ipt" type="text" v-model="userName" placeholder="请输入用户名" value="">
       </p>
       <p style="position: relative;"><span class="p_logo"></span>
         <input class="ipt" id="password" type="password" v-model="password" placeholder="请输入密码" value="">
       </p>
       <div id="errorText" style="height: 20px;margin-top:10px">
         <p  style="color: red;display: none">用户名密码错误请从新输入</p>
       </div>
       <div style="height: 50px; line-height: 50px; margin-top: 30px; border-top-color: rgb(231, 231, 231); border-top-width: 1px; border-top-style: solid;">
         <!--        <p style="margin: 0px 35px 20px 45px;"><span style="float: left;"><a style="color: rgb(204, 204, 204);"-->
         <!--                                                                             href="#">忘记密码?</a></span>-->
         <router-link to='/Register'>
           <span style="float: left;margin-left: 10px;font-size: 14px;">没有账号?现在注册</span>
         </router-link>

         <span style="float: right;">
              <a id="loginBtn" @click="login()">登录</a>
           </span></div>

     </div>
   </div>
</template>

<script>
import Headerr from 'components/headerr/Headerr.vue'

export default {
  name: 'PjLogin',
  components:{
    Headerr
  },
  data () {
    return {
      userName: "",
      password:""
    }
  },
  created(){

  },
  methods:{
    login: function(){
      let fd = new FormData();
      fd.append("username",this.userName);
      fd.append("pwd",this.password);

      let config = {
        headers: {
          'Content-Type': 'application/x-www-form-urlencoded'
        }
      }

      this.$axios.post("active", fd,config).then( res => {
        if(res.data.msg === "操作成功"){
          this.$store.commit("edit",this.userName);
          console.log(this.$store.state.userName);
          this.$router.push({path:'/entry'})
        }else{
          alert("用户名或密码错误")
        }
      }).catch( res => {
        alert("网络错误")
        //alert(res.data.msg)
      })
    }

  }
}
</script>

<!-- Add "scoped" attribute to limit CSS to this component only -->
<style scoped>
  .loginMainDiv{
  background-image: url(~assets/bj.jpg);
  width: 100%;
    height: 2000%;
    /* background-size: 100% 100%; */
    background-attachment: fixed;
  position: fixed;
  }
  body{
    background: #ebebeb;
    font-family: "Helvetica Neue","Hiragino Sans GB","Microsoft YaHei","\9ED1\4F53",Arial,sans-serif;
    color: #222;
    font-size: 12px;
  }
  *{padding: 0px;margin: 0px;}
  .top_div{
    /* background: #008ead; */
    width: 100%;
    height: 240px;
  }
  .ipt{
    border: 1px solid #d3d3d3;
    padding: 10px 10px;
    width: 290px;
    border-radius: 4px;
    padding-left: 35px;
    -webkit-box-shadow: inset 0 1px 1px rgba(0,0,0,.075);
    box-shadow: inset 0 1px 1px rgba(0,0,0,.075);
    -webkit-transition: border-color ease-in-out .15s,-webkit-box-shadow ease-in-out .15s;
    -o-transition: border-color ease-in-out .15s,box-shadow ease-in-out .15s;
    transition: border-color ease-in-out .15s,box-shadow ease-in-out .15s
  }
  .ipt:focus{
    border-color: #66afe9;
    outline: none;
    -webkit-box-shadow: inset 0 1px 1px rgba(0,0,0,.075),0 0 8px rgba(102,175,233,.6);
    box-shadow: inset 0 1px 1px rgba(0,0,0,.075),0 0 8px rgba(102,175,233,.6)
  }
  .u_logo{
    background: url("~assets/images/username.png") no-repeat;
    padding: 10px 10px;
    position: absolute;
    top: 43px;
    left: 40px;

  }
  .p_logo{
    background: url("~assets/images/password.png") no-repeat;
    padding: 10px 10px;
    position: absolute;
    top: 12px;
    left: 40px;
  }
  a{
    text-decoration: none;
  }
  .tou{
    background: url("~assets/images/tou.png") no-repeat;
    width: 97px;
    height: 92px;
    position: absolute;
    top: -87px;
    left: 140px;
  }
  .left_hand{
    background: url("~assets/images/left_hand.png") no-repeat;
    width: 32px;
    height: 37px;
    position: absolute;
    top: -38px;
    left: 150px;
  }
  .right_hand{
    background: url("~assets/images/right_hand.png") no-repeat;
    width: 32px;
    height: 37px;
    position: absolute;
    top: -38px;
    right: -64px;
  }
  .initial_left_hand{
    background: url("~assets/images/hand.png") no-repeat;
    width: 30px;
    height: 20px;
    position: absolute;
    top: -12px;
    left: 100px;
  }
  .initial_right_hand{
    background: url("~assets/images/hand.png") no-repeat;
    width: 30px;
    height: 20px;
    position: absolute;
    top: -12px;
    right: -112px;
  }
  .left_handing{
    background: url("~assets/images/left-handing.png") no-repeat;
    width: 30px;
    height: 20px;
    position: absolute;
    top: -24px;
    left: 139px;
  }
  .right_handinging{
    background: url("~assets/images/right_handing.png") no-repeat;
    width: 30px;
    height: 20px;
    position: absolute;
    top: -21px;
    left: 210px;
  }
  #loginBtn {
    margin-right: 30px;
    background: rgb(0, 142, 173);
    padding: 7px 10px;
    border-radius: 4px;
    border: 1px solid rgb(26, 117, 152);
    border-image: none;
    color: rgb(255, 255, 255);
    font-weight: bold;
    cursor: pointer;
  }

</style>

注册:

<template>
  <div class="registerMainDiv">
    <headerr></headerr>
    <div class="top_div"></div>
    <div
      style="
        background: rgb(255, 255, 255);
        margin: -120px auto auto;
        border: 1px solid rgb(231, 231, 231);
        border-image: none;
        width: 400px;
        height: 270px;
        text-align: center;
      "
    >
      <div style="width: 165px; height: 96px; position: absolute">
        <div class="tou"></div>
        <div class="initial_left_hand" id="left_hand"></div>
        <div class="initial_right_hand" id="right_hand"></div>
      </div>
      <p style="padding: 30px 0px 10px; position: relative">
        <span class="u_logo"></span>
        <input
          id="loginName"
          class="ipt"
          type="text"
          v-model="userName"
          placeholder="请输入用户名"
          value=""
        />
      </p>
      <p style="position: relative">
        <span class="p_logo"></span>
        <input
          class="ipt"
          id="password"
          type="password"
          v-model="password"
          placeholder="请输入密码"
          value=""
        />
      </p>
      <p style="position: relative; margin-top: 10px">
        <span class="p_logo"></span>
        <input
          class="ipt"
          id="password2"
          type="password"
          v-model="password2"
          placeholder="请输入密码"
          value=""
        />
      </p>
      <p style="position: relative; margin-top: 10px">
        <span class="p_logo"></span>
        <input
          class="ipt"
          id="email"
          type="email"
          v-model="email"
          placeholder="请输入邮箱"
          value=""
        />
      </p>
      <span v-show="show" class="sendTestCode">
        <a id="loginBtn" @click="sendCode()">发送验证码</a>
      </span>
      <span v-show="!show" class="sendTestCode">
        <a id="loginBtn" style="padding: 6px 36px">{{ count }} s</a>
      </span>
      <div class="testCodeInfo">
        <p style="position: relative; margin-top: 10px">
          <span class="p_logo"></span>
          <input
            class="ipt"
            id="testCode"
            type="testCode"
            v-model="testCode"
            placeholder="请输入验证码"
            value=""
          />
        </p>
      </div>

      <!-- <div id="errorText" style="height: 20px;margin-top:10px">
         <p  style="color: red;display: none">用户名密码错误请从新输入</p>
       </div> -->
      <div
        style="
          height: 50px;
          line-height: 50px;
          margin-top: 5px;
          border-top-color: rgb(231, 231, 231);
          border-top-width: 1px;
          border-top-style: solid;
        "
      >
        <router-link to="/">
          <span style="float: left; margin-left: 10px; font-size: 14px"
            >已有账号,现在登录</span
          >
        </router-link>

        <span style="float: right">
          <a id="loginBtn" @click="registe()">注册</a>
        </span>
      </div>
    </div>
  </div>
</template>

<script>
import Headerr from "components/headerr/Headerr.vue";

export default {
  name: "Register",
  data() {
    return {
      userName: "",
      password: "",
      password2: "",
      email: "",
      testCode: "",
      show: true,
      count: "",
      timer: null,
    };
  },
  components: {
    Headerr,
  },
  created() {},
  methods: {
    sendCode() {
      const TIME_COUNT = 60;

      var reg = new RegExp(
        "^[a-z0-9]+([._\\-]*[a-z0-9])*@([a-z0-9]+[-a-z0-9]*[a-z0-9]+.){1,63}[a-z0-9]+$"
      ); //正则表达式
      let fd = new FormData();
      fd.append("username", this.userName);
      fd.append("pwd", this.password);
      fd.append("email", this.email);

      let config = {
        headers: {
          "Content-Type": "application/x-www-form-urlencoded",
        },
      };

      var flag = true;
      //判空
      if (this.userName == "") {
        alert("用户名不能为空!");
        flag = false;
        return;
      }

      //判空
      if (this.password == "") {
        alert("密码不能为空!");
        flag = false;
        return;
      }

      //判空
      if (this.password2 == "") {
        alert("确认密码不能为空!");
        flag = false;
        return;
      }

      //判空
      if (this.email == "") {
        alert("邮箱号不能为空!");
        flag = false;
        return;
      }

      //判断两次密码是否相同
      if (this.password != this.password2) {
        alert("两次密码不一致!");
        flag = false;
        return;
      }

      if (!reg.test(this.email)) {
        alert("请填写正确的邮箱格式!");
        flag = false;
        return;
      }

      if (this.password === this.password2 && flag) {
        //倒数60秒
        if (!this.timer) {
          this.count = TIME_COUNT;
          this.show = false;
          this.timer = setInterval(() => {
            if (this.count > 0 && this.count <= TIME_COUNT) {
              this.count--;
            } else {
              this.show = true;
              clearInterval(this.timer);
              this.timer = null;
            }
          }, 1000);

          //请求发注册码
          this.$axios
            .post("/sendCode", fd)
            .then((res) => {
              // alert(res);
            })
            .catch((res) => {
              // alert(res.data.msg);
            });
        }
      }
    },
    registe() {
      let fd = new FormData();
      fd.append("username", this.userName);
      fd.append("code", this.testCode);
      this.$axios
        .post("/regist", fd)
        .then((res) => {
          this.$confirm(res.data.msg, "提示", {
            cancelButtonClass: "btn-custom-cancel",
          })
            .then((action) => {
              if (action == "confirm") {
                //确认的回调
                if(res.data.msg == "注册成功,点击确定前往登录界面登录"){
                  this.$router.push({ path: "/" });
                }
              }
            })
            .catch((err) => {
              if (err == "cancel") {
                //取消的回调
              }
            });
        })
        .catch((res) => {
          alert(res.data.msg);
        });
    },
  },
};
</script>

<!-- Add "scoped" attribute to limit CSS to this component only -->
<style scoped>
.registerMainDiv {
  background-image: url(~assets/bj.jpg);
  width: 100%;
    height: 2000%;
    /* background-size: 100% 100%; */
    background-attachment: fixed;
  position: fixed;
}
body {
  background: #ebebeb;
  font-family: "Helvetica Neue", "Hiragino Sans GB", "Microsoft YaHei",
    "\9ED1\4F53", Arial, sans-serif;
  color: #222;
  font-size: 12px;
}
* {
  padding: 0px;
  margin: 0px;
}
.top_div {
  width: 100%;
  height: 240px;
}
.ipt {
  border: 1px solid #d3d3d3;
  padding: 10px 10px;
  width: 290px;
  border-radius: 4px;
  padding-left: 35px;
  -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075);
  box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075);
  -webkit-transition: border-color ease-in-out 0.15s,
    -webkit-box-shadow ease-in-out 0.15s;
  -o-transition: border-color ease-in-out 0.15s, box-shadow ease-in-out 0.15s;
  transition: border-color ease-in-out 0.15s, box-shadow ease-in-out 0.15s;
}

.ipt:focus {
  border-color: #66afe9;
  outline: 0;
  -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075),
    0 0 8px rgba(102, 175, 233, 0.6);
  box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075),
    0 0 8px rgba(102, 175, 233, 0.6);
}
.u_logo {
  background: url("~assets/images/username.png") no-repeat;
  padding: 10px 10px;
  position: absolute;
  top: 43px;
  left: 40px;
}
.p_logo {
  background: url("~assets/images/password.png") no-repeat;
  padding: 10px 10px;
  position: absolute;
  top: 12px;
  left: 40px;
  z-index: 9;
}
a {
  text-decoration: none;
}
.tou {
  background: url("~assets/images/tou.png") no-repeat;
  width: 97px;
  height: 92px;
  position: absolute;
  top: -87px;
  left: 140px;
}
.left_hand {
  background: url("~assets/images/left_hand.png") no-repeat;
  width: 32px;
  height: 37px;
  position: absolute;
  top: -38px;
  left: 150px;
}
.right_hand {
  background: url("~assets/images/right_hand.png") no-repeat;
  width: 32px;
  height: 37px;
  position: absolute;
  top: -38px;
  right: -64px;
}
.initial_left_hand {
  background: url("~assets/images/hand.png") no-repeat;
  width: 30px;
  height: 20px;
  position: absolute;
  top: -12px;
  left: 100px;
}
.initial_right_hand {
  background: url("~assets/images/hand.png") no-repeat;
  width: 30px;
  height: 20px;
  position: absolute;
  top: -12px;
  right: -112px;
}
.left_handing {
  background: url("~assets/images/left-handing.png") no-repeat;
  width: 30px;
  height: 20px;
  position: absolute;
  top: -24px;
  left: 139px;
}
.right_handinging {
  background: url("~assets/images/right_handing.png") no-repeat;
  width: 30px;
  height: 20px;
  position: absolute;
  top: -21px;
  left: 210px;
}
#loginBtn {
  margin-right: 30px;
  background: rgb(0, 142, 173);
  padding: 7px 10px;
  border-radius: 4px;
  border: 1px solid rgb(26, 117, 152);
  border-image: none;
  color: rgb(255, 255, 255);
  font-weight: bold;
  cursor: pointer;
}
.sendTestCode {
  position: relative;
  top: -30px;
  right: -130px;
}
#email {
  width: 180px;
  position: relative;
  left: -55px;
}
.testCodeInfo {
  position: relative;
  top: -20px;
}
</style>
<style>
.btn-custom-cancel{
  background-color: red;
}
</style>

SQL文件

/*
 Navicat Premium Data Transfer

 Source Server         : mysql
 Source Server Type    : MySQL
 Source Server Version : 50722
 Source Host           : localhost:3306
 Source Schema         : test

 Target Server Type    : MySQL
 Target Server Version : 50722
 File Encoding         : 65001

*/

SET NAMES utf8mb4;
SET FOREIGN_KEY_CHECKS = 0;

-- ----------------------------
-- Table structure for t_user
-- ----------------------------
DROP TABLE IF EXISTS `t_user`;
CREATE TABLE `t_user`  (
  `id` int(32) NOT NULL AUTO_INCREMENT,
  `username` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,
  `pwd` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,
  `zt` int(255) NULL DEFAULT NULL,
  `email` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,
  `code` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,
  `createdate` datetime(0) NULL DEFAULT NULL,
  PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 6 CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Dynamic;

SET FOREIGN_KEY_CHECKS = 1;

点击链接查看项目

相关实践学习
每个IT人都想学的“Web应用上云经典架构”实战
本实验从Web应用上云这个最基本的、最普遍的需求出发,帮助IT从业者们通过“阿里云Web应用上云解决方案”,了解一个企业级Web应用上云的常见架构,了解如何构建一个高可用、可扩展的企业级应用架构。
MySQL数据库入门学习
本课程通过最流行的开源数据库MySQL带你了解数据库的世界。 &nbsp; 相关的阿里云产品:云数据库RDS MySQL 版 阿里云关系型数据库RDS(Relational Database Service)是一种稳定可靠、可弹性伸缩的在线数据库服务,提供容灾、备份、恢复、迁移等方面的全套解决方案,彻底解决数据库运维的烦恼。 了解产品详情:&nbsp;https://www.aliyun.com/product/rds/mysql&nbsp;
目录
相关文章
|
5月前
|
前端开发 Java 关系型数据库
基于Java+Springboot+Vue开发的鲜花商城管理系统源码+运行
基于Java+Springboot+Vue开发的鲜花商城管理系统(前后端分离),这是一项为大学生课程设计作业而开发的项目。该系统旨在帮助大学生学习并掌握Java编程技能,同时锻炼他们的项目设计与开发能力。通过学习基于Java的鲜花商城管理系统项目,大学生可以在实践中学习和提升自己的能力,为以后的职业发展打下坚实基础。技术学习共同进步
402 7
|
5月前
|
XML 前端开发 Java
SpringBoot实现文件上传下载功能
本文介绍了如何使用SpringBoot实现文件上传与下载功能,涵盖配置和代码实现。包括Maven依赖配置(如`spring-boot-starter-web`和`spring-boot-starter-thymeleaf`)、前端HTML页面设计、WebConfig路径映射配置、YAML文件路径设置,以及核心的文件上传(通过`MultipartFile`处理)和下载(利用`ResponseEntity`返回文件流)功能的Java代码实现。文章由Colorful_WP撰写,内容详实,适合开发者学习参考。
480 0
|
6月前
|
JSON 自然语言处理 前端开发
【01】对APP进行语言包功能开发-APP自动识别地区ip后分配对应的语言功能复杂吗?-成熟app项目语言包功能定制开发-前端以uniapp-基于vue.js后端以laravel基于php为例项目实战-优雅草卓伊凡
【01】对APP进行语言包功能开发-APP自动识别地区ip后分配对应的语言功能复杂吗?-成熟app项目语言包功能定制开发-前端以uniapp-基于vue.js后端以laravel基于php为例项目实战-优雅草卓伊凡
276 72
【01】对APP进行语言包功能开发-APP自动识别地区ip后分配对应的语言功能复杂吗?-成熟app项目语言包功能定制开发-前端以uniapp-基于vue.js后端以laravel基于php为例项目实战-优雅草卓伊凡
|
4月前
|
供应链 JavaScript BI
ERP系统源码,基于SpringBoot+Vue+ElementUI+UniAPP开发
这是一款专为小微企业打造的 SaaS ERP 管理系统,基于 SpringBoot+Vue+ElementUI+UniAPP 技术栈开发,帮助企业轻松上云。系统覆盖进销存、采购、销售、生产、财务、品质、OA 办公及 CRM 等核心功能,业务流程清晰且操作简便。支持二次开发与商用,提供自定义界面、审批流配置及灵活报表设计,助力企业高效管理与数字化转型。
424 2
ERP系统源码,基于SpringBoot+Vue+ElementUI+UniAPP开发
|
4月前
|
安全 Java API
Spring Boot 功能模块全解析:构建现代Java应用的技术图谱
Spring Boot不是一个单一的工具,而是一个由众多功能模块组成的生态系统。这些模块可以根据应用需求灵活组合,构建从简单的REST API到复杂的微服务系统,再到现代的AI驱动应用。
|
5月前
|
存储 JavaScript 前端开发
基于 ant-design-vue 和 Vue 3 封装的功能强大的表格组件
VTable 是一个基于 ant-design-vue 和 Vue 3 的多功能表格组件,支持列自定义、排序、本地化存储、行选择等功能。它继承了 Ant-Design-Vue Table 的所有特性并加以扩展,提供开箱即用的高性能体验。示例包括基础表格、可选择表格和自定义列渲染等。
373 6
|
5月前
|
SQL 前端开发 Java
深入理解 Spring Boot 项目中的分页与排序功能
本文深入讲解了在Spring Boot项目中实现分页与排序功能的完整流程。通过实际案例,从Service层接口设计到Mapper层SQL动态生成,再到Controller层参数传递及前端页面交互,逐一剖析每个环节的核心逻辑与实现细节。重点包括分页计算、排序参数校验、动态SQL处理以及前后端联动,确保数据展示高效且安全。适合希望掌握分页排序实现原理的开发者参考学习。
315 4
|
5月前
|
存储 Java 定位技术
SpringBoot整合高德地图完成天气预报功能
本文介绍了如何在SpringBoot项目中整合高德地图API实现天气预报功能。从创建SpringBoot项目、配置依赖和申请高德地图API开始,详细讲解了实体类设计、服务层实现(调用高德地图API获取实时与预报天气数据)、控制器层接口开发以及定时任务的设置。通过示例代码,展示了如何获取并处理天气数据,最终提供实时天气与未来几天天气预报的接口。文章还提供了测试方法及运行步骤,帮助开发者快速上手并扩展功能。
|
5月前
|
JavaScript 前端开发 Java
Spring Boot 与 Vue.js 前后端分离中的数据交互机制
本文深入探讨了Spring Boot与Vue.js在前后端分离架构下的数据交互机制。通过对比传统`model.addAttribute()`方法与RESTful API的设计,分析了两者在耦合性、灵活性及可扩展性方面的差异。Spring Boot以RESTful API提供数据服务,Vue.js借助Axios消费API并动态渲染页面,实现了职责分明的解耦架构。该模式显著提升了系统的灵活性和维护性,适用于复杂应用场景如论坛、商城系统等,为现代Web开发提供了重要参考。
431 0
|
8月前
|
JavaScript Java 测试技术
基于SpringBoot+Vue实现的留守儿童爱心网站设计与实现(计算机毕设项目实战+源码+文档)
博主是一位全网粉丝超过100万的CSDN特邀作者、博客专家,专注于Java、Python、PHP等技术领域。提供SpringBoot、Vue、HTML、Uniapp、PHP、Python、NodeJS、爬虫、数据可视化等技术服务,涵盖免费选题、功能设计、开题报告、论文辅导、答辩PPT等。系统采用SpringBoot后端框架和Vue前端框架,确保高效开发与良好用户体验。所有代码由博主亲自开发,并提供全程录音录屏讲解服务,保障学习效果。欢迎点赞、收藏、关注、评论,获取更多精品案例源码。