为什么我的数组从Spring展平到Angular?

时间:2018-09-25 21:32:10

标签: spring angular

在Spring JPA方面,在我的控制器中,我有:

@GetMapping()
public List<Product> getProducts() {
    List<Product> products = repository.findAll();
    int a = 1;
    return products;
}

在Angular(6)服务中,我有:

getAll(): Observable<Product[]> {
    return this.http.get<Product[]>(this.PRODUCT_API);
}

在Angular组件中,我有:

products: Product[] = [];

ngOnInit() {
    this.productService.getAll().subscribe((data: Product[]) => {
        console.log(data);
        this.products = data;
    });
}

在列表组件HTML中,数据库的4个产品中,第一个产品的属性正确发出,但其他3个字段中没有任何内容。

在浏览器的控制台中,我看到以下内容:

Array(4) [ {…}, 2, 3, 4 ] product-list.component.ts:19:6

我可以在Spring控制器中运行的代码中的虚假赋值上放置一个断点,并看到我正在按预期返回Product数组。但是,当它离开Spring并到达Angular时,该数组已变平为一个对象(第一个乘积)和3个数字。

一切似乎都正确键入。我不知道应该怎么做才能正确返回我的Product类型的数组。


根据从API端显示JSON的请求,我终于弄清楚了如何进行一些基本日志记录,并转储了产品列表。现在我更加困惑了。果然,Angular端正在准确显示它收到的内容:

[ {
  "id" : 1,
  "title" : "New Friggin Product",
  "note" : "This is a note",
  "createDateTime" : {
    "month" : "AUGUST",
    "year" : 2018,
    "dayOfMonth" : 20,
    "dayOfWeek" : "MONDAY",
    "dayOfYear" : 232,
... <SNIP>
        "second" : 59,
        "monthValue" : 8,
        "chronology" : {
          "id" : "ISO",
          "calendarType" : "iso8601"
        }
      },
      "engine" : 1
    } ]
  }
}, 2, 3, 4 ]

JSON中有一个产品数组,然后是3个数字。

双重编辑!我已经列出了存储库代码,但是经过进一步的思考,repo类是正确的。它会在响应中返回4种正确的产品。

Correct response before returning to Angular

问题是转换为JSON,当我将响应返回到Angular时,我想我已经完全记录了Jackson库对List所做的事情。问题是,为什么在正确键入所有内容后。

1 个答案:

答案 0 :(得分:0)

结果证明这是一个已知问题。 Jackson中的JSON渲染器在对象列表中未包含对重复的子对象的引用。出于某些奇怪的原因,这是设计使然。

要解决此问题,您需要在Spring端使用JSOG(https://github.com/jsog/jsog)在Angular端使用JSOG-Typescript(https://github.com/emundo/jsog-typescript)生成JSON响应。

请注意,您仍然需要@JsonBackReference@JsonManagedReferences来防止无限递归循环。

我的期末课程如下:

Engine.java(父级)

@Entity
@Getter @Setter
@NoArgsConstructor
@ToString @EqualsAndHashCode
@JsonIdentityInfo(generator = JSOGGenerator.class)
public class Engine implements Serializable { //

    @Id
    @GeneratedValue(strategy=IDENTITY)
    private Long id;

    @NonNull
    private String name;

    private String family;

    @CreationTimestamp
    private LocalDateTime createDateTime;

    @UpdateTimestamp
    private LocalDateTime updateDateTime;

    @OneToMany(fetch = FetchType.EAGER, mappedBy = "engine")
    @JsonBackReference
    private Collection<Product> products;

}

Product.java(子级)

@Entity
@Getter @Setter
@NoArgsConstructor
@ToString @EqualsAndHashCode
@JsonIdentityInfo(generator = JSOGGenerator.class)
public class Product implements Serializable { //

    @Id
    @GeneratedValue(strategy=IDENTITY)
    private Long id;

    @NonNull
    private String title;

    private String note;

    @CreationTimestamp
    private LocalDateTime createDateTime;

    @UpdateTimestamp
    private LocalDateTime updateDateTime;

    @ManyToOne(fetch = FetchType.EAGER, cascade = CascadeType.ALL)
    @JoinColumn(name = "engine_id")
    @JsonManagedReference
    private Engine engine;

}

product-list.component.ts

import { Component, OnInit } from '@angular/core';
import { ProductService } from '../shared/product/product.service';
import { Product } from '../shared/models/product';
import { JsogService } from 'jsog-typescript';

@Component({
  selector: 'app-product-list',
  templateUrl: './product-list.component.html',
  styleUrls: ['./product-list.component.css']
})

export class ProductListComponent implements OnInit {
  products: Product[] = [];

  constructor(private productService: ProductService) { }

  ngOnInit() {
    this.productService.getAll().subscribe(data => {
      const jsog = new JsogService();
      this.products = jsog.deserializeArray(data, Product);
    });
  }

}

此外,要完成上述工作,我必须在Angular组件中返回联合国类型的.getAll():

getAll(): Observable<any> {
    return this.http.get(this.PRODUCT_API);
}