Spring Boot HATEOAS输出失败

时间:2018-02-19 10:16:34

标签: spring rest spring-boot hateoas spring-hateoas

Sprint Boot REST HATEOAS服务中的实体输出不起作用。该服务为每个实体返回一个空字符串。没有错误消息。我试过Spring Boot 1.5.4和2.0.0.RC1。

完整的源代码在GitHub上:https://github.com/murygin/hateoas-people-service

应用

@SpringBootApplication
@Configuration
@EnableHypermediaSupport(type={EnableHypermediaSupport.HypermediaType.HAL})
public class Application {   
  public static void main(String args[]) {
    SpringApplication.run(Application.class);
  }
}

PersonController

@RestController
@RequestMapping(value = "/persons", produces = "application/hal+json")
public class PersonController {

  @GetMapping
  public ResponseEntity<Resources<PersonResource>> all() {
    final List<PersonResource> collection =
        getPersonList().stream().map(PersonResource::new).collect(Collectors.toList());
    final Resources<PersonResource> resources = new Resources<>(collection);
    final String uriString = ServletUriComponentsBuilder.fromCurrentRequest().build().toUriString();
    resources.add(new Link(uriString, "self"));
    return ResponseEntity.ok(resources);
  }

  @GetMapping("/{id}")
  public ResponseEntity<PersonResource> get(@PathVariable final long id) {
    Person p = new Person((long)1,"Donald","Duck");
    return ResponseEntity.ok(new PersonResource(p));
  }

  private List<Person> getPersonList() {
    List<Person> personList = new LinkedList<>();
    personList.add(new Person((long)1,"Donald","Duck"));
    personList.add(new Person((long)2,"Dagobert","Duck"));
    personList.add(new Person((long)3,"Daniel","Duesentrieb"));
    return personList;
  }

}

PersonResource

public class PersonResource extends ResourceSupport {

  private final Person person;

  public PersonResource(final Person person) {
    this.person = person;
    final long id = person.getId();
    add(linkTo(PersonController.class).withRel("people"));
    add(linkTo(methodOn(PersonController.class).get(id)).withSelfRel());
  }
}

public class Person {    
  private Long id;   
  private String firstName;   
  private String secondName;

  public Person() {
  }

  public Person(Long id, String firstName, String secondName) {
    this.id = id;
    this.firstName = firstName;
    this.secondName = secondName;
  }

  // getter and setter...
}

http://localhost:8080/persons

的输出
    {
        _embedded: {
            personResourceList: [{
                    _links: {
                        people: {
                            href: "http://localhost:8080/persons"
                        },
                        self: {
                            href: "http://localhost:8080/persons/1"
                        }
                    }
                },
                {
                    _links: {
                        people: {
                            href: "http://localhost:8080/persons"
                        },
                        self: {
                            href: "http://localhost:8080/persons/2"
                        }
                    }
                },
                {
                    _links: {
                        people: {
                            href: "http://localhost:8080/persons"
                        },
                        self: {
                            href: "http://localhost:8080/persons/3"
                        }
                    }
                }
            ]
        },
        _links: {
            self: {
                href: "http://localhost:8080/persons"
            }
        }
    }

http://localhost:8080/persons/1

的输出
    {
        _links: {
            people: {
                href: "http://localhost:8080/persons"
            },
            self: {
                href: "http://localhost:8080/persons/1"
            }
        }
    }

2 个答案:

答案 0 :(得分:1)

在PersonResource中为person添加一个getter:

<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/tether/1.4.0/js/tether.min.js" ></script>
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0-alpha.6/js/bootstrap.min.js"></script>
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0-alpha.6/css/bootstrap.min.css">
<div class="container">
<div class="">
    <div class="float-left">div 1</div>
    <div class="float-right">div end</div>
</div>
</div>

使用getter,Spring会获取PersonResource中包含的人并对其进行序列化:

获取http://localhost:8080/persons/1

public class PersonResource extends ResourceSupport {

  private final Person person;

  public PersonResource(final Person person) {
    this.person = person;
    final long id = person.getId();
    add(linkTo(PersonController.class).withRel("people"));
    add(linkTo(methodOn(PersonController.class).get(id)).withSelfRel());
  }

    public Person getPerson() {
        return person;
    }
}

获取http://localhost:8080/persons

{
  "person" : {
    "id" : 1,
    "firstName" : "Donald",
    "secondName" : "Duck"
  },
  "_links" : {
    "people" : {
      "href" : "http://localhost:8080/persons"
    },
    "self" : {
      "href" : "http://localhost:8080/persons/1"
    }
  }
}

注意:我是一个懒惰的流浪汉,我将spring-boot-starter-data-rest添加到pom.xml依赖项中以便打印结果,因此您的实际结果可能会有所不同。

答案 1 :(得分:1)

我建议您使用资源而不是 ResourceSupport 的扩展,为您的案例采用非常少侵入性的方法。你的代码看起来像这样:

@RestController
@RequestMapping(value = "/persons", produces = "application/hal+json")
public class PersonController {

  @GetMapping
  public ResponseEntity<List<Resource<Person>>> all() {
    final List<Resource<Person>> collection =
        getPersonList().stream()
                .map(p -> new Resource<>(p, this.getLinks(p.getId())))
                .collect(Collectors.toList());
    return ResponseEntity.ok(collection);
  }

  @GetMapping("/{id}")
  public ResponseEntity<Resource<Person>> get(@PathVariable final long id) {
    Person p = new Person(id,"Donald","Duck");
    Resource<Person> resource = new Resource<>(p, this.getLinks(id));
    return ResponseEntity.ok(resource);
  }

  private List<Person> getPersonList() {
    List<Person> personList = new LinkedList<>();
    personList.add(new Person((long)1,"Donald","Duck"));
    personList.add(new Person((long)2,"Dagobert","Duck"));
    personList.add(new Person((long)3,"Daniel","Duesentrieb"));
    return personList;
  }

  private List<Link> getLinks(long id) {
      return Arrays.asList(
              linkTo(PersonController.class).withRel("people"),
              linkTo(methodOn(getClass()).get(id)).withSelfRel());
  }
}

输出更清晰:

获取http://localhost:8080/persons/1

{
   "id": 1,
   "firstName": "Donald",
   "secondName": "Duck",
   "_links":    {
      "people": {"href": "http://localhost:8080/persons"},
      "self": {"href": "http://localhost:8080/persons/1"}
   }
}

获取http://localhost:8080/persons

[
   {
      "id": 1,
      "firstName": "Donald",
      "secondName": "Duck",
      "_links":       {
         "people": {"href": "http://localhost:8080/persons"},
         "self": {"href": "http://localhost:8080/persons/1"}
      }
   },
   {
      "id": 2,
      "firstName": "Dagobert",
      "secondName": "Duck",
      "_links":       {
         "people": {"href": "http://localhost:8080/persons"},
         "self": {"href": "http://localhost:8080/persons/2"}
      }
   },
   {
      "id": 3,
      "firstName": "Daniel",
      "secondName": "Duesentrieb",
      "_links":       {
         "people": {"href": "http://localhost:8080/persons"},
         "self": {"href": "http://localhost:8080/persons/3"}
      }
   }
]

只是另一种观点,希望这会有所帮助。