使用 Spring Boot 的 RESTful API 中的循环依赖
Posted
技术标签:
【中文标题】使用 Spring Boot 的 RESTful API 中的循环依赖【英文标题】:Circular Dependencies in RESTful API with Spring Boot 【发布时间】:2017-10-25 10:44:57 【问题描述】:我正在使用 Spring Boot、JPA 和 Hibernate 以及 Maven 作为存储库管理器开发一个 Rest API。在我的模型中,我有课程Club
:
@Entity
@Table( name = "CLUB")
public class Club
/**
* Id da entidade
*/
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
/**
* Atual técnico do clube.
*/
@OneToOne(mappedBy = "actualClub")
private Coach coach;
//Outros atributos, getters e setters
上述类与Coach
类有@OneToOne
关系:
@Entity
@Table(name = "COACH")
public class Coach extends Person
/**
* Clube atual do técnico.
*/
@OneToOne
@JoinColumn(name = "CLUB_ID")
private Club actualClub;
//Outros atributos, getters e setters
Person
类还有一个属性 id,带有 @Id
和 @GeneratedValue
注释。
最后,我还有控制器类ClubController
,它处理一些请求,如下所示:
@RestController
public class ClubController
/**
* Instância da classe de serviços da entidade <i>Club</i>
*/
@Autowired
private ClubService clubService;
/**
* Retorna JSON que representa o clube com o 'id' especificado.
*
* @param id Identificador do clube a ser buscado.
* @return ResponseEntity Objeto com detalhes da requisição HTTP, como o Status.
*/
@RequestMapping(value = "/clubs/id", produces = MediaType.APPLICATION_JSON_VALUE,
method = RequestMethod.GET)
public ResponseEntity<?> getClubById(@PathVariable Long id)
final Club club = this.clubService.findById(id);
if (club != null)
return new ResponseEntity<>(club, HttpStatus.FOUND);
else
return new ResponseEntity<>("Não encontrado", HttpStatus.NOT_FOUND);
/*Entre outros métodos...*/
问题是:在/clubs/id
中的GET
中,返回的JSON 内部有一个循环(无限)依赖关系。俱乐部有一个教练,教练也有一个俱乐部,所以它去...... X(
@OneToMany relationship between
Cluband
Player`也会发生这种情况...
我找到了这个解决方案:Link。我只需要在类声明中使用@JsonIdentityInfo
注释。这个解决方案的问题是我不会使用的信息开销(想想@OneToMany
与Player
的关系)。此外,正如您在上面的链接中看到的那样:
“但是,JSON id 引用需要在整个图表中是唯一的,而 JPA id 只需要在同一实体中是唯一的。””
所以,我必须将 UUID 用于 JPA id 字段。
我还找到了另一种可能的解决方案:Spring HATEOAS。在这种情况下,我可以将链接(href)添加到某些属性,然后将申请“按需”。但似乎 Spring HATEOAS 有一些限制,比如支持嵌入资源......
那么,我应该采用哪种方法?还有其他解决方案吗?
很快,我打算在 ios 应用程序中使用这个 API(我不知道它是否有区别)。
对不起,我的英语很差...来自巴西的问候 x)
【问题讨论】:
第二种方法看起来像 Spotify Web API link 。每张专辑都有指向其曲目的 href 链接。 只是为了这个案子,这与我有关:Why I Hate HATEOAS 要解决循环引用,你应该打破两个对象的链接。你可以看到注释JsonManagedReference和JsonBackReference。 【参考方案1】:这个问题可以通过创建你自己的 DTO (https://en.wikipedia.org/wiki/Data_transfer_object)来解决
数据传输对象 (DTO) 是一种 Java 结构,其创建只是为了组织数据以传输到另一个系统。它是根据需要创建的,没有无关或私人信息,也没有循环引用。
例如:
private Map<String, Object> makeClubDTO(Club club)
Map<String, Object> dto = new LinkedHashMap<String, Object>();
dto.put("id", club.getId());
dto.put("coach", club.getCoach().getId());
return dto;
【讨论】:
它对我有用。这听起来是个好主意。仅供参考:Entity To DTO Conversion for a Spring REST API.【参考方案2】:用@JsonIgnoreProperties
注释这两个关系
如下
// Employee entity, owning side of relationship
@ManyToOne(cascade = CascadeType.ALL)
@JsonIgnoreProperties("employee")
private Department department;
// Department side, inverse side of relationship
@OneToMany(mappedBy = "department")
@JsonIgnoreProperties("department")
private Collection<Employee> employee;
【讨论】:
以上是关于使用 Spring Boot 的 RESTful API 中的循环依赖的主要内容,如果未能解决你的问题,请参考以下文章
无法使用 Spring Boot App 访问 RESTful 服务
Spring Boot + Spring Security Restful 登录
spring boot:使接口返回统一的RESTful格式数据(spring boot 2.3.1)
spring boot使用TestRestTemplate集成测试 RESTful 接口