복붙노트

[SPRING] 스프링 데이터 REST로 중첩 된 엔티티를 POST하는 방법

SPRING

스프링 데이터 REST로 중첩 된 엔티티를 POST하는 방법

나는 Spring Data REST 애플리케이션을 만들고 있는데 POST 할 때 몇 가지 문제가있다. 주체에는 다른 두 개의 관련 엔티티가 중첩되어 있습니다.

많은 답변을 가진 "질문"객체가 있으며이 답변 중 많은 답변이 많습니다.

나는 앞의 애플리케이션에서 설문지를 POST하기 위해 JSON을 생성한다.

{
    "user": "http://localhost:8080/users/1",
    "status": 1,
    "answers": [
        {
            "img": "urlOfImg",
            "question": "http://localhost:8080/question/6",
            "replies": [
                {
                    "literal": "http://localhost:8080/literal/1",
                    "result": "6"
                },
                {
                    "literal": "http://localhost:8080/literal/1",
                    "result": "6"
                }
            ]
        },
        {
            "img": "urlOfImg",
            "question": "http://localhost:8080/question/6",
            "replies": [
                {
                    "literal": "http://localhost:8080/literal/3",
                    "result": "10"
                }
            ]
        }
    ]
}

하지만 게시하려고하면 다음과 같은 오류 응답이 나타납니다.

{

    "cause" : {
        "cause" : {
          "cause" : null,
          "message" : "Template must not be null or empty!"
        },
        "message" : "Template must not be null or empty! (through reference chain: project.models.Questionary[\"answers\"])"
      },
      "message" : "Could not read JSON: Template must not be null or empty! (through reference chain: project.models.Questionary[\"answers\"]); nested exception is com.fasterxml.jackson.databind.JsonMappingException: Template must not be null or empty! (through reference chain: project.models.Questionary[\"answers\"])"
}

편집하다:

내 저장소도 추가합니다.

@RepositoryRestResource(collectionResourceRel = "questionaries", path = "questionaries")
public interface InspeccionRepository extends JpaRepository<Inspeccion, Integer> {
    @RestResource(rel="byUser", path="byUser")
    public List<Questionary> findByUser (@Param("user") User user);
}

My Entity Question 강의는 다음과 같습니다.

@Entity @Table(name="QUESTIONARY", schema="enco" )
public class Questionary implements Serializable {
     private static final long serialVersionUID = 1L;
     //----------------------------------------------------------------------
     // ENTITY PRIMARY KEY ( BASED ON A SINGLE FIELD )
     //----------------------------------------------------------------------
     @Id
     @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "SEC_QUESTIONARY")
     @SequenceGenerator(name = "SEC_QUESTIONARY", sequenceName = "ENCO.SEC_QUESTIONARY", allocationSize = 1)
     @Column(name="IDQUES", nullable=false)
     private Integer idques        ;

     //----------------------------------------------------------------------
     // ENTITY DATA FIELDS 
     //----------------------------------------------------------------------    

     @Column(name="ESTATUS")
     private Integer estatus       ;


     //----------------------------------------------------------------------
     // ENTITY LINKS ( RELATIONSHIP )
     //----------------------------------------------------------------------

     @ManyToOne
     @JoinColumn(name="IDUSER", referencedColumnName="IDUSER")
     private User user;

     @OneToMany(mappedBy="questionary", targetEntity=Answer.class)
     private List<Answer> answers;



     //----------------------------------------------------------------------
     // CONSTRUCTOR(S)
     //----------------------------------------------------------------------
     public Questionary()
     {
        super();
     }


     //----------------------------------------------------------------------
     // GETTERS & SETTERS FOR FIELDS
     //----------------------------------------------------------------------

     //--- DATABASE MAPPING : IDNSE ( NUMBER ) 
     public void setIdnse( Integer idnse )
     {
         this.idnse = idnse;
     }
     public Integer getIdnse()
     {
         return this.idnse;
     }

     //--- DATABASE MAPPING : ESTADO ( NUMBER ) 
     public void setEstatus Integer estatus )
     {
         this.estatus = estatus;
     }
     public Integer getEstatus()
     {
         return this.estatus;
     }      
     //----------------------------------------------------------------------
     // GETTERS & SETTERS FOR LINKS
     //----------------------------------------------------------------------
     public void setUser( Usuario user )
     {
         this.user = user;
     }
     public User getUser()
     {
         return this.user;
     }


     public void setAnswers( List<Respuesta> answers )
     {
         this.answers = answer;
     }
     public List<Answer> getAnswers()
     {
         return this.answers;
     }


     // Get Complete Object method      public List<Answer>
     getAnswerComplete() {
         List<Answer> answers = this.answers;
         return answers;
    }
}

