rest repository都做了什么?
- 根据我们创建的repository自动生成api
- 返回的json格式数据是用hateoas进行封装过的
- 提供了一整套可供选择的集成方案,便于我们修改与使用
多返回值样例
- 我们已经有了一个名叫admin的帐号,现在需要获取所用用户的信息,但是我们又规定获取所有用户这个接口只有拥有ROLE_ADMIN权限的人才能够访问,所以首先得给admin增加ROLE_ADMIN权限(请先查询admin对应的user_id)
insert into authorities(authority, user_id) values("ROLE_ADMIN", 4);
- 然后打开postman向/api/users接口发送请求,使用Basic Auth认证模式
- 得到如下结果
{
"_embedded": {
"users": [
{
"id": 1,
"username": "user1",
"password": "$2a$10$U720kXDptsU5NOQjr7O.zewUx1S9gdppgrbsuf6vfFoxzMOF1eP4C",
"enabled": true,
"firstName": null,
"lastName": null,
"gender": 0,
"phone": null,
"email": null,
"icon": null,
"birthday": "2021-04-29T02:15:32.000+00:00",
"joinedDate": "2021-04-29T02:15:32.000+00:00",
"credentialsNonExpired": true,
"accountNonLocked": true,
"accountNonExpired": true,
"_links": {
"self": {
"href": "http://127.0.0.1:9001/api/users/1"
},
"user": {
"href": "http://127.0.0.1:9001/api/users/1"
},
"authorities": {
"href": "http://127.0.0.1:9001/api/users/1/authorities"
}
}
},
{
"id": 3,
"username": "user2",
"password": "$2a$10$MsvkTIPTvpD7/vgXc1gEauFlQuNH5bi3Gvoypp11A/Hxhp67CXWL2",
"enabled": true,
"firstName": null,
"lastName": null,
"gender": 0,
"phone": null,
"email": null,
"icon": null,
"birthday": "2021-04-29T02:42:26.000+00:00",
"joinedDate": "2021-04-29T02:42:26.000+00:00",
"credentialsNonExpired": true,
"accountNonLocked": true,
"accountNonExpired": true,
"_links": {
"self": {
"href": "http://127.0.0.1:9001/api/users/3"
},
"user": {
"href": "http://127.0.0.1:9001/api/users/3"
},
"authorities": {
"href": "http://127.0.0.1:9001/api/users/3/authorities"
}
}
},
{
"id": 4,
"username": "admin",
"password": "$2a$10$wDk9AuORolw2M1486MReXuwMZbJRCrtvzH/EHopvk/8EufqaAts86",
"enabled": true,
"firstName": null,
"lastName": null,
"gender": 0,
"phone": null,
"email": null,
"icon": null,
"birthday": "2021-04-29T02:44:46.000+00:00",
"joinedDate": "2021-04-29T02:44:46.000+00:00",
"credentialsNonExpired": true,
"accountNonLocked": true,
"accountNonExpired": true,
"_links": {
"self": {
"href": "http://127.0.0.1:9001/api/users/4"
},
"user": {
"href": "http://127.0.0.1:9001/api/users/4"
},
"authorities": {
"href": "http://127.0.0.1:9001/api/users/4/authorities"
}
}
}
]
},
"_links": {
"self": {
"href": "http://127.0.0.1:9001/api/users"
},
"profile": {
"href": "http://127.0.0.1:9001/api/profile/users"
},
"search": {
"href": "http://127.0.0.1:9001/api/users/search"
}
}
}
- 对以上代码进行分析
- 因为hateoas包装的原因,如果返回的结果是一个列表的形式,那么列表最外层必然是_embedded这个key
- _embedded下方有users这个key,它其实是User类的复数形式,如果对于GroupAuthority来说,就是groupAuthorities
- 列表中每一个user都有着表中的信息,并且有着_links连接,里面包含了对自身的描述,以及对权限的描述,刚好就对应了@OneToMany
- 和_embedded平级的还有_links,里面同样也包含了资源本身的描述,profile代表可以对资源进行的一些操作和附加信息
返回单个值样例
- 用postman直接对admin用户发送请求,向/api/users/admin发送请求
{
"password": "$2a$10$DmOZXqJFHrNMqp/QZdoVr.RVBtx/5S4erF2V.zCxFnn0SUIBjKD7K",
"enabled": true,
"firstName": null,
"lastName": null,
"gender": 0,
"phone": null,
"email": null,
"icon": null,
"birthday": null,
"joinedDate": "2021-04-22T09:47:11.000+00:00",
"credentialsNonExpired": true,
"accountNonExpired": true,
"accountNonLocked": true,
"_links": {
"self": {
"href": "http://127.0.0.1:9001/api/users/admin"
},
"user": {
"href": "http://127.0.0.1:9001/api/users/admin"
},
"authorities": {
"href": "http://127.0.0.1:9001/api/users/admin/authorities"
}
}
}
- 可以看到返回的json格式数据其实就是多返回值情况中的每一个user
用户id不见了?
- rest repository默认返回值是不包含主键的,所以自然作为用户主键的id不会被包含进去,但是很多情况下我们都需要用到id
- 这时候可以通过实现RepositoryRestConfigurer接口,并且重写configureRepositoryRestConfiguration(RepositoryRestConfiguration config, CorsRegistry cors)方法来实现id的显示
- 将如下代码写在kmhc.config包中
package kmhc.config;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.rest.core.config.RepositoryRestConfiguration;
import org.springframework.data.rest.webmvc.config.RepositoryRestConfigurer;
import org.springframework.web.servlet.config.annotation.CorsRegistry;
import kmhc.domain.user.User;
@Configuration
public class RestIdConfig implements RepositoryRestConfigurer {
@Override
public void configureRepositoryRestConfiguration(RepositoryRestConfiguration config, CorsRegistry cors) {
config
.exposeIdsFor(User.class);
}
}
- 这时我们向/api/users/4接口发送请求
{
"id": 4,
"username": "admin",
"password": "$2a$10$wDk9AuORolw2M1486MReXuwMZbJRCrtvzH/EHopvk/8EufqaAts86",
"enabled": true,
"firstName": null,
"lastName": null,
"gender": 0,
"phone": null,
"email": null,
"icon": null,
"birthday": "2021-04-29T02:44:46.000+00:00",
"joinedDate": "2021-04-29T02:44:46.000+00:00",
"credentialsNonExpired": true,
"accountNonLocked": true,
"accountNonExpired": true,
"_links": {
"self": {
"href": "http://127.0.0.1:9001/api/users/4"
},
"user": {
"href": "http://127.0.0.1:9001/api/users/4"
},
"authorities": {
"href": "http://127.0.0.1:9001/api/users/4/authorities"
}
}
}
- 可以看到id显示出来了
如何实现中间过程处理?
- 很多时候我们想对中间过程进行一些处理,比方说对提交上来的json格式数据进行格式化、对密码进行加密操作,防止短时间内数据的重复提交等
- 这时候就需要用到rest repository提供的EventHandler了,以如下方式使用它
- 定义一个类,并且加上@RepositoryEventHandler注解
- 在类中定义方法,并且加上自己想操作的过程,比如@HandleBeforeSave
- 在一个配置类中将自定义的Handler类声明为一个Bean并且返回
- 给出一个样例
package kmhc.handler;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.rest.core.annotation.HandleBeforeCreate;
import org.springframework.data.rest.core.annotation.RepositoryEventHandler;
import org.springframework.security.crypto.password.PasswordEncoder;
import kmhc.domain.user.User;
@RepositoryEventHandler(User.class)
public class UserEventHandler {
@Autowired
private PasswordEncoder passwordEncoder;
@HandleBeforeCreate
public void handleUserBeforeSave(User user) {
user.setPassword(passwordEncoder.encode(user.getPassword()));
}
}
package kmhc.config;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import kmhc.handler.UserEventHandler;
@Configuration
public class RepositoryConfig {
@Bean
public UserEventHandler userEventHandler() {
return new UserEventHandler();
}
}
- rest repository提供了如下几个中间过程
- BeforeCreateEvent
- AfterCreateEvent
- BeforeSaveEvent
- AfterSaveEvent
- BeforeLinkSaveEvent
- AfterLinkSaveEvent
- BeforeDeleteEvent
- AfterDeleteEvent
如何自定义接口?
- 有时候我们不满足于rest repository提供给我们的接口,需要自定义接口,但又希望接口能够符合restful规范,这时我们可以借助rest repository提供给我们的RepositoryEntityLinks类
- 这个类可以让你快速构建出符合要求的接口,你只需要在类中自动注入它
- 给出一个样例(仅供参考)
@Autowired
private RepositoryEntityLinks entityLinks;
// 返回描述全部用户的链接
Link link = entityLinks.linkToCollectionResource(User.class)
// 返回单个用户链接
Link link = entityLinks.linkToItemResource(User.class, user.getUsername())
- 具体使用RepositoryEntityLinks的实例会在后续章节中详细解释
更多
- 我强烈建议你去查询spring data rest的官网文档,并且自己琢磨,动手实践
至此,spring data rest的简单介绍讲解完毕,下一节将开始前端环境的搭建,初步目标是做一个用户管理的后台