我正在使用配置了@EnableHypermediaSupport(type = HAL)的Spring Boot和Spring Hateoas.虽然这在基本场景中运行良好,但我希望能够为链接添加其他属性.例如,很容易返回链接,这些链接将呈现如下链接:
{
"_links":{
"self":{
"href":"http://localhost/"
},
"something":[
{
"href":"http://some-url.com/something1"
},
{
"href":"http://some-url.com/something2"
}
]
}
Run Code Online (Sandbox Code Playgroud)
我想要做的是为rel中的对象添加更多属性.例如:
{
"_links":{
"self":{
"href":"http://localhost/"
},
"something":[
{
"name":"something1",
"href":"http://some-url.com/something1"
},
{
"name":"something2",
"href":"http://some-url.com/something2"
}
]
}
}
Run Code Online (Sandbox Code Playgroud)
在不创建自己的DTO的情况下,最好的方法是什么(最好使用ControllerLinkBuilder)?我已经尝试创建自己的Link子类并为name(以及getter和setter)添加字段,但它们似乎被忽略了.
我的控制器中有以下内容:
@RequestMapping
@ResponseBody
public HttpEntity<PagedResources<PromotionResource>> promotions(
@PageableDefault(size = RestAPIConfig.DEFAULT_PAGE_SIZE, page = 0) Pageable pageable,
PagedResourcesAssembler<Promotion> assembler
){
PagedResources<PromotionResource> r = assembler.toResource(this.promoService.find(pageable), this.promoAssembler);
return new ResponseEntity<PagedResources<PromotionResource>>(r, HttpStatus.OK);
}
Run Code Online (Sandbox Code Playgroud)
如果我导航到映射到该控制器方法的URL,则会收到500错误,其根本原因是:
com.sun.istack.internal.SAXException2: unable to marshal type "commerce.api.rest.resources.PromotionResource " as an element because it is missing an @XmlRootElement annotation
Run Code Online (Sandbox Code Playgroud)
如果我在资源上抛出@XmlRootElement批注,则会出现此错误:
com.sun.istack.internal.SAXException2: unable to marshal type "commerce.api.rest.resources.PromotionResource " as an element because it is not known to this context.
Run Code Online (Sandbox Code Playgroud)
如果accept标头是application / json或application / hal + json,那么一切都很好。仅当客户端(在本例中为chrome)正在寻找application / xml时才引起问题(这在HATEOAS遵循客户端请求时才有意义。我使用的是Spring Boot的@EnableAutoConfiguration,它将XML消息转换器添加到列表中从而启用XML内容类型。
我猜我至少有2个选择:1.修复jaxb错误2.删除xml作为受支持的内容类型
不知道该怎么做,或者还有另一种选择。
我有一个用Spring构建的简单HATEOAS提供程序,它为我提供以下资源:
{
"_links" : {
"self" : {
"href" : "http://localhost:8080/employees{?page,size,sort}",
"templated" : true
},
"search" : {
"href" : "http://localhost:8080/employees/search"
}
},
"_embedded" : {
"employees" : [ {
"id" : "5400d5152f5243f1988c649b",
"name" : "Some Employee",
"location" : [ 0.0, 0.0 ],
"_links" : {
"self" : {
"href" : "http://localhost:8080/employees/5400d5152f5243f1988c649b"
}
}
}, {
"id" : "5400d5162f5243f1988c649c",
"name" : "Some Employee",
"location" : [ 0.0, 0.0 ],
"_links" : {
"self" : {
"href" …Run Code Online (Sandbox Code Playgroud) 我试过了:
@BeforeClass
public static void setUpClass() {
CurieProvider curieProvider = new DefaultCurieProvider("a", new UriTemplate("a{yey}"));
RelProvider relProvider = new DefaultRelProvider();
ObjectMapper halObjectMapper = JsonUtils.mapper;
halObjectMapper.registerModule(new Jackson2HalModule());
halObjectMapper.setHandlerInstantiator(new Jackson2HalModule.HalHandlerInstantiator(relProvider, curieProvider));
}
Run Code Online (Sandbox Code Playgroud)
但仍然出现错误:
03:26:25.936 [main] ERROR org.soluvas.json.JsonUtils - Cannot serialize id.co.bippo.product.rs.commerceplug.ProductOrServiceImpl as JSON
com.fasterxml.jackson.databind.JsonMappingException: Class org.springframework.hateoas.hal.Jackson2HalModule$HalLinkListSerializer has no default (no arg) constructor
at com.fasterxml.jackson.databind.SerializerProvider._createAndCacheUntypedSerializer(SerializerProvider.java:1042) ~[jackson-databind-2.4.3.jar:2.4.3]
at com.fasterxml.jackson.databind.SerializerProvider.findValueSerializer(SerializerProvider.java:445) ~[jackson-databind-2.4.3.jar:2.4.3]
at com.fasterxml.jackson.databind.SerializerProvider.findTypedValueSerializer(SerializerProvider.java:599) ~[jackson-databind-2.4.3.jar:2.4.3]
at com.fasterxml.jackson.databind.ser.DefaultSerializerProvider.serializeValue(DefaultSerializerProvider.java:92) ~[jackson-databind-2.4.3.jar:2.4.3]
at com.fasterxml.jackson.databind.ObjectWriter._configAndWriteValue(ObjectWriter.java:800) ~[jackson-databind-2.4.3.jar:2.4.3]
at com.fasterxml.jackson.databind.ObjectWriter.writeValueAsString(ObjectWriter.java:676) ~[jackson-databind-2.4.3.jar:2.4.3]
at org.soluvas.json.JsonUtils.asJson(JsonUtils.java:54) ~[classes/:na]
at id.co.bippo.product.rs.commerceplug.ProductOrServiceImplTest.productOrService(ProductOrServiceImplTest.java:41) [test-classes/:na]
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:1.8.0_20]
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) ~[na:1.8.0_20] …Run Code Online (Sandbox Code Playgroud) 我有一个 AWS Elastic Load Balancer,其中包含我的域的证书并终止SSL流量。该ELB有一个监听https端口,并转发为http给Zuul。
当我使用时Spring Boot HATEOAS,Zuul 将用正确的地址替换链接,http而不是https:
"_links": {
"self": {
"href": "http://my.domain.com:80/rest/foo/bar"
}
}
Run Code Online (Sandbox Code Playgroud)
但我想要的是:
"_links": {
"self": {
"href": "https://my.domain.com/rest/foo/bar"
}
}
Run Code Online (Sandbox Code Playgroud)
生成此响应的请求已完成 https
因为Zuul在 ELB 后面,我猜它不知道它应该通过 https 接收流量。
有没有办法告诉Zuul替换链接,https即使它通过 接收未加密的流量http?
我想另一种方法是使用自签名证书进行部署Zuul,https但如果可以的话,我宁愿避免这种复杂情况。
spring amazon-web-services spring-hateoas spring-cloud netflix-zuul
我正在使用spring-data-rest公开REST API。我的搜索方法之一返回实体列表。存储库和其余响应如下
List<Order> findByKeywordContaining(String keyword);
Run Code Online (Sandbox Code Playgroud)
搜索响应:
{
"_embedded":{
"orders":[
{
"keyword":"Iron mattress",
"name":"Hostel",
"_links":{
"self":{
"href":"http://localhost:8081/orders/2"
},
"order":{
"href":"http://localhost:8081/orders/2"
}
}
},
{
"keyword":"Iron",
"name":"Weat strong",
"_links":{
"self":{
"href":"http://localhost:8081/orders/40"
},
"order":{
"href":"http://localhost:8081/orders/40"
}
}
}
]
},
"_links":{
"self":{
"href":"http://localhost:8081/orders/search/findByKeywordContaining?keyword=iron"
}
}
}
Run Code Online (Sandbox Code Playgroud)
现在,我正在使用RestTemplate消耗此响应以在客户端进行处理,如下所示
List<Order> orders = restOperations.exchange(new URI(url), HttpMethod.GET, null, new ParameterizedTypeReference<Resource<List<Order>>>() {}).getBody().getContent();
Run Code Online (Sandbox Code Playgroud)
上面的代码对于响应中的单个对象可以正常工作,但是如果响应中包含多个对象,则上述代码可以正常工作。代码抛出以下错误
org.springframework.http.converter.HttpMessageNotReadableException: Could not read JSON: Unrecognized field "_embedded" (class org.springframework.hateoas.Resource), not marked as ignorable (3 known properties: , "links", "content", "page"])
at [Source: sun.net.www.protocol.http.HttpURLConnection$HttpInputStream@6a2bc870; line: …Run Code Online (Sandbox Code Playgroud) Spring HATEOAS 非常适合链接到同一应用程序中的另一个方法。例如:
Greeting greeting = new Greeting(String.format(TEMPLATE, name));
greeting.add(linkTo(methodOn(GreetingController.class).greeting(name)).withSelfRel());
Run Code Online (Sandbox Code Playgroud)
如果要实现微服务架构,那么大多数链接方法将是不同服务和不同 Java 项目的一部分。
我可以看到在现有项目之外添加指向方法的链接的唯一方法是在 URL 中进行硬编码(或将其放在外部配置中)。
有没有其他方法可以动态创建 URL?例如,是否可以将 Spring HATEOAS 与 Service Registry(如 Eureka)结合使用?
我有以下 REST 控制器。
@RepositoryRestController
@RequestMapping(value = "/booksCustom")
public class BooksController extends ResourceSupport {
@Autowired
public BooksService booksService;
@Autowired
private PagedResourcesAssembler<Books> booksAssembler;
@RequestMapping("/search")
public HttpEntity<PagedResources<Resource<Books>>> search(@RequestParam(value = "q", required = false) String query, @PageableDefault(page = 0, size = 20) Pageable pageable) {
pageable = new PageRequest(0, 20);
Page<Books> booksResult = BooksService.findBookText(query, pageable);
return new ResponseEntity<PagedResources<Resource<Books>>>(BooksAssembler.toResource(BooksResult), HttpStatus.OK);
}
Run Code Online (Sandbox Code Playgroud)
我Page<Books> BooksResult = BooksService.findBookText(query, pageable);的由SolrCrudRepository. 当它运行时BookResult有几个字段,内容字段和其他几个字段,一个是highlighted. 不幸的是,我从 REST 响应中得到的唯一content信息是字段中的数据和 HATEOAS 响应中的元数据信息(例如页面信息、链接等)。将highlighted字段添加到响应的正确方法是什么?我假设我需要修改ResponseEntity …
我想根据我的 API 动态生成 crud 表单。
我正在使用 spring、spring-data-rest 和 spring-hateoas。
我不想从 java 呈现反应。
我正在考虑调整/profile并添加一些元信息来呈现我的表单。
有没有人对我有实施建议?
我已经看到一些反应项目与我需要的客户端相似,但它不适用于 spring:
我正在构建一个基于Spring Data REST/Spring HATEOAS的应用程序,并且我正在尝试遵循此处(以及其他地方)概述的DDD原则:
特别是通过专用资源的聚合和复杂状态变化的概念.
还要避免将HTTP PATCH或PUT用于业务域的(复杂)状态转换,因为您错过了有关触发此更新的实际业务域事件的大量信息.例如,更改客户的邮件地址是对新"ChangeOfAddress"资源的POST,而不是具有不同邮件地址字段值的"Customer"资源的PATCH或PUT.
我正在努力的是一种强制执行此操作的方法,同时允许对聚合根进行外观修改.
使用这个简化的例子:
@Entity
public class Customer
{
private @Id @GeneratedValue(strategy = GenerationType.AUTO) Long id;
private String name;
private String comment;
@Access(AccessType.PROPERTY)
@OneToMany(cascade = CascadeType.ALL, orphanRemoval = true)
private Set<Address> addresses = new HashSet<>();
... getters and setters
public void addAddress(Address address)
{
addresses.add(address);
... custom code to raise events etc
}
}
public interface Customer extends CrudRepository<Customer, Long>
{
}
Run Code Online (Sandbox Code Playgroud)
允许更改化妆品(例如更新评论)但阻止直接更新子集合的更改的最佳/正确方法是什么?
如果尝试修改子集合,如果让setter抛出异常,我唯一能想到的就是这样做.
java spring domain-driven-design spring-data-rest spring-hateoas
spring-hateoas ×10
spring ×8
jackson ×2
java ×2
rest ×2
spring-data ×2
spring-mvc ×2
hal-json ×1
hateoas ×1
hypermedia ×1
json ×1
netflix-zuul ×1
reactjs ×1
spring-boot ×1
spring-cloud ×1