You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Spring Boot项目signup方法及CommandLineRunner抛出NullPointerException排查

问题根因分析

1. findUserByEmail方法设计不符合调用方预期

你当前的findUserByEmail逻辑是:邮箱存在返回UserDto,不存在直接抛自定义异常。但你在两处调用它校验邮箱是否存在时,都是用if (返回结果 == null)判断邮箱不存在:

  • CommandLineRunner中:UserDto adminDto = userService.findUserByEmail("admin3@example.com"); if (adminDto == null)
  • AdminController中:UserDto userDto = userService.findUserByEmail(adminSignupCommand.getEmail()); if (userDto !=null)
    当邮箱不存在时,方法直接抛出异常,根本不会执行到后续的空判断逻辑,这是触发本次报错的直接原因。

2. signup方法逻辑完全写反

你设计signup的目标是邮箱不存在时创建新用户,但当前代码逻辑完全相反:

Optional<User> user = userRepository.findUserByEmail(userDto.getEmail());
if (user.isPresent()) { // 只有邮箱已存在才会走创建用户逻辑
    // 新建用户保存代码
}
throw exception(/* 邮箱不存在直接抛异常 */);

就算通过了校验步骤,调用signup也会要么重复创建用户,要么邮箱不存在直接抛异常。

3. 自定义异常抛出时触发空指针

堆栈显示空指针出现在KalanblowSystemManagementException.format方法中,说明你抛异常时传入的参数存在null值,或者异常消息模板的占位符和传入参数不匹配,导致格式化时触发空指针。


修复方案

第一步:修改findUserByEmail方法适配校验逻辑

建议改方法返回Optional<UserDto>,不存在时返回空容器,不要直接抛异常:

@Override
public Optional<UserDto> findUserByEmail(String email) {
    Optional<User> user = userRepository.findUserByEmail(email);
    if (user.isPresent()) {
        log.debug("findUserByEmail:{}", user.get());
        return Optional.of(UserMapper.userToUserDto(user.get()));
    }
    return Optional.empty();
}

对应修改调用方的判断逻辑:

  • CommandLineRunner改为:Optional<UserDto> adminOpt = userService.findUserByEmail("admin3@example.com"); if (adminOpt.isEmpty())
  • Controller改为:Optional<UserDto> userOpt = userService.findUserByEmail(adminSignupCommand.getEmail()); if (userOpt.isPresent())

第二步:修正signup方法的逻辑

把判断条件反过来,邮箱不存在时才走创建逻辑:

@Override
@SneakyThrows
public UserDto signup(UserDto userDto) {
    Optional<User> existUser = userRepository.findUserByEmail(userDto.getEmail());
    // 邮箱不存在才创建用户
    if (existUser.isEmpty()) {
        Role userRole = userDto.isAdmin() 
                ? roleRepository.findRoleByUserRoleName(UserRole.ADMIN)
                : roleRepository.findRoleByUserRoleName(UserRole.STUDENT);
        User newUser = new User()
                .setEmail(userDto.getEmail())
                .setFirstName(userDto.getFirstName())
                .setLastName(userDto.getLastName())
                .setPassword(passwordEncoder.encode(userDto.getPassword()))
                .setRoles(new HashSet<>(Arrays.asList(userRole)))
                .setMobileNumber(userDto.getMobileNumber());
        User saved = userRepository.save(newUser);
        log.debug("signup new user:{}", UserMapper.userToUserDto(saved));
        return UserMapper.userToUserDto(saved);
    }
    // 邮箱已存在时抛异常
    throw exception(EntityType.USER, ExceptionType.ENTITY_EXISTS, "用户邮箱"+ userDto.getEmail() +"已存在");
}

第三步:排查自定义异常的格式化逻辑

检查KalanblowSystemManagementException.format方法,确保传入的所有参数都不为null,消息模板的占位符数量和传入参数数量匹配。

内容的提问来源于stack exchange,提问作者user16117306

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.09 09:54:03