springboot前后端分离,邮箱/手机验证号激活和登录,手机注册和激活

2022-08-16 11:36:56

@TOC

1、父项目

1.1、依赖在这里插入图片描述

2、前端项目

2.1、依赖

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>com</groupId>
    <artifactId>0125-front</artifactId>
    <version>1.0</version>

    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.1.4.RELEASE</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>

    <dependencies>
        <!-- springboot核心 -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
        <!-- springboot web -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
    </dependencies>
</project>

2.2、启动类

package com;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class FrontApplication {
    public static void main(String[] args) {
        SpringApplication.run(FrontApplication.class, args);
    }
}

2.3、yml文件

server:
  port: 8080

2.4、前端样式

放入webapp文件夹中
在这里插入图片描述
在这里插入图片描述

2.5、控制类

package com.controller;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;

@Controller
public class ViewController {

    @RequestMapping("/")
    public String base(){
        System.out.println(">>> base");
        return "/demo.html";
    }
}

2.6、访问页面

然后启动启动类,就可以在网页访问到前端页面

3、配置集群

3.1/配置IP

在这里插入图片描述

3.2/集群配置

在这里插入图片描述
在这里插入图片描述

修改auto项目的application.yml文件的端口未8180

4/后端项目

4.1、依赖

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <parent>
        <artifactId>0125-email-sms-token</artifactId>
        <groupId>com</groupId>
        <version>1.0</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>

    <artifactId>auth</artifactId>

    <dependencies>
        <!-- springboot核心 -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
        <!-- springboot web -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <!-- mybatis -->
        <dependency>
            <groupId>org.mybatis</groupId>
            <artifactId>mybatis</artifactId>
            <version>3.5.2</version>
        </dependency>
        <!-- springboot mybaits整合 -->
        <dependency>
            <groupId>org.mybatis.spring.boot</groupId>
            <artifactId>mybatis-spring-boot-starter</artifactId>
            <version>1.3.2</version>
        </dependency>
        <!-- mysql -->
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>5.1.47</version>
        </dependency>
        <!-- 数据源 -->
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>druid-spring-boot-starter</artifactId>
            <version>1.1.9</version>
        </dependency>
        <!-- java mail -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-mail</artifactId>
        </dependency>
        <!-- redis -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-redis</artifactId>
        </dependency>
        <!-- 辅助插件 -->
        <dependency>
            <groupId>cz.mallat.uasparser</groupId>
            <artifactId>uasparser</artifactId>
            <version>0.6.0</version>
        </dependency>
        <!-- token需要json依赖 -->
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>fastjson</artifactId>
            <version>1.2.31</version>
        </dependency>
        <!-- 容联云通讯 -->
        <dependency>
            <groupId>com.google.code.gson</groupId>
            <artifactId>gson</artifactId>
            <version>2.8.6</version>
        </dependency>
        <dependency>
            <groupId>com.cloopen</groupId>
            <artifactId>CCPRestSDK</artifactId>
            <version>2.7</version>
        </dependency>
    </dependencies>
</project>

4.2/邮箱验证码登录

4.2.1/邮箱发送验证码的流程

用户发送邮箱,服务器发送验证码给用户,并将用户和验证码存到redis上

代码

application.yml

server:
  port: 8101

spring:
  datasource:
    type: com.alibaba.druid.pool.DruidDataSource
    url: jdbc:mysql://localhost:3306/market?characterEncoding=utf-8
    username: root
    password: 111111
    druid:
      driver-class-name: com.mysql.jdbc.Driver
  mail:
    host: smtp.163.com # 邮件服务器地址
    username: xxxx_test@163.com  # 发出邮件的邮箱
    password: DGBWOQAQEZYGWVQU # 发出邮箱的邮箱的验证码
    default-encoding: utf-8

password的授权码
在这里插入图片描述

sql代码,添加status关键字,默认值是1激活状态
在这里插入图片描述
实体类添加status关键字private Integer status;
添加util工具类
RedisUtil.java

