一,点睛Spring Data REST
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(org.springframework.data.rest.webmvc.config.RepositoryRestMvcConfiguration)配置类中已经配置好了,我们可以通过继承此类或直接在自己的配置类上@Import此配置类。
1)继承方式演示
package com.jack.springboot6springdatarest.config;
import org.springframework.context.annotation.Configuration;
/**
* create by jack 2017/10/5
*/
@Configuration
public class MyRepositoryRestMvcConfiguration extends RepositoryRestMvcConfiguration{
@Override
public RepositoryRestMvcConfiguration config(){
return super.config();
}
//其他可重写以config开头的方法
}
2)导入方式演示
package com.jack.springboot6springdatarest.config;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
/**
* create by jack 2017/10/5
*/
@Configuration
@Import(RepositoryRestMvcConfiguration.class)
public class AppConfig {
}
因为Spring MVC中使用Spring Data REST和在Spring Boot中使用的方式是一样的,因此我们将在实战环节细说Spring Data REST。
二,Spring Boot的支持
Spring Boot对Spring Data REST的自动配置放置在Rest中,如下图:
通过RepositoryRestMvcAutoConfiguration类的源码我们可以得出,spring boot已经为我们自动配置了RepositoryRestMvcConfiguration,所以在Spring Boot中使用Spring Data REST只需导入spring-boot-starter-data-rest的依赖,无须任何配置即可使用。
RepositoryRestConfiguration,如下:
三,实战
1,新建Spring Boot项目
新建Spring Boot项目依赖JPA,WEB,添加mysql的驱动,pom.xml代码如下:
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.jack</groupId>
<artifactId>springboot6springdatarest</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>jar</packaging>
<name>springboot6springdatarest</name>
<description>Demo project for Spring Boot</description>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>1.5.7.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<java.version>1.8</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!--mysql连接驱动-->
<!-- https://mvnrepository.com/artifact/mysql/mysql-connector-java -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
2,新建实体类
package com.jack.springboot6springdatarest.entity;
import javax.persistence.*;
/**
* create by jack 2017/10/3
*/
//@Entity注解指明这是一个和数据库表映射的实体类
@Entity
public class Person {
/**
* 主键id
* @Id注解指明这个属性映射为数据库的主键
* @GeneratedValue定义主键生成的方式,下面采用的是mysql的自增属性
*/
@Id
@GeneratedValue(strategy= GenerationType.AUTO)
private Integer id;
/**
* 姓名
*/
private String name;
/**
* 年龄
*/
private Integer age;
/**
* 地址
*/
private String address;
public Person() {
super();
}
public Person(Integer id, String name, Integer age, String address) {
super();
this.id = id;
this.name = name;
this.age = age;
this.address = address;
}
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Integer getAge() {
return age;
}
public void setAge(Integer age) {
this.age = age;
}
public String getAddress() {
return address;
}
public void setAddress(String address) {
this.address = address;
}
}
3,配置application.yml
这里涉及到spring jpa的知识,具体的可以参考:
server:
port: 9090
spring:
#application:
#name: rest-test
datasource:
driver-class-name: com.mysql.jdbc.Driver
url: jdbc:mysql://127.0.0.1:3306/jack
username: root
password: root
jpa:
hibernate:
#hibernate\u63D0\u4F9B\u4E86\u6839\u636E\u5B9E\u4F53\u7C7B\u81EA\u52A8\u7EF4\u62A4\u6570\u636E\u5E93\u8868\u7ED3\u6784\u7684\u529F\u80FD\uFF0C\u53EF\u901A\u8FC7spring.jpa.hibernate.ddl-auto\u6765\u914D\u7F6E\uFF0C\u6709\u4E0B\u5217\u53EF\u9009\u9879
#create\uFF1A\u542F\u52A8\u65F6\u5220\u9664\u4E0A\u4E00\u6B21\u751F\u6210\u7684\u8868\uFF0C\u5E76\u6839\u636E\u5B9E\u4F53\u7C7B\u751F\u6210\u8868\uFF0C\u8868\u4E2D\u6570\u636E\u4F1A\u88AB\u6E05\u7A7A
#create-drop\uFF1A\u542F\u52A8\u65F6\u6839\u636E\u5B9E\u4F53\u7C7B\u751F\u6210\u8868\uFF0CsessionFacotry\u5173\u95ED\u65F6\u8868\u4F1A\u88AB\u5220\u9664
#update\uFF1A\u542F\u52A8\u65F6\u6839\u636E\u5B9E\u4F53\u7C7B\u751F\u6210\u8868\uFF0C\u5F53\u5B9E\u4F53\u7C7B\u5C5E\u6027\u53D8\u52A8\u7684\u65F6\u5019\uFF0C\u8868\u7ED3\u6784\u4E5F\u4F1A\u66F4\u65B0\uFF0C\u5728\u521D\u671F\u5F00\u53D1\u9636\u6BB5\u4F7F\u7528\u6B64\u9879
#validate\uFF1B\u542F\u52A8\u65F6\u9A8C\u8BC1\u5B9E\u4F53\u7C7B\u548C\u6570\u636E\u8868\u662F\u5426\u4E00\u81F4\uFF0C\u5728\u6211\u4EEC\u6570\u636E\u7ED3\u6784\u7A33\u5B9A\u65F6\u91C7\u7528\u6B64\u9009\u9879
#none\uFF1A\u4E0D\u91C7\u53D6\u4EFB\u4F55\u63AA\u65BD
ddl-auto: update
#show-sql\u7528\u6765\u8BBE\u7F6Ehibernate\u64CD\u4F5C\u7684\u65F6\u5019\u5728\u63A7\u5236\u53F0\u663E\u793A\u5176\u771F\u5B9E\u7684sql\u8BED\u53E5
show-sql: true
properties:
hibernate:
dialect: org.hibernate.dialect.MySQL5Dialect
jackson:
serialization:
#\u8BA9\u63A7\u5236\u5668\u8F93\u51FA\u7684json\u5B57\u7B26\u4E32\u683C\u5F0F\u66F4\u7F8E\u89C2
indent_output: true
4,实体类的Repository
package com.jack.springboot6springdatarest.dao;
import com.jack.springboot6springdatarest.entity.Person;
import org.springframework.data.jpa.repository.JpaRepository;
import java.util.List;
/**
* create by jack 2017/10/5
*/
public interface PersonRepository extends JpaRepository<Person,Integer>{
List<Person> findByNameStartingWith(String name);
}
5,安装postman插件
postman插件是一个用来测试后台接口的软件插件,可以百度查找进行安装。
5,测试
1)在postman中使用get方式访问http://localhost:9090/persons,获得列表数据如下:
2)获取单一对象
在postman中使用get访问http://localhost:9090/persons/75,获得id为75的对象,如下:
3)查询
在上面的自定义实体类Repository中定义了findByNameStartsWith方法,若想此方法也曝露为REST资源,需要做如下的修改
package com.jack.springboot6springdatarest.dao;
import com.jack.springboot6springdatarest.entity.Person;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.repository.query.Param;
import org.springframework.data.rest.core.annotation.RestResource;
import java.util.List;
/**
* create by jack 2017/10/5
*/
public interface PersonRepository extends JpaRepository<Person,Integer>{
@RestResource(path = "nameStartsWith",rel = "nameStartsWith")
List<Person> findByNameStartingWith(@Param("name") String name);
}
此时在postman中使用http://localhost:9090/persons/search/nameStartsWith?name=jack,可以实现查询操作,如下:
4)分页
在psotman中使用get访问http://localhost:9090/persons/?page=1&size=2,即page=1为第二页,size=2即每页数量为2,返回数据如下:
{
"_embedded": {
"persons": [
{
"name": "jack3",
"age": 20,
"address": "杭州",
"_links": {
"self": {
"href": "http://localhost:9090/persons/77"
},
"person": {
"href": "http://localhost:9090/persons/77"
}
}
},
{
"name": "jack4",
"age": 21,
"address": "广州",
"_links": {
"self": {
"href": "http://localhost:9090/persons/78"
},
"person": {
"href": "http://localhost:9090/persons/78"
}
}
}
]
},
"_links": {
"first": {
"href": "http://localhost:9090/persons?page=0&size=2"
},
"prev": {
"href": "http://localhost:9090/persons?page=0&size=2"
},
"self": {
"href": "http://localhost:9090/persons{&sort}",
"templated": true
},
"next": {
"href": "http://localhost:9090/persons?page=2&size=2"
},
"last": {
"href": "http://localhost:9090/persons?page=3&size=2"
},
"profile": {
"href": "http://localhost:9090/profile/persons"
},
"search": {
"href": "http://localhost:9090/persons/search"
}
},
"page": {
"size": 2,
"totalElements": 7,
"totalPages": 4,
"number": 1
}
}
5)排序
在postman中使用get访问http://localhost:9090/persons/?sort=age,desc,即按照age属性倒序排序,postman返回数据如下:
{
"_embedded": {
"persons": [
{
"name": "jack7",
"age": 24,
"address": "南京",
"_links": {
"self": {
"href": "http://localhost:9090/persons/81"
},
"person": {
"href": "http://localhost:9090/persons/81"
}
}
},
{
"name": "jack6",
"age": 23,
"address": "长沙",
"_links": {
"self": {
"href": "http://localhost:9090/persons/80"
},
"person": {
"href": "http://localhost:9090/persons/80"
}
}
},
{
"name": "jack5",
"age": 22,
"address": "深圳",
"_links": {
"self": {
"href": "http://localhost:9090/persons/79"
},
"person": {
"href": "http://localhost:9090/persons/79"
}
}
},
{
"name": "jack4",
"age": 21,
"address": "广州",
"_links": {
"self": {
"href": "http://localhost:9090/persons/78"
},
"person": {
"href": "http://localhost:9090/persons/78"
}
}
},
{
"name": "jack3",
"age": 20,
"address": "杭州",
"_links": {
"self": {
"href": "http://localhost:9090/persons/77"
},
"person": {
"href": "http://localhost:9090/persons/77"
}
}
},
{
"name": "jack2",
"age": 19,
"address": "上海",
"_links": {
"self": {
"href": "http://localhost:9090/persons/76"
},
"person": {
"href": "http://localhost:9090/persons/76"
}
}
},
{
"name": "jack1",
"age": 18,
"address": "北京",
"_links": {
"self": {
"href": "http://localhost:9090/persons/75"
},
"person": {
"href": "http://localhost:9090/persons/75"
}
}
}
]
},
"_links": {
"self": {
"href": "http://localhost:9090/persons"
},
"profile": {
"href": "http://localhost:9090/profile/persons"
},
"search": {
"href": "http://localhost:9090/persons/search"
}
},
"page": {
"size": 20,
"totalElements": 7,
"totalPages": 1,
"number": 0
}
}
6)保存
向http://localhost:9090/persons发起post请求,将我们要保存的数据放置在请求体中,数据类型设置为json,json内容如下:
{
"name":"test rest",
"age":"28",
"address":"the rest test address"
}
输出如下:
通过输出可以看出,保存成功后我们的新数据的id为82
7)保存
现在我们更新新增的id为82的数据,用put方式发生访问http://localhost:9090/persons/82,并修改提交的数据如下:
{
"name":"test rest",
"age":"99",
"address":"update the rest test address"
}
结果如下:
从输出我们可以看出,数据更新已经成功了。
8)删除
在这一步我们删除刚才新增的id为82的数据,使用delete方式访问http://localhost:9090/persons/82,如下图:
查看数据库,发现数据已经被删除了,此时用get方式访问http://localhost:9090/persons/82,如下图:
已经访问不到数据了。
6,定制
1)定制根路径
在上面实战的例子中,我们访问的REST资源的路径是在根目录下的,即http://localhost:9090/persons,如果我们需要定制根路径的话,只需在Spring Boot的application.properties下增加如下定义即可:
spring.data.rest.base-path=/api
此时rest资源的路径变成了http://localhost:9090/api/persons/
修改applicaiton.yml,如下:
server:
port: 9090
spring:
#application:
#name: rest-test
datasource:
driver-class-name: com.mysql.jdbc.Driver
url: jdbc:mysql://127.0.0.1:3306/jack
username: root
password: root
data:
rest:
base-path: /api
jpa:
hibernate:
#hibernate\u63D0\u4F9B\u4E86\u6839\u636E\u5B9E\u4F53\u7C7B\u81EA\u52A8\u7EF4\u62A4\u6570\u636E\u5E93\u8868\u7ED3\u6784\u7684\u529F\u80FD\uFF0C\u53EF\u901A\u8FC7spring.jpa.hibernate.ddl-auto\u6765\u914D\u7F6E\uFF0C\u6709\u4E0B\u5217\u53EF\u9009\u9879
#create\uFF1A\u542F\u52A8\u65F6\u5220\u9664\u4E0A\u4E00\u6B21\u751F\u6210\u7684\u8868\uFF0C\u5E76\u6839\u636E\u5B9E\u4F53\u7C7B\u751F\u6210\u8868\uFF0C\u8868\u4E2D\u6570\u636E\u4F1A\u88AB\u6E05\u7A7A
#create-drop\uFF1A\u542F\u52A8\u65F6\u6839\u636E\u5B9E\u4F53\u7C7B\u751F\u6210\u8868\uFF0CsessionFacotry\u5173\u95ED\u65F6\u8868\u4F1A\u88AB\u5220\u9664
#update\uFF1A\u542F\u52A8\u65F6\u6839\u636E\u5B9E\u4F53\u7C7B\u751F\u6210\u8868\uFF0C\u5F53\u5B9E\u4F53\u7C7B\u5C5E\u6027\u53D8\u52A8\u7684\u65F6\u5019\uFF0C\u8868\u7ED3\u6784\u4E5F\u4F1A\u66F4\u65B0\uFF0C\u5728\u521D\u671F\u5F00\u53D1\u9636\u6BB5\u4F7F\u7528\u6B64\u9879
#validate\uFF1B\u542F\u52A8\u65F6\u9A8C\u8BC1\u5B9E\u4F53\u7C7B\u548C\u6570\u636E\u8868\u662F\u5426\u4E00\u81F4\uFF0C\u5728\u6211\u4EEC\u6570\u636E\u7ED3\u6784\u7A33\u5B9A\u65F6\u91C7\u7528\u6B64\u9009\u9879
#none\uFF1A\u4E0D\u91C7\u53D6\u4EFB\u4F55\u63AA\u65BD
ddl-auto: update
#show-sql\u7528\u6765\u8BBE\u7F6Ehibernate\u64CD\u4F5C\u7684\u65F6\u5019\u5728\u63A7\u5236\u53F0\u663E\u793A\u5176\u771F\u5B9E\u7684sql\u8BED\u53E5
show-sql: true
properties:
hibernate:
dialect: org.hibernate.dialect.MySQL5Dialect
jackson:
serialization:
#\u8BA9\u63A7\u5236\u5668\u8F93\u51FA\u7684json\u5B57\u7B26\u4E32\u683C\u5F0F\u66F4\u7F8E\u89C2
indent_output: true
2)定制节点路径
上例实战中我们的节点为http://localhost:9090/persons,这是spring data rest的默认规则,就是在实体类之后加“s”来形成路径。我们知道person的复数是people而不是persons,在类似的情况下要对映射的名称进行修改的话,我们需要在实体类Repository上使用@RepositoryRestResource注解的path属性进行修改,代码如下:
package com.jack.springboot6springdatarest.dao;
import com.jack.springboot6springdatarest.entity.Person;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.repository.query.Param;
import org.springframework.data.rest.core.annotation.RepositoryRestResource;
import org.springframework.data.rest.core.annotation.RestResource;
import org.springframework.data.rest.webmvc.RepositoryRestController;
import java.util.List;
/**
* create by jack 2017/10/5
*/
@RepositoryRestResource(path = "people")
public interface PersonRepository extends JpaRepository<Person,Integer>{
@RestResource(path = "nameStartsWith",rel = "nameStartsWith")
List<Person> findByNameStartingWith(@Param("name") String name);
}
此时我们访问rest服务的地址变为:http://localhost:9090/api/people
此时访问id为81的结果如下: