TenantDataSourceUtil.java 24 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653
  1. package jnpf.database.util;
  2. import cn.hutool.core.text.StrPool;
  3. import cn.hutool.http.HttpRequest;
  4. import cn.hutool.http.HttpResponse;
  5. import com.alibaba.druid.pool.DruidDataSource;
  6. import com.alibaba.fastjson.JSON;
  7. import com.alibaba.fastjson.JSONObject;
  8. import com.alibaba.fastjson.TypeReference;
  9. import com.baomidou.dynamic.datasource.ds.ItemDataSource;
  10. import com.baomidou.dynamic.datasource.enums.DdConstants;
  11. import jnpf.base.UserInfo;
  12. import jnpf.config.ConfigValueUtil;
  13. import jnpf.constant.GlobalConst;
  14. import jnpf.constant.MsgCode;
  15. import jnpf.consts.AuthConsts;
  16. import jnpf.exception.TenantInvalidException;
  17. import jnpf.model.tenant.TenantAuthorizeModel;
  18. import jnpf.model.tenant.TenantLinkModel;
  19. import jnpf.model.tenant.TenantMenuModel;
  20. import jnpf.model.tenant.TenantVO;
  21. import jnpf.database.model.entity.DbLinkEntity;
  22. import jnpf.database.model.interfaces.DbSourceOrDbLink;
  23. import jnpf.database.plugins.MySchemaInnerInterceptor;
  24. import jnpf.database.plugins.MyTenantLineInnerInterceptor;
  25. import jnpf.database.source.DbBase;
  26. import jnpf.database.source.impl.DbKingbase;
  27. import jnpf.database.source.impl.DbPostgre;
  28. import jnpf.exception.LoginException;
  29. import jnpf.util.*;
  30. import jnpf.util.data.DataSourceContextHolder;
  31. import lombok.extern.slf4j.Slf4j;
  32. import net.sf.jsqlparser.JSQLParserException;
  33. import net.sf.jsqlparser.parser.CCJSqlParserUtil;
  34. import net.sf.jsqlparser.statement.Statement;
  35. import net.sf.jsqlparser.statement.select.Select;
  36. import org.apache.http.HttpStatus;
  37. import org.springframework.beans.factory.annotation.Autowired;
  38. import org.springframework.stereotype.Component;
  39. import org.springframework.util.Assert;
  40. import javax.sql.DataSource;
  41. import java.sql.SQLException;
  42. import java.util.*;
  43. import java.util.stream.Collectors;
  44. /**
  45. * 租户数据工具类
  46. * @author JNPF开发平台组
  47. * @user N
  48. * @copyright 引迈信息技术有限公司
  49. * @date 2022/10/13 16:16
  50. */
  51. @Slf4j
  52. @Component
  53. public class TenantDataSourceUtil {
  54. public static final String DBLINK_KEY = "TenantInfo";
  55. public static final String MODULEID_KEY = "ModuleAuthorize";
  56. private static ConfigValueUtil configValueUtil;
  57. private static MyTenantLineInnerInterceptor myTenantLineInnerInterceptor;
  58. private static MySchemaInnerInterceptor mySchemaInnerInterceptor;
  59. private static boolean absentPermittionApi = false;
  60. @Autowired(required = false)
  61. public void setDynamicTableNameInnerInterceptor(MySchemaInnerInterceptor mySchemaInnerInterceptor) {
  62. TenantDataSourceUtil.mySchemaInnerInterceptor = mySchemaInnerInterceptor;
  63. }
  64. @Autowired(required = false)
  65. public void setMyTenantLineInnerInterceptor(MyTenantLineInnerInterceptor myTenantLineInnerInterceptor) {
  66. TenantDataSourceUtil.myTenantLineInnerInterceptor = myTenantLineInnerInterceptor;
  67. }
  68. @Autowired
  69. public void setConfigValueUtil(ConfigValueUtil configValueUtil) {
  70. TenantDataSourceUtil.configValueUtil = configValueUtil;
  71. }
  72. /**
  73. * 清空本地租户缓存信息
  74. */
  75. public static void clearLocalTenantInfo(){
  76. TenantHolder.clearLocalTenantCache();
  77. DataSourceContextHolder.clearDatasourceType();
  78. }
  79. /**
  80. * 设置租户信息到Redis缓存中
  81. *
  82. * @param tenantCode
  83. * @param tenant
  84. */
  85. public static void setCacheTenantInfo(String tenantCode, TenantVO tenant) {
  86. TenantProvider.putTenantCache(tenantCode, DBLINK_KEY, tenant);
  87. }
  88. /**
  89. * 设置租户菜单权限信息到Redis缓存中
  90. *
  91. * @param tenantCode
  92. * @param tenantAuthorizeModel
  93. */
  94. public static void setCacheModuleAuthorize(String tenantCode, TenantAuthorizeModel tenantAuthorizeModel) {
  95. TenantProvider.putTenantCache(tenantCode, MODULEID_KEY, tenantAuthorizeModel);
  96. }
  97. /**
  98. * 设置租户信息到Redis缓存、线程缓存中
  99. * @param tenantInfo
  100. */
  101. public static void setTenantInfo(TenantVO tenantInfo){
  102. setCacheTenantInfo(tenantInfo.getEnCode(), tenantInfo);
  103. TenantHolder.setLocalTenantCache(tenantInfo);
  104. }
  105. /**
  106. * 获取当前租户信息
  107. *
  108. * @return
  109. */
  110. public static TenantVO getTenantInfo() {
  111. return getTenantInfo(null);
  112. }
  113. /**
  114. * 从本地线程、Redis缓存或远程获取租户信息
  115. *
  116. * @param tenantCode
  117. * @return
  118. */
  119. public static TenantVO getTenantInfo(String tenantCode) {
  120. if(!isMultiTenancy()) return null;
  121. TenantVO tenantVO = TenantHolder.getLocalTenantCache();
  122. if(StringUtil.isEmpty(tenantCode)) {
  123. if (tenantCode == null) {
  124. UserInfo userInfo = UserProvider.getUser();
  125. if (userInfo != null && userInfo.getUserId() != null) {
  126. tenantCode = userInfo.getTenantId();
  127. }
  128. }
  129. }
  130. //判断线程缓存中的租户信息是否是当前需要获取的租户
  131. if(tenantVO != null && StringUtil.isNotEmpty(tenantCode) && !Objects.equals(tenantVO.getEnCode(), tenantCode)){
  132. tenantVO = null;
  133. }
  134. if(StringUtil.isEmpty(tenantCode) && tenantVO == null){
  135. return null;
  136. }
  137. if(tenantVO == null) {
  138. tenantVO = TenantDataSourceUtil.getCacheTenantInfo(tenantCode);
  139. if (tenantVO == null) {
  140. tenantVO = TenantDataSourceUtil.getRemoteTenantInfo(tenantCode);
  141. }
  142. }
  143. return tenantVO;
  144. }
  145. /**
  146. * 从Redis缓存中获取租户信息
  147. *
  148. * @param tenantCode
  149. * @return
  150. */
  151. public static TenantVO getCacheTenantInfo(String tenantCode) {
  152. return TenantProvider.getTenantCache(tenantCode, DBLINK_KEY);
  153. }
  154. /**
  155. * 从Redis缓存中获取租户信息
  156. *
  157. * @param tenantCode
  158. * @return
  159. */
  160. public static TenantAuthorizeModel getCacheModuleAuthorize(String tenantCode) {
  161. TenantAuthorizeModel tenantCache = TenantProvider.getTenantCache(tenantCode, MODULEID_KEY);
  162. return Optional.ofNullable(tenantCache).isPresent() ? tenantCache : new TenantAuthorizeModel();
  163. }
  164. /**
  165. * 从租户系统获取租户信息
  166. *
  167. * @param tenantCode
  168. * @return
  169. * @throws LoginException
  170. */
  171. public static TenantVO getRemoteTenantInfo(String tenantCode) throws LoginException {
  172. if(!isMultiTenancy()) return null;
  173. if(StringUtil.isEmpty(tenantCode)){
  174. throw new LoginException(MsgCode.LOG114.get());
  175. }
  176. Map<String, String> headers = new HashMap<>(2,1);
  177. headers.put(AuthConsts.INNER_TOKEN_KEY, UserProvider.getInnerAuthToken());
  178. try{
  179. String ip = IpUtil.getIpAddr();
  180. if(StringUtil.isNotEmpty(ip) && !Objects.equals("127.0.0.1", ip)) {
  181. headers.put("X-Forwarded-For", ip);
  182. }
  183. }catch (Exception e){}
  184. JSONObject object = null;
  185. try (HttpResponse execute = HttpRequest.get(configValueUtil.getMultiTenancyUrl() + tenantCode)
  186. .addHeaders(headers)
  187. .execute()) {
  188. object = JSON.parseObject(execute.body());
  189. }catch (Exception e){
  190. log.error("获取远端多租户信息失败: {}", e.getMessage());
  191. }
  192. if (object == null || "500".equals(object.get("code").toString())) {
  193. throw new LoginException(MsgCode.LOG105.get());
  194. }
  195. if (!"200".equals(object.getString("code"))) {
  196. log.error("获取多租户信息失败:{}", object.getString("msg"));
  197. JSON data = null;
  198. if(object.containsKey("data")){
  199. data = object.getJSONObject("data");
  200. }
  201. throw new TenantInvalidException(object.getString("msg")).setData(data);
  202. }
  203. JSONObject resulList = object.getJSONObject("data");
  204. // 租户库名
  205. TenantVO vo;
  206. if (resulList.containsKey("db_names")){
  207. vo = JsonUtil.getJsonToBean(resulList.getJSONObject("db_names"), TenantVO.class);
  208. if(vo.getDbName() == null){
  209. vo.setDbName((String) resulList.getJSONObject("db_names").get("java"));
  210. }
  211. vo.setWl_qrcode(resulList.getObject("wl_qrcode", new TypeReference<Map<String, String>>(){}));
  212. } else{
  213. vo = new TenantVO();
  214. vo.setDbName(resulList.getString("java"));
  215. }
  216. if(Objects.equals(vo.getType(), TenantVO.REMOTE)){
  217. //取主库库名作为租户库名
  218. vo.setDbName(vo.getLinkList().stream().filter(l->l.getConfigType().equals(0)).findFirst().get().getServiceName());
  219. }else{
  220. if(StringUtil.isEmpty(vo.getDbName())){
  221. throw new TenantInvalidException().setLogMsg(MsgCode.LOG118.get());
  222. }
  223. }
  224. vo.setEnCode(tenantCode);
  225. TenantDataSourceUtil.setCacheTenantInfo(tenantCode, vo);
  226. if(!absentPermittionApi) {
  227. try (HttpResponse execute = HttpRequest.get(configValueUtil.getMultiTenancyUrl() + "authorize/" + tenantCode)
  228. .addHeaders(headers)
  229. .execute()) {
  230. switch (execute.getStatus()){
  231. case HttpStatus.SC_OK:
  232. TenantMenuModel model = JsonUtil.getJsonToBean(execute.body(), TenantMenuModel.class);
  233. TenantAuthorizeModel tenantAuthorizeModel = new TenantAuthorizeModel(model.getIds(), model.getUrlAddressList());
  234. TenantDataSourceUtil.setCacheModuleAuthorize(tenantCode, tenantAuthorizeModel);
  235. break;
  236. case HttpStatus.SC_NOT_FOUND:
  237. absentPermittionApi = true;
  238. log.error("租户系统不存在权限管理接口, 关闭权限请求功能");
  239. break;
  240. default:
  241. log.error("获取远端多租户菜单权限失败: {}, {}", tenantCode, execute.body());
  242. }
  243. } catch (Exception e) {
  244. TenantDataSourceUtil.setCacheModuleAuthorize(tenantCode, new TenantAuthorizeModel());
  245. log.error("获取远端多租户菜单权限失败: {}, {}", tenantCode, e.getMessage());
  246. }
  247. }
  248. return vo;
  249. }
  250. /**
  251. * 获取租户指定库主库
  252. * @param tenantCode
  253. * @return
  254. */
  255. public static TenantLinkModel getTenantAssignDataSource(String tenantCode){
  256. List<TenantLinkModel> linkList = getTenantAssignDataSourceList(tenantCode);
  257. return linkList.stream().filter(link->link.getConfigType().equals(0)).findFirst().orElse(null);
  258. }
  259. /**
  260. * 获取租户指定库列表
  261. * @param tenantCode
  262. * @return
  263. */
  264. public static List<TenantLinkModel> getTenantAssignDataSourceList(String tenantCode){
  265. if(isMultiTenancy()){
  266. TenantVO tenantVO = getTenantInfo(tenantCode);
  267. List<TenantLinkModel> linkList = tenantVO.getLinkList();
  268. return linkList;
  269. }
  270. return Collections.EMPTY_LIST;
  271. }
  272. /**
  273. * 切换至当前用户的租户
  274. */
  275. public static void resetUserTenant(){
  276. }
  277. /**
  278. * 切换租户, 先从Redis缓存中获取, 再从租户系统中获取
  279. *
  280. * @param tenantCode
  281. */
  282. public static TenantVO switchTenant(String tenantCode) {
  283. if(!isMultiTenancy()) return null;
  284. TenantHolder.clearLocalTenantCache();
  285. TenantVO tenantVO = TenantDataSourceUtil.getTenantInfo(tenantCode);
  286. switchTenant(tenantCode, tenantVO);
  287. return tenantVO;
  288. }
  289. /**
  290. * 切换租户
  291. */
  292. public static void switchTenant(String tenantCode, TenantVO tenantVO) throws LoginException {
  293. if(!isMultiTenancy()) return;
  294. if (!Optional.ofNullable(tenantVO).isPresent()) {
  295. throw new LoginException(MsgCode.LOG115.get());
  296. }
  297. boolean isAssign = Objects.equals(tenantVO.getType(), TenantVO.REMOTE);
  298. TenantHolder.setLocalTenantCache(tenantVO);
  299. try {
  300. initTenantAssignDataSource(tenantVO);
  301. } catch (SQLException e) {
  302. throw new RuntimeException(e);
  303. }
  304. DataSourceContextHolder.setDatasource(tenantCode, tenantVO.getDbName(), isAssign);
  305. }
  306. /**
  307. * 获取库隔离模式的租户库名称
  308. *
  309. * @return
  310. */
  311. public static String getTenantSchema() {
  312. String result = StringUtil.EMPTY;
  313. if (isTenantSchema()) {
  314. result = getTenantName();
  315. }
  316. return result;
  317. }
  318. /**
  319. * 获取字段隔离的租户库名称, 非字段隔离返回默认值 0
  320. *
  321. * @return
  322. */
  323. public static String getTenantColumn() {
  324. String result = GlobalConst.DEFAULT_TENANT_VALUE;
  325. if (isTenantColumn()) {
  326. result = getTenantName();
  327. }
  328. return result;
  329. }
  330. /**
  331. * 获取当前租户名
  332. * 字段模式返回对应数据库默认隔离实现方式的库名 Postgre、Kingbase模式隔离 Mysql、Sqlserver、Oracle、DM库隔离
  333. * 租户指定数据源和Schema模式返回租户库名
  334. *
  335. * @return
  336. */
  337. public static String getTenantDbName() {
  338. String result = StringUtil.EMPTY;
  339. if (isMultiTenancy()) {
  340. DataSourceUtil dataSourceUtil = DynamicDataSourceUtil.getDataSourceUtil();
  341. if(isTenantColumn()){
  342. switch (dataSourceUtil.getDbType()){
  343. case DbBase.POSTGRE_SQL:
  344. result = StringUtil.isEmpty(dataSourceUtil.getDbSchema()) ? DbPostgre.DEF_SCHEMA : dataSourceUtil.getDbSchema();
  345. break;
  346. case DbBase.KINGBASE_ES:
  347. result = StringUtil.isEmpty(dataSourceUtil.getDbSchema()) ? DbKingbase.DEF_SCHEMA : dataSourceUtil.getDbSchema();
  348. break;
  349. case DbBase.ORACLE:
  350. default:
  351. result = dataSourceUtil.getDbName();
  352. }
  353. }else{
  354. result = TenantHolder.getDatasourceName();
  355. result = convertSchemaName(result);
  356. }
  357. }
  358. return result;
  359. }
  360. public static void initDataSourceTenantDbName(DbSourceOrDbLink dataSourceUtil){
  361. if(isMultiTenancy()) {
  362. if(isTenantAssignDataSource()){
  363. return;
  364. }
  365. if (!(dataSourceUtil instanceof DataSourceUtil) || (dataSourceUtil instanceof DbLinkEntity && !"0".equals(((DbLinkEntity) dataSourceUtil).getId()) && ((DbLinkEntity) dataSourceUtil).getId() != null)) {
  366. return;
  367. }
  368. boolean isColumn = isTenantColumn();
  369. //默认库在多租户Schema模式情况下需要切库
  370. //字段多租户模式下, Schema为空设置默认值
  371. DataSourceUtil ds = (DataSourceUtil) dataSourceUtil;
  372. switch (ds.getDbType()){
  373. case DbBase.POSTGRE_SQL:
  374. if(isColumn){
  375. if(StringUtil.isEmpty(ds.getDbSchema())) {
  376. ds.setDbSchema(DbPostgre.DEF_SCHEMA);
  377. }
  378. }else {
  379. ds.setDbSchema(TenantDataSourceUtil.getTenantDbName());
  380. }
  381. break;
  382. case DbBase.KINGBASE_ES:
  383. if(isColumn){
  384. if(StringUtil.isEmpty(ds.getDbSchema())) {
  385. ds.setDbSchema(DbKingbase.DEF_SCHEMA);
  386. }
  387. }else {
  388. ds.setDbSchema(TenantDataSourceUtil.getTenantDbName());
  389. }
  390. break;
  391. case DbBase.DM:
  392. case DbBase.ORACLE:
  393. ds.setDbSchema(TenantDataSourceUtil.getTenantDbName());
  394. break;
  395. default:
  396. ds.setDbName(TenantDataSourceUtil.getTenantDbName());
  397. }
  398. }
  399. }
  400. /**
  401. * 获取当前租户名
  402. *
  403. * @return
  404. */
  405. public static String getTenantName() {
  406. String result = StringUtil.EMPTY;
  407. if (isMultiTenancy() && !getTenantInfo().isRemote()) {
  408. result = TenantHolder.getDatasourceName();
  409. result = convertSchemaName(result);
  410. }
  411. return result;
  412. }
  413. /**
  414. * 转换不同数据库租户模式名
  415. * @param dbName
  416. * @return
  417. */
  418. public static String convertSchemaName(String dbName){
  419. if(StringUtil.isNotEmpty(dbName)) {
  420. switch (DynamicDataSourceUtil.dataSourceUtil.getDbType()) {
  421. case DbBase.POSTGRE_SQL:
  422. dbName = dbName.toLowerCase();
  423. break;
  424. case DbBase.DM:
  425. case DbBase.ORACLE:
  426. dbName = dbName.toUpperCase();
  427. break;
  428. }
  429. }
  430. return dbName;
  431. }
  432. /**
  433. * 初始化连接隔离数据源
  434. * @throws SQLException
  435. */
  436. public static void initTenantAssignDataSource(TenantVO tenantVO) throws SQLException {
  437. if(isTenantAssignDataSource()){
  438. String tenantId = TenantHolder.getDatasourceId();
  439. String dbKey = tenantId + StrPool.DASHED + DdConstants.MASTER;
  440. synchronized (LockObjectUtil.addLockKey(tenantId)) {
  441. if(!DynamicDataSourceUtil.dynamicRoutingDataSource.getGroupDataSources().containsKey(dbKey)) {
  442. List<String> list = new ArrayList<>(16);
  443. List<TenantLinkModel> linkList = tenantVO.getLinkList();
  444. Assert.notNull(linkList, MsgCode.FA035.get());
  445. // 添加数据源信息到redis中
  446. String mKey = dbKey + StrPool.UNDERLINE;
  447. String sKey = tenantId + StrPool.DASHED + DdConstants.SLAVE + StrPool.UNDERLINE;
  448. for (TenantLinkModel model : linkList) {
  449. DbLinkEntity dbLinkEntity = model.toDbLink(new DbLinkEntity());
  450. if ("0".equals(String.valueOf(model.getConfigType()))) {
  451. dbLinkEntity.setId(mKey + dbLinkEntity.getId());
  452. } else {
  453. dbLinkEntity.setId(sKey + dbLinkEntity.getId());
  454. }
  455. try {
  456. DataSource dataSource = DynamicDataSourceUtil.createDataSource(dbLinkEntity);
  457. dataSource.getConnection().close();
  458. list.add(dbLinkEntity.getId());
  459. DynamicDataSourceUtil.dynamicRoutingDataSource.addDataSource(dbLinkEntity.getId(), dataSource);
  460. } catch (SQLException e) {
  461. for (String s : list) {
  462. try {
  463. DynamicDataSourceUtil.dynamicRoutingDataSource.removeDataSource(s);
  464. } catch (Exception e1) {
  465. e1.printStackTrace();
  466. }
  467. }
  468. throw e;
  469. }
  470. }
  471. }
  472. }
  473. }
  474. }
  475. /**
  476. * 移除当前租户的指定数据源信息
  477. */
  478. public static void removeAllAssignDataSource(){
  479. if(isTenantAssignDataSource()) {
  480. String tenantId = TenantHolder.getDatasourceId();
  481. String dbKey = tenantId + StrPool.DASHED + DdConstants.MASTER;
  482. TenantVO tenantVO = TenantDataSourceUtil.getTenantInfo();
  483. if(tenantVO != null) {
  484. List<TenantLinkModel> linkList = tenantVO.getLinkList();
  485. if (linkList != null) {
  486. // 添加数据源信息到redis中
  487. String mKey = dbKey + StrPool.UNDERLINE;
  488. String sKey = tenantId + StrPool.DASHED + DdConstants.SLAVE + StrPool.UNDERLINE;
  489. for (TenantLinkModel model : linkList) {
  490. DbLinkEntity dbLinkEntity = model.toDbLink(new DbLinkEntity());
  491. String key;
  492. if ("0".equals(String.valueOf(model.getConfigType()))) {
  493. key = mKey + dbLinkEntity.getId();
  494. } else {
  495. key = sKey + dbLinkEntity.getId();
  496. }
  497. try {
  498. DataSource dataSource = DynamicDataSourceUtil.dynamicRoutingDataSource.getDataSources().get(key);
  499. if (dataSource instanceof ItemDataSource && ((ItemDataSource) dataSource).getRealDataSource() instanceof DruidDataSource) {
  500. //Druid数据源如果正在获取数据源 有概率连接创建线程无法停止
  501. ((DruidDataSource) ((ItemDataSource) dataSource).getRealDataSource()).setBreakAfterAcquireFailure(true);
  502. }
  503. DynamicDataSourceUtil.dynamicRoutingDataSource.removeDataSource(key);
  504. } catch (Exception e) {
  505. }
  506. }
  507. }
  508. }else{
  509. log.error("获取缓存租户库列表失败: {}", tenantId);
  510. }
  511. }
  512. }
  513. /**
  514. * 获取租户指定数据源 在连接池中的主库KEY
  515. * @return
  516. */
  517. public static String getTenantAssignDataSourceMasterKeyName(){
  518. if(isTenantAssignDataSource()){
  519. return TenantHolder.getDatasourceId() + StrPool.DASHED +DdConstants.MASTER;
  520. }
  521. return StringUtil.EMPTY;
  522. }
  523. public static boolean isMultiTenancy(){
  524. return configValueUtil.isMultiTenancy();
  525. }
  526. public static boolean isTenantAssignDataSource(){
  527. return isMultiTenancy() && getTenantInfo().isRemote();
  528. }
  529. /**
  530. * 是否开启多租户, 且Column模式
  531. * @return
  532. */
  533. public static boolean isTenantColumn(){
  534. return isMultiTenancy() && getTenantInfo().isColumn();
  535. }
  536. /**
  537. * 是否开启多租户, 且Schema模式
  538. * @return
  539. */
  540. public static boolean isTenantSchema(){
  541. return isMultiTenancy() && getTenantInfo().isSchema();
  542. }
  543. /**
  544. * 将SQL语句添加多租户过滤
  545. * @param sql
  546. * @return
  547. */
  548. public static String parseTenantSql(String sql){
  549. if (isTenantColumn()) {
  550. try {
  551. Statement statement = CCJSqlParserUtil.parse(sql);
  552. if (statement instanceof Select) {
  553. return myTenantLineInnerInterceptor.parserSingle(sql, null);
  554. } else {
  555. return myTenantLineInnerInterceptor.parserMulti(sql, null);
  556. }
  557. } catch(JSQLParserException e){
  558. throw new RuntimeException(e);
  559. }
  560. }else if(isTenantSchema()){
  561. return mySchemaInnerInterceptor.changeTable(sql);
  562. }
  563. return sql;
  564. }
  565. /**
  566. * 官网租户短信验证码专用
  567. * @param mobile 手机号
  568. * @param code 验证码
  569. * @param type 验证类型, 1:登录, 2:重置密码
  570. * @return
  571. */
  572. public static boolean checkOfficialSmsCode(String mobile, String code, int type) throws LoginException {
  573. String url;
  574. switch (type){
  575. case 1:
  576. url = configValueUtil.getMultiTenancyOfficialLoginCodeUrl();
  577. break;
  578. case 2:
  579. url = configValueUtil.getMultiTenancyOfficialResetCodeUrl();
  580. break;
  581. default:
  582. throw new RuntimeException(MsgCode.LOG116.get());
  583. }
  584. JSONObject object = null;
  585. try (HttpResponse execute = HttpRequest.get(String.format("%s%s/%s", url, mobile, code))
  586. .execute()) {
  587. object = JSON.parseObject(execute.body());
  588. }catch (Exception e){
  589. log.error("校验官网短信失败", e);
  590. }
  591. if (object == null || Objects.equals(500, object.getIntValue("code"))) {
  592. throw new LoginException(MsgCode.LOG105.get());
  593. }
  594. if (!Objects.equals(200, object.getIntValue("code"))) {
  595. throw new LoginException(MsgCode.LOG117.get(object.getString("msg")));
  596. }
  597. return true;
  598. }
  599. }