我有两个JPA实体,一个带有SDR导出存储库,另一个带有Spring MVC控制器和非导出存储库。
MVC公开实体具有对SDR管理实体的引用。代码参考见下文。
当从用户控制器中检索用户时,问题就出现了。SDR管理的实体不会序列化,而且Spring可能试图在响应中使用HATEOAS引用。
对于一个完全填充的用户,下面是一个如何获取的:
{
"username": "foo@gmail.com",
"enabled": true,
"roles": [
{
"role": "ROLE_USER",
"content": [],
"links": [] // why the content and links?
}
// no places?
]
}
如何清楚地从我的控制器返回带有嵌入式SDR托管实体的User
实体?
Spring MVC管理
实体
@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
}
您可以在控制器中很好地使用@响应实体,然后在响应实体中设置用户对象。
请看下面的例子:
ResponseEntity<User> respEntity = new ResponseEntity<User>(user, HttpStatus.OK);
然后在客户端,您可以调用restTemplate.getForEntity
请参阅下面的restTemplate文档:
http://docs.spring.io/spring/docs/current/javadoc-api/org/springframework/web/client/RestTemplate.html#getForObject-java。lang.String-java。lang.Class-java。lang.Object-
简而言之: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
的信息,但根据您的代码,它似乎不是在User
之外管理的,因此没有注册Spring Data存储库。如果是这种情况,这就是它被嵌入的原因——没有其他存储库可以“链接”到。
角色下的内容
和链接
看起来像Spring试图像Page
一样序列化它。通常内容
将有一个资源数组,链接
将有诸如“自己”或指向其他资源的链接。我不确定是什么导致的。
位置
Place有自己的Spring数据存储库,因此它将被视为一个托管实体,并链接到而不是嵌入。我怀疑你要找的是投影。检查有关投影的Spring文档。它看起来像这样:
@Projection(name = "embedPlaces", types = { User.class })
interface EmbedPlaces {
String getUsername();
boolean isEnabled();
Set<Place> getPlaces();
}
这应该序列化用户名、enabled和角色,并省略所有其他内容。我个人还没有使用过投影,所以我不能保证它的效果如何,但这是文档中的解决方案。
编辑:当我们在做时,请注意这也适用于创建或更新资源。Spring希望资源作为URL。因此,以人物/地址为例,如果我要创建一个新的人物,我的身体可能会像:
{
"firstName": "New",
"lastName": "Person",
"address": "http://localhost:8080/addresses/1290312039123"
}
很容易忘记这些事情,因为绝大多数的“REST”API都不是REST,SDR/HATEOAS对REST持固执己见的观点(例如,它应该是REST)。
我在Chrome Developer Tools中出现这个错误已经有一段时间了,我似乎就是找不到不安全的http://请求。它指向我的域,但没有https://。http://www.example.com/不是一个脚本,所以我不明白它是从哪里来的。 内容混杂:“HTTPS://www.example.com/categoy/a-product.html”页面是通过HTTPS加载的,但请求的脚本“
问题内容: 我有这段代码: 如您所见,我仅在columnRendered为true时才渲染该outputPanel。 好吧,在某些情况下(仅用于测试以批准其应做的事情): 为true,因此应在c:if中输入,并将columnRendered切换为false。但是事实并非如此,因此columnRendered永远是正确的… 你知道为什么吗? 问题答案: JSF和JSTL不会像您期望的那样同步运行。J
问题内容: 我想我发现了一个错误。也许不是,但是Super CSV不能很好地处理。 我正在使用MapReader解析具有41列的CSV文件。但是,我得到的是CSV- 而使我获得CSV的Web服务错了一行。“标题”行是制表符分隔的行,具有41个单元格。 而且“错误的行”是一个由制表符分隔的行,其中包含36个单元格,其内容没有任何意义。 这是我正在使用的代码: 我在上面提到的行中执行mapReader
当我的应用程序中的表单提交时,它将(在客户端)转换为超文本标记语言字符串,如下所示: 作为转换过程的一部分,每个字段值都被清理(通过Angular的服务)以删除任何
我正在Apache Camel中使用新的REST DSL,配置如下: getAllMessages方法返回一个没有任何JAXB注释的简单POJO集合。如果我将bindingMode设置为json,API/message可以正常工作,但API/handshake当然不行。 这样混合数据格式可能吗?我需要更改什么才能使它正常工作?
好的,最近我在寻找一种在PowerShell中实现空合并的方法,我遇到了这篇文章:在PowerShells中实现空聚合。 我看到了@Zenexer的评论,很感兴趣。语法如下: 这非常有效。然而,我的一位同事(沃尔特·帕克特)和我非常感兴趣,对语法做了更多的挖掘,发现了一些真正的奇怪之处。 在我进入怪异之前,任何人都可以指出任何解释这种语法的文档吗? 经验教训: < li >测试应该进入数组的最后一