注册功能之邮箱激活

前言

在我们进行用户注册的时候,有的时候会碰到需要先登录到邮箱,点击激活后,才可以进行登录。
站在用户角度来说,这我还要登录邮箱,麻烦的一批,站在公司的角度来说,我需要确认你填写的邮箱是否是准确的,这样后续我才好打广告呀,手动滑稽
那么现在站在一个开发者的角度来说,我们应该如何去实现这个邮箱激活的功能呢,个人思路,还有待完善,欢迎各位大佬提出建议,欢迎评论~~

正文

主要的思路是,当用户进行注册时,在用户未点击注册邮件进行激活时,用户的数据会被保存在redis中,并给定一个过期时间,用户需要在过期时间内进行邮件激活,从而才可以登录,这样的好处是可以拦截一些恶意的注册避免数据库中无用数据过多,在这里,后端使用SSM框架,前端主要使用JQuery的ajax方法实现,通过html+ajax向后台发起请求,当用户点击注册按钮时,则发起一个ajax请求,并将表单信息作为params传递给controller层。代码示例如下:

$(function(){
			$("#regist").click(function () {
				if(doCheckUsername()&&doCheckPassword()&&doCheckPhone()&&doCheckEmail()){
					var username=$("#usernameId").val();
					var password = $("#password").val();
					var mobile = $("#mobile").val();
					var email = $("#email").val();
					var params = {};
					params.username=username;
					params.password = password;
					params.mobile = mobile;
					params.email = email;
					$.getJSON("register/doRegister",params, function (result) {
						if(result.data){
							alert("注册成功,请登录邮箱进行激活账号");
							location.href="login.html";
						}else{
							alert("注册失败");
						}
					})
				}
			});

Controller层

当前端发起ajax请求后,controller层用user对象接收用户信息的参数,随后调用Service层方法进行逻辑处理

@Controller
@RequestMapping("/register/")
public class registerController {
    @Autowired
    private RegisterService registerService;
    @RequestMapping("doRegister")
    @ResponseBody
    public JsonResult doRegister(SysUser user){
        registerService.doRegister(user);
        return new JsonResult(new RegisterWarn("注册成功,请登录邮箱进行激活"));
    }
}

Service层

为了用户的信息安全,我对用户密码进行了md5加密,邮箱的激活码通过UUID.randomUUID().toString() 生成一个随机数,保证每个用户的激活码不一致。并将生成的激活码作为redis中的key,将用户的信息转换为json作为value,并设置过期时间,随后调用发送邮件的工具类发送邮件。(关于如何编写邮件工具类,这边不再展开,大家可以自行百度)

@Service
public class RegisterServiceImpl implements RegisterService {
    @Override
    public void doRegister(SysUser user) {
        if(user==null)
           throw new ServiceException("保存的对象不能为空");
        //对密码进行加密
        String password = user.getPassword();
        String salt = UUID.randomUUID().toString();
        SimpleHash md5 = new SimpleHash("MD5", password, salt);
        user.setSalt(salt);
        user.setPassword(md5.toHex());
        String createdUser = user.getUsername();
        String modifiedUser = user.getUsername();
        user.setCreatedUser(createdUser);
        user.setModifiedUser(modifiedUser);
        String activecode = UUID.randomUUID().toString();//生成一个随机数,作为邮箱的激活码
        //将User对象转化成json格式的数据
        ObjectMapper mapper = new ObjectMapper();
        String sUser = null;
        try {
            sUser = mapper.writeValueAsString(user);
        } catch (Exception e) {
            e.printStackTrace();
        }
        //将数据保存进redis缓存中
        Jedis jedis = JedisPoolUtil.getJedis();//使用自定义jedis池
        jedis.setex(activecode,60*60,sUser);//设置过期时间
        jedis.close();
        //发送邮件
        MailUtils.sendMail(user.getEmail(),"这是一封激活邮件,请在1小时内点击下方链接进行账号激活,<br/><a href=http://localhost/register/"+activecode+">请点击进行这里进行用户激活</a>","激活账户");

    }
}

http://localhost/register/activecode,实际上走的是另一个controller的请求路径,当用户点击激活时,则跳转到相应的controller中。

激活邮件Controller

使用 @PathVariable注解来接收Rest风格的参数,通过activeCode从redis中取出相对应的value值,也就是用户的信息的json数据,随后解析json转换为user对象,到了这一步就表示用户已激活邮件,我们可以将用户信息保存到数据库中了,调用service层处理。

@Controller
@RequestMapping("/register/")
public class registerController {
    @Autowired
    private RegisterService registerService;
    @RequestMapping("{activecode}")
    public String doCheckEmail(@PathVariable String activecode){
        Jedis jedis = JedisPoolUtil.getJedis();
        String sUser = jedis.get(activecode);
        //将json格式的数据转换为user对象
        ObjectMapper objectMapper = new ObjectMapper();
        SysUser user = null;
        try {
            user = objectMapper.readValue(sUser, SysUser.class);
        } catch (IOException e) {
            e.printStackTrace();
        }
        Boolean flag = registerService.doInsertUser(user);
        if(!flag){//如果注册失败,跳回注册页面
            return "register";
        }
        return "register_ok";
    }
}

激活邮件Service

调用DAO层去连接数据库并保存用户信息

@Service
public class RegisterServiceImpl implements RegisterService {
    @Autowired
    private SysUserDao userDao;
    @Override
    public Boolean doInsertUser(SysUser user) {
        if(user==null)
            return false;
        int rows = userDao.insertObject(user);
        if(rows==0){
            throw new ServiceException("数据写入失败");
        }
        return true;
    }
}

激活邮件DAO层

@Mapper
public interface SysUserDao {
    int insertObject(SysUser user);
}

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.cy.pj.sys.dao.SysUserDao">
    <insert id="insertObject" parameterType="com.cy.pj.sys.entity.SysUser">
        insert into sys_users values(null,#{username},#{password},#{salt},#{email},#{mobile},now(),now(),#{createdUser},#{modifiedUser})
    </insert>
</mapper>

总结

第一次记录博客,相信也不会是最后一次哈哈,以后有好的想法就会上来记录一下,欢迎各位大佬和我讨论
现在来说说我所知道的不足吧。

1.没有使用nginx反向代理,某些情况下在邮件里访问http://localhost/register/activecode这个链接时,会无法跳转,导致没有办法激活成功。

解决方案

  1. 配置nginx反向代理和修改相应的hosts文件
  2. 打开万能的开发者模式F12,找到对应的a标签下的链接点击访问

个人推荐第一种方法,我在这里没有配置只是因为我懒

2.没有做redis集群,如果redis服务器宕机了会导致用户无法注册也无法激活

解决方案

  1. 配置redis哨兵,当主服务器宕机后会通过哨兵机制会自动将slave切换成master
  2. 配置redis集群

推荐使用redis集群,原因是虽然哨兵模式实现了高可用,但是当保存的数据量越来越大时,无法实现扩容。而redis集群既实现了高可用也实现扩容。

  • 6
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值