我有兩個JPA實體,一個具備SDR導出的存儲庫,另外一個具備Spring MVC控制器和一個未導出的存儲庫.html
MVC暴露實體引用了SDR管理實體.參見下面的代碼參考.spring
從UserController檢索用戶時,問題出現. SDR管理實體不會序列化,彷佛Spring可能正在嘗試在響應中使用HATEOAS參考.性能優化
如下是徹底填充用戶的GET以下所示:架構
{ "username": "foo@gmail.com", "enabled": true, "roles": [ { "role": "ROLE_USER", "content": [], "links": [] // why the content and links? } // no places? ] }
如何使用嵌入式SDR管理實體清楚地從Controller中返回User實體?併發
Spring MVC管理app
實體分佈式
@Entity @Table(name = "users") public class User implements Serializable { // UID @Id @GeneratedValue(strategy = GenerationType.IDENTITY) @JsonIgnore private Long id; @Column(unique = true) @NotNull private String username; @Column(name = "password_hash") @JsonIgnore @NotNull private String passwordHash; @NotNull private Boolean enabled; // No Repository @OneToMany(mappedBy = "user", cascade = CascadeType.ALL, orphanRemoval = true, fetch = FetchType.EAGER) @NotEmpty private Set<UserRole> roles = new HashSet<>(); // The SDR Managed Entity @ManyToMany(cascade = CascadeType.ALL, fetch = FetchType.EAGER) @JoinTable(name = "user_place", joinColumns = { @JoinColumn(name = "users_id") }, inverseJoinColumns = { @JoinColumn(name = "place_id")}) private Set<Place> places = new HashSet<>(); // getters and setters }
回購微服務
@RepositoryRestResource(exported = false) public interface UserRepository extends PagingAndSortingRepository<User, Long> { // Query Methods }
調節器高併發
@RestController public class UserController { // backed by UserRepository private final UserService userService; @Autowired public UserController(UserService userService) { this.userService = userService; } @RequestMapping(path = "/users/{username}", method = RequestMethod.GET) public User getUser(@PathVariable String username) { return userService.getByUsername(username); } @RequestMapping(path = "/users", method = RequestMethod.POST) public User createUser(@Valid @RequestBody UserCreateView user) { return userService.create(user); } // Other MVC Methods }
SDR管理源碼分析
實體
@Entity public class Place implements Serializable { // UID @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private long id; @NotBlank private String name; @Column(unique = true) private String handle; @OneToOne(cascade = CascadeType.ALL, orphanRemoval = true) @JoinColumn(name = "address_id") private Address address; @OneToOne(cascade = CascadeType.ALL, orphanRemoval = true) @JoinColumn(name = "contact_info_id") private ContactInfo contactInfo; // getters and setters }
回購
public interface PlaceRepository extends PagingAndSortingRepository<Place, Long> { // Query Methods }
簡而言之:Spring Data REST和Spring HATEOAS劫持ObjectMapper,並但願將資源之間的關係用做連接,而不是嵌入資源.
拿一個與另外一個實體有一一對應關係的實體:
@Entity public class Person { private String firstName; private String lastName; @OneToOne private Address address; }
SDR / HATEOAS將返回地址做爲連接:
{ "firstName": "Joe", "lastName": "Smith", "_links": { "self": { "href": "http://localhost:8080/persons/123123123" }, "address": { "href": "http://localhost:8080/addresses/9127391273" } } }
默認格式能夠根據您在類路徑上的具體狀況而有所不一樣.我相信這是個人例子中的HAL,這是你包括SDR和HATEOAS的默認值.根據所述配置可能不一樣但類似.
當地址由SDR管理時,Spring將會執行此操做.若是它不是由SDR管理的,那麼它將包含響應中的整個地址對象.我懷疑單獨解釋你所看到的行爲.
角色
您沒有包含關於UserRole的信息,可是根據您的代碼,它彷佛可能不在用戶管理以外,所以沒有註冊一個Spring數據存儲庫.若是是這種狀況,那就是爲何它被嵌入 – 沒有其餘的「連接」的存儲庫.
角色下的內容和連接看起來像Spring試圖將其序列化爲一個頁面.通常狀況下,內容將會有一系列的資源,連接將會有諸如「self」的連接或其餘資源的連接.我不知道是什麼緣由形成的.
地點
Place擁有本身的Spring Data存儲庫,所以它將被視爲一個被管理實體,而且被連接而不是嵌入.我懷疑你正在尋找的是一個投影.結賬春天 documentation on projections .它看起來像這樣:
在此我向你們推薦一個架構學習交流羣。交流學習羣號:821169538 裏面會分享一些資深架構師錄製的視頻錄像:有Spring,MyBatis,Netty源碼分析,高併發、高性能、分佈式、微服務架構的原理,JVM性能優化、分佈式架構等這些成爲架構師必備的知識體系。還能領取免費的學習資源,目前受益良多。
@Projection(name = "embedPlaces", types = { User.class }) interface EmbedPlaces { String getUsername(); boolean isEnabled(); Set<Place> getPlaces(); }
這應該是序列化用戶名,啓用和角色,並省略一切.我沒有親自使用預測,因此我不能保證它的工做效率,但這是文檔中的解決方案.
編輯:當咱們在此時,請注意,這也適用於建立或更新資源. Spring將資源做爲URL.所以,若是我正在建立一個新人,個人身體可能看起來像我的/地址示例:
{ "firstName": "New", "lastName": "Person", "address": "http://localhost:8080/addresses/1290312039123" }
很容易忘記這些東西,由於普遍,普遍,普遍,普遍,絕大多數的「REST」API不是REST,SDR / HATEOAS採起REST的觀點(例如,應該是REST).