Commit 9bc9b2ac authored by YunaiV's avatar YunaiV
Browse files

多模块重构 5:infra 模块的修改~~~

Showing with 45 additions and 340 deletions
+45 -340
......@@ -99,12 +99,6 @@
<artifactId>yudao-spring-boot-starter-redis</artifactId>
</dependency>
<!-- Config 配置中心相关 -->
<dependency>
<groupId>cn.iocoder.boot</groupId>
<artifactId>yudao-spring-boot-starter-config</artifactId>
</dependency>
<!-- Job 定时任务相关 -->
<dependency>
<groupId>cn.iocoder.boot</groupId>
......@@ -152,11 +146,6 @@
<artifactId>velocity-engine-core</artifactId>
</dependency>
<dependency>
<groupId>cn.smallbun.screw</groupId>
<artifactId>screw-core</artifactId> <!-- 实现数据库文档 -->
</dependency>
<!-- 三方云服务相关 -->
<dependency>
......
......@@ -5,7 +5,7 @@ import org.springframework.boot.autoconfigure.SpringBootApplication;
@SuppressWarnings("SpringComponentScan") // 忽略 IDEA 无法识别 ${yudao.info.base-package} 和 ${yudao.core-service.base-package}
@SpringBootApplication(scanBasePackages = {"${yudao.info.base-package}", "${yudao.core-service.base-package}",
"${yudao.info.member-package}", "${yudao.info.system-package}"}) // TODO 芋艿:重构
"${yudao.info.base-package2}"}) // TODO 芋艿:重构
public class AdminServerApplication {
public static void main(String[] args) {
......
......@@ -100,7 +100,7 @@ apollo:
eagerLoad:
enabled: true # 设置 Apollo 在日志初始化前生效,可以实现日志的动态级别配置
jdbc: # 自定义的 JDBC 配置项,用于数据库的地址
dao: cn.iocoder.yudao.coreservice.modules.infra.dal.mysql.config.InfConfigCoreDAOImpl
dao: cn.iocoder.yudao.module.infra.dal.mysql.config.ConfigCoreDAOImpl
url: ${spring.datasource.dynamic.datasource.master.url}
username: ${spring.datasource.dynamic.datasource.master.username}
password: ${spring.datasource.dynamic.datasource.master.password}
......
......@@ -113,7 +113,7 @@ apollo:
eagerLoad:
enabled: true # 设置 Apollo 在日志初始化前生效,可以实现日志的动态级别配置
jdbc: # 自定义的 JDBC 配置项,用于数据库的地址
dao: cn.iocoder.yudao.coreservice.modules.infra.dal.mysql.config.InfConfigCoreDAOImpl
dao: cn.iocoder.yudao.module.infra.dal.mysql.config.ConfigCoreDAOImpl
url: ${spring.datasource.dynamic.datasource.master.url}
username: ${spring.datasource.dynamic.datasource.master.username}
password: ${spring.datasource.dynamic.datasource.master.password}
......
......@@ -48,17 +48,16 @@ yudao:
info:
version: 1.0.0
base-package: cn.iocoder.yudao.adminserver
member-package: cn.iocoder.yudao.module.member
system-package: cn.iocoder.yudao.module.system
base-package2: cn.iocoder.yudao.module
core-service:
base-package: cn.iocoder.yudao.coreservice
web:
admin-api:
prefix: /admin-api
controller: cn.iocoder.yudao.module.system.controller.admin # TODO 芋艿:需要改造
controller: '**.controller.admin.**'
app-api:
prefix: /app-api
controller: cn.iocoder.yudao.module.member.controller.app # TODO 芋艿:需要改造
controller: '**.controller.app.**'
swagger:
title: 管理后台
......
-- inf 开头的 DB
DELETE FROM "inf_config";
DELETE FROM "inf_file";
DELETE FROM "inf_job";
DELETE FROM "inf_job_log";
DELETE FROM "inf_api_access_log";
DELETE FROM "inf_api_error_log";
-- pay 开头的 DB
DELETE FROM pay_merchant;
......
-- inf 开头的 DB
CREATE TABLE IF NOT EXISTS "inf_config" (
"id" bigint(20) NOT NULL GENERATED BY DEFAULT AS IDENTITY,
"group" varchar(50) NOT NULL,
"type" tinyint NOT NULL,
"name" varchar(100) NOT NULL DEFAULT '',
"key" varchar(100) NOT NULL DEFAULT '',
"value" varchar(500) NOT NULL DEFAULT '',
"sensitive" bit NOT NULL,
"remark" varchar(500) DEFAULT NULL,
"creator" varchar(64) DEFAULT '',
"create_time" timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
"updater" varchar(64) DEFAULT '',
"update_time" timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
"deleted" bit NOT NULL DEFAULT FALSE,
PRIMARY KEY ("id")
) COMMENT '参数配置表';
CREATE TABLE IF NOT EXISTS "inf_file" (
"id" varchar(188) NOT NULL,
"type" varchar(63) DEFAULT NULL,
"content" blob NOT NULL,
"creator" varchar(64) DEFAULT '',
"create_time" timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
"updater" varchar(64) DEFAULT '',
"update_time" timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
"deleted" bit NOT NULL DEFAULT FALSE,
"tenant_id" bigint not null default '0',
PRIMARY KEY ("id")
) COMMENT '文件表';
CREATE TABLE IF NOT EXISTS "inf_job" (
"id" bigint(20) NOT NULL GENERATED BY DEFAULT AS IDENTITY COMMENT '任务编号',
"name" varchar(32) NOT NULL COMMENT '任务名称',
"status" tinyint(4) NOT NULL COMMENT '任务状态',
"handler_name" varchar(64) NOT NULL COMMENT '处理器的名字',
"handler_param" varchar(255) DEFAULT NULL COMMENT '处理器的参数',
"cron_expression" varchar(32) NOT NULL COMMENT 'CRON 表达式',
"retry_count" int(11) NOT NULL DEFAULT '0' COMMENT '重试次数',
"retry_interval" int(11) NOT NULL DEFAULT '0' COMMENT '重试间隔',
"monitor_timeout" int(11) NOT NULL DEFAULT '0' COMMENT '监控超时时间',
"creator" varchar(64) DEFAULT '' COMMENT '创建者',
"create_time" datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
"updater" varchar(64) DEFAULT '' COMMENT '更新者',
"update_time" datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
"deleted" bit NOT NULL DEFAULT FALSE COMMENT '是否删除',
PRIMARY KEY ("id")
) COMMENT='定时任务表';
CREATE TABLE IF NOT EXISTS "inf_job_log" (
"id" bigint(20) NOT NULL GENERATED BY DEFAULT AS IDENTITY COMMENT '日志编号',
"job_id" bigint(20) NOT NULL COMMENT '任务编号',
"handler_name" varchar(64) NOT NULL COMMENT '处理器的名字',
"handler_param" varchar(255) DEFAULT NULL COMMENT '处理器的参数',
"execute_index" tinyint(4) NOT NULL DEFAULT '1' COMMENT '第几次执行',
"begin_time" datetime NOT NULL COMMENT '开始执行时间',
"end_time" datetime DEFAULT NULL COMMENT '结束执行时间',
"duration" int(11) DEFAULT NULL COMMENT '执行时长',
"status" tinyint(4) NOT NULL COMMENT '任务状态',
"result" varchar(4000) DEFAULT '' COMMENT '结果数据',
"creator" varchar(64) DEFAULT '' COMMENT '创建者',
"create_time" datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
"updater" varchar(64) DEFAULT '' COMMENT '更新者',
"update_time" datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
"deleted" bit(1) NOT NULL DEFAULT FALSE COMMENT '是否删除',
PRIMARY KEY ("id")
)COMMENT='定时任务日志表';
CREATE TABLE IF NOT EXISTS "pay_merchant"
(
......
......@@ -40,10 +40,6 @@
<groupId>cn.iocoder.boot</groupId>
<artifactId>yudao-spring-boot-starter-biz-tenant</artifactId>
</dependency>
<dependency>
<groupId>cn.iocoder.boot</groupId>
<artifactId>yudao-spring-boot-starter-biz-social</artifactId>
</dependency>
<!-- Web 相关 -->
<dependency>
......
package cn.iocoder.yudao.coreservice;
import cn.iocoder.yudao.coreservice.config.RedisTestConfiguration;
import cn.iocoder.yudao.framework.datasource.config.YudaoDataSourceAutoConfiguration;
import cn.iocoder.yudao.framework.mybatis.config.YudaoMybatisAutoConfiguration;
import cn.iocoder.yudao.framework.redis.config.YudaoRedisAutoConfiguration;
import com.alibaba.druid.spring.boot.autoconfigure.DruidDataSourceAutoConfigure;
import com.baomidou.mybatisplus.autoconfigure.MybatisPlusAutoConfiguration;
import org.redisson.spring.starter.RedissonAutoConfiguration;
import org.springframework.boot.autoconfigure.data.redis.RedisAutoConfiguration;
import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration;
import org.springframework.boot.autoconfigure.jdbc.DataSourceTransactionManagerAutoConfiguration;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.context.annotation.Import;
import org.springframework.test.context.ActiveProfiles;
import org.springframework.test.context.jdbc.Sql;
/**
* 依赖内存 DB + Redis 的单元测试
*
* 相比 {@link BaseDbUnitTest} 来说,额外增加了内存 Redis
*
* @author 芋道源码
*/
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.NONE, classes = BaseDbAndRedisUnitTest.Application.class)
@ActiveProfiles("unit-test") // 设置使用 application-unit-test 配置文件
@Sql(scripts = "/sql/clean.sql", executionPhase = Sql.ExecutionPhase.AFTER_TEST_METHOD) // 每个单元测试结束后,清理 DB
public class BaseDbAndRedisUnitTest {
@Import({
// DB 配置类
YudaoDataSourceAutoConfiguration.class, // 自己的 DB 配置类
DataSourceAutoConfiguration.class, // Spring DB 自动配置类
DataSourceTransactionManagerAutoConfiguration.class, // Spring 事务自动配置类
DruidDataSourceAutoConfigure.class, // Druid 自动配置类
// MyBatis 配置类
YudaoMybatisAutoConfiguration.class, // 自己的 MyBatis 配置类
MybatisPlusAutoConfiguration.class, // MyBatis 的自动配置类
// Redis 配置类
RedisTestConfiguration.class, // Redis 测试配置类,用于启动 RedisServer
RedisAutoConfiguration.class, // Spring Redis 自动配置类
YudaoRedisAutoConfiguration.class, // 自己的 Redis 配置类
RedissonAutoConfiguration.class, // Redisson 自动高配置类
})
public static class Application {
}
}
package cn.iocoder.yudao.coreservice;
import cn.iocoder.yudao.framework.datasource.config.YudaoDataSourceAutoConfiguration;
import cn.iocoder.yudao.framework.mybatis.config.YudaoMybatisAutoConfiguration;
import com.alibaba.druid.spring.boot.autoconfigure.DruidDataSourceAutoConfigure;
import com.baomidou.mybatisplus.autoconfigure.MybatisPlusAutoConfiguration;
import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration;
import org.springframework.boot.autoconfigure.jdbc.DataSourceTransactionManagerAutoConfiguration;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.context.annotation.Import;
import org.springframework.test.context.ActiveProfiles;
import org.springframework.test.context.jdbc.Sql;
/**
* 依赖内存 DB 的单元测试
*
* 注意,Service 层同样适用。对于 Service 层的单元测试,我们针对自己模块的 Mapper 走的是 H2 内存数据库,针对别的模块的 Service 走的是 Mock 方法
*
* @author 芋道源码
*/
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.NONE, classes = BaseDbUnitTest.Application.class)
@ActiveProfiles("unit-test") // 设置使用 application-unit-test 配置文件
@Sql(scripts = "/sql/clean.sql", executionPhase = Sql.ExecutionPhase.AFTER_TEST_METHOD) // 每个单元测试结束后,清理 DB
public class BaseDbUnitTest {
@Import({
// DB 配置类
YudaoDataSourceAutoConfiguration.class, // 自己的 DB 配置类
DataSourceAutoConfiguration.class, // Spring DB 自动配置类
DataSourceTransactionManagerAutoConfiguration.class, // Spring 事务自动配置类
DruidDataSourceAutoConfigure.class, // Druid 自动配置类
// MyBatis 配置类
YudaoMybatisAutoConfiguration.class, // 自己的 MyBatis 配置类
MybatisPlusAutoConfiguration.class, // MyBatis 的自动配置类
})
public static class Application {
}
}
package cn.iocoder.yudao.coreservice;
import cn.iocoder.yudao.coreservice.config.RedisTestConfiguration;
import cn.iocoder.yudao.framework.redis.config.YudaoRedisAutoConfiguration;
import org.redisson.spring.starter.RedissonAutoConfiguration;
import org.springframework.boot.autoconfigure.data.redis.RedisAutoConfiguration;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.context.annotation.Import;
import org.springframework.test.context.ActiveProfiles;
/**
* 依赖内存 Redis 的单元测试
*
* 相比 {@link BaseDbUnitTest} 来说,从内存 DB 改成了内存 Redis
*
* @author 芋道源码
*/
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.NONE, classes = BaseRedisUnitTest.Application.class)
@ActiveProfiles("unit-test") // 设置使用 application-unit-test 配置文件
public class BaseRedisUnitTest {
@Import({
// Redis 配置类
RedisTestConfiguration.class, // Redis 测试配置类,用于启动 RedisServer
RedisAutoConfiguration.class, // Spring Redis 自动配置类
YudaoRedisAutoConfiguration.class, // 自己的 Redis 配置类
RedissonAutoConfiguration.class, // Redisson 自动高配置类
})
public static class Application {
}
}
package cn.iocoder.yudao.coreservice.config;
import com.github.fppt.jedismock.RedisServer;
import org.springframework.boot.autoconfigure.data.redis.RedisProperties;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Lazy;
import java.io.IOException;
@Configuration(proxyBeanMethods = false)
@Lazy(false) // 禁止延迟加载
@EnableConfigurationProperties(RedisProperties.class)
public class RedisTestConfiguration {
/**
* 创建模拟的 Redis Server 服务器
*/
@Bean
public RedisServer redisServer(RedisProperties properties) throws IOException {
RedisServer redisServer = new RedisServer(properties.getPort());
// TODO 芋艿:一次执行多个单元测试时,貌似创建多个 spring 容器,导致不进行 stop。这样,就导致端口被占用,无法启动。。。
try {
redisServer.start();
} catch (Exception ignore) {}
return redisServer;
}
}
package cn.iocoder.yudao.coreservice.modules.infra.service.logger;
import cn.hutool.core.util.RandomUtil;
import cn.iocoder.yudao.coreservice.BaseDbUnitTest;
import cn.iocoder.yudao.coreservice.modules.infra.dal.dataobject.logger.InfApiAccessLogDO;
import cn.iocoder.yudao.coreservice.modules.infra.dal.mysql.logger.InfApiAccessLogCoreMapper;
import cn.iocoder.yudao.coreservice.modules.infra.service.logger.impl.InfApiAccessLogCoreServiceImpl;
import cn.iocoder.yudao.framework.apilog.core.service.dto.ApiAccessLogCreateReqDTO;
import cn.iocoder.yudao.framework.common.enums.UserTypeEnum;
import cn.iocoder.yudao.framework.test.core.util.RandomUtils;
import org.junit.jupiter.api.Test;
import org.springframework.context.annotation.Import;
import javax.annotation.Resource;
import static cn.iocoder.yudao.framework.test.core.util.AssertUtils.assertPojoEquals;
import static org.junit.jupiter.api.Assertions.assertNotNull;
/**
* {@link InfApiAccessLogCoreServiceImpl} 单元测试
*/
@Import(InfApiAccessLogCoreServiceImpl.class)
public class InfApiAccessLogCoreServiceTest extends BaseDbUnitTest {
@Resource
private InfApiAccessLogCoreService apiAccessLogCoreService;
@Resource
private InfApiAccessLogCoreMapper apiAccessLogCoreMapper;
@Test
public void testCreateApiAccessLogAsync() {
// 准备参数
ApiAccessLogCreateReqDTO createDTO = RandomUtils.randomPojo(ApiAccessLogCreateReqDTO.class,
dto -> dto.setUserType(RandomUtil.randomEle(UserTypeEnum.values()).getValue()));
// 调用
apiAccessLogCoreService.createApiAccessLogAsync(createDTO);
// 断言
InfApiAccessLogDO infApiAccessLogDO = apiAccessLogCoreMapper.selectOne(null);
assertNotNull(infApiAccessLogDO);
assertPojoEquals(createDTO, infApiAccessLogDO);
}
}
package cn.iocoder.yudao.coreservice.modules.infra.service.logger;
import cn.hutool.core.util.RandomUtil;
import cn.iocoder.yudao.coreservice.BaseDbUnitTest;
import cn.iocoder.yudao.coreservice.modules.infra.dal.dataobject.logger.InfApiErrorLogDO;
import cn.iocoder.yudao.coreservice.modules.infra.dal.mysql.logger.InfApiErrorLogCoreMapper;
import cn.iocoder.yudao.coreservice.modules.infra.service.logger.impl.InfApiErrorLogCoreServiceImpl;
import cn.iocoder.yudao.framework.apilog.core.service.dto.ApiErrorLogCreateReqDTO;
import cn.iocoder.yudao.framework.common.enums.UserTypeEnum;
import cn.iocoder.yudao.framework.test.core.util.RandomUtils;
import org.junit.jupiter.api.Test;
import org.springframework.context.annotation.Import;
import javax.annotation.Resource;
import static cn.iocoder.yudao.framework.test.core.util.AssertUtils.assertPojoEquals;
import static org.junit.jupiter.api.Assertions.assertNotNull;
/**
* {@link InfApiErrorLogCoreServiceImpl} 单元测试
*/
@Import(InfApiErrorLogCoreServiceImpl.class)
public class InfApiErrorLogCoreServiceTest extends BaseDbUnitTest {
@Resource
private InfApiErrorLogCoreService apiErrorLogCoreService;
@Resource
private InfApiErrorLogCoreMapper infApiErrorLogCoreMapper;
@Test
public void testCreateApiErrorLogAsync() {
// 准备参数
ApiErrorLogCreateReqDTO createDTO = RandomUtils.randomPojo(ApiErrorLogCreateReqDTO.class,
dto -> dto.setUserType(RandomUtil.randomEle(UserTypeEnum.values()).getValue()));
// 调用
apiErrorLogCoreService.createApiErrorLogAsync(createDTO);
// 断言
InfApiErrorLogDO infApiErrorLogDO = infApiErrorLogCoreMapper.selectOne(null);
assertNotNull(infApiErrorLogDO);
assertPojoEquals(createDTO, infApiErrorLogDO);
}
}
package cn.iocoder.yudao.coreservice.modules.infra.service;
......@@ -24,6 +24,7 @@ import java.util.List;
import java.util.Properties;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.function.Predicate;
@Slf4j
public class DBConfigRepository extends AbstractConfigRepository {
......@@ -135,7 +136,7 @@ public class DBConfigRepository extends AbstractConfigRepository {
private Properties buildProperties(List<ConfigRespDTO> configs) {
Properties properties = propertiesFactory.getPropertiesInstance();
configs.stream().filter(ConfigRespDTO::getDeleted) // 过滤掉被删除的配置
configs.stream().filter(config -> !config.getDeleted()) // 过滤掉被删除的配置
.forEach(config -> properties.put(config.getKey(), config.getValue()));
return properties;
}
......
......@@ -16,7 +16,7 @@ import org.springframework.context.annotation.Configuration;
*/
@Configuration
@MapperScan(value = {"${yudao.info.base-package}", "${yudao.core-service.base-package}",
"${yudao.info.member-package}", "${yudao.info.system-package}"},
"${yudao.info.base-package2}"},
annotationClass = Mapper.class,
lazyInitialization = "${mybatis.lazy-initialization:false}") // Mapper 懒加载,目前仅用于单元测试
public class YudaoMybatisAutoConfiguration {
......
......@@ -36,11 +36,9 @@ public class WebProperties {
private String prefix;
/**
* Controller 所在包
* Controller 所在包的 Ant 路径规则
*
* 主要目的是,给该 Controller 设置指定的 {@link #prefix}
*
* 因为我们有多个 modules 包里会包含 Controller,所以只需要写到 cn.iocoder.yudao 这样的层级
*/
@NotEmpty(message = "Controller 所在包不能为空")
private String controller;
......
......@@ -13,6 +13,7 @@ import org.springframework.boot.context.properties.EnableConfigurationProperties
import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.util.AntPathMatcher;
import org.springframework.util.PathMatcher;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.cors.CorsConfiguration;
......@@ -49,8 +50,9 @@ public class YudaoWebAutoConfiguration implements WebMvcConfigurer {
* @param api API 配置
*/
private void configurePathMatch(PathMatchConfigurer configurer, WebProperties.Api api) {
AntPathMatcher antPathMatcher = new AntPathMatcher(".");
configurer.addPathPrefix(api.getPrefix(), clazz -> clazz.isAnnotationPresent(RestController.class)
&& clazz.getPackage().getName().startsWith(api.getController())); // 仅仅匹配 controller 包
&& antPathMatcher.match(api.getController(), clazz.getPackage().getName())); // 仅仅匹配 controller 包
}
@Bean
......
package cn.iocoder.yudao.module.infra.api.file;
import cn.hutool.core.util.IdUtil;
/**
* 文件 API 接口
*
* @author 芋道源码
*/
public interface FileApi {
/**
* 保存文件,并返回文件的访问路径
*
* @param content 文件内容
* @return 文件路径
*/
default String createFile(byte[] content) {
return createFile(IdUtil.fastUUID(), content);
}
/**
* 保存文件,并返回文件的访问路径
*
* @param path 文件路径
* @param content 文件内容
* @return 文件路径
*/
String createFile(String path, byte[] content);
}
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment