如何将Spring Data JPA的分页实体映射为自定义的类型

问题

使用Spring Data JPA可以让操作数据库数据变得极为简单:定义一个实体类、然后再创建一个Interface继承JpaRepository,通过这个Interface的实例便可以对数据库进行增删改查。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
public class User
{
/**
* 用户名称
*/
private String username;

/**
* 用户密码
*/
private String password;

// ...省略getter和setter
}

@Repository
public interface UserRepository extends JpaRepository<User, String>, QuerydslPredicateExecutor<User>
{
// ...不需要任何代码
}


@RestController
@RequestMapping("/users")
@Slf4j
public class UserController
{
@Autowired
private UserRepository userRepository;

public Object listUser(Predicate predicate, Pageable pageable)
{
return userRepository.findAll(predicate, pageable);
}
}

数据库实体Entity是不可以直接返回给调用者的,因为有可能实体中包含像“用户密码”、“家庭住址”这样的敏感信息,或者“创建时间”、“最后更新时间”这样的无用信息。

因此,在查询出实体之后,就需要额外的一个转换动作,将数据库实体转换成视图对象或传输对象,但是数据仓库repository,返回的结果是一个org.springframework.data.domain.Page类型,如何能转换成自定义的类型呢?

方案

不要试图去操作这个“不可变”的对象(Page),例如List<User> content = userRepository.findAll(predicate, pageable).getContent();,乖乖的用这个接口中提供的map方法!

方案一

不使用Lamdba表达式,创建一个java.util.function.Function逆名内部类,覆写apply方法进行转换:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
@RestController
@RequestMapping("/users")
@Slf4j
public class UserController
{
@Autowired
private UserRepository userRepository;

public Page<UserDto> listUser(Predicate predicate, Pageable pageable)
{
Page<User> entities = userRepository.findAll(predicate, pageable);
Page<UserDto> result = entities.map(new Function<User, UserDto>() { //import java.util.function.Function;
@Override
public UserDto apply(User user)
{
UserDto dto = new UserDto();
dto.setUsername(user.getCode());
return dto;
}
});
return result;
}
}

方案二

使用Lamdba表达式

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
@RestController
@RequestMapping("/users")
@Slf4j
public class UserController
{
@Autowired
private UserRepository userRepository;

public Page<UserDto> listUser(Predicate predicate, Pageable pageable)
{
Page<UserDto> entities = userRepository.findAll(predicate, pageable).map(UserDto::fromEntity);
return entities;
}
}

public class UserDto
{
private String username;

// 省略getter和setter

public static UserDto fromEntity(User user)
{
UserDto userDto = new UserDto();
userDto.setUsername(user.getCode());
return userDto;
}
}

代码片段

1
2
3
4
5
6
7
8
9
public Page<UserDto> listUser(Predicate predicate, Pageable pageable)
{
return userRepository.findAll(predicate, pageable).map(user ->
{
UserDto dto = new UserDto();
// conversion here
return dto;
});
}

参考