package com.util;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.data.redis.core.ValueOperations;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import java.util.concurrent.TimeUnit;

@Component
public class RedisUtil {

    @Autowired
    private StringRedisTemplate stringRedisTemplate;
    @Resource(name = "stringRedisTemplate")
    private ValueOperations<String, String> valOpsStr;
    @Autowired
    private RedisTemplate<Object, Object> redisTemplate;
    @Resource(name = "redisTemplate")
    private ValueOperations<Object, Object> valOpsObj;

    /**
     * 判断key是否存在
     * @param key
     * @return
     */
    public boolean exists(String key){
        String value = getString(key);
        if (value == null) return false;
        return true;
    }

    /**
     * 获取失效时间
     * @param key
     * @return
     */
    public long getExpire(String key){
        return redisTemplate.getExpire(key);
    }

    /**
     * 删除键
     * @param key
     */
    public void delete(String key){
        redisTemplate.delete(key);
    }

    /**
     * 设置字符串数据
     * @param key
     * @param val
     */
    public void setString(String key, String val){
        valOpsStr.set(key, val);
    }

    /**
     * 设置字符串数据
     * @param key 键
     * @param val 值
     * @param expire 有效时间
     */
    public void setString(String key, String val, long expire){
        valOpsStr.set(key, val, expire, TimeUnit.SECONDS);
    }

    /**
     * 读取字符串数据
     * @param key
     * @return
     */
    public String getString(String key){
        return valOpsStr.get(key);
    }
}

MD5.java

package com.util;

import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.Random;

public class MD5 {

	public static String getMd5(String plainText,int length) {
		try {
			MessageDigest md = MessageDigest.getInstance("MD5");
			md.update(plainText.getBytes());
			byte b[] = md.digest();

			int i;

			StringBuffer buf = new StringBuffer("");
			for (int offset = 0; offset < b.length; offset++) {
				i = b[offset];
				if (i < 0)
					i += 256;
				if (i < 16)
					buf.append("0");
				buf.append(Integer.toHexString(i));
			}
			// 32位
			// return buf.toString();
			// 16位
			// return buf.toString().substring(0, 16);
			
			return buf.toString().substring(0, length);
		} catch (NoSuchAlgorithmException e) {
			e.printStackTrace();
			return null;
		}

	}

	public static int getRandomCode(){		
		int max=9999;
        int min=1111;
        Random random = new Random();
        return random.nextInt(max)%(max-min+1) + min;		
	}
	public static void main(String[] args) {
		System.out.println(MD5.getMd5("helloadsfdsffsf",6));
		System.out.println(getRandomCode());
	}

}

MailUtil.java

package com.util;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.mail.MailSender;
import org.springframework.mail.SimpleMailMessage;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;

/**
 * 邮件发送接口的实现
 * @author hduser
 *
 */
@Component
public class MailUtil {

	@Autowired
	private MailSender mailSender;

	/**
	 * 发送邮件
	 */
	public void send(String mailTo, String mailFrom, String mailSubject, String mailText) {

		//邮件对象
		SimpleMailMessage mailMessage = new SimpleMailMessage();

		//设置发件人邮箱
		mailMessage.setFrom(mailFrom);
		//设置邮件主题
		mailMessage.setSubject(mailSubject);
		//设置收件人邮箱
		mailMessage.setTo(mailTo);
		//设置邮件内容
		mailMessage.setText(mailText);

		//发送邮件
		mailSender.send(mailMessage);
	}
}

重写UserService.java

package com.service;

import com.bean.User;

/**
 * 用户业务逻辑接口
 */
public interface UserService extends BaseService<User> {
    /** 通过邮箱添加用户 */
    void addUserByMail(User user);
    /** 激活账号 */
    boolean active(String userName, String code);
    /** 通过手机号添加用户 */
    void addUserByPhone(User user);
    /** 发送激活码短信 */
    void sendActiveMessage(String userName);
}

