爪哇2博客
爪哇2博客

春季靴 Crud存储库

在这篇文章中,我们’我将寻找如何创建和使用Spring Boot Crud存储库。

弹簧Boot Crud存储库 为要管理的实体类型提供复杂的CRUD功能。此接口主要用作标记接口,以捕获要使用的类型并帮助您发现扩展该接口的接口。它需要域类以及域类的id类型作为类型参数来管理。

Generally, to use up a Crud存储库 you’ll need a 数据base弹簧Framework 支持s a wide number of them including the most common ones like SQL, MySQL, MongoDB, H2 数据base 和 more. 让’那就继续吧。


使用的工具

  • 爪哇 8+
  • Maven 3+
  • 春季靴(您选择的版本,我们’将会使用v2.2.2.RELEASE,但是这些概念对于2.x 弹簧Boot是有效的)
  • 您选择的数据库(我们’ll be using MongoDB)
  • 您选择的IDE(我们’将会使用Intellij IDea)

项目结构:

春季靴项目结构

让’从示例开始。
获取文件->新建项目并添加必要的依赖项,您可以转到 弹簧 Starter IO
添加以下依赖项:

  • 弹簧启动启动器网络
  • 弹簧-boot-starter-data-mongodb

After that your pom.xml would look like:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
 
    <父母>
        <groupId>组织.弹簧框架.开机</groupId>
        <artifactId>弹簧-开机-起动机-父母</artifactId>
        <>2.2.2。发布</>
        <relativePath/> <!- 抬头 父母 资料库 ->
    </父母>
 
    <依存关系>
 
        <依赖>
            <groupId>组织.弹簧框架.开机</groupId>
            <artifactId>弹簧-开机-起动机-网路</artifactId>
        </依赖>
 
        <依赖>
            <groupId>组织.弹簧框架.开机</groupId>
            <artifactId>弹簧-开机-起动机-数据-mongodb</artifactId>
        </依赖>
 
    </依存关系>
 
    <建立>
        <最后Name>${项目.artifactId}</最后Name>
        <外挂程式>
            <插入>
                <groupId>组织.弹簧框架.开机</groupId>
                <artifactId>弹簧-开机-专家-插入</artifactId>
                <处决>
                    <执行>
                        <ID>建立-信息</ID>
                        <目标>
                            <目标>建立-信息</目标>
                        </目标>
                    </执行>
                </处决>
            </插入>
        </外挂程式>
        <资源>
            <资源>
                <目录>src/主要/资源</目录>
                <过滤>真正</过滤>
            </资源>
        </资源>
    </建立>
 

弹簧基本上是一个巨大的框架伞,它支持多个数据库的方式是利用入门
项目及其各自的自动配置。您可以阅读所有有关它们的信息
这里
起动机-parent is how 弹簧 handles 依赖 management 和 solves a few of many problems with transitive 依存关系


连接MongoDB

有很多方法可以连接MongoDb。我们’ll be using the MongoURI method with 弹簧 autoconfiguration by
setting the relevant properties in our application.properties file 和 let 弹簧 handle everything else.

For 这个 all you need to define is the MongoURIDBName in your application.properties file.

弹簧.data.mongodb.database = 弹簧CRUDS样本
弹簧.data.mongodb.uri=mongodb://127.0.0.1/

but you can 加 all sorts of 加itional settings 这里 including 用户名password 如果 your DB has them.

弹簧.data.mongodb.database = 弹簧CRUDS样本
弹簧.data.mongodb.uri=mongodb://127.0.0.1:27017/springCRUDSample?username=TestUser&password=TestPassword&socketTimeoutMS=60000

阅读更多关于 这个.


储存库类

创建一个名为的新接口 用户资料库

1
2
3
4
5
6
 
    @资料库
    上市 接口 用户资料库 延伸 Crud存储库<UserDao, > {
 
    }
 

用户资料库 would extend the Crud存储库&lt;T, Y&gt; 接口. Here ‘T’是需要在数据库中创建,读取,更新,删除的实体的类,以及‘Y’实体的ID字段的类型。

@资料库 annotation marks the 接口 as a 弹簧 Stereotype 和 弹簧 would provide 和 implementation for 这个 接口 at 跑time (reducing boiler-plate 数据base code) 阅读更多.

