请对我有耐心。我尽了最大的努力用简单的代码来解释。
两个实体:Shop
和Product
。
一个Shop
可以有多个Product
。
我返回一个Shop对象,它会像这样打印-
{
"shopId": 1,
"shopName": "S1",
"productList": [
{
"productId": 100,
"productName": "MOBILE",
"shop": {
"shopId": 1,
"shopName": "S1",
"productList": [
{
"productId": 100,
"productName": "MOBILE",
"shop": {
在我开始实际的问题之前,我确实部分解决了循环问题**,但又遇到了一个新的问题**。我在@JsonIgnore
的帮助下阻止了它
基本上,当我打印我的父(Shop
)json对象时,我通过在子(Product
)类字段中使用@JsonIgnore
来停止循环响应。
@JsonIgnore
private Shop shop
因此,现在API 1=
@GetMapping("/getShopById")
public Shop getShopById(){
return shopRepo.findById(1L).get();
}
给我输出-(这是完美的,因为我避免打印Shop
回来);
{
"shopId": 1,
"shopName": "S1",
"productList": [
{
"productId": 100,
"productName": "MOBILE"
},
{
"productId": 101,
"productName": "EARPHONE"
}
]
}
但是现在每当我想从Product
对象中获取Shop
并发送响应时,我都会得到一个错误,我猜这是因为@JsonIgnore
,它基本上完全停止了Product
对象中字段的序列化。
API 2=
@GetMapping("/getShopFromTheProductId")
public Shop getShopFromProductId() {
Shop s = productRepo.findById(100L).get().getShop();
return s;
}
给我错误-
com.fasterxml.jackson.databind.exc.InvalidDefinitionException: No serializer found for class org.hibernate.proxy.pojo.bytebuddy.ByteBuddyInterceptor and no properties discovered to create BeanSerializer (to avoid exception, disable SerializationFeature.FAIL_ON_EMPTY_BEANS) (through reference chain: com.doubt.StackOverFlow.Shop$HibernateProxy$YEW0qvzw["hibernateLazyInitializer"])
at com.fasterxml.jackson.databind.exc.InvalidDefinitionException.from(InvalidDefinitionException.java:77) ~[jackson-databind-2.12.3.jar:2.12.3]
at com.fasterxml.jackson.databind.SerializerProvider.reportBadDefinition(SerializerProvider.java:1276) ~[jackson-databind-2.12.3.jar:2.12.3]
at com.fasterxml.jackson.databind.DatabindContext.reportBadDefinition(DatabindContext.java:400) ~[jackson-databind-2.12.3.jar:2.12.3]
at com.fasterxml.jackson.databind.ser.impl.UnknownSerializer.failForEmpty
因此,总结一下,我如何忽略打印/从Child返回Parent,直到并且除非我明确要求它?
可能的解决方案1 -从Product
实体中删除Shop
(private Shop getShop()
)的getter。但这对我来说不是一个解决方案,因为当我在业务逻辑中需要它时,我将永远无法追溯到父母。
我的课-
控制器-
@RestController
public class MainController {
@Autowired
private ShopRepo shopRepo;
@Autowired
private ProductRepo productRepo;
@GetMapping("/getShopById")
public Shop getShopById(){
return shopRepo.findById(1L).get();
}
@GetMapping("/getShopFromTheProductId")
public Shop getShopFromProductId() {
Shop s = productRepo.findById(100L).get().getShop();
return s;
}
}
店铺实体-
@Entity
@Table(name = "SHOP")
public class Shop {
@Id
@Column(name = "SHOP_ID")
private Long shopId;
@Column(name = "SHOP_NAME")
private String shopName;
@OneToMany(fetch = FetchType.LAZY,targetEntity = Product.class, mappedBy = "shop")
private List<Product> productList;
........
all the getters and setters
产品实体-
@Entity
@Table(name = "PRODUCT")
public class Product {
@Id
@Column(name = "PRODUCT_ID")
private Long productId;
@Column(name = "PRODUCT_NAME")
private String productName;
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "SHOP_ID")
@JsonIgnore
private Shop shop;
........
all getters and setters
2条答案
按热度按时间ltqd579y1#
所以我已经接受了这个问题。首先,直接发送域对象作为响应是错误的。不是最好的做法。最好的做法是有一个
RequestShopDTO
对象和类似的ResponseShopDTO
。我们应该让DTO具有与域对象相同的getter和setter,在本例中为Shop
。RequestShopDTO
对象。1.使用工厂类/适配器类将
RequestShopDTO
转换为ShopDomain对象并将其转发到业务层。1.类似地,我们应该将Response Shop域对象转换为
ResponseShopDTO
对象并将其作为响应发送。1.我们应该有一个类似BaseRequest的类,扩展为类似于RequestRequest,UpdateRequest,GetRequest等。其中所有get请求的公共属性都在GetRequest中,然后由更具体的请求类(如RequestShopDTO)扩展。
1.类似地,我们可以有一个抽象的Adapter类,比如这个RequestDtoToDomainBaseAdapter,它可以被类似ShopDtoShopDomainAdapter的东西扩展。
参考- inor的答案-Design Pattern to model Request and Response Objects for Webservices P.S. - DTO -数据传输对象
toiithl62#
以避免循环问题。使用
@JsonManagedReference
和@JsonBackReference
如下。在Parent类上添加
@JsonManagedReference
,商店实体。在Child类上添加
@JsonBackReference
,如下所示。