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

FGGIT 2022-11-22 10:42:04

点击链接查看项目

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;

点击链接查看项目
%2522%252C%2522scm%2522%253A%252220140713.130102334.pc%255Fdownload.%2522%257D&request_id=166908208816782395362691&biz_id=1&utm_medium=distribute.pc_search_result.none-task-download-2downloadfirst_rank_ecpm_v1~rank_v31_ecpm-1-74791243-null-null.pc_v2_rank_dl_default&utm_term=%E9%82%AE%E4%BB%B6&spm=1018.2226.3001.4451.1)

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;

点击链接查看项目

...全文
137 回复 打赏 收藏 转发到动态 举报
写回复
用AI写文章
回复
切换为时间正序
请发表友善的回复…
发表回复

16,148

社区成员

发帖
与我相关
我的任务
社区描述
CSDN 官方活动专区,欢迎加入
其他 其他
社区管理员
  • 活动助手
  • CSDN学习
  • 我是阿萌
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告

试试用AI创作助手写篇文章吧