1. 什么是Spring Data REST
Spring Data JPA是基于Spring Data 的Repository之上,可以将Repository自动输出为REST资源。目前Spring Data REST支持将Spring Data JPA、Spring Data MongoDB、Spring Data Neo4j、Spring Data Gemfire以及Spring Data Cassandra的Repository自动转换成REST服务。
2. Spring mvc中配置使用Spring Data REST
Spring Data REST的配置是定义在RepositoryRestMvcConfiguration配置类中已经配置好了,我们可以通过继承此类或者直接在自己的配置类上@Import此配置类
3. Spring boot的支持
Spring Boot对Spring Data REST的自动配置放置在rest包中
通过SpringBootRestConfiguration类的源码我们可以得出,Spring Boot已经为我们自动配置了RepositoryRestConfiguration,所以在Spring boot中使用Spring Data REST只需引入spring-boot-starter-data-rest的依赖,无须任何配置即可使用。
Spring boot通过在application.properties中配置以“spring.data.rest”为前缀的属性来配置RepositoryRestConfiguration
1 import org.springframework.beans.factory.annotation.Autowired; 2 import org.springframework.core.annotation.Order; 3 import org.springframework.data.rest.core.config.RepositoryRestConfiguration; 4 import org.springframework.data.rest.webmvc.config.RepositoryRestConfigurerAdapter; 5 import org.springframework.http.converter.json.Jackson2ObjectMapperBuilder; 6 7 @Order(0) 8 class SpringBootRepositoryRestConfigurer extends RepositoryRestConfigurerAdapter { 9 10 @Autowired(required = false) 11 private Jackson2ObjectMapperBuilder objectMapperBuilder; 12 13 @Autowired 14 private RepositoryRestProperties properties; 15 16 @Override 17 public void configureRepositoryRestConfiguration(RepositoryRestConfiguration config) { 18 this.properties.applyTo(config); 19 } 20 21 @Override 22 public void configureJacksonObjectMapper(ObjectMapper objectMapper) { 23 if (this.objectMapperBuilder != null) { 24 this.objectMapperBuilder.configure(objectMapper); 25 } 26 } 27 28 }
1 @ConfigurationProperties(prefix = "spring.data.rest") 2 public class RepositoryRestProperties { 3 4 /** 5 * Base path to be used by Spring Data REST to expose repository resources. 6 */ 7 private String basePath; 8 9 /** 10 * Default size of pages. 11 */ 12 private Integer defaultPageSize; 13 14 /** 15 * Maximum size of pages. 16 */ 17 private Integer maxPageSize; 18 19 /** 20 * Name of the URL query string parameter that indicates what page to return. 21 */ 22 private String pageParamName; 23 24 /** 25 * Name of the URL query string parameter that indicates how many results to return at 26 * once. 27 */ 28 private String limitParamName; 29 30 /** 31 * Name of the URL query string parameter that indicates what direction to sort 32 * results. 33 */ 34 private String sortParamName; 35 36 /** 37 * Strategy to use to determine which repositories get exposed. 38 */ 39 private RepositoryDetectionStrategies detectionStrategy = RepositoryDetectionStrategies.DEFAULT; 40 41 /** 42 * Content type to use as a default when none is specified. 43 */ 44 private MediaType defaultMediaType; 45 46 /** 47 * Return a response body after creating an entity. 48 */ 49 private Boolean returnBodyOnCreate; 50 51 /** 52 * Return a response body after updating an entity. 53 */ 54 private Boolean returnBodyOnUpdate; 55 56 /** 57 * Enable enum value translation via the Spring Data REST default resource bundle. 58 * Will use the fully qualified enum name as key. 59 */ 60 private Boolean enableEnumTranslation; 61 62 public String getBasePath() { 63 return this.basePath; 64 } 65 66 public void setBasePath(String basePath) { 67 this.basePath = basePath; 68 } 69 70 public Integer getDefaultPageSize() { 71 return this.defaultPageSize; 72 } 73 74 public void setDefaultPageSize(Integer defaultPageSize) { 75 this.defaultPageSize = defaultPageSize; 76 } 77 78 public Integer getMaxPageSize() { 79 return this.maxPageSize; 80 } 81 82 public void setMaxPageSize(Integer maxPageSize) { 83 this.maxPageSize = maxPageSize; 84 } 85 86 public String getPageParamName() { 87 return this.pageParamName; 88 } 89 90 public void setPageParamName(String pageParamName) { 91 this.pageParamName = pageParamName; 92 } 93 94 public String getLimitParamName() { 95 return this.limitParamName; 96 } 97 98 public void setLimitParamName(String limitParamName) { 99 this.limitParamName = limitParamName; 100 } 101 102 public String getSortParamName() { 103 return this.sortParamName; 104 } 105 106 public void setSortParamName(String sortParamName) { 107 this.sortParamName = sortParamName; 108 } 109 110 public RepositoryDetectionStrategies getDetectionStrategy() { 111 return this.detectionStrategy; 112 } 113 114 public void setDetectionStrategy(RepositoryDetectionStrategies detectionStrategy) { 115 this.detectionStrategy = detectionStrategy; 116 } 117 118 public MediaType getDefaultMediaType() { 119 return this.defaultMediaType; 120 } 121 122 public void setDefaultMediaType(MediaType defaultMediaType) { 123 this.defaultMediaType = defaultMediaType; 124 } 125 126 public Boolean getReturnBodyOnCreate() { 127 return this.returnBodyOnCreate; 128 } 129 130 public void setReturnBodyOnCreate(Boolean returnBodyOnCreate) { 131 this.returnBodyOnCreate = returnBodyOnCreate; 132 } 133 134 public Boolean getReturnBodyOnUpdate() { 135 return this.returnBodyOnUpdate; 136 } 137 138 public void setReturnBodyOnUpdate(Boolean returnBodyOnUpdate) { 139 this.returnBodyOnUpdate = returnBodyOnUpdate; 140 } 141 142 public Boolean getEnableEnumTranslation() { 143 return this.enableEnumTranslation; 144 } 145 146 public void setEnableEnumTranslation(Boolean enableEnumTranslation) { 147 this.enableEnumTranslation = enableEnumTranslation; 148 } 149 150 public void applyTo(RepositoryRestConfiguration configuration) { 151 if (this.basePath != null) { 152 configuration.setBasePath(this.basePath); 153 } 154 if (this.defaultPageSize != null) { 155 configuration.setDefaultPageSize(this.defaultPageSize); 156 } 157 if (this.maxPageSize != null) { 158 configuration.setMaxPageSize(this.maxPageSize); 159 } 160 if (this.pageParamName != null) { 161 configuration.setPageParamName(this.pageParamName); 162 } 163 if (this.limitParamName != null) { 164 configuration.setLimitParamName(this.limitParamName); 165 } 166 if (this.sortParamName != null) { 167 configuration.setSortParamName(this.sortParamName); 168 } 169 if (this.detectionStrategy != null) { 170 configuration.setRepositoryDetectionStrategy(this.detectionStrategy); 171 } 172 if (this.defaultMediaType != null) { 173 configuration.setDefaultMediaType(this.defaultMediaType); 174 } 175 if (this.returnBodyOnCreate != null) { 176 configuration.setReturnBodyOnCreate(this.returnBodyOnCreate); 177 } 178 if (this.returnBodyOnUpdate != null) { 179 configuration.setReturnBodyOnUpdate(this.returnBodyOnUpdate); 180 } 181 if (this.enableEnumTranslation != null) { 182 configuration.setEnableEnumTranslation(this.enableEnumTranslation); 183 } 184 } 185 186 }
实战演练
1.定义实体类
2.定义Repository
3.测试
1 @Entity 2 public class Person { 3 @Id 4 @GeneratedValue 5 private Long id; 6 7 private String name; 8 9 private Integer age; 10 11 private String address; 12 13 14 15 public Person() { 16 super(); 17 } 18 public Person(Long id, String name, Integer age, String address) { 19 super(); 20 this.id = id; 21 this.name = name; 22 this.age = age; 23 this.address = address; 24 } 25 public Long getId() { 26 return id; 27 } 28 public void setId(Long id) { 29 this.id = id; 30 } 31 public String getName() { 32 return name; 33 } 34 public void setName(String name) { 35 this.name = name; 36 } 37 public Integer getAge() { 38 return age; 39 } 40 public void setAge(Integer age) { 41 this.age = age; 42 } 43 public String getAddress() { 44 return address; 45 } 46 public void setAddress(String address) { 47 this.address = address; 48 } 49 50 51 }
public interface PersonRepository extends JpaRepository<Person, Long> { Person findByNameStartsWith(@Param("name")String name); }
GET请求
http://localhost:8080/psersons 获取列表
http://localhost:8080/1 获取id为1的对象
在上面的自定义Repository中定义了findByNameStartsWith方法,若想此方法也暴露为REST资源,需做如下修改
public interface PersonRepository extends JpaRepository<Person, Long> { @RestResource(path = "nameStartsWith", rel = "nameStartsWith") Person findByNameStartsWith(@Param("name")String name); }
此时使用GET访问http://localhost:8080/persons/search/nameStartsWith?name=kevin,可实现查询操作
http://localhost:8080/persons/?page=1&size=2 分页查询,page-1即第2页,size=2即每页数量为2
http://localhost:8080/persons/?sort=age,desc 排序,即按照age属性倒序
POST请求
http://localhost:8080/persons ,并将数据放到请求体中 保存
http://localhost:8080/persons/21,并将数据放到请求体中 更新
DELETE请求
http://localhost:8080/persons/21 删除
4. 定制
(1)定制根路径
在上面的实战例子中,我们访问的REST资源的路径是在根目录下的,即http://localhost:8080/persos,如果我们需要定制根路径的话,只需要在Spring Boot的application.properties中添加定义 spring.data.rest.base-path= /api 此时REST资源的路径变成了http://localhost:8080/api/persons
(2)定制节点路径
上例实战中,我们的节点路径为http://localhost:8080/persons,这是Spring Data REST的默认规则,就是在实体类之后加“s”来形成路径。如果要对映射的名称进行修改的话,需要在实体类Repository上使用@RepositoryRestResource注解的path属性进行修改
1 @RepositoryRestResource(path = "people") 2 public interface PersonRepository extends JpaRepository<Person, Long> { 3 4 @RestResource(path = "nameStartsWith", rel = "nameStartsWith") 5 Person findByNameStartsWith(@Param("name")String name); 6 7 }
此时访问REST服务的地址变成http://localhost:8080/api/people