SpringBoot笔记:SpringBoot 集成 Dataway 多数据源配置(二)

文章目录

  • 前言
  • 核心代码和配置
    • yml 配置
    • 注入多数据源
    • 常用Spi实现
    • swagger 配置
    • 自定义 Udf
    • 指定数据源进行查询

前言

之前简单介绍了一下 Dataway 使用,本文继续介绍一下它的多数据源配置和使用。

核心代码和配置

yml 配置

# springboot多环境配置
#端口,项目上下文
server:port: 8080servlet:context-path: /springboot-dataway# 全局服务编码设置encoding:charset: utf-8enabled: trueforce: true# mysql 连接信息配置
spring:# mysql 数据库连接信息,本地使用 mysql 服务版本为:8.0.28datasource:username: rootpassword: 6tojyh*A3eQ6url: jdbc:mysql://localhost:3306/dataway?useSSL=false&useUnicode=true&characterEncoding=utf8&serverTimezone=Asia/Shanghai&rewriteBatchedStatements=true&allowPublicKeyRetrieval=truedriver-class-name: com.mysql.cj.jdbc.Driver# druid 数据连接池配置druid:initial-size: 3min-idle: 3max-active: 10max-wait: 6000# 配置druid监控页aop-patterns: com.demo.* #监控springBeanstat-view-servlet: # 配置监控页功能enabled: true # 默认开启,这里显示说明login-username: admin # 登录名login-password: 6tojyh*A3eQ6 # 登录密码reset-enable: false # 禁用重置按钮web-stat-filter: # 监控 webenabled: trueurl-pattern: /* # 监控所有exclusions: '*.js,*.gif,*.jpg,*.png,*.css,*.ico,/druid/*'  #放行filter:stat: # 对上面 filters 里的 stat 的详细配置slow-sql-millis: 1000 # 慢 sql 时间是毫秒单位的,执行时间 1 秒以上的为慢 SQLlog-slow-sql: true # 日志记录enabled: truewall:enabled: trueconfig:drop-table-allow: false # 禁用删除表的 sql# 除主数据源外,第1个数据源db1:username: rootpassword: 6tojyh*A3eQ6url: jdbc:mysql://localhost:3306/console?useSSL=false&useUnicode=true&characterEncoding=utf8&serverTimezone=Asia/Shanghai&rewriteBatchedStatements=true&allowPublicKeyRetrieval=truedriver-class-name: com.mysql.cj.jdbc.Driver# 除主数据源外,第 2 个数据源db2:username: postgrespassword: UFWOd75qD7url: jdbc:postgresql://localhost:32770/postgres?binaryTransfer=false&forceBinary=false&reWriteBatchedInserts=truedriver-class-name: org.postgresql.Driver# mdataway 配置
# 是否启用 Dataway 功能(必选:默认false)
HASOR_DATAQL_DATAWAY: true
# 开启 ui 管理功能(注意生产环境必须要设置为 false,否则会造成严重的生产安全事故)
HASOR_DATAQL_DATAWAY_ADMIN: true
# dataway  API工作路径(可选,默认:/api/)
HASOR_DATAQL_DATAWAY_API_URL: /api/
# dataway-ui 的工作路径(可选,默认:/interface-ui/)
HASOR_DATAQL_DATAWAY_UI_URL: /interface-ui/
# SQL执行器方言设置(可选,建议设置)
HASOR_DATAQL_FX_PAGE_DIALECT: mysql
# 登陆认证方式在 basic 模式下的时候,配置的登陆账号
HASOR_DATAQL_DATAWAY_AUTHORIZATION_USERNAME: admin
# 登陆认证方式在 basic 模式下的时候,配置的登陆密码,默认密码admin
HASOR_DATAQL_DATAWAY_AUTHORIZATION_PASSWORD: 6tojyh*A3eQ6# 日志输出配置
logging:level:root: debugorg:springframework:security: WARNweb: ERROR# 设置自己的 com.demo.mapper 目录 输出sql日志com.demo.mapper: debugfile:path: ./logsname: './logs/springboot-dataway.log'pattern:file: '%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50}:%L - %msg%n'console: '%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50}:%L - %msg%n'

