SpringBoot构建CRUD有比这更快的方式吗?

SpringBoot构建CRUD有比这更快的方式吗?

优点

  1. 支持动态多条件分页查询
  2. 客制化逻辑代码少,这样有利于Ctrl+C/Ctrl+V、在一定程度上减少了出错的几率
  3. 支持动态构建数据库表
  4. 模式固定、学习成本非常低、开发效率高

缺点

  1. 动态多条件分页查询不支持模糊查询

基础环境配置

maven依赖

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
    <dependencies>
<!-- spring start -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<scope>runtime</scope>
<optional>true</optional>
</dependency>
<!--spring end-->

<!-- querydsl start -->
<dependency>
<groupId>com.querydsl</groupId>
<artifactId>querydsl-apt</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>com.querydsl</groupId>
<artifactId>querydsl-jpa</artifactId>
</dependency>
<!-- querydsl end-->

<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<scope>runtime</scope>
</dependency>

<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>

<dependency>
<groupId>commons-lang</groupId>
<artifactId>commons-lang</artifactId>
<version>2.6</version>
</dependency>

<dependency>
<groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>
<version>2.6</version>
</dependency>

</dependencies>

<build>

<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<source>1.8</source>
<target>1.8</target>
<compilerVersion>1.8</compilerVersion>
<encoding>UTF-8</encoding>
</configuration>
</plugin>

<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<version>${springboot.version}</version>
<configuration>
<mainClass>MainClass</mainClass>
</configuration>
<executions>
<execution>
<goals>
<goal>repackage</goal>
</goals>
</execution>
</executions>
</plugin>

<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<configuration>
<skipTests>true</skipTests>
</configuration>
</plugin>

<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
<configuration>
<archive>
<manifestEntries>
<Class-Path>conf/</Class-Path>
</manifestEntries>
</archive>
</configuration>
</plugin>

<plugin>
<groupId>com.mysema.maven</groupId>
<artifactId>apt-maven-plugin</artifactId>
<version>1.1.3</version>
<executions>
<execution>
<phase>generate-sources</phase>
<goals>
<goal>process</goal>
</goals>
<configuration>
<outputDirectory>target/generated-sources</outputDirectory>
<processor>com.querydsl.apt.jpa.JPAAnnotationProcessor</processor>
</configuration>
</execution>
</executions>
</plugin>

</plugins>
</build>

</project>

BaseEntity

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
package com.yuewen.bigdata.dataapi.entity;

import lombok.Data;

import javax.persistence.Column;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.MappedSuperclass;
import java.io.Serializable;
import java.util.Date;

/**
* 基础实体表
* Created by xiehui1956(@)gmail.com on 2020/4/23
*/
@Data
@MappedSuperclass
public class BaseEntity implements Serializable {

/**
* 主键id
*/
@Id
@GeneratedValue
private long id;

/**
* 记录状态
*/
@Column(columnDefinition = "int default 1")
private int state = 1;

public static class State {

/**
* 可用记录
*/
public static int ENABLE = 1;

/**
* 不可用记录
*/
public static int DISABLE = 2;
}

@Column(columnDefinition = "int default 1")
private int version = 1;

/**
* 描述
*/
private String description;

@Column(name = "create_time")
private Date createTime;

@Column(name = "update_time")
private Date updateTime;

/**
* 创建人
*/
@Column(name = "create_username")
private String createUsername;

/**
* 更新人
*/
@Column(name = "update_username")
private String updateUsername;
}

DbEntity

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
package com.yuewen.bigdata.dataapi.entity;

import lombok.Data;

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.Table;

/**
* 数据库表
* Created by xiehui1956(@)gmail.com on 2020/4/23
*/
@Data
@Entity
@Table(name = "bigdata_data_api_db")
public class DbEntity extends BaseEntity {

/**
* 数据库连接地址
*/
@Column(name = "db_host")
private String dbHost;

/**
* 数据库端口
*/
@Column(name = "db_port", columnDefinition = "int default 0")
private Integer dbPort = 0;

/**
* 数据库名字
*/
@Column(name = "db_name")
private String dbName;

/**
* 连接url
*/
private String url;

/**
* 连接用户名
*/
private String username;

/**
* 连接密码
*/
private String password;

}

