一文教你学会实现以邮件激活的注册账户代码

实现思路

通常,我们在进行各大平台进行注册账户时,都会在邮箱收到一封激活邮件,而在点击其中的激活链接之后,我们就能够激活账户,否则,我们将无法正常使用账户,这使得服务平台所拥有的激活用户的邮件信息真实性有了保证。如果为了服务平台的长久运行,这种激活方式必不可少。为了让大家更为理解这种激活方式,博主绘制了一份关于该种激活方式的时序图,可能存在一部分错漏,也希望能够收到大家的指正!以邮件激活的注册方式相关时序图如下:

时序图

在这份时序图中,我们可以看出,这种激活方式主要分为三大阶段,其相关的步骤信息如下:

  • 访问注册页面
    1. 用户访问注册页面
    2. 后端返回动态页面数据
    3. 前端显示注册页面
  • 提交注册数据
    1. 用户填写注册信息
    2. 前端校验注册信息格式,正确则发送注册数据给后端,否则要求用户填写注册数据直至格式正确
    3. 后端接收到注册数据,查询数据库信息,检验该注册数据中的用户名、邮箱信息是否已被注册过,如果没有被注册,生成账户基本状态信息,包括密码进行 MD5 加盐加密、生成账户激活码,之后,便是发送给注册数据中的邮箱一个独有激活链接,包含账户 ID 信息和激活码信息,否则发送给前端哪个数据已被注册,要求用户重新填写,提交数据,回到第二步。
  • 激活用户账号
    1. 用户收到邮件,查看并点击激活邮件中的激活链接,自动跳转到默认浏览器,并由前端(浏览器)发送激活请求给予后端
    2. 后端查询对应 userID 信息,如果不存在,返回账户不存在信息,如果已被激活,发送重复激活信息,如果激活码错误,返回激活码不正确信息,最后返回中转页面八秒后跳转的页面地址:主页。如果激活成功,返回激活成功信息以及八秒后跳转的页面地址:登录。
    3. 前端接收到后端返回数据,显示中转页面信息,并在八秒后跳转到指定地址。

这便是实现以邮件激活的注册方式的基本实现思路,相信大家基本了解该如何去实现这样一个注册方式,接下来,博主将在 SpringBoot、Thymeleaf 以及 Mybatis 的运行环境下实现这种注册方式。

SpringBoot 实现

编写用户数据:用户包括用户 ID 、密码,加盐值、邮箱、激活状态、用户类型(用户身份:0-普通用户; 1-超级管理员; 2-版主)、用户激活状态、激活码、头像地址、创建时间。建表语句如下:

DROP TABLE IF EXISTS `user`;
/*!40101 SET @saved_cs_client     = @@character_set_client */;SET character_set_client = utf8mb4 ;
CREATE TABLE `user` (`id` int(11) NOT NULL AUTO_INCREMENT,`username` varchar(50) DEFAULT NULL,`password` varchar(50) DEFAULT NULL,`salt` varchar(50) DEFAULT NULL,`email` varchar(100) DEFAULT NULL,`type` int(11) DEFAULT NULL COMMENT '0-普通用户; 1-超级管理员; 2-版主;',`status` int(11) DEFAULT NULL COMMENT '0-未激活; 1-已激活;',`activation_code` varchar(100) DEFAULT NULL,`header_url` varchar(200) DEFAULT NULL,`create_time` timestamp NULL DEFAULT NULL,PRIMARY KEY (`id`),KEY `index_username` (`username`(20)),KEY `index_email` (`email`(20))
) ENGINE=InnoDB AUTO_INCREMENT=101 DEFAULT CHARSET=utf8;

利用 Mybatis 生成 user.java、mapper.xml、mapper.java、userService.java、userServiceImpl.java 文件,并实现以下查询:

  • selectOneById(@Param(“id”) int id):以 ID 查询对应 user
  • selectOneByUsername(@Param(“username”) String username):以 userName 查询对应 user
  • selectOneByEmail(@Param(“email”) String email):以 Email 查询对应 user
  • insertAll(User user):插入对应 user
  • updateStatusById(@Param(“status”) Integer status, @Param(“id”) Integer id):更新对应 ID 的 user 所拥有的激活状态