Crud存储库 has basic 创造, read, update, 删除 operation methods:

  • &lt;S 延伸 T&gt; S 保存(S entity); 将给定记录保存到数据库
  • &lt;S 延伸 T&gt; 可迭代的&lt;S&gt; 保存All(Iterable&lt;S&gt; entities); 将多个记录保存到数据库。
  • 可选的&lt;T&gt; findById(ID ID); 查找与ID匹配的记录
  • 布尔值 existsById(ID ID); 检查记录是否存在提供的ID
  • 可迭代的&lt;T&gt; 找到所有(); 从数据库获取所有记录
  • 可迭代的&lt;T&gt; 找到所有ById(Iterable&lt;ID&gt; IDs); 获取与提供的ID匹配的所有记录
  • 长 计数(); 返回数据库中的记录数。
  • 虚空 删除ById(ID ID); 删除具有给定id的实体。
  • 虚空 删除(T entity); 删除给定的实体。
  • 虚空 删除All(Iterable&lt;? 延伸 T&gt; entities); 删除所有提供的记录。
  • 虚空 删除All(); 从数据库中删除所有记录

大多数功能是不言自明的,我们’我将在此示例中查看其中的一些,但让’s first talk about
the 保存保存All method.


保存方法

的 reason why 保存 gets a whole section is because something that got to me as well when I was in the initial stages
with 弹簧Boot.

保存保存All basically works as an upsert (update or insert). If the object you pass in the 保存 method
has an ID (annotated with the @Id in MongoDB UserDao) value, 弹簧 would understand that there seems to be
具有相同ID的数据库中的一条记录,如果没有,将尝试查找该记录以执行更新’t find it 弹簧
将创建一个新记录,并将id字段(在DB中)设置为对象的id字段中存在的值。在
case the ID field is 空值 or empty, 弹簧 would treat it as a 新 record 和 perform the insert.

Careful though with the ID field, 如果 lets say that you don’t have any ID field in your 数据base 类 (DAO) even 如果 you read the record 从 the DB 和 call the 保存() method, 弹簧 would consider it as a 新 record 和 a Duplicate record would be 被创造. If you have any 独特 constraints in your 数据base 采集 they would fail 和 throw a DuplicateKeyException

用户实体类

UserDao is the 类 that represents the 用户 record stored in the 数据base.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
 
    @文件(采集 = “用户”)
    上市 UserDao {
 
        @ID
        私人的 用户身份;
 
        @索引(独特 = 真正)
        @领域(“用户名”)
        私人的 用户名;
 
        @领域(“名字”)
        私人的 名字;
 
        @领域(“姓”)
        私人的 ;
 
        上市 UserDao() {
        }
 
        上市 UserDao(UserDto 语境) {
            这个.用户身份 = 语境.getUserId();
            这个.用户名 = 语境.getUsername();
            这个.名字 = 语境.getFirstName();
            这个. = 语境.getLastName();
        }
 
        上市 UserDao UpdatedFrom(UserDto 语境) {
 
            如果 (语境.getUsername() != 空值 && !语境.getUsername().修剪().是空的())
                这个.用户名 = 语境.getUsername();
 
            如果 (语境.getUsername() != 空值 && !语境.getUsername().修剪().是空的())
                这个.名字 = 语境.getFirstName();
 
            如果 (语境.getUsername() != 空值 && !语境.getUsername().修剪().是空的())
                这个. = 语境.getLastName();
 
            返回 这个;
        }
 
        上市 getUserId() {
            返回 用户身份;
        }
 
        上市 getUsername() {
            返回 用户名;
        }
 
        上市 getFirstName() {
            返回 名字;
        }
 
        上市 getLastName() {
            返回 ;
        }
    }
 

该类包含一些字段,如userId,用户名,名字,姓氏。 用户身份是代表的字段
the ID field of the 数据base 和 hence is annotated as @Id (that’s how it’s done for MongoDB).

@Document annotation is another 弹簧 Stereotype that marks the 类 as a 数据base 类 和 弹簧 would use that 类 for any 数据 that’读取或写入用户集合(其中users是集合的名称)

@Field annotation defines the name of the field in the 数据base 和 地图s it to the property. If no field is annotated with @Field then the name of the variable is taken as that of the field name. This is primarily useful when the 数据base record has different names as posed to 类 fields. e.g. the ID field, in the 类 the ID field is 用户身份 but when it comes to MongoDB the ID field name is _id 和 that’s what the @Id field does. Alternatively you can use the @Field(&quot;_id&quot;) instead of the @Id 和 it’ll work the same.

@Indexed(unique=true) field is what sets the 用户名 field to be 独特 和 no two records can have the same 用户名. 的 reason why it’不能放在userId字段上是因为’s the ID field 和 each DB has it’开箱即用的s ID字段是唯一的

