@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");
}