注入多数据源

package com.demo.config;import com.alibaba.druid.pool.DruidDataSource;
import com.demo.chain.*;
import net.hasor.core.ApiBinder;
import net.hasor.core.DimModule;
import net.hasor.core.TypeSupplier;
import net.hasor.dataql.Finder;
import net.hasor.dataql.QueryApiBinder;
import net.hasor.dataql.fx.db.FxSqlCheckChainSpi;
import net.hasor.dataway.spi.LoginPerformChainSpi;
import net.hasor.dataway.spi.LoginTokenChainSpi;
import net.hasor.dataway.spi.PreExecuteChainSpi;
import net.hasor.dataway.spi.ResultProcessChainSpi;
import net.hasor.db.JdbcModule;
import net.hasor.db.Level;
import net.hasor.spring.SpringModule;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.ApplicationContext;
import org.springframework.stereotype.Component;import javax.annotation.Resource;
import javax.sql.DataSource;/*** @Classname DatawayModule* @Description 将Hasor模块注入spring,并注入数据源* @Date 2023/7/28 11:43* @Created by Leo825*/
@DimModule  // Hasor 中的标签,表明是一个Hasor的model
@Component  // Spring 中的标签,表明是一个组件
public class DatawayModule implements SpringModule,TypeSupplier {// 默认数据源@Autowiredprivate DataSource dataSource;// 数据源1的配置信息@Value("${spring.datasource.db1.url}")private String jdbcUrl1;@Value("${spring.datasource.db1.driver-class-name}")private String driver1;@Value("${spring.datasource.db1.username}")private String username1;@Value("${spring.datasource.db1.password}")private String password1;// 数据源2的配置信息@Value("${spring.datasource.db2.url}")private String jdbcUrl2;@Value("${spring.datasource.db2.driver-class-name}")private String driver2;@Value("${spring.datasource.db2.username}")private String username2;@Value("${spring.datasource.db2.password}")private String password2;@Resourceprivate ApplicationContext applicationContext;@Overridepublic <T> T get(Class<? extends T> targetType) {return applicationContext.getBean(targetType);}@Overridepublic <T> boolean test(Class<? extends T> targetType) {return applicationContext.getBeanNamesForType(targetType).length > 0;}@Overridepublic void loadModule(ApiBinder apiBinder) throws Throwable {// .DataSource form Spring boot into HasorapiBinder.installModule(new JdbcModule(Level.Full, this.dataSource));// 注入数据源apiBinder.installModule(new JdbcModule(Level.Full, this.dataSource));apiBinder.installModule(new JdbcModule(Level.Full, "dataSource1", getDataSource(jdbcUrl1, driver1, username1, password1)));apiBinder.installModule(new JdbcModule(Level.Full, "dataSource2", getDataSource(jdbcUrl2, driver2, username2, password2)));// 打印sql日志apiBinder.bindSpiListener(FxSqlCheckChainSpi.class, FxSqlCheckChain.getInstance());// 数据权限参数apiBinder.bindSpiListener(PreExecuteChainSpi.class, PreExecuteChain.getInstance());// 返回结果apiBinder.bindSpiListener(ResultProcessChainSpi.class, ResultProcessChain.getInstance());
//        // 登录过滤
//        apiBinder.bindSpiListener(LoginPerformChainSpi.class, LoginPerformChain.getInstance());// 登录 token 过滤
//        apiBinder.bindSpiListener(LoginTokenChainSpi.class, LoginTokenChain.getInstance());// udf/udfSource/import 指令 的类型创建委托给 springQueryApiBinder queryBinder = apiBinder.tryCast(QueryApiBinder.class);queryBinder.bindFinder(Finder.TYPE_SUPPLIER.apply(this));}/*** 注入数据源** @param* @param driver* @param username* @param password* @return*/private DruidDataSource getDataSource(String jdbcUrl, String driver, String username, String password) {DruidDataSource dataSource = new DruidDataSource();dataSource.setUrl(jdbcUrl);dataSource.setUsername(username);dataSource.setPassword(password);dataSource.setDriverClassName(driver);// 用来检测连接是否有效dataSource.setValidationQuery("SELECT 1");// 借用连接时执行validationQuery检测连接是否有效,做了这个配置会降低性能dataSource.setTestOnBorrow(false);// 归还连接时执行validationQuery检测连接是否有效,做了这个配置会降低性能dataSource.setTestOnReturn(false);// 连接空闲时检测,如果连接空闲时间大于timeBetweenEvictionRunsMillis指定的毫秒,// 执行validationQuery指定的SQL来检测连接是否有效// 如果检测失败,则连接将被从池中去除dataSource.setTestWhileIdle(true);dataSource.setTimeBetweenEvictionRunsMillis(60000);//1分钟dataSource.setMaxActive(20);dataSource.setInitialSize(5);return dataSource;}
}