注意可以从DB中反序列化类’使用默认构造函数(NoArgsConstructor)很重要,这样spring才能创建该类的新对象并设置相关数据。当您未定义任何构造函数时,Java规则确实具有含义,那么每个类都有一个来自Object基类的自动实现的默认构造函数。

UserDto is just another 类 that represents the Data Transfer Object 返回ed 从 the service to the controller. You can look up the file in the Git存储库.

使UserDto具有几乎相同的字段的缺点是代码重复和多个对象的创建
但是如果那些不’这似乎是一个巨大的折衷,这种方法给您带来的核心优势是您拥有一层
中间的适配器将数据库字段与API响应的字段分开,这样,当数据库中的任何内容发生更改时,API用户/客户端都不会受到影响。


将UserDao和CrudRepository放在一起

弹簧如何知道要链接到哪个数据库集合的存储库?它’s all with the help of Generics. 弹簧 first resolves Crud存储库&lt;UserDao, 串&gt; 和 pulls out UserDao 和 looks for a 类 with that type which is annotated with
@Document,找到后,便会从
@Document(collection=users) 现在,它已将UserRepository链接到CrudRepository,以链接到数据库中的用户集合。


服务

We’已经连接了我们的存储库和实体类,现在让’查看控制器将调用以进行交互的服务。

Below is an implementation of the 用户服务. 的 code is 修剪med to only the relevant ones. For a complete sample
you should 抬头 the Git存储库. You can refer to the above section about the Crud存储库 methods to know
用什么方法做什么

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
 
    @服务
    上市 用户服务Impl 实施 用户服务 {
 
        私人的 最后 用户资料库 用户Repository;
 
        上市 用户服务Impl(用户资料库 用户Repository) {
            这个.用户Repository = 用户Repository;
        }
 
        @覆写
        上市 创建用户(UserDto 语境) 抛出 服务ClientException {
 
            尝试 {
 
                UserDao 保存dUser = 用户Repository.保存( UserDao(语境));
 
                返回 保存dUser.getUserId();
 
            } 抓住 (DuplicateKeyException e) {
                //处理重复的用户名
                返回 空值;
            }
        }
 
        @覆写
        上市 UserCountResponseDto 用户Count() {
 
             用户Count = 用户Repository.计数();
 
            返回 UserCountResponseDto(用户Count);
        }
 
        @覆写
        上市 采集<UserDto> getUsers() {
 
            可迭代的<UserDao> 使用者 = 用户Repository.找到所有();
 
            如果 (!使用者.迭代器().hasNext())
                返回 空值;
 
            采集<UserDto> 返回者 = 数组列表<>();
            使用者.每次(x -> 返回者.( UserDto(x)));
 
            返回 返回者;
        }
 
        @覆写
        上市 UserDto getUsers( 用户身份) 抛出 服务ClientException {
 
            可选的<UserDao> 用户Optional = 用户Repository.findById(用户身份);
            UserDao 用户 = 用户Optional.要不然(空值);
            返回 UserDto(用户);
        }
 
        @覆写
        上市 采集<UserDto> getUsersByPet( petName) {
 
            采集<UserDao> 使用者 = 用户Repository.findByPets(petName);
 
            返回 使用者.().地图(UserDto:: ).收藏(收藏家.到清单());
        }
 
        @覆写
        上市 布尔值 updateUser( 用户身份, UserDto 语境) 抛出 服务ClientException {
 
            尝试 {
 
                UserDao 用户 = 用户Repository.findById(用户身份).要不然(空值);
                用户Repository.保存(用户.UpdatedFrom(语境));
                返回 真正;
 
            } 抓住 (DuplicateKeyException e) {
                //处理重复的用户名
 
            } 抓住 (例外 e) {
            }
            返回 ;
        }
 
        @覆写
        上市 布尔值 删除User( 用户身份) 抛出 服务ClientException {
 
            用户Repository.删除ById(用户身份);
            返回 ;
        }
    }
 

Notice the 删除 method, it directly calls the 删除ById() 和 这个 would work because the 用户身份 is the ID
field of the 数据base but what 如果 the 用户身份 is not the ID field of the 数据base? Another way would be read the
用户,然后通过传递实例删除该记录。

1
2
3
4
5
6
7
8
9
 
    @覆写
    上市 布尔值 删除User( 用户身份) 抛出 服务ClientException {
 
        UserDao 现有用户 = 用户Repository.findById(用户身份).要不然(空值);
        用户Repository.删除(现有用户)
        返回 ;
    }
 


控制者

