SpringBoot与JPA构建RESTful风格

Lou.Chen
大约 6 分钟

springboot与jpa构建restful风格

一、基本配置

1、pom.xml

spring-boot-starter-data-rest

<?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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.2.5.RELEASE</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <groupId>org.lc</groupId>
    <artifactId>jpa-rest</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>jpa-rest</name>
    <description>Demo project for Spring Boot</description>

    <properties>
        <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-data-rest</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>druid-spring-boot-starter</artifactId>
            <version>1.1.18</version>
        </dependency>

        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <scope>runtime</scope>
            <version>5.1.27</version>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
            <exclusions>
                <exclusion>
                    <groupId>org.junit.vintage</groupId>
                    <artifactId>junit-vintage-engine</artifactId>
                </exclusion>
            </exclusions>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>

</project>

2、实体bean
@Getter
@Setter
@ToString
@Entity(name = "t_book")
public class Book {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Integer id;
    private String name;
    private String author;
}
3、yaml配置
spring:
  datasource:
    type: com.alibaba.druid.pool.DruidDataSource
    driver-class-name: com.mysql.jdbc.Driver
    url: jdbc:mysql://127.0.0.1:3306/test?useUnicode=true&characterEncoding=UTF-8
    username: root
    password: 123456

  jpa:
    #    显示sql语句
    show-sql: true
    #    数据库
    database: mysql
    #    数据库平台
    database-platform: mysql
    #    设置表的结构的生成类型
    hibernate:
      #      每次启动更新表结构
      ddl-auto: update
    properties:
      hibernate:
        #        设置方言 mysql57
        dialect: org.hibernate.dialect.MySQL57Dialect
4、dao接口配置
public interface BookDao extends JpaRepository<Book,Integer> {
}

二、基本的restful风格的增删改查

1、查询所有数据

要查询的实体的类名首字母小写,然后在后面加s

get: http://localhost:8080/books

{
  "_embedded": {
    "books": [
      {
        "name": "三国演义",
        "author": "罗贯中",
        "_links": {
          "self": {
            "href": "http://localhost:8080/books/1"
          },
          "book": {
            "href": "http://localhost:8080/books/1"
          }
        }
      },
      {
        "name": "水浒传",
        "author": "施耐庵",
        "_links": {
          "self": {
            "href": "http://localhost:8080/books/2"
          },
          "book": {
            "href": "http://localhost:8080/books/2"
          }
        }
      },
      {
        "name": "红楼梦",
        "author": "曹雪芹",
        "_links": {
          "self": {
            "href": "http://localhost:8080/books/3"
          },
          "book": {
            "href": "http://localhost:8080/books/3"
          }
        }
      },
      {
        "name": "西游记",
        "author": "吴承恩",
        "_links": {
          "self": {
            "href": "http://localhost:8080/books/4"
          },
          "book": {
            "href": "http://localhost:8080/books/4"
          }
        }
      },
      {
        "name": "童年",
        "author": "鲁迅",
        "_links": {
          "self": {
            "href": "http://localhost:8080/books/5"
          },
          "book": {
            "href": "http://localhost:8080/books/5"
          }
        }
      }
    ]
  },
  "_links": {
    "self": {
        //可对分页进行排序操作
      "href": "http://localhost:8080/books{?page,size,sort}",
      "templated": true
    },
    "profile": {
      "href": "http://localhost:8080/profile/books"
    }
  },
    //分页信息
    //页的大小20 ;总记录数为5  ,总页数为1 , 当前页为1(jpa中页面从0开始)  
  "page": {
    "size": 20,
    "totalElements": 5,
    "totalPages": 1,
    "number": 0
  }
}
2、分页查询

查询第二页,每页大小为2

get: http://localhost:8080/books?page=1&size=2

