【问题标题】:Exclude column from resultset in controller | Spring data jpa从控制器的结果集中排除列 |弹簧数据 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

【问题讨论】:

    标签: java spring hibernate spring-mvc jpa


    【解决方案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,请写评论,解决方案有什么问题
        猜你喜欢
        • 2012-09-09
        • 1970-01-01
        • 2016-09-05
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2020-12-21
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多