从控制器的结果集中排除列 |弹簧数据 jpa

Posted

技术标签:

【中文标题】从控制器的结果集中排除列 |弹簧数据 jpa【英文标题】:Exclude column from resultset in controller | Spring data jpa 【发布时间】:2017-01-10 16:52:23 【问题描述】:

我有一个用户实体:

public class SpringUsers implements Serializable 
    private String password;
    // other fields omitted
    @Basic
    @Column(name = "password")
    public String getPassword() 
        return password;
    

    public void setPassword(String password) 
        this.password = password;
    

及其存储库:

public interface SpringUsersRepository extends CrudRepository<SpringUsers, Integer> 
    SpringUsers findByUsername(String username);
    List<SpringUsers> findByUserId(Integer userId);

我有一个控制器方法,它应该获取与当前经过身份验证的用户具有相同 userId(内部使用)的所有注册用户的列表:

public List<SpringUsers> getRegisteredUsers() 
    CustomUserDetails authenticatedUserDetails = getCustomUserDetails();
    List<SpringUsers> registered = springUsersRepository.findByUserId(
        authenticatedUserDetails.getUserMyId());
    return registered.stream().map(v -> 
        v.setPassword(null);
        return v;
    ).collect(Collectors.toList());

我不想将密码(即使它是加密的)传递给前端 - 所以我通过用户流式传输并将密码设置为 null,如上所示。

但是,我想知道是否有可能一开始就在查询结果中不包含用户的密码?


版本信息:

春季启动 1.4.0 & 休眠 5.0.9.Final

【问题讨论】:

【参考方案1】:

您可以使用@Query 选择性地包含一些字段:

// Include all fields you wanna query for using u.x syntax
// AFAIK there is no exclusion syntatic sugar
@Query("select u.id, u.username from SpringUsers u where u.id = ?1")
List<SpringUsers> findByUserId(Integer userId);

您也可以使用Projections。首先通过引入投影接口来定义投影:

interface NoPasswordUser 
    Long getId();
    String getUsername();
    // Do not include getPassword();

然后在你的仓库中使用它:

public interface SpringUsersRepository extends CrudRepository<SpringUsers, Integer> 
    NoPasswordUser findByUsername(String username);
    List<NoPasswordUser> findByUserId(Integer userId);

无论如何,最好不要通过 REST 或任何远程接口公开您的实体。你可以使用 DTO,这个post 可能在这个领域很有用。

【讨论】:

是的,投影似乎是一种方法 --- 如果我找不到其他解决方案,我会这样做。谢谢你的提示! 不幸的是,这似乎不适用于嵌套对象。【参考方案2】:

使用@JsonIgnore,这将使它在后面可用但转换为json时不会返回

@Size(min = 8)
@JsonIgnore
private String password;

【讨论】:

【参考方案3】:

我认为在从 db 获取实体时无法忽略某些字段,因为这些实体不会处于一致状态 - 它们的数据会与数据库中的数据不同。但也存在其他选项(自定义查询、投影)。

一种选择是使用constructor expressions 并在查询中直接用只需要的数据填充一些 POJO

select new my.company.SafeUser(u.username, u.email) from User u

无论如何,我认为您应该将 DTO 发送到前端,并在其中公开您在前端所需的属性。这种方法有很多优点,你可以像上面的例子那样初始化它们,或者在结果的循环中。

【讨论】:

【参考方案4】:

将密码排除在写入 json 并继续读取的最佳方法是 Jackson 注释:

@JsonProperty(access = JsonProperty.Access.WRITE_ONLY)
private String password;

类似,注册日期:

@JsonProperty(access = JsonProperty.Access.READ_ONLY)
private Date registered = new Date();

见Jackson @JsonProperty examples

【讨论】:

如果你按munis,请写评论,解决方案有什么问题

以上是关于从控制器的结果集中排除列 |弹簧数据 jpa的主要内容,如果未能解决你的问题,请参考以下文章

JDBC结果集

JDBC的结果集

将两个数据库列连接到一个结果集列

SAS - 如何从数据集中获取最后的“n”个观察结果?

使用空数据集的Spark SQL连接会导致更大的输出文件大小

使用存储过程的结果加入表