如何将 Spring REST 投影与自定义控制器一起使用
How to use Spring REST Projections with custom controller
我有以下投影,其中 return 标签名称:
@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> {
}
一切正常,它 return 仅包含 nae 的标签列表。
但是如果我想使用具有相同端点的自定义控制器(假设我这样做是为了错误处理),它 return 我只有没有标签列表的新闻,就像投影不存在一样.
这是控制器:
@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);
}
}
如果要添加News的所有字段,可以操作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
--> newsTag
字段应该是这样的(请不要忘记在你的资源汇编器中设置所有标签 class!) ;
private List<NewsTagFields> newsTag = new ArrayList<>();
现在您需要NewsTagFields.class。你也可以使用这个 class ;
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;
}
}
最后将此代码添加到 ResourceAssembler
以添加新的 NewsTagFields 列表;
(此代码提供获取所有 newsTag 并完全转换为 NewsTagFields 列表。并添加到 newsResource 发送给客户端)
final List<NewsTagFields> allNewsTag =
news.getNewsTag().stream()
.map(newsTag -> new NewsTagFields(newsTag.getId(), newsTag.getName()))
.collect(Collectors.toList());
newsResource.setNewsTagList(allNewsTag);
我有以下投影,其中 return 标签名称:
@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> {
}
一切正常,它 return 仅包含 nae 的标签列表。
但是如果我想使用具有相同端点的自定义控制器(假设我这样做是为了错误处理),它 return 我只有没有标签列表的新闻,就像投影不存在一样.
这是控制器:
@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);
}
}
如果要添加News的所有字段,可以操作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
--> newsTag
字段应该是这样的(请不要忘记在你的资源汇编器中设置所有标签 class!) ;
private List<NewsTagFields> newsTag = new ArrayList<>();
现在您需要NewsTagFields.class。你也可以使用这个 class ;
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;
}
}
最后将此代码添加到 ResourceAssembler
以添加新的 NewsTagFields 列表;
(此代码提供获取所有 newsTag 并完全转换为 NewsTagFields 列表。并添加到 newsResource 发送给客户端)
final List<NewsTagFields> allNewsTag =
news.getNewsTag().stream()
.map(newsTag -> new NewsTagFields(newsTag.getId(), newsTag.getName()))
.collect(Collectors.toList());
newsResource.setNewsTagList(allNewsTag);