springboot快速创建增删改查接口
Easul Lv6

准备工作

spring initializr 创建相关初始工程。
Project, Language, Spring BootProject Metadata 都需要进行自己手动选择和填写。
相关 jar 包的依赖需要包括 Spring Web, Spring Boot DevTools, Rest Repositories(快速创建Rest API), H2 Database(内存型数据库), Lombok(快速添加 getter 和 setter ), Spring Data JPA(用于方便的快速存取数据)。
选择好后,下载打包好的工程。

开始测试

将下载的压缩包解压,拖到 vscode ,打开项目。
进入到 src=>main=>java下的java文件 。
然后在该文件中编写相关示例代码。

以下为使用 JPA 的情况下,通过 controller 来暴露 API
适用于复杂情况时的组装

折叠代码块JAVA 复制代码
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
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
package com.example.faststart;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.List;
import java.util.Optional;

import org.springframework.boot.CommandLineRunner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.Bean;
import org.springframework.core.annotation.Order;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PatchMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RestController;

import jakarta.persistence.Entity;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.GenerationType;
import jakarta.persistence.Id;
import jakarta.persistence.Table;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

@SpringBootApplication
public class FaststartApplication {

public static void main(String[] args) {
SpringApplication.run(FaststartApplication.class, args);
}

// 指明一个 bean,当他处于 SpringApplication 中时,他将会被运行
// 使用 @Order 注解来指定运行的顺序
@Bean
@Order(0)
CommandLineRunner saveSomeRepositories(ProductRepository productRepository) {
return args -> {
productRepository.save(new Product(null, "Bob", 12.1, true));
productRepository.save(new Product(null, "Stevie", 10.1, true));
productRepository.findAll().forEach(product -> {
System.out.println(product.toString());
});
};
}

@Bean
@Order(1)
CommandLineRunner run(ProductRepository productRepository) {
return args -> {
productRepository.findAll().forEach(product -> {
System.out.println(product.getId());
});
};
}
}

@Entity
@Data
@NoArgsConstructor
@AllArgsConstructor
// 指定与哪个表进行关联
// 如果使用的是 postgresql ,那么可能还需要加上 scheme 成员
@Table(name = "mytest")
class Product {
// 指定主键及其值生成策略
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
// 使用包装类,没有传入的值为 null
private String name;
private Double price;
private Boolean isInStock;
}

// 指定一个 JPA 接口,用于持久化数据到数据库
// 需要指定相关实体类
interface ProductRepository extends JpaRepository<Product, Long>{

};

// 创建一个 controller 用于增删改查
@RestController
@AllArgsConstructor
class ProductController {
private final ProductRepository productRepository;

@GetMapping(path = "/products")
public List<Product> list() {
return productRepository.findAll();
}

@GetMapping(path = "/products/{id}")
public Product getProduct(@PathVariable Long id) {
return productRepository.findById(id).get();
}

@PostMapping(path = "/products")
public Product postProduct(@RequestBody Product product) {
return productRepository.save(product);
}

// 用于更新全部数据
@PutMapping(path = "/products/{id}")
public Product putProduct(@PathVariable Long id, @RequestBody Product product) {
// 更新操作,这里只需要更新id, save 的时候 hibernate 会自动判断有没有该 id
// 有的话则进行更新操作
product.setId(id);
return productRepository.save(product);
}

// 用于更新部分数据
@PatchMapping(path = "/products/{id}")
public Product patchProduct(@PathVariable Long id, @RequestBody Product product) throws IllegalAccessException, IllegalArgumentException, InvocationTargetException, NoSuchMethodException, SecurityException {
Optional<Product> originProductOpt = productRepository.findById(id);
if (originProductOpt.isEmpty()) {
return new Product();
}
Product originProduct = originProductOpt.get();
Class<?> productClass = product.getClass();
Method[] methods = productClass.getMethods();
for (Method method: methods) {
String methodName = method.getName();
Class<?> methodReturnedType = method.getReturnType();
if (methodName.startsWith("get") && !"getClass".equals(methodName)) {
Object value = method.invoke(product);
if (null == value) {
continue;
}

String setMethodName = methodName.replaceAll("get", "set");
if (methodReturnedType == Integer.class) {
Integer newValue = (Integer)value;
Method setMethod = productClass.getMethod(setMethodName, Integer.class);
setMethod.invoke(originProduct, newValue);
continue;
}
if (methodReturnedType == Long.class) {
Long newValue = (Long)value;
Method setMethod = productClass.getMethod(setMethodName, Long.class);
setMethod.invoke(originProduct, newValue);
continue;
}
if (methodReturnedType == Double.class) {
Double newValue = (Double)value;
Method setMethod = productClass.getMethod(setMethodName, Double.class);
setMethod.invoke(originProduct, newValue);
continue;
}
if (methodReturnedType == Boolean.class) {
Boolean newValue = (Boolean)value;
Method setMethod = productClass.getMethod(setMethodName, Boolean.class);
setMethod.invoke(originProduct, newValue);
continue;
}

String newValue = (String)value;
Method setMethod = productClass.getMethod(setMethodName, String.class);
setMethod.invoke(originProduct, newValue);
}
}

return productRepository.save(originProduct);
}

@DeleteMapping(path = "/products/{id}")server.port=8085
public void deleteProduct(@PathVariable Long id) {
productRepository.deleteById(id);
}
}