UserServiceImpl.java

package com.service.impl;

import com.bean.User;
import com.dao.UserMapper;
import com.service.UserService;
import com.util.MD5;
import com.util.MailUtil;
import com.util.RedisUtil;
import com.util.SmsUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

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

/**
 * 用户业务逻辑实现
 */
@Service
public class UserServiceImpl implements UserService {

    @Autowired
    private UserMapper mapper;
    @Autowired
    private MailUtil mailUtil;
    @Autowired
    private RedisUtil redisUtil;
    @Autowired
    private SmsUtil smsUtil;

    //激活码前缀
    private String active_prefix = "active:";
    //邮件激活码有效期
    private int timeForMail = 30;
    //手机激活码有效期
    private Integer timeForPhone = 2;

    @Transactional
    @Override
    public int save(User user) {
        return mapper.insert(user);
    }

    @Override
    public void addUserByMail(User user) {

        /* 验证账号邮箱是否可用 */

        /* 添加到数据库 */
        //设置账号状态
        user.setStatus(0);
        //添加
        mapper.insert(user);

        /* 发送邮件到用户邮箱 */
        //生成激活码
        String code = MD5.getMd5(new Date().toString(), 32);

        //发送激活码到用户邮箱
        mailUtil.send(user.getUserName(), "makey_test@163.com",
                "激活【超市订单管理系统】账号",
                "请在" + timeForMail + "分钟内激活账号, 激活码:" + code);

        //将激活码保存到redis
        redisUtil.setString(active_prefix + user.getUserName(),
                code, timeForMail * 60);
    }

    @Override
    public boolean active(String userName, String code) {

        /* 判断, key是否存在 */
        if (!redisUtil.exists(active_prefix + userName)) return false;

        /* 比对激活码 */
        //获取redis中的激活码
        String value = redisUtil.getString(active_prefix + userName);
        //比对
        if (code.equals(value)) {
            //修改用户账号的状态
            mapper.update(new User(userName, 1));
            return true;
        }

        return false;
    }

    @Override
    public void addUserByPhone(User user) {

        /* 验证账号邮箱是否可用 */

        /* 添加到数据库 */
        //设置账号状态
        user.setStatus(0);
        //添加
        mapper.insert(user);
    }

    @Override
    public void sendActiveMessage(String userName) {
        /* 发送验证短信 */
        //生成手机激活码
        Integer code = MD5.getRandomCode();
        //发送到手机
        try {
            smsUtil.send(userName, "1",
                    new String[]{code.toString(), timeForPhone.toString()});
        } catch (Exception e) {
            e.printStackTrace();
        }
        //将验证码保存到缓存
        redisUtil.setString(active_prefix + userName,
                code.toString(), timeForPhone.intValue()*60);
    }

controller.java

package com.controller;

import com.bean.User;
import com.bean.dto.Dto;
import com.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.ResponseBody;

@Controller
public class UserController {

    @Autowired
    private UserService userService;

    @PostMapping("/registe/mail")
    @ResponseBody
    public Dto registeByEmail(User user){
        System.out.println(">>> 用户注册--邮箱");
        System.out.println(user);

        //添加用户
        userService.addUserByMail(user);

        return new Dto("注册成功, 请尽快激活账号!");
    }

    @PostMapping("/registe/phone")
    @ResponseBody
    public Dto registeByPhone(User user){
        System.out.println(">>> 用户注册--手机");
        System.out.println(user);

        //添加用户
        userService.addUserByPhone(user);

        return new Dto("注册成功, 请尽快激活账号!");
    }

    @PostMapping("/sms")
    @ResponseBody
    public Dto sendCode(String userName){

        System.out.println(">>> 获取手机激活码");
        System.out.println(userName);

        userService.sendActiveMessage(userName);

        return new Dto("激活码已发送!");
    }

