一,点睛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中,如下图:

springboot rest请求时间 springboot data rest_rest


       通过RepositoryRestMvcAutoConfiguration类的源码我们可以得出,spring boot已经为我们自动配置了RepositoryRestMvcConfiguration,所以在Spring Boot中使用Spring Data REST只需导入spring-boot-starter-data-rest的依赖,无须任何配置即可使用。

RepositoryRestConfiguration,如下:

springboot rest请求时间 springboot data rest_rest_02





三,实战

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,获得列表数据如下:

springboot rest请求时间 springboot data rest_spring cloud_03



2)获取单一对象

    在postman中使用get访问http://localhost:9090/persons/75,获得id为75的对象,如下:

springboot rest请求时间 springboot data rest_rest_04



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,可以实现查询操作,如下:

springboot rest请求时间 springboot data rest_spring cloud_05


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"
}



输出如下:

springboot rest请求时间 springboot data rest_rest_06


  通过输出可以看出,保存成功后我们的新数据的id为82

7)保存

      现在我们更新新增的id为82的数据,用put方式发生访问http://localhost:9090/persons/82,并修改提交的数据如下:

{
	"name":"test rest",
	"age":"99",
	"address":"update the rest test address"
}



结果如下:

springboot rest请求时间 springboot data rest_springboot rest请求时间_07


     从输出我们可以看出,数据更新已经成功了。


8)删除

    在这一步我们删除刚才新增的id为82的数据,使用delete方式访问http://localhost:9090/persons/82,如下图:

springboot rest请求时间 springboot data rest_springboot rest请求时间_08


      查看数据库,发现数据已经被删除了,此时用get方式访问http://localhost:9090/persons/82,如下图:

springboot rest请求时间 springboot data rest_rest_09



已经访问不到数据了。


 

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的结果如下:

springboot rest请求时间 springboot data rest_spring cloud_10