我尝试用 java - hibernate - spring 实现服务器 REST,它返回一个 json。
我映射了多对多关系。
我解释得更好,我有一个有配料清单的供应商,每种配料都有一个供应商清单。
我创建了表:
CREATE TABLE supplier_ingredient (
supplier_id BIGINT,
ingredient_id BIGINT
)
ALTER TABLE supplier_ingredient ADD CONSTRAINT supplier_ingredient_pkey
PRIMARY KEY(supplier_id, ingredient_id);
ALTER TABLE supplier_ingredient ADD CONSTRAINT
fk_supplier_ingredient_ingredient_id FOREIGN KEY (ingredient_id)
REFERENCES ingredient(id);
ALTER TABLE supplier_ingredient ADD CONSTRAINT
fk_supplier_ingredient_supplier_id FOREIGN KEY (supplier_id) REFERENCES
supplier(id);
然后我有 成分 模型:
.....
.....
@ManyToMany(mappedBy = "ingredients")
@OrderBy("created DESC")
@BatchSize(size = 1000)
private List<Supplier> suppliers = new ArrayList<>();
....
....
然后我有 供应商 模型:
....
@ManyToMany
@JoinTable( name = "supplier_ingredient ",
joinColumns = @JoinColumn(name = "supplier_id", referencedColumnName = "id"),
inverseJoinColumns = @JoinColumn(name = "ingredient_id", referencedColumnName = "id"),
foreignKey = @ForeignKey(name = "fk_supplier_ingredient_supplier_id"))
@OrderBy("created DESC")
@Cascade(CascadeType.SAVE_UPDATE)
@BatchSize(size = 1000)
private List<Ingredient> ingredients = new ArrayList<>();
....
端点:
@RequestMapping(value = "/{supplierId:[0-9]+}", method = RequestMethod.GET)
@ResponseStatus(value = HttpStatus.OK)
@ResponseBody
public SupplierObject get(@PathVariable Long supplierId) {
Supplier supplier = supplierService.get(supplierId);
SupplierObject supplierObject = new SupplierObject (supplier);
return SupplierObject;
}
服务
....
public Supplier get(Long supplierId) {
Supplier supplier = supplierDao.getById(supplierId); (it does entityManager.find(entityClass, id))
if (supplier == null) throw new ResourceNotFound("supplier", supplierId);
return supplier;
}
....
供应商对象
@JsonIgnoreProperties(ignoreUnknown = true)
public class SupplierObject extends IdAbstractObject {
public String email;
public String phoneNumber;
public String address;
public String responsible;
public String companyName;
public String vat;
public List<Ingredient> ingredients = new ArrayList<>();
public SupplierObject () {
}
public SupplierObject (Supplier supplier) {
id = supplier.getId();
email = supplier.getEmail();
responsible = supplier.getResponsible();
companyName = supplier.getCompanyName();
phoneNumber = supplier.getPhone_number();
ingredients = supplier.getIngredients();
vat = supplier.getVat();
address = supplier.getAddress();
}
}
和 IdAbstractObject
public abstract class IdAbstractObject{
public Long id;
}
我的问题是,当我调用端点时:
http://localhost:8080/supplier/1
我收到一个错误:
“无法写入 JSON:无法延迟初始化角色集合:myPackage.ingredient.Ingredient.suppliers,无法初始化代理 - 无会话;嵌套异常是 com.fasterxml.jackson.databind.JsonMappingException:无法延迟初始化集合角色:myPackage.ingredient.Ingredient.suppliers,无法初始化代理 - 无会话(通过引用链:myPackage.supplier.SupplierObject[\“ingredients\”]->org.hibernate.collection.internal.PersistentBag[0]- >myPackage.ingredient.Ingredient[\“供应商\”])”
我跟着这个:
现在我没有错误,但在返回的 json 中,成分字段为空:
{
"id": 1,
"email": "mail@gmail.com",
"phoneNumber": null,
"address": null,
"responsible": null,
"companyName": "Company name",
"vat": "vat number",
"ingredients": null
}
但在调试中我可以看到成分….
原文由 Gjord83 发布,翻译遵循 CC BY-SA 4.0 许可协议
这是 Hibernate 和 Jackson Marshaller 的正常行为 基本上您需要以下内容:一个包含所有 Supplier 对象详细信息的 JSON…包括成分。
请注意,在这种情况下,您必须非常小心,因为当您尝试创建 JSON 本身时可能会有循环引用,因此您还应该使用
JsonIgnore
注释您必须做的第一件事是加载供应商及其所有详细信息(包括成分)。
你怎么能这样做?通过使用多种策略…让我们使用
Hibernate.initialize
。这 必须在 DAO(或存储库)实现(基本上是您使用休眠会话的地方)中的休眠会话关闭之前 使用。所以在这种情况下(我假设使用 Hibernate)在我的存储库类中我应该写这样的东西:
现在你有了
Supplier
对象及其所有详细信息(Ingredients
也)现在在你的服务中你可以做你所做的是:通过这种方式,Jackson 能够编写 JSON
but
让我们看看Ingredient
对象。它具有以下属性:当 Jackson 尝试创建 JSON 时会发生什么?它将访问
List<Ingredient>
中的每个元素,它也会尝试为这个元素创建一个 JSON……也为供应商列表创建一个 JSON,这是一个循环引用……所以你必须避免它,您可以使用 JsonIgnore 注释来避免它。例如,您可以这样编写Ingredient
实体类:这样你:
无论如何,我建议您创建特定的 DTO(或 VO)对象以用于编组和解组 JSON
我希望这是有用的
安吉洛