如何在Spring MVC控制器中应用Spring数据投影?
直接调用数据存储库方法时,是否可以指定如何在Spring MVC控制器中应用Spring数据投影?,spring,spring-security,spring-data,Spring,Spring Security,Spring Data,直接调用数据存储库方法时,是否可以指定投影?以下是存储库代码-注意,我不想通过REST公开它,而是希望能够从服务或控制器调用它: @RepositoryRestResource(exported = false) public interface UsersRepository extends PagingAndSortingRepository<User, Long> { @Query(value = "SELECT u FROM User u WHERE ....")
投影
?以下是存储库代码-注意,我不想通过REST公开它,而是希望能够从服务或控制器调用它:
@RepositoryRestResource(exported = false)
public interface UsersRepository extends PagingAndSortingRepository<User, Long> {
@Query(value = "SELECT u FROM User u WHERE ....")
public Page<User> findEmployeeUsers(Pageable p);
}
@RepositoryRestResource(exported=false)
公共接口用户存储库扩展了分页和排序存储库{
@查询(value=“从用户u中选择u,其中….”)
公共页面findEmployeeUsers(可分页);
}
然后在控制器中执行以下操作:
@PreAuthorize(value = "hasRole('ROLE_ADMIN')")
@RequestMapping(value = "/users/employee")
public Page<User> listEmployees(Pageable pageable) {
return usersRepository.findEmployeeUsers(pageable);
}
@PreAuthorize(value=“hasRole('ROLE\u ADMIN'))
@请求映射(value=“/users/employee”)
公共页面列表员工(可分页){
return users respository.findeEmployeeUsers(可分页);
}
当像上面那样直接调用findeEmployeeUsers
方法时,有没有办法为其指定projection
我意识到上面的代码对某些人来说可能很奇怪。。。可以通过REST公开存储库,并将@PreAuthorize
东西放在存储库中。ThinkController是进行安全检查的更合适的地方——它更自然,测试也更简单
所以,
projection
这个东西能以某种方式传递到一个直接调用的存储库方法中吗?不,它不是,特别是当投影通常是根据具体情况应用于查询执行的结果时。因此,它们目前被设计为选择性地应用于域类型
从最新的SpringDataFowler发行版TrainGA发行版开始,投影基础设施可以在SpringMVC控制器中以编程方式使用。只需为SpelAwareProxyProjectionFactory
声明一个Springbean:
@Configuration
class SomeConfig {
@Bean
public SpelAwareProxyProjectionFactory projectionFactory() {
return new SpelAwareProxyProjectionFactory();
}
}
然后将其注入控制器并使用:
@Controller
class SampleController {
private final ProjectionFactory projectionFactory;
@Autowired
public SampleController(ProjectionFactory projectionFactory) {
this.projectionFactory = projectionFactory;
}
@PreAuthorize(value = "hasRole('ROLE_ADMIN')")
@RequestMapping(value = "/users/employee")
public Page<?> listEmployees(Pageable pageable) {
return usersRepository.findEmployeeUsers(pageable).//
map(user -> projectionFactory.createProjection(Projection.class, user);
}
}
@控制器
类采样控制器{
私人最终项目工厂项目工厂;
@自动连线
公共采样控制器(ProjectionFactory ProjectionFactory){
this.projectionFactory=projectionFactory;
}
@预授权(value=“hasRole('ROLE\u ADMIN'))
@请求映射(value=“/users/employee”)
公共页面列表员工(可分页){
return usersRepository.findeEmployeeUsers(可分页)//
map(用户->projectionFactory.createProjection(Projection.class,用户);
}
}
查看最新版本的
页面
如何具有映射(…)
方法,可用于动态转换页面内容。我们使用JDK 8 lambda提供转换步骤,使用ProjectionFactory
作为@Oliver答案的补充,如果您想像SpringDataRest那样按名称查找投影(而不是在控制器中硬连线),这是您必须做的:
RepositoryRestConfiguration
注入控制器。此bean允许您访问名为ProjectionDefinitions
(请参阅,getProjectionConfiguration()
)的类,该类充当投影元数据目录ProjectionDefinitions
可以检索给定名称的投影类及其关联的绑定类@RestController
@RequestMapping("students")
public class StudentController {
/**
* {@link StudentController} logger.
*/
private static final Logger logger =
LoggerFactory.getLogger(StudentController.class);
/**
* Projections Factory.
*/
private ProjectionFactory p8nFactory;
/**
* Projections Directory.
*/
private ProjectionDefinitions p8nDefs;
/**
* {@link Student} repository.
*/
private StudentRepository repo;
/**
* Class Constructor.
*
* @param repoConfig
* {@code RepositoryRestConfiguration} bean
* @param p8nFactory
* Factory used to create projections
* @param repo
* {@link StudentRepository} instance
*/
@Autowired
public StudentController(
RepositoryRestConfiguration repoConfig,
ProjectionFactory p8nFactory,
StudentRepository repo
) {
super();
this.p8nFactory = p8nFactory;
this.p8nDefs = repoConfig.getProjectionConfiguration();
this.repo = repo;
}
...
/**
* Retrieves all persisted students.
*
* @param projection
* (Optional) Name of the projection to be applied to
* students retrieved from the persistence layer
* @return
* {@code ResponseEntity} whose content can be a list of Students
* or a projected view of them
*/
@GetMapping(path = "", produces = APPLICATION_JSON_VALUE)
public ResponseEntity<Object> retrieveAll(
@RequestParam(required = false) String projection
) {
Class<?> type; // Kind of Projection to be applied
List<?> rawData; // Raw Entity Students
List<?> pjData; // Projected students (if applies)
rawData = this.repo.findAll();
pjData = rawData;
if (projection != null) {
type = this.p8nDefs.getProjectionType(Student.class, projection);
pjData = rawData
.stream()
.map(s -> this.p8nFactory.createProjection(type, s))
.collect(Collectors.toList());
}
return new ResponseEntity<>(pjData, HttpStatus.OK);
}
}
@RestController
@请求映射(“学生”)
公共班级学生控制员{
/**
*{@link StudentController}记录器。
*/
专用静态最终记录器=
LoggerFactory.getLogger(StudentController.class);
/**
*投影厂。
*/
私营项目工厂P8N工厂;
/**
*投影目录。
*/
私人项目定义p8nDefs;
/**
*{@link Student}存储库。
*/
私人储蓄回购;
/**
*类构造函数。
*
*@param repoConfig
*{@code RepositoryRestConfiguration}bean
*@param p8n工厂
*用于创建投影的工厂
*@param repo
*{@link StudentRepository}实例
*/
@自动连线
公共学生控制员(
RepositoryRestConfiguration repoConfig,
项目工厂P8N工厂,
存款回购
) {
超级();
this.p8nFactory=p8nFactory;
this.p8nDefs=repoConfig.getProjectionConfiguration();
this.repo=回购;
}
...
/**
*检索所有保留的学生。
*
*@param投影
*(可选)要应用到的投影的名称
*从持久层检索的学生
*@返回
*{@code ResponseEntity},其内容可以是学生列表
*或者它们的投影视图
*/
@GetMapping(path=”“,products=APPLICATION\u JSON\u值)
公共响应检索所有(
@RequestParam(必需=false)字符串投影
) {
类类型;//要应用的投影类型
列出rawData;//原始实体学生
列出pjData;//预计学生(如果适用)
rawData=this.repo.findAll();
pjData=原始数据;
if(投影!=null){
type=this.p8nDefs.getProjectionType(Student.class,projection);
pjData=rawData
.stream()
.map(s->this.p8nFactory.createProjection(type,s))
.collect(Collectors.toList());
}
返回新的响应属性(pjData,HttpStatus.OK);
}
}
愉快的编码!在最新的Spring数据Rest版本中,它可以轻松完成 您需要做的就是:
`/api/users/search/findEmployeeUsers?projection=userView`
PagedModel
,而不是Page
@Override
@Transactional(readOnly = true)
public PagedModel<PersistentEntityResource> listEmployees(Pageable pageable, PersistentEntityResourceAssembler resourceAssembler) {
Page<User> users = userRepository.findEmployeeUsers(pageable);
List<User> entities = users.getContent();
entities.forEach(user -> user.setOnVacation(isUserOnVacationNow(user)));
CollectionModel<PersistentEntityResource> collectionModel = resourceAssembler.toCollectionModel(entities);
return PagedModel.of(collectionModel.getContent(), new PagedModel.PageMetadata(
users.getSize(),
users.getNumber(),
users.getTotalElements(),
users.getTotalPages()));
}
@BasePathAwareController
public class UsersController {
@GetMapping(value = "/users/search/findEmployeeUsers")
ResponseEntity<PagedModel<PersistentEntityResource>> findEmployeeUsers(Pageable pageable,
PersistentEntityResourceAssembler resourceAssembler) {
return ResponseEntity.status(HttpStatus.OK)
.body(userService.listEmployees(pageable, resourceAssembler));
}
}
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.3.4.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>