我有两节课:课程和课程。课程是与课程的@OneToMany关系。使用Spring Boot,我创建了一个简单的REST API来管理类。我已经用邮递员手动测试了API,看起来一切正常。
接下来,我编写了简单的JUnite来自动测试API。测试完成后,“课程”实体已正确保存在数据库中,但“课程”抛出错误:
2014-10-15 20:19:15.162错误5812 --- [nio-8080-exec-2] sdrwAbstractRepositoryRestController:无法读取JSON:模板不能为null或为空!(通过参考链:com.mbury.elearning.domain.Lesson [“ course”]);嵌套的异常是com.fasterxml.jackson.databind.JsonMappingException:模板不能为null或为空!(通过参考链:com.mbury.elearning.domain.Lesson [“ course”])
看起来@OneToMany关系没有正确映射,但我不知道该如何处理。有谁知道如何使用包含子对象的实体配置Spring REST以使其正常工作?
波纹管我已经附上了我所有的代码:
LessonTest.java
package com.mbury.elearning;
import static org.hamcrest.Matchers.equalTo;
import static org.springframework.test.util.MatcherAssertionErrors.assertThat;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.boot.test.IntegrationTest;
import org.springframework.boot.test.SpringApplicationConfiguration;
import org.springframework.boot.test.TestRestTemplate;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.springframework.test.context.web.WebAppConfiguration;
import org.springframework.web.client.RestTemplate;
import com.mbury.elearning.domain.Course;
import com.mbury.elearning.domain.Lesson;
@RunWith(SpringJUnit4ClassRunner.class)
@SpringApplicationConfiguration(classes = Application.class)
@WebAppConfiguration
@IntegrationTest
public class LessonTest {
final String BASE_URL_COURSE = "http://localhost:8080/courses/";
final String BASE_URL_LESSON = "http://localhost:8080/lessons/";
@Test
public void shouldCreateNewLesson() {
final String COURSE_TITLE = "test";
final String COURSE_DESCRIPTION = "test";
final String LESSON_TOPIC = "test";
Course course = new Course();
course.setTitle(COURSE_TITLE);
course.setDescription(COURSE_DESCRIPTION);
Lesson lesson = new Lesson();
lesson.setTopic(LESSON_TOPIC);
lesson.setCourse(course);
RestTemplate rest = new TestRestTemplate();
ResponseEntity<Course> response = rest.postForEntity(BASE_URL_COURSE, course,
Course.class);
assertThat(response.getStatusCode(), equalTo(HttpStatus.CREATED));
ResponseEntity<Lesson> response1 = rest.postForEntity(BASE_URL_LESSON, lesson,
Lesson.class);
assertThat(response1.getStatusCode(), equalTo(HttpStatus.CREATED));
}
}
Course.java
package com.mbury.elearning.domain;
import java.util.List;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.OneToMany;
import javax.persistence.Table;
@Entity
@Table(name = "course")
public class Course {
@Column(name = "description")
private String description;
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
@Column(name = "id")
private Integer id;
@OneToMany(mappedBy = "course")
private List<Lesson> lesson;
@Column(name = "title")
private String title;
public String getDescription() {
return description;
}
public Integer getId() {
return id;
}
public List<Lesson> getLesson() {
return lesson;
}
public String getTitle() {
return title;
}
public void setDescription(String description) {
this.description = description;
}
public void setId(Integer id) {
this.id = id;
}
public void setLesson(List<Lesson> lesson) {
this.lesson = lesson;
}
public void setTitle(String title) {
this.title = title;
}
}
Lesson.java
package com.mbury.elearning.domain;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne;
import javax.persistence.Table;
@Entity
@Table(name = "lesson")
public class Lesson {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
@Column(name = "id")
private int id;
@Column(name = "topic")
private String topic;
@ManyToOne(optional = false)
@JoinColumn(name = "ID_COURSE")
Course course;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getTopic() {
return topic;
}
public void setTopic(String topic) {
this.topic = topic;
}
public Course getCourse() {
return course;
}
public void setCourse(Course course) {
this.course = course;
}
}
CourseRepository.java
package com.mbury.elearning.repository;
import org.springframework.data.repository.CrudRepository;
import org.springframework.data.rest.core.annotation.RepositoryRestResource;
import com.mbury.elearning.domain.Course;
@RepositoryRestResource
public interface CourseRepository extends CrudRepository<Course, Integer> {
}
LessonRepository .java
package com.mbury.elearning.repository;
import org.springframework.data.repository.CrudRepository;
import org.springframework.data.rest.core.annotation.RepositoryRestResource;
import com.mbury.elearning.domain.Lesson;
@RepositoryRestResource
public interface LessonRepository extends CrudRepository<Lesson, Integer> {
}
应用程序.java
package com.mbury.elearning;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
import org.springframework.data.jpa.repository.config.EnableJpaRepositories;
import org.springframework.data.rest.webmvc.config.RepositoryRestMvcConfiguration;
@Configuration
@ComponentScan
@EnableJpaRepositories
@Import(RepositoryRestMvcConfiguration.class)
@EnableAutoConfiguration
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
问题的根源在于,您试图重用您的域对象,Lesson
并Course
尝试创建要发送到REST API的JSON有效负载。这不能用作REST API的视图,Lesson
或者Course
与实现的基于JPA的视图不同。例如,在服务器上,Lesson
or的IDCourse
是int,而在REST API中,ID是URI。
由于Course
和Lession
都是相当简单的类型,它可能比较容易,当你发送到REST API的请求使用地图。例如,您可以创建如下课程:
Map<String, Object> course = new HashMap<String, Object>();
course.put("title", "test");
course.put("description", "test");
我在上面提到,在REST API中,URI用于标识课程。这意味着在创建课程时,您需要课程所属的课程的URI。您从Location
创建课程时返回的响应的标头中获得该URI :
ResponseEntity<Void> courseResponse = rest.postForEntity(BASE_URL_COURSE, course, Void.class);
assertThat(courseResponse.getStatusCode(), equalTo(HttpStatus.CREATED));
URI courseLocation = courseResponse.getHeaders().getLocation();
然后,您可以使用此URI创建课程地图,并进行API调用以创建它:
Map<String, Object> lesson = new HashMap<String, Object>();
lesson.put("topic", "test");
lesson.put("course", courseLocation);
ResponseEntity<Void> lessonResponse = rest.postForEntity(BASE_URL_LESSON, lesson, Void.class);
assertThat(lessonResponse.getStatusCode(), equalTo(HttpStatus.CREATED));
将所有这些放在一起可以得到以下测试方法:
@Test
public void shouldCreateNewLesson() {
Map<String, Object> course = new HashMap<String, Object>();
course.put("title", "test");
course.put("description", "test");
RestTemplate rest = new TestRestTemplate();
ResponseEntity<Void> courseResponse = rest.postForEntity(BASE_URL_COURSE, course, Void.class);
assertThat(courseResponse.getStatusCode(), equalTo(HttpStatus.CREATED));
URI courseLocation = courseResponse.getHeaders().getLocation();
Map<String, Object> lesson = new HashMap<String, Object>();
lesson.put("topic", "test");
lesson.put("course", courseLocation);
ResponseEntity<Void> lessonResponse = rest.postForEntity(BASE_URL_LESSON, lesson, Void.class);
assertThat(lessonResponse.getStatusCode(), equalTo(HttpStatus.CREATED));
}
本文收集自互联网,转载请注明来源。
如有侵权,请联系[email protected] 删除。
我来说两句