HAL с Spring Hateoas и Mvc (без загрузки)
Я использую Spring MVC и Hateoas, чтобы построить успокоительный API. Ранее я использовал весеннюю загрузку с hateoas, и сервер отображал ответы, как я и ожидал. Теперь, когда я не использую весеннюю загрузку, сервер не отображает ответы должным образом. Из моего исследования я обнаружил, что некоторые люди говорят о решении, которое включает в себя настройку конвертеров сообщений. Итак, в дополнение к аннотации @EnableHypermediaSupport, что необходимо для установки типа носителя HAL без пружинной загрузки?
ApiConfiguration.java:
@Configuration
@ComponentScan
@EnableWebMvc
@EnableHypermediaSupport(type = { HypermediaType.HAL })
public class ApiConfiguration {
}
ApiInitializer.java:
public class ApiInitializer extends AbstractAnnotationConfigDispatcherServletInitializer {
@Override
protected Class<?>[] getRootConfigClasses() {
return null;
}
@Override
protected Class<?>[] getServletConfigClasses() {
return new Class[] { ApiConfiguration.class };
}
@Override
protected String[] getServletMappings() {
return new String[] { "/" };
}
}
pom.xml:
...
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-framework-bom</artifactId>
<version>4.2.0.RELEASE</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.hateoas</groupId>
<artifactId>spring-hateoas</artifactId>
<version>0.19.0.RELEASE</version>
</dependency>
...
AdaptationRestController.java:
@RestController
@ExposesResourceFor(Adaptation.class)
@RequestMapping(value = "/adaptations")
public class AdaptationRestController {
...
@RequestMapping(value = "/{id}", method = RequestMethod.GET, produces = "application/vnd.xpto-adaptation+json")
public ResponseEntity<AdaptationResource> getAdaptation(@PathVariable("id") String adaptationId) {
Adaptation adaptation = adaptationGateway.getAdaptation(adaptationId);
AdaptationResource adaptationResource = adaptationResourceAssembler.toResource(adaptation);
return new ResponseEntity<AdaptationResource>(adaptationResource, HttpStatus.OK);
}
}
AdaptationResource.java:
public class AdaptationResource extends Resource<Adaptation> {
public AdaptationResource(Adaptation adaptation) {
super(adaptation);
}
}
Что я получаю:
"links": [
{
"rel": "self",
"href": "http://xpto.com"
}
],
...
Что предполагается:
"_links": {
"self": {"href": "http://xpto.com"}
},
...
3 ответа
Если вы используете Spring Data JPA для доступа к данным, вы можете включить его веб-поддержку декларативно, добавив EnableSpringDataWebSupport
, Это бы зарегистрировать кучу ArgumentResolvers
за Controller
методы. Проще говоря, вы можете добавить PagedResourcesAssembler
аргумент к вашим методам и использовать его toResource
метод конвертации Page
Отредактируйте сущности к ресурсам, например так:
@RequestMapping(method = GET)
public ResponseEntity getAll(PagedResourcesAssembler ass) {
Page<User> users = userRepository.findAll(new PageRequest(0, 10));
PagedResources pagedResources = ass.toResource(users, assembler);
return ok(pagedResources);
}
с этим выводом json:
{"_embedded":{...},"_links":{"self":{"href":"http://localhost:8080/users"}},"page":{...}}
Можно сделать так, чтобы ваша модель расширяла org.springframework.hateoas.ResourceSupport
public class MyModelClass extends ResourceSupport
затем
@RequestMapping(value="/myresource", method=RequestMethod.GET)
public ResponseEntity<Iterable<MyModelClass>> getAll() {
Iterable<MyModelClass> all= repository.findAll();
for(MyModelClass p : all) {
p.add(linkTo(methodOn(MyController.class).getAll()).slash(p.getId()).withSelfRel());
}
return new ResponseEntity<>(all, HttpStatus.OK);
}
В основном я использую EntityLinks
строить ссылки, не расширяя мой Pojo из каких-либо фреймворк-зависимых классов.
@RestController
@ExposesResourceFor(ProjectServiceResponse.class)
public class ProjectController {
@Autowired
private org.springframework.hateoas.EntityLinks entityLinks;
public HttpEntity<Resource<ProjectServiceResponse>> get(...){
Resource resource = new Resource<ProjectServiceResponse>(response);
resource.add(entityLinks.linkToCollectionResource(ProjectServiceResponse.class).withSelfRel());
return new ResponseEntity<Resource<ProjectServiceResponse>>(resource, HttpStatus.OK);
}
}
Отклик:
"_links": {
"self": {
"href": "http://localhost:8080/project"
}
В моем коде выше ProjectServiceResponse.class
это POJO.
Вы можете сослаться на полный проект на GitHub