如何将Spring REST Projections与自定义控制器一起使用

时间:2018-09-03 22:14:01

标签: java spring spring-boot spring-data spring-rest

我有以下Projection,它们返回标签的名称:

@Projection(types = NewsTag.class, name = "newsTag")
public interface NewsTagProjection {

    @Value("#{target.tag.name}")
    String getName();
}

我在负责newsTag模型的以下存储库中使用它:

@RepositoryRestResource(excerptProjection = NewsTagProjection.class)
public interface NewsTagRepository extends JpaRepository<NewsTag, Integer> {
}

因此,当我调用包含NewsTag列表的新闻存储库时:

@RepositoryRestResource
public interface NewsRepository extends JpaRepository<News, Integer> {
}

一切正常,它只返回带有nae的标签列表。
但是,如果我想使用具有相同端点的自定义控制器(让我说这是为了进行错误处理),它只会向我返回没有标签列表的新闻,就像投影不存在一样。

这是控制器:

@RepositoryRestController
@RequestMapping("news")
public class NewsController {

    private NewsService newsService;
    private PagedResourcesAssembler<News> pagedAssembler;
    private NewsResourceAssembler newsResourceAssembler;

    @Autowired
    public void setNewsService(NewsService newsService) {
        this.newsService = newsService;
    }

    @SuppressWarnings("SpringJavaInjectionPointsAutowiringInspection")
    @Autowired
    public void setPagedAssembler(PagedResourcesAssembler<News> pagedAssembler) {
        this.pagedAssembler = pagedAssembler;
    }

    @Autowired
    public void setNewsResourceAssembler(NewsResourceAssembler newsResourceAssembler) {
        this.newsResourceAssembler = newsResourceAssembler;
    }

    // Return all news with pagination
    @GetMapping
    public ResponseEntity<?> getAllNews(Pageable pageable) {
        Page<News> newsPage = this.newsService.getAllNews(pageable);
        return ResponseEntity.ok(this.pagedAssembler.toResource(newsPage, this.newsResourceAssembler));
    }
}

修改 NewsResourceAssembler:

@Service
public class NewsResourceAssembler implements ResourceAssembler<News, Resource<News>> {

    private EntityLinks entityLinks;

    @Autowired
    public void setEntityLinks(EntityLinks entityLinks) {
        this.entityLinks = entityLinks;
    }

    @Override
    public Resource<News> toResource(News news) {
        Link self = entityLinks.linkFor(News.class).slash(news.getId()).withSelfRel();
        Link newsTags = entityLinks.linkFor(News.class).slash(news.getId()).slash("newsTags").withRel("newsTags");
        Link newsComments = entityLinks.linkFor(News.class).slash(news.getId()).slash("newsComments").withRel("newsComments");
        return new Resource<>(news, self, newsTags, newsComments);
    }
}

1 个答案:

答案 0 :(得分:3)

如果要添加新闻的所有字段,则可以操纵 ResponseEntity 的返回对象。所以我更改了此代码,您可以申请代码吗?

NewsResourceAssembler.class应该像;

@Service
public class NewsResourceAssembler implements ResourceAssembler<News, Resource<NewsResource>> {

    private EntityLinks entityLinks;

    @Autowired
    public void setEntityLinks(EntityLinks entityLinks) {
        this.entityLinks = entityLinks;
    }

    @Override
    public Resource<NewsResource> toResource(News news) {

        Link self = entityLinks.linkFor(News.class).slash(news.getId()).withSelfRel();
        Link newsTags = entityLinks.linkFor(News.class).slash(news.getId()).slash("newsTags").withRel("newsTags");
        Link newsComments = entityLinks.linkFor(News.class).slash(news.getId()).slash("newsComments").withRel("newsComments");

        final NewsResource newsResource = new NewsResource();
        //set any fields to which do you wants to send client
        //newsResource.setExampleFields();
        //newsResource.setNewsTagList(news.getNewsTag()); //example code. Change according to your models

        return new Resource(newsResource, self, newsTags, newsComments);
    }
}

现在您需要NewsResource.class,所以应该像这样;

@JsonIgnoreProperties(ignoreUnknown = true)
public class NewsResource extends ResourceSupport {

    //private fields of which do you wants
    //dont forget list of newstag field
    //ex : private List<NewsTagFields> newsTag = new ArrayList<>();

    //Also should write getter and setter methods
}

PS:请不要忘记注释行的规则。根据此更改,您的客户应分析对客户的传入响应。因为作为响应,某些链接rel应该在主对象上更改。但是您的自定义参数没有改变。

编辑: 如果在NewsResource.class的{​​{1}}->字段中应该是(请不要忘记在资源汇编程序类中设置所有标签!);

newsTag

现在您需要NewsTagFields.class。你也可以使用这个类;

private List<NewsTagFields> newsTag = new ArrayList<>();

最后将这段代码添加到public class NewsTagFields { private final String id; private final String name; public NewsTagFields(String id, String name) { this.id = id; this.name = name; } public String getId() { return id; } public String getName() { return name; } } 中,以添加新的NewsTagFields列表; (此代码提供了获取所有 newsTag 并完全转换为 NewsTagFields 的列表。并添加到 newsResource 中发送给客户端

ResourceAssembler