如何添加" book"到/ shelf / 1 / books

时间:2014-11-05 23:08:21

标签: spring-boot spring-data-rest

我无法弄清楚如何做一些非常简单的事情。

我有两个实体:架子和书。书架可以有一本或多本书。这些实体中的每一个都使用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

2 个答案:

答案 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)

我认为我找到了最简单的方法(我已经将书架关系双向化)。

  1. 通过将货架{“name:”westerns“}发布到/ shelf
  2. 来创建需要拿着书的书架
  3. 通过将{“name”:“mybook”,“shelf”:“localhost:8080 / shelves / 1”}发布到/ books
  4. ,将新书与父书架的URI一起发布

    这完美无缺。好吧,有点。本书是使用与父母的正确链接创建的,但现在我遇到的问题是家长没有在/ shelf / 1 / books下显示该书。我为here发布了一个新问题。