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

Spring Boot查询用户接口userName返回null问题求助

问题分析与解决方案

问题描述

集成Spring Security并实现用户创建、数据库接入后,调用查询所有用户的GET接口时出现以下异常:

  • 仅userName字段返回null,id和password字段值正常返回
  • UserRepository.findAll()方法返回的结果中userName同样为null,但数据库中该字段已存储有效数据

相关代码如下:

User实体类

@Entity
@Table(name = "users")
@Data
@AllArgsConstructor
@NoArgsConstructor
public class User implements UserDetails{
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private int id;
    @Column(name = "userName")
    private String userName;
    @Column(name = "password")
    private String password;
}

UserRepository

public interface UserRepository extends JpaRepository<User, Integer> {
    User findByUserName(String userName);
}

UserManager

@Service
@AllArgsConstructor
public class UserManager {
    private UserRepository userRepository;
    private PasswordEncoderConfig passwordEncoderConfig;
    private ModelMapperService modelMapperService;

    public Result createUser(CreateUserRequest createUserRequest){
        User checkUser = userRepository.findByUserName(createUserRequest.getUserName());
        if(checkUser != null){
            return new ErrorResult("User available");
        }
        createUserRequest.setPassword(passwordEncoderConfig.bCryptPasswordEncoder().encode(createUserRequest.getPassword()));
        User user = this.modelMapperService.forRequest().map(createUserRequest, User.class);
        userRepository.save(user);
        return new SuccessResult("Add User");
    }

    public DataResult<List<GetAllUsersResponse>> getAllUser(){
        List<User> users = userRepository.findAll();
        System.out.println(users);
        List<GetAllUsersResponse> responses = users.stream()
                .map(user->this.modelMapperService.forResponse()
                        .map(user, GetAllUsersResponse.class)).collect(Collectors.toList());
        return new SuccessDataResult<List<GetAllUsersResponse>>(responses, "Data");
    }
}

UserController

@RestController
@RequestMapping("/user")
@AllArgsConstructor
public class UserController {
    private UserManager userManager;

    @PostMapping("/add")
    public Result createUser(@RequestBody CreateUserRequest createUserRequest) {
        return userManager.createUser(createUserRequest);
    }
    @GetMapping("/getall")
    public DataResult<List<GetAllUsersResponse>> getAllUser() {
        return userManager.getAllUser();
    }
}

GetAllUsersResponse

@Data
@NoArgsConstructor
@AllArgsConstructor
public class GetAllUsersResponse {
    private int id;
    private String userName;
    private String password;
}

ModelMapperManager

@AllArgsConstructor
public class ModelMapperManager implements ModelMapperService{
    private ModelMapper modelMapper;
    @Override
    public ModelMapper forResponse() {
        this.modelMapper.getConfiguration()
                .setAmbiguityIgnored(true)
                .setMatchingStrategy(MatchingStrategies.LOOSE);
        return this.modelMapper;
    }

    @Override
    public ModelMapper forRequest() {
        this.modelMapper.getConfiguration()
                .setAmbiguityIgnored(true)
                .setMatchingStrategy(MatchingStrategies.STANDARD);
        return this.modelMapper;
    }
}

原因分析

核心问题在于User实体类实现了UserDetails接口,但未重写接口要求的getUsername()方法:

  • UserDetails接口定义了String getUsername();方法,用于获取用户名
  • 实体类字段名为userName,Lombok的@Data注解生成的getter方法是getUserName(),而非getUsername()
  • JPA/Spring Security在映射数据时,会优先识别UserDetails接口的getUsername()方法,但该方法未被正确实现,导致无法读取userName字段的值

额外排查点:数据库字段名与@Column(name = "userName")的配置是否完全匹配(包括大小写),部分数据库对字段名大小写敏感,若数据库实际字段为username/USER_NAME等,会导致映射失败。

解决方案

1. 重写UserDetails的getUsername()方法

修改User实体类,明确重写getUsername()方法并返回userName字段,同时实现UserDetails接口的其他必要方法:

@Entity
@Table(name = "users")
@Data
@AllArgsConstructor
@NoArgsConstructor
public class User implements UserDetails{
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private int id;
    @Column(name = "userName")
    private String userName;
    @Column(name = "password")
    private String password;

    // 重写UserDetails的getUsername方法
    @Override
    public String getUsername() {
        return this.userName;
    }

    @Override
    public boolean isAccountNonExpired() {
        return true;
    }

    @Override
    public boolean isAccountNonLocked() {
        return true;
    }

    @Override
    public boolean isCredentialsNonExpired() {
        return true;
    }

    @Override
    public boolean isEnabled() {
        return true;
    }

    @Override
    public Collection<? extends GrantedAuthority> getAuthorities() {
        // 根据实际需求配置权限,此处默认返回空集合
        return new ArrayList<>();
    }
}

2. 校验数据库字段与实体类映射一致性

  • 确认数据库中用户表的字段名与@Column注解的name属性完全一致,若数据库字段为下划线命名(如user_name),可修改注解为@Column(name = "user_name")
  • 若使用MySQL,可检查lower_case_table_names配置,确保字段名大小写处理符合预期

验证方案

修改代码后重启服务,重新调用/user/getall接口,确认userName字段能正常返回数据库中的值;同时查看UserRepository.findAll()的打印结果,确认userName不再为null。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.30 15:00:01