{
  "_embedded": {
    "books": [
      {
        "name": "红楼梦",
        "author": "曹雪芹",
        "_links": {
          "self": {
            "href": "http://localhost:8080/books/3"
          },
          "book": {
            "href": "http://localhost:8080/books/3"
          }
        }
      },
      {
        "name": "西游记",
        "author": "吴承恩",
        "_links": {
          "self": {
            "href": "http://localhost:8080/books/4"
          },
          "book": {
            "href": "http://localhost:8080/books/4"
          }
        }
      }
    ]
  },
  "_links": {
      //首页地址
    "first": {
      "href": "http://localhost:8080/books?page=0&size=2"
    },
      //上一页地址
    "prev": {
      "href": "http://localhost:8080/books?page=0&size=2"
    },
      //排序
    "self": {
      "href": "http://localhost:8080/books{&sort}",
      "templated": true
    },
      //下一页地址
    "next": {
      "href": "http://localhost:8080/books?page=2&size=2"
    },
      //最后一页地址
    "last": {
      "href": "http://localhost:8080/books?page=2&size=2"
    },
    "profile": {
      "href": "http://localhost:8080/profile/books"
    }
  },
  "page": {
    "size": 2,
    "totalElements": 5,
    "totalPages": 3,
    "number": 1
  }
}
3、分页排序查询

先按照id降序排列,然后查询出第二页的数据

get : http://localhost:8080/books?page=1&size=2&sort=id,desc

{
  "_embedded": {
    "books": [
      {
        "name": "红楼梦",
        "author": "曹雪芹",
        "_links": {
          "self": {
            "href": "http://localhost:8080/books/3"
          },
          "book": {
            "href": "http://localhost:8080/books/3"
          }
        }
      },
      {
        "name": "水浒传",
        "author": "施耐庵",
        "_links": {
          "self": {
            "href": "http://localhost:8080/books/2"
          },
          "book": {
            "href": "http://localhost:8080/books/2"
          }
        }
      }
    ]
  },
  "_links": {
    "first": {
      "href": "http://localhost:8080/books?page=0&size=2&sort=id,desc"
    },
    "prev": {
      "href": "http://localhost:8080/books?page=0&size=2&sort=id,desc"
    },
    "self": {
      "href": "http://localhost:8080/books"
    },
    "next": {
      "href": "http://localhost:8080/books?page=2&size=2&sort=id,desc"
    },
    "last": {
      "href": "http://localhost:8080/books?page=2&size=2&sort=id,desc"
    },
    "profile": {
      "href": "http://localhost:8080/profile/books"
    }
  },
  "page": {
    "size": 2,
    "totalElements": 5,
    "totalPages": 3,
    "number": 1
  }
}
4、查询指定id数据

查询id为3的数据

get: http://localhost:8080/books/3

{
  "name": "红楼梦",
  "author": "曹雪芹",
  "_links": {
    "self": {
      "href": "http://localhost:8080/books/3"
    },
    "book": {
      "href": "http://localhost:8080/books/3"
    }
  }
}
5、添加数据

post: http://localhost:8080/books

application-type: json

{
	"name":"史记",
	"author":"司马迁"
}
{
  "name": "史记",
  "author": "司马迁",
  "_links": {
    "self": {
      "href": "http://localhost:8080/books/6"
    },
    "book": {
      "href": "http://localhost:8080/books/6"
    }
  }
}
6、根据id修改

put: http://localhost:8080/books/6

application-type: json

这里的修改必须要传所有字段,否则没有传的字段会赋值为null

{
	"name":"《史记》",
	"author":"司马老贼"
}
{
  "name": "《史记》",
  "author": "司马老贼",
  "_links": {
    "self": {
      "href": "http://localhost:8080/books/6"
    },
    "book": {
      "href": "http://localhost:8080/books/6"
    }
  }
}
7、根据id删除

delete: http://localhost:8080/books/6

三、自定义查询方法接口

1、dao接口
public interface BookDao extends JpaRepository<Book,Integer> {

    /**
     * 查询包含的名称的数据
     * @param name
     * @return
     */
    List<Book> findBooksByNameContaining(@Param("name") String name);
}
2、postman测试
①查询所有可使用的接口

get: http://localhost:8080/books/search

{
  "_links": {
    "findBooksByNameContaining": {
      "href": "http://localhost:8080/books/search/findBooksByNameContaining{?name}",
      "templated": true
    },
    "self": {
      "href": "http://localhost:8080/books/search"
    }
  }
}
②使用自定义的接口

查询名称包含红的集合

get: http://localhost:8080/books/search/findBooksByNameContaining?name=红