    @PostMapping("/active")
    @ResponseBody
    public Dto active(String userName, String code){
        System.out.println(">>> 激活账号");
        System.out.println(userName + ", " + code);

        //激活
        boolean active = userService.active(userName, code);

        if (active)
            return new Dto("激活成功! 您可以登录网站了!");

        return new Dto("激活失败! 请重试!", "2000001");
    }
}

关于前端
由于前后端分咯,所以获取数据必须走post方面,所以前端要写Ajax
在这里插入图片描述
启动后
在这里插入图片描述
前缀要正确,否则会跳转不动
在这里插入图片描述
在这里插入图片描述
两个都要开启
在这里插入图片描述

4.2.2/手机注册和激活

和邮箱差不多,上述代码有写
区别:
https://www.yuntongxun.com/
在这里插入图片描述
SmsUtil.java

package com.util;

import com.cloopen.rest.sdk.CCPRestSmsSDK;
import org.springframework.stereotype.Component;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.HashMap;
import java.util.Set;

@Component
public class SmsUtil {

	/** 服务器地址 */
	//沙盒环境(用于应用开发调试): sandboxapp.cloopen.com
	//生产环境(用户应用上线使用): app.cloopen.com
	private String smsServerIP = "sandboxapp.cloopen.com";
	/** 服务器端口 */
	private String port = "8883";
	/** acount sid 主账号 */
	private String smsAccountSid = "8aaf0708762cb1cf017731fa1e525b15";
	/** auth token 主账号令牌 */
	private String smsAuthToken = "a3852ead06be4d95a052e344f2d67409";
	/** 应用ID */
	private String smsAppID = "8aaf0708762cb1cf017731fa1f205b1c";

	public void send(String to, String templateId, String[] datas) throws Exception {

		//短信发送结果
		HashMap<String, Object> result = null;

		//初始化SDK,这是云通讯给出的jar包,需要手动导入
		CCPRestSmsSDK restAPI = new CCPRestSmsSDK();
		
		//******************************注释*********************************************
		//*初始化服务器地址和端口                                                       *
		//*沙盒环境(用于应用开发调试):restAPI.init("sandboxapp.cloopen.com", "8883");*
		//*生产环境(用户应用上线使用):restAPI.init("app.cloopen.com", "8883");       *
		//*******************************************************************************
        restAPI.init(smsServerIP, port);
		
		//******************************注释*********************************************
		//*初始化主帐号和主帐号令牌,对应官网开发者主账号下的ACCOUNT SID和AUTH TOKEN     *
		//*ACOUNT SID和AUTH TOKEN在登陆官网后,在“应用-管理控制台”中查看开发者主账号获取*
		//*参数顺序:第一个参数是ACOUNT SID,第二个参数是AUTH TOKEN。                   *
		//*******************************************************************************
		restAPI.setAccount(smsAccountSid,smsAuthToken);

		//******************************注释*********************************************
		//*初始化应用ID                                                                 *
		//*测试开发可使用“测试Demo”的APP ID,正式上线需要使用自己创建的应用的App ID     *
		//*应用ID的获取:登陆官网,在“应用-应用列表”,点击应用名称,看应用详情获取APP ID*
		//*******************************************************************************
//		restAPI.setAppId(systemConfig.getSmsAppID());
		restAPI.setAppId(smsAppID);

		//******************************注释****************************************************************
		//*调用发送模板短信的接口发送短信                                                                  *
		//*参数顺序说明:                                                                                  *
		//*第一个参数:是要发送的手机号码,可以用逗号分隔,一次最多支持100个手机号                          *
		//*第二个参数:是模板ID,在平台上创建的短信模板的ID值;测试的时候可以使用系统的默认模板,id为1。    *
		//*系统默认模板的内容为“【云通讯】您使用的是云通讯短信模板,您的验证码是{1},请于{2}分钟内正确输入”*,测试只能1
		//*第三个参数是要替换的内容数组。																														       *
		//**************************************************************************************************
		
		//**************************************举例说明***********************************************************************
		//*假设您用测试Demo的APP ID,则需使用默认模板ID 1,发送手机号是13800000000,传入参数为6532和5,则调用方式为           *
		//*result = restAPI.sendTemplateSMS("13800000000","1" ,new String[]{"6532","5"});																		  *
		//*则13800000000手机号收到的短信内容是:【云通讯】您使用的是云通讯短信模板,您的验证码是6532,请于5分钟内正确输入     *
		//*********************************************************************************************************************
		result = restAPI.sendTemplateSMS(to,templateId,datas);
		
		System.out.println("SDKTestGetSubAccounts result=" + result);

		if("000000".equals(result.get("statusCode"))){
			//正常返回输出data包体信息(map)
			HashMap<String,Object> data = (HashMap<String, Object>) result.get("data");
			Set<String> keySet = data.keySet();
			for(String key:keySet){
				Object object = data.get(key);
				System.out.println(key +" = "+object);
			}
		}else{
			//异常返回输出错误码和错误信息
			System.out.println("错误码=" + result.get("statusCode") +" 错误信息= "+result.get("statusMsg"));
			throw new Exception("错误码=" + result.get("statusCode") +" 错误信息= "+result.get("statusMsg"));
		}
	}
}

在这里插入图片描述
在这里插入图片描述
管理测试号码
在这里插入图片描述

可以去缓存里看验证码在这里插入图片描述
操作
UserService.java