现在我们已经连接了服务,我们只需要添加控制器以实际添加可访问的接口
这样客户可以访问我们的功能’ve在这里构建(使用API​​)。我们赢了’涵盖基础知识
of APIs or @RestController in 这个 blog post but you can 抬头 春季靴子休息示例
以获得更多信息。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
 
    @RestController
    上市 用户控制器 {
 
        私人的 最后 用户服务 用户Service;
 
        上市 用户控制器(用户服务 用户Service) {
            这个.用户Service = 用户Service;
        }
 
        @后期制图(“ /用户”)
        上市 响应实体<?> 创造NewUser(@RequestBody UserDto 语境) {
 
            尝试 {
 
                 用户身份 = 用户Service.创建用户(语境);
 
                如果 (用户身份 == 空值)
                    返回 响应实体.状态(HttpStatus.NOT_MODIFIED).建立();
 
                返回 响应实体.被创造(URI.创造("http://127.0.0.1:8080/users/" + 用户身份)).建立();
 
            } 抓住 (服务ClientException e) {
                返回 响应实体.错误的请求().标头(“信息”, e.getMessage()).建立();
            }
        }
 
        @GetMapping(“ /用户/计数”)
        上市 响应实体<?> getUsersCount() {
 
            UserCountResponseDto 用户Count = 用户Service.用户Count();
 
            如果 (用户Count == 空值)
                返回 响应实体.无内容().建立();
 
            返回 响应实体.().内容类型(媒体类型.APPLICATION_JSON).身体(用户Count);
        }
 
        @GetMapping(“ /用户”)
        上市 响应实体<?> getAllUsers() {
 
            采集<UserDto> 使用者 = 用户Service.getUsers();
 
            如果 (使用者 == 空值 || 使用者.是空的())
                返回 响应实体.无内容().建立();
 
            返回 响应实体.().内容类型(媒体类型.APPLICATION_JSON).身体(使用者);
        }
 
        @GetMapping(“ / 使用者 / {userId}”)
        上市 响应实体<?> getAllUsersById(@路径变量(“用户身份”) 用户身份) {
 
            尝试 {
 
                UserDto 用户 = 用户Service.getUsers(用户身份);
 
                如果 (用户 == 空值)
                    响应实体.无内容().建立();
 
                返回 响应实体.().内容类型(媒体类型.APPLICATION_JSON).身体(用户);
 
            } 抓住 (服务ClientException e) {
                返回 响应实体.错误的请求().标头(“信息”, e.getMessage()).建立();
            }
        }
 
        @贴图(“ / 使用者 / {userId}”)
        上市 响应实体<?> updateUser(@路径变量(“用户身份”) 用户身份, @RequestBody UserDto 语境) {
 
            尝试 {
 
                布尔值 那是成功的 = 用户Service.updateUser(用户身份, 语境);
 
                如果 (!那是成功的)
                    返回 响应实体.状态(HttpStatus.NOT_MODIFIED).建立();
 
                返回 响应实体.().建立();
 
            } 抓住 (服务ClientException e) {
                返回 响应实体.错误的请求().标头(“信息”, e.getMessage()).建立();
            }
        }
 
        @删除映射(“ / 使用者 / {userId}”)
        上市 响应实体<?> 删除User(@路径变量(“用户身份”) 用户身份) {
 
            尝试 {
 
                布尔值 那是成功的 = 用户Service.删除User(用户身份);
 
                如果 (!那是成功的)
                    返回 响应实体.状态(HttpStatus.NOT_MODIFIED).建立();
 
                返回 响应实体.().建立();
 
            } 抓住 (服务ClientException e) {
                返回 响应实体.错误的请求().标头(“信息”, e.getMessage()).建立();
            }
        }
    }
 

的 above is a sample snippet of the 用户控制器 for the complete code you can refer to the GitHub 资料库.

控制器必须遵守 RFC-7231 that states the standards for RESTful APIs.You can see based on the 状态 codes 和 the 创造 用户 201 (with URL) response. During the POST call, the server must 返回 the URL of the 资源 that was 被创造.


应用类别

这是Application.java,它将用于运行代码。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
 
com.亚姆卡罗.样本.弹簧bootcrud存储库;
 
进口 组织.弹簧框架.开机.弹簧应用;
进口 组织.弹簧框架.开机.自动配置.弹簧Boot应用程序;
进口 组织.弹簧框架.开机.网路.小服务程序.支持.弹簧BootServletInitializer;
 
@弹簧Boot应用程序
上市 应用 延伸 弹簧BootServletInitializer {
 
    上市 静态的 虚空 主要([] args) {
        弹簧应用.(应用., args);
    }
 
}
 


运行代码示例

现在我们已经准备就绪,我们只需运行代码并尝试使用API​​。我们’ll be using 邮差 去做这个。

