idea邮箱登录

邮箱登录

框架搭建

实体类 User(正常创建)
Mapper接口 UserMapper(正常创建)
业务层接口 UserService

import com.baomidou.mybatisplus.extension.service.IService;
import com.XXX.XXX.entity.User;
import javax.servlet.http.HttpSession;

public interface UserService extends IService<User> {
    /**
     * 发送验证码
     */
    void sendCode(String email, HttpSession session);
    /**
     * 验证码登陆账号,如果是新用户,则自动注册
     */
    User loginByVerificationCode(String email, String code, HttpSession session);
}

业务层实现类 UserServicelmpl

@Service
@Slf4j
public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements UserService {
    /**
     * 邮箱发送器
     */
    @Autowired
    private JavaMailSender javaMailSender;
    /**
     * 发送验证码的邮箱地址
     */
    @Value("${spring.mail.username}")
    private String FROM;
    /**
     * 失效时间
     */
    @Value("${spring.mail.timeout}")
    private int TIME_OUT_MINUTES;

    /**
     * RedisTemplate redis操作模板
     */
    @Autowired
    private RedisTemplate<Object, Object> redisTemplate;

    public void sendCode(String email, HttpSession session) {
        // 生成4位验证码
        String code = ValidateCodeUtils.generateValidateCode(4).toString();
        log.info("Session:{}, Code:{}, to {}", session, code, email);      // Slf4j的日志输出
        // 发送邮件
        // 构建一个邮件对象
        SimpleMailMessage simpleMailMessage = new SimpleMailMessage();
        // 设置邮件发送者
        simpleMailMessage.setFrom(FROM);
        // 设置邮件接收者
        simpleMailMessage.setTo(email);
        // 设置邮件主题
        simpleMailMessage.setSubject("[悦刻外卖]登陆验证码");
        // 设置邮件内容
        simpleMailMessage.setText("欢迎使用外卖平台\n您的验证码为:" + code + ",请在" + TIME_OUT_MINUTES + "分钟内使用!\n【该邮件为系统自动发送,请勿回复】");
        // 将验证码存入redis,设置失效时间TIME_OUT_MINUTES分钟
        redisTemplate.opsForValue().set(email, code, TIME_OUT_MINUTES, java.util.concurrent.TimeUnit.MINUTES);
        // 发送邮件
        try {
            javaMailSender.send(simpleMailMessage);
        } catch (MailException e) {
            e.printStackTrace();
            throw new CustomException("致命错误!");
        }


    }

    /**
     * 验证码登陆账号,如果是新用户,则自动注册     */
    @Override
    public User loginByVerificationCode(String email, String code, HttpSession session) {
        // 获取redis中的验证码
        Object verificationCodeInRedis = redisTemplate.opsForValue().get(email);
        // 验证码是否正确
        if (verificationCodeInRedis != null && verificationCodeInRedis.equals(code)) {
            // 验证码正确
            // 查询用户是否存在
            LambdaQueryWrapper<User> queryWrapper = new LambdaQueryWrapper<>();
            queryWrapper.eq(User::getEmail, email);
            User user = this.getOne(queryWrapper);// 查询用户
            // 用户不存在,自动注册
            if (user == null) {
                user = new User();
                user.setEmail(email);
                user.setStatus(1);      // 设置用户状态为正常
                this.save(user);
            }
            // 将用户信息存入session
            session.setAttribute("user", user.getId());
            // 将redis中的验证码删除
            redisTemplate.delete(email);
            return user;
        } else {
            // 验证码错误
            throw new CustomException("验证码错误!");
        }
    }
    }


控制层 UserController
这里有个问题,如果这个人登陆过前端,则在数据库中就会有记录,那么他就会在登录后端时成功,但是后端不允许顾客登录,所以这里不算严谨


@Slf4j
@RestController
@RequestMapping("/user")
public class UserController {
    @Autowired
    private UserService userService;

    /**
     * 发送邮箱验证码
     */
    @PostMapping("/sendMsg")
    public R<String> sendMsg(@RequestBody User user, HttpSession session) {
        log.info("发送验证码,用户信息:{},session:{}", user, session);
        // 获得前端登陆邮箱地址
        String email = user.getEmail();
        // 判断邮箱地址是否为空
        if (!StringUtils.isEmpty(email)) {
            // 发送验证码
            userService.sendCode(email, session);    // 通过工具类发送验证码,sendCode方法在UserService接口中
            return R.success("发送成功,请及时查看邮箱");
        }
        return R.error("发送失败");
    }


    /**
     * 移动端用户登录
     */
    @PostMapping("/login")
    public R<User> login(@RequestBody Map map, HttpSession session) {
        log.info("用户登陆,用户信息:{},session:{}", map.toString(), session);
        // 从map里获取邮箱地址和验证码
        String email = (String) map.get("email");
        String code = (String) map.get("code");
        // 判断邮箱地址和验证码是否为空
        if (!StringUtils.isEmpty(email) && !StringUtils.isEmpty(code)) {
            // 验证码登陆
            User user = userService.loginByVerificationCode(email, code, session);// 通过工具类发送验证码,login方法在UserService接口中
            return R.success(user);
        }
        return R.error("登陆失败,请检查邮箱地址和验证码");
    }
}

工具类ValidateCodeUtils(随机生成验证码工具类)

import java.util.Random;