常用Spi实现

FxSqlCheckChainSpi,这里主要用来打印 sql

package com.demo.chain;import lombok.extern.slf4j.Slf4j;
import net.hasor.dataql.fx.db.FxSqlCheckChainSpi;
import net.hasor.utils.StringUtils;/*** @Classname FxSqlCheckChain* @Description 打印sql* @Date 2023/8/3 20:35* @Created by Leo825*/
@Slf4j
public class FxSqlCheckChain implements FxSqlCheckChainSpi {public static FxSqlCheckChain getInstance() {return new FxSqlCheckChain();}@Overridepublic int doCheck(FxSqlInfo fxSqlInfo) throws Throwable {String sourceName = fxSqlInfo.getSourceName();if (StringUtils.isNotEmpty(sourceName)) {log.info("【dataway】dataSource ==>:{}", sourceName);}log.info("【dataway】sql ==>:{}", fxSqlInfo.getQueryString().trim());log.info("【dataway】params ==>: {}", fxSqlInfo.getQueryParams());// 如果存在后续,那么继续执行检查,否则使用 EXIT 常量控制退出后续的检查。return FxSqlCheckChainSpi.NEXT;}
}

PreExecuteChainSpi,这里主要是在接口执行前进行一些权限参数控制

package com.demo.chain;import lombok.extern.slf4j.Slf4j;
import net.hasor.dataway.spi.ApiInfo;
import net.hasor.dataway.spi.PreExecuteChainSpi;
import net.hasor.utils.future.BasicFuture;
import org.apache.commons.collections4.MapUtils;import java.util.HashMap;
import java.util.Map;/*** @Classname PreExecuteChain* @Description 接口执行前* @Date 2023/8/3 20:37* @Created by Leo825*/
@Slf4j
public class PreExecuteChain implements PreExecuteChainSpi {public static PreExecuteChain getInstance() {return new PreExecuteChain();}/*** sql 直接前* @param apiInfo* @param basicFuture*/@Overridepublic void preExecute(ApiInfo apiInfo, BasicFuture<Object> basicFuture) {Map<String, Object> parameter = apiInfo.getParameterMap();// 注入用户权限参数parameter.putAll(MapUtils.emptyIfNull(loginUserAuthParams()));}/*** 获取登录用户权限参数* @return*/private Map<String, Object> loginUserAuthParams () {Map<String, Object> authParams = new HashMap<>();// todo 注入登录用户 权限参数return authParams;}
}

ResultProcessChainSpi,主要是返回值进行一些封装

package com.demo.chain;
import com.demo.common.AjaxResult;
import lombok.extern.slf4j.Slf4j;
import net.hasor.dataway.spi.ApiInfo;
import net.hasor.dataway.spi.ResultProcessChainSpi;
/*** @Classname ReturnProcessChain* @Description 兼* 容 4.1.5之前 dataway版本 dataway 执行结果处理, 让 structure 配置仅使用于   dataway页面调试使用* @Date 2023/8/3 20:47* @Created by Leo825*/
@Slf4j
public class ResultProcessChain implements ResultProcessChainSpi {public static ResultProcessChain getInstance() {return new ResultProcessChain();}/*** 对返回结果进行处理* @param formPre* @param apiInfo* @param result* @return*/@Overridepublic Object callAfter(boolean formPre, ApiInfo apiInfo, Object result) {// apiInfo.isPerform() 为 true 表示,API 调用是从 UI 界面发起的。if (apiInfo.isPerform() || apiInfo.getParameterMap().containsKey("SELF_CALL")) {return result;}apiInfo.getOptionMap().put("resultStructure", false);return AjaxResult.success(result);}/*** 异常* @param formPre* @param apiInfo* @param e* @return*/@Overridepublic Object callError(boolean formPre, ApiInfo apiInfo, Throwable e) {if (apiInfo.isPerform()) {return ResultProcessChainSpi.super.callError(formPre, apiInfo, e);}apiInfo.getOptionMap().put("resultStructure", false);return AjaxResult.error( "系统繁忙");}
}

swagger 配置

package com.demo.config;
import org.springframework.context.annotation.Primary;
import org.springframework.stereotype.Component;
import springfox.documentation.swagger.web.SwaggerResource;
import springfox.documentation.swagger.web.SwaggerResourcesProvider;import java.util.ArrayList;
import java.util.List;/*** swagger配置*/
@Component
@Primary
public class SwaggerProvider implements SwaggerResourcesProvider {@Overridepublic List<SwaggerResource> get() {List<SwaggerResource> resources = new ArrayList<>();resources.add(swaggerResource("应用接口", "/v2/api-docs", "1.0"));resources.add(swaggerResource("Dataway接口", "/interface-ui/api/docs/swagger2.json", "1.0"));return resources;}private SwaggerResource swaggerResource(String name, String location, String version) {SwaggerResource swaggerResource = new SwaggerResource();swaggerResource.setName(name);swaggerResource.setLocation(location);swaggerResource.setSwaggerVersion(version);return swaggerResource;}
}

将 Dataway 里面的接口发布到 swagger里面

package com.demo.config;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import springfox.documentation.builders.ApiInfoBuilder;
import springfox.documentation.builders.PathSelectors;
import springfox.documentation.builders.RequestHandlerSelectors;
import springfox.documentation.service.ApiInfo;
import springfox.documentation.spi.DocumentationType;
import springfox.documentation.spring.web.plugins.Docket;
import springfox.documentation.swagger2.annotations.EnableSwagger2;/*** swagger配置*/
@EnableSwagger2
@Configuration()
public class SwaggerConfig {@Beanpublic Docket createRestApi() {return new Docket(DocumentationType.SWAGGER_2)//.apiInfo(apiInfo())//.select()//.apis(RequestHandlerSelectors.basePackage("com.demo"))//.paths(PathSelectors.any())//.build();}private ApiInfo apiInfo() {return new ApiInfoBuilder()//.title("Spring Boot中使用Swagger2构建RESTful APIs")//.description("参考手册:https://www.hasor.net/doc/display/dataql/")//.termsOfServiceUrl("https://www.hasor.net/doc/display/dataql/")//.contact("zyc@hasor.net").version("1.0")//.build();}
}

自定义 Udf

可以使用自定义udf,并且在管理页面可以直接访问

package com.demo.udf;import com.demo.config.SpringContextUtil;
import com.demo.service.MyUdfService;
import lombok.extern.slf4j.Slf4j;
import net.hasor.dataql.DimUdf;
import net.hasor.dataql.Hints;
import net.hasor.dataql.Udf;
import org.springframework.stereotype.Service;import javax.annotation.Resource;/*** 自定义 udf,需要在 DatawayModule 添加以下配置代码,否则会出现注入为 null 问题* // udf/udfSource/import 指令 的类型创建委托给 spring* QueryApiBinder queryBinder = apiBinder.tryCast(QueryApiBinder.class);* queryBinder.bindFinder(Finder.TYPE_SUPPLIER.apply(this));*/
@Slf4j
@DimUdf("myNameUdf")
@Service
public class MyNameUdf implements Udf {@Resourceprivate MyUdfService myUdfService;@Overridepublic Object call(Hints readOnly, Object... params) {log.info("获取当前服务信息: " + myUdfService.myName());return "张三";}
}

web管理页面调用方式如下:

import 'com.demo.udf.MyNameUdf' as myNameUdf;
return myNameUdf();

示意图1

据官方文档说可以通过 import ‘bean’ 方式引入,但是尝试了没有成功。

指定数据源进行查询

主要通过 FRAGMENT_SQL_DATA_SOURCE 来指定数据源:

// springboot 整合Dataway 多数据源配置。使用示例:
hint FRAGMENT_SQL_DATA_SOURCE = "dataSource2";
var query = @@sql()<%select * from subjects
%>
return query()

测试2

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/84910.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

3D Web轻量化引擎HOOPS Communicator如何实现对BIM桌面端的支持?

HOOPS Communicator是一款简单而强大的工业级高性能3D Web轻量化渲染开发包&#xff0c;其主要应用于Web领域&#xff0c;主要加载其专有的SCS、SC、SCZ格式文件&#xff1b;HOOPS还拥有另一个桌面端开发包HOOPS Visualize&#xff0c;主要加载HSF、HMF轻量化格式文件。两者虽然…

git一次错误merge的回滚

场景&#xff1a;提交到sit的代码&#xff0c;结果解决冲突merge了DEV的代码&#xff0c;所以要回滚到合并之前的代码 &#xff08;原因是我再网页上处理了冲突&#xff0c;他就自动merge了,如图—所以还是idea处理冲突&#xff0c;可控&#xff09; 方式二&#xff1a; &…

详解C语言函数:深入了解函数的使用和特性

目录 引言 一、函数的概念 1.1 函数关键特点 1.2 函数的组成部分 1.3 函数声明和定义格式 二、函数分类 2.1 库函数 使用库函数的步骤 2.2 自定义函数 创建自定义函数的步骤 三、函数的参数类型 3.1 形式参数&#xff08;形参&#xff09;&#xff1a; 格式&#x…

springboot工程集成前端编译包,用于uni-app webView工程,解决其需独立部署带来的麻烦,场景如页面->画布->图片->pdf

前端工程 访问方式 http://127.0.0.1:8080/context/frontEnd/index放行 public class SecurityConfig extends WebSecurityConfigurerAdapter { "/frontEnd/**",SysFrontEndController import lombok.extern.slf4j.Slf4j; import nl.basjes.shaded.org.springfram…

【Mybatis】调试查看执行的 SQL 语句

1. 问题场景&#xff1a; 记录日常开发过程中 Mybatis 调试 SQL 语句&#xff0c;想要查看Mybatis 中执行的 SQL语句&#xff0c;导致定位问题困难 2. 解决方式 双击shift找到mybatis源码中的 MappedStatement的getBoundSql()方法 public BoundSql getBoundSql(Object para…

leetcode - 75. 颜色分类(java)

颜色分类 leetcode - 75. 颜色分类题目描述双指针代码演示 双指针算法专题 leetcode - 75. 颜色分类 难度 - 中等 原题链接 - 颜色分类 题目描述 给定一个包含红色、白色和蓝色、共 n 个元素的数组 nums &#xff0c;原地对它们进行排序&#xff0c;使得相同颜色的元素相邻&…

栈和队列详解(1)

目录 一、什么是栈&#xff1f; 二、创建一个我们自己的栈 1.前置准备 1.1需要的三个文件 1.2结构体的创建和头文件的引用 2.接口的实现 2.1初始化栈结构体 2.2尾插(压栈) 2.3栈存放的元素个数和判断栈是否为空 2.4获取栈顶元素 2.5出栈 2.6摧毁栈 2.7测试接口 三、…

Java基础入门篇——IDEA开发第一个入门程序(五)

目录 一、IDEA层级结构分类 二、IDEA层级结构介绍 三、IDEA层级关系 四、创建IDEA中的第一个代码 一、IDEA层级结构分类 IntelliJ IDEA的项目结构主要分为以下几个层级&#xff1a; Project&#xff1a; 项目Module: 模块Package: 包Class&#xff1a; 类 一个项目里面…

预测赢家(力扣)dfs + 备忘录 JAVA

给你一个整数数组 nums 。玩家 1 和玩家 2 基于这个数组设计了一个游戏。 玩家 1 和玩家 2 轮流进行自己的回合&#xff0c;玩家 1 先手。开始时&#xff0c;两个玩家的初始分值都是 0 。每一回合&#xff0c;玩家从数组的任意一端取一个数字&#xff08;即&#xff0c;nums[0]…

【LeetCode】45. 跳跃游戏 II - 贪婪算法

目录标题 2023-8-11 09:49:25 45. 跳跃游戏 II 2023-8-11 09:49:25 自己没做出来&#xff0c;废物Orz class Solution {public int jump(int[] nums) {int length nums.length;int end 0;int maxPosition 0;int steps 0;for (int i 0; i < length - 1; i) {maxPosit…

首批获得金融级行业云平台认证,天翼云深耕行业云

云计算下半场看什么&#xff1f; 无疑是金融、政务、制造等传统政企用户的上云与用云。随着数字经济发展和产业数字化的提速&#xff0c;上云已是政企用户推动其数字化转型不断深入的重要抓手&#xff0c;成为不可阻挡的趋势。 与互联网用户相比&#xff0c;政企用户上云极为…

从数据仓库到数据结构:数据架构的演变之路

在上个世纪&#xff0c;从电子商务巨头到医疗服务机构和政府部门&#xff0c;数据已成为每家组织的生命线。有效地收集和管理这些数据可以为组织提供宝贵的洞察力&#xff0c;以帮助决策&#xff0c;然而这是一项艰巨的任务。 尽管数据很重要&#xff0c;但CIOinsight声称&…

那些年的Java开发经验记录

Java同步锁(浅显易懂&#xff0c;精简讲解) 详细讲解可以看这篇文章Java对象锁和类锁全面解析&#xff08;多线程synchronized关键字&#xff09; 精简如下&#xff1a; 1.不管什么锁&#xff0c;都是属于对象锁(类也是一种对象) 2.一个对象只有一个锁 3.锁最大可以锁整个…

【框架类】—Vue3的生命周期

一、生命周期的相关函数 onBeforeMount 页面渲染之前 和 onMounted渲染之后 示例 <template><div class"test"><div ref"el">组件初始化</div></div> </template> <script> //按需引入所需方法 import { ref,…

Redux - Redux在React函数式组件中的基本使用

文章目录 一&#xff0c;简介二&#xff0c;安装三&#xff0c;三大核心概念Store、Action、Reducer3.1 Store3.2 Reducer3.3 Action 四&#xff0c;开始函数式组件中使用4.1&#xff0c;引入store4.1&#xff0c;store.getState()方法4.3&#xff0c;store.dispatch()方法4.4&…

04-4_Qt 5.9 C++开发指南_时间日期与定时器

文章目录 1. 时间日期相关的类2. 源码2.1 可视化UI设计2.2 dialog.h2.3 dialog.cpp 1. 时间日期相关的类 时间日期是经常遇到的数据类型&#xff0c;Qt 中时间日期类型的类如下。 QTime:时间数据类型&#xff0c;仅表示时间&#xff0c;如 15:23:13。 QDate:日期数据类型&…

虹科方案 | 汽车总线协议转换解决方案

汽车总线&#xff1a; 汽车总线是一种用于在车辆电子系统中传输数据和控制信息的通信系统。它允许不同的电子控制单元&#xff08;ECU&#xff09;在车辆中相互通信&#xff0c;协调各个系统的操作&#xff0c;以实现功能的集成和协同工作。 在现代汽车中&#xff0c;综合通信…

微信公众号模板消息推送测试Python版无需服务器-保姆级教程

手上有个项目&#xff0c;是服务器挂着自动化的爬虫的&#xff0c;但我用的那个IP代理商没有用尽报警&#xff0c;导致几次IP用尽&#xff0c;程序爬不到数据&#xff0c;进程死循环了。之前想过发邮箱提醒我&#xff0c;但是邮箱把又不及时&#xff0c;老忘记看&#xff0c;因…

C语言必会题目(1)

W...Y的主页 &#x1f60a; 代码仓库分享❤️ 在学习语言时&#xff0c;最重要的就是练习&#xff0c;光听不练假把式。下面我就推荐一些C语言必会的题。 执行下面程序&#xff0c;正确的输出是&#xff08; &#xff09; int x5,y7; void swap() { int z; zx; xy; yz; } int…