Gjo*_*d83 4 java spring hibernate jackson spring-boot
我正在用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);
Run Code Online (Sandbox Code Playgroud)
然后我有成分模型:
.....
.....
@ManyToMany(mappedBy = "ingredients")
@OrderBy("created DESC")
@BatchSize(size = 1000)
private List<Supplier> suppliers = new ArrayList<>();
....
....
Run Code Online (Sandbox Code Playgroud)
然后我有供应商模型:
....
@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<>();
....
Run Code Online (Sandbox Code Playgroud)
终点:
@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;
}
Run Code Online (Sandbox Code Playgroud)
服务
....
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;
}
....
Run Code Online (Sandbox Code Playgroud)
SupplierObject
@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();
}
}
Run Code Online (Sandbox Code Playgroud)
和IdAbstractObject
public abstract class IdAbstractObject{
public Long id;
}
Run Code Online (Sandbox Code Playgroud)
我的问题是,当我调用端点时:
http://localhost:8080/supplier/1
Run Code Online (Sandbox Code Playgroud)
我收到一个错误:
“无法编写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中,Ingredients字段为null:
{
"id": 1,
"email": "mail@gmail.com",
"phoneNumber": null,
"address": null,
"responsible": null,
"companyName": "Company name",
"vat": "vat number",
"ingredients": null
}
Run Code Online (Sandbox Code Playgroud)
但是在调试中我可以看到成分。
这是Hibernate和Jackson Marshaller的正常行为基本上,您希望具有以下内容:具有所有Supplier对象详细信息的JSON ...包括成分。
请注意,在这种情况下,您必须非常小心,因为在尝试创建JSON本身时可以使用循环引用,因此也应使用JsonIgnore注释
您必须做的第一件事是加载供应商及其所有详细信息(包括成分)。
你怎么能这样做?通过使用几种策略...让我们使用Hibernate.initialize。这必须休眠会议闭幕之前使用的是在DAO(或仓库)实施(基本上,你使用Hibernate Session)。
因此,在这种情况下(我假设要使用Hibernate),我的存储库类中应编写如下内容:
public Supplier findByKey(Long id)
{
Supplier result = (Supplier) getSession().find(Supplier.class, id);
Hibernate.initialize(result.getIngredients());
return result;
}
Run Code Online (Sandbox Code Playgroud)
现在,您也拥有该Supplier对象及其所有详细信息。Ingredients现在,在服务中,您可以执行以下操作:
@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;
}
Run Code Online (Sandbox Code Playgroud)
通过这种方式,Jackson能够编写JSON,but让我们看一下该Ingredient对象。它具有以下属性:
@ManyToMany(mappedBy = "ingredients")
@OrderBy("created DESC")
@BatchSize(size = 1000)
private List<Supplier> suppliers = new ArrayList<>();
Run Code Online (Sandbox Code Playgroud)
当Jackson尝试创建JSON时会发生什么?它将访问内部的每个元素,List<Ingredient>并且还将尝试为此创建一个JSON。...也用于供应商列表,这是一个循环引用...因此您必须避免使用它,并且可以通过以下方法避免使用它使用JsonIgnore批注。例如,您可以Ingredient通过以下方式编写实体类:
@JsonIgnoreProperties(value= {"suppliers"})
public class Ingredient implements Serializable
{
......
}
Run Code Online (Sandbox Code Playgroud)
通过这种方式,您可以:
无论如何,我建议您创建特定的DTO(或VO)对象以用于编组和解组JSON。
我希望这是有用的
安杰洛
您有一些解决方案可以解决此问题:
@ManyToMany(fetch = FetchType.LAZY)但是从性能的角度来看,EAGER 获取非常糟糕。此外,一旦你有了一个 EAGER 协会,你就无法让它变得懒惰。
@ManyToMany @Fetch(FetchMode.JOIN)更多信息:https : //docs.jboss.org/hibernate/orm/3.2/api/org/hibernate/FetchMode.html
编辑:当您的application.properties文件中有以下行时,可能会发生这种情况:
spring.jpa.open-in-view = false
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
12648 次 |
| 最近记录: |