Как работать с DTO в проектах Spring Data REST?

Spring Data REST автоматизирует отображение только объекта домена. Но чаще всего приходится иметь дело с объектами передачи данных. Итак,как это сделать в SDR?

1 ответов


подход, как работать с DTO на Весна данные проекты

рабочий пример здесь

объекты

субъекты должны реализовать идентифицируемых интерфейс. Например:

@Entity
public class Category implements Identifiable<Integer> {

    @Id
    @GeneratedValue
    private final Integer id;

    private final String name;

    @OneToMany
    private final Set<Product> products = new HashSet<>();

    // skipped
}

@Entity
public class Product implements Identifiable<Integer> {

    @Id
    @GeneratedValue
    private final Integer id;

    private final String name;

    // skipped
}

прогнозы

сделать проекция интерфейс, который методы запроса репозитория вернут:

public interface CategoryProjection {

    Category getCategory();
    Long getQuantity();
}

это будет подвал для DTO. В этом примере DTO будет представлять собой Category и ряд Products принадлежат к нему.

методы репозитория

Create методы возвращают проекцию: один, список DTO и выгружаемый список DTO.

@RepositoryRestResource
public interface CategoryRepo extends JpaRepository<Category, Integer> {

    @RestResource(exported = false)
    @Query("select c as category, count(p) as quantity from Category c join c.products p where c.id = ?1 group by c")
    CategoryProjection getDto(Integer categoryId);

    @RestResource(exported = false)
    @Query("select c as category, count(p) as quantity from Category c join c.products p group by c")
    List<CategoryProjection> getDtos();

    @RestResource(exported = false)
    @Query("select c as category, count(p) as quantity from Category c join c.products p group by c")
    Page<CategoryProjection> getDtos(Pageable pageable);
}

DTO

реализовать DTO из его интерфейс:

@Relation(value = "category", collectionRelation = "categories")
public class CategoryDto implements CategoryProjection {

    private final Category category;
    private final Long quantity;

    // skipped
}

аннотации Relation используется, когда Spring Data REST отрисовывает объект.

контроллер

добавить пользовательские методы RepositoryRestController что будет обслуживать запросы DTO:

@RepositoryRestController
@RequestMapping("/categories")
public class CategoryController {

    @Autowired private CategoryRepo repo;
    @Autowired private RepositoryEntityLinks links;
    @Autowired private PagedResourcesAssembler<CategoryProjection> assembler;

    /**
    * Single DTO
    */
    @GetMapping("/{id}/dto")
    public ResponseEntity<?> getDto(@PathVariable("id") Integer categoryId) {
        CategoryProjection dto = repo.getDto(categoryId);

        return ResponseEntity.ok(toResource(dto));
    }

    /**
    * List of DTO
    */
    @GetMapping("/dto")
    public ResponseEntity<?> getDtos() {
        List<CategoryProjection> dtos = repo.getDtos();

        Link listSelfLink = links.linkFor(Category.class).slash("/dto").withSelfRel();
        List<?> resources = dtos.stream().map(this::toResource).collect(toList());

        return ResponseEntity.ok(new Resources<>(resources, listSelfLink));
    }

    /**
    * Paged list of DTO
    */
    @GetMapping("/dtoPaged")
    public ResponseEntity<?> getDtosPaged(Pageable pageable) {
        Page<CategoryProjection> dtos = repo.getDtos(pageable);

        Link pageSelfLink = links.linkFor(Category.class).slash("/dtoPaged").withSelfRel();
        PagedResources<?> resources = assembler.toResource(dtos, this::toResource, pageSelfLink);

        return ResponseEntity.ok(resources);
    }

    private ResourceSupport toResource(CategoryProjection projection) {
        CategoryDto dto = new CategoryDto(projection.getCategory(), projection.getQuantity());

        Link categoryLink = links.linkForSingleResource(projection.getCategory()).withRel("category");
        Link selfLink = links.linkForSingleResource(projection.getCategory()).slash("/dto").withSelfRel();

        return new Resource<>(dto, categoryLink, selfLink);
    }
}

когда проекции получены из репозитория, мы должны сделать окончательное преобразование из проекции в DTO и "оберните" его в ResourceSupport