1
0

fix(xbatis): 完善测试用例

This commit is contained in:
2026-01-21 16:34:49 +08:00
parent a8e8ec0ef2
commit af4d13d76c
23 changed files with 215 additions and 260 deletions

View File

@@ -32,6 +32,7 @@
<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> <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> <hutool.version>5.8.43</hutool.version>
</properties> </properties>
@@ -120,7 +121,7 @@
<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>

View File

@@ -26,9 +26,7 @@ public class AbstractTestApplication {
var cid3 = saveItem("company", randomCompany()).get("data").asLong(); var cid3 = saveItem("company", randomCompany()).get("data").asLong();
formatLog("List"); formatLog("List");
var companies1 = listItems("company"); assertListItems(listItems("company"), 3, 3);
Assert.isTrue(companies1.at("/data/items").size() == 3, "数量错误");
Assert.isTrue(companies1.at("/data/total").asLong() == 3, "返回数量错误");
formatLog("Detail"); formatLog("Detail");
var company1 = detailItem("company", cid1); var company1 = detailItem("company", cid1);
@@ -51,9 +49,7 @@ public class AbstractTestApplication {
} }
} }
"""; """;
var companies2 = listItems("company", pageRequest); assertListItems(listItems("company", pageRequest), 2, 3);
Assert.isTrue(companies2.at("/data/items").size() == 2, "数量错误");
Assert.isTrue(companies2.at("/data/total").asLong() == 3, "返回数量错误");
formatLog("List Queryable"); formatLog("List Queryable");
// language=JSON // language=JSON
@@ -104,18 +100,21 @@ public class AbstractTestApplication {
} }
} }
"""; """;
var companies3 = listItems("company", queryRequest); assertListItems(listItems("company", queryRequest), 1, 1);
Assert.isTrue(companies3.at("/data/items").size() == 1, "数量错误");
Assert.isTrue(companies3.at("/data/total").asLong() == 1, "返回数量错误");
formatLog("Clean"); formatLog("Clean");
removeItem("company", cid1); removeItem("company", cid1);
Assert.isTrue(listItems("company").at("/data/items").size() == 2, "数量错误"); assertListItems(listItems("company"), 2, 2);
Assert.isTrue(listItems("company").at("/data/total").asLong() == 2, "返回数量错误");
removeItem("company", cid2); removeItem("company", cid2);
removeItem("company", cid3); removeItem("company", cid3);
Assert.isTrue(listItems("company").at("/data/items").isEmpty(), "数量错误"); assertListItems(listItems("company"), 0, 0);
Assert.isTrue(listItems("company").at("/data/total").asLong() == 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) { protected void formatLog(String text) {

View File

@@ -29,8 +29,8 @@
</dependency> </dependency>
<dependency> <dependency>
<groupId>com.h2database</groupId> <groupId>com.lanyuanxiaoyao</groupId>
<artifactId>h2</artifactId> <artifactId>spring-boot-service-template-database-common-test</artifactId>
<scope>test</scope> <scope>test</scope>
</dependency> </dependency>
</dependencies> </dependencies>

View File

@@ -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;

View File

@@ -1,11 +1,11 @@
package com.lanyuanxiaoyao.service.template.xbatis.controller; package com.lanyuanxiaoyao.service.template.database.xbatis.controller;
import com.lanyuanxiaoyao.service.template.common.helper.ObjectHelper; import com.lanyuanxiaoyao.service.template.common.helper.ObjectHelper;
import com.lanyuanxiaoyao.service.template.database.common.controller.SimpleController; import com.lanyuanxiaoyao.service.template.database.common.controller.SimpleController;
import com.lanyuanxiaoyao.service.template.database.common.entity.GlobalResponse; import com.lanyuanxiaoyao.service.template.database.common.entity.GlobalResponse;
import com.lanyuanxiaoyao.service.template.database.common.entity.Query; import com.lanyuanxiaoyao.service.template.database.common.entity.Query;
import com.lanyuanxiaoyao.service.template.xbatis.entity.SimpleEntity; import com.lanyuanxiaoyao.service.template.database.xbatis.entity.SimpleEntity;
import com.lanyuanxiaoyao.service.template.xbatis.service.SimpleServiceSupport; 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;

View File

@@ -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;

View File

@@ -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;
}

View File

@@ -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)

View File

@@ -1,4 +1,4 @@
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.database.common.helper.SnowflakeHelper; import com.lanyuanxiaoyao.service.template.database.common.helper.SnowflakeHelper;

View File

@@ -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;

View File

@@ -1,4 +1,4 @@
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;
@@ -9,8 +9,8 @@ import com.lanyuanxiaoyao.service.template.database.common.entity.Query;
import com.lanyuanxiaoyao.service.template.database.common.exception.IdNotFoundException; 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.QueryParser;
import com.lanyuanxiaoyao.service.template.database.common.service.SimpleService; import com.lanyuanxiaoyao.service.template.database.common.service.SimpleService;
import com.lanyuanxiaoyao.service.template.xbatis.entity.SimpleEntity; import com.lanyuanxiaoyao.service.template.database.xbatis.entity.SimpleEntity;
import com.lanyuanxiaoyao.service.template.xbatis.mapper.MybatisBasicMapper; 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;
@@ -37,13 +37,14 @@ public abstract class SimpleServiceSupport<ENTITY extends SimpleEntity> implemen
@Transactional(rollbackFor = Throwable.class) @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) @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
@@ -75,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()));
@@ -85,14 +85,16 @@ public abstract class SimpleServiceSupport<ENTITY extends SimpleEntity> implemen
commonPredicates(where); commonPredicates(where);
new XBatisQueryParser<>(query.query(), where, target, factory).build(); 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") @Named("detail")
@@ -181,22 +183,22 @@ public abstract class SimpleServiceSupport<ENTITY extends SimpleEntity> implemen
@Override @Override
protected void startWith(Query.Queryable queryable, Where where) { 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, Where where) { 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, Where where) { 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, Where where) { 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

View File

@@ -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
); );

View File

@@ -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, "查询数量错误");
}
}

View File

@@ -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;

View File

@@ -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;

View File

@@ -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;
}

View File

@@ -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;
} }

View File

@@ -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);
}
}

View File

@@ -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);
}
}

View File

@@ -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(), "请求失败");
}
}

View File

@@ -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);
}
}

View File

@@ -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);
}
}

View File

@@ -1,8 +1,6 @@
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-database/spring-boot-service-template-database-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
@@ -10,13 +8,4 @@ spring:
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)"