java – 混合Spring MVC Spring數據休息致使奇怪的MVC響應

我有兩個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).

相關文章
相關標籤/搜索