SpringBoot发送OTP邮件调用sendOtp时出现NullPointerException异常
问题根因
抛出空指针的直接原因是执行this.emailService.sendMail()时,emailService变量为null,由两个常见错误导致:
OtpEmailController中的emailService字段没有添加依赖注入注解,Spring容器不会自动为该字段装配EmailSenderService实例- 从错误堆栈可见,
sendOtp()方法是在SessionHandlingController.loginUser()中被调用的,如果你是通过new OtpEmailController()手动创建实例后调用方法,该实例不受Spring容器管理,即使加了注入注解,所有依赖字段也会是null
另外你的现有代码还存在几个会影响功能正常运行的隐患:
Random random = new Random(1000)使用固定种子初始化随机数生成器,生成的OTP序列完全可预测,没有安全校验价值SimpleMailMessage仅支持纯文本内容,你拼接的<h1>HTML标签会作为明文展示给用户,不会被渲染为标题格式- 发件人邮箱拼写错误(
gamil.com应为gmail.com),且第三方邮箱SMTP发件需要提前开启服务、配置应用专用密码,直接使用账号密码会发件失败
修复方案
- 修正
OtpEmailController的依赖注入,替换不安全的随机数生成器,推荐使用构造器注入(Spring 4.3+单构造器无需额外添加@Autowired):
@Controller public class OtpEmailController { private final EmailSenderService emailService; private final SecureRandom secureRandom = new SecureRandom(); // 构造器注入,Spring会自动传入装配完成的EmailSenderService Bean public OtpEmailController(EmailSenderService emailService) { this.emailService = emailService; } @PostMapping("/send-otp") public String sendOtp(@RequestParam("email") String email) { // 生成固定6位长度的OTP,不足位数补前导零 int otp = secureRandom.nextInt(1000000); String formattedOtp = String.format("%06d", otp); String subject = "OTP from session-handling-proj By Harshit"; String body = String.format("<h1>OTP = %s</h1>", formattedOtp); emailService.sendMail(email, subject, body); return "success"; } }
- 禁止手动new Spring管理的Bean(包括Controller、Service),如果需要在
SessionHandlingController中触发OTP发送逻辑,直接注入Spring管理的EmailSenderService或OtpEmailController实例使用。
最佳实践:不要跨Controller调用业务方法,将发OTP的逻辑下沉到Service层,所有Web层Controller只做请求参数接收和响应返回,避免出现对象脱离容器管理的问题。
- 修正
EmailSenderService支持HTML邮件发送,补全异常处理:
@Service public class EmailSenderService { private final JavaMailSender mailSender; public EmailSenderService(JavaMailSender mailSender) { this.mailSender = mailSender; } public void sendMail(String toEmail, String subject, String htmlContent) { MimeMessage message = mailSender.createMimeMessage(); try { MimeMessageHelper helper = new MimeMessageHelper(message, true); // 替换为正确的发件人邮箱,确保已开启SMTP服务、配置应用专用密码 helper.setFrom("growthgreek@gmail.com"); helper.setTo(toEmail); helper.setSubject(subject); // 第二个参数传true标识内容为HTML格式 helper.setText(htmlContent, true); mailSender.send(message); System.out.println("OTP邮件发送完成"); } catch (MessagingException e) { throw new RuntimeException("邮件发送失败", e); } } }
- 在
application.properties中补全正确的邮箱SMTP配置,以Gmail为例:
spring.mail.host=smtp.gmail.com spring.mail.port=587 spring.mail.username=你的Gmail邮箱地址 spring.mail.password=Google账号后台生成的应用专用密码 spring.mail.properties.mail.smtp.auth=true spring.mail.properties.mail.smtp.starttls.enable=true
内容的提问来源于stack exchange,提问作者Harshit Toxia
相关产品推荐
相关产品推荐