   /** 通过手机号添加用户 */
    void addUserByPhone(User user);
    /** 发送激活码短信 */
    void sendActiveMessage(String userName);

UserServiceImpl.java

  //激活码前缀
    private String active_prefix = "active:";
    //邮件激活码有效期
    private int timeForMail = 30;
    //手机激活码有效期
    private Integer timeForPhone = 2;

 @Override
    public boolean active(String userName, String code) {

        /* 判断, key是否存在 */
        if (!redisUtil.exists(active_prefix + userName)) return false;

        /* 比对激活码 */
        //获取redis中的激活码
        String value = redisUtil.getString(active_prefix + userName);
        //比对
        if (code.equals(value)) {
            //修改用户账号的状态
            mapper.update(new User(userName, 1));
            return true;
        }

        return false;
    }


 @Override
    public void addUserByPhone(User user) {

        /* 验证账号邮箱是否可用 */

        /* 添加到数据库 */
        //设置账号状态
        user.setStatus(0);
        //添加
        mapper.insert(user);
    }

    @Override
    public void sendActiveMessage(String userName) {
        /* 发送验证短信 */
        //生成手机激活码
        Integer code = MD5.getRandomCode();
        //发送到手机,模板只能选1
        try {
            smsUtil.send(userName, "1",
                    new String[]{code.toString(), timeForPhone.toString()});
        } catch (Exception e) {
            e.printStackTrace();
        }
        //将验证码保存到缓存
        redisUtil.setString(active_prefix + userName,
                code.toString(), timeForPhone.intValue()*60);
    }

controller.java

@PostMapping("/sms")
    @ResponseBody
    public Dto sendCode(String userName){

        System.out.println(">>> 获取手机激活码");
        System.out.println(userName);

        userService.sendActiveMessage(userName);

        return new Dto("激活码已发送!");
    }

    @PostMapping("/active")
    @ResponseBody
    public Dto active(String userName, String code){
        System.out.println(">>> 激活账号");
        System.out.println(userName + ", " + code);

        //激活
        boolean active = userService.active(userName, code);

        if (active)
            return new Dto("激活成功! 您可以登录网站了!");

        return new Dto("激活失败! 请重试!", "2000001");
    }
  • 作者:PayDurian
  • 原文链接:https://blog.csdn.net/weixin_46101839/article/details/115103013
    更新时间:2022-08-16 11:36:56