{
  "_embedded": {
    "books": [
      {
        "name": "红楼梦",
        "author": "曹雪芹",
        "_links": {
          "self": {
            "href": "http://localhost:8080/books/3"
          },
          "book": {
            "href": "http://localhost:8080/books/3"
          }
        }
      }
    ]
  },
  "_links": {
    "self": {
      "href": "http://localhost:8080/books/search/findBooksByNameContaining?name=%E7%BA%A2"
    }
  }
}
③修改请求路径及集合路径

@RepositoryRestResource(path = "bs",collectionResourceRel = "bs1",itemResourceRel = "b")

path: 请求的一级路径

collectionResourceRel : 集合名称

itemResourceRel : 集合中的路径herf元素名称

@RestResource(exported = true,path = "byname",rel = "findByName")

exported : 是否暴露此接口(默认为true)

path: 请求的二级路径

rel : 查询所有接口时的该方法的对象名称

修改dao接口==>

@RepositoryRestResource(path = "bs",collectionResourceRel = "bs1",itemResourceRel = "b")
public interface BookDao extends JpaRepository<Book,Integer> {

    /**
     * 查询包含的名称的数据
     * @param name
     * @return
     */
    @RestResource(exported = true,path = "byname",rel = "findByName")
    List<Book> findBooksByNameContaining(@Param("name") String name);
  
}

查询所有接口==>

get: http://localhost:8080/bs/search

{
  "_links": {
    "findByName": {
      "href": "http://localhost:8080/bs/search/byname{?name}",
      "templated": true
    },
    "self": {
      "href": "http://localhost:8080/bs/search"
    }
  }
}

使用该findByName接口==>

get : http://localhost:8080/bs/search/byname?name=红

{
  "_embedded": {
    "bs1": [
      {
        "name": "红楼梦",
        "author": "曹雪芹",
        "_links": {
          "self": {
            "href": "http://localhost:8080/bs/3"
          },
          "b": {
            "href": "http://localhost:8080/bs/3"
          }
        }
      }
    ]
  },
  "_links": {
    "self": {
      "href": "http://localhost:8080/bs/search/byname?name=%E7%BA%A2"
    }
  }
}

四、实现跨域

@CrossOrigin 默认为允许所有请求 @CrossOrigin("*")

@CrossOrigin
@RepositoryRestResource(path = "bs",collectionResourceRel = "bs1",itemResourceRel = "b")
public interface BookDao extends JpaRepository<Book,Integer> {

    /**
     * 查询包含的名称的数据
     * @param name
     * @return
     */
    @RestResource(exported = true,path = "byname",rel = "findByName")
    List<Book> findBooksByNameContaining(@Param("name") String name);

}

五、更改spring中对restful的自动配置

org.springframework.boot.autoconfigure.data.rest.RepositoryRestProperties==>

@ConfigurationProperties(
    prefix = "spring.data.rest"
)
public class RepositoryRestProperties {
    //基础路径
    private String basePath;
    //默认页
    private Integer defaultPageSize;
    //每页的最大尺寸
    private Integer maxPageSize;
    //页码的参数名称
    private String pageParamName;
    private String limitParamName;
    //排序的参数名称
    private String sortParamName;
    private RepositoryDetectionStrategies detectionStrategy;
    private MediaType defaultMediaType;
    //创建后并返回
    private Boolean returnBodyOnCreate;
    //更新后并返回
    private Boolean returnBodyOnUpdate;
    private Boolean enableEnumTranslation;
    //****
    //****
}
1、yaml的配置
spring:
  data:
    rest:
#      加前缀
      base-path: /api
2、配置文件配置
/**
 * 此类的优先级配置 高于 yaml中的配置
 */
@Configuration
public class RestConfig implements RepositoryRestConfigurer {

    @Override
    public void configureRepositoryRestConfiguration(RepositoryRestConfiguration config) {
                //设置默认路径
        config.setBasePath("/lc")
                //设置默认页大小
                .setDefaultPageSize(2);
    }
}

请求测试:==>

get: http://localhost:8080/lc/bs/search/byname?name=红

{
  "_embedded": {
    "bs1": [
      {
        "name": "红楼梦",
        "author": "曹雪芹",
        "_links": {
          "self": {
            "href": "http://localhost:8080/lc/bs/3"
          },
          "b": {
            "href": "http://localhost:8080/lc/bs/3"
          }
        }
      }
    ]
  },
  "_links": {
    "self": {
      "href": "http://localhost:8080/lc/bs/search/byname?name=%E7%BA%A2"
    }
  }
}