내 답변 엔티티 :

 @Entity @Table(name="ANSWER", schema="enco" ) public class Answer
 implements Serializable {
     private static final long serialVersionUID = 1L;

     //----------------------------------------------------------------------
     // ENTITY PRIMARY KEY ( BASED ON A SINGLE FIELD )
     //----------------------------------------------------------------------
     @Id
     @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "SEC_ANSWER")
     @SequenceGenerator(name = "SEC_ANSWER", sequenceName = "ENCOADMIN.SEC_ANSWER", allocationSize = 1)
     @Column(name="IDANS", nullable=false)
     private Integer idans        ;


     //----------------------------------------------------------------------
     // ENTITY DATA FIELDS 
     //----------------------------------------------------------------------    

     @Column(name="IMG", length=100)
     private String     img       ;


     //----------------------------------------------------------------------
     // ENTITY LINKS ( RELATIONSHIP )
     //----------------------------------------------------------------------
     @ManyToOne
     @JoinColumn(name="IDQUES", referencedColumnName="IDQUES")
     private Questionary questionary  ;

     @OneToMany(mappedBy="answer", targetEntity=Reply.class)
     private List<Reply> replies;

     @ManyToOne
     @JoinColumn(name="IDQUE", referencedColumnName="IDQUE")
     private Question Question    ;


     //----------------------------------------------------------------------
     // CONSTRUCTOR(S)
     //----------------------------------------------------------------------
     public Answer()
     {
        super();
     }

     //----------------------------------------------------------------------
     // GETTER & SETTER FOR THE KEY FIELD
     //----------------------------------------------------------------------
     public void setIdans( Integer idans )
     {
         this.idans = idans ;
     }
     public Integer getIdans()
     {
         return this.idans;
     }

     //----------------------------------------------------------------------
     // GETTERS & SETTERS FOR FIELDS
     //----------------------------------------------------------------------

     //--- DATABASE MAPPING : IMAGEN ( VARCHAR2 ) 
     public void setImg( String img )
     {
         this.img = img;
     }
     public String getImg()
     {
         return this.img;
     }


     //----------------------------------------------------------------------
     // GETTERS & SETTERS FOR LINKS
     //----------------------------------------------------------------------
     public void setQuestionary( Questionary questionary )
     {
         this.questionary = questionary;
     }
     public Questionary getQuestionary()
     {
         return this.questionary;
     }

     public void setReplies( List<Reply> contestaciones )
     {
         this.replies = replies;
     }
     public List<Reply> getReplies()
     {
         return this.replies;
     }

     public void setQuestion( Question question )
     {
         this.question = question;
     }
     public Question getQuestion()
     {
         return this.question;
     }


}

그리고 이것은 오류 콘솔입니다.

Caused by: com.fasterxml.jackson.databind.JsonMappingException:
Template must not be null or empty! (through reference chain:
project.models.Questionary["answers"])  at
  com.fasterxml.jackson.databind.JsonMappingException.wrapWithPath(JsonMappingException.java:232)
 ~[jackson-databind-2.3.3.jar:2.3.3]    at *snip*

해결법

  1. ==============================

    1.Questionnaire 클래스의 필드 응답에 @RestResource (exported = false)를 추가하십시오.

    Questionnaire 클래스의 필드 응답에 @RestResource (exported = false)를 추가하십시오.

    내 말에 따르면,이 오류는 JSON에 응답을 중첩하는 대신 URI가 응답을 가져올 것으로 예상하기 때문에 디시리얼라이저가 발생하기 때문에 발생합니다. 주석을 추가하면 JSON을 대신 보게됩니다.

  2. ==============================

    2.2.3.0.M1에서이 오류가 계속 표시되지만 해결 방법을 찾았습니다.

    2.3.0.M1에서이 오류가 계속 표시되지만 해결 방법을 찾았습니다.

    기본 문제는 다음과 같습니다. JSON에 포함 된 엔티티의 URL을 게시하면 작동합니다. 실제 포함 된 엔티티 JSON을 게시하면 그렇지 않습니다. 엔티티 JSON을 URI로 역 직렬화하려고 시도하지만 당연히 실패합니다.

    이 문제는 스프링 데이터 나머지가 해당 구성 (RepositoryRestMvcConfiguration.defaultMessageConverters ())에서 생성하는 두 개의 TypeConstrainedMappingJackson2HttpMessageConverter 객체 인 것 같습니다.

    마지막으로 messageConverters의 지원되는 미디어 유형을 구성하여이 두 가지를 건너 뛰고 중첩 된 엔티티에서 올바르게 작동하는 일반 MappingJackson2HttpMessageConverter를 히트하도록 문제를 해결했습니다.

    예를 들어 RepositoryRestMvcConfiguration을 확장하고이 메서드를 추가하면 content-type이 'application / json'인 요청을 보내면 URI로 역 직렬화하지 않고 일반 MappingJackson2HttpMessageConverter에 도달합니다.

    @Override
    public void configureHttpMessageConverters(List<HttpMessageConverter<?>> messageConverters) {
        ((MappingJackson2HttpMessageConverter) messageConverters.get(0))
                .setSupportedMediaTypes(asList(MediaTypes.HAL_JSON));
        ((MappingJackson2HttpMessageConverter) messageConverters.get(2))
                .setSupportedMediaTypes(asList(MediaType.APPLICATION_JSON));
    }
    

    이는 RepositoryRestMvcConfiguration에서 defaultMessageConverters ()가 생성 한 메시지 변환기를 구성합니다.

    평범한 objectMapper는 JSON의 URI를 처리 할 수 ​​없다는 것을 명심하십시오. 임베디드 엔티티의 URI를 전달할 때마다 미리 구성된 두 개의 메시지 변환기 중 하나에 도달해야합니다.

  3. ==============================

    3.JSON의 한 가지 문제점은 문자열을 질문으로 역 직렬화하려고한다는 것입니다.

    JSON의 한 가지 문제점은 문자열을 질문으로 역 직렬화하려고한다는 것입니다.

    "question": "http://localhost:8080/question/6"
    

    Answer 개체에서 Jackson은 질문 용 개체를 기다리고 있습니다. ID 대신 URL을 사용하고있는 것으로 보입니다. 문자열 대신 다음과 같이 질문에 전달해야합니다.

    "question": {
        "id": "http://localhost:8080/question/6"
    }
    
  4. ==============================

    4."Spring Boot Data REST Starter"라이브러리를 업데이트하십시오. 나를 위해 일했다.

    "Spring Boot Data REST Starter"라이브러리를 업데이트하십시오. 나를 위해 일했다.

  5. from https://stackoverflow.com/questions/24569399/how-to-post-nested-entities-with-spring-data-rest by cc-by-sa and MIT license