我无法弄清楚如何做一些非常简单的事情。
我有两个实体:架子和书。书架可以有一本或多本书。这些实体中的每一个都使用Spring Data Rest将相应的JpaRepository公开为rest库。当我运行应用程序时,所有查询端点都能正常工作,但我无法弄清楚如何将书籍添加到书架上。
首先,我通过POST {" name":" westerns"}到/ shelf(正常工作)添加一个架子。
方法1:我尝试通过POST {" name":" mybook"}到/ shelf / 1 / books来添加一本书,但我获得405"方法不允许"错误。我是否只能将书籍发布到/ books端点(我的意思是不写自己的控制器)?如果是这样,我是否必须嵌入该书所属的货架实体?
方法2:如果我尝试使用内容{" name":" westerns"对PALL / 1进行PUT来添加一本书。 ," books":[{" name":" mybook"}]},我收到以下错误消息:
消息:"无法读取JSON:模板不能为空或空! (通过参考链:org.demo.Shelf [" books"]);嵌套异常是com.fasterxml.jackson.databind.JsonMappingException:模板不能为null或为空! (通过参考链:org.demo.Shelf [" books"])
statcktrace:
2014-11-06 06:55:18.864 ERROR 9888 --- [nio-8080-exec-5] s.d.r.w.AbstractRepositoryRestController:无法读取JSON: 模板不能为空或空! (通过参考文章: org.demo.Shelf ["书籍"]);嵌套异常是 com.fasterxml.jackson.databind.JsonMappingException:模板不能 是空的或空的! (通过参考链:org.demo.Shelf [" books"])
org.springframework.http.converter.HttpMessageNotReadableException: 无法读取JSON:模板不能为空或空! (通过 参考链:org.demo.Shelf [" books"]); nes ted例外是 com.fasterxml.jackson.databind.JsonMappingException:模板不能 是空的或空的! (通过参考链:org.demo.Shelf [" books"]) 在 org.springframework.http.converter.json.MappingJackson2HttpMessageConverter.readJavaType(MappingJackson2HttpMessageConverter.java:228) 在 org.springframework.http.converter.json.MappingJackson2HttpMessageConverter.readInternal(MappingJackson2HttpMessageConverter.java:212) 在 org.springframework.http.converter.AbstractHttpMessageConverter.read(AbstractHttpMessageConverter.java:159) 在 org.springframework.data.rest.webmvc.config.PersistentEntityResourceHandlerMethodArgumentResolver.resolveArgument(PersistentEntityResourceHandlerMethodArgumentResolver.java:100 ) 在 org.springframework.web.method.support.HandlerMethodArgumentResolverComposite.resolveArgument(HandlerMethodArgumentResolverComposite.java:79) 在 org.springframework.web.method.support.InvocableHandlerMethod.getMethodArgumentValues(InvocableHandlerMethod.java:157) 在 org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:124) 在 org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:104) 在 org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandleMethod(RequestMappingHandlerAdapter.java:749) 在 org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:689) 在 org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:83) 在 org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:938) 在 org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:870) 在 org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:961) 在 org.springframework.web.servlet.FrameworkServlet.doPut(FrameworkServlet.java:874) 在javax.servlet.http.HttpServlet.service(HttpServlet.java:649)at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:837) 在javax.servlet.http.HttpServlet.service(HttpServlet.java:727)at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:303) 在 org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:208) 在 org.springframework.web.filter.HiddenHttpMethodFilter.doFilterInternal(HiddenHttpMethodFilter.java:77) 在 org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107) 在 org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:241) 在 org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:208) 在 org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:220) 在 org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:122) 在 org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:501) 在 org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:171) 在 org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:103) 在 org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:116) 在 org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:408) 在 org.apache.coyote.http11.AbstractHttp11Processor.process(AbstractHttp11Processor.java:1070) 在 org.apache.coyote.AbstractProtocol $ AbstractConnectionHandler.process(AbstractProtocol.java:611) 在 org.apache.tomcat.util.net.NioEndpoint $ SocketProcessor.doRun(NioEndpoint.java:1736) 在 org.apache.tomcat.util.net.NioEndpoint $ SocketProcessor.run(NioEndpoint.java:1695) 在 java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1145) 在 java.util.concurrent.ThreadPoolExecutor中的$ Worker.run(ThreadPoolExecutor.java:615) 在 org.apache.tomcat.util.threads.TaskThread $ WrappingRunnable.run(TaskThread.java:61) 在java.lang.Thread.run(Thread.java:745)引起: com.fasterxml.jackson.databind.JsonMappingException:模板不能 是空的或空的! (通过参考链:org.demo.Shelf [" books"]) 在 com.fasterxml.jackson.databind.JsonMappingException.wrapWithPath(JsonMappingException.java:232) 在 com.fasterxml.jackson.databind.JsonMappingException.wrapWithPath(JsonMappingException.java:197) 在 com.fasterxml.jackson.databind.deser.BeanDeserializerBase.wrapAndThrow(BeanDeserializerBase.java:1420) 在 com.fasterxml.jackson.databind.deser.BeanDeserializer.vanillaDeserialize(BeanDeserializer.java:244) 在 com.fasterxml.jackson.databind.deser.BeanDeserializer.deserialize(BeanDeserializer.java:118) 在 com.fasterxml.jackson.databind.ObjectMapper._readMapAndClose(ObjectMapper.java:2993) 在 com.fasterxml.jackson.databind.ObjectMapper.readValue(ObjectMapper.java:2158) 在 org.springframework.http.converter.json.MappingJackson2HttpMessageConverter.readJavaType(MappingJackson2HttpMessageConverter.java:225) ...省略了38个常见帧引起的: java.lang.IllegalArgumentException:模板不能为null或 空!在org.springframework.util.Assert.hasText(Assert.java:162) 在 org.springframework.hateoas.UriTemplate。(UriTemplate.java:56) 在 org.springframework.data.rest.webmvc.json.PersistentEntityJackson2Module $ UriStringDeserializer.deserialize(PersistentEntityJackson2Module.java:380) 在 com.fasterxml.jackson.databind.deser.std.CollectionDeserializer.deserialize(CollectionDeserializer.java:227) 在 com.fasterxml.jackson.databind.deser.std.CollectionDeserializer.deserialize(CollectionDeserializer.java:204) 在 com.fasterxml.jackson.databind.deser.std.CollectionDeserializer.deserialize(CollectionDeserializer.java:23) 在 com.fasterxml.jackson.databind.deser.SettableBeanProperty.deserialize(SettableBeanProperty.java:525) 在 com.fasterxml.jackson.databind.deser.impl.MethodProperty.deserializeAndSet(MethodProperty.java:99) 在 com.fasterxml.jackson.databind.deser.BeanDeserializer.vanillaDeserialize(BeanDeserializer.java:242) ...省略了42个常见帧
以下是所有相关代码(当然,每个类都在自己的文件中)。
@Entity
public class Shelf {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private long id;
private String name;
@OneToMany
private List<Book> books;
public List<Book> getBooks() {
return books;
}
public void setBooks(List<Book> books) {
this.books = books;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
@Entity
public class Book {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private long id;
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
@RepositoryRestResource
public interface BookRepository extends JpaRepository<Book, Long>{
}
@RepositoryRestResource
public interface ShelfRepository extends JpaRepository<Shelf, Long>{
}
我使用的是Spring Boot 1.1.8.RELEASE
答案 0 :(得分:3)
Book
个实体拥有自己的REST端点,并创建一个必须POST到该端点的实体。
要将书籍放在书架上,您必须将该书籍的URI发送到关联URI(/shelves/{id}/books
)。令人惊讶的是,文档有错误,添加项目不是通过POST完成的,而是PATCH:
PATCH http://localhost:8080/shelves/1/books
Content-Type: text/uri-list
http://localhost:8080//books/1
您可以一次添加多个图书,每行一个URI。如果您不想添加书籍,而是用新的书籍替换书架上的所有书籍,即替换整个书籍,则可以使用PUT。
答案 1 :(得分:0)
我认为我找到了最简单的方法(我已经将书架关系双向化)。
这完美无缺。好吧,有点。本书是使用与父母的正确链接创建的,但现在我遇到的问题是家长没有在/ shelf / 1 / books下显示该书。我为here发布了一个新问题。