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
相关产品推荐
相关产品推荐

