Compare commits
6 Commits
c839dfc4e3
...
53d94c5f4c
| Author | SHA1 | Date | |
|---|---|---|---|
| 53d94c5f4c | |||
| af4d13d76c | |||
| a8e8ec0ef2 | |||
| 02b9636fec | |||
| 54c12deb25 | |||
| e6a48d8e88 |
93
pom.xml
93
pom.xml
@@ -11,9 +11,11 @@
|
|||||||
|
|
||||||
<modules>
|
<modules>
|
||||||
<module>spring-boot-service-template-common</module>
|
<module>spring-boot-service-template-common</module>
|
||||||
<module>spring-boot-service-template-eq</module>
|
<module>spring-boot-service-template-database/spring-boot-service-template-database-common</module>
|
||||||
<module>spring-boot-service-template-jpa</module>
|
<module>spring-boot-service-template-database/spring-boot-service-template-database-common-test</module>
|
||||||
<module>spring-boot-service-template-xbatis</module>
|
<module>spring-boot-service-template-database/spring-boot-service-template-database-eq</module>
|
||||||
|
<module>spring-boot-service-template-database/spring-boot-service-template-database-jpa</module>
|
||||||
|
<module>spring-boot-service-template-database/spring-boot-service-template-database-xbatis</module>
|
||||||
</modules>
|
</modules>
|
||||||
|
|
||||||
<properties>
|
<properties>
|
||||||
@@ -29,6 +31,10 @@
|
|||||||
<mapstruct.version>1.6.3</mapstruct.version>
|
<mapstruct.version>1.6.3</mapstruct.version>
|
||||||
<mapstruct-plus.version>1.5.0</mapstruct-plus.version>
|
<mapstruct-plus.version>1.5.0</mapstruct-plus.version>
|
||||||
<datasource-decorator.version>2.0.0</datasource-decorator.version>
|
<datasource-decorator.version>2.0.0</datasource-decorator.version>
|
||||||
|
<easy-query.version>3.1.68</easy-query.version>
|
||||||
|
<xbatis.version>1.9.7-spring-boot4</xbatis.version>
|
||||||
|
|
||||||
|
<hutool.version>5.8.43</hutool.version>
|
||||||
</properties>
|
</properties>
|
||||||
|
|
||||||
<dependencies>
|
<dependencies>
|
||||||
@@ -36,6 +42,10 @@
|
|||||||
<groupId>org.projectlombok</groupId>
|
<groupId>org.projectlombok</groupId>
|
||||||
<artifactId>lombok</artifactId>
|
<artifactId>lombok</artifactId>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.jspecify</groupId>
|
||||||
|
<artifactId>jspecify</artifactId>
|
||||||
|
</dependency>
|
||||||
</dependencies>
|
</dependencies>
|
||||||
|
|
||||||
<dependencyManagement>
|
<dependencyManagement>
|
||||||
@@ -47,7 +57,12 @@
|
|||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>com.lanyuanxiaoyao</groupId>
|
<groupId>com.lanyuanxiaoyao</groupId>
|
||||||
<artifactId>spring-boot-service-template-jpa</artifactId>
|
<artifactId>spring-boot-service-template-database-common</artifactId>
|
||||||
|
<version>${project.version}</version>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.lanyuanxiaoyao</groupId>
|
||||||
|
<artifactId>spring-boot-service-template-database-common-test</artifactId>
|
||||||
<version>${project.version}</version>
|
<version>${project.version}</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
@@ -67,23 +82,6 @@
|
|||||||
<scope>import</scope>
|
<scope>import</scope>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
<dependency>
|
|
||||||
<groupId>com.blinkfox</groupId>
|
|
||||||
<artifactId>fenix-spring-boot-starter</artifactId>
|
|
||||||
<version>${fenix.version}</version>
|
|
||||||
</dependency>
|
|
||||||
<dependency>
|
|
||||||
<groupId>io.github.openfeign.querydsl</groupId>
|
|
||||||
<artifactId>querydsl-jpa</artifactId>
|
|
||||||
<version>${querydsl.version}</version>
|
|
||||||
</dependency>
|
|
||||||
|
|
||||||
<dependency>
|
|
||||||
<groupId>org.hibernate.orm</groupId>
|
|
||||||
<artifactId>hibernate-ant</artifactId>
|
|
||||||
<version>${hibernate.version}</version>
|
|
||||||
</dependency>
|
|
||||||
|
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.mapstruct</groupId>
|
<groupId>org.mapstruct</groupId>
|
||||||
<artifactId>mapstruct</artifactId>
|
<artifactId>mapstruct</artifactId>
|
||||||
@@ -102,20 +100,65 @@
|
|||||||
<version>${datasource-decorator.version}</version>
|
<version>${datasource-decorator.version}</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
|
<!-- jpa -->
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.jspecify</groupId>
|
<groupId>com.blinkfox</groupId>
|
||||||
<artifactId>jspecify</artifactId>
|
<artifactId>fenix-spring-boot-starter</artifactId>
|
||||||
<version>1.0.0</version>
|
<version>${fenix.version}</version>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>io.github.openfeign.querydsl</groupId>
|
||||||
|
<artifactId>querydsl-jpa</artifactId>
|
||||||
|
<version>${querydsl.version}</version>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.hibernate.orm</groupId>
|
||||||
|
<artifactId>hibernate-ant</artifactId>
|
||||||
|
<version>${hibernate.version}</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
<!-- xbatis -->
|
<!-- xbatis -->
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>cn.xbatis</groupId>
|
<groupId>cn.xbatis</groupId>
|
||||||
<artifactId>xbatis-spring-boot-parent</artifactId>
|
<artifactId>xbatis-spring-boot-parent</artifactId>
|
||||||
<version>1.9.6-spring-boot4</version>
|
<version>${xbatis.version}</version>
|
||||||
<type>pom</type>
|
<type>pom</type>
|
||||||
<scope>import</scope>
|
<scope>import</scope>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
|
<!-- easy-query -->
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.easy-query</groupId>
|
||||||
|
<artifactId>sql-springboot4-starter</artifactId>
|
||||||
|
<version>3.1.68</version>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.jspecify</groupId>
|
||||||
|
<artifactId>jspecify</artifactId>
|
||||||
|
<version>1.0.0</version>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<dependency>
|
||||||
|
<groupId>cn.hutool</groupId>
|
||||||
|
<artifactId>hutool-all</artifactId>
|
||||||
|
<version>${hutool.version}</version>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>cn.hutool</groupId>
|
||||||
|
<artifactId>hutool-core</artifactId>
|
||||||
|
<version>${hutool.version}</version>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>cn.hutool</groupId>
|
||||||
|
<artifactId>hutool-http</artifactId>
|
||||||
|
<version>${hutool.version}</version>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>cn.hutool</groupId>
|
||||||
|
<artifactId>hutool-json</artifactId>
|
||||||
|
<version>${hutool.version}</version>
|
||||||
|
</dependency>
|
||||||
</dependencies>
|
</dependencies>
|
||||||
</dependencyManagement>
|
</dependencyManagement>
|
||||||
|
|
||||||
|
|||||||
@@ -1,125 +0,0 @@
|
|||||||
package com.lanyuanxiaoyao.service.template.common.service;
|
|
||||||
|
|
||||||
import com.lanyuanxiaoyao.service.template.common.entity.Query;
|
|
||||||
import com.lanyuanxiaoyao.service.template.common.helper.ObjectHelper;
|
|
||||||
|
|
||||||
public abstract class QueryParser<O> {
|
|
||||||
protected abstract void nullEqual(Query.Queryable queryable);
|
|
||||||
|
|
||||||
protected abstract void notNullEqual(Query.Queryable queryable);
|
|
||||||
|
|
||||||
protected abstract void empty(Query.Queryable queryable);
|
|
||||||
|
|
||||||
protected abstract void notEmpty(Query.Queryable queryable);
|
|
||||||
|
|
||||||
protected abstract void equal(Query.Queryable queryable);
|
|
||||||
|
|
||||||
protected abstract void notEqual(Query.Queryable queryable);
|
|
||||||
|
|
||||||
protected abstract void like(Query.Queryable queryable);
|
|
||||||
|
|
||||||
protected abstract void notLike(Query.Queryable queryable);
|
|
||||||
|
|
||||||
protected abstract void contain(Query.Queryable queryable);
|
|
||||||
|
|
||||||
protected abstract void notContain(Query.Queryable queryable);
|
|
||||||
|
|
||||||
protected abstract void startWith(Query.Queryable queryable);
|
|
||||||
|
|
||||||
protected abstract void notStartWith(Query.Queryable queryable);
|
|
||||||
|
|
||||||
protected abstract void endWith(Query.Queryable queryable);
|
|
||||||
|
|
||||||
protected abstract void notEndWith(Query.Queryable queryable);
|
|
||||||
|
|
||||||
protected abstract void great(Query.Queryable queryable);
|
|
||||||
|
|
||||||
protected abstract void less(Query.Queryable queryable);
|
|
||||||
|
|
||||||
protected abstract void greatEqual(Query.Queryable queryable);
|
|
||||||
|
|
||||||
protected abstract void lessEqual(Query.Queryable queryable);
|
|
||||||
|
|
||||||
protected abstract void inside(Query.Queryable queryable);
|
|
||||||
|
|
||||||
protected abstract void notInside(Query.Queryable queryable);
|
|
||||||
|
|
||||||
protected abstract void between(Query.Queryable queryable);
|
|
||||||
|
|
||||||
protected abstract void notBetween(Query.Queryable queryable);
|
|
||||||
|
|
||||||
protected abstract O build();
|
|
||||||
|
|
||||||
public O build(Query.Queryable queryable) {
|
|
||||||
if (ObjectHelper.isNull(queryable)) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
if (ObjectHelper.isNotEmpty(queryable.nullEqual())) {
|
|
||||||
nullEqual(queryable);
|
|
||||||
}
|
|
||||||
if (ObjectHelper.isNotEmpty(queryable.notNullEqual())) {
|
|
||||||
notNullEqual(queryable);
|
|
||||||
}
|
|
||||||
if (ObjectHelper.isNotEmpty(queryable.empty())) {
|
|
||||||
empty(queryable);
|
|
||||||
}
|
|
||||||
if (ObjectHelper.isNotEmpty(queryable.notEmpty())) {
|
|
||||||
notEmpty(queryable);
|
|
||||||
}
|
|
||||||
if (ObjectHelper.isNotEmpty(queryable.equal())) {
|
|
||||||
equal(queryable);
|
|
||||||
}
|
|
||||||
if (ObjectHelper.isNotEmpty(queryable.notEqual())) {
|
|
||||||
notEqual(queryable);
|
|
||||||
}
|
|
||||||
if (ObjectHelper.isNotEmpty(queryable.like())) {
|
|
||||||
like(queryable);
|
|
||||||
}
|
|
||||||
if (ObjectHelper.isNotEmpty(queryable.notLike())) {
|
|
||||||
notLike(queryable);
|
|
||||||
}
|
|
||||||
if (ObjectHelper.isNotEmpty(queryable.contain())) {
|
|
||||||
contain(queryable);
|
|
||||||
}
|
|
||||||
if (ObjectHelper.isNotEmpty(queryable.notContain())) {
|
|
||||||
notContain(queryable);
|
|
||||||
}
|
|
||||||
if (ObjectHelper.isNotEmpty(queryable.startWith())) {
|
|
||||||
startWith(queryable);
|
|
||||||
}
|
|
||||||
if (ObjectHelper.isNotEmpty(queryable.notStartWith())) {
|
|
||||||
notStartWith(queryable);
|
|
||||||
}
|
|
||||||
if (ObjectHelper.isNotEmpty(queryable.endWith())) {
|
|
||||||
endWith(queryable);
|
|
||||||
}
|
|
||||||
if (ObjectHelper.isNotEmpty(queryable.notEndWith())) {
|
|
||||||
notEndWith(queryable);
|
|
||||||
}
|
|
||||||
if (ObjectHelper.isNotEmpty(queryable.great())) {
|
|
||||||
great(queryable);
|
|
||||||
}
|
|
||||||
if (ObjectHelper.isNotEmpty(queryable.less())) {
|
|
||||||
less(queryable);
|
|
||||||
}
|
|
||||||
if (ObjectHelper.isNotEmpty(queryable.greatEqual())) {
|
|
||||||
greatEqual(queryable);
|
|
||||||
}
|
|
||||||
if (ObjectHelper.isNotEmpty(queryable.lessEqual())) {
|
|
||||||
lessEqual(queryable);
|
|
||||||
}
|
|
||||||
if (ObjectHelper.isNotEmpty(queryable.inside())) {
|
|
||||||
inside(queryable);
|
|
||||||
}
|
|
||||||
if (ObjectHelper.isNotEmpty(queryable.notInside())) {
|
|
||||||
notInside(queryable);
|
|
||||||
}
|
|
||||||
if (ObjectHelper.isNotEmpty(queryable.between())) {
|
|
||||||
between(queryable);
|
|
||||||
}
|
|
||||||
if (ObjectHelper.isNotEmpty(queryable.notBetween())) {
|
|
||||||
notBetween(queryable);
|
|
||||||
}
|
|
||||||
return build();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -0,0 +1,44 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||||
|
xmlns="http://maven.apache.org/POM/4.0.0"
|
||||||
|
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||||
|
<modelVersion>4.0.0</modelVersion>
|
||||||
|
<parent>
|
||||||
|
<groupId>com.lanyuanxiaoyao</groupId>
|
||||||
|
<artifactId>spring-boot-service-template</artifactId>
|
||||||
|
<version>1.1.0-SNAPSHOT</version>
|
||||||
|
</parent>
|
||||||
|
|
||||||
|
<artifactId>spring-boot-service-template-database-common-test</artifactId>
|
||||||
|
|
||||||
|
<dependencies>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.springframework.boot</groupId>
|
||||||
|
<artifactId>spring-boot-starter-web</artifactId>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.springframework.boot</groupId>
|
||||||
|
<artifactId>spring-boot-starter-jdbc</artifactId>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.springframework.boot</groupId>
|
||||||
|
<artifactId>spring-boot-starter-test</artifactId>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.mapstruct</groupId>
|
||||||
|
<artifactId>mapstruct</artifactId>
|
||||||
|
<scope>compile</scope>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.github.gavlyukovskiy</groupId>
|
||||||
|
<artifactId>p6spy-spring-boot-starter</artifactId>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.h2database</groupId>
|
||||||
|
<artifactId>h2</artifactId>
|
||||||
|
</dependency>
|
||||||
|
</dependencies>
|
||||||
|
</project>
|
||||||
@@ -0,0 +1,234 @@
|
|||||||
|
package com.lanyuanxiaoyao.service.template.database.common.test;
|
||||||
|
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Random;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.springframework.http.HttpEntity;
|
||||||
|
import org.springframework.http.HttpHeaders;
|
||||||
|
import org.springframework.http.MediaType;
|
||||||
|
import org.springframework.util.Assert;
|
||||||
|
import org.springframework.web.client.RestTemplate;
|
||||||
|
import tools.jackson.databind.JsonNode;
|
||||||
|
import tools.jackson.databind.ObjectMapper;
|
||||||
|
|
||||||
|
@Slf4j
|
||||||
|
public class AbstractTestApplication {
|
||||||
|
private static final String BASE_URL = "http://localhost:2490";
|
||||||
|
private static final RestTemplate REST_CLIENT = new RestTemplate();
|
||||||
|
private static final ObjectMapper MAPPER = new ObjectMapper();
|
||||||
|
private static final Random random = new Random();
|
||||||
|
private static final String randomChars = "qwertyuiopasdfghjklzxcvbnmQWERTYUIOPASDFGHJKLZXCVBNM";
|
||||||
|
|
||||||
|
protected void testCrud() {
|
||||||
|
formatLog("Save");
|
||||||
|
var cid1 = saveItem("company", randomCompany("Apple")).get("data").asLong();
|
||||||
|
var cid2 = saveItem("company", randomCompany()).get("data").asLong();
|
||||||
|
var cid3 = saveItem("company", randomCompany()).get("data").asLong();
|
||||||
|
|
||||||
|
formatLog("List");
|
||||||
|
assertListItems(listItems("company"), 3, 3);
|
||||||
|
|
||||||
|
formatLog("Detail");
|
||||||
|
var company1 = detailItem("company", cid1);
|
||||||
|
Assert.isTrue(cid1 == company1.at("/data/id").asLong(), "id错误");
|
||||||
|
Assert.isTrue(company1.at("/data/name").asString("").startsWith("Apple"), "name错误");
|
||||||
|
|
||||||
|
var company2 = detailItem("company", cid2);
|
||||||
|
Assert.isTrue(cid2 == company2.at("/data/id").asLong(), "id错误");
|
||||||
|
|
||||||
|
var company3 = detailItem("company", cid3);
|
||||||
|
Assert.isTrue(cid3 == company3.at("/data/id").asLong(), "id错误");
|
||||||
|
|
||||||
|
formatLog("List Page");
|
||||||
|
// language=JSON
|
||||||
|
var pageRequest = """
|
||||||
|
{
|
||||||
|
"page": {
|
||||||
|
"index": 1,
|
||||||
|
"size": 2
|
||||||
|
}
|
||||||
|
}
|
||||||
|
""";
|
||||||
|
assertListItems(listItems("company", pageRequest), 2, 3);
|
||||||
|
|
||||||
|
formatLog("List Queryable");
|
||||||
|
// language=JSON
|
||||||
|
var queryRequest = """
|
||||||
|
{
|
||||||
|
"query": {
|
||||||
|
"notNullEqual": [
|
||||||
|
"name"
|
||||||
|
],
|
||||||
|
"equal": {
|
||||||
|
"name": "Apple"
|
||||||
|
},
|
||||||
|
"like": {
|
||||||
|
"name": "Appl%"
|
||||||
|
},
|
||||||
|
"contain": {
|
||||||
|
"name": "ple"
|
||||||
|
},
|
||||||
|
"startWith": {
|
||||||
|
"name": "Appl"
|
||||||
|
},
|
||||||
|
"endWith": {
|
||||||
|
"name": "le"
|
||||||
|
},
|
||||||
|
"less": {
|
||||||
|
"members": 100
|
||||||
|
},
|
||||||
|
"greatEqual": {
|
||||||
|
"members": 0,
|
||||||
|
"createdTime": "2025-01-01 00:00:00"
|
||||||
|
},
|
||||||
|
"inside": {
|
||||||
|
"name": [
|
||||||
|
"Apple",
|
||||||
|
"Banana"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"between": {
|
||||||
|
"members": {
|
||||||
|
"start": 0,
|
||||||
|
"end": 100
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"page": {
|
||||||
|
"index": 1,
|
||||||
|
"size": 2
|
||||||
|
}
|
||||||
|
}
|
||||||
|
""";
|
||||||
|
assertListItems(listItems("company", queryRequest), 1, 1);
|
||||||
|
|
||||||
|
formatLog("Clean");
|
||||||
|
removeItem("company", cid1);
|
||||||
|
assertListItems(listItems("company"), 2, 2);
|
||||||
|
removeItem("company", cid2);
|
||||||
|
removeItem("company", cid3);
|
||||||
|
assertListItems(listItems("company"), 0, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void assertListItems(JsonNode node, int itemSizeTarget, int itemTotalTarget) {
|
||||||
|
var itemSize = node.at("/data/items").size();
|
||||||
|
var itemTotal = node.at("/data/total").asLong();
|
||||||
|
Assert.isTrue(itemSize == itemSizeTarget, "数量错误 (%d)".formatted(itemSize));
|
||||||
|
Assert.isTrue(itemTotal == itemTotalTarget, "分页总数错误 (%d)".formatted(itemTotal));
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void formatLog(String text) {
|
||||||
|
log.info("===== {} =====", text);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected Map<String, Object> randomCompany() {
|
||||||
|
return randomCompany(randomString(10));
|
||||||
|
}
|
||||||
|
|
||||||
|
protected Map<String, Object> randomCompany(String name) {
|
||||||
|
return Map.of(
|
||||||
|
"name", name,
|
||||||
|
"members", randomInt(100)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected Map<String, Object> randomEmployee(Long companyId) {
|
||||||
|
return randomEmployee(companyId, randomString(10));
|
||||||
|
}
|
||||||
|
|
||||||
|
protected Map<String, Object> randomEmployee(Long companyId, String name) {
|
||||||
|
return Map.of(
|
||||||
|
"name", name,
|
||||||
|
"age", randomInt(100),
|
||||||
|
"companyId", companyId
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected Map<String, Object> randomReport(Long employeeId) {
|
||||||
|
return Map.of(
|
||||||
|
"score", randomDouble(200),
|
||||||
|
"level", randomChar("ABCDE"),
|
||||||
|
"employeeId", employeeId
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected String randomString(String prefix, int length) {
|
||||||
|
return prefix + randomString(length);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected String randomString(int length) {
|
||||||
|
var builder = new StringBuilder();
|
||||||
|
for (int i = 0; i < length; i++) {
|
||||||
|
builder.append(randomChars.charAt(random.nextInt(randomChars.length())));
|
||||||
|
}
|
||||||
|
return builder.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected String randomChar(String base) {
|
||||||
|
return base.charAt(randomInt(base.length())) + "";
|
||||||
|
}
|
||||||
|
|
||||||
|
protected int randomInt(int bound) {
|
||||||
|
return random.nextInt(1, bound);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected double randomDouble(int bound) {
|
||||||
|
return random.nextDouble(1, bound);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected HttpHeaders headers() {
|
||||||
|
var headers = new HttpHeaders();
|
||||||
|
headers.setContentType(MediaType.APPLICATION_JSON);
|
||||||
|
return headers;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected JsonNode saveItem(String path, Object body) {
|
||||||
|
var response = REST_CLIENT.postForEntity(
|
||||||
|
"%s/%s/save".formatted(BASE_URL, path),
|
||||||
|
new HttpEntity<>(body, headers()),
|
||||||
|
String.class
|
||||||
|
);
|
||||||
|
Assert.isTrue(response.getStatusCode().is2xxSuccessful(), "请求失败");
|
||||||
|
Assert.notNull(response.getBody(), "请求失败");
|
||||||
|
return MAPPER.readTree(response.getBody());
|
||||||
|
}
|
||||||
|
|
||||||
|
protected JsonNode listItems(String path) {
|
||||||
|
var response = REST_CLIENT.getForEntity(
|
||||||
|
"%s/%s/list".formatted(BASE_URL, path),
|
||||||
|
String.class
|
||||||
|
);
|
||||||
|
Assert.isTrue(response.getStatusCode().is2xxSuccessful(), "请求失败");
|
||||||
|
Assert.notNull(response.getBody(), "请求失败");
|
||||||
|
return MAPPER.readTree(response.getBody());
|
||||||
|
}
|
||||||
|
|
||||||
|
protected JsonNode listItems(String path, String query) {
|
||||||
|
var response = REST_CLIENT.postForEntity(
|
||||||
|
"%s/%s/list".formatted(BASE_URL, path),
|
||||||
|
new HttpEntity<>(query, headers()),
|
||||||
|
String.class
|
||||||
|
);
|
||||||
|
Assert.isTrue(response.getStatusCode().is2xxSuccessful(), "请求失败");
|
||||||
|
Assert.notNull(response.getBody(), "请求失败");
|
||||||
|
return MAPPER.readTree(response.getBody());
|
||||||
|
}
|
||||||
|
|
||||||
|
protected JsonNode detailItem(String path, Long id) {
|
||||||
|
var response = REST_CLIENT.getForEntity(
|
||||||
|
"%s/%s/detail/%d".formatted(BASE_URL, path, id),
|
||||||
|
String.class
|
||||||
|
);
|
||||||
|
Assert.isTrue(response.getStatusCode().is2xxSuccessful(), "请求失败");
|
||||||
|
Assert.notNull(response.getBody(), "请求失败");
|
||||||
|
return MAPPER.readTree(response.getBody());
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void removeItem(String path, Long id) {
|
||||||
|
var response = REST_CLIENT.getForEntity(
|
||||||
|
"%s/%s/remove/%d".formatted(BASE_URL, path, id),
|
||||||
|
Void.class
|
||||||
|
);
|
||||||
|
Assert.isTrue(response.getStatusCode().is2xxSuccessful(), "请求失败");
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,14 @@
|
|||||||
|
package com.lanyuanxiaoyao.service.template.database.common.test.entity;
|
||||||
|
|
||||||
|
public enum Industry {
|
||||||
|
TECHNOLOGY,
|
||||||
|
FINANCE,
|
||||||
|
MEDIA,
|
||||||
|
SERVICE,
|
||||||
|
GOVERNMENT,
|
||||||
|
EDUCATION,
|
||||||
|
HEALTHCARE,
|
||||||
|
CONSTRUCTION,
|
||||||
|
RETAIL,
|
||||||
|
OTHER,
|
||||||
|
}
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
package com.lanyuanxiaoyao.service.template.database.common.test.entity;
|
||||||
|
|
||||||
|
public enum Level {
|
||||||
|
A, B, C, D, E
|
||||||
|
}
|
||||||
@@ -0,0 +1,12 @@
|
|||||||
|
server:
|
||||||
|
port: 2490
|
||||||
|
decorator:
|
||||||
|
datasource:
|
||||||
|
p6spy:
|
||||||
|
multiline: false
|
||||||
|
exclude-categories:
|
||||||
|
- commit
|
||||||
|
- result
|
||||||
|
- resultset
|
||||||
|
- rollback
|
||||||
|
log-format: "%(category)|%(executionTime)|%(sqlSingleLine)"
|
||||||
@@ -0,0 +1,20 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||||
|
xmlns="http://maven.apache.org/POM/4.0.0"
|
||||||
|
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||||
|
<modelVersion>4.0.0</modelVersion>
|
||||||
|
<parent>
|
||||||
|
<groupId>com.lanyuanxiaoyao</groupId>
|
||||||
|
<artifactId>spring-boot-service-template</artifactId>
|
||||||
|
<version>1.1.0-SNAPSHOT</version>
|
||||||
|
</parent>
|
||||||
|
|
||||||
|
<artifactId>spring-boot-service-template-database-common</artifactId>
|
||||||
|
|
||||||
|
<dependencies>
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.lanyuanxiaoyao</groupId>
|
||||||
|
<artifactId>spring-boot-service-template-common</artifactId>
|
||||||
|
</dependency>
|
||||||
|
</dependencies>
|
||||||
|
</project>
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
package com.lanyuanxiaoyao.service.template.common.controller;
|
package com.lanyuanxiaoyao.service.template.database.common.controller;
|
||||||
|
|
||||||
import com.lanyuanxiaoyao.service.template.common.entity.GlobalResponse;
|
import com.lanyuanxiaoyao.service.template.database.common.entity.GlobalResponse;
|
||||||
import com.lanyuanxiaoyao.service.template.common.entity.Query;
|
import com.lanyuanxiaoyao.service.template.database.common.entity.Query;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 查询控制器接口,用于定义统一的查询实体详情和列表的接口规范
|
* 查询控制器接口,用于定义统一的查询实体详情和列表的接口规范
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
package com.lanyuanxiaoyao.service.template.common.controller;
|
package com.lanyuanxiaoyao.service.template.database.common.controller;
|
||||||
|
|
||||||
import com.lanyuanxiaoyao.service.template.common.entity.GlobalResponse;
|
import com.lanyuanxiaoyao.service.template.database.common.entity.GlobalResponse;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 删除控制器接口,用于定义统一的删除实体对象的接口规范
|
* 删除控制器接口,用于定义统一的删除实体对象的接口规范
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
package com.lanyuanxiaoyao.service.template.common.controller;
|
package com.lanyuanxiaoyao.service.template.database.common.controller;
|
||||||
|
|
||||||
import com.lanyuanxiaoyao.service.template.common.entity.GlobalResponse;
|
import com.lanyuanxiaoyao.service.template.database.common.entity.GlobalResponse;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 保存控制器接口,用于定义统一的保存实体对象的接口规范
|
* 保存控制器接口,用于定义统一的保存实体对象的接口规范
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
package com.lanyuanxiaoyao.service.template.common.controller;
|
package com.lanyuanxiaoyao.service.template.database.common.controller;
|
||||||
|
|
||||||
public interface SimpleController<SAVE_ITEM, LIST_ITEM, DETAIL_ITEM> extends SaveController<SAVE_ITEM>, QueryController<LIST_ITEM, DETAIL_ITEM>, RemoveController {
|
public interface SimpleController<SAVE_ITEM, LIST_ITEM, DETAIL_ITEM> extends SaveController<SAVE_ITEM>, QueryController<LIST_ITEM, DETAIL_ITEM>, RemoveController {
|
||||||
}
|
}
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
package com.lanyuanxiaoyao.service.template.common.entity;
|
package com.lanyuanxiaoyao.service.template.database.common.entity;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
package com.lanyuanxiaoyao.service.template.common.entity;
|
package com.lanyuanxiaoyao.service.template.database.common.entity;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
package com.lanyuanxiaoyao.service.template.common.entity;
|
package com.lanyuanxiaoyao.service.template.database.common.entity;
|
||||||
|
|
||||||
import java.io.Serializable;
|
import java.io.Serializable;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
package com.lanyuanxiaoyao.service.template.common.exception;
|
package com.lanyuanxiaoyao.service.template.database.common.exception;
|
||||||
|
|
||||||
public class IdNotFoundException extends RuntimeException {
|
public class IdNotFoundException extends RuntimeException {
|
||||||
public IdNotFoundException(Long id) {
|
public IdNotFoundException(Long id) {
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
package com.lanyuanxiaoyao.service.template.common.exception;
|
package com.lanyuanxiaoyao.service.template.database.common.exception;
|
||||||
|
|
||||||
public class NotCollectionException extends RuntimeException {
|
public class NotCollectionException extends RuntimeException {
|
||||||
public NotCollectionException(String variable) {
|
public NotCollectionException(String variable) {
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
package com.lanyuanxiaoyao.service.template.common.exception;
|
package com.lanyuanxiaoyao.service.template.database.common.exception;
|
||||||
|
|
||||||
public class NotComparableException extends RuntimeException {
|
public class NotComparableException extends RuntimeException {
|
||||||
public NotComparableException(String variable) {
|
public NotComparableException(String variable) {
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
package com.lanyuanxiaoyao.service.template.common.exception;
|
package com.lanyuanxiaoyao.service.template.database.common.exception;
|
||||||
|
|
||||||
public class NotStringException extends RuntimeException {
|
public class NotStringException extends RuntimeException {
|
||||||
public NotStringException(String variable) {
|
public NotStringException(String variable) {
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
package com.lanyuanxiaoyao.service.template.common.helper;
|
package com.lanyuanxiaoyao.service.template.database.common.helper;
|
||||||
|
|
||||||
import java.time.Instant;
|
import java.time.Instant;
|
||||||
|
|
||||||
@@ -0,0 +1,128 @@
|
|||||||
|
package com.lanyuanxiaoyao.service.template.database.common.service;
|
||||||
|
|
||||||
|
import com.lanyuanxiaoyao.service.template.common.helper.ObjectHelper;
|
||||||
|
import com.lanyuanxiaoyao.service.template.database.common.entity.Query;
|
||||||
|
import lombok.AccessLevel;
|
||||||
|
import lombok.RequiredArgsConstructor;
|
||||||
|
|
||||||
|
@RequiredArgsConstructor(access = AccessLevel.PROTECTED)
|
||||||
|
public abstract class QueryParser<O> {
|
||||||
|
private final Query.Queryable queryable;
|
||||||
|
private final O container;
|
||||||
|
|
||||||
|
protected abstract void nullEqual(Query.Queryable queryable, O container);
|
||||||
|
|
||||||
|
protected abstract void notNullEqual(Query.Queryable queryable, O container);
|
||||||
|
|
||||||
|
protected abstract void empty(Query.Queryable queryable, O container);
|
||||||
|
|
||||||
|
protected abstract void notEmpty(Query.Queryable queryable, O container);
|
||||||
|
|
||||||
|
protected abstract void equal(Query.Queryable queryable, O container);
|
||||||
|
|
||||||
|
protected abstract void notEqual(Query.Queryable queryable, O container);
|
||||||
|
|
||||||
|
protected abstract void like(Query.Queryable queryable, O container);
|
||||||
|
|
||||||
|
protected abstract void notLike(Query.Queryable queryable, O container);
|
||||||
|
|
||||||
|
protected abstract void contain(Query.Queryable queryable, O container);
|
||||||
|
|
||||||
|
protected abstract void notContain(Query.Queryable queryable, O container);
|
||||||
|
|
||||||
|
protected abstract void startWith(Query.Queryable queryable, O container);
|
||||||
|
|
||||||
|
protected abstract void notStartWith(Query.Queryable queryable, O container);
|
||||||
|
|
||||||
|
protected abstract void endWith(Query.Queryable queryable, O container);
|
||||||
|
|
||||||
|
protected abstract void notEndWith(Query.Queryable queryable, O container);
|
||||||
|
|
||||||
|
protected abstract void great(Query.Queryable queryable, O container);
|
||||||
|
|
||||||
|
protected abstract void less(Query.Queryable queryable, O container);
|
||||||
|
|
||||||
|
protected abstract void greatEqual(Query.Queryable queryable, O container);
|
||||||
|
|
||||||
|
protected abstract void lessEqual(Query.Queryable queryable, O container);
|
||||||
|
|
||||||
|
protected abstract void inside(Query.Queryable queryable, O container);
|
||||||
|
|
||||||
|
protected abstract void notInside(Query.Queryable queryable, O container);
|
||||||
|
|
||||||
|
protected abstract void between(Query.Queryable queryable, O container);
|
||||||
|
|
||||||
|
protected abstract void notBetween(Query.Queryable queryable, O container);
|
||||||
|
|
||||||
|
public void build() {
|
||||||
|
if (ObjectHelper.isNull(queryable)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (ObjectHelper.isNotEmpty(queryable.nullEqual())) {
|
||||||
|
nullEqual(queryable, container);
|
||||||
|
}
|
||||||
|
if (ObjectHelper.isNotEmpty(queryable.notNullEqual())) {
|
||||||
|
notNullEqual(queryable, container);
|
||||||
|
}
|
||||||
|
if (ObjectHelper.isNotEmpty(queryable.empty())) {
|
||||||
|
empty(queryable, container);
|
||||||
|
}
|
||||||
|
if (ObjectHelper.isNotEmpty(queryable.notEmpty())) {
|
||||||
|
notEmpty(queryable, container);
|
||||||
|
}
|
||||||
|
if (ObjectHelper.isNotEmpty(queryable.equal())) {
|
||||||
|
equal(queryable, container);
|
||||||
|
}
|
||||||
|
if (ObjectHelper.isNotEmpty(queryable.notEqual())) {
|
||||||
|
notEqual(queryable, container);
|
||||||
|
}
|
||||||
|
if (ObjectHelper.isNotEmpty(queryable.like())) {
|
||||||
|
like(queryable, container);
|
||||||
|
}
|
||||||
|
if (ObjectHelper.isNotEmpty(queryable.notLike())) {
|
||||||
|
notLike(queryable, container);
|
||||||
|
}
|
||||||
|
if (ObjectHelper.isNotEmpty(queryable.contain())) {
|
||||||
|
contain(queryable, container);
|
||||||
|
}
|
||||||
|
if (ObjectHelper.isNotEmpty(queryable.notContain())) {
|
||||||
|
notContain(queryable, container);
|
||||||
|
}
|
||||||
|
if (ObjectHelper.isNotEmpty(queryable.startWith())) {
|
||||||
|
startWith(queryable, container);
|
||||||
|
}
|
||||||
|
if (ObjectHelper.isNotEmpty(queryable.notStartWith())) {
|
||||||
|
notStartWith(queryable, container);
|
||||||
|
}
|
||||||
|
if (ObjectHelper.isNotEmpty(queryable.endWith())) {
|
||||||
|
endWith(queryable, container);
|
||||||
|
}
|
||||||
|
if (ObjectHelper.isNotEmpty(queryable.notEndWith())) {
|
||||||
|
notEndWith(queryable, container);
|
||||||
|
}
|
||||||
|
if (ObjectHelper.isNotEmpty(queryable.great())) {
|
||||||
|
great(queryable, container);
|
||||||
|
}
|
||||||
|
if (ObjectHelper.isNotEmpty(queryable.less())) {
|
||||||
|
less(queryable, container);
|
||||||
|
}
|
||||||
|
if (ObjectHelper.isNotEmpty(queryable.greatEqual())) {
|
||||||
|
greatEqual(queryable, container);
|
||||||
|
}
|
||||||
|
if (ObjectHelper.isNotEmpty(queryable.lessEqual())) {
|
||||||
|
lessEqual(queryable, container);
|
||||||
|
}
|
||||||
|
if (ObjectHelper.isNotEmpty(queryable.inside())) {
|
||||||
|
inside(queryable, container);
|
||||||
|
}
|
||||||
|
if (ObjectHelper.isNotEmpty(queryable.notInside())) {
|
||||||
|
notInside(queryable, container);
|
||||||
|
}
|
||||||
|
if (ObjectHelper.isNotEmpty(queryable.between())) {
|
||||||
|
between(queryable, container);
|
||||||
|
}
|
||||||
|
if (ObjectHelper.isNotEmpty(queryable.notBetween())) {
|
||||||
|
notBetween(queryable, container);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
package com.lanyuanxiaoyao.service.template.common.service;
|
package com.lanyuanxiaoyao.service.template.database.common.service;
|
||||||
|
|
||||||
import com.lanyuanxiaoyao.service.template.common.entity.Page;
|
import com.lanyuanxiaoyao.service.template.database.common.entity.Page;
|
||||||
import com.lanyuanxiaoyao.service.template.common.entity.Query;
|
import com.lanyuanxiaoyao.service.template.database.common.entity.Query;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
package com.lanyuanxiaoyao.service.template.common.service;
|
package com.lanyuanxiaoyao.service.template.database.common.service;
|
||||||
|
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
package com.lanyuanxiaoyao.service.template.common.service;
|
package com.lanyuanxiaoyao.service.template.database.common.service;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 保存服务接口,用于定义统一的保存实体对象的服务规范
|
* 保存服务接口,用于定义统一的保存实体对象的服务规范
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
package com.lanyuanxiaoyao.service.template.common.service;
|
package com.lanyuanxiaoyao.service.template.database.common.service;
|
||||||
|
|
||||||
public interface SimpleService<ENTITY> extends SaveService<ENTITY>, QueryService<ENTITY>, RemoveService<ENTITY> {
|
public interface SimpleService<ENTITY> extends SaveService<ENTITY>, QueryService<ENTITY>, RemoveService<ENTITY> {
|
||||||
}
|
}
|
||||||
@@ -9,37 +9,28 @@
|
|||||||
<version>1.1.0-SNAPSHOT</version>
|
<version>1.1.0-SNAPSHOT</version>
|
||||||
</parent>
|
</parent>
|
||||||
|
|
||||||
<artifactId>spring-boot-service-template-eq</artifactId>
|
<artifactId>spring-boot-service-template-database-eq</artifactId>
|
||||||
|
|
||||||
<dependencies>
|
<dependencies>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>com.lanyuanxiaoyao</groupId>
|
<groupId>com.lanyuanxiaoyao</groupId>
|
||||||
<artifactId>spring-boot-service-template-common</artifactId>
|
<artifactId>spring-boot-service-template-database-common</artifactId>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.springframework.boot</groupId>
|
<groupId>org.springframework.boot</groupId>
|
||||||
<artifactId>spring-boot-starter-web</artifactId>
|
<artifactId>spring-boot-starter-web</artifactId>
|
||||||
|
<scope>provided</scope>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>com.easy-query</groupId>
|
<groupId>com.easy-query</groupId>
|
||||||
<artifactId>sql-springboot4-starter</artifactId>
|
<artifactId>sql-springboot4-starter</artifactId>
|
||||||
<version>3.1.68</version>
|
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>com.github.gavlyukovskiy</groupId>
|
<groupId>com.lanyuanxiaoyao</groupId>
|
||||||
<artifactId>p6spy-spring-boot-starter</artifactId>
|
<artifactId>spring-boot-service-template-database-common-test</artifactId>
|
||||||
</dependency>
|
|
||||||
|
|
||||||
<dependency>
|
|
||||||
<groupId>org.jspecify</groupId>
|
|
||||||
<artifactId>jspecify</artifactId>
|
|
||||||
</dependency>
|
|
||||||
|
|
||||||
<dependency>
|
|
||||||
<groupId>com.h2database</groupId>
|
|
||||||
<artifactId>h2</artifactId>
|
|
||||||
<scope>test</scope>
|
<scope>test</scope>
|
||||||
</dependency>
|
</dependency>
|
||||||
</dependencies>
|
</dependencies>
|
||||||
@@ -70,7 +61,7 @@
|
|||||||
<path>
|
<path>
|
||||||
<groupId>com.easy-query</groupId>
|
<groupId>com.easy-query</groupId>
|
||||||
<artifactId>sql-processor</artifactId>
|
<artifactId>sql-processor</artifactId>
|
||||||
<version>3.1.68</version>
|
<version>${easy-query.version}</version>
|
||||||
</path>
|
</path>
|
||||||
</annotationProcessorPaths>
|
</annotationProcessorPaths>
|
||||||
</configuration>
|
</configuration>
|
||||||
@@ -1,13 +1,13 @@
|
|||||||
package com.lanyuanxiaoyao.service.template.eq.controller;
|
package com.lanyuanxiaoyao.service.template.database.eq.controller;
|
||||||
|
|
||||||
import com.easy.query.core.proxy.AbstractProxyEntity;
|
import com.easy.query.core.proxy.AbstractProxyEntity;
|
||||||
import com.easy.query.core.proxy.ProxyEntityAvailable;
|
import com.easy.query.core.proxy.ProxyEntityAvailable;
|
||||||
import com.lanyuanxiaoyao.service.template.common.controller.SimpleController;
|
|
||||||
import com.lanyuanxiaoyao.service.template.common.entity.GlobalResponse;
|
|
||||||
import com.lanyuanxiaoyao.service.template.common.entity.Query;
|
|
||||||
import com.lanyuanxiaoyao.service.template.common.helper.ObjectHelper;
|
import com.lanyuanxiaoyao.service.template.common.helper.ObjectHelper;
|
||||||
import com.lanyuanxiaoyao.service.template.eq.entity.SimpleEntity;
|
import com.lanyuanxiaoyao.service.template.database.common.controller.SimpleController;
|
||||||
import com.lanyuanxiaoyao.service.template.eq.service.SimpleServiceSupport;
|
import com.lanyuanxiaoyao.service.template.database.common.entity.GlobalResponse;
|
||||||
|
import com.lanyuanxiaoyao.service.template.database.common.entity.Query;
|
||||||
|
import com.lanyuanxiaoyao.service.template.database.eq.entity.SimpleEntity;
|
||||||
|
import com.lanyuanxiaoyao.service.template.database.eq.service.SimpleServiceSupport;
|
||||||
import java.util.function.Function;
|
import java.util.function.Function;
|
||||||
import lombok.RequiredArgsConstructor;
|
import lombok.RequiredArgsConstructor;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
package com.lanyuanxiaoyao.service.template.eq.entity;
|
package com.lanyuanxiaoyao.service.template.database.eq.entity;
|
||||||
|
|
||||||
import com.easy.query.core.annotation.Column;
|
import com.easy.query.core.annotation.Column;
|
||||||
import lombok.Getter;
|
import lombok.Getter;
|
||||||
@@ -0,0 +1,16 @@
|
|||||||
|
package com.lanyuanxiaoyao.service.template.database.eq.entity;
|
||||||
|
|
||||||
|
import com.easy.query.core.annotation.LogicDelete;
|
||||||
|
import lombok.Getter;
|
||||||
|
import lombok.Setter;
|
||||||
|
import lombok.ToString;
|
||||||
|
import lombok.experimental.FieldNameConstants;
|
||||||
|
|
||||||
|
@Getter
|
||||||
|
@Setter
|
||||||
|
@ToString
|
||||||
|
@FieldNameConstants
|
||||||
|
public class LogicDeleteEntity extends IdOnlyEntity {
|
||||||
|
@LogicDelete
|
||||||
|
private Boolean deleted = false;
|
||||||
|
}
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
package com.lanyuanxiaoyao.service.template.eq.entity;
|
package com.lanyuanxiaoyao.service.template.database.eq.entity;
|
||||||
|
|
||||||
import java.time.LocalDateTime;
|
import java.time.LocalDateTime;
|
||||||
import lombok.Getter;
|
import lombok.Getter;
|
||||||
@@ -10,7 +10,7 @@ import lombok.experimental.FieldNameConstants;
|
|||||||
@Setter
|
@Setter
|
||||||
@ToString(callSuper = true)
|
@ToString(callSuper = true)
|
||||||
@FieldNameConstants
|
@FieldNameConstants
|
||||||
public class SimpleEntity extends IdOnlyEntity {
|
public class SimpleEntity extends LogicDeleteEntity {
|
||||||
private LocalDateTime createdTime;
|
private LocalDateTime createdTime;
|
||||||
private LocalDateTime modifiedTime;
|
private LocalDateTime modifiedTime;
|
||||||
}
|
}
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
package com.lanyuanxiaoyao.service.template.eq.entity;
|
package com.lanyuanxiaoyao.service.template.database.eq.entity;
|
||||||
|
|
||||||
import com.easy.query.core.basic.extension.generated.PrimaryKeyGenerator;
|
import com.easy.query.core.basic.extension.generated.PrimaryKeyGenerator;
|
||||||
import com.lanyuanxiaoyao.service.template.common.helper.SnowflakeHelper;
|
import com.lanyuanxiaoyao.service.template.database.common.helper.SnowflakeHelper;
|
||||||
import java.io.Serializable;
|
import java.io.Serializable;
|
||||||
import org.springframework.stereotype.Component;
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
@@ -1,22 +1,24 @@
|
|||||||
package com.lanyuanxiaoyao.service.template.eq.service;
|
package com.lanyuanxiaoyao.service.template.database.eq.service;
|
||||||
|
|
||||||
import com.easy.query.api.proxy.client.EasyEntityQuery;
|
import com.easy.query.api.proxy.client.EasyEntityQuery;
|
||||||
import com.easy.query.core.enums.SQLExecuteStrategyEnum;
|
import com.easy.query.core.enums.SQLExecuteStrategyEnum;
|
||||||
import com.easy.query.core.proxy.AbstractProxyEntity;
|
import com.easy.query.core.proxy.AbstractProxyEntity;
|
||||||
import com.easy.query.core.proxy.ProxyEntityAvailable;
|
import com.easy.query.core.proxy.ProxyEntityAvailable;
|
||||||
import com.lanyuanxiaoyao.service.template.common.entity.Page;
|
|
||||||
import com.lanyuanxiaoyao.service.template.common.entity.Query;
|
|
||||||
import com.lanyuanxiaoyao.service.template.common.exception.IdNotFoundException;
|
|
||||||
import com.lanyuanxiaoyao.service.template.common.helper.ObjectHelper;
|
import com.lanyuanxiaoyao.service.template.common.helper.ObjectHelper;
|
||||||
import com.lanyuanxiaoyao.service.template.common.service.QueryParser;
|
import com.lanyuanxiaoyao.service.template.database.common.entity.Page;
|
||||||
import com.lanyuanxiaoyao.service.template.common.service.SimpleService;
|
import com.lanyuanxiaoyao.service.template.database.common.entity.Query;
|
||||||
import com.lanyuanxiaoyao.service.template.eq.entity.SimpleEntity;
|
import com.lanyuanxiaoyao.service.template.database.common.exception.IdNotFoundException;
|
||||||
|
import com.lanyuanxiaoyao.service.template.database.common.service.QueryParser;
|
||||||
|
import com.lanyuanxiaoyao.service.template.database.common.service.SimpleService;
|
||||||
|
import com.lanyuanxiaoyao.service.template.database.eq.entity.SimpleEntity;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
import lombok.RequiredArgsConstructor;
|
import lombok.RequiredArgsConstructor;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.mapstruct.Named;
|
||||||
|
import org.springframework.transaction.annotation.Transactional;
|
||||||
|
|
||||||
@Slf4j
|
@Slf4j
|
||||||
@RequiredArgsConstructor
|
@RequiredArgsConstructor
|
||||||
@@ -27,6 +29,7 @@ public abstract class SimpleServiceSupport<ENTITY extends SimpleEntity & ProxyEn
|
|||||||
protected final EasyEntityQuery entityQuery;
|
protected final EasyEntityQuery entityQuery;
|
||||||
private final Class<ENTITY> target;
|
private final Class<ENTITY> target;
|
||||||
|
|
||||||
|
@Transactional(rollbackFor = Throwable.class)
|
||||||
@Override
|
@Override
|
||||||
public Long save(ENTITY entity) {
|
public Long save(ENTITY entity) {
|
||||||
if (ObjectHelper.isNull(entity.getId())) {
|
if (ObjectHelper.isNull(entity.getId())) {
|
||||||
@@ -39,6 +42,7 @@ public abstract class SimpleServiceSupport<ENTITY extends SimpleEntity & ProxyEn
|
|||||||
return entity.getId();
|
return entity.getId();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Transactional(rollbackFor = Throwable.class)
|
||||||
@Override
|
@Override
|
||||||
public void save(Iterable<ENTITY> entities) {
|
public void save(Iterable<ENTITY> entities) {
|
||||||
var insertList = new ArrayList<ENTITY>();
|
var insertList = new ArrayList<ENTITY>();
|
||||||
@@ -94,7 +98,7 @@ public abstract class SimpleServiceSupport<ENTITY extends SimpleEntity & ProxyEn
|
|||||||
|
|
||||||
var result = entityQuery.queryable(target)
|
var result = entityQuery.queryable(target)
|
||||||
.where(this::commonPredicates)
|
.where(this::commonPredicates)
|
||||||
.where(proxy -> new EqQueryParser<ENTITY, PROXY>(proxy).build(query.query()))
|
.where(proxy -> new EqQueryParser<ENTITY, PROXY>(query.query(), proxy).build())
|
||||||
.orderBy(ObjectHelper.isNotEmpty(query.sort()), proxy -> query.sort().forEach(sort -> proxy.anyColumn(sort.column()).orderBy(Query.Sortable.Direction.ASC.equals(sort.direction()))))
|
.orderBy(ObjectHelper.isNotEmpty(query.sort()), proxy -> query.sort().forEach(sort -> proxy.anyColumn(sort.column()).orderBy(Query.Sortable.Direction.ASC.equals(sort.direction()))))
|
||||||
.toPageResult(index, size);
|
.toPageResult(index, size);
|
||||||
|
|
||||||
@@ -110,16 +114,19 @@ public abstract class SimpleServiceSupport<ENTITY extends SimpleEntity & ProxyEn
|
|||||||
.singleOptional();
|
.singleOptional();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Named("detail")
|
||||||
@Override
|
@Override
|
||||||
public ENTITY detail(Long id) {
|
public ENTITY detail(Long id) {
|
||||||
return detailOptional(id).orElse(null);
|
return detailOptional(id).orElse(null);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Named("detailOrThrow")
|
||||||
@Override
|
@Override
|
||||||
public ENTITY detailOrThrow(Long id) {
|
public ENTITY detailOrThrow(Long id) {
|
||||||
return detailOptional(id).orElseThrow(() -> new IdNotFoundException(id));
|
return detailOptional(id).orElseThrow(() -> new IdNotFoundException(id));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Transactional(rollbackFor = Throwable.class)
|
||||||
@Override
|
@Override
|
||||||
public void remove(Long id) {
|
public void remove(Long id) {
|
||||||
if (ObjectHelper.isNotNull(id)) {
|
if (ObjectHelper.isNotNull(id)) {
|
||||||
@@ -130,6 +137,7 @@ public abstract class SimpleServiceSupport<ENTITY extends SimpleEntity & ProxyEn
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Transactional(rollbackFor = Throwable.class)
|
||||||
@Override
|
@Override
|
||||||
public void remove(Set<Long> ids) {
|
public void remove(Set<Long> ids) {
|
||||||
if (ObjectHelper.isNotEmpty(ids)) {
|
if (ObjectHelper.isNotEmpty(ids)) {
|
||||||
@@ -140,102 +148,103 @@ public abstract class SimpleServiceSupport<ENTITY extends SimpleEntity & ProxyEn
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@RequiredArgsConstructor
|
private static final class EqQueryParser<ENTITY extends SimpleEntity & ProxyEntityAvailable<ENTITY, PROXY>, PROXY extends AbstractProxyEntity<PROXY, ENTITY>> extends QueryParser<PROXY> {
|
||||||
private static final class EqQueryParser<ENTITY extends SimpleEntity & ProxyEntityAvailable<ENTITY, PROXY>, PROXY extends AbstractProxyEntity<PROXY, ENTITY>> extends QueryParser<Void> {
|
public EqQueryParser(Query.Queryable queryable, PROXY container) {
|
||||||
private final PROXY proxy;
|
super(queryable, container);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void nullEqual(Query.Queryable queryable) {
|
protected void nullEqual(Query.Queryable queryable, PROXY proxy) {
|
||||||
queryable.nullEqual().forEach(column -> proxy.anyColumn(column).isNull());
|
queryable.nullEqual().forEach(column -> proxy.anyColumn(column).isNull());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void notNullEqual(Query.Queryable queryable) {
|
protected void notNullEqual(Query.Queryable queryable, PROXY proxy) {
|
||||||
queryable.notNullEqual().forEach(column -> proxy.anyColumn(column).isNotNull());
|
queryable.notNullEqual().forEach(column -> proxy.anyColumn(column).isNotNull());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void empty(Query.Queryable queryable) {
|
protected void empty(Query.Queryable queryable, PROXY proxy) {
|
||||||
throw new UnsupportedOperationException();
|
throw new UnsupportedOperationException();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void notEmpty(Query.Queryable queryable) {
|
protected void notEmpty(Query.Queryable queryable, PROXY proxy) {
|
||||||
throw new UnsupportedOperationException();
|
throw new UnsupportedOperationException();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void equal(Query.Queryable queryable) {
|
protected void equal(Query.Queryable queryable, PROXY proxy) {
|
||||||
queryable.equal().forEach((column, value) -> proxy.anyColumn(column).eq(value));
|
queryable.equal().forEach((column, value) -> proxy.anyColumn(column).eq(value));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void notEqual(Query.Queryable queryable) {
|
protected void notEqual(Query.Queryable queryable, PROXY proxy) {
|
||||||
queryable.notEqual().forEach((column, value) -> proxy.anyColumn(column).ne(value));
|
queryable.notEqual().forEach((column, value) -> proxy.anyColumn(column).ne(value));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void like(Query.Queryable queryable) {
|
protected void like(Query.Queryable queryable, PROXY proxy) {
|
||||||
queryable.like().forEach((column, value) -> proxy.anyColumn(column).likeRaw(value));
|
queryable.like().forEach((column, value) -> proxy.anyColumn(column).likeRaw(value));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void notLike(Query.Queryable queryable) {
|
protected void notLike(Query.Queryable queryable, PROXY proxy) {
|
||||||
queryable.notLike().forEach((column, value) -> proxy.anyColumn(column).notLikeRaw(value));
|
queryable.notLike().forEach((column, value) -> proxy.anyColumn(column).notLikeRaw(value));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void contain(Query.Queryable queryable) {
|
protected void contain(Query.Queryable queryable, PROXY proxy) {
|
||||||
queryable.contain().forEach((column, value) -> proxy.anyColumn(column).like(value));
|
queryable.contain().forEach((column, value) -> proxy.anyColumn(column).like(value));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void notContain(Query.Queryable queryable) {
|
protected void notContain(Query.Queryable queryable, PROXY proxy) {
|
||||||
queryable.notContain().forEach((column, value) -> proxy.anyColumn(column).notLike(value));
|
queryable.notContain().forEach((column, value) -> proxy.anyColumn(column).notLike(value));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void startWith(Query.Queryable queryable) {
|
protected void startWith(Query.Queryable queryable, PROXY proxy) {
|
||||||
queryable.startWith().forEach((column, value) -> proxy.anyColumn(column).likeMatchLeft(value));
|
queryable.startWith().forEach((column, value) -> proxy.anyColumn(column).likeMatchLeft(value));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void notStartWith(Query.Queryable queryable) {
|
protected void notStartWith(Query.Queryable queryable, PROXY proxy) {
|
||||||
queryable.notStartWith().forEach((column, value) -> proxy.anyColumn(column).notLikeMatchLeft(value));
|
queryable.notStartWith().forEach((column, value) -> proxy.anyColumn(column).notLikeMatchLeft(value));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void endWith(Query.Queryable queryable) {
|
protected void endWith(Query.Queryable queryable, PROXY proxy) {
|
||||||
queryable.endWith().forEach((column, value) -> proxy.anyColumn(column).likeMatchRight(value));
|
queryable.endWith().forEach((column, value) -> proxy.anyColumn(column).likeMatchRight(value));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void notEndWith(Query.Queryable queryable) {
|
protected void notEndWith(Query.Queryable queryable, PROXY proxy) {
|
||||||
queryable.notEndWith().forEach((column, value) -> proxy.anyColumn(column).notLikeMatchRight(value));
|
queryable.notEndWith().forEach((column, value) -> proxy.anyColumn(column).notLikeMatchRight(value));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void great(Query.Queryable queryable) {
|
protected void great(Query.Queryable queryable, PROXY proxy) {
|
||||||
queryable.great().forEach((column, value) -> proxy.anyColumn(column).gt(value));
|
queryable.great().forEach((column, value) -> proxy.anyColumn(column).gt(value));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void less(Query.Queryable queryable) {
|
protected void less(Query.Queryable queryable, PROXY proxy) {
|
||||||
queryable.less().forEach((column, value) -> proxy.anyColumn(column).lt(value));
|
queryable.less().forEach((column, value) -> proxy.anyColumn(column).lt(value));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void greatEqual(Query.Queryable queryable) {
|
protected void greatEqual(Query.Queryable queryable, PROXY proxy) {
|
||||||
queryable.greatEqual().forEach((column, value) -> proxy.anyColumn(column).ge(value));
|
queryable.greatEqual().forEach((column, value) -> proxy.anyColumn(column).ge(value));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void lessEqual(Query.Queryable queryable) {
|
protected void lessEqual(Query.Queryable queryable, PROXY proxy) {
|
||||||
queryable.lessEqual().forEach((column, value) -> proxy.anyColumn(column).le(value));
|
queryable.lessEqual().forEach((column, value) -> proxy.anyColumn(column).le(value));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void inside(Query.Queryable queryable) {
|
protected void inside(Query.Queryable queryable, PROXY proxy) {
|
||||||
queryable.inside()
|
queryable.inside()
|
||||||
.entrySet()
|
.entrySet()
|
||||||
.stream()
|
.stream()
|
||||||
@@ -244,7 +253,7 @@ public abstract class SimpleServiceSupport<ENTITY extends SimpleEntity & ProxyEn
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void notInside(Query.Queryable queryable) {
|
protected void notInside(Query.Queryable queryable, PROXY proxy) {
|
||||||
queryable.notInside()
|
queryable.notInside()
|
||||||
.entrySet()
|
.entrySet()
|
||||||
.stream()
|
.stream()
|
||||||
@@ -253,18 +262,19 @@ public abstract class SimpleServiceSupport<ENTITY extends SimpleEntity & ProxyEn
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void between(Query.Queryable queryable) {
|
protected void between(Query.Queryable queryable, PROXY proxy) {
|
||||||
throw new UnsupportedOperationException();
|
queryable.between().forEach((column, value) -> {
|
||||||
|
proxy.anyColumn(column).gt(value.start());
|
||||||
|
proxy.anyColumn(column).le(value.end());
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void notBetween(Query.Queryable queryable) {
|
protected void notBetween(Query.Queryable queryable, PROXY proxy) {
|
||||||
throw new UnsupportedOperationException();
|
queryable.between().forEach((column, value) -> {
|
||||||
}
|
proxy.anyColumn(column).le(value.start());
|
||||||
|
proxy.anyColumn(column).gt(value.end());
|
||||||
@Override
|
});
|
||||||
protected Void build() {
|
|
||||||
return null;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -4,7 +4,8 @@ create table if not exists Company
|
|||||||
name varchar(255) not null,
|
name varchar(255) not null,
|
||||||
members int not null,
|
members int not null,
|
||||||
created_time timestamp not null default current_timestamp(),
|
created_time timestamp not null default current_timestamp(),
|
||||||
modified_time timestamp not null default current_timestamp() on update current_timestamp()
|
modified_time timestamp not null default current_timestamp() on update current_timestamp(),
|
||||||
|
deleted tinyint not null default false
|
||||||
);
|
);
|
||||||
|
|
||||||
create table if not exists Employee
|
create table if not exists Employee
|
||||||
@@ -12,6 +13,8 @@ create table if not exists Employee
|
|||||||
id bigint primary key,
|
id bigint primary key,
|
||||||
name varchar(255) not null,
|
name varchar(255) not null,
|
||||||
age int not null,
|
age int not null,
|
||||||
|
company_id bigint not null,
|
||||||
created_time timestamp not null default current_timestamp(),
|
created_time timestamp not null default current_timestamp(),
|
||||||
modified_time timestamp not null default current_timestamp() on update current_timestamp()
|
modified_time timestamp not null default current_timestamp() on update current_timestamp(),
|
||||||
|
deleted tinyint not null default false
|
||||||
);
|
);
|
||||||
@@ -0,0 +1,76 @@
|
|||||||
|
package com.lanyuanxiaoyao.service.template.database.eq;
|
||||||
|
|
||||||
|
import com.easy.query.api.proxy.client.EasyEntityQuery;
|
||||||
|
import com.lanyuanxiaoyao.service.template.database.common.test.AbstractTestApplication;
|
||||||
|
import com.lanyuanxiaoyao.service.template.database.eq.entity.Company;
|
||||||
|
import com.lanyuanxiaoyao.service.template.database.eq.entity.Employee;
|
||||||
|
import com.lanyuanxiaoyao.service.template.database.eq.entity.proxy.EmployeeProxy;
|
||||||
|
import java.util.List;
|
||||||
|
import lombok.RequiredArgsConstructor;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.springframework.boot.SpringApplication;
|
||||||
|
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||||
|
import org.springframework.boot.context.event.ApplicationReadyEvent;
|
||||||
|
import org.springframework.context.event.EventListener;
|
||||||
|
import org.springframework.util.Assert;
|
||||||
|
|
||||||
|
@Slf4j
|
||||||
|
@RequiredArgsConstructor
|
||||||
|
@SpringBootApplication
|
||||||
|
public class TestApplication extends AbstractTestApplication {
|
||||||
|
private final EasyEntityQuery entityQuery;
|
||||||
|
|
||||||
|
public static void main(String[] args) {
|
||||||
|
SpringApplication.run(TestApplication.class, args);
|
||||||
|
}
|
||||||
|
|
||||||
|
@EventListener(ApplicationReadyEvent.class)
|
||||||
|
public void runTests() {
|
||||||
|
testCrud();
|
||||||
|
testDelete();
|
||||||
|
testQuery();
|
||||||
|
|
||||||
|
System.exit(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void testDelete() {
|
||||||
|
formatLog("Delete");
|
||||||
|
saveItem("company", randomCompany());
|
||||||
|
saveItem("company", randomCompany());
|
||||||
|
entityQuery.deletable(Company.class)
|
||||||
|
.where(proxy -> proxy.id().isNotNull())
|
||||||
|
.allowDeleteStatement(true)
|
||||||
|
.executeRows();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void testQuery() {
|
||||||
|
formatLog("Added");
|
||||||
|
var company1 = Company.builder().name(randomString(5)).members(randomInt(100)).build();
|
||||||
|
entityQuery.insertable(company1).executeRows();
|
||||||
|
var company2 = Company.builder().name(randomString(5)).members(randomInt(100)).build();
|
||||||
|
entityQuery.insertable(company2).executeRows();
|
||||||
|
var employee1 = Employee.builder().name("Tom").age(randomInt(100)).companyId(company1.getId()).build();
|
||||||
|
entityQuery.insertable(employee1).executeRows();
|
||||||
|
var employee2 = Employee.builder().name(randomString(10)).age(randomInt(100)).companyId(company2.getId()).build();
|
||||||
|
entityQuery.insertable(employee2).executeRows();
|
||||||
|
|
||||||
|
formatLog("Query");
|
||||||
|
var employees1 = entityQuery.queryable(Employee.class)
|
||||||
|
.include(EmployeeProxy::company)
|
||||||
|
.where(proxy -> {
|
||||||
|
proxy.name().isNotNull();
|
||||||
|
proxy.name().eq("Tom");
|
||||||
|
proxy.name().startsWith("To");
|
||||||
|
proxy.name().endsWith("om");
|
||||||
|
proxy.age().lt(200);
|
||||||
|
proxy.age().gt(0);
|
||||||
|
proxy.name().in(List.of("Tom", "Mike"));
|
||||||
|
})
|
||||||
|
.toList();
|
||||||
|
Assert.isTrue(employees1.size() == 1, "查询数量错误");
|
||||||
|
|
||||||
|
formatLog("Clean");
|
||||||
|
entityQuery.deletable(Company.class).where(proxy -> proxy.id().isNotNull()).executeRows();
|
||||||
|
entityQuery.deletable(Employee.class).where(proxy -> proxy.id().isNotNull()).executeRows();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,8 +1,8 @@
|
|||||||
package com.lanyuanxiaoyao.service.template.eq.controller;
|
package com.lanyuanxiaoyao.service.template.database.eq.controller;
|
||||||
|
|
||||||
import com.lanyuanxiaoyao.service.template.eq.entity.Company;
|
import com.lanyuanxiaoyao.service.template.database.eq.entity.Company;
|
||||||
import com.lanyuanxiaoyao.service.template.eq.entity.proxy.CompanyProxy;
|
import com.lanyuanxiaoyao.service.template.database.eq.entity.proxy.CompanyProxy;
|
||||||
import com.lanyuanxiaoyao.service.template.eq.service.CompanyService;
|
import com.lanyuanxiaoyao.service.template.database.eq.service.CompanyService;
|
||||||
import java.time.LocalDateTime;
|
import java.time.LocalDateTime;
|
||||||
import java.util.function.Function;
|
import java.util.function.Function;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
@@ -0,0 +1,33 @@
|
|||||||
|
package com.lanyuanxiaoyao.service.template.database.eq.entity;
|
||||||
|
|
||||||
|
import com.easy.query.core.annotation.EntityProxy;
|
||||||
|
import com.easy.query.core.annotation.Navigate;
|
||||||
|
import com.easy.query.core.annotation.Table;
|
||||||
|
import com.easy.query.core.enums.RelationTypeEnum;
|
||||||
|
import com.easy.query.core.proxy.ProxyEntityAvailable;
|
||||||
|
import com.lanyuanxiaoyao.service.template.database.eq.entity.proxy.CompanyProxy;
|
||||||
|
import java.util.List;
|
||||||
|
import lombok.AllArgsConstructor;
|
||||||
|
import lombok.Builder;
|
||||||
|
import lombok.Getter;
|
||||||
|
import lombok.NoArgsConstructor;
|
||||||
|
import lombok.Setter;
|
||||||
|
import lombok.ToString;
|
||||||
|
import lombok.experimental.FieldNameConstants;
|
||||||
|
|
||||||
|
@Getter
|
||||||
|
@Setter
|
||||||
|
@ToString(callSuper = true)
|
||||||
|
@FieldNameConstants
|
||||||
|
@AllArgsConstructor
|
||||||
|
@NoArgsConstructor
|
||||||
|
@Builder
|
||||||
|
@Table
|
||||||
|
@EntityProxy
|
||||||
|
public class Company extends SimpleEntity implements ProxyEntityAvailable<Company, CompanyProxy> {
|
||||||
|
private String name;
|
||||||
|
private Integer members;
|
||||||
|
|
||||||
|
@Navigate(value = RelationTypeEnum.OneToMany, selfProperty = {"id"}, targetProperty = {"companyId"})
|
||||||
|
private List<Employee> employees;
|
||||||
|
}
|
||||||
@@ -0,0 +1,33 @@
|
|||||||
|
package com.lanyuanxiaoyao.service.template.database.eq.entity;
|
||||||
|
|
||||||
|
import com.easy.query.core.annotation.EntityProxy;
|
||||||
|
import com.easy.query.core.annotation.Navigate;
|
||||||
|
import com.easy.query.core.annotation.Table;
|
||||||
|
import com.easy.query.core.enums.RelationTypeEnum;
|
||||||
|
import com.easy.query.core.proxy.ProxyEntityAvailable;
|
||||||
|
import com.lanyuanxiaoyao.service.template.database.eq.entity.proxy.EmployeeProxy;
|
||||||
|
import lombok.AllArgsConstructor;
|
||||||
|
import lombok.Builder;
|
||||||
|
import lombok.Getter;
|
||||||
|
import lombok.NoArgsConstructor;
|
||||||
|
import lombok.Setter;
|
||||||
|
import lombok.ToString;
|
||||||
|
import lombok.experimental.FieldNameConstants;
|
||||||
|
|
||||||
|
@Getter
|
||||||
|
@Setter
|
||||||
|
@ToString(callSuper = true)
|
||||||
|
@FieldNameConstants
|
||||||
|
@AllArgsConstructor
|
||||||
|
@NoArgsConstructor
|
||||||
|
@Builder
|
||||||
|
@Table
|
||||||
|
@EntityProxy
|
||||||
|
public class Employee extends SimpleEntity implements ProxyEntityAvailable<Employee, EmployeeProxy> {
|
||||||
|
private String name;
|
||||||
|
private Integer age;
|
||||||
|
private Long companyId;
|
||||||
|
|
||||||
|
@Navigate(value = RelationTypeEnum.OneToOne, selfProperty = {"companyId"}, targetProperty = {"id"})
|
||||||
|
private Company company;
|
||||||
|
}
|
||||||
@@ -1,8 +1,8 @@
|
|||||||
package com.lanyuanxiaoyao.service.template.eq.service;
|
package com.lanyuanxiaoyao.service.template.database.eq.service;
|
||||||
|
|
||||||
import com.easy.query.api.proxy.client.EasyEntityQuery;
|
import com.easy.query.api.proxy.client.EasyEntityQuery;
|
||||||
import com.lanyuanxiaoyao.service.template.eq.entity.Company;
|
import com.lanyuanxiaoyao.service.template.database.eq.entity.Company;
|
||||||
import com.lanyuanxiaoyao.service.template.eq.entity.proxy.CompanyProxy;
|
import com.lanyuanxiaoyao.service.template.database.eq.entity.proxy.CompanyProxy;
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
@Service
|
@Service
|
||||||
@@ -1,8 +1,8 @@
|
|||||||
package com.lanyuanxiaoyao.service.template.eq.service;
|
package com.lanyuanxiaoyao.service.template.database.eq.service;
|
||||||
|
|
||||||
import com.easy.query.api.proxy.client.EasyEntityQuery;
|
import com.easy.query.api.proxy.client.EasyEntityQuery;
|
||||||
import com.lanyuanxiaoyao.service.template.eq.entity.Employee;
|
import com.lanyuanxiaoyao.service.template.database.eq.entity.Employee;
|
||||||
import com.lanyuanxiaoyao.service.template.eq.entity.proxy.EmployeeProxy;
|
import com.lanyuanxiaoyao.service.template.database.eq.entity.proxy.EmployeeProxy;
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
@Service
|
@Service
|
||||||
@@ -1,10 +1,8 @@
|
|||||||
server:
|
|
||||||
port: 2490
|
|
||||||
spring:
|
spring:
|
||||||
application:
|
profiles:
|
||||||
name: Test
|
include: test
|
||||||
datasource:
|
datasource:
|
||||||
url: "jdbc:h2:mem:testdb;DB_CLOSE_DELAY=-1;MODE=MySQL;DATABASE_TO_LOWER=TRUE;INIT=runscript from '/Users/lanyuanxiaoyao/Project/IdeaProjects/spring-boot-service-template/spring-boot-service-template-eq/src/test/initial.sql'"
|
url: "jdbc:h2:mem:testdb;DB_CLOSE_DELAY=-1;MODE=MySQL;DATABASE_TO_LOWER=TRUE;INIT=runscript from '/Users/lanyuanxiaoyao/Project/IdeaProjects/spring-boot-service-template/spring-boot-service-template-database/spring-boot-service-template-database-eq/src/test/initial.sql'"
|
||||||
username: test
|
username: test
|
||||||
password: test
|
password: test
|
||||||
driver-class-name: org.h2.Driver
|
driver-class-name: org.h2.Driver
|
||||||
@@ -12,13 +10,4 @@ easy-query:
|
|||||||
database: mysql
|
database: mysql
|
||||||
name-conversion: underlined
|
name-conversion: underlined
|
||||||
print-sql: false
|
print-sql: false
|
||||||
decorator:
|
print-nav-sql: false
|
||||||
datasource:
|
|
||||||
p6spy:
|
|
||||||
multiline: false
|
|
||||||
exclude-categories:
|
|
||||||
- commit
|
|
||||||
- result
|
|
||||||
- resultset
|
|
||||||
- rollback
|
|
||||||
log-format: "%(category)|%(executionTime)|%(sqlSingleLine)"
|
|
||||||
@@ -9,12 +9,12 @@
|
|||||||
<version>1.1.0-SNAPSHOT</version>
|
<version>1.1.0-SNAPSHOT</version>
|
||||||
</parent>
|
</parent>
|
||||||
|
|
||||||
<artifactId>spring-boot-service-template-jpa</artifactId>
|
<artifactId>spring-boot-service-template-database-jpa</artifactId>
|
||||||
|
|
||||||
<dependencies>
|
<dependencies>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>com.lanyuanxiaoyao</groupId>
|
<groupId>com.lanyuanxiaoyao</groupId>
|
||||||
<artifactId>spring-boot-service-template-common</artifactId>
|
<artifactId>spring-boot-service-template-database-common</artifactId>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
<dependency>
|
<dependency>
|
||||||
@@ -22,6 +22,7 @@
|
|||||||
<artifactId>spring-boot-starter-web</artifactId>
|
<artifactId>spring-boot-starter-web</artifactId>
|
||||||
<scope>provided</scope>
|
<scope>provided</scope>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.springframework.boot</groupId>
|
<groupId>org.springframework.boot</groupId>
|
||||||
<artifactId>spring-boot-starter-data-jpa</artifactId>
|
<artifactId>spring-boot-starter-data-jpa</artifactId>
|
||||||
@@ -41,24 +42,8 @@
|
|||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.mapstruct</groupId>
|
<groupId>com.lanyuanxiaoyao</groupId>
|
||||||
<artifactId>mapstruct</artifactId>
|
<artifactId>spring-boot-service-template-database-common-test</artifactId>
|
||||||
<scope>compile</scope>
|
|
||||||
</dependency>
|
|
||||||
|
|
||||||
<dependency>
|
|
||||||
<groupId>com.github.gavlyukovskiy</groupId>
|
|
||||||
<artifactId>p6spy-spring-boot-starter</artifactId>
|
|
||||||
</dependency>
|
|
||||||
|
|
||||||
<dependency>
|
|
||||||
<groupId>org.jspecify</groupId>
|
|
||||||
<artifactId>jspecify</artifactId>
|
|
||||||
</dependency>
|
|
||||||
|
|
||||||
<dependency>
|
|
||||||
<groupId>com.h2database</groupId>
|
|
||||||
<artifactId>h2</artifactId>
|
|
||||||
<scope>test</scope>
|
<scope>test</scope>
|
||||||
</dependency>
|
</dependency>
|
||||||
</dependencies>
|
</dependencies>
|
||||||
@@ -1,11 +1,11 @@
|
|||||||
package com.lanyuanxiaoyao.service.template.xbatis.controller;
|
package com.lanyuanxiaoyao.service.template.database.jpa.controller;
|
||||||
|
|
||||||
import com.lanyuanxiaoyao.service.template.common.controller.SimpleController;
|
|
||||||
import com.lanyuanxiaoyao.service.template.common.entity.GlobalResponse;
|
|
||||||
import com.lanyuanxiaoyao.service.template.common.entity.Query;
|
|
||||||
import com.lanyuanxiaoyao.service.template.common.helper.ObjectHelper;
|
import com.lanyuanxiaoyao.service.template.common.helper.ObjectHelper;
|
||||||
import com.lanyuanxiaoyao.service.template.xbatis.entity.SimpleEntity;
|
import com.lanyuanxiaoyao.service.template.database.common.controller.SimpleController;
|
||||||
import com.lanyuanxiaoyao.service.template.xbatis.service.SimpleServiceSupport;
|
import com.lanyuanxiaoyao.service.template.database.common.entity.GlobalResponse;
|
||||||
|
import com.lanyuanxiaoyao.service.template.database.common.entity.Query;
|
||||||
|
import com.lanyuanxiaoyao.service.template.database.jpa.entity.SimpleEntity;
|
||||||
|
import com.lanyuanxiaoyao.service.template.database.jpa.service.SimpleServiceSupport;
|
||||||
import java.util.function.Function;
|
import java.util.function.Function;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import org.springframework.transaction.annotation.Transactional;
|
import org.springframework.transaction.annotation.Transactional;
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
package com.lanyuanxiaoyao.service.template.jpa.entity;
|
package com.lanyuanxiaoyao.service.template.database.jpa.entity;
|
||||||
|
|
||||||
import jakarta.persistence.Column;
|
import jakarta.persistence.Column;
|
||||||
import jakarta.persistence.EntityListeners;
|
import jakarta.persistence.EntityListeners;
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
package com.lanyuanxiaoyao.service.template.jpa.entity;
|
package com.lanyuanxiaoyao.service.template.database.jpa.entity;
|
||||||
|
|
||||||
import jakarta.persistence.Column;
|
import jakarta.persistence.Column;
|
||||||
import jakarta.persistence.EntityListeners;
|
import jakarta.persistence.EntityListeners;
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
package com.lanyuanxiaoyao.service.template.jpa.entity;
|
package com.lanyuanxiaoyao.service.template.database.jpa.entity;
|
||||||
|
|
||||||
import java.lang.annotation.ElementType;
|
import java.lang.annotation.ElementType;
|
||||||
import java.lang.annotation.Retention;
|
import java.lang.annotation.Retention;
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
package com.lanyuanxiaoyao.service.template.jpa.entity;
|
package com.lanyuanxiaoyao.service.template.database.jpa.entity;
|
||||||
|
|
||||||
import com.lanyuanxiaoyao.service.template.common.helper.SnowflakeHelper;
|
import com.lanyuanxiaoyao.service.template.database.common.helper.SnowflakeHelper;
|
||||||
import java.io.Serializable;
|
import java.io.Serializable;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import org.hibernate.engine.spi.SharedSessionContractImplementor;
|
import org.hibernate.engine.spi.SharedSessionContractImplementor;
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
package com.lanyuanxiaoyao.service.template.jpa.helper;
|
package com.lanyuanxiaoyao.service.template.database.jpa.helper;
|
||||||
|
|
||||||
import jakarta.persistence.Entity;
|
import jakarta.persistence.Entity;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
package com.lanyuanxiaoyao.service.template.jpa.repository;
|
package com.lanyuanxiaoyao.service.template.database.jpa.repository;
|
||||||
|
|
||||||
import com.blinkfox.fenix.jpa.FenixJpaRepository;
|
import com.blinkfox.fenix.jpa.FenixJpaRepository;
|
||||||
import com.blinkfox.fenix.specification.FenixJpaSpecificationExecutor;
|
import com.blinkfox.fenix.specification.FenixJpaSpecificationExecutor;
|
||||||
@@ -1,23 +1,22 @@
|
|||||||
package com.lanyuanxiaoyao.service.template.jpa.service;
|
package com.lanyuanxiaoyao.service.template.database.jpa.service;
|
||||||
|
|
||||||
import com.lanyuanxiaoyao.service.template.common.entity.Page;
|
|
||||||
import com.lanyuanxiaoyao.service.template.common.entity.Query;
|
|
||||||
import com.lanyuanxiaoyao.service.template.common.exception.IdNotFoundException;
|
|
||||||
import com.lanyuanxiaoyao.service.template.common.exception.NotCollectionException;
|
|
||||||
import com.lanyuanxiaoyao.service.template.common.exception.NotComparableException;
|
|
||||||
import com.lanyuanxiaoyao.service.template.common.exception.NotStringException;
|
|
||||||
import com.lanyuanxiaoyao.service.template.common.helper.ObjectHelper;
|
import com.lanyuanxiaoyao.service.template.common.helper.ObjectHelper;
|
||||||
import com.lanyuanxiaoyao.service.template.common.service.QueryParser;
|
import com.lanyuanxiaoyao.service.template.database.common.entity.Page;
|
||||||
import com.lanyuanxiaoyao.service.template.common.service.SimpleService;
|
import com.lanyuanxiaoyao.service.template.database.common.entity.Query;
|
||||||
import com.lanyuanxiaoyao.service.template.jpa.entity.IdOnlyEntity;
|
import com.lanyuanxiaoyao.service.template.database.common.exception.IdNotFoundException;
|
||||||
import com.lanyuanxiaoyao.service.template.jpa.entity.SimpleEntity;
|
import com.lanyuanxiaoyao.service.template.database.common.exception.NotCollectionException;
|
||||||
import com.lanyuanxiaoyao.service.template.jpa.repository.SimpleRepository;
|
import com.lanyuanxiaoyao.service.template.database.common.exception.NotComparableException;
|
||||||
|
import com.lanyuanxiaoyao.service.template.database.common.exception.NotStringException;
|
||||||
|
import com.lanyuanxiaoyao.service.template.database.common.service.QueryParser;
|
||||||
|
import com.lanyuanxiaoyao.service.template.database.common.service.SimpleService;
|
||||||
|
import com.lanyuanxiaoyao.service.template.database.jpa.entity.IdOnlyEntity;
|
||||||
|
import com.lanyuanxiaoyao.service.template.database.jpa.entity.SimpleEntity;
|
||||||
|
import com.lanyuanxiaoyao.service.template.database.jpa.repository.SimpleRepository;
|
||||||
import jakarta.persistence.criteria.CriteriaBuilder;
|
import jakarta.persistence.criteria.CriteriaBuilder;
|
||||||
import jakarta.persistence.criteria.CriteriaQuery;
|
import jakarta.persistence.criteria.CriteriaQuery;
|
||||||
import jakarta.persistence.criteria.Path;
|
import jakarta.persistence.criteria.Path;
|
||||||
import jakarta.persistence.criteria.Predicate;
|
import jakarta.persistence.criteria.Predicate;
|
||||||
import jakarta.persistence.criteria.Root;
|
import jakarta.persistence.criteria.Root;
|
||||||
import jakarta.transaction.Transactional;
|
|
||||||
import java.time.LocalDateTime;
|
import java.time.LocalDateTime;
|
||||||
import java.time.format.DateTimeFormatter;
|
import java.time.format.DateTimeFormatter;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
@@ -29,6 +28,7 @@ import lombok.extern.slf4j.Slf4j;
|
|||||||
import org.mapstruct.Named;
|
import org.mapstruct.Named;
|
||||||
import org.springframework.data.domain.PageRequest;
|
import org.springframework.data.domain.PageRequest;
|
||||||
import org.springframework.data.domain.Sort;
|
import org.springframework.data.domain.Sort;
|
||||||
|
import org.springframework.transaction.annotation.Transactional;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 简单服务支持类,提供基础的业务逻辑实现
|
* 简单服务支持类,提供基础的业务逻辑实现
|
||||||
@@ -87,7 +87,7 @@ public abstract class SimpleServiceSupport<ENTITY extends SimpleEntity> implemen
|
|||||||
* @param entity 需要保存的实体对象
|
* @param entity 需要保存的实体对象
|
||||||
* @return 返回保存后的实体ID
|
* @return 返回保存后的实体ID
|
||||||
*/
|
*/
|
||||||
@Transactional(rollbackOn = Throwable.class)
|
@Transactional(rollbackFor = Throwable.class)
|
||||||
@Override
|
@Override
|
||||||
public Long save(ENTITY entity) {
|
public Long save(ENTITY entity) {
|
||||||
entity = repository.saveOrUpdateByNotNullProperties(entity);
|
entity = repository.saveOrUpdateByNotNullProperties(entity);
|
||||||
@@ -103,7 +103,7 @@ public abstract class SimpleServiceSupport<ENTITY extends SimpleEntity> implemen
|
|||||||
*
|
*
|
||||||
* @param entities 需要保存的实体对象集合
|
* @param entities 需要保存的实体对象集合
|
||||||
*/
|
*/
|
||||||
@Transactional(rollbackOn = Throwable.class)
|
@Transactional(rollbackFor = Throwable.class)
|
||||||
@Override
|
@Override
|
||||||
public void save(Iterable<ENTITY> entities) {
|
public void save(Iterable<ENTITY> entities) {
|
||||||
repository.saveOrUpdateAllByNotNullProperties(entities);
|
repository.saveOrUpdateAllByNotNullProperties(entities);
|
||||||
@@ -194,7 +194,11 @@ public abstract class SimpleServiceSupport<ENTITY extends SimpleEntity> implemen
|
|||||||
var result = repository.findAll(
|
var result = repository.findAll(
|
||||||
(root, query, builder) -> {
|
(root, query, builder) -> {
|
||||||
var predicate = commonPredicates(root, query, builder);
|
var predicate = commonPredicates(root, query, builder);
|
||||||
var queryPredicate = new JpaQueryParser<>(root, query, builder).build(listQuery.query());
|
var predicates = new ArrayList<Predicate>();
|
||||||
|
new JpaQueryParser<>(listQuery.query(), predicates, root, query, builder).build();
|
||||||
|
var queryPredicate = predicates.size() == 1
|
||||||
|
? predicates.get(0)
|
||||||
|
: builder.and(predicates.toArray(Predicate[]::new));
|
||||||
return ObjectHelper.isNull(predicate)
|
return ObjectHelper.isNull(predicate)
|
||||||
? queryPredicate
|
? queryPredicate
|
||||||
: builder.and(predicate, queryPredicate);
|
: builder.and(predicate, queryPredicate);
|
||||||
@@ -268,11 +272,11 @@ public abstract class SimpleServiceSupport<ENTITY extends SimpleEntity> implemen
|
|||||||
*
|
*
|
||||||
* @param id 实体主键ID
|
* @param id 实体主键ID
|
||||||
*/
|
*/
|
||||||
@Transactional(rollbackOn = Throwable.class)
|
@Transactional(rollbackFor = Throwable.class)
|
||||||
@Override
|
@Override
|
||||||
public void remove(Long id) {
|
public void remove(Long id) {
|
||||||
if (ObjectHelper.isNotNull(id)) {
|
if (ObjectHelper.isNotNull(id)) {
|
||||||
repository.deleteById(id);
|
repository.deleteBatchByIds(List.of(id));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -286,7 +290,7 @@ public abstract class SimpleServiceSupport<ENTITY extends SimpleEntity> implemen
|
|||||||
*
|
*
|
||||||
* @param ids 实体主键ID集合
|
* @param ids 实体主键ID集合
|
||||||
*/
|
*/
|
||||||
@Transactional(rollbackOn = Throwable.class)
|
@Transactional(rollbackFor = Throwable.class)
|
||||||
@Override
|
@Override
|
||||||
public void remove(Set<Long> ids) {
|
public void remove(Set<Long> ids) {
|
||||||
if (ObjectHelper.isNotEmpty(ids)) {
|
if (ObjectHelper.isNotEmpty(ids)) {
|
||||||
@@ -295,14 +299,14 @@ public abstract class SimpleServiceSupport<ENTITY extends SimpleEntity> implemen
|
|||||||
}
|
}
|
||||||
|
|
||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
private static final class JpaQueryParser<ENTITY> extends QueryParser<Predicate> {
|
private static final class JpaQueryParser<ENTITY> extends QueryParser<List<Predicate>> {
|
||||||
private final Root<ENTITY> root;
|
private final Root<ENTITY> root;
|
||||||
@SuppressWarnings({"unused", "FieldCanBeLocal"})
|
@SuppressWarnings({"unused", "FieldCanBeLocal"})
|
||||||
private final CriteriaQuery<?> query;
|
private final CriteriaQuery<?> query;
|
||||||
private final CriteriaBuilder builder;
|
private final CriteriaBuilder builder;
|
||||||
private final List<Predicate> predicates = new ArrayList<>();
|
|
||||||
|
|
||||||
private JpaQueryParser(Root<ENTITY> root, CriteriaQuery<?> query, CriteriaBuilder builder) {
|
private JpaQueryParser(Query.Queryable queryable, List<Predicate> predicates, Root<ENTITY> root, CriteriaQuery<?> query, CriteriaBuilder builder) {
|
||||||
|
super(queryable, predicates);
|
||||||
this.root = root;
|
this.root = root;
|
||||||
this.query = query;
|
this.query = query;
|
||||||
this.builder = builder;
|
this.builder = builder;
|
||||||
@@ -434,17 +438,17 @@ public abstract class SimpleServiceSupport<ENTITY extends SimpleEntity> implemen
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void nullEqual(Query.Queryable queryable) {
|
protected void nullEqual(Query.Queryable queryable, List<Predicate> predicates) {
|
||||||
queryable.nullEqual().forEach(column -> predicates.add(builder.isNull(column(root, column))));
|
queryable.nullEqual().forEach(column -> predicates.add(builder.isNull(column(root, column))));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void notNullEqual(Query.Queryable queryable) {
|
protected void notNullEqual(Query.Queryable queryable, List<Predicate> predicates) {
|
||||||
queryable.notNullEqual().forEach(column -> predicates.add(builder.isNotNull(column(root, column))));
|
queryable.notNullEqual().forEach(column -> predicates.add(builder.isNotNull(column(root, column))));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void empty(Query.Queryable queryable) {
|
protected void empty(Query.Queryable queryable, List<Predicate> predicates) {
|
||||||
queryable.empty().forEach(column -> {
|
queryable.empty().forEach(column -> {
|
||||||
var path = this.<Collection<Object>>column(root, column);
|
var path = this.<Collection<Object>>column(root, column);
|
||||||
checkCollection(path, column);
|
checkCollection(path, column);
|
||||||
@@ -453,7 +457,7 @@ public abstract class SimpleServiceSupport<ENTITY extends SimpleEntity> implemen
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void notEmpty(Query.Queryable queryable) {
|
protected void notEmpty(Query.Queryable queryable, List<Predicate> predicates) {
|
||||||
queryable.notEmpty().forEach(column -> {
|
queryable.notEmpty().forEach(column -> {
|
||||||
var path = this.<Collection<Object>>column(root, column);
|
var path = this.<Collection<Object>>column(root, column);
|
||||||
checkCollection(path, column);
|
checkCollection(path, column);
|
||||||
@@ -462,7 +466,7 @@ public abstract class SimpleServiceSupport<ENTITY extends SimpleEntity> implemen
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void equal(Query.Queryable queryable) {
|
protected void equal(Query.Queryable queryable, List<Predicate> predicates) {
|
||||||
queryable.equal().forEach((column, value) -> {
|
queryable.equal().forEach((column, value) -> {
|
||||||
var path = column(root, column);
|
var path = column(root, column);
|
||||||
predicates.add(builder.equal(path, value(path, value)));
|
predicates.add(builder.equal(path, value(path, value)));
|
||||||
@@ -470,7 +474,7 @@ public abstract class SimpleServiceSupport<ENTITY extends SimpleEntity> implemen
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void notEqual(Query.Queryable queryable) {
|
protected void notEqual(Query.Queryable queryable, List<Predicate> predicates) {
|
||||||
queryable.notEqual().forEach((column, value) -> {
|
queryable.notEqual().forEach((column, value) -> {
|
||||||
var path = column(root, column);
|
var path = column(root, column);
|
||||||
predicates.add(builder.notEqual(path, value(path, value)));
|
predicates.add(builder.notEqual(path, value(path, value)));
|
||||||
@@ -478,7 +482,7 @@ public abstract class SimpleServiceSupport<ENTITY extends SimpleEntity> implemen
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void like(Query.Queryable queryable) {
|
protected void like(Query.Queryable queryable, List<Predicate> predicates) {
|
||||||
queryable.like().forEach((column, value) -> {
|
queryable.like().forEach((column, value) -> {
|
||||||
var path = this.<String>column(root, column);
|
var path = this.<String>column(root, column);
|
||||||
checkString(path, value, column);
|
checkString(path, value, column);
|
||||||
@@ -487,7 +491,7 @@ public abstract class SimpleServiceSupport<ENTITY extends SimpleEntity> implemen
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void notLike(Query.Queryable queryable) {
|
protected void notLike(Query.Queryable queryable, List<Predicate> predicates) {
|
||||||
queryable.notLike().forEach((column, value) -> {
|
queryable.notLike().forEach((column, value) -> {
|
||||||
var path = this.<String>column(root, column);
|
var path = this.<String>column(root, column);
|
||||||
checkString(path, value, column);
|
checkString(path, value, column);
|
||||||
@@ -496,7 +500,7 @@ public abstract class SimpleServiceSupport<ENTITY extends SimpleEntity> implemen
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void contain(Query.Queryable queryable) {
|
protected void contain(Query.Queryable queryable, List<Predicate> predicates) {
|
||||||
queryable.contain().forEach((column, value) -> {
|
queryable.contain().forEach((column, value) -> {
|
||||||
var path = this.<String>column(root, column);
|
var path = this.<String>column(root, column);
|
||||||
checkString(path, value, column);
|
checkString(path, value, column);
|
||||||
@@ -505,7 +509,7 @@ public abstract class SimpleServiceSupport<ENTITY extends SimpleEntity> implemen
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void notContain(Query.Queryable queryable) {
|
protected void notContain(Query.Queryable queryable, List<Predicate> predicates) {
|
||||||
queryable.notContain().forEach((column, value) -> {
|
queryable.notContain().forEach((column, value) -> {
|
||||||
var path = this.<String>column(root, column);
|
var path = this.<String>column(root, column);
|
||||||
checkString(path, value, column);
|
checkString(path, value, column);
|
||||||
@@ -514,7 +518,7 @@ public abstract class SimpleServiceSupport<ENTITY extends SimpleEntity> implemen
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void startWith(Query.Queryable queryable) {
|
protected void startWith(Query.Queryable queryable, List<Predicate> predicates) {
|
||||||
queryable.startWith().forEach((column, value) -> {
|
queryable.startWith().forEach((column, value) -> {
|
||||||
var path = this.<String>column(root, column);
|
var path = this.<String>column(root, column);
|
||||||
checkString(path, value, column);
|
checkString(path, value, column);
|
||||||
@@ -523,7 +527,7 @@ public abstract class SimpleServiceSupport<ENTITY extends SimpleEntity> implemen
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void notStartWith(Query.Queryable queryable) {
|
protected void notStartWith(Query.Queryable queryable, List<Predicate> predicates) {
|
||||||
queryable.notStartWith().forEach((column, value) -> {
|
queryable.notStartWith().forEach((column, value) -> {
|
||||||
var path = this.<String>column(root, column);
|
var path = this.<String>column(root, column);
|
||||||
checkString(path, value, column);
|
checkString(path, value, column);
|
||||||
@@ -532,7 +536,7 @@ public abstract class SimpleServiceSupport<ENTITY extends SimpleEntity> implemen
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void endWith(Query.Queryable queryable) {
|
protected void endWith(Query.Queryable queryable, List<Predicate> predicates) {
|
||||||
queryable.endWith().forEach((column, value) -> {
|
queryable.endWith().forEach((column, value) -> {
|
||||||
var path = this.<String>column(root, column);
|
var path = this.<String>column(root, column);
|
||||||
checkString(path, value, column);
|
checkString(path, value, column);
|
||||||
@@ -541,7 +545,7 @@ public abstract class SimpleServiceSupport<ENTITY extends SimpleEntity> implemen
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void notEndWith(Query.Queryable queryable) {
|
protected void notEndWith(Query.Queryable queryable, List<Predicate> predicates) {
|
||||||
queryable.notEndWith().forEach((column, value) -> {
|
queryable.notEndWith().forEach((column, value) -> {
|
||||||
var path = this.<String>column(root, column);
|
var path = this.<String>column(root, column);
|
||||||
checkString(path, value, column);
|
checkString(path, value, column);
|
||||||
@@ -550,7 +554,7 @@ public abstract class SimpleServiceSupport<ENTITY extends SimpleEntity> implemen
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void great(Query.Queryable queryable) {
|
protected void great(Query.Queryable queryable, List<Predicate> predicates) {
|
||||||
queryable.great().forEach((column, value) -> {
|
queryable.great().forEach((column, value) -> {
|
||||||
var path = this.<Comparable<Object>>column(root, column);
|
var path = this.<Comparable<Object>>column(root, column);
|
||||||
checkComparable(path, value, column);
|
checkComparable(path, value, column);
|
||||||
@@ -559,7 +563,7 @@ public abstract class SimpleServiceSupport<ENTITY extends SimpleEntity> implemen
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void less(Query.Queryable queryable) {
|
protected void less(Query.Queryable queryable, List<Predicate> predicates) {
|
||||||
queryable.less().forEach((column, value) -> {
|
queryable.less().forEach((column, value) -> {
|
||||||
var path = this.<Comparable<Object>>column(root, column);
|
var path = this.<Comparable<Object>>column(root, column);
|
||||||
checkComparable(path, value, column);
|
checkComparable(path, value, column);
|
||||||
@@ -568,7 +572,7 @@ public abstract class SimpleServiceSupport<ENTITY extends SimpleEntity> implemen
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void greatEqual(Query.Queryable queryable) {
|
protected void greatEqual(Query.Queryable queryable, List<Predicate> predicates) {
|
||||||
queryable.greatEqual().forEach((column, value) -> {
|
queryable.greatEqual().forEach((column, value) -> {
|
||||||
var path = this.<Comparable<Object>>column(root, column);
|
var path = this.<Comparable<Object>>column(root, column);
|
||||||
checkComparable(path, value, column);
|
checkComparable(path, value, column);
|
||||||
@@ -577,7 +581,7 @@ public abstract class SimpleServiceSupport<ENTITY extends SimpleEntity> implemen
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void lessEqual(Query.Queryable queryable) {
|
protected void lessEqual(Query.Queryable queryable, List<Predicate> predicates) {
|
||||||
queryable.lessEqual().forEach((column, value) -> {
|
queryable.lessEqual().forEach((column, value) -> {
|
||||||
var path = this.<Comparable<Object>>column(root, column);
|
var path = this.<Comparable<Object>>column(root, column);
|
||||||
checkComparable(path, value, column);
|
checkComparable(path, value, column);
|
||||||
@@ -586,7 +590,7 @@ public abstract class SimpleServiceSupport<ENTITY extends SimpleEntity> implemen
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void inside(Query.Queryable queryable) {
|
protected void inside(Query.Queryable queryable, List<Predicate> predicates) {
|
||||||
queryable.inside()
|
queryable.inside()
|
||||||
.entrySet()
|
.entrySet()
|
||||||
.stream()
|
.stream()
|
||||||
@@ -595,7 +599,7 @@ public abstract class SimpleServiceSupport<ENTITY extends SimpleEntity> implemen
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void notInside(Query.Queryable queryable) {
|
protected void notInside(Query.Queryable queryable, List<Predicate> predicates) {
|
||||||
queryable.notInside()
|
queryable.notInside()
|
||||||
.entrySet()
|
.entrySet()
|
||||||
.stream()
|
.stream()
|
||||||
@@ -604,7 +608,7 @@ public abstract class SimpleServiceSupport<ENTITY extends SimpleEntity> implemen
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void between(Query.Queryable queryable) {
|
protected void between(Query.Queryable queryable, List<Predicate> predicates) {
|
||||||
queryable.between().forEach((column, value) -> {
|
queryable.between().forEach((column, value) -> {
|
||||||
var path = this.<Comparable<Object>>column(root, column);
|
var path = this.<Comparable<Object>>column(root, column);
|
||||||
checkComparable(path, value, column);
|
checkComparable(path, value, column);
|
||||||
@@ -613,19 +617,12 @@ public abstract class SimpleServiceSupport<ENTITY extends SimpleEntity> implemen
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void notBetween(Query.Queryable queryable) {
|
protected void notBetween(Query.Queryable queryable, List<Predicate> predicates) {
|
||||||
queryable.notBetween().forEach((column, value) -> {
|
queryable.notBetween().forEach((column, value) -> {
|
||||||
var path = this.<Comparable<Object>>column(root, column);
|
var path = this.<Comparable<Object>>column(root, column);
|
||||||
checkComparable(path, value, column);
|
checkComparable(path, value, column);
|
||||||
predicates.add(builder.between(path, (Comparable<Object>) value(path, value.start()), (Comparable<Object>) value(path, value.end())).not());
|
predicates.add(builder.between(path, (Comparable<Object>) value(path, value.start()), (Comparable<Object>) value(path, value.end())).not());
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
protected Predicate build() {
|
|
||||||
return predicates.size() == 1
|
|
||||||
? predicates.get(0)
|
|
||||||
: builder.and(predicates.toArray(Predicate[]::new));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,185 @@
|
|||||||
|
package com.lanyuanxiaoyao.service.template.database.jpa;
|
||||||
|
|
||||||
|
import com.blinkfox.fenix.EnableFenix;
|
||||||
|
import com.lanyuanxiaoyao.service.template.database.common.test.AbstractTestApplication;
|
||||||
|
import com.lanyuanxiaoyao.service.template.database.common.test.entity.Industry;
|
||||||
|
import com.lanyuanxiaoyao.service.template.database.common.test.entity.Level;
|
||||||
|
import com.lanyuanxiaoyao.service.template.database.jpa.entity.Company;
|
||||||
|
import com.lanyuanxiaoyao.service.template.database.jpa.entity.Company_;
|
||||||
|
import com.lanyuanxiaoyao.service.template.database.jpa.entity.Employee;
|
||||||
|
import com.lanyuanxiaoyao.service.template.database.jpa.entity.Employee_;
|
||||||
|
import com.lanyuanxiaoyao.service.template.database.jpa.entity.QEmployee;
|
||||||
|
import com.lanyuanxiaoyao.service.template.database.jpa.entity.Report;
|
||||||
|
import com.lanyuanxiaoyao.service.template.database.jpa.repository.CompanyRepository;
|
||||||
|
import com.lanyuanxiaoyao.service.template.database.jpa.repository.EmployeeRepository;
|
||||||
|
import com.lanyuanxiaoyao.service.template.database.jpa.repository.ReportRepository;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Set;
|
||||||
|
import lombok.RequiredArgsConstructor;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.springframework.boot.SpringApplication;
|
||||||
|
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||||
|
import org.springframework.boot.context.event.ApplicationReadyEvent;
|
||||||
|
import org.springframework.context.event.EventListener;
|
||||||
|
import org.springframework.data.jpa.repository.config.EnableJpaAuditing;
|
||||||
|
import org.springframework.util.Assert;
|
||||||
|
|
||||||
|
@Slf4j
|
||||||
|
@RequiredArgsConstructor
|
||||||
|
@SpringBootApplication
|
||||||
|
@EnableFenix
|
||||||
|
@EnableJpaAuditing
|
||||||
|
public class TestApplication extends AbstractTestApplication {
|
||||||
|
private final CompanyRepository companyRepository;
|
||||||
|
private final EmployeeRepository employeeRepository;
|
||||||
|
private final ReportRepository reportRepository;
|
||||||
|
|
||||||
|
public static void main(String[] args) {
|
||||||
|
SpringApplication.run(TestApplication.class, args);
|
||||||
|
}
|
||||||
|
|
||||||
|
@EventListener(ApplicationReadyEvent.class)
|
||||||
|
public void runTests() {
|
||||||
|
testCrud();
|
||||||
|
testDelete();
|
||||||
|
testSpecification();
|
||||||
|
testNative();
|
||||||
|
|
||||||
|
System.exit(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void testDelete() {
|
||||||
|
formatLog("Delete JPA");
|
||||||
|
saveItem("company", randomCompany());
|
||||||
|
saveItem("company", randomCompany());
|
||||||
|
companyRepository.deleteAll();
|
||||||
|
|
||||||
|
formatLog("Delete JPA Batch");
|
||||||
|
saveItem("company", randomCompany());
|
||||||
|
saveItem("company", randomCompany());
|
||||||
|
companyRepository.deleteAllInBatch();
|
||||||
|
|
||||||
|
formatLog("Delete JPA by id");
|
||||||
|
var cid1 = saveItem("company", randomCompany()).get("data").asLong();
|
||||||
|
var cid2 = saveItem("company", randomCompany()).get("data").asLong();
|
||||||
|
companyRepository.deleteAllById(List.of(cid1, cid2));
|
||||||
|
|
||||||
|
formatLog("Delete Fenix by id");
|
||||||
|
cid1 = saveItem("company", randomCompany()).get("data").asLong();
|
||||||
|
cid2 = saveItem("company", randomCompany()).get("data").asLong();
|
||||||
|
companyRepository.deleteByIds(List.of(cid1, cid2));
|
||||||
|
|
||||||
|
formatLog("Delete Fenix Batch by id");
|
||||||
|
cid1 = saveItem("company", randomCompany()).get("data").asLong();
|
||||||
|
cid2 = saveItem("company", randomCompany()).get("data").asLong();
|
||||||
|
companyRepository.deleteBatchByIds(List.of(cid1, cid2));
|
||||||
|
}
|
||||||
|
|
||||||
|
private void testSpecification() {
|
||||||
|
formatLog("Added");
|
||||||
|
var company1 = companyRepository.save(Company.builder().name(randomString(5)).members(randomInt(100)).industries(Set.of(Industry.MEDIA, Industry.SERVICE)).build());
|
||||||
|
var company2 = companyRepository.save(Company.builder().name(randomString(5)).members(randomInt(100)).industries(Set.of(Industry.MEDIA, Industry.SERVICE)).build());
|
||||||
|
var employee1 = employeeRepository.save(
|
||||||
|
Employee.builder()
|
||||||
|
.name("Tom")
|
||||||
|
.age(randomInt(100))
|
||||||
|
.role(Employee.Role.USER)
|
||||||
|
.company(company1)
|
||||||
|
.connections(Map.of(
|
||||||
|
Employee.ConnectionType.ADDRESS, randomString(50),
|
||||||
|
Employee.ConnectionType.EMAIL, randomString(20)
|
||||||
|
))
|
||||||
|
.build()
|
||||||
|
);
|
||||||
|
var employee2 = employeeRepository.save(
|
||||||
|
Employee.builder()
|
||||||
|
.name(randomString(10))
|
||||||
|
.age(randomInt(100))
|
||||||
|
.role(Employee.Role.USER)
|
||||||
|
.company(company2)
|
||||||
|
.connections(Map.of(
|
||||||
|
Employee.ConnectionType.ADDRESS, randomString(50),
|
||||||
|
Employee.ConnectionType.EMAIL, randomString(20)
|
||||||
|
))
|
||||||
|
.build()
|
||||||
|
);
|
||||||
|
var report1 = reportRepository.save(Report.builder().score(randomDouble(50)).level(Level.B).employeeId(employee1.getId()).build());
|
||||||
|
var report2 = reportRepository.save(Report.builder().score(randomDouble(50)).level(Level.E).employeeId(employee2.getId()).build());
|
||||||
|
|
||||||
|
formatLog("Query");
|
||||||
|
var employees1 = employeeRepository.findAll(
|
||||||
|
builder -> builder
|
||||||
|
.andIsNotNull(Employee.Fields.name)
|
||||||
|
.andEquals(Employee.Fields.name, "Tom")
|
||||||
|
.andLike(Employee.Fields.name, "To")
|
||||||
|
.andStartsWith(Employee.Fields.name, "To")
|
||||||
|
.andEndsWith(Employee.Fields.name, "om")
|
||||||
|
.andLessThan(Employee.Fields.age, 200)
|
||||||
|
.andGreaterThanEqual(Employee.Fields.age, 0)
|
||||||
|
.andIn(Employee.Fields.name, List.of("Tom", "Mike"))
|
||||||
|
.andBetween(Employee.Fields.age, 0, 200)
|
||||||
|
.build()
|
||||||
|
);
|
||||||
|
Assert.isTrue(employees1.size() == 1, "查询数量错误");
|
||||||
|
|
||||||
|
var employees2 = employeeRepository.findAll(
|
||||||
|
(root, query, builder) ->
|
||||||
|
builder.and(
|
||||||
|
builder.isNotNull(root.get(Employee_.name)),
|
||||||
|
builder.equal(root.get(Employee_.name), "Tom"),
|
||||||
|
builder.like(root.get(Employee_.name), "To%"),
|
||||||
|
builder.lessThan(root.get(Employee_.age), 200),
|
||||||
|
builder.greaterThanOrEqualTo(root.get(Employee_.age), 0),
|
||||||
|
builder.in(root.get(Employee_.NAME)).value(List.of("Tom", "Mike")),
|
||||||
|
builder.between(root.get(Employee_.age), 0, 200),
|
||||||
|
builder.isNotEmpty(root.get(Employee_.company).get(Company_.employees)),
|
||||||
|
builder.isMember(Industry.MEDIA, root.get(Employee_.company).get(Company_.industries))
|
||||||
|
)
|
||||||
|
);
|
||||||
|
Assert.isTrue(employees2.size() == 1, "查询数量错误");
|
||||||
|
|
||||||
|
var employees3 = employeeRepository.findAll(
|
||||||
|
QEmployee.employee.name.isNotNull()
|
||||||
|
.and(QEmployee.employee.name.eq("Tom"))
|
||||||
|
.and(QEmployee.employee.name.like("To%"))
|
||||||
|
.and(QEmployee.employee.name.startsWith("To"))
|
||||||
|
.and(QEmployee.employee.name.endsWith("om"))
|
||||||
|
.and(QEmployee.employee.age.lt(200))
|
||||||
|
.and(QEmployee.employee.age.goe(0))
|
||||||
|
.and(QEmployee.employee.name.in("Tom", "Mike"))
|
||||||
|
.and(QEmployee.employee.age.between(0, 200))
|
||||||
|
.and(QEmployee.employee.company().employees.isNotEmpty())
|
||||||
|
.and(QEmployee.employee.company().industries.contains(Industry.MEDIA))
|
||||||
|
.and(QEmployee.employee.connections.containsKey(Employee.ConnectionType.EMAIL))
|
||||||
|
);
|
||||||
|
Assert.isTrue(employees3.size() == 1, "查询数量错误");
|
||||||
|
|
||||||
|
formatLog("Clean");
|
||||||
|
reportRepository.deleteAllInBatch();
|
||||||
|
employeeRepository.deleteAllInBatch();
|
||||||
|
companyRepository.deleteAllInBatch();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void testNative() {
|
||||||
|
formatLog("Added");
|
||||||
|
var company1 = companyRepository.save(Company.builder().name(randomString(5)).members(randomInt(100)).build());
|
||||||
|
var company2 = companyRepository.save(Company.builder().name(randomString(5)).members(randomInt(100)).build());
|
||||||
|
var company3 = companyRepository.save(Company.builder().name(randomString(5)).members(randomInt(100)).build());
|
||||||
|
var employee1 = employeeRepository.save(Employee.builder().name(randomString(10)).age(randomInt(100)).role(Employee.Role.USER).company(company1).build());
|
||||||
|
var employee2 = employeeRepository.save(Employee.builder().name(randomString(10)).age(randomInt(100)).role(Employee.Role.USER).company(company2).build());
|
||||||
|
var employee3 = employeeRepository.save(Employee.builder().name(randomString(10)).age(randomInt(100)).role(Employee.Role.USER).company(company3).build());
|
||||||
|
|
||||||
|
formatLog("HQL Query");
|
||||||
|
var list = employeeRepository.findAllEmployeeWithCompanyName();
|
||||||
|
Assert.isTrue(list.size() == 3, "数量错误");
|
||||||
|
|
||||||
|
formatLog("SQL Query");
|
||||||
|
var list_native = employeeRepository.findAllEmployeeWithCompanyNameNative();
|
||||||
|
Assert.isTrue(list_native.size() == 3, "数量错误");
|
||||||
|
|
||||||
|
formatLog("Clean");
|
||||||
|
employeeRepository.deleteAllInBatch();
|
||||||
|
companyRepository.deleteAllInBatch();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
package com.lanyuanxiaoyao.service.template.jpa.controller;
|
package com.lanyuanxiaoyao.service.template.database.jpa.controller;
|
||||||
|
|
||||||
import com.lanyuanxiaoyao.service.template.jpa.entity.Company;
|
import com.lanyuanxiaoyao.service.template.database.jpa.entity.Company;
|
||||||
import com.lanyuanxiaoyao.service.template.jpa.service.CompanyService;
|
import com.lanyuanxiaoyao.service.template.database.jpa.service.CompanyService;
|
||||||
import java.time.LocalDateTime;
|
import java.time.LocalDateTime;
|
||||||
import java.util.function.Function;
|
import java.util.function.Function;
|
||||||
import org.springframework.web.bind.annotation.RequestMapping;
|
import org.springframework.web.bind.annotation.RequestMapping;
|
||||||
@@ -1,8 +1,8 @@
|
|||||||
package com.lanyuanxiaoyao.service.template.jpa.controller;
|
package com.lanyuanxiaoyao.service.template.database.jpa.controller;
|
||||||
|
|
||||||
import com.lanyuanxiaoyao.service.template.jpa.entity.Employee;
|
import com.lanyuanxiaoyao.service.template.database.jpa.entity.Employee;
|
||||||
import com.lanyuanxiaoyao.service.template.jpa.service.CompanyService;
|
import com.lanyuanxiaoyao.service.template.database.jpa.service.CompanyService;
|
||||||
import com.lanyuanxiaoyao.service.template.jpa.service.EmployeeService;
|
import com.lanyuanxiaoyao.service.template.database.jpa.service.EmployeeService;
|
||||||
import java.time.LocalDateTime;
|
import java.time.LocalDateTime;
|
||||||
import java.util.function.Function;
|
import java.util.function.Function;
|
||||||
import org.springframework.web.bind.annotation.RequestMapping;
|
import org.springframework.web.bind.annotation.RequestMapping;
|
||||||
@@ -1,8 +1,9 @@
|
|||||||
package com.lanyuanxiaoyao.service.template.jpa.controller;
|
package com.lanyuanxiaoyao.service.template.database.jpa.controller;
|
||||||
|
|
||||||
import com.lanyuanxiaoyao.service.template.jpa.entity.Report;
|
import com.lanyuanxiaoyao.service.template.database.common.test.entity.Level;
|
||||||
import com.lanyuanxiaoyao.service.template.jpa.service.EmployeeService;
|
import com.lanyuanxiaoyao.service.template.database.jpa.entity.Report;
|
||||||
import com.lanyuanxiaoyao.service.template.jpa.service.ReportService;
|
import com.lanyuanxiaoyao.service.template.database.jpa.service.EmployeeService;
|
||||||
|
import com.lanyuanxiaoyao.service.template.database.jpa.service.ReportService;
|
||||||
import java.time.LocalDateTime;
|
import java.time.LocalDateTime;
|
||||||
import java.util.function.Function;
|
import java.util.function.Function;
|
||||||
import org.springframework.web.bind.annotation.RequestMapping;
|
import org.springframework.web.bind.annotation.RequestMapping;
|
||||||
@@ -63,7 +64,7 @@ public class ReportController extends SimpleControllerSupport<Report, ReportCont
|
|||||||
public record SaveItem(
|
public record SaveItem(
|
||||||
Long id,
|
Long id,
|
||||||
Double score,
|
Double score,
|
||||||
Report.Level level,
|
Level level,
|
||||||
Long employeeId
|
Long employeeId
|
||||||
) {
|
) {
|
||||||
}
|
}
|
||||||
@@ -73,7 +74,7 @@ public class ReportController extends SimpleControllerSupport<Report, ReportCont
|
|||||||
Long employeeId,
|
Long employeeId,
|
||||||
String employeeName,
|
String employeeName,
|
||||||
Double score,
|
Double score,
|
||||||
Report.Level level
|
Level level
|
||||||
) {
|
) {
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -82,7 +83,7 @@ public class ReportController extends SimpleControllerSupport<Report, ReportCont
|
|||||||
Long employeeId,
|
Long employeeId,
|
||||||
String employeeName,
|
String employeeName,
|
||||||
Double score,
|
Double score,
|
||||||
Report.Level level,
|
Level level,
|
||||||
LocalDateTime createdTime,
|
LocalDateTime createdTime,
|
||||||
LocalDateTime modifiedTime
|
LocalDateTime modifiedTime
|
||||||
) {
|
) {
|
||||||
@@ -1,5 +1,6 @@
|
|||||||
package com.lanyuanxiaoyao.service.template.jpa.entity;
|
package com.lanyuanxiaoyao.service.template.database.jpa.entity;
|
||||||
|
|
||||||
|
import com.lanyuanxiaoyao.service.template.database.common.test.entity.Industry;
|
||||||
import jakarta.persistence.Column;
|
import jakarta.persistence.Column;
|
||||||
import jakarta.persistence.ConstraintMode;
|
import jakarta.persistence.ConstraintMode;
|
||||||
import jakarta.persistence.ElementCollection;
|
import jakarta.persistence.ElementCollection;
|
||||||
@@ -13,7 +14,10 @@ import jakarta.persistence.OneToMany;
|
|||||||
import jakarta.persistence.Table;
|
import jakarta.persistence.Table;
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
import lombok.AllArgsConstructor;
|
||||||
|
import lombok.Builder;
|
||||||
import lombok.Getter;
|
import lombok.Getter;
|
||||||
|
import lombok.NoArgsConstructor;
|
||||||
import lombok.Setter;
|
import lombok.Setter;
|
||||||
import lombok.ToString;
|
import lombok.ToString;
|
||||||
import lombok.experimental.FieldNameConstants;
|
import lombok.experimental.FieldNameConstants;
|
||||||
@@ -26,6 +30,9 @@ import org.springframework.data.jpa.domain.support.AuditingEntityListener;
|
|||||||
@Getter
|
@Getter
|
||||||
@ToString(callSuper = true)
|
@ToString(callSuper = true)
|
||||||
@FieldNameConstants
|
@FieldNameConstants
|
||||||
|
@AllArgsConstructor
|
||||||
|
@NoArgsConstructor
|
||||||
|
@Builder
|
||||||
@Entity
|
@Entity
|
||||||
@SoftDelete
|
@SoftDelete
|
||||||
@DynamicUpdate
|
@DynamicUpdate
|
||||||
@@ -38,26 +45,13 @@ public class Company extends SimpleEntity {
|
|||||||
@Column(nullable = false, comment = "成员数")
|
@Column(nullable = false, comment = "成员数")
|
||||||
private Integer members;
|
private Integer members;
|
||||||
|
|
||||||
@OneToMany(mappedBy = "company")
|
|
||||||
@ToString.Exclude
|
|
||||||
private Set<Employee> employees;
|
|
||||||
|
|
||||||
@ElementCollection
|
@ElementCollection
|
||||||
@JoinTable(foreignKey = @ForeignKey(ConstraintMode.NO_CONSTRAINT), inverseForeignKey = @ForeignKey(ConstraintMode.NO_CONSTRAINT))
|
@JoinTable(foreignKey = @ForeignKey(ConstraintMode.NO_CONSTRAINT), inverseForeignKey = @ForeignKey(ConstraintMode.NO_CONSTRAINT))
|
||||||
@Enumerated(EnumType.STRING)
|
@Enumerated(EnumType.STRING)
|
||||||
@Column(nullable = false)
|
@Column(nullable = false)
|
||||||
private Set<Industry> industries = new HashSet<>();
|
private Set<Industry> industries = new HashSet<>();
|
||||||
|
|
||||||
public enum Industry {
|
@OneToMany(mappedBy = "company")
|
||||||
TECHNOLOGY,
|
@ToString.Exclude
|
||||||
FINANCE,
|
private Set<Employee> employees;
|
||||||
MEDIA,
|
|
||||||
SERVICE,
|
|
||||||
GOVERNMENT,
|
|
||||||
EDUCATION,
|
|
||||||
HEALTHCARE,
|
|
||||||
CONSTRUCTION,
|
|
||||||
RETAIL,
|
|
||||||
OTHER,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
package com.lanyuanxiaoyao.service.template.jpa.entity;
|
package com.lanyuanxiaoyao.service.template.database.jpa.entity;
|
||||||
|
|
||||||
import jakarta.persistence.Column;
|
import jakarta.persistence.Column;
|
||||||
import jakarta.persistence.ConstraintMode;
|
import jakarta.persistence.ConstraintMode;
|
||||||
@@ -15,7 +15,10 @@ import jakarta.persistence.MapKeyEnumerated;
|
|||||||
import jakarta.persistence.Table;
|
import jakarta.persistence.Table;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
import lombok.AllArgsConstructor;
|
||||||
|
import lombok.Builder;
|
||||||
import lombok.Getter;
|
import lombok.Getter;
|
||||||
|
import lombok.NoArgsConstructor;
|
||||||
import lombok.Setter;
|
import lombok.Setter;
|
||||||
import lombok.ToString;
|
import lombok.ToString;
|
||||||
import lombok.experimental.FieldNameConstants;
|
import lombok.experimental.FieldNameConstants;
|
||||||
@@ -28,6 +31,9 @@ import org.springframework.data.jpa.domain.support.AuditingEntityListener;
|
|||||||
@Getter
|
@Getter
|
||||||
@ToString(callSuper = true)
|
@ToString(callSuper = true)
|
||||||
@FieldNameConstants
|
@FieldNameConstants
|
||||||
|
@AllArgsConstructor
|
||||||
|
@NoArgsConstructor
|
||||||
|
@Builder
|
||||||
@Entity
|
@Entity
|
||||||
@SoftDelete
|
@SoftDelete
|
||||||
@DynamicUpdate
|
@DynamicUpdate
|
||||||
@@ -1,12 +1,16 @@
|
|||||||
package com.lanyuanxiaoyao.service.template.jpa.entity;
|
package com.lanyuanxiaoyao.service.template.database.jpa.entity;
|
||||||
|
|
||||||
|
import com.lanyuanxiaoyao.service.template.database.common.test.entity.Level;
|
||||||
import jakarta.persistence.Column;
|
import jakarta.persistence.Column;
|
||||||
import jakarta.persistence.Entity;
|
import jakarta.persistence.Entity;
|
||||||
import jakarta.persistence.EntityListeners;
|
import jakarta.persistence.EntityListeners;
|
||||||
import jakarta.persistence.EnumType;
|
import jakarta.persistence.EnumType;
|
||||||
import jakarta.persistence.Enumerated;
|
import jakarta.persistence.Enumerated;
|
||||||
import jakarta.persistence.Table;
|
import jakarta.persistence.Table;
|
||||||
|
import lombok.AllArgsConstructor;
|
||||||
|
import lombok.Builder;
|
||||||
import lombok.Getter;
|
import lombok.Getter;
|
||||||
|
import lombok.NoArgsConstructor;
|
||||||
import lombok.Setter;
|
import lombok.Setter;
|
||||||
import lombok.ToString;
|
import lombok.ToString;
|
||||||
import lombok.experimental.FieldNameConstants;
|
import lombok.experimental.FieldNameConstants;
|
||||||
@@ -19,6 +23,9 @@ import org.springframework.data.jpa.domain.support.AuditingEntityListener;
|
|||||||
@Getter
|
@Getter
|
||||||
@ToString(callSuper = true)
|
@ToString(callSuper = true)
|
||||||
@FieldNameConstants
|
@FieldNameConstants
|
||||||
|
@AllArgsConstructor
|
||||||
|
@NoArgsConstructor
|
||||||
|
@Builder
|
||||||
@Entity
|
@Entity
|
||||||
@SoftDelete
|
@SoftDelete
|
||||||
@DynamicUpdate
|
@DynamicUpdate
|
||||||
@@ -34,8 +41,4 @@ public class Report extends SimpleEntity {
|
|||||||
|
|
||||||
@Column(nullable = false, comment = "员工 ID")
|
@Column(nullable = false, comment = "员工 ID")
|
||||||
private Long employeeId;
|
private Long employeeId;
|
||||||
|
|
||||||
public enum Level {
|
|
||||||
A, B, C, D, E
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
package com.lanyuanxiaoyao.service.template.jpa.entity.vo;
|
package com.lanyuanxiaoyao.service.template.database.jpa.entity.vo;
|
||||||
|
|
||||||
public record EmployeeWithCompanyName(
|
public record EmployeeWithCompanyName(
|
||||||
String name,
|
String name,
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
package com.lanyuanxiaoyao.service.template.database.jpa.repository;
|
||||||
|
|
||||||
|
import com.lanyuanxiaoyao.service.template.database.jpa.entity.Company;
|
||||||
|
import org.springframework.stereotype.Repository;
|
||||||
|
|
||||||
|
@Repository
|
||||||
|
public interface CompanyRepository extends SimpleRepository<Company> {
|
||||||
|
}
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
package com.lanyuanxiaoyao.service.template.jpa.repository;
|
package com.lanyuanxiaoyao.service.template.database.jpa.repository;
|
||||||
|
|
||||||
import com.lanyuanxiaoyao.service.template.jpa.entity.Employee;
|
import com.lanyuanxiaoyao.service.template.database.jpa.entity.Employee;
|
||||||
import com.lanyuanxiaoyao.service.template.jpa.entity.vo.EmployeeWithCompanyName;
|
import com.lanyuanxiaoyao.service.template.database.jpa.entity.vo.EmployeeWithCompanyName;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
import org.springframework.data.jpa.domain.Specification;
|
import org.springframework.data.jpa.domain.Specification;
|
||||||
@@ -16,9 +16,9 @@ public interface EmployeeRepository extends SimpleRepository<Employee> {
|
|||||||
@Override
|
@Override
|
||||||
Optional<Employee> findOne(Specification<Employee> specification);
|
Optional<Employee> findOne(Specification<Employee> specification);
|
||||||
|
|
||||||
@Query(value = "select e.name, c.name, e.age, e.role from employee e, company c where e.company_id = c.id", nativeQuery = true)
|
@Query(value = "select e.name, c.name, e.age, e.role from employee e, company c where e.company_id = c.id and c.deleted = false and e.deleted = false", nativeQuery = true)
|
||||||
List<EmployeeWithCompanyName> findAllEmployeeWithCompanyNameNative();
|
List<EmployeeWithCompanyName> findAllEmployeeWithCompanyNameNative();
|
||||||
|
|
||||||
@Query("select new com.lanyuanxiaoyao.service.template.jpa.entity.vo.EmployeeWithCompanyName(employee.name, employee.company.name, employee.age, cast(employee.role as string)) from Employee employee")
|
@Query("select new com.lanyuanxiaoyao.service.template.database.jpa.entity.vo.EmployeeWithCompanyName(employee.name, employee.company.name, employee.age, cast(employee.role as string)) from Employee employee")
|
||||||
List<EmployeeWithCompanyName> findAllEmployeeWithCompanyName();
|
List<EmployeeWithCompanyName> findAllEmployeeWithCompanyName();
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
package com.lanyuanxiaoyao.service.template.database.jpa.repository;
|
||||||
|
|
||||||
|
import com.lanyuanxiaoyao.service.template.database.jpa.entity.Report;
|
||||||
|
import org.springframework.stereotype.Repository;
|
||||||
|
|
||||||
|
@Repository
|
||||||
|
public interface ReportRepository extends SimpleRepository<Report> {
|
||||||
|
}
|
||||||
@@ -0,0 +1,12 @@
|
|||||||
|
package com.lanyuanxiaoyao.service.template.database.jpa.service;
|
||||||
|
|
||||||
|
import com.lanyuanxiaoyao.service.template.database.jpa.entity.Company;
|
||||||
|
import com.lanyuanxiaoyao.service.template.database.jpa.repository.CompanyRepository;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
|
@Service
|
||||||
|
public class CompanyService extends SimpleServiceSupport<Company> {
|
||||||
|
public CompanyService(CompanyRepository repository) {
|
||||||
|
super(repository);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,12 @@
|
|||||||
|
package com.lanyuanxiaoyao.service.template.database.jpa.service;
|
||||||
|
|
||||||
|
import com.lanyuanxiaoyao.service.template.database.jpa.entity.Employee;
|
||||||
|
import com.lanyuanxiaoyao.service.template.database.jpa.repository.EmployeeRepository;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
|
@Service
|
||||||
|
public class EmployeeService extends SimpleServiceSupport<Employee> {
|
||||||
|
public EmployeeService(EmployeeRepository repository) {
|
||||||
|
super(repository);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,12 @@
|
|||||||
|
package com.lanyuanxiaoyao.service.template.database.jpa.service;
|
||||||
|
|
||||||
|
import com.lanyuanxiaoyao.service.template.database.jpa.entity.Report;
|
||||||
|
import com.lanyuanxiaoyao.service.template.database.jpa.repository.ReportRepository;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
|
@Service
|
||||||
|
public class ReportService extends SimpleServiceSupport<Report> {
|
||||||
|
public ReportService(ReportRepository repository) {
|
||||||
|
super(repository);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,12 @@
|
|||||||
|
spring:
|
||||||
|
profiles:
|
||||||
|
include: test
|
||||||
|
datasource:
|
||||||
|
url: jdbc:h2:mem:testdb;DB_CLOSE_DELAY=-1
|
||||||
|
username: test
|
||||||
|
password: test
|
||||||
|
driver-class-name: org.h2.Driver
|
||||||
|
jpa:
|
||||||
|
generate-ddl: true
|
||||||
|
fenix:
|
||||||
|
print-banner: false
|
||||||
@@ -9,12 +9,12 @@
|
|||||||
<version>1.1.0-SNAPSHOT</version>
|
<version>1.1.0-SNAPSHOT</version>
|
||||||
</parent>
|
</parent>
|
||||||
|
|
||||||
<artifactId>spring-boot-service-template-xbatis</artifactId>
|
<artifactId>spring-boot-service-template-database-xbatis</artifactId>
|
||||||
|
|
||||||
<dependencies>
|
<dependencies>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>com.lanyuanxiaoyao</groupId>
|
<groupId>com.lanyuanxiaoyao</groupId>
|
||||||
<artifactId>spring-boot-service-template-common</artifactId>
|
<artifactId>spring-boot-service-template-database-common</artifactId>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
<dependency>
|
<dependency>
|
||||||
@@ -22,30 +22,15 @@
|
|||||||
<artifactId>spring-boot-starter-web</artifactId>
|
<artifactId>spring-boot-starter-web</artifactId>
|
||||||
<scope>provided</scope>
|
<scope>provided</scope>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>cn.xbatis</groupId>
|
<groupId>cn.xbatis</groupId>
|
||||||
<artifactId>xbatis-spring-boot-starter</artifactId>
|
<artifactId>xbatis-spring-boot-starter</artifactId>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>com.github.gavlyukovskiy</groupId>
|
<groupId>com.lanyuanxiaoyao</groupId>
|
||||||
<artifactId>p6spy-spring-boot-starter</artifactId>
|
<artifactId>spring-boot-service-template-database-common-test</artifactId>
|
||||||
</dependency>
|
|
||||||
|
|
||||||
<dependency>
|
|
||||||
<groupId>org.mapstruct</groupId>
|
|
||||||
<artifactId>mapstruct</artifactId>
|
|
||||||
<scope>compile</scope>
|
|
||||||
</dependency>
|
|
||||||
|
|
||||||
<dependency>
|
|
||||||
<groupId>org.jspecify</groupId>
|
|
||||||
<artifactId>jspecify</artifactId>
|
|
||||||
</dependency>
|
|
||||||
|
|
||||||
<dependency>
|
|
||||||
<groupId>com.h2database</groupId>
|
|
||||||
<artifactId>h2</artifactId>
|
|
||||||
<scope>test</scope>
|
<scope>test</scope>
|
||||||
</dependency>
|
</dependency>
|
||||||
</dependencies>
|
</dependencies>
|
||||||
@@ -1,9 +1,9 @@
|
|||||||
package com.lanyuanxiaoyao.service.template.xbatis.configuration;
|
package com.lanyuanxiaoyao.service.template.database.xbatis.configuration;
|
||||||
|
|
||||||
import cn.xbatis.core.incrementer.GeneratorFactory;
|
import cn.xbatis.core.incrementer.GeneratorFactory;
|
||||||
import cn.xbatis.core.mybatis.mapper.BasicMapper;
|
import cn.xbatis.core.mybatis.mapper.BasicMapper;
|
||||||
import com.lanyuanxiaoyao.service.template.xbatis.entity.SnowflakeIdGenerator;
|
import com.lanyuanxiaoyao.service.template.database.xbatis.entity.SnowflakeIdGenerator;
|
||||||
import com.lanyuanxiaoyao.service.template.xbatis.mapper.MybatisBasicMapper;
|
import com.lanyuanxiaoyao.service.template.database.xbatis.mapper.MybatisBasicMapper;
|
||||||
import org.mybatis.spring.annotation.MapperScan;
|
import org.mybatis.spring.annotation.MapperScan;
|
||||||
import org.springframework.context.annotation.Configuration;
|
import org.springframework.context.annotation.Configuration;
|
||||||
|
|
||||||
@@ -1,11 +1,11 @@
|
|||||||
package com.lanyuanxiaoyao.service.template.jpa.controller;
|
package com.lanyuanxiaoyao.service.template.database.xbatis.controller;
|
||||||
|
|
||||||
import com.lanyuanxiaoyao.service.template.common.controller.SimpleController;
|
|
||||||
import com.lanyuanxiaoyao.service.template.common.entity.GlobalResponse;
|
|
||||||
import com.lanyuanxiaoyao.service.template.common.entity.Query;
|
|
||||||
import com.lanyuanxiaoyao.service.template.common.helper.ObjectHelper;
|
import com.lanyuanxiaoyao.service.template.common.helper.ObjectHelper;
|
||||||
import com.lanyuanxiaoyao.service.template.jpa.entity.SimpleEntity;
|
import com.lanyuanxiaoyao.service.template.database.common.controller.SimpleController;
|
||||||
import com.lanyuanxiaoyao.service.template.jpa.service.SimpleServiceSupport;
|
import com.lanyuanxiaoyao.service.template.database.common.entity.GlobalResponse;
|
||||||
|
import com.lanyuanxiaoyao.service.template.database.common.entity.Query;
|
||||||
|
import com.lanyuanxiaoyao.service.template.database.xbatis.entity.SimpleEntity;
|
||||||
|
import com.lanyuanxiaoyao.service.template.database.xbatis.service.SimpleServiceSupport;
|
||||||
import java.util.function.Function;
|
import java.util.function.Function;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import org.springframework.transaction.annotation.Transactional;
|
import org.springframework.transaction.annotation.Transactional;
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
package com.lanyuanxiaoyao.service.template.xbatis.entity;
|
package com.lanyuanxiaoyao.service.template.database.xbatis.entity;
|
||||||
|
|
||||||
import cn.xbatis.db.IdAutoType;
|
import cn.xbatis.db.IdAutoType;
|
||||||
import cn.xbatis.db.annotations.TableId;
|
import cn.xbatis.db.annotations.TableId;
|
||||||
@@ -0,0 +1,20 @@
|
|||||||
|
package com.lanyuanxiaoyao.service.template.database.xbatis.entity;
|
||||||
|
|
||||||
|
import cn.xbatis.db.annotations.LogicDelete;
|
||||||
|
import cn.xbatis.db.annotations.LogicDeleteTime;
|
||||||
|
import java.time.LocalDateTime;
|
||||||
|
import lombok.Getter;
|
||||||
|
import lombok.Setter;
|
||||||
|
import lombok.ToString;
|
||||||
|
import lombok.experimental.FieldNameConstants;
|
||||||
|
|
||||||
|
@Getter
|
||||||
|
@Setter
|
||||||
|
@ToString
|
||||||
|
@FieldNameConstants
|
||||||
|
public class LogicDeleteEntity extends IdOnlyEntity {
|
||||||
|
@LogicDelete
|
||||||
|
private Boolean deleted = false;
|
||||||
|
@LogicDeleteTime
|
||||||
|
private LocalDateTime deletedTime;
|
||||||
|
}
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
package com.lanyuanxiaoyao.service.template.xbatis.entity;
|
package com.lanyuanxiaoyao.service.template.database.xbatis.entity;
|
||||||
|
|
||||||
import cn.xbatis.db.annotations.TableField;
|
import cn.xbatis.db.annotations.TableField;
|
||||||
import java.time.LocalDateTime;
|
import java.time.LocalDateTime;
|
||||||
@@ -11,7 +11,7 @@ import lombok.experimental.FieldNameConstants;
|
|||||||
@Setter
|
@Setter
|
||||||
@ToString(callSuper = true)
|
@ToString(callSuper = true)
|
||||||
@FieldNameConstants
|
@FieldNameConstants
|
||||||
public class SimpleEntity extends IdOnlyEntity {
|
public class SimpleEntity extends LogicDeleteEntity {
|
||||||
@TableField(defaultValue = "{NOW}", defaultValueFillAlways = true)
|
@TableField(defaultValue = "{NOW}", defaultValueFillAlways = true)
|
||||||
private LocalDateTime createdTime;
|
private LocalDateTime createdTime;
|
||||||
@TableField(defaultValue = "{NOW}", defaultValueFillAlways = true, updateDefaultValue = "{NOW}", updateDefaultValueFillAlways = true)
|
@TableField(defaultValue = "{NOW}", defaultValueFillAlways = true, updateDefaultValue = "{NOW}", updateDefaultValueFillAlways = true)
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
package com.lanyuanxiaoyao.service.template.xbatis.entity;
|
package com.lanyuanxiaoyao.service.template.database.xbatis.entity;
|
||||||
|
|
||||||
import cn.xbatis.core.incrementer.Generator;
|
import cn.xbatis.core.incrementer.Generator;
|
||||||
import com.lanyuanxiaoyao.service.template.common.helper.SnowflakeHelper;
|
import com.lanyuanxiaoyao.service.template.database.common.helper.SnowflakeHelper;
|
||||||
|
|
||||||
public class SnowflakeIdGenerator implements Generator<Long> {
|
public class SnowflakeIdGenerator implements Generator<Long> {
|
||||||
@Override
|
@Override
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
package com.lanyuanxiaoyao.service.template.xbatis.mapper;
|
package com.lanyuanxiaoyao.service.template.database.xbatis.mapper;
|
||||||
|
|
||||||
import cn.xbatis.core.mybatis.mapper.BasicMapper;
|
import cn.xbatis.core.mybatis.mapper.BasicMapper;
|
||||||
|
|
||||||
@@ -1,16 +1,16 @@
|
|||||||
package com.lanyuanxiaoyao.service.template.xbatis.service;
|
package com.lanyuanxiaoyao.service.template.database.xbatis.service;
|
||||||
|
|
||||||
import cn.xbatis.core.mybatis.mapper.context.Pager;
|
import cn.xbatis.core.mybatis.mapper.context.Pager;
|
||||||
import cn.xbatis.core.sql.MybatisCmdFactory;
|
import cn.xbatis.core.sql.MybatisCmdFactory;
|
||||||
import cn.xbatis.core.sql.executor.chain.QueryChain;
|
import cn.xbatis.core.sql.executor.chain.QueryChain;
|
||||||
import com.lanyuanxiaoyao.service.template.common.entity.Page;
|
|
||||||
import com.lanyuanxiaoyao.service.template.common.entity.Query;
|
|
||||||
import com.lanyuanxiaoyao.service.template.common.exception.IdNotFoundException;
|
|
||||||
import com.lanyuanxiaoyao.service.template.common.helper.ObjectHelper;
|
import com.lanyuanxiaoyao.service.template.common.helper.ObjectHelper;
|
||||||
import com.lanyuanxiaoyao.service.template.common.service.QueryParser;
|
import com.lanyuanxiaoyao.service.template.database.common.entity.Page;
|
||||||
import com.lanyuanxiaoyao.service.template.common.service.SimpleService;
|
import com.lanyuanxiaoyao.service.template.database.common.entity.Query;
|
||||||
import com.lanyuanxiaoyao.service.template.xbatis.entity.SimpleEntity;
|
import com.lanyuanxiaoyao.service.template.database.common.exception.IdNotFoundException;
|
||||||
import com.lanyuanxiaoyao.service.template.xbatis.mapper.MybatisBasicMapper;
|
import com.lanyuanxiaoyao.service.template.database.common.service.QueryParser;
|
||||||
|
import com.lanyuanxiaoyao.service.template.database.common.service.SimpleService;
|
||||||
|
import com.lanyuanxiaoyao.service.template.database.xbatis.entity.SimpleEntity;
|
||||||
|
import com.lanyuanxiaoyao.service.template.database.xbatis.mapper.MybatisBasicMapper;
|
||||||
import db.sql.api.cmd.LikeMode;
|
import db.sql.api.cmd.LikeMode;
|
||||||
import db.sql.api.impl.cmd.basic.OrderByDirection;
|
import db.sql.api.impl.cmd.basic.OrderByDirection;
|
||||||
import db.sql.api.impl.cmd.struct.Where;
|
import db.sql.api.impl.cmd.struct.Where;
|
||||||
@@ -18,6 +18,8 @@ import java.util.List;
|
|||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.mapstruct.Named;
|
||||||
|
import org.springframework.transaction.annotation.Transactional;
|
||||||
|
|
||||||
@Slf4j
|
@Slf4j
|
||||||
public abstract class SimpleServiceSupport<ENTITY extends SimpleEntity> implements SimpleService<ENTITY> {
|
public abstract class SimpleServiceSupport<ENTITY extends SimpleEntity> implements SimpleService<ENTITY> {
|
||||||
@@ -32,14 +34,17 @@ public abstract class SimpleServiceSupport<ENTITY extends SimpleEntity> implemen
|
|||||||
this.mapper = mapper;
|
this.mapper = mapper;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Transactional(rollbackFor = Throwable.class)
|
||||||
@Override
|
@Override
|
||||||
public Long save(ENTITY entity) {
|
public Long save(ENTITY entity) {
|
||||||
return (long) mapper.save(entity);
|
mapper.saveOrUpdate(entity);
|
||||||
|
return entity.getId();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Transactional(rollbackFor = Throwable.class)
|
||||||
@Override
|
@Override
|
||||||
public void save(Iterable<ENTITY> entities) {
|
public void save(Iterable<ENTITY> entities) {
|
||||||
mapper.save(entities);
|
mapper.saveOrUpdate(entities);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -71,7 +76,6 @@ public abstract class SimpleServiceSupport<ENTITY extends SimpleEntity> implemen
|
|||||||
var size = Math.max(ObjectHelper.defaultIfNull(query.page().size(), DEFAULT_PAGE_SIZE), 1);
|
var size = Math.max(ObjectHelper.defaultIfNull(query.page().size(), DEFAULT_PAGE_SIZE), 1);
|
||||||
paging = Pager.of(index, size);
|
paging = Pager.of(index, size);
|
||||||
}
|
}
|
||||||
chain.paging(paging);
|
|
||||||
|
|
||||||
if (ObjectHelper.isNotEmpty(query.sort())) {
|
if (ObjectHelper.isNotEmpty(query.sort())) {
|
||||||
query.sort().forEach(sort -> chain.orderBy(OrderByDirection.valueOf(sort.direction().name()), sort.column()));
|
query.sort().forEach(sort -> chain.orderBy(OrderByDirection.valueOf(sort.direction().name()), sort.column()));
|
||||||
@@ -79,141 +83,146 @@ public abstract class SimpleServiceSupport<ENTITY extends SimpleEntity> implemen
|
|||||||
|
|
||||||
var where = chain.where();
|
var where = chain.where();
|
||||||
commonPredicates(where);
|
commonPredicates(where);
|
||||||
new XBatisQueryParser<>(target, factory, where).build(query.query());
|
new XBatisQueryParser<>(query.query(), where, target, factory).build();
|
||||||
|
|
||||||
return new Page<>(chain.list(), chain.count());
|
var pager = chain.paging(paging);
|
||||||
|
|
||||||
|
return new Page<>(pager.getResults(), pager.getTotal());
|
||||||
}
|
}
|
||||||
|
|
||||||
private Optional<ENTITY> detailOptional(Long id) {
|
private Optional<ENTITY> detailOptional(Long id) {
|
||||||
if (ObjectHelper.isNull(id)) {
|
if (ObjectHelper.isNull(id)) {
|
||||||
return Optional.empty();
|
return Optional.empty();
|
||||||
}
|
}
|
||||||
return Optional.ofNullable(mapper.getById(target, id));
|
return mapper.getOptionalById(target, id);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Named("detail")
|
||||||
@Override
|
@Override
|
||||||
public ENTITY detail(Long id) {
|
public ENTITY detail(Long id) {
|
||||||
return detailOptional(id).orElse(null);
|
return detailOptional(id).orElse(null);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Named("detailOrThrow")
|
||||||
@Override
|
@Override
|
||||||
public ENTITY detailOrThrow(Long id) {
|
public ENTITY detailOrThrow(Long id) {
|
||||||
return detailOptional(id).orElseThrow(() -> new IdNotFoundException(id));
|
return detailOptional(id).orElseThrow(() -> new IdNotFoundException(id));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Transactional(rollbackFor = Throwable.class)
|
||||||
@Override
|
@Override
|
||||||
public void remove(Long id) {
|
public void remove(Long id) {
|
||||||
mapper.deleteById(target, id);
|
mapper.deleteById(target, id);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Transactional(rollbackFor = Throwable.class)
|
||||||
@Override
|
@Override
|
||||||
public void remove(Set<Long> ids) {
|
public void remove(Set<Long> ids) {
|
||||||
mapper.deleteByIds(target, ids);
|
mapper.deleteByIds(target, ids);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static final class XBatisQueryParser<ENTITY> extends QueryParser<Void> {
|
private static final class XBatisQueryParser<ENTITY> extends QueryParser<Where> {
|
||||||
private final Class<ENTITY> target;
|
private final Class<ENTITY> target;
|
||||||
private final MybatisCmdFactory factory;
|
private final MybatisCmdFactory factory;
|
||||||
private final Where where;
|
|
||||||
|
|
||||||
private XBatisQueryParser(Class<ENTITY> target, MybatisCmdFactory factory, Where where) {
|
private XBatisQueryParser(Query.Queryable queryable, Where where, Class<ENTITY> target, MybatisCmdFactory factory) {
|
||||||
|
super(queryable, where);
|
||||||
this.target = target;
|
this.target = target;
|
||||||
this.factory = factory;
|
this.factory = factory;
|
||||||
this.where = where;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void nullEqual(Query.Queryable queryable) {
|
protected void nullEqual(Query.Queryable queryable, Where where) {
|
||||||
queryable.nullEqual().forEach(column -> where.isNull(factory.field(target, column)));
|
queryable.nullEqual().forEach(column -> where.isNull(factory.field(target, column)));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void notNullEqual(Query.Queryable queryable) {
|
protected void notNullEqual(Query.Queryable queryable, Where where) {
|
||||||
queryable.notNullEqual().forEach(column -> where.isNotNull(factory.field(target, column)));
|
queryable.notNullEqual().forEach(column -> where.isNotNull(factory.field(target, column)));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void empty(Query.Queryable queryable) {
|
protected void empty(Query.Queryable queryable, Where where) {
|
||||||
throw new UnsupportedOperationException();
|
throw new UnsupportedOperationException();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void notEmpty(Query.Queryable queryable) {
|
protected void notEmpty(Query.Queryable queryable, Where where) {
|
||||||
throw new UnsupportedOperationException();
|
throw new UnsupportedOperationException();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void equal(Query.Queryable queryable) {
|
protected void equal(Query.Queryable queryable, Where where) {
|
||||||
queryable.equal().forEach((column, value) -> where.eq(factory.field(target, column), value));
|
queryable.equal().forEach((column, value) -> where.eq(factory.field(target, column), value));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void notEqual(Query.Queryable queryable) {
|
protected void notEqual(Query.Queryable queryable, Where where) {
|
||||||
queryable.notEqual().forEach((column, value) -> where.ne(factory.field(target, column), value));
|
queryable.notEqual().forEach((column, value) -> where.ne(factory.field(target, column), value));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void like(Query.Queryable queryable) {
|
protected void like(Query.Queryable queryable, Where where) {
|
||||||
queryable.like().forEach((column, value) -> where.like(LikeMode.NONE, factory.field(target, column), value));
|
queryable.like().forEach((column, value) -> where.like(LikeMode.NONE, factory.field(target, column), value));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void notLike(Query.Queryable queryable) {
|
protected void notLike(Query.Queryable queryable, Where where) {
|
||||||
queryable.notLike().forEach((column, value) -> where.notLike(LikeMode.NONE, factory.field(target, column), value));
|
queryable.notLike().forEach((column, value) -> where.notLike(LikeMode.NONE, factory.field(target, column), value));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void contain(Query.Queryable queryable) {
|
protected void contain(Query.Queryable queryable, Where where) {
|
||||||
queryable.contain().forEach((column, value) -> where.like(factory.field(target, column), value));
|
queryable.contain().forEach((column, value) -> where.like(factory.field(target, column), value));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void notContain(Query.Queryable queryable) {
|
protected void notContain(Query.Queryable queryable, Where where) {
|
||||||
queryable.notContain().forEach((column, value) -> where.notLike(factory.field(target, column), value));
|
queryable.notContain().forEach((column, value) -> where.notLike(factory.field(target, column), value));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void startWith(Query.Queryable queryable) {
|
protected void startWith(Query.Queryable queryable, Where where) {
|
||||||
queryable.startWith().forEach((column, value) -> where.like(LikeMode.LEFT, factory.field(target, column), value));
|
queryable.startWith().forEach((column, value) -> where.like(LikeMode.RIGHT, factory.field(target, column), value));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void notStartWith(Query.Queryable queryable) {
|
protected void notStartWith(Query.Queryable queryable, Where where) {
|
||||||
queryable.notStartWith().forEach((column, value) -> where.notLike(LikeMode.LEFT, factory.field(target, column), value));
|
queryable.notStartWith().forEach((column, value) -> where.notLike(LikeMode.RIGHT, factory.field(target, column), value));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void endWith(Query.Queryable queryable) {
|
protected void endWith(Query.Queryable queryable, Where where) {
|
||||||
queryable.endWith().forEach((column, value) -> where.like(LikeMode.RIGHT, factory.field(target, column), value));
|
queryable.endWith().forEach((column, value) -> where.like(LikeMode.LEFT, factory.field(target, column), value));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void notEndWith(Query.Queryable queryable) {
|
protected void notEndWith(Query.Queryable queryable, Where where) {
|
||||||
queryable.notEndWith().forEach((column, value) -> where.notLike(LikeMode.RIGHT, factory.field(target, column), value));
|
queryable.notEndWith().forEach((column, value) -> where.notLike(LikeMode.LEFT, factory.field(target, column), value));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void great(Query.Queryable queryable) {
|
protected void great(Query.Queryable queryable, Where where) {
|
||||||
queryable.great().forEach((column, value) -> where.gt(factory.field(target, column), value));
|
queryable.great().forEach((column, value) -> where.gt(factory.field(target, column), value));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void less(Query.Queryable queryable) {
|
protected void less(Query.Queryable queryable, Where where) {
|
||||||
queryable.less().forEach((column, value) -> where.lt(factory.field(target, column), value));
|
queryable.less().forEach((column, value) -> where.lt(factory.field(target, column), value));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void greatEqual(Query.Queryable queryable) {
|
protected void greatEqual(Query.Queryable queryable, Where where) {
|
||||||
queryable.greatEqual().forEach((column, value) -> where.gte(factory.field(target, column), value));
|
queryable.greatEqual().forEach((column, value) -> where.gte(factory.field(target, column), value));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void lessEqual(Query.Queryable queryable) {
|
protected void lessEqual(Query.Queryable queryable, Where where) {
|
||||||
queryable.lessEqual().forEach((column, value) -> where.lte(factory.field(target, column), value));
|
queryable.lessEqual().forEach((column, value) -> where.lte(factory.field(target, column), value));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void inside(Query.Queryable queryable) {
|
protected void inside(Query.Queryable queryable, Where where) {
|
||||||
queryable.inside()
|
queryable.inside()
|
||||||
.entrySet()
|
.entrySet()
|
||||||
.stream()
|
.stream()
|
||||||
@@ -222,7 +231,7 @@ public abstract class SimpleServiceSupport<ENTITY extends SimpleEntity> implemen
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void notInside(Query.Queryable queryable) {
|
protected void notInside(Query.Queryable queryable, Where where) {
|
||||||
queryable.notInside()
|
queryable.notInside()
|
||||||
.entrySet()
|
.entrySet()
|
||||||
.stream()
|
.stream()
|
||||||
@@ -231,18 +240,13 @@ public abstract class SimpleServiceSupport<ENTITY extends SimpleEntity> implemen
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void between(Query.Queryable queryable) {
|
protected void between(Query.Queryable queryable, Where where) {
|
||||||
queryable.between().forEach((column, value) -> where.between(factory.field(target, column), value.start(), value.end()));
|
queryable.between().forEach((column, value) -> where.between(factory.field(target, column), value.start(), value.end()));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void notBetween(Query.Queryable queryable) {
|
protected void notBetween(Query.Queryable queryable, Where where) {
|
||||||
queryable.notBetween().forEach((column, value) -> where.notBetween(factory.field(target, column), value.start(), value.end()));
|
queryable.notBetween().forEach((column, value) -> where.notBetween(factory.field(target, column), value.start(), value.end()));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
protected Void build() {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -4,7 +4,9 @@ create table if not exists Company
|
|||||||
name varchar(255) not null,
|
name varchar(255) not null,
|
||||||
members int not null,
|
members int not null,
|
||||||
created_time timestamp not null,
|
created_time timestamp not null,
|
||||||
modified_time timestamp not null
|
modified_time timestamp not null,
|
||||||
|
deleted tinyint not null default 0,
|
||||||
|
deleted_time timestamp
|
||||||
);
|
);
|
||||||
|
|
||||||
create table if not exists Employee
|
create table if not exists Employee
|
||||||
@@ -12,6 +14,9 @@ create table if not exists Employee
|
|||||||
id bigint primary key,
|
id bigint primary key,
|
||||||
name varchar(255) not null,
|
name varchar(255) not null,
|
||||||
age int not null,
|
age int not null,
|
||||||
|
company_id bigint not null,
|
||||||
created_time timestamp not null,
|
created_time timestamp not null,
|
||||||
modified_time timestamp not null
|
modified_time timestamp not null,
|
||||||
|
deleted tinyint not null default 0,
|
||||||
|
deleted_time timestamp
|
||||||
);
|
);
|
||||||
@@ -0,0 +1,82 @@
|
|||||||
|
package com.lanyuanxiaoyao.service.template.database.xbatis;
|
||||||
|
|
||||||
|
import cn.xbatis.core.sql.executor.chain.QueryChain;
|
||||||
|
import com.lanyuanxiaoyao.service.template.database.common.test.AbstractTestApplication;
|
||||||
|
import com.lanyuanxiaoyao.service.template.database.xbatis.entity.Company;
|
||||||
|
import com.lanyuanxiaoyao.service.template.database.xbatis.entity.Employee;
|
||||||
|
import com.lanyuanxiaoyao.service.template.database.xbatis.entity.vo.EmployeeWithCompanyName;
|
||||||
|
import com.lanyuanxiaoyao.service.template.database.xbatis.mapper.MybatisBasicMapper;
|
||||||
|
import db.sql.api.cmd.LikeMode;
|
||||||
|
import lombok.RequiredArgsConstructor;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.mybatis.spring.annotation.MapperScan;
|
||||||
|
import org.springframework.boot.SpringApplication;
|
||||||
|
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||||
|
import org.springframework.boot.context.event.ApplicationReadyEvent;
|
||||||
|
import org.springframework.context.event.EventListener;
|
||||||
|
import org.springframework.util.Assert;
|
||||||
|
|
||||||
|
@Slf4j
|
||||||
|
@RequiredArgsConstructor
|
||||||
|
@MapperScan("com.lanyuanxiaoyao.service.template.database.xbatis.mapper")
|
||||||
|
@SpringBootApplication
|
||||||
|
public class TestApplication extends AbstractTestApplication {
|
||||||
|
private final MybatisBasicMapper mapper;
|
||||||
|
|
||||||
|
public static void main(String[] args) {
|
||||||
|
SpringApplication.run(TestApplication.class, args);
|
||||||
|
}
|
||||||
|
|
||||||
|
@EventListener(ApplicationReadyEvent.class)
|
||||||
|
public void runTests() {
|
||||||
|
testCrud();
|
||||||
|
testDelete();
|
||||||
|
testQuery();
|
||||||
|
|
||||||
|
System.exit(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void testDelete() {
|
||||||
|
formatLog("Delete");
|
||||||
|
saveItem("company", randomCompany());
|
||||||
|
saveItem("company", randomCompany());
|
||||||
|
mapper.deleteAll(Company.class);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void testQuery() {
|
||||||
|
formatLog("Added");
|
||||||
|
var company1 = Company.builder().name(randomString(5)).members(randomInt(100)).build();
|
||||||
|
mapper.saveOrUpdate(company1);
|
||||||
|
var company2 = Company.builder().name(randomString(5)).members(randomInt(100)).build();
|
||||||
|
mapper.saveOrUpdate(company2);
|
||||||
|
var employee1 = Employee.builder().name("Tom").age(randomInt(100)).companyId(company1.getId()).build();
|
||||||
|
mapper.saveOrUpdate(employee1);
|
||||||
|
var employee2 = Employee.builder().name(randomString(10)).age(randomInt(100)).companyId(company2.getId()).build();
|
||||||
|
mapper.saveOrUpdate(employee2);
|
||||||
|
|
||||||
|
formatLog("Query");
|
||||||
|
var employees1 = QueryChain.of(mapper, Employee.class)
|
||||||
|
.isNotNull(Employee::getName)
|
||||||
|
.eq(Employee::getName, "Tom")
|
||||||
|
.like(Employee::getName, "To")
|
||||||
|
.like(LikeMode.RIGHT, Employee::getName, "To")
|
||||||
|
.like(LikeMode.LEFT, Employee::getName, "om")
|
||||||
|
.lt(Employee::getAge, 200)
|
||||||
|
.gt(Employee::getAge, 0)
|
||||||
|
.in(Employee::getName, "Tom", "Mike")
|
||||||
|
.between(Employee::getAge, 0, 200)
|
||||||
|
.list();
|
||||||
|
Assert.isTrue(employees1.size() == 1, "查询数量错误");
|
||||||
|
|
||||||
|
formatLog("Query Join");
|
||||||
|
var employees2 = QueryChain.of(mapper, Employee.class)
|
||||||
|
.select(Employee::getName, Employee::getAge)
|
||||||
|
.select(Company::getId, c -> c.as(EmployeeWithCompanyName::getCompanyName))
|
||||||
|
.leftJoin(Employee.class, Company.class, on -> on.eq(Employee::getCompanyId, Company::getId).gt(Company::getMembers, 0))
|
||||||
|
.eq(Employee::getName, "Tom")
|
||||||
|
.lt(Company::getMembers, 200)
|
||||||
|
.returnType(EmployeeWithCompanyName.class)
|
||||||
|
.list();
|
||||||
|
Assert.isTrue(employees2.size() == 1, "查询数量错误");
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
package com.lanyuanxiaoyao.service.template.xbatis.controller;
|
package com.lanyuanxiaoyao.service.template.database.xbatis.controller;
|
||||||
|
|
||||||
import com.lanyuanxiaoyao.service.template.xbatis.entity.Company;
|
import com.lanyuanxiaoyao.service.template.database.xbatis.entity.Company;
|
||||||
import com.lanyuanxiaoyao.service.template.xbatis.service.CompanyService;
|
import com.lanyuanxiaoyao.service.template.database.xbatis.service.CompanyService;
|
||||||
import java.time.LocalDateTime;
|
import java.time.LocalDateTime;
|
||||||
import java.util.function.Function;
|
import java.util.function.Function;
|
||||||
import org.springframework.web.bind.annotation.RequestMapping;
|
import org.springframework.web.bind.annotation.RequestMapping;
|
||||||
@@ -1,7 +1,10 @@
|
|||||||
package com.lanyuanxiaoyao.service.template.xbatis.entity;
|
package com.lanyuanxiaoyao.service.template.database.xbatis.entity;
|
||||||
|
|
||||||
import cn.xbatis.db.annotations.Table;
|
import cn.xbatis.db.annotations.Table;
|
||||||
|
import lombok.AllArgsConstructor;
|
||||||
|
import lombok.Builder;
|
||||||
import lombok.Getter;
|
import lombok.Getter;
|
||||||
|
import lombok.NoArgsConstructor;
|
||||||
import lombok.Setter;
|
import lombok.Setter;
|
||||||
import lombok.ToString;
|
import lombok.ToString;
|
||||||
import lombok.experimental.FieldNameConstants;
|
import lombok.experimental.FieldNameConstants;
|
||||||
@@ -10,6 +13,9 @@ import lombok.experimental.FieldNameConstants;
|
|||||||
@Setter
|
@Setter
|
||||||
@ToString(callSuper = true)
|
@ToString(callSuper = true)
|
||||||
@FieldNameConstants
|
@FieldNameConstants
|
||||||
|
@AllArgsConstructor
|
||||||
|
@NoArgsConstructor
|
||||||
|
@Builder
|
||||||
@Table
|
@Table
|
||||||
public class Company extends SimpleEntity {
|
public class Company extends SimpleEntity {
|
||||||
private String name;
|
private String name;
|
||||||
@@ -0,0 +1,25 @@
|
|||||||
|
package com.lanyuanxiaoyao.service.template.database.xbatis.entity;
|
||||||
|
|
||||||
|
import cn.xbatis.db.annotations.Table;
|
||||||
|
import lombok.AllArgsConstructor;
|
||||||
|
import lombok.Builder;
|
||||||
|
import lombok.Getter;
|
||||||
|
import lombok.NoArgsConstructor;
|
||||||
|
import lombok.Setter;
|
||||||
|
import lombok.ToString;
|
||||||
|
import lombok.experimental.FieldNameConstants;
|
||||||
|
|
||||||
|
@Getter
|
||||||
|
@Setter
|
||||||
|
@ToString(callSuper = true)
|
||||||
|
@FieldNameConstants
|
||||||
|
@AllArgsConstructor
|
||||||
|
@NoArgsConstructor
|
||||||
|
@Builder
|
||||||
|
@Table
|
||||||
|
public class Employee extends SimpleEntity {
|
||||||
|
private String name;
|
||||||
|
private Integer age;
|
||||||
|
|
||||||
|
private Long companyId;
|
||||||
|
}
|
||||||
@@ -1,6 +1,5 @@
|
|||||||
package com.lanyuanxiaoyao.service.template.xbatis.entity;
|
package com.lanyuanxiaoyao.service.template.database.xbatis.entity.vo;
|
||||||
|
|
||||||
import cn.xbatis.db.annotations.Table;
|
|
||||||
import lombok.Getter;
|
import lombok.Getter;
|
||||||
import lombok.Setter;
|
import lombok.Setter;
|
||||||
import lombok.ToString;
|
import lombok.ToString;
|
||||||
@@ -10,8 +9,8 @@ import lombok.experimental.FieldNameConstants;
|
|||||||
@Setter
|
@Setter
|
||||||
@ToString(callSuper = true)
|
@ToString(callSuper = true)
|
||||||
@FieldNameConstants
|
@FieldNameConstants
|
||||||
@Table
|
public class EmployeeWithCompanyName {
|
||||||
public class Employee extends SimpleEntity {
|
|
||||||
private String name;
|
private String name;
|
||||||
private Integer age;
|
private Integer age;
|
||||||
|
private String companyName;
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,12 @@
|
|||||||
|
package com.lanyuanxiaoyao.service.template.database.xbatis.service;
|
||||||
|
|
||||||
|
import com.lanyuanxiaoyao.service.template.database.xbatis.entity.Company;
|
||||||
|
import com.lanyuanxiaoyao.service.template.database.xbatis.mapper.MybatisBasicMapper;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
|
@Service
|
||||||
|
public class CompanyService extends SimpleServiceSupport<Company> {
|
||||||
|
public CompanyService(MybatisBasicMapper mapper) {
|
||||||
|
super(Company.class, mapper);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,12 @@
|
|||||||
|
package com.lanyuanxiaoyao.service.template.database.xbatis.service;
|
||||||
|
|
||||||
|
import com.lanyuanxiaoyao.service.template.database.xbatis.entity.Employee;
|
||||||
|
import com.lanyuanxiaoyao.service.template.database.xbatis.mapper.MybatisBasicMapper;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
|
@Service
|
||||||
|
public class EmployeeService extends SimpleServiceSupport<Employee> {
|
||||||
|
public EmployeeService(MybatisBasicMapper mapper) {
|
||||||
|
super(Employee.class, mapper);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,22 +1,11 @@
|
|||||||
server:
|
|
||||||
port: 2490
|
|
||||||
spring:
|
spring:
|
||||||
application:
|
profiles:
|
||||||
name: Test
|
include: test
|
||||||
datasource:
|
datasource:
|
||||||
url: "jdbc:h2:mem:testdb;DB_CLOSE_DELAY=-1;MODE=MySQL;DATABASE_TO_LOWER=TRUE;INIT=runscript from '/Users/lanyuanxiaoyao/Project/IdeaProjects/spring-boot-service-template/spring-boot-service-template-xbatis/src/test/initial.sql'"
|
url: "jdbc:h2:mem:testdb;DB_CLOSE_DELAY=-1;MODE=MySQL;DATABASE_TO_LOWER=TRUE;INIT=runscript from '/Users/lanyuanxiaoyao/Project/IdeaProjects/spring-boot-service-template/spring-boot-service-template-database/spring-boot-service-template-database-xbatis/src/test/initial.sql'"
|
||||||
username: test
|
username: test
|
||||||
password: test
|
password: test
|
||||||
driver-class-name: org.h2.Driver
|
driver-class-name: org.h2.Driver
|
||||||
mybatis:
|
mybatis:
|
||||||
configuration:
|
configuration:
|
||||||
banner: false
|
banner: false
|
||||||
decorator:
|
|
||||||
datasource:
|
|
||||||
p6spy:
|
|
||||||
multiline: false
|
|
||||||
exclude-categories:
|
|
||||||
- commit
|
|
||||||
- result
|
|
||||||
- resultset
|
|
||||||
log-format: "%(category)|%(executionTime)|%(sqlSingleLine)"
|
|
||||||
@@ -1,167 +0,0 @@
|
|||||||
package com.lanyuanxiaoyao.service.template.eq;
|
|
||||||
|
|
||||||
import lombok.RequiredArgsConstructor;
|
|
||||||
import lombok.extern.slf4j.Slf4j;
|
|
||||||
import org.springframework.boot.SpringApplication;
|
|
||||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
|
||||||
import org.springframework.boot.context.event.ApplicationReadyEvent;
|
|
||||||
import org.springframework.context.event.EventListener;
|
|
||||||
import org.springframework.http.HttpEntity;
|
|
||||||
import org.springframework.http.HttpHeaders;
|
|
||||||
import org.springframework.http.MediaType;
|
|
||||||
import org.springframework.util.Assert;
|
|
||||||
import org.springframework.web.client.RestTemplate;
|
|
||||||
import tools.jackson.databind.JsonNode;
|
|
||||||
import tools.jackson.databind.ObjectMapper;
|
|
||||||
|
|
||||||
@Slf4j
|
|
||||||
@RequiredArgsConstructor
|
|
||||||
@SpringBootApplication
|
|
||||||
public class TestApplication {
|
|
||||||
private static final String BASE_URL = "http://localhost:2490";
|
|
||||||
private static final RestTemplate REST_CLIENT = new RestTemplate();
|
|
||||||
private static final ObjectMapper MAPPER = new ObjectMapper();
|
|
||||||
|
|
||||||
public static void main(String[] args) {
|
|
||||||
SpringApplication.run(TestApplication.class, args);
|
|
||||||
}
|
|
||||||
|
|
||||||
@EventListener(ApplicationReadyEvent.class)
|
|
||||||
public void runTests() {
|
|
||||||
// 增
|
|
||||||
var cid1 = saveItem("company", "{\"name\": \"Apple\",\"members\": 10}").get("data").asLong();
|
|
||||||
var cid2 = saveItem("company", "{\"name\": \"Banana\",\"members\": 20}").get("data").asLong();
|
|
||||||
var cid3 = saveItem("company", "{\"name\": \"Cheery\",\"members\": 20}").get("data").asLong();
|
|
||||||
|
|
||||||
// 查
|
|
||||||
var companies = listItems("company");
|
|
||||||
Assert.isTrue(companies.at("/data/items").size() == 3, "数量错误");
|
|
||||||
Assert.isTrue(companies.at("/data/total").asLong() == 3, "返回数量错误");
|
|
||||||
|
|
||||||
// language=JSON
|
|
||||||
var companies2 = listItems("company", "{\n" +
|
|
||||||
" \"page\": {\n" +
|
|
||||||
" \"index\": 1,\n" +
|
|
||||||
" \"size\": 2\n" +
|
|
||||||
" }\n" +
|
|
||||||
"}");
|
|
||||||
Assert.isTrue(companies2.at("/data/items").size() == 2, "数量错误");
|
|
||||||
Assert.isTrue(companies2.at("/data/total").asLong() == 3, "返回数量错误");
|
|
||||||
// language=JSON
|
|
||||||
var companies3 = listItems("company", "{\n" +
|
|
||||||
" \"query\": {\n" +
|
|
||||||
" \"notNullEqual\": [\n" +
|
|
||||||
" \"name\"\n" +
|
|
||||||
" ],\n" +
|
|
||||||
" \"equal\": {\n" +
|
|
||||||
" \"name\": \"Apple\"\n" +
|
|
||||||
" },\n" +
|
|
||||||
" \"like\": {\n" +
|
|
||||||
" \"name\": \"Appl%\"\n" +
|
|
||||||
" },\n" +
|
|
||||||
" \"contain\": {\n" +
|
|
||||||
" \"name\": \"ple\"\n" +
|
|
||||||
" },\n" +
|
|
||||||
" \"startWith\": {\n" +
|
|
||||||
" \"name\": \"Appl\"\n" +
|
|
||||||
" },\n" +
|
|
||||||
" \"endWith\": {\n" +
|
|
||||||
" \"name\": \"le\"\n" +
|
|
||||||
" },\n" +
|
|
||||||
" \"less\": {\n" +
|
|
||||||
" \"members\": 50\n" +
|
|
||||||
" },\n" +
|
|
||||||
" \"greatEqual\": {\n" +
|
|
||||||
" \"members\": 0,\n" +
|
|
||||||
" \"createdTime\": \"2025-01-01 00:00:00\"\n" +
|
|
||||||
" },\n" +
|
|
||||||
" \"inside\": {\n" +
|
|
||||||
" \"name\": [\n" +
|
|
||||||
" \"Apple\",\n" +
|
|
||||||
" \"Banana\"\n" +
|
|
||||||
" ]\n" +
|
|
||||||
" }\n" +
|
|
||||||
" },\n" +
|
|
||||||
" \"page\": {\n" +
|
|
||||||
" \"index\": 1,\n" +
|
|
||||||
" \"size\": 2\n" +
|
|
||||||
" }\n" +
|
|
||||||
"}");
|
|
||||||
Assert.isTrue(companies3.at("/data/items").size() == 1, "数量错误");
|
|
||||||
Assert.isTrue(companies3.at("/data/total").asLong() == 1, "返回数量错误");
|
|
||||||
|
|
||||||
var company1 = detailItem("company", cid1);
|
|
||||||
Assert.isTrue(cid1 == company1.at("/data/id").asLong(), "id错误");
|
|
||||||
Assert.isTrue("Apple".equals(company1.at("/data/name").asString()), "name错误");
|
|
||||||
|
|
||||||
// 改
|
|
||||||
var cid4 = saveItem("company", "{\"id\": %d, \"name\": \"Dog\"}".formatted(cid2)).get("data").asLong();
|
|
||||||
Assert.isTrue(cid2 == cid4, "id错误");
|
|
||||||
var company2 = detailItem("company", cid2);
|
|
||||||
Assert.isTrue("Dog".equals(company2.at("/data/name").asString()), "name错误");
|
|
||||||
|
|
||||||
// 删
|
|
||||||
removeItem("company", cid3);
|
|
||||||
Assert.isTrue(listItems("company").at("/data/items").size() == 2, "数量错误");
|
|
||||||
Assert.isTrue(listItems("company").at("/data/total").asLong() == 2, "返回数量错误");
|
|
||||||
|
|
||||||
log.info(listItems("company").toPrettyString());
|
|
||||||
System.exit(0);
|
|
||||||
}
|
|
||||||
|
|
||||||
private HttpHeaders headers() {
|
|
||||||
var headers = new HttpHeaders();
|
|
||||||
headers.setContentType(MediaType.APPLICATION_JSON);
|
|
||||||
return headers;
|
|
||||||
}
|
|
||||||
|
|
||||||
private JsonNode saveItem(String path, String body) {
|
|
||||||
var response = REST_CLIENT.postForEntity(
|
|
||||||
"%s/%s/save".formatted(BASE_URL, path),
|
|
||||||
new HttpEntity<>(body, headers()),
|
|
||||||
String.class
|
|
||||||
);
|
|
||||||
Assert.isTrue(response.getStatusCode().is2xxSuccessful(), "请求失败");
|
|
||||||
Assert.notNull(response.getBody(), "请求失败");
|
|
||||||
return MAPPER.readTree(response.getBody());
|
|
||||||
}
|
|
||||||
|
|
||||||
private JsonNode listItems(String path) {
|
|
||||||
var response = REST_CLIENT.getForEntity(
|
|
||||||
"%s/%s/list".formatted(BASE_URL, path),
|
|
||||||
String.class
|
|
||||||
);
|
|
||||||
Assert.isTrue(response.getStatusCode().is2xxSuccessful(), "请求失败");
|
|
||||||
Assert.notNull(response.getBody(), "请求失败");
|
|
||||||
return MAPPER.readTree(response.getBody());
|
|
||||||
}
|
|
||||||
|
|
||||||
private JsonNode listItems(String path, String query) {
|
|
||||||
var response = REST_CLIENT.postForEntity(
|
|
||||||
"%s/%s/list".formatted(BASE_URL, path),
|
|
||||||
new HttpEntity<>(query, headers()),
|
|
||||||
String.class
|
|
||||||
);
|
|
||||||
Assert.isTrue(response.getStatusCode().is2xxSuccessful(), "请求失败");
|
|
||||||
Assert.notNull(response.getBody(), "请求失败");
|
|
||||||
return MAPPER.readTree(response.getBody());
|
|
||||||
}
|
|
||||||
|
|
||||||
private JsonNode detailItem(String path, Long id) {
|
|
||||||
var response = REST_CLIENT.getForEntity(
|
|
||||||
"%s/%s/detail/%d".formatted(BASE_URL, path, id),
|
|
||||||
String.class
|
|
||||||
);
|
|
||||||
Assert.isTrue(response.getStatusCode().is2xxSuccessful(), "请求失败");
|
|
||||||
Assert.notNull(response.getBody(), "请求失败");
|
|
||||||
return MAPPER.readTree(response.getBody());
|
|
||||||
}
|
|
||||||
|
|
||||||
private void removeItem(String path, Long id) {
|
|
||||||
var response = REST_CLIENT.getForEntity(
|
|
||||||
"%s/%s/remove/%d".formatted(BASE_URL, path, id),
|
|
||||||
Void.class
|
|
||||||
);
|
|
||||||
Assert.isTrue(response.getStatusCode().is2xxSuccessful(), "请求失败");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,21 +0,0 @@
|
|||||||
package com.lanyuanxiaoyao.service.template.eq.entity;
|
|
||||||
|
|
||||||
import com.easy.query.core.annotation.EntityProxy;
|
|
||||||
import com.easy.query.core.annotation.Table;
|
|
||||||
import com.easy.query.core.proxy.ProxyEntityAvailable;
|
|
||||||
import com.lanyuanxiaoyao.service.template.eq.entity.proxy.CompanyProxy;
|
|
||||||
import lombok.Getter;
|
|
||||||
import lombok.Setter;
|
|
||||||
import lombok.ToString;
|
|
||||||
import lombok.experimental.FieldNameConstants;
|
|
||||||
|
|
||||||
@Getter
|
|
||||||
@Setter
|
|
||||||
@ToString(callSuper = true)
|
|
||||||
@FieldNameConstants
|
|
||||||
@Table
|
|
||||||
@EntityProxy
|
|
||||||
public class Company extends SimpleEntity implements ProxyEntityAvailable<Company, CompanyProxy> {
|
|
||||||
private String name;
|
|
||||||
private Integer members;
|
|
||||||
}
|
|
||||||
@@ -1,21 +0,0 @@
|
|||||||
package com.lanyuanxiaoyao.service.template.eq.entity;
|
|
||||||
|
|
||||||
import com.easy.query.core.annotation.EntityProxy;
|
|
||||||
import com.easy.query.core.annotation.Table;
|
|
||||||
import com.easy.query.core.proxy.ProxyEntityAvailable;
|
|
||||||
import com.lanyuanxiaoyao.service.template.eq.entity.proxy.EmployeeProxy;
|
|
||||||
import lombok.Getter;
|
|
||||||
import lombok.Setter;
|
|
||||||
import lombok.ToString;
|
|
||||||
import lombok.experimental.FieldNameConstants;
|
|
||||||
|
|
||||||
@Getter
|
|
||||||
@Setter
|
|
||||||
@ToString(callSuper = true)
|
|
||||||
@FieldNameConstants
|
|
||||||
@Table
|
|
||||||
@EntityProxy
|
|
||||||
public class Employee extends SimpleEntity implements ProxyEntityAvailable<Employee, EmployeeProxy> {
|
|
||||||
private String name;
|
|
||||||
private Integer age;
|
|
||||||
}
|
|
||||||
@@ -1,89 +0,0 @@
|
|||||||
package com.lanyuanxiaoyao.service.template.jpa;
|
|
||||||
|
|
||||||
import com.lanyuanxiaoyao.service.template.jpa.helper.DatabaseHelper;
|
|
||||||
import java.lang.reflect.InvocationTargetException;
|
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.Map;
|
|
||||||
import java.util.Objects;
|
|
||||||
import lombok.extern.slf4j.Slf4j;
|
|
||||||
import org.springframework.util.Assert;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Helper测试类
|
|
||||||
* 用于测试驼峰命名法转下划线命名法的功能
|
|
||||||
*/
|
|
||||||
@Slf4j
|
|
||||||
public class HelperTest {
|
|
||||||
|
|
||||||
public static void main(String[] args) throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
|
|
||||||
// 通过反射调用Helper类中的private静态方法camelConvert
|
|
||||||
var camelConvert = DatabaseHelper.class.getDeclaredMethod("camelConvert", String.class);
|
|
||||||
camelConvert.setAccessible(true);
|
|
||||||
|
|
||||||
// 测试用例集合
|
|
||||||
Map<String, String> testCases = new HashMap<>();
|
|
||||||
|
|
||||||
// 基本转换测试
|
|
||||||
testCases.put("helloWorld", "hello_world");
|
|
||||||
testCases.put("firstName", "first_name");
|
|
||||||
testCases.put("lastName", "last_name");
|
|
||||||
testCases.put("URL", "url");
|
|
||||||
testCases.put("HTTPResponse", "http_response");
|
|
||||||
testCases.put("XMLParser", "xml_parser");
|
|
||||||
|
|
||||||
// 边界情况测试
|
|
||||||
testCases.put(null, null); // null输入
|
|
||||||
testCases.put("", ""); // 空字符串
|
|
||||||
testCases.put("a", "a"); // 单个小写字母
|
|
||||||
testCases.put("A", "a"); // 单个大写字母
|
|
||||||
testCases.put("aB", "a_b"); // 两个字符
|
|
||||||
testCases.put("Ab", "ab"); // 首字母大写
|
|
||||||
|
|
||||||
// 数字相关测试
|
|
||||||
testCases.put("field1Name", "field1_name");
|
|
||||||
testCases.put("field12Name", "field12_name");
|
|
||||||
testCases.put("2FARequired", "2_fa_required");
|
|
||||||
testCases.put("ID", "id");
|
|
||||||
testCases.put("userID", "user_id");
|
|
||||||
testCases.put("HTML5Parser", "html5_parser");
|
|
||||||
|
|
||||||
// 连续大写字母测试
|
|
||||||
testCases.put("HTTPSConnection", "https_connection");
|
|
||||||
testCases.put("XMLHttpRequest", "xml_http_request");
|
|
||||||
testCases.put("URLPath", "url_path");
|
|
||||||
testCases.put("APIKey", "api_key");
|
|
||||||
testCases.put("JWTToken", "jwt_token");
|
|
||||||
|
|
||||||
// 特殊场景测试
|
|
||||||
testCases.put("iPhone", "i_phone"); // 以小写字母开头,后面有大写
|
|
||||||
testCases.put("iOSVersion", "i_os_version"); // 连续小写字母后跟大写
|
|
||||||
testCases.put("CAPTCHA", "captcha"); // 全大写字母缩写
|
|
||||||
|
|
||||||
log.info("开始执行驼峰命名转下划线命名测试...");
|
|
||||||
|
|
||||||
int passedTests = 0;
|
|
||||||
int totalTests = testCases.size();
|
|
||||||
|
|
||||||
for (Map.Entry<String, String> testCase : testCases.entrySet()) {
|
|
||||||
String input = testCase.getKey();
|
|
||||||
String expected = testCase.getValue();
|
|
||||||
String actual = (String) camelConvert.invoke(null, input);
|
|
||||||
|
|
||||||
try {
|
|
||||||
Assert.isTrue(Objects.equals(expected, actual), "测试失败: 输入='%s', 期望='%s', 实际='%s'".formatted(input, expected, actual));
|
|
||||||
passedTests++;
|
|
||||||
log.info("✓ 测试通过: '{}' -> '{}'", input, actual);
|
|
||||||
} catch (Exception e) {
|
|
||||||
log.error("✗ {}", e.getMessage());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
log.info("测试结果: {}/{} 通过", passedTests, totalTests);
|
|
||||||
if (passedTests == totalTests) {
|
|
||||||
log.info("所有测试通过!✓");
|
|
||||||
} else {
|
|
||||||
log.error("有测试失败!✗");
|
|
||||||
System.exit(1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,302 +0,0 @@
|
|||||||
package com.lanyuanxiaoyao.service.template.jpa;
|
|
||||||
|
|
||||||
import com.blinkfox.fenix.EnableFenix;
|
|
||||||
import com.lanyuanxiaoyao.service.template.jpa.entity.Company;
|
|
||||||
import com.lanyuanxiaoyao.service.template.jpa.entity.Company_;
|
|
||||||
import com.lanyuanxiaoyao.service.template.jpa.entity.Employee;
|
|
||||||
import com.lanyuanxiaoyao.service.template.jpa.entity.Employee_;
|
|
||||||
import com.lanyuanxiaoyao.service.template.jpa.entity.QEmployee;
|
|
||||||
import com.lanyuanxiaoyao.service.template.jpa.entity.Report;
|
|
||||||
import com.lanyuanxiaoyao.service.template.jpa.entity.Report_;
|
|
||||||
import com.lanyuanxiaoyao.service.template.jpa.repository.EmployeeRepository;
|
|
||||||
import jakarta.annotation.Resource;
|
|
||||||
import java.util.List;
|
|
||||||
import org.slf4j.Logger;
|
|
||||||
import org.slf4j.LoggerFactory;
|
|
||||||
import org.springframework.boot.SpringApplication;
|
|
||||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
|
||||||
import org.springframework.boot.context.event.ApplicationReadyEvent;
|
|
||||||
import org.springframework.context.event.EventListener;
|
|
||||||
import org.springframework.data.jpa.repository.config.EnableJpaAuditing;
|
|
||||||
import org.springframework.http.HttpEntity;
|
|
||||||
import org.springframework.http.HttpHeaders;
|
|
||||||
import org.springframework.http.MediaType;
|
|
||||||
import org.springframework.util.Assert;
|
|
||||||
import org.springframework.web.client.RestTemplate;
|
|
||||||
import tools.jackson.databind.JsonNode;
|
|
||||||
import tools.jackson.databind.ObjectMapper;
|
|
||||||
|
|
||||||
@SpringBootApplication
|
|
||||||
@EnableFenix
|
|
||||||
@EnableJpaAuditing
|
|
||||||
public class TestApplication {
|
|
||||||
private static final Logger log = LoggerFactory.getLogger(TestApplication.class);
|
|
||||||
private static final String BASE_URL = "http://localhost:2490";
|
|
||||||
private static final RestTemplate REST_CLIENT = new RestTemplate();
|
|
||||||
private static final ObjectMapper MAPPER = new ObjectMapper();
|
|
||||||
@Resource
|
|
||||||
private EmployeeRepository employeeRepository;
|
|
||||||
|
|
||||||
public static void main(String[] args) {
|
|
||||||
SpringApplication.run(TestApplication.class, args);
|
|
||||||
}
|
|
||||||
|
|
||||||
@EventListener(ApplicationReadyEvent.class)
|
|
||||||
public void runTests() {
|
|
||||||
// 增
|
|
||||||
var cid1 = saveItem("company", "{\"name\": \"Apple\",\"members\": 10}").get("data").asLong();
|
|
||||||
var cid2 = saveItem("company", "{\"name\": \"Banana\",\"members\": 20}").get("data").asLong();
|
|
||||||
var cid3 = saveItem("company", "{\"name\": \"Cheery\",\"members\": 20}").get("data").asLong();
|
|
||||||
|
|
||||||
// 查
|
|
||||||
var companies = listItems("company");
|
|
||||||
Assert.isTrue(companies.at("/data/items").size() == 3, "数量错误");
|
|
||||||
Assert.isTrue(companies.at("/data/total").asLong() == 3, "返回数量错误");
|
|
||||||
|
|
||||||
// language=JSON
|
|
||||||
var companies2 = listItems("company", "{\n" +
|
|
||||||
" \"page\": {\n" +
|
|
||||||
" \"index\": 1,\n" +
|
|
||||||
" \"size\": 2\n" +
|
|
||||||
" }\n" +
|
|
||||||
"}");
|
|
||||||
Assert.isTrue(companies2.at("/data/items").size() == 2, "数量错误");
|
|
||||||
Assert.isTrue(companies2.at("/data/total").asLong() == 3, "返回数量错误");
|
|
||||||
// language=JSON
|
|
||||||
var companies3 = listItems("company", "{\n" +
|
|
||||||
" \"query\": {\n" +
|
|
||||||
" \"notNullEqual\": [\n" +
|
|
||||||
" \"name\"\n" +
|
|
||||||
" ],\n" +
|
|
||||||
" \"equal\": {\n" +
|
|
||||||
" \"name\": \"Apple\"\n" +
|
|
||||||
" },\n" +
|
|
||||||
" \"like\": {\n" +
|
|
||||||
" \"name\": \"Appl%\"\n" +
|
|
||||||
" },\n" +
|
|
||||||
" \"contain\": {\n" +
|
|
||||||
" \"name\": \"ple\"\n" +
|
|
||||||
" },\n" +
|
|
||||||
" \"startWith\": {\n" +
|
|
||||||
" \"name\": \"Appl\"\n" +
|
|
||||||
" },\n" +
|
|
||||||
" \"endWith\": {\n" +
|
|
||||||
" \"name\": \"le\"\n" +
|
|
||||||
" },\n" +
|
|
||||||
" \"less\": {\n" +
|
|
||||||
" \"members\": 50\n" +
|
|
||||||
" },\n" +
|
|
||||||
" \"greatEqual\": {\n" +
|
|
||||||
" \"members\": 0,\n" +
|
|
||||||
" \"createdTime\": \"2025-01-01 00:00:00\"\n" +
|
|
||||||
" },\n" +
|
|
||||||
" \"inside\": {\n" +
|
|
||||||
" \"name\": [\n" +
|
|
||||||
" \"Apple\",\n" +
|
|
||||||
" \"Banana\"\n" +
|
|
||||||
" ]\n" +
|
|
||||||
" },\n" +
|
|
||||||
" \"between\": {\n" +
|
|
||||||
" \"members\": {\n" +
|
|
||||||
" \"start\": 0,\n" +
|
|
||||||
" \"end\": 50\n" +
|
|
||||||
" }\n" +
|
|
||||||
" }\n" +
|
|
||||||
" },\n" +
|
|
||||||
" \"page\": {\n" +
|
|
||||||
" \"index\": 1,\n" +
|
|
||||||
" \"size\": 2\n" +
|
|
||||||
" }\n" +
|
|
||||||
"}");
|
|
||||||
Assert.isTrue(companies3.at("/data/items").size() == 1, "数量错误");
|
|
||||||
Assert.isTrue(companies3.at("/data/total").asLong() == 1, "返回数量错误");
|
|
||||||
|
|
||||||
var company1 = detailItem("company", cid1);
|
|
||||||
Assert.isTrue(cid1 == company1.at("/data/id").asLong(), "id错误");
|
|
||||||
Assert.isTrue("Apple".equals(company1.at("/data/name").asText()), "name错误");
|
|
||||||
|
|
||||||
// 改
|
|
||||||
var cid4 = saveItem("company", "{\"id\": %d, \"name\": \"Dog\"}".formatted(cid2)).get("data").asLong();
|
|
||||||
Assert.isTrue(cid2 == cid4, "id错误");
|
|
||||||
var company2 = detailItem("company", cid2);
|
|
||||||
Assert.isTrue("Dog".equals(company2.at("/data/name").asText()), "name错误");
|
|
||||||
|
|
||||||
// 删
|
|
||||||
removeItem("company", cid3);
|
|
||||||
Assert.isTrue(listItems("company").at("/data/items").size() == 2, "数量错误");
|
|
||||||
Assert.isTrue(listItems("company").at("/data/total").asLong() == 2, "返回数量错误");
|
|
||||||
|
|
||||||
log.info(listItems("company").toPrettyString());
|
|
||||||
|
|
||||||
var eid1 = saveItem("employee", "{\"name\": \"Tom\",\"age\": 18, \"companyId\": %d}".formatted(cid1)).get("data").asLong();
|
|
||||||
var eid2 = saveItem("employee", "{\"name\": \"Jerry\",\"age\": 18, \"companyId\": %d}".formatted(cid1)).get("data").asLong();
|
|
||||||
var eid3 = saveItem("employee", "{\"name\": \"Mike\",\"age\": 18, \"companyId\": %d}".formatted(cid2)).get("data").asLong();
|
|
||||||
|
|
||||||
var employees = listItems("employee");
|
|
||||||
Assert.isTrue(employees.at("/data/items").size() == 3, "数量错误");
|
|
||||||
Assert.isTrue(employees.at("/data/total").asLong() == 3, "返回数量错误");
|
|
||||||
|
|
||||||
var employee1 = detailItem("employee", eid1);
|
|
||||||
Assert.isTrue(eid1 == employee1.at("/data/id").asLong(), "id错误");
|
|
||||||
Assert.isTrue("Tom".equals(employee1.at("/data/name").asText()), "name错误");
|
|
||||||
Assert.isTrue(18 == employee1.at("/data/age").asInt(), "age错误");
|
|
||||||
|
|
||||||
System.exit(0);
|
|
||||||
}
|
|
||||||
|
|
||||||
@EventListener(ApplicationReadyEvent.class)
|
|
||||||
public void runSpecificationTests() {
|
|
||||||
// 增
|
|
||||||
var cid1 = saveItem("company", "{\"name\": \"Apple\",\"members\": 10}").get("data").asLong();
|
|
||||||
var cid2 = saveItem("company", "{\"name\": \"Banana\",\"members\": 20}").get("data").asLong();
|
|
||||||
var cid3 = saveItem("company", "{\"name\": \"Cheery\",\"members\": 20}").get("data").asLong();
|
|
||||||
var eid1 = saveItem("employee", "{\"name\": \"Tom\",\"age\": 18, \"companyId\": %d}".formatted(cid1)).get("data").asLong();
|
|
||||||
var eid2 = saveItem("employee", "{\"name\": \"Jerry\",\"age\": 18, \"companyId\": %d}".formatted(cid1)).get("data").asLong();
|
|
||||||
var eid3 = saveItem("employee", "{\"name\": \"Mike\",\"age\": 18, \"companyId\": %d}".formatted(cid2)).get("data").asLong();
|
|
||||||
var rid = saveItem("report", "{\"employeeId\": %d, \"score\": 56.38, \"level\": \"A\"}".formatted(eid1)).get("data").asLong();
|
|
||||||
var rid2 = saveItem("report", "{\"employeeId\": %d, \"score\": 78.98, \"level\": \"B\"}".formatted(eid2)).get("data").asLong();
|
|
||||||
|
|
||||||
log.debug(
|
|
||||||
"Results: {}",
|
|
||||||
employeeRepository.findAll(
|
|
||||||
builder -> builder
|
|
||||||
.andIsNotNull(Employee.Fields.name)
|
|
||||||
.andEquals(Employee.Fields.name, "Tom")
|
|
||||||
.andLike(Employee.Fields.name, "To%")
|
|
||||||
.andStartsWith(Employee.Fields.name, "To")
|
|
||||||
.andEndsWith(Employee.Fields.name, "om")
|
|
||||||
.andLessThan(Employee.Fields.age, 50)
|
|
||||||
.andGreaterThanEqual(Employee.Fields.age, 0)
|
|
||||||
.andIn(Employee.Fields.name, List.of("Tom", "Mike"))
|
|
||||||
.andBetween(Employee.Fields.age, 0, 50)
|
|
||||||
.build()
|
|
||||||
)
|
|
||||||
);
|
|
||||||
|
|
||||||
log.debug(
|
|
||||||
"Results: {}",
|
|
||||||
employeeRepository.findAll(
|
|
||||||
(root, query, builder) ->
|
|
||||||
builder.and(
|
|
||||||
builder.isNotNull(root.get(Employee_.name)),
|
|
||||||
builder.equal(root.get(Employee_.name), "Tom"),
|
|
||||||
builder.like(root.get(Employee_.name), "To%"),
|
|
||||||
builder.lessThan(root.get(Employee_.age), 50),
|
|
||||||
builder.greaterThanOrEqualTo(root.get(Employee_.age), 0),
|
|
||||||
builder.in(root.get(Employee_.NAME)).value(List.of("Tom", "Mike")),
|
|
||||||
builder.between(root.get(Employee_.age), 0, 50),
|
|
||||||
builder.isNotEmpty(root.get(Employee_.company).get(Company_.employees)),
|
|
||||||
builder.isMember(Company.Industry.MEDIA, root.get(Employee_.company).get(Company_.industries))
|
|
||||||
)
|
|
||||||
)
|
|
||||||
);
|
|
||||||
|
|
||||||
log.debug(
|
|
||||||
"Results: {}",
|
|
||||||
employeeRepository.findAll(
|
|
||||||
QEmployee.employee.name.isNotNull()
|
|
||||||
.and(QEmployee.employee.name.eq("Tom"))
|
|
||||||
.and(QEmployee.employee.name.like("To%"))
|
|
||||||
.and(QEmployee.employee.name.startsWith("To"))
|
|
||||||
.and(QEmployee.employee.name.endsWith("om"))
|
|
||||||
.and(QEmployee.employee.age.lt(50))
|
|
||||||
.and(QEmployee.employee.age.goe(0))
|
|
||||||
.and(QEmployee.employee.name.in("Tom", "Mike"))
|
|
||||||
.and(QEmployee.employee.age.between(0, 50))
|
|
||||||
.and(QEmployee.employee.company().employees.isNotEmpty())
|
|
||||||
.and(QEmployee.employee.company().employees.any().name.ne("Tom"))
|
|
||||||
.and(QEmployee.employee.company().industries.contains(Company.Industry.MEDIA))
|
|
||||||
.and(QEmployee.employee.connections.containsKey(Employee.ConnectionType.EMAIL))
|
|
||||||
)
|
|
||||||
);
|
|
||||||
|
|
||||||
log.debug(
|
|
||||||
"Results: {}",
|
|
||||||
employeeRepository.findAll(
|
|
||||||
(root, query, builder) -> {
|
|
||||||
var reportRoot = query.from(Report.class);
|
|
||||||
return builder.and(
|
|
||||||
builder.equal(root.get(Employee_.id), reportRoot.get(Report_.employeeId)),
|
|
||||||
builder.equal(reportRoot.get(Report_.level), Report.Level.A)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
)
|
|
||||||
);
|
|
||||||
|
|
||||||
System.exit(0);
|
|
||||||
}
|
|
||||||
|
|
||||||
@EventListener(ApplicationReadyEvent.class)
|
|
||||||
public void runNativeQueryTests() {
|
|
||||||
// 增
|
|
||||||
var cid1 = saveItem("company", "{\"name\": \"Apple\",\"members\": 10}").get("data").asLong();
|
|
||||||
var cid2 = saveItem("company", "{\"name\": \"Banana\",\"members\": 20}").get("data").asLong();
|
|
||||||
var cid3 = saveItem("company", "{\"name\": \"Cheery\",\"members\": 20}").get("data").asLong();
|
|
||||||
var eid1 = saveItem("employee", "{\"name\": \"Tom\",\"age\": 18, \"companyId\": %d}".formatted(cid1)).get("data").asLong();
|
|
||||||
var eid2 = saveItem("employee", "{\"name\": \"Jerry\",\"age\": 18, \"companyId\": %d}".formatted(cid1)).get("data").asLong();
|
|
||||||
var eid3 = saveItem("employee", "{\"name\": \"Mike\",\"age\": 18, \"companyId\": %d}".formatted(cid2)).get("data").asLong();
|
|
||||||
|
|
||||||
var list = employeeRepository.findAllEmployeeWithCompanyName();
|
|
||||||
Assert.isTrue(list.size() == 3, "数量错误");
|
|
||||||
log.debug("Results: {}", list);
|
|
||||||
var list_native = employeeRepository.findAllEmployeeWithCompanyNameNative();
|
|
||||||
Assert.isTrue(list_native.size() == 3, "数量错误");
|
|
||||||
log.debug("Results: {}", list_native);
|
|
||||||
}
|
|
||||||
|
|
||||||
private HttpHeaders headers() {
|
|
||||||
var headers = new HttpHeaders();
|
|
||||||
headers.setContentType(MediaType.APPLICATION_JSON);
|
|
||||||
return headers;
|
|
||||||
}
|
|
||||||
|
|
||||||
private JsonNode saveItem(String path, String body) {
|
|
||||||
var response = REST_CLIENT.postForEntity(
|
|
||||||
"%s/%s/save".formatted(BASE_URL, path),
|
|
||||||
new HttpEntity<>(body, headers()),
|
|
||||||
String.class
|
|
||||||
);
|
|
||||||
Assert.isTrue(response.getStatusCode().is2xxSuccessful(), "请求失败");
|
|
||||||
Assert.notNull(response.getBody(), "请求失败");
|
|
||||||
return MAPPER.readTree(response.getBody());
|
|
||||||
}
|
|
||||||
|
|
||||||
private JsonNode listItems(String path) {
|
|
||||||
var response = REST_CLIENT.getForEntity(
|
|
||||||
"%s/%s/list".formatted(BASE_URL, path),
|
|
||||||
String.class
|
|
||||||
);
|
|
||||||
Assert.isTrue(response.getStatusCode().is2xxSuccessful(), "请求失败");
|
|
||||||
Assert.notNull(response.getBody(), "请求失败");
|
|
||||||
return MAPPER.readTree(response.getBody());
|
|
||||||
}
|
|
||||||
|
|
||||||
private JsonNode listItems(String path, String query) {
|
|
||||||
var response = REST_CLIENT.postForEntity(
|
|
||||||
"%s/%s/list".formatted(BASE_URL, path),
|
|
||||||
new HttpEntity<>(query, headers()),
|
|
||||||
String.class
|
|
||||||
);
|
|
||||||
Assert.isTrue(response.getStatusCode().is2xxSuccessful(), "请求失败");
|
|
||||||
Assert.notNull(response.getBody(), "请求失败");
|
|
||||||
return MAPPER.readTree(response.getBody());
|
|
||||||
}
|
|
||||||
|
|
||||||
private JsonNode detailItem(String path, Long id) {
|
|
||||||
var response = REST_CLIENT.getForEntity(
|
|
||||||
"%s/%s/detail/%d".formatted(BASE_URL, path, id),
|
|
||||||
String.class
|
|
||||||
);
|
|
||||||
Assert.isTrue(response.getStatusCode().is2xxSuccessful(), "请求失败");
|
|
||||||
Assert.notNull(response.getBody(), "请求失败");
|
|
||||||
return MAPPER.readTree(response.getBody());
|
|
||||||
}
|
|
||||||
|
|
||||||
private void removeItem(String path, Long id) {
|
|
||||||
var response = REST_CLIENT.getForEntity(
|
|
||||||
"%s/%s/remove/%d".formatted(BASE_URL, path, id),
|
|
||||||
Void.class
|
|
||||||
);
|
|
||||||
Assert.isTrue(response.getStatusCode().is2xxSuccessful(), "请求失败");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,8 +0,0 @@
|
|||||||
package com.lanyuanxiaoyao.service.template.jpa.repository;
|
|
||||||
|
|
||||||
import com.lanyuanxiaoyao.service.template.jpa.entity.Company;
|
|
||||||
import org.springframework.stereotype.Repository;
|
|
||||||
|
|
||||||
@Repository
|
|
||||||
public interface CompanyRepository extends SimpleRepository<Company> {
|
|
||||||
}
|
|
||||||
@@ -1,8 +0,0 @@
|
|||||||
package com.lanyuanxiaoyao.service.template.jpa.repository;
|
|
||||||
|
|
||||||
import com.lanyuanxiaoyao.service.template.jpa.entity.Report;
|
|
||||||
import org.springframework.stereotype.Repository;
|
|
||||||
|
|
||||||
@Repository
|
|
||||||
public interface ReportRepository extends SimpleRepository<Report> {
|
|
||||||
}
|
|
||||||
@@ -1,12 +0,0 @@
|
|||||||
package com.lanyuanxiaoyao.service.template.jpa.service;
|
|
||||||
|
|
||||||
import com.lanyuanxiaoyao.service.template.jpa.entity.Company;
|
|
||||||
import com.lanyuanxiaoyao.service.template.jpa.repository.CompanyRepository;
|
|
||||||
import org.springframework.stereotype.Service;
|
|
||||||
|
|
||||||
@Service
|
|
||||||
public class CompanyService extends SimpleServiceSupport<Company> {
|
|
||||||
public CompanyService(CompanyRepository repository) {
|
|
||||||
super(repository);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,12 +0,0 @@
|
|||||||
package com.lanyuanxiaoyao.service.template.jpa.service;
|
|
||||||
|
|
||||||
import com.lanyuanxiaoyao.service.template.jpa.entity.Employee;
|
|
||||||
import com.lanyuanxiaoyao.service.template.jpa.repository.EmployeeRepository;
|
|
||||||
import org.springframework.stereotype.Service;
|
|
||||||
|
|
||||||
@Service
|
|
||||||
public class EmployeeService extends SimpleServiceSupport<Employee> {
|
|
||||||
public EmployeeService(EmployeeRepository repository) {
|
|
||||||
super(repository);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,12 +0,0 @@
|
|||||||
package com.lanyuanxiaoyao.service.template.jpa.service;
|
|
||||||
|
|
||||||
import com.lanyuanxiaoyao.service.template.jpa.entity.Report;
|
|
||||||
import com.lanyuanxiaoyao.service.template.jpa.repository.ReportRepository;
|
|
||||||
import org.springframework.stereotype.Service;
|
|
||||||
|
|
||||||
@Service
|
|
||||||
public class ReportService extends SimpleServiceSupport<Report> {
|
|
||||||
public ReportService(ReportRepository repository) {
|
|
||||||
super(repository);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,23 +0,0 @@
|
|||||||
server:
|
|
||||||
port: 2490
|
|
||||||
spring:
|
|
||||||
application:
|
|
||||||
name: Test
|
|
||||||
datasource:
|
|
||||||
url: jdbc:h2:mem:testdb;DB_CLOSE_DELAY=-1
|
|
||||||
username: test
|
|
||||||
password: test
|
|
||||||
driver-class-name: org.h2.Driver
|
|
||||||
jpa:
|
|
||||||
generate-ddl: true
|
|
||||||
fenix:
|
|
||||||
print-banner: false
|
|
||||||
decorator:
|
|
||||||
datasource:
|
|
||||||
p6spy:
|
|
||||||
multiline: false
|
|
||||||
exclude-categories:
|
|
||||||
- commit
|
|
||||||
- result
|
|
||||||
- resultset
|
|
||||||
log-format: "%(category)|%(executionTime)|%(sqlSingleLine)"
|
|
||||||
@@ -1,173 +0,0 @@
|
|||||||
package com.lanyuanxiaoyao.service.template.xbatis;
|
|
||||||
|
|
||||||
import lombok.extern.slf4j.Slf4j;
|
|
||||||
import org.mybatis.spring.annotation.MapperScan;
|
|
||||||
import org.springframework.boot.SpringApplication;
|
|
||||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
|
||||||
import org.springframework.boot.context.event.ApplicationReadyEvent;
|
|
||||||
import org.springframework.context.event.EventListener;
|
|
||||||
import org.springframework.http.HttpEntity;
|
|
||||||
import org.springframework.http.HttpHeaders;
|
|
||||||
import org.springframework.http.MediaType;
|
|
||||||
import org.springframework.util.Assert;
|
|
||||||
import org.springframework.web.client.RestTemplate;
|
|
||||||
import tools.jackson.databind.JsonNode;
|
|
||||||
import tools.jackson.databind.ObjectMapper;
|
|
||||||
|
|
||||||
@Slf4j
|
|
||||||
@MapperScan("com.lanyuanxiaoyao.service.template.xbatis.mapper")
|
|
||||||
@SpringBootApplication
|
|
||||||
public class TestApplication {
|
|
||||||
private static final String BASE_URL = "http://localhost:2490";
|
|
||||||
private static final RestTemplate REST_CLIENT = new RestTemplate();
|
|
||||||
private static final ObjectMapper MAPPER = new ObjectMapper();
|
|
||||||
|
|
||||||
public static void main(String[] args) {
|
|
||||||
SpringApplication.run(TestApplication.class, args);
|
|
||||||
}
|
|
||||||
|
|
||||||
@EventListener(ApplicationReadyEvent.class)
|
|
||||||
public void runTests() {
|
|
||||||
// 增
|
|
||||||
var cid1 = saveItem("company", "{\"name\": \"Apple\",\"members\": 10}").get("data").asLong();
|
|
||||||
var cid2 = saveItem("company", "{\"name\": \"Banana\",\"members\": 20}").get("data").asLong();
|
|
||||||
var cid3 = saveItem("company", "{\"name\": \"Cheery\",\"members\": 20}").get("data").asLong();
|
|
||||||
|
|
||||||
// 查
|
|
||||||
var companies = listItems("company");
|
|
||||||
Assert.isTrue(companies.at("/data/items").size() == 3, "数量错误");
|
|
||||||
Assert.isTrue(companies.at("/data/total").asLong() == 3, "返回数量错误");
|
|
||||||
|
|
||||||
// language=JSON
|
|
||||||
var companies2 = listItems("company", "{\n" +
|
|
||||||
" \"page\": {\n" +
|
|
||||||
" \"index\": 1,\n" +
|
|
||||||
" \"size\": 2\n" +
|
|
||||||
" }\n" +
|
|
||||||
"}");
|
|
||||||
Assert.isTrue(companies2.at("/data/items").size() == 2, "数量错误");
|
|
||||||
Assert.isTrue(companies2.at("/data/total").asLong() == 3, "返回数量错误");
|
|
||||||
// language=JSON
|
|
||||||
var companies3 = listItems("company", "{\n" +
|
|
||||||
" \"query\": {\n" +
|
|
||||||
" \"notNullEqual\": [\n" +
|
|
||||||
" \"name\"\n" +
|
|
||||||
" ],\n" +
|
|
||||||
" \"equal\": {\n" +
|
|
||||||
" \"name\": \"Apple\"\n" +
|
|
||||||
" },\n" +
|
|
||||||
" \"like\": {\n" +
|
|
||||||
" \"name\": \"Appl%\"\n" +
|
|
||||||
" },\n" +
|
|
||||||
" \"contain\": {\n" +
|
|
||||||
" \"name\": \"ple\"\n" +
|
|
||||||
" },\n" +
|
|
||||||
" \"startWith\": {\n" +
|
|
||||||
" \"name\": \"Appl\"\n" +
|
|
||||||
" },\n" +
|
|
||||||
" \"endWith\": {\n" +
|
|
||||||
" \"name\": \"le\"\n" +
|
|
||||||
" },\n" +
|
|
||||||
" \"less\": {\n" +
|
|
||||||
" \"members\": 50\n" +
|
|
||||||
" },\n" +
|
|
||||||
" \"greatEqual\": {\n" +
|
|
||||||
" \"members\": 0,\n" +
|
|
||||||
" \"createdTime\": \"2025-01-01 00:00:00\"\n" +
|
|
||||||
" },\n" +
|
|
||||||
" \"inside\": {\n" +
|
|
||||||
" \"name\": [\n" +
|
|
||||||
" \"Apple\",\n" +
|
|
||||||
" \"Banana\"\n" +
|
|
||||||
" ]\n" +
|
|
||||||
" },\n" +
|
|
||||||
" \"between\": {\n" +
|
|
||||||
" \"members\": {\n" +
|
|
||||||
" \"start\": 0,\n" +
|
|
||||||
" \"end\": 50\n" +
|
|
||||||
" }\n" +
|
|
||||||
" }\n" +
|
|
||||||
" },\n" +
|
|
||||||
" \"page\": {\n" +
|
|
||||||
" \"index\": 1,\n" +
|
|
||||||
" \"size\": 2\n" +
|
|
||||||
" }\n" +
|
|
||||||
"}");
|
|
||||||
Assert.isTrue(companies3.at("/data/items").size() == 1, "数量错误");
|
|
||||||
Assert.isTrue(companies3.at("/data/total").asLong() == 1, "返回数量错误");
|
|
||||||
|
|
||||||
var company1 = detailItem("company", cid1);
|
|
||||||
Assert.isTrue(cid1 == company1.at("/data/id").asLong(), "id错误");
|
|
||||||
Assert.isTrue("Apple".equals(company1.at("/data/name").asText()), "name错误");
|
|
||||||
|
|
||||||
// 改
|
|
||||||
var cid4 = saveItem("company", "{\"id\": %d, \"name\": \"Dog\"}".formatted(cid2)).get("data").asLong();
|
|
||||||
Assert.isTrue(cid2 == cid4, "id错误");
|
|
||||||
var company2 = detailItem("company", cid2);
|
|
||||||
Assert.isTrue("Dog".equals(company2.at("/data/name").asText()), "name错误");
|
|
||||||
|
|
||||||
// 删
|
|
||||||
removeItem("company", cid3);
|
|
||||||
Assert.isTrue(listItems("company").at("/data/items").size() == 2, "数量错误");
|
|
||||||
Assert.isTrue(listItems("company").at("/data/total").asLong() == 2, "返回数量错误");
|
|
||||||
|
|
||||||
log.info(listItems("company").toPrettyString());
|
|
||||||
System.exit(0);
|
|
||||||
}
|
|
||||||
|
|
||||||
private HttpHeaders headers() {
|
|
||||||
var headers = new HttpHeaders();
|
|
||||||
headers.setContentType(MediaType.APPLICATION_JSON);
|
|
||||||
return headers;
|
|
||||||
}
|
|
||||||
|
|
||||||
private JsonNode saveItem(String path, String body) {
|
|
||||||
var response = REST_CLIENT.postForEntity(
|
|
||||||
"%s/%s/save".formatted(BASE_URL, path),
|
|
||||||
new HttpEntity<>(body, headers()),
|
|
||||||
String.class
|
|
||||||
);
|
|
||||||
Assert.isTrue(response.getStatusCode().is2xxSuccessful(), "请求失败");
|
|
||||||
Assert.notNull(response.getBody(), "请求失败");
|
|
||||||
return MAPPER.readTree(response.getBody());
|
|
||||||
}
|
|
||||||
|
|
||||||
private JsonNode listItems(String path) {
|
|
||||||
var response = REST_CLIENT.getForEntity(
|
|
||||||
"%s/%s/list".formatted(BASE_URL, path),
|
|
||||||
String.class
|
|
||||||
);
|
|
||||||
Assert.isTrue(response.getStatusCode().is2xxSuccessful(), "请求失败");
|
|
||||||
Assert.notNull(response.getBody(), "请求失败");
|
|
||||||
return MAPPER.readTree(response.getBody());
|
|
||||||
}
|
|
||||||
|
|
||||||
private JsonNode listItems(String path, String query) {
|
|
||||||
var response = REST_CLIENT.postForEntity(
|
|
||||||
"%s/%s/list".formatted(BASE_URL, path),
|
|
||||||
new HttpEntity<>(query, headers()),
|
|
||||||
String.class
|
|
||||||
);
|
|
||||||
Assert.isTrue(response.getStatusCode().is2xxSuccessful(), "请求失败");
|
|
||||||
Assert.notNull(response.getBody(), "请求失败");
|
|
||||||
return MAPPER.readTree(response.getBody());
|
|
||||||
}
|
|
||||||
|
|
||||||
private JsonNode detailItem(String path, Long id) {
|
|
||||||
var response = REST_CLIENT.getForEntity(
|
|
||||||
"%s/%s/detail/%d".formatted(BASE_URL, path, id),
|
|
||||||
String.class
|
|
||||||
);
|
|
||||||
Assert.isTrue(response.getStatusCode().is2xxSuccessful(), "请求失败");
|
|
||||||
Assert.notNull(response.getBody(), "请求失败");
|
|
||||||
return MAPPER.readTree(response.getBody());
|
|
||||||
}
|
|
||||||
|
|
||||||
private void removeItem(String path, Long id) {
|
|
||||||
var response = REST_CLIENT.getForEntity(
|
|
||||||
"%s/%s/remove/%d".formatted(BASE_URL, path, id),
|
|
||||||
Void.class
|
|
||||||
);
|
|
||||||
Assert.isTrue(response.getStatusCode().is2xxSuccessful(), "请求失败");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,12 +0,0 @@
|
|||||||
package com.lanyuanxiaoyao.service.template.xbatis.service;
|
|
||||||
|
|
||||||
import com.lanyuanxiaoyao.service.template.xbatis.entity.Company;
|
|
||||||
import com.lanyuanxiaoyao.service.template.xbatis.mapper.MybatisBasicMapper;
|
|
||||||
import org.springframework.stereotype.Service;
|
|
||||||
|
|
||||||
@Service
|
|
||||||
public class CompanyService extends SimpleServiceSupport<Company> {
|
|
||||||
public CompanyService(MybatisBasicMapper mapper) {
|
|
||||||
super(Company.class, mapper);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,12 +0,0 @@
|
|||||||
package com.lanyuanxiaoyao.service.template.xbatis.service;
|
|
||||||
|
|
||||||
import com.lanyuanxiaoyao.service.template.xbatis.entity.Employee;
|
|
||||||
import com.lanyuanxiaoyao.service.template.xbatis.mapper.MybatisBasicMapper;
|
|
||||||
import org.springframework.stereotype.Service;
|
|
||||||
|
|
||||||
@Service
|
|
||||||
public class EmployeeService extends SimpleServiceSupport<Employee> {
|
|
||||||
public EmployeeService(MybatisBasicMapper mapper) {
|
|
||||||
super(Employee.class, mapper);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Reference in New Issue
Block a user