介绍
这是一个简单的响应式接口开发框架,基于对vertx的路由创建,服务注册,Verticle部署等基本操作的简单封装,让接口开发过程更接近于传统的开发模式,简化响应式接口开发流程,降低开发门槛。
框架目前接入了jdbc,redis,后续根据具体需要在接入其他组件,更多组件信息见:https://vertx.io/docs
源码地址:https://gitee.com/javacoo/vertx-framework
软件架构
软件架构说明
安装教程
-
引入pom
<dependency> <groupId>org.javacoo.vertx</groupId> <artifactId>vertx-core</artifactId> <version>1.0</version> </dependency> <dependency> <groupId>org.javacoo.vertx</groupId> <artifactId>vertx-database</artifactId> <version>1.0</version> </dependency>
开发步骤
-
配置文件:
主配置文件:application.yaml
server: port: 8080 contextPath: / redis: urls: - redis://127.0.0.1:6379/0 clientType: STANDALONE poolName: p-red poolCleanerInterval: 30000 maxPoolSize: 8 maxPoolWaiting: 32 password: 1239abcz vertx: eventLoopPoolSize: 2 workerPoolSize: 4 eventBusOptions: connectTimeout: 6000 vertxScan: routerPackage: test.api.rest servicePackage: test.api.service serviceInstances: 1
环境配置文件:application-cloud.yaml
env: cloud dataSource: driverClass: org.postgresql.Driver url: jdbc:postgresql://127.0.0.1:9000/test?allowMultiQueries=true&useUnicode=true&characterEncoding=UTF-8&useSSL=false&serverTimezone=GMT%2B8&tinyInt1isBit=false user: postgres password: 123456 maxPoolSize: 30 sqlConfig: init: SELECT 1=1 # 总览-根据区域查询学校 getSchoolsInfoByArea: SELECT t.xxmc schoolName, t.xxdz schoolAddress, t.xxbsm schoolCode, t.jgjd longitude, t.jgwd latitude FROM gis_school_location t WHERE t.xxbxlx = !{eduType} AND t.area_code LIKE !{queryAreaCode} LIMIT !{pageSize} OFFSET !{offset}
-
启动类
public class ApiLauncher implements Launcher { private static final Logger LOGGER = LoggerFactory.getLogger(ApiLauncher.class); /** * 环境 */ private static String env = EnvEnum.CLOUD.getCode(); /** * 服务端口 */ private static int serverPort = Constant.HTTP_PORT; private Vertx vertx; @Override public void start() { Vertx tempVertx = Vertx.vertx(); // 加载配置 ConfigRetriever retriever = initConfigRetriever(tempVertx); retriever.getConfig(json -> { tempVertx.close(); if(json.succeeded()){ doStart(json); }else{ LOGGER.error("加载配置"); } }); } /** * 执行启动 * <li></li> * @author duanyong * @date 2023/3/31 21:26 * @param json * @return: void */ private void doStart(AsyncResult<JsonObject> json){ JsonObject envConfig = json.result(); LOGGER.info("配置读取成功"); //默认读取dev开发环境配置 JsonObject vertxConfig = envConfig.getJsonObject("vertx"); Vertx mainVertx = Vertx.vertx(new VertxOptions(vertxConfig)); //初始化 VertxHolder.init(mainVertx); //配置保存在共享数据中 SharedData sharedData = mainVertx.sharedData(); LocalMap<String, Object> localMap = sharedData.getLocalMap("/"); localMap.put("env", env); localMap.put("envConfig", envConfig); //先初始化再发布Http服务 mainVertx.executeBlocking(p -> { //顺序不能乱 try { //初始化ConfigProperties ConfigPropertiesHolder.init(envConfig); //初始化RedisClientHolder RedisAPIHolder.init(mainVertx, envConfig, redisConnectionAsyncResult -> { if(redisConnectionAsyncResult.succeeded()){ LOGGER.info("redis初始化成功"); }else{ LOGGER.error("redis初始化失败",redisConnectionAsyncResult.cause()); } }); //初始化JDBCClient JDBCClientHolder.init(envConfig, ready -> { if (ready.succeeded()) { p.complete(); LOGGER.info("JDBCClient初始化成功"); } else { p.fail(ready.cause()); LOGGER.error("JDBCClient初始化失败",ready.cause()); } }); } catch (Exception e) { LOGGER.error("初始化失败:{}",e); p.fail(e); } }).onComplete(ar2 -> { if (ar2.succeeded()) { JsonObject vertxScanConfig = envConfig.getJsonObject("vertxScan"); JsonObject serverConfig = envConfig.getJsonObject("server"); if(EnvEnum.CLOUD.getCode().equals(env)){ serverPort = serverConfig.getInteger("port"); } LOGGER.info("准备启动服务,http服务端口:{}",serverPort); EventConsumerConfig eventConsumerConfig = new EventConsumerConfig(); Router router = new RouterHandlerFactory(vertxScanConfig.getString("routerPackage"), serverConfig.getString("contextPath")).createRouter(); DeployVertxServer.startDeploy(eventConsumerConfig.consumer(),router, vertxScanConfig.getString("servicePackage"), serverPort, vertxScanConfig.getInteger("serviceInstances")); } else { LOGGER.error(ar2.cause().getMessage(), ar2.cause()); } }); } @Override public void stop() { vertx.close(); } /** * 初始化ConfigRetriever * <li></li> * @author duanyong * @date 2023/3/27 22:08 * @param vertx * @return: ConfigRetriever */ private ConfigRetriever initConfigRetriever(Vertx vertx) { //初始化 ConfigRetrieverOptions options = initOptions(); //创建 return ConfigRetriever.create(vertx, options); } /** * 初始化ConfigRetrieverOptions * <li></li> * @author duanyong * @date 2023/3/27 23:08 * @return: ConfigRetrieverOptions */ private ConfigRetrieverOptions initOptions() { // 使用默认ConfigStore ConfigRetrieverOptions options = new ConfigRetrieverOptions().setIncludeDefaultStores(false); // 禁用配置刷新 options.setScanPeriod(-1); //加载主配置 options.addStore(new ConfigStoreOptions() .setType("file") .setFormat("yaml") .setOptional(true) .setConfig(new JsonObject().put("path", "application.yaml"))); String envFile = new StringBuilder("application-").append(env).append(".yaml").toString(); //加载环境配置 options.addStore(new ConfigStoreOptions() .setType("file") .setFormat("yaml") .setOptional(true) .setConfig(new JsonObject().put("path", envFile))); // 禁用缓存 options.getStores().forEach(store -> { store.getConfig().put("cache", "false"); }); return options; } public static void main(String[] args) { if (args.length >= 1 && !CONFIG_DEFAULT.equals(args[0])) { env = args[0]; } if (args.length >= 2 && !CONFIG_DEFAULT.equals(args[1])) { serverPort = Integer.valueOf(args[1]); } Launcher launcher = new GisApiLauncher(); launcher.start(); } }
-
编写服务
接口类:TestService
/** * 测试服务接口 * <li></li> * * @author duanyong * @version 1.0 * @date 2023/6/24 22:17 */ @ProxyGen @VertxGen public interface TestService { @GenIgnore static test.api.reactivex.service.TestService createRxProxy() { return new test.api.reactivex.service.TestService(AsyncServiceUtil.getAsyncServiceInstance(TestService.class)); } /** * 测试方法 * <li></li> * @author duanyong * @date 2023/6/24 22:47 * @param query * @param resultHandler * @return: OverviewService */ @Fluent TestService test(JsonObject query,Handler<AsyncResult<List<JsonObject>>> resultHandler); }
实现类:TestServiceImpl
/** * 总览服务接口实现类 * <li></li> * * @author duanyong * @version 1.0 * @date 2023/6/24 23:20 */ public class TestServiceImpl extends BaseAsyncService implements TestService { protected ConfigProperties.SqlConfigProperties sqlConfig; protected JDBCClient dbClient; public OverviewServiceImpl() { sqlConfig = ConfigPropertiesHolder.getConfigProperties().getSqlConfig(); dbClient = JDBCClientHolder.getJDBCClient(); } @Override public TestService test(JsonObject query, Handler<AsyncResult<List<JsonObject>>> resultHandler) { String areaCode = getAreaCodePrefix(query); String eduType = query.getString("eduType"); Integer pageSize = query.getInteger("pageSize"); Integer pageNum = query.getInteger("pageNum"); JsonObject result = parseTemplateSQL(sqlConfig.getGetSchoolsInfoByArea(),query); String finalSql = result.getString(SQL_KEY); JsonArray data = result.getJsonArray(PARAM_KEY); String cacheKey = new StringBuilder("getSchoolsInfoByArea_").append(areaCode).append(eduType).append(pageSize).append(pageNum).toString(); loadListData(dbClient,resultHandler, finalSql, data, cacheKey); return this; } }
-
编写接口
/** * 测试服务接口 * <li></li> * * @author duanyong * @version 1.0 * @date 2023/6/25 22:27 */ @RouteHandler public class TestApi extends BaseRestApi { /** * 测试服务 */ private TestService testService = test.api.service.TestService.createRxProxy(); /** * 测试 * @return */ @RouteMapping(value = "/api/test", method = RouteMethod.POST) public Handler<RoutingContext> test() { return ctx -> { JsonObject query = ctx.body().asJsonObject(); if (!validateJsonPageDocument(ctx, query, "areaCode","level")) { return; } testService.rxTest(query) .subscribe(totalList -> fireJsonResponse(ctx, new JsonResult(totalList)), t -> fireErrorJsonResponse(ctx, t.getMessage())); }; } }
至此便完成整个开发流程