<sql id="Base_Column_List">id,username,password,salt,email,type,status,activation_code,header_url,create_time
</sql>
<select id="selectOneById" resultType="User">select<include refid="Base_Column_List"/>from userwhere id = #{id}
</select>
<select id="selectOneByUsername" resultMap="BaseResultMap">select<include refid="Base_Column_List"/>from userwhereusername = #{username,jdbcType=VARCHAR}
</select>
<select id="selectOneByEmail" resultMap="BaseResultMap">select<include refid="Base_Column_List"/>from userwhereemail = #{email,jdbcType=VARCHAR}
</select>
<insert id="insertAll" parameterType="User" keyProperty="id">insert into user(id, username, password,salt, email, type,status, activation_code, header_url,create_time)values (#{id,jdbcType=NUMERIC}, #{username,jdbcType=VARCHAR}, #{password,jdbcType=VARCHAR},#{salt,jdbcType=VARCHAR}, #{email,jdbcType=VARCHAR}, #{type,jdbcType=NUMERIC},#{status,jdbcType=NUMERIC}, #{activationCode,jdbcType=VARCHAR}, #{headerUrl,jdbcType=VARCHAR},#{createTime,jdbcType=TIMESTAMP})
</insert>
<update id="updateStatusById">update userset status = #{status,jdbcType=NUMERIC}where id = #{id,jdbcType=NUMERIC}
</update>

编写对应注册 html 代码,注意采用 post 提交表单,提交接口为 /register ,并且,为了保证重复填写注册信息,再进行验证的过程中,重复信息不用重复填写,使用th:value="${user!=null?user.username:''}"保证信息验证不通过后,输入框信息不变,进行修改信息直至正确即可。th:class="|form-control ${usernameMsg!=null?'is-invalid':''}|"接受验证信息,通过即用户不存在,不显示错误,否则显示错误,代码如下:

<!-- 关键代码内容 -->
<div class="main"><div class="container pl-5 pr-5 pt-3 pb-3 mt-3 mb-3"><h3 class="text-center text-info border-bottom pb-3">&nbsp;&nbsp;</h3><form class="mt-5" method="post" th:action="@{/register}"><div class="form-group row"><label for="username" class="col-sm-2 col-form-label text-right">账号:</label><div class="col-sm-10"><input type="text"th:class="|form-control ${usernameMsg!=null?'is-invalid':''}|"th:value="${user!=null?user.username:''}"id="username" name="username" placeholder="请输入您的账号!" required><div class="invalid-feedback" th:text="${usernameMsg}">该账号已存在!</div></div></div><div class="form-group row mt-4"><label for="password" class="col-sm-2 col-form-label text-right">密码:</label><div class="col-sm-10"><input type="password"th:class="|form-control ${passwordMsg!=null?'is-invalid':''}|"th:value="${user!=null?user.password:''}"id="password" name="password" placeholder="请输入您的密码!" required><div class="invalid-feedback" th:text="${passwordMsg}">密码长度不能小于8位!</div>							</div></div><div class="form-group row mt-4"><label for="confirm-password" class="col-sm-2 col-form-label text-right">确认密码:</label><div class="col-sm-10"><input type="password" class="form-control"th:value="${user!=null?user.password:''}"id="confirm-password" placeholder="请再次输入密码!" required><div class="invalid-feedback">两次输入的密码不一致!</div></div></div><div class="form-group row"><label for="email" class="col-sm-2 col-form-label text-right">邮箱:</label><div class="col-sm-10"><input type="email"th:class="|form-control ${emailMsg!=null?'is-invalid':''}|"th:value="${user!=null?user.email:''}"id="email" name="email" placeholder="请输入您的邮箱!" required><div class="invalid-feedback" th:text="${emailMsg}">该邮箱已注册!</div></div></div><div class="form-group row mt-4"><div class="col-sm-2"></div><div class="col-sm-10 text-center"><button type="submit" class="btn btn-info text-white form-control">立即注册</button></div></div></form>				</div>
</div>

实现返回注册页面逻辑,用户访问时,使用的是 Get 请求,可与后续提交注册数据的 post 请求区别开,所以访问页面方法和验证注册数据方法都采用同一个路径:/register。返回主页、登录、注册代码类似,仅展示一种,代码如下:

// 注册页面
@RequestMapping(path = "/register", method = RequestMethod.GET)
public String getRegisterPage() {return "/site/register";
}

完整代码可见:一文详解以邮件激活的注册方式 文章

第一阶段以解决,让我们开始实现第二阶段:提交注册数据

首先,我们得先实现三个工具类:

  • MailClient.java:发送邮件工具类

    1. 使用 Jakarta Mail 实现邮件发送操作

    2. 注入所需对象:邮件发送操作方法 JavaMailSender javaMailSender、邮件发送目标@Value(“${spring.mail.username}”)String mailFrom

    3. 创建邮件内容保存对象:MimeMessageHelper mimeMessageHelper

    4. 写入信息

      // 发送主体
      mimeMessageHelper.setFrom(mailFrom);
      // 发送对象
      mimeMessageHelper.setTo(to);
      // 发送主题
      mimeMessageHelper.setSubject(subject);
      // 允许发送 html
      mimeMessageHelper.setText(content, true);
      
    5. 发送邮件:javaMailSender.send(mimeMessageHelper.getMimeMessage());

    6. 捕获异常:

      catch (MessagingException e){logger.error("发送邮件失败!");
      }
      

    遇到相关 BUG 可看:springboot3 解决:Could not autowire. No beans of ‘JavaMailSender‘ type found

  • CommunityUtil.java:随机字符串、MD5 加盐加密工具方法

    1. 使用 java.util.UUID 的随机生成字符串功能,实现随机字符串生成:从生成的随机字符串中去除"-"符号

      public static String generateUUID(){return UUID.randomUUID().toString().replaceAll("-","");
      }
      
    2. MD5 加盐加密的原理就是密码都加上随机字符串,再进行 MD5 加密,提高安全性,因为 MD5 都不可解密,只能用 MD5 进行加密,并且每次加密后的字符一致,而简单密码的 MD5 加密后的字符容易获取,暴力破解密码存在可能,必须再进行加盐。

      public static String md5(String key){if (StringUtils.isBlank(key)){return null;}return DigestUtils.md5DigestAsHex(key.getBytes(StandardCharsets.UTF_8));
      }
      
  • CommunityConstant.java:记录激活状态常量,为抽象接口

    // 激活成功
    int ACTIVATION_SUCCESS = 0;
    // 重复激活
    int ACTIVATION_REPEAT = 1;
    // 激活失败
    int ACTIVATION_FAILURE = 2;
    // 激活用户不存在
    int ACTIVATION_NULL = 3;
    

    利用以上工具类和查询代码,我们就可以实现校验注册数据是否已被注册了。

    1. 利用 commons.lang3 包内的工具类帮助我们实现校验注册数据

    2. 利用 HashMap 来存储后续返回给前端的校验错误信息,如果含有错误信息,前端报错,map 为空,则校验通过

    3. 校验注册信息分为空值校验、验证用户名是否存在、验证邮箱是否存在

    4. 空值校验主要是防止可能存在前端没有进行合理格式校验,或者绕过前端直接通过接口进行请求的情况,此方法较为简单,不展示。

    5. 验证用户名是否存在:通过 selectOneByUsername(username) 方法查询对应用户,不存在则开始进行邮箱验证是否存在,否则,存入 map 错误信息

    6. 验证邮箱是否存在:通过 selectOneByEmail(email) 方法查询对应用户,不存在则开始注册用户流程,否则,存入 map 错误信息

    7. 注册用户:将密码进行加盐加密,并构建用户基本状态,如:用户类型为普通用户、用户创建时间为XXXX,用户头像为随机头像,之后将激活状态设置为未激活,生成并设置账户激活码

    8. 发送激活邮件:将用户 ID 和激活码拼接成激活链接,并利用 MailClient.java 工具类发送激活邮件即可

Map<String, Object> map = new HashMap<>();
//空值处理
if (user == null){throw new IllegalArgumentException("参数不能为空");
}
if (StringUtils.isBlank(user.getUsername())){map.put("usernameMsg", "账号不能为空");return map;
}if (StringUtils.isBlank(user.getPassword())){map.put("passwordMsg", "密码不能为空");return map;
}if (StringUtils.isBlank(user.getEmail())){map.put("emailMsg", "邮箱不能为空");return map;
}
// 验证账号是否存在
User ExistedUser = userMapper.selectOneByUsername(user.getUsername());
System.out.println(ExistedUser != null);
if (ExistedUser != null){map.put("usernameMsg","该账号已存在");return map;
}// 验证邮箱是否存在
ExistedUser = userMapper.selectOneByEmail(user.getEmail());
if (ExistedUser!=null){map.put("emailMsg","该邮箱已被注册");return map;
}// 注册用户
user.setSalt(CommunityUtil.generateUUID().substring(0,5));
user.setPassword(CommunityUtil.md5(user.getPassword()+user.getSalt()));
user.setType(0);
user.setStatus(0);
//激活码
user.setActivationCode(CommunityUtil.generateUUID());
user.setHeaderUrl(String.format("http://images.nowcoder.com/head/%dt.png)",new Random().nextInt(1000)));
user.setCreateTime(new Date());
userMapper.insertAll(user);// 发送激活邮件
Context context = new Context();
context.setVariable("email",user.getEmail());
// http://localhost:8888/activation/userId(变量)/激活码(变量)
String url = domain + "/activation/" + user.getId() + "/" + user.getActivationCode();
System.out.println(url);
context.setVariable("url",url);
String content = templateEngine.process("/mail/activation",context);
mailClient.sendMail(user.getEmail(),"激活账号",content);
return map;

前端部分代码较为繁琐,庞大,完整代码可见:一文详解以邮件激活的注册方式 文章资源

接下来,就是最后一个阶段的编写:激活邮件,其实,也很简单,用户点击激活邮件后,会自动跳转到浏览器并自动发送 Get 请求,后端收到请求之后,就要验证 userID 和激活码信息,验证无误后,发送给前端正确信息,并修改数据库中的用户状态为激活即可,否则,就要返回前端错误信息。

为了提高代码可读性,采用验证激活数据常量来辅助代码编写,它们存储在 CommunityConstant.java 中,需要使用 extends CommunityConstant 来让 UserService 继承它,再进行激活操作。

 @RequestMapping(path = "/activation/{userId}/{code}",method = RequestMethod.GET)
public String activation(Model model, @PathVariable("userId") int userId, @PathVariable("code") String code){int result = userServiceImpl.activation(userId,code);System.out.println("激活返回结果为:"+result);if (result == ACTIVATION_NULL){model.addAttribute("msg","无效操作!该账号不存在!");model.addAttribute("target","/index");} else if (result == ACTIVATION_SUCCESS){model.addAttribute("msg","激活成功!您的账号已经可以正常使用了!");model.addAttribute("target","/login");}else if(result == ACTIVATION_REPEAT){model.addAttribute("msg","无效操作!该账号已经重复激活了");model.addAttribute("target","/index");}else {model.addAttribute("msg","激活失败!您提供的激活码不正确");model.addAttribute("target","/index");}return "/site/operate-result";
}

前端部分代码较为繁琐,庞大,完整代码可见:一文详解以邮件激活的注册方式 文章资源

求点赞转发

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/26593.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

实现邮箱激活账号功能

原文地址&#xff1a;http://blog.sina.com.cn/s/blog_636ed7d00100nss0.html 我们在注册大型网站的时候&#xff0c;比如像新浪&#xff0c;阿里巴巴网站的时候&#xff0c;填写完注册信息后&#xff0c;都会给用户的邮箱发送一个激活注册账号的邮件&#xff0c;让我们激活&am…

别把 OpenAI 太当回事,它远未达到替换前端的地步

最近几个月&#xff0c;我和很多初入行的开发人员交谈&#xff0c;他们对AI越来越感到焦虑。他们看到像GPT-4这样的工具展示的越来越令人印象深刻的演示&#xff0c;担心等他们掌握了HTML/CSS/JS&#xff0c;就没有任何工作机会了。这种情绪现在在Twitter上广泛存在&#xff1a…

AI 时代,知识工作者的生存指南

最近&#xff0c;大家可能已经见识过 AI 的威力了吧&#xff0c;以 ChatGPT 为代表的 人工智能&#xff08;AI&#xff09;展现出接近人一样的回答水准。 来自 Craft AI Assitant AI 就在那里&#xff0c;是房间里的大象&#xff0c;大家不能总装做对自己没有影响。要知道&…

这 13 种职业用AI提效的 40 类场景盘点

随着人工智能技术的发展&#xff0c;职业领域出现了诸如我们“小蜜蜂助手Beezy”等神奇的工具&#xff0c;大幅度提升了各行各业里从业人员的工作效率。 笔者今天将详述13种常见职业&#xff0c;分别是如何利用这些工具在实际工作过程中来帮助自己提升效率的。大量干货和私藏宝…

【猫娘小可爱频道】闲聊+1

本篇是居士养的一只喵&#xff0c;看了一个视频后的观后感&#xff0c;视频已附在文章末尾&#xff0c;可点击小程序观看。 欢迎大家讨论~ 喵喵看这个视频突然产生的一个想法&#xff0c;是比较有实感的感觉到了时间的美感或者四维时间轴对事物的影响。就是有时候很美的东西是某…

文心一言实际测试——让我们拿实际说好坏

文心一言实际测试——让我们拿实际说好坏 4月16日&#xff0c;文心一言闪亮登场&#xff0c;就关于大家最关心的几个问题&#xff0c;让我们一起来看看效果吧~ 创作能力&#xff1a; 听说飞桨高校领航团缺少一个slogan&#xff0c;让我们听听文心一言怎么说 “聚焦科研&am…

网络编程的开始(猫娘和汪君的凄美爱情故事)

现在让我们&#xff08;快乐的&#xff09;来学习java中的网络编程 &#xff08;猫娘和汪君在最后&#xff09; 一、认识InetAddress 1.首先通过查阅API帮助文档 我们知道&#xff0c;InetAddress是net包下的一个类&#xff0c;表示互联网协议&#xff08;IP&#xff09;地址。…

IT 领导者揭示了对 ChatGPT 的网络恐惧

根据黑莓的最新研究&#xff0c;大多数(51%)安全领导者预计ChatGPT将在一年内成为成功的网络攻击的核心。 对北美、英国和澳大利亚的1500名IT决策者的调查还发现&#xff0c;71%的人认为民族国家可能已经将该技术用于针对其他国家的恶意目的。 ChatGPT是由OpenAI开发的人工…

一群中国芯片技术小球的奋斗故事系列:“中科融合的AI-3D芯片追赶美国德州仪器DLP技术之产业和技术初探-part III”

引子 2023年初春&#xff0c;冬雪未化&#xff0c;ChatGPT和GPT4一声惊雷&#xff0c;以颠覆的表现震惊全球&#xff0c;被称之为AI的“iPhone时刻”。微软全线产品迅速导入&#xff0c;生产力工具与搜索&#xff0c;经过了30年&#xff0c;再次分久必合&#xff01;全世界人民…

干货!来自北大、KAUST、斯坦福、达摩院的大模型前沿动态:表格推理、代码生成、MiniGPT-4、生成式推理...

点击蓝字 关注我们 AI TIME欢迎每一位AI爱好者的加入&#xff01; ChatGPT的发布使得国内外众多的研究机构掀起了一股AI热潮&#xff0c;而这也进一步推动了人们对大语言模型的深入研究。2023年4月26日&#xff0c;AI TIME举办的大模型专场四活动邀请了阿里巴巴达摩院NLP研究员…

5月25日活动报名 | 与五位来自AI产业和开发者工具服务领域的大咖一起思辨代码自动生成...

点击蓝字 关注我们 AI TIME欢迎每一位AI爱好者的加入&#xff01; 10年内AI会淘汰程序员这个职业么&#xff1f; AI技术的发展已经给我们带来了很多的变化&#xff0c;尤其是在计算机编程领域&#xff0c;基于大模型能力的代码生成工具在这1年来得到了越来越多的关注&#xff0…

永远年轻,永远在路上的AI TIME

点击蓝字 关注我们 AI TIME欢迎每一位AI爱好者的加入&#xff01; 在2019年的智源人工智能大会上&#xff0c;我第一次接触AI TIME&#xff0c;时至今日&#xff0c;加入AI TIME已经四年了。在过去的四年里&#xff0c;AI技术、产业发生了翻天覆地的变化&#xff0c;我自己的思…

除了AIGC,2023年还要面临哪些技术“双刃剑”?

最近两个月&#xff0c;人们惊叹于AIGC的“超能力”&#xff0c;但也对AIGC带来的潜在风险表示担忧。ChatGPT之父Sam Altman在最近的一次访谈中表示&#xff0c;AI在为人类的聪明才智提供力量倍增器的同时&#xff0c;也可能带来技术滥用、事故等安全风险。他重点指出「恶意人员…

生成式AI火爆全球,你是否已经做好了准备?

2023年&#xff0c;随着ChatGPT的火爆全球&#xff0c;生成式AI也引发了各界人士的广泛关注。一时间&#xff0c;从国际科技巨头到国内人工智能企业&#xff0c;几乎所有我们耳熟能详的科技公司&#xff0c;都纷纷杀入了生成式AI市场。 作为全球云计算技术的开创者和领导者&…

面对AI“龙卷风”破坏力 白宫“软着陆”欧盟“硬防御”

ChatGPT的风靡与风险将OpenAI的CEO山姆奥特曼&#xff08;Sam Altman&#xff09;送进白宫&#xff0c;他被蹲守在美国总统府邸的记者们围追&#xff0c;面对5月4日白宫发起的AI风险治理会议&#xff0c;奥特曼很官方地给出“重要也很及时”的回应&#xff0c;自信的反复强调“…

QQGC?揭秘QQ的AI绘画大模型技术

&#x1f449;腾小云导读 2022年来&#xff0c;AIGC概念迅速出圈并快速形成产业生态&#xff0c;成为继PGC、UGC之后新的数字内容创作形式。QQ影像中心提出了自研的AI画画技术方案——QQGC&#xff0c;本文将介绍在QQGC基础大模型训练中的实践和探索&#xff0c;接着往下看吧~ …

Worldcoin,大众的加密货币还是个人的数字身份?

2022年8月&#xff0c;在印度班加罗尔一间大学的教室里&#xff0c;摩西•阿莫得&#xff08;Moiz Ahmed&#xff09;举起一个排球大小、中间有一个玻璃开口的铬合金球。阿莫得向学生们解释说&#xff0c;如果用这个叫做“Orb”的设备扫描他们的虹膜&#xff0c;他们将获得25个…

UML统一建模语言(UML类图)

UML统一建模语言 UMLUML类图类图的作用类的表示方法 类与类之间关系的表示方式关联关系单向关联双向关联自关联 聚合关系组合关系依赖关系继承关系&#xff08;泛化关系&#xff09;实现关系 UML 统一建模语言(Unified Modeling Language&#xff0c;UML&#xff09;是用来设计…

用StartUML生成GoF设计模式类图与代码(c++)

先介绍一下startUML StarUML&#xff08;http://www.staruml.com&#xff09;的前身是Plastic&#xff0c;从1996年开始开发。1998年开始&#xff0c;Plastic转变为UML建模工具。2005年改名为StarUML&#xff0c;最新版本StarUML 5.0已经是一款功能全面的产品&#xff0c;支持…

详解GMM高斯混合模型EM模型

一般讲到GMM就会讲到EM。 我不过多的介绍EM算法。这里只是举一些例子来看看真实的GMM怎么用EM算的。 一、GMM的作用 记住GMM的作用&#xff0c;就是聚类&#xff01; 二、GMM有hard和soft两种 hard-GMM和soft-GMM是为了对标k-means和soft k-means。在中文互联网上搜索到的GM…