Spring 启动 HATEOAS 输出失败
Spring Boot HATEOAS Output Fails
我的实体在 Sprint Boot REST HATEOAS 服务中的输出不起作用。服务 returns 每个实体的空字符串。没有错误消息。我试过 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);
}
}
个人控制器
@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;
}
}
人物资源
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...
}
的输出
{
_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"
}
}
}
为 PersonResource 中的人员添加 getter:
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;
}
}
使用 getter,Spring 将 person 包裹在您的 PersonResource 中并将其序列化:
获取http://localhost:8080/persons/1
{
"person" : {
"id" : 1,
"firstName" : "Donald",
"secondName" : "Duck"
},
"_links" : {
"people" : {
"href" : "http://localhost:8080/persons"
},
"self" : {
"href" : "http://localhost:8080/persons/1"
}
}
}
获取http://localhost:8080/persons
{
"_embedded" : {
"personResources" : [ {
"person" : {
"id" : 1,
"firstName" : "Donald",
"secondName" : "Duck"
},
"_links" : {
"people" : {
"href" : "http://localhost:8080/persons"
},
"self" : {
"href" : "http://localhost:8080/persons/1"
}
}
}, {
"person" : {
"id" : 2,
"firstName" : "Dagobert",
"secondName" : "Duck"
},
"_links" : {
"people" : {
"href" : "http://localhost:8080/persons"
},
"self" : {
"href" : "http://localhost:8080/persons/2"
}
}
}, {
"person" : {
"id" : 3,
"firstName" : "Daniel",
"secondName" : "Duesentrieb"
},
"_links" : {
"people" : {
"href" : "http://localhost:8080/persons"
},
"self" : {
"href" : "http://localhost:8080/persons/3"
}
}
} ]
},
"_links" : {
"self" : {
"href" : "http://localhost:8080/persons"
}
}
}
注意:我是个懒惰的流浪汉,我在 pom.xml 依赖项中添加了 spring-boot-starter-data-rest 以漂亮地打印结果,因此您的实际结果可能会有所不同。
我建议您使用 Resource 而不是 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"}
}
}
]
换个角度,希望对你有帮助。
我的实体在 Sprint Boot REST HATEOAS 服务中的输出不起作用。服务 returns 每个实体的空字符串。没有错误消息。我试过 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);
}
}
个人控制器
@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;
}
}
人物资源
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...
}
的输出
{
_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"
}
}
}
为 PersonResource 中的人员添加 getter:
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;
}
}
使用 getter,Spring 将 person 包裹在您的 PersonResource 中并将其序列化:
获取http://localhost:8080/persons/1
{
"person" : {
"id" : 1,
"firstName" : "Donald",
"secondName" : "Duck"
},
"_links" : {
"people" : {
"href" : "http://localhost:8080/persons"
},
"self" : {
"href" : "http://localhost:8080/persons/1"
}
}
}
获取http://localhost:8080/persons
{
"_embedded" : {
"personResources" : [ {
"person" : {
"id" : 1,
"firstName" : "Donald",
"secondName" : "Duck"
},
"_links" : {
"people" : {
"href" : "http://localhost:8080/persons"
},
"self" : {
"href" : "http://localhost:8080/persons/1"
}
}
}, {
"person" : {
"id" : 2,
"firstName" : "Dagobert",
"secondName" : "Duck"
},
"_links" : {
"people" : {
"href" : "http://localhost:8080/persons"
},
"self" : {
"href" : "http://localhost:8080/persons/2"
}
}
}, {
"person" : {
"id" : 3,
"firstName" : "Daniel",
"secondName" : "Duesentrieb"
},
"_links" : {
"people" : {
"href" : "http://localhost:8080/persons"
},
"self" : {
"href" : "http://localhost:8080/persons/3"
}
}
} ]
},
"_links" : {
"self" : {
"href" : "http://localhost:8080/persons"
}
}
}
注意:我是个懒惰的流浪汉,我在 pom.xml 依赖项中添加了 spring-boot-starter-data-rest 以漂亮地打印结果,因此您的实际结果可能会有所不同。
我建议您使用 Resource 而不是 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"}
}
}
]
换个角度,希望对你有帮助。