这里有新鲜出炉的精品教程, 程序狗速度看过来!
Spring Boot
Spring Boot 项目旨在简化创建产品级的 Spring 应用和服务你可通过它来选择不同的 Spring 平台可创建独立的 Java 应用和 web 应用, 同时提供了命令行工具来允许'spring scripts'.
本篇文章主要介绍了 Spring Boot 实现邮件注册功能示例代码, 小编觉得挺不错的, 现在分享给大家, 也给大家做个参考一起跟随小编过来看看吧
注册流程
1.[前端] 用户在注册页面提交注册信息;
2.[后端] 校验用户提交的参数, 有误直接返回错误信息, 无误向下执行;
3.[后端] 随机生成一个 ID, 将 ID 作为 key, 用户信息作为 value, 存入 redis, 设置时长;
4.[后端] 生成激活链接, 通过邮件系统发送邮件到用户邮箱
5.[前端] 用户点击上图的确认注册;
6.[后端] 校验 value 是否过期, 校验邮箱是否已经注册, 没有则保存用户信息到数据库, 提示用户已经注册成功;
功能实现 (逆向分析)
1 先看看邮件发送的实现 cn.ictgu.tools.mail.MailService
- package cn.ictgu.tools.mail;
- import cn.ictgu.dao.model.User;
- import com.alibaba.fastjson.JSONObject;
- import lombok.extern.log4j.Log4j;
- import org.springframework.beans.factory.annotation.Autowired;
- import org.springframework.beans.factory.annotation.Value;
- import org.springframework.mail.javamail.JavaMailSender;
- import org.springframework.mail.javamail.MimeMessageHelper;
- import org.springframework.stereotype.Service;
- import javax.mail.MessagingException;
- import javax.mail.internet.MimeMessage;
- /**
- * 邮件服务
- * Created by Silence on 2017/3/11.
- */
- @Service
- @Log4j
- public class MailService {
- @Autowired
- private JavaMailSender mailSender;
- @Value("${spring.mail.username}")
- private String from;
- private static final String TITLE_SIGN_UP = "[邮件标题]";
- private static final String CONTENT = "[邮件内容]";
- public void userValidate(User user, String token){
- MimeMessage mailMessage = mailSender.createMimeMessage();
- try {
- MimeMessageHelper helper = new MimeMessageHelper(mailMessage, true, "GBK");
- helper.setFrom(from);
- helper.setTo(user.getEmail());
- helper.setSubject(TITLE_SIGN_UP);
- String link = "http://www.ictgu.cn/validate/" + token;
- String message = String.format(CONTENT, user.getNickname(), link, link, user.getEmail());
- helper.setText(message, true);
- mailSender.send(mailMessage);
- } catch (MessagingException e) {
- log.error("发送邮件失败: User:" + JSONObject.toJSONString(user) + ", Token:" + token);
- }
- }
说明: 发送邮件需要传入 2 个参数 user 和 token,user 即为用户注册信息, token 是一个随机的 UUID,redis 中有与之对应的 key, 其 value 是 user 的 json 字符串 (key 的规则是配置文件 redis.prefix.signUp + UUID)
邮件模板问题:
邮件内容的本质是一段字符串, 样式由 html+CSS 控制, 开发时, 在邮箱设计好模板, 变量用 %s 代替, 然后将整段字符串存放在一个合适的地方, 发送邮件时, 使用 String.format() 方法将 %s 替换为实际值, 就生成了最终用户看到邮件所以没有必要使用第三方模板, 添加 jar 包会增加系统的复杂度, 同样的功能, 能简化的尽量简化
2 如何生成 Token 呢? 请看 cn.ictgu.redis.RedisTokenManager
- public String getTokenOfSignUp(User user){
- String token = UUID.randomUUID().toString();
- String value = JSONObject.toJSONString(user);
- stringRedisTemplate.opsForValue().set(signUpPrefix + token, value);
- stringRedisTemplate.expire(signUpPrefix + token, 12, TimeUnit.HOURS);
- return token;
- }
说明: UUID.randomUUID().toString() 是 javaJDK 提供的一个自动生成主键的方法 UUID(Universally Unique Identifier) 全局唯一标识符, 是指在一台机器上生成的数字, 它保证对在同一时空中的所有机器都是唯一的, 是由一个十六位的数字组成, 表现出来的形式由以下几部分的组合: 当前日期和时间 (UUID 的第一个部分与时间有关, 如果你在生成一个 UUID 之后, 过几秒又生成一个 UUID, 则第一个部分不同, 其余相同), 时钟序列, 全局唯一的 IEEE 机器识别号 (如果有网卡, 从网卡获得, 没有网卡以其他方式获得),UUID 的唯一缺陷在于生成的结果串会比较长
3token 有了, 就需要在 service 层关联 user 和 token 发送邮件啦, 看看 cn.ictgu.dao.service.UserService
- public boolean signUp(User user){
- String email = user.getEmail();
- if (existEmail(email)){
- log.error("用户注册, 邮箱已注册:" + email);
- return false;
- }
- sendValidateEmail(user);
- return true;
- }
- @Async
- private void sendValidateEmail(User user){
- String token = tokenManager.getTokenOfSignUp(user);
- log.error("用户注册, 准备发送邮件: User:" + JSONObject.toJSONString(user) + ", Token:" + token);
- mailService.userValidate(user, token);
- }
- private boolean existEmail(String email){
- return mapper.selectByEmail(email) != null;
- }
说明: 发送邮件耗时较长, 使用异步来做, 提高用户体验
4user 就简单了
- @RestController
- public class UserApi {
- @Autowired
- private UserService userService;
- @RequestMapping(value = "/sign-up", method = RequestMethod.POST)
- public SimpleResponse signUp(HttpServletRequest request){
- User user = createUser(request);
- SimpleResponse response = checkSignUpRequest(user);
- if (response.getCode() == 100){
- if (!userService.signUp(user)){
- response.setCode(200);
- response.setMessage("此邮箱已注册, 请勿重复注册!");
- return response;
- }else {
- response.setMessage("注册激活邮件已发送至您邮箱, 请在 12 小时内激活完成注册!");
- return response;
- }
- }
- return response;
- }
- private SimpleResponse checkSignUpRequest(User user){
- SimpleResponse response = new SimpleResponse();
- String email = user.getEmail();
- if (!CheckUtils.checkEmail(email)){
- response.setCode(200);
- response.setMessage("邮箱格式不合法");
- return response;
- }
- String password = user.getPassword();
- if (!CheckUtils.checkPassword(password)){
- response.setCode(200);
- response.setMessage("密码长度必须为 8-16 位, 且必须包含数字和字母");
- return response;
- }
- String nickname = user.getNickname();
- if (!CheckUtils.checkNickname(nickname)){
- response.setCode(200);
- response.setMessage("昵称长度不合法");
- return response;
- }
- response.setCode(100);
- return response;
- }
- }
说明: 这一层主要做了用户注册参数的校验
效果图
回顾
从下往上看, 从用户注册到邮件发送就实现了, 大部分代码都是做的参数校验, 因为用户行为是不可信的, 要构建安全的后台系统, 就要无死角的校验校验
Github 地址: https://github.com/ChinaSilence/any-video
来源: http://www.phperz.com/article/18/0310/357244.html