编写完后,在 src=>main=>resources=>application.properties 添加如下配置

折叠代码块PROPERTIES 复制代码
1
2
3
4
5
6
7
8
server.port=8085
# 这里指定了端口为 8085 ,那么 h2 的数据库访问可以从如下链接进入
# http://localhost:8085/h2-console
# JDBC URL 可以改成 jdbc:h2:mem:productdb ,然后进入即可
spring.datasource.url=jdbc:h2:mem:productdb
# 普通数据库的连接同样需要下边的 用户名 和 密码 的配置
# spring.datasource.username=postgres
# spring.datasource.password=postgres

如果只需要进行简单 增删改查 的操作,那么添加 @RepositoryRestResource 注解即可。
这里返回的 JSON 格式为 HATEOAS

折叠代码块JAVA 复制代码
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
102
103
104
105
106
107
108
109
110
111
112
113
114
115
package com.example.faststart;


import org.springframework.boot.CommandLineRunner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.Bean;
import org.springframework.core.annotation.Order;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
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.core.config.Projection;
import org.springframework.data.rest.core.config.RepositoryRestConfiguration;

import jakarta.persistence.Entity;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.GenerationType;
import jakarta.persistence.Id;
import jakarta.persistence.Table;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

@SpringBootApplication
public class FaststartApplication {

public static void main(String[] args) {
SpringApplication.run(FaststartApplication.class, args);
}

// 指明一个 bean,当他处于 SpringApplication 中时,他将会被运行
// 使用 @Order 注解来指定运行的顺序
@Bean
@Order(0)
CommandLineRunner saveSomeRepositories(ProductRepository productRepository, RepositoryRestConfiguration repositoryRestConfiguration) {
return args -> {
// 设置了 @RepositoryRestResource 注解后,可以添加一些其他的配置
// 用 repositoryRestConfiguration 即可设置
// 用于为 Product 类暴露 id
repositoryRestConfiguration.exposeIdsFor(Product.class);

productRepository.save(new Product(null, "Bob", 12.1, true));
productRepository.save(new Product(null, "Stevie", 10.1, true));
productRepository.findAll().forEach(product -> {
System.out.println(product.toString());
});
};
}

@Bean
@Order(1)
CommandLineRunner run(ProductRepository productRepository) {
return args -> {
productRepository.findAll().forEach(product -> {
System.out.println(product.getId());
});
};
}
}

@Entity
@Data
@NoArgsConstructor
@AllArgsConstructor
// 指定与哪个表进行关联
// 如果使用的是 postgresql ,那么可能还需要加上 scheme 成员
@Table(name = "mytest")
class Product {
// 指定主键及其值生成策略
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String name;
private Double price;
private Boolean isInStock;
}

/**
* 添加了该 注解 将不需要再编写相关controller
*
* 获取所有数据 使用 /products
* 获取数据并排序 使用 /products?sort=name,asc
* 获取分页数据 使用 /products?page=0&size=1
* 获取不同 projection 下的数据 使用 /products?projection=web
* 根据方法名获取数据 使用 /products/search/findByNameContains?name=Bob
* 根据指定的名称获取数据 使用 /products/search/findByName?productName=Bob
*
* 获取单个数据使用 /products/{id}
*/
@RepositoryRestResource
interface ProductRepository extends JpaRepository<Product, Long>{
// 指定查询使用的名称
@RestResource(path = "/findByName")
// 指定通过其他参数进行数据查询
// @Param 用于为传入的参数指定别名
Page<Product> findByNameContains(@Param("productName") String name, Pageable pageable);
};

// 用于指定 web接口 需要暴露出的属性
@Projection(name = "web", types = Product.class)
interface WebProjection {
Long getId();
String getName();
Double getPrice();
}

// 用于指定 手机接口 需要暴露出的属性
@Projection(name = "mobile", types = Product.class)
interface MobileProjection {
Long getId();
String getName();
}

相关参考视频

点击 跳转 B站相关视频。

 评论
来发评论吧~
Powered By Valine
v1.5.2