/**
 * 随机生成验证码工具类
 */
public class ValidateCodeUtils {
    /**
     * 随机生成验证码
     * @param length 长度为4位或者6位
     * @return
     */
    public static Integer generateValidateCode(int length){
        Integer code =null;
        if(length == 4){
            code = new Random().nextInt(9999);//生成随机数,最大为9999
            if(code < 1000){
                code = code + 1000;//保证随机数为4位数字
            }
        }else if(length == 6){
            code = new Random().nextInt(999999);//生成随机数,最大为999999
            if(code < 100000){
                code = code + 100000;//保证随机数为6位数字
            }
        }else{
            throw new RuntimeException("只能生成4位或6位数字验证码");
        }
        return code;
    }

    /**
     * 随机生成指定长度字符串验证码
     * @param length 长度
     * @return
     */
    public static String generateValidateCode4String(int length){
        Random rdm = new Random();
        String hash1 = Integer.toHexString(rdm.nextInt());
        String capstr = hash1.substring(0, length);
        return capstr;
    }
}

修改LoginCheckFilter(过滤器)

在这里插入图片描述
增加判断条件,之前是判断后端是否登录,现在则是判断前端是否登录,二者代码差不多

 // 4.判断用户登陆状态,如果为已登录,则放行  前端用户
        if (request.getSession().getAttribute("user") != null) {
            log.info("本次请求{},用户id={},已登录,直接放行", requestURI, request.getSession().getAttribute("user"));   // Slf4j的日志输出

            Long userId = (Long) request.getSession().getAttribute("user");
            // 在该线程中保存当前用户的id,BaseContext为common包中的工具类,用于保存当前线程的数据
            BaseContext.setCurrentId(userId);

            filterChain.doFilter(request, response);    // 放行
            return;                                     // 结束方法
        }

完善front/api/login.js

(如果没有设计这个api会出现ReferenceError: sendMsgApi is not defined api报错,但是这个报错的原因不一定是因为这个原因,还有可能是因为浏览器的原因,换个浏览器可能就会好)

function sendMsgApi(data) {
    return $axios({
        'url': '/user/sendMsg',
        'method': 'post',
        data
    })
}

添加配置application.yml

因为这里用了redis,所以在运行过程中如果只是配置了会出现java.net.ConnectException: Connection refused: no further information报错,这里是因为redis没有开启

  # 邮箱验证配置信息|必填
  mail:
    host: smtp.qq.com   # 如果你需要使用非qq邮箱,请自行配置host
    username: 3028375407@qq.com # 请自行配置邮箱地址
    password: cmouqanbpxordfcc # 请自行配置邮箱smtp授权码 具体请看本项目根目录下的README.md
    port: 587
    default-encoding: UTF-8
    timeout: 10 # 验证码有效时间 单位:分钟
    properties:
      mail:
        smtp:
          socketFactoryClass: javax.net.ssl.SSLSocketFactory
        # 开启debug以后,邮件发送过程的日志会在控制台上打印出来
        debug: true


  # redis缓存相关配置|必填
  redis:
    host: localhost
    port: 6379          # 默认端口
    password:           # 默认为空
    database: 0         # 默认使用0号数据库

以下是如何开启redis :

首先找到redis目录,右击点击在终端打开,输入redis-server,再回车即可,这样redis默认端口号也是6379


在这里插入图片描述

添加maven配置。pom.xml

    <!-- 邮箱验证码服务dependency -->
    <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-mail</artifactId>
    </dependency>

    <!-- Jedis -->
    <dependency>
      <groupId>redis.clients</groupId>
      <artifactId>jedis</artifactId>
      <version>2.8.0</version>
    </dependency>

    <!-- Spring Data Redis -->
    <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-data-redis</artifactId>
    </dependency>

    <!-- Spring Cache | not used -->
    <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-cache</artifactId>
    </dependency>
在IntelliJ IDEA中创建一个简单的网页登录邮箱功能并设置条件,通常涉及到前端的HTML、CSS和JavaScript,以及后端的Java Servlet或Spring MVC处理用户输入。这里是一个简化的步骤和示例代码: 1. **前端代码(HTML + JavaScript)**: ```html <!-- index.html --> <form id="loginForm"> <input type="text" id="username" placeholder="用户名" required> <input type="password" id="password" placeholder="密码" required> <button onclick="submitLogin()">登录</button> </form> <script> function submitLogin() { const username = document.getElementById('username').value; const password = document.getElementById('password').value; // 这里只是一个模拟请求,实际应用会发送Ajax到服务器 fetch('/login', {method: 'POST', body: JSON.stringify({username, password})}) .then(response => response.json()) .then(data => { if (data.success) { alert('登录成功'); } else { alert('用户名或密码错误'); } }); } </script> ``` 2. **后端Java代码(假设使用Spring Boot)**: ```java // LoginController.java @PostMapping("/login") public Result login(@RequestBody Map<String, String> params) { String username = params.get("username"); String password = params.get("password"); // 检查用户名和密码是否匹配真实数据库中的记录(省略了数据库操作) boolean isValid = checkCredentials(username, password); return new Result(isValid, "success", "登录失败"); } private boolean checkCredentials(String username, String password) { // 真实情况下的密码验证 // ... return false; // 示例返回假值 } ``` `Result`是自定义的数据对象,用于封装状态信息。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值