Dao

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
package com.yuewen.bigdata.dataapi.dao.repository;

import com.yuewen.bigdata.dataapi.entity.DbEntity;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.querydsl.QuerydslPredicateExecutor;

import java.util.List;
import java.util.Set;

/**
* Created by xiehui1956(@)gmail.com on 2020/4/23
*/
public interface DbRepository extends JpaRepository<DbEntity, Long>, QuerydslPredicateExecutor<DbEntity> {

List<DbEntity> findByIdIn(Set<Long> dbIdList);
}

Service

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
package com.yuewen.bigdata.dataapi.service.mng;

import com.querydsl.core.types.Predicate;
import com.yuewen.bigdata.dataapi.dao.repository.DbRepository;
import com.yuewen.bigdata.dataapi.entity.BaseEntity;
import com.yuewen.bigdata.dataapi.entity.DbEntity;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.Date;
import java.util.Optional;

/**
* Created by xiehui1956(@)gmail.com on 2020/4/28
*/
@Service
public class MngDbService {

@Resource
private DbRepository dbRepository;

public Page<DbEntity> page(Predicate predicate, Pageable pageable) {
return dbRepository.findAll(predicate, pageable);
}

public DbEntity findById(long id) {
Optional<DbEntity> entityOptional = dbRepository.findById(id);
if (entityOptional.isPresent())
return entityOptional.get();
return null;
}

public DbEntity save(DbEntity dbEntity) {
Date now = new Date();
dbEntity.setCreateTime(now);
dbEntity.setUpdateTime(now);
dbEntity.setState(BaseEntity.State.ENABLE);
return dbRepository.save(dbEntity);
}

public void delete(long id) {
dbRepository.deleteById(id);
}

public DbEntity update(DbEntity dbEntity) {
dbEntity.setUpdateTime(new Date());
dbEntity.setVersion(dbEntity.getVersion() + 1);
return dbRepository.save(dbEntity);
}
}

Controller

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
package com.yuewen.bigdata.dataapi.controller.mng;

import com.querydsl.core.types.Predicate;
import com.yuewen.bigdata.dataapi.entity.DbEntity;
import com.yuewen.bigdata.dataapi.help.CommonResult;
import com.yuewen.bigdata.dataapi.service.mng.MngDbService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeanUtils;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.data.querydsl.binding.QuerydslPredicate;
import org.springframework.data.web.PageableDefault;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import javax.annotation.Resource;

/**
* Created by xiehui1956(@)gmail.com on 2020/4/28
*/
@RestController
@RequestMapping("/mng/db")
public class MngDbController {

private Logger logger = LoggerFactory.getLogger(getClass());

@Resource
private MngDbService mngDbService;

/**
* 名称查询
*
* @return
*/
@GetMapping("/page")
public CommonResult<Page<DbEntity>> page(@QuerydslPredicate(root = DbEntity.class) Predicate predicate
, @PageableDefault(value = 20, sort = {"id"}, direction = Sort.Direction.DESC) Pageable pageable
, CommonResult<Page<DbEntity>> commonResult) {
Page<DbEntity> page = mngDbService.page(predicate, pageable);
return commonResult.setData(page);
}

@PostMapping("/save")
public CommonResult<DbEntity> save(DbEntity dbEntity, CommonResult<DbEntity> commonResult) {
long id = dbEntity.getId();
DbEntity service = mngDbService.findById(id);
if (null == service) { //insert
dbEntity = mngDbService.save(dbEntity);
return commonResult.setData(dbEntity);
} else { //update
BeanUtils.copyProperties(dbEntity, service);
dbEntity = mngDbService.update(service);
return commonResult.setData(dbEntity);
}
}

@PostMapping("/delete")
public CommonResult delete(long id, CommonResult commonResult) {
mngDbService.delete(id);
return commonResult;
}
}

请求实例

图片

响应结果包含了:响应数据以及详细的分页信息。

总结

以上的开发模式吸引我的有两点:一点开发时只需要关心Entity表可以自动创建,这样对系统的表结构维护和二次开发提供了便捷性。

另一点是可以如此便捷的实现动态多条件分页查询。

如果有比这种方式开发效率更高、又能解决分页模糊查询的方式麻烦留言交流。感谢。