私は本当に簡単なはずだと思うことをやろうとしています。 Question
オブジェクトがあり、spring-boot、spring-data-rest、spring-hateoasでセットアップされています。すべての基本は正常に機能します。 List<Question>
をRepository
の/questions
URLへのGETとまったく同じ形式で返すカスタムコントローラーを追加して、2つの間の応答に互換性を持たせたいと思います。
これが私のコントローラーです:
@Controller
public class QuestionListController {
@Autowired private QuestionRepository questionRepository;
@Autowired private PagedResourcesAssembler<Question> pagedResourcesAssembler;
@Autowired private QuestionResourceAssembler questionResourceAssembler;
@RequestMapping(
value = "/api/questions/filter", method = RequestMethod.GET,
consumes = MediaType.APPLICATION_JSON_VALUE,
produces = MediaType.APPLICATION_JSON_VALUE)
public @ResponseBody PagedResources<QuestionResource> filter(
@RequestParam(value = "filter", required = false) String filter,
Pageable p) {
// Using queryDSL here to get a paged list of Questions
Page<Question> page =
questionRepository.findAll(
QuestionPredicate.findWithFilter(filter), p);
// Option 1 - default resource assembler
return pagedResourcesAssembler.toResource(page);
// Option 2 - custom resource assembler
return pagedResourcesAssembler.toResource(page, questionResourceAssembler);
}
}
オプション1:提供されたSimplePagedResourceAssembler
に依存します
このオプションの問題は、必要な_links
がレンダリングされないことです。これに対する修正があれば、それが最も簡単な解決策になります。
オプション2:オープンリソースアセンブラを実装します
このオプションの問題は、 Spring-Hateoasドキュメント に従ってQuestionResourceAssembler
を実装すると、QuestionResource
がQuestion
のほぼ重複するパスになり、アセンブラが手動でデータをコピーする必要があることです。 2つのオブジェクト、および関連するすべての_links
を手動で作成する必要があります。これは多くの無駄な努力のようです。
何をしますか?
SpringがQuestionRepository
をエクスポートするときに、これらすべてを実行するコードをすでに生成していることを私は知っています。そのコードを利用して使用し、コントローラーからの出力がシームレスで、生成された応答と交換可能であることを確認する方法はありますか?
Spring DataRestの動作を完全に模倣する方法を見つけました。秘訣は、PagedResourcesAssembler
と引数が挿入されたPersistentEntityResourceAssembler
のインスタンスの組み合わせを使用することにあります。コントローラを次のように定義するだけです...
@RepositoryRestController
@RequestMapping("...")
public class ThingController {
@Autowired
private PagedResourcesAssembler pagedResourcesAssembler;
@SuppressWarnings("unchecked") // optional - ignores warning on return statement below...
@RequestMapping(value = "...", method = RequestMethod.GET)
@ResponseBody
public PagedResources<PersistentEntityResource> customMethod(
...,
Pageable pageable,
// this gets automatically injected by Spring...
PersistentEntityResourceAssembler resourceAssembler) {
Page<MyEntity> page = ...;
...
return pagedResourcesAssembler.toResource(page, resourceAssembler);
}
}
これは、SpringがPersistentEntityResourceAssemblerArgumentResolver
を挿入するために使用するPersistentEntityResourceAssembler
の存在のおかげで機能します。結果は、リポジトリクエリメソッドの1つに期待するものとまったく同じです。
この古い質問に対する更新された回答:PersistentEntityResourceAssembler
でそれを行うことができるようになりました
@RepositoryRestControllerの内部:
@RequestMapping(value = "somePath", method = POST)
public @ResponseBody PersistentEntityResource postEntity(@RequestBody Resource<EntityModel> newEntityResource, PersistentEntityResourceAssembler resourceAssembler)
{
EntityModel newEntity = newEntityResource.getContent();
// ... do something additional with new Entity if you want here ...
EntityModel savedEntity = entityRepo.save(newEntity);
return resourceAssembler.toResource(savedEntity); // this will create the complete HATEOAS response
}
この問題はかなり簡単な方法で解決できたと思いますが、より適切に文書化されている可能性があります。
SimplePagedResourceAssembler
の実装を読んだ後、ハイブリッドソリューションが機能する可能性があることに気付きました。提供されたResource<?>
クラスはエンティティを正しくレンダリングしますが、リンクは含まれていないため、追加するだけで済みます。
私のQuestionResourceAssembler
実装は次のようになります。
@Component
public class QuestionResourceAssembler implements ResourceAssembler<Question, Resource<Question>> {
@Autowired EntityLinks entityLinks;
@Override
public Resource<Question> toResource(Question question) {
Resource<Question> resource = new Resource<Question>(question);
final LinkBuilder lb =
entityLinks.linkForSingleResource(Question.class, question.getId());
resource.add(lb.withSelfRel());
resource.add(lb.slash("answers").withRel("answers"));
// other links
return resource;
}
}
それが終わったら、私のコントローラーでオプション2上記を使用しました:
return pagedResourcesAssembler.toResource(page, questionResourceAssembler);
これはうまく機能し、コードはそれほど多くありません。唯一の面倒は、必要な参照ごとに手動でリンクを追加する必要があることです。