We’ll first make the Post request to 创造 the 用户:

CreateUserCall

Notice the Response Headers has a key called Location that is 弹簧 doing its work for obeying RFC-7231 based on the URL we 加ed in the 响应实体.created(&quot;URL&quot;)

让’现在让我们看一下数据库,对于数据库,我喜欢使用一个称为 蒙哥罗盘 而不是终端,只是使这变得容易。

的 pets 和 age are basically extra fields I 加ed up. Notice how our 用户身份 is stored as ObjectId(&quot;OurID&quot;) 和 the actual field name is _id even though in our model 类 it was 用户身份 that’s the @Id doing it’s job.

让’尝试立即获取用户信息:

就在那里。

也注册了其他端点,您可以类似地调用它们

终点 方法类型 描述
/用户/数量 得到 获取注册的用户数
/用户 得到 获取所有注册的用户
/ 使用者 / {userId} 更新用户数据
/ 使用者 / {userId} 删除 删除用户

Careful about the 得到 /用户 call though imagine you have 1 million 使用者, would you want to 返回 all of them in a single call? Wouldn’对服务器来说太难了吗?为了解决这个问题,我将在另一篇博客文章中介绍分页’超出了本博客文章的范围。


结论

我们看了一下SpringBoot Crud存储库,’的方法以及与存储库交互的示例服务。
从上面的示例中删除了很多代码(例如异常处理,空检查和控制器),以带来
更着重于CrudRepository的实际方法。

请记住,CrudRepository只是一个基本的即用型功能,尽管它’s a great way to get started you may would want to define your own methods in the 用户资料库 that would be more bound to your use cases. This i超出了本博客文章的范围。 的 删除ById(), findById()保存() they all work on the ID field of the 数据base 和 如果 you want your own ID fields then you can 创造 them 和 write queries 和 methods in the 用户资料库 接口 和 弹簧 would wire up an implementation for you at 跑time.

源代码

那’关于Spring Boot Crud存储库的所有内容。


导入联系人

您可能还喜欢:

分享这个

作者

关注作者

相关文章

  • 1月11日

    春季靴 JDBC示例

    在本文中,我们将看到Spring 开机 JDBC示例。众所周知,Spring Boot会执行许多自动配置,这有助于我们避免大量样板代码。对于JDBC,spring 开机提供了自动配置,例如根据application.properties自动创建DataSource和JDBCTemplate对象。所以你只需要[…]

  • 一月02

    春季靴开发工具教程

    在这篇文章中,我们’我会一直在寻找spring为开发人员提供的体验。概述使用Eclipse,Spring Tool Suite,Intellij IDea等IDE,一个典型的开发设置包括一个应用程序代码库,该代码库已部署在Web应用程序服务器上,例如Wildfly或Tomcat甚至Glassfish。发展的速度是[…]

  • 12月26日

    春季靴 H2数据库示例

    在这篇文章中,我们 are going to see how to 创造 弹簧 开机 application integrating with H2 数据base. What is H2 数据base? H2 is open source 数据base. It is very fast 和 smaller in size. It is in-memory 数据base 和 keeps all 数据 in memory. If you start 和 stop the application, all the 数据 […]

  • 4月10日

    弹簧和Spring Boot之间的区别

    在这篇文章中,我们 will see difference between 弹簧 和 弹簧 开机. If you have followed 弹簧 项目 over time, you might have noticed it has become increasingly complex. If you want to 创造 a 弹簧 application, you still need to put a lot of efforts. 弹簧 开机 is introduced to 保存 time to 开机strap […]

  • 9月17日

    春季靴 SOAP Web服务示例

    在这篇文章中,我们 will see how to 创造 soap 网路 services with 弹簧 开机. We will 创造 contract first soap 网路 service with 弹簧 开机. We will focus on how to define configurations for soap 网路 services. 使用的工具 JDK 1.8, Eclipse, Maven 弹簧-boot – Underlying application framework wsdl4j – for publishing WSDL for our […]

  • 8月08

    春季靴配置文件示例

    在本教程中,我们将看到有关Spring引导配置文件的信息。需要概要文件应用程序开发是一个复杂的过程。您可能具有用于应用程序开发的不同环境。开发SIT QA产品我们需要根据环境进行不同的配置。例如:使用不同的数据库或不同的队列。让’创建一个简单的spring 开机应用程序。步 […]

发表评论

您的电子邮件地址不会被公开。 必需的地方已做标记 *

订阅我们的新闻

获取质量教程到您的收件箱。现在订阅。


让’s be Friends

©2020 爪哇2博客