Spring Data REST是一个了不起的项目,它提供了一些机制来将基于Spring Data的存储库中的资源公开为REST资源。
使用链接资源公开服务
考虑两个简单的基于JPA的实体,课程和教师:
@Entity
@Table(name = "teachers")
public class Teacher {@Id@GeneratedValue(strategy = GenerationType.AUTO)@Column(name = "id")private Long id;@Size(min = 2, max = 50)@Column(name = "name")private String name;@Column(name = "department")@Size(min = 2, max = 50)private String department; ...
}@Entity
@Table(name = "courses")
public class Course {@Id@GeneratedValue(strategy = GenerationType.AUTO)@Column(name = "id")private Long id;@Size(min = 1, max = 10)@Column(name = "coursecode")private String courseCode;@Size(min = 1, max = 50)@Column(name = "coursename")private String courseName;@ManyToOne@JoinColumn(name = "teacher_id")private Teacher teacher;....
}
本质上,该关系如下所示:
现在,将这些实体作为REST资源公开所需要做的就是以这种方式在基于JPA的Spring Data存储库上添加@RepositoryRestResource批注,首先是“ Teacher”资源:
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.rest.core.annotation.RepositoryRestResource;
import univ.domain.Teacher;@RepositoryRestResource
public interface TeacherRepo extends JpaRepository<Teacher, Long> {
}
并公开课程资源:
@RepositoryRestResource
public interface CourseRepo extends JpaRepository<Course, Long> {
}
完成此操作并假设数据存储区中已经有几名教师和几门课程,关于课程的GET将产生以下类型的响应:
{"_links" : {"self" : {"href" : "http://localhost:8080/api/courses{?page,size,sort}","templated" : true}},"_embedded" : {"courses" : [ {"courseCode" : "Course1","courseName" : "Course Name 1","version" : 0,"_links" : {"self" : {"href" : "http://localhost:8080/api/courses/1"},"teacher" : {"href" : "http://localhost:8080/api/courses/1/teacher"}}}, {"courseCode" : "Course2","courseName" : "Course Name 2","version" : 0,"_links" : {"self" : {"href" : "http://localhost:8080/api/courses/2"},"teacher" : {"href" : "http://localhost:8080/api/courses/2/teacher"}}} ]},"page" : {"size" : 20,"totalElements" : 2,"totalPages" : 1,"number" : 0}
}
特定的课程如下所示:
{"courseCode" : "Course1","courseName" : "Course Name 1","version" : 0,"_links" : {"self" : {"href" : "http://localhost:8080/api/courses/1"},"teacher" : {"href" : "http://localhost:8080/api/courses/1/teacher"}}
}
如果您想知道“ _links”,“ _ embedded”是什么– Spring Data REST使用超文本应用程序语言(或简称HAL)来表示链接,例如说一门课程和一位老师之间的链接。
基于HAL的REST服务–使用
有了基于HAL的REST服务,我想到的问题就是如何为该服务编写客户端。 我相信有更好的方法可以做到这一点,但是接下来的工作对我来说很有效,我欢迎任何更简洁的编写客户方法。
首先,我修改了RestTemplate来注册一个定制的Json转换器,该转换器可以理解基于HAL的链接:
public RestTemplate getRestTemplateWithHalMessageConverter() {RestTemplate restTemplate = new RestTemplate();List<HttpMessageConverter<?>> existingConverters = restTemplate.getMessageConverters();List<HttpMessageConverter<?>> newConverters = new ArrayList<>();newConverters.add(getHalMessageConverter());newConverters.addAll(existingConverters);restTemplate.setMessageConverters(newConverters);return restTemplate;
}private HttpMessageConverter getHalMessageConverter() {ObjectMapper objectMapper = new ObjectMapper();objectMapper.registerModule(new Jackson2HalModule());MappingJackson2HttpMessageConverter halConverter = new TypeConstrainedMappingJackson2HttpMessageConverter(ResourceSupport.class);halConverter.setSupportedMediaTypes(Arrays.asList(HAL_JSON));halConverter.setObjectMapper(objectMapper);return halConverter;
}
Spring HATEOS项目提供了Jackson2HalModule并了解HAL表示形式。
有了这个闪亮的新RestTemplate,首先让我们创建一个Teacher实体 :
Teacher teacher1 = new Teacher();
teacher1.setName("Teacher 1");
teacher1.setDepartment("Department 1");
URI teacher1Uri =testRestTemplate.postForLocation("http://localhost:8080/api/teachers", teacher1);
请注意,在创建实体时,响应为http状态码201,位置标头指向新创建的资源的uri,Spring RestTemplate提供了一种巧妙的方式来通过API发布和获取此位置标头。 因此,现在我们有一个Teacher1Uri代表新创建的老师。
给定此教师URI,现在让我们检索教师 ,教师资源的原始json如下所示:
{"name" : "Teacher 1","department" : "Department 1","version" : 0,"_links" : {"self" : {"href" : "http://localhost:8080/api/teachers/1"}}
}
并使用RestTemplate来检索它:
ResponseEntity<Resource<Teacher>> teacherResponseEntity= testRestTemplate.exchange("http://localhost:8080/api/teachers/1", HttpMethod.GET, null, new ParameterizedTypeReference<Resource<Teacher>>() {
});Resource<Teacher> teacherResource = teacherResponseEntity.getBody();Link teacherLink = teacherResource.getLink("self");
String teacherUri = teacherLink.getHref();Teacher teacher = teacherResource.getContent();
Jackson2HalModule可以帮助干净地解压缩链接并掌握教师实体本身。 我之前已经在这里解释了ParameterizedTypeReference。
现在,更棘手的部分是创建课程。
创建课程很棘手,因为它与教师有关系,使用HAL表示这种关系并不是那么简单。 创建课程的原始POST如下所示:
{"courseCode" : "Course1","courseName" : "Course Name 1","version" : 0,"teacher" : "http://localhost:8080/api/teachers/1"
}
请注意,对教师的引用是一个URI,这就是HAL如何表示专门针对POST内容的嵌入式引用,因此现在可以通过RestTemplate获得此表单。
首先创建一个课程:
Course course1 = new Course();
course1.setCourseCode("Course1");
course1.setCourseName("Course Name 1");
在这一点上,通过处理json树表示形式并将教师链接添加为教师uri,可以更轻松地提供教师链接:
ObjectMapper objectMapper = getObjectMapperWithHalModule();
ObjectNode jsonNodeCourse1 = (ObjectNode) objectMapper.valueToTree(course1);
jsonNodeCourse1.put("teacher", teacher1Uri.getPath());
并发布此内容,应与链接的老师一起创建课程:
URI course1Uri = testRestTemplate.postForLocation(coursesUri, jsonNodeCourse1);
并检索此新创建的课程:
ResponseEntity<Resource<Course>> courseResponseEntity= testRestTemplate.exchange(course1Uri, HttpMethod.GET, null, new ParameterizedTypeReference<Resource<Course>>() {
});Resource<Course> courseResource = courseResponseEntity.getBody();
Link teacherLinkThroughCourse = courseResource.getLink("teacher");
这总结了如何使用RestTemplate创建和检索链接的资源,欢迎提出其他建议。
- 如果您有兴趣进一步探索它,可以在github repo上找到整个示例–测试在这里 。
翻译自: https://www.javacodegeeks.com/2014/12/spring-resttemplate-with-a-linked-resource.html