通用mybatis执行sql工具系列解决方案lingdu

个人博客

整套逻辑可执行保存到数据库中的sql例如:select * from a where a.name = #{ling.name}
ling.name中的name是由前端传入的参数,经过Lingdu类的动态封装,传入到mapper.xml中的sql字符串中的#{ling.name}就能获取的这个参数了

本文基于开源框架若依配套使用,在这记录可供参考思想,主要是思想参考,结合网上搜集的一些好的想法整的一套可用方案,作为学习参考,若有不合理的地方感谢指正

1. SqlDoorMapper.xml

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
        PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.zero.dimensiondoor.mapper.SqlDoorMapper">

    <!--自定义sql查询    statementType="STATEMENT" 非预编译  -->
    <select id="selectBySql" parameterType="Object" resultType="java.util.LinkedHashMap">
    <![CDATA[
        ${sql}
        ]]>
    </select>

    <!--插入-->
    <insert id="insertBySql" parameterType="Object">
        <![CDATA[
        ${sql}
        ]]>
    </insert>

    <!--修改-->
    <update id="updateBySql" parameterType="Object">
        <![CDATA[
        ${sql}
        ]]>
    </update>

    <!--删除-->
    <delete id="deleteBySql" parameterType="Object">
        <![CDATA[
        ${sql}
        ]]>
    </delete>



</mapper>

2. ZeroMapper

package com.zero.dimensiondoor.mapper;

import org.apache.ibatis.annotations.Param;
import org.springframework.stereotype.Repository;

import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;

/**
 * @ClassName SqlDoorMapper
 * @Description TODO
 * 作者:99013
 * 创建时间:2021年06月07日 19:25:28
 * @Version 1.0
 **/
@Repository
public interface SqlDoorMapper {
	/**
	 * 自定义sql查询
	 * @param sql sql语句
	 * @param ling 传参实体类
	 * @return
	 */
	public List<LinkedHashMap<String, Object>> selectBySql(@Param("sql") String sql, @Param("ling") Object ling);
	/**
	 * 插入
	 * @param sql sql 语句
	 * @param ling 传参实体类
	 * @return int 返回成功条数
	 * <br><br><b>作者: 990130556 <a class=b href="https://blog.csdn.net/lingdu_dou">lingdu</a></b><br>
	 * 创建时间: 2021年12月16日 18:52:52
	 */
	public int insertBySql(@Param("sql") String sql,@Param("ling") Object ling);
	/**
	 * 修改
	 * @param sql sql 语句
	 * @param ling 传参实体类
	 * @return int 返回成功条数
	 * <br><br><b>作者: 990130556 <a class=b href="https://blog.csdn.net/lingdu_dou">lingdu</a></b><br>
	 * 创建时间: 2021年12月16日 18:53:30
	 */
	public int updateBySql(@Param("sql") String sql,@Param("ling") Object ling);
	/**
	 * 删除
	 * @param sql sql 语句
	 * @param ling 传参实体类
	 * @return int 返回成功条数
	 * <br><br><b>作者: 990130556 <a class=b href="https://blog.csdn.net/lingdu_dou">lingdu</a></b><br>
	 * 创建时间: 2021年12月16日 18:54:00
	 */
	public int deleteBySql(@Param("sql") String sql,@Param("ling") Object ling);

}

3. ISqlDoorService

package com.zero.dimensiondoor.service;

/**
 * sql门业务层接口
 * @ClassName ISqlDoorService
 * @Description TODO
 * 作者:99013
 * 创建时间:2021年06月07日 19:31:25
 * @Version 1.0
 **/
public interface ISqlDoorService {

	/**
	 * 执行sql
	 * @param systemDsn 数据源
	 * @param sql sql语句
	 * @param ling 通用实体类
	 * @return java.util.List<java.util.LinkedHashMap<java.lang.String,java.lang.Object>>
	 * <br><br><b>作者: 990130556 <a class=b href="https://blog.csdn.net/lingdu_dou">lingdu</a></b><br>
	 * 创建时间: 2021年08月27日 11:39:33
	 */
	public Object executeTheSql(String type,String systemDsn, String sql, Object ling);

	/**
	 * 默认数据源执行
	 * @param type 请求类型
	 * @param sql sql语句
	 * @param ling 传参实体类
	 * @return java.lang.Object
	 * <br><br><b>作者: 990130556 <a class=b href="https://blog.csdn.net/lingdu_dou">lingdu</a></b><br>
	 * 创建时间: 2021年12月17日 09:45:55
	 */
	public Object executeTheSql(String type,String sql, Object ling);

	/**
	 * 数据中心主数据源执行
	 * @param type 请求类型
	 * @param sql sql语句
	 * @param ling 传参实体类
	 * @return java.lang.Object
	 * <br><br><b>作者: 990130556 <a class=b href="https://blog.csdn.net/lingdu_dou">lingdu</a></b><br>
	 * 创建时间: 2021年12月17日 09:47:10
	 */
	public Object executeTheSqlToMethod(String type, String sql, Object ling);
}

4. Method

package com.zero.dimensiondoor.service.impl;

import com.zero.common.core.lingdu.utils.HttpRequestUtil;
import com.zero.dimensiondoor.mapper.DatareductionMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

/**
 * 公共方法
 * @ClassName Method
 * @Description TODO
 * 作者:99013
 * 创建时间:2021年12月16日 19:42:18
 * @Version 1.0
 **/
@Component
public class Method {

	@Autowired
	protected ZeroMapper zeroMapper;

	// 基于若依微服务版的多数据源注解方式分配衍生的引用各个不同数据源的业务层接口引用
	@Autowired
	protected AServiceImpl aService;
	@Autowired
	protected BServiceImpl bService;
	@Autowired
	protected CServiceImpl cService;
	@Autowired
	protected DServiceImpl dService;
	@Autowired
	protected EServiceImpl eService;
	@Autowired
	protected FServiceImpl fService;

	public Object executeTheSqlByType(String type, String sql, Object ling) {
		switch (type){
			case HttpRequestUtil.GET:
				return zeroMapper.selectBySql(sql,ling);
			case HttpRequestUtil.POST:
				return zeroMapper.insertBySql(sql,ling);
			case HttpRequestUtil.PUT:
				return zeroMapper.updateBySql(sql,ling);
			case HttpRequestUtil.DELETE:
				return zeroMapper.deleteBySql(sql,ling);

			default:
				return "未执行任何语句!";
		}
	}
}

5. SqlDoorServiceImpl

package com.zero.dimensiondoor.service.impl;

import com.github.pagehelper.PageHelper;
import com.zero.common.core.lingdu.utils.HttpRequestUtil;
import com.zero.common.core.utils.sql.SqlUtil;
import com.zero.common.core.web.page.PageDomain;
import com.zero.common.core.web.page.TableSupport;
import com.zero.common.datasource.annotation.DcNameConstants;
import com.zero.common.datasource.annotation.dc.DC_0;
import com.zero.dimensiondoor.service.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;

import java.util.LinkedHashMap;
import java.util.List;

/**
 * @author 99013
 * @ClassName SqlDoorServiceImpl
 * @Description TODO
 * 作者:99013
 * 创建时间:2021年06月07日 19:32:07
 * @Version 1.0
 **/
@Service
public class SqlDoorServiceImpl extends Method implements ISqlDoorService {

	private static final Logger log = LoggerFactory.getLogger(SqlDoorServiceImpl.class);

	/**
	 * 执行sql
	 * @param type 请求类型
	 * @param systemDsn 数据源
	 * @param sql sql语句
	 * @param ling 通用实体类
	 * @return java.util.List<java.util.LinkedHashMap<java.lang.String,java.lang.Object>>
	 * <br><br><b>作者: 990130556 <a class=b href="https://blog.csdn.net/lingdu_dou">lingdu</a></b><br>
	 * 创建时间: 2021年08月27日 10:08:22
	 */
	@Override
//	@Transactional(rollbackFor=Exception.class)
	public Object executeTheSql(String type,String systemDsn, String sql, Object ling) {
		if(type.equals(HttpRequestUtil.GET)&&!systemDsn.equals(DcNameConstants.SQL_SERVER)){
			// 设置分页参数(基于若依微服务版配置定制)
			startPageForSqlDoor();
		}
		switch (systemDsn){
			// A数据源
			case DcNameConstants.A:
				log.info("A数据源 执行sql "+type+"请求");
				return aService.executeTheSql(type,sql,ling);
			// B数据源
			case DcNameConstants.B:
				log.info("B数据源 执行sql "+type+"请求");
				return bService.executeTheSql(type,sql,ling);
			// C数据源
			case DcNameConstants.C:
				log.info("C数据源 执行sql "+type+"请求");
				return cService.executeTheSql(type,sql,ling);
			// D数据源名
			case DcNameConstants.D:
				log.info("D数据源 执行sql "+type+"请求");
				return dService.executeTheSql(type,sql,ling);
			// E数据源名
			case DcNameConstants.E:
				log.info("E数据源 执行sql "+type+"请求");
				return eService.executeTheSql(type,sql,ling);
			// F数据源名
			case DcNameConstants.F:
				log.info("F数据源 执行sql "+type+"请求");
				return fService.executeTheSql(type,sql,ling);
			default:
				log.info("默认主数据源 执行sql "+type+"请求");
				return executeTheSql(type,sql,ling);
		}
	}

	@Override
//	@Transactional(rollbackFor=Exception.class)
	public Object executeTheSql(String type,String sql, Object ling) {
		return super.executeTheSqlByType(type,sql,ling);
	}
	@Override
	@DC_0
//	@Transactional(rollbackFor=Exception.class)
	public Object executeTheSqlToMethod(String type, String sql, Object ling) {
		return super.executeTheSqlByType(type,sql,ling);
	}


	/**
	 * 任意sql模块设置请求分页数据
	 * 经过测试不支持SQL server
	 */
	private void startPageForSqlDoor()
	{
		PageDomain pageDomain = TableSupport.buildPageRequest();
		Integer pageNum = pageDomain.getPageNum();
		Integer pageSize = pageDomain.getPageSize();
		pageSize=pageSize==null?500:pageSize>500?500:pageSize;
		pageNum=pageNum==null?1:pageNum;
		String orderBy = SqlUtil.escapeOrderBySql(pageDomain.getOrderBy());
		Boolean reasonable = pageDomain.getReasonable();
		PageHelper.startPage(pageNum, pageSize, orderBy).setReasonable(reasonable);
	}

}

6. IBaseService

package com.zero.dimensiondoor.service;

/**
 * @ClassName IBaseService
 * @Description TODO
 * 作者:99013
 * 创建时间:2021年10月27日 15:10:37
 * @Version 1.0
 **/
public interface IBaseService {

	/**
	 * 执行sql语句
	 * @param type 请求类型
	 * @param sql sql语句
	 * @param ling 传参实体类
	 * @return java.util.List<java.util.LinkedHashMap<java.lang.String,java.lang.Object>>
	 * <br><br><b>作者: 990130556 <a class=b href="https://blog.csdn.net/lingdu_dou">lingdu</a></b><br>
	 * 创建时间: 2021年10月27日 15:26:27
	 */
	public Object executeTheSql(String type, String sql, Object ling);

}

7. 示例A数据源对应ServiceImpl

package com.zero.dimensiondoor.service.impl;

import com.zero.common.datasource.annotation.dc.DC_A;
import com.zero.dimensiondoor.mapper.DatareductionMapper;
import com.zero.dimensiondoor.service.IBaseService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

/**
 * 数据中心核心数据源业务层实现类
 * @ClassName SjzxSysServiceImpl
 * @Description TODO
 * 作者:99013
 * 创建时间:2021年10月27日 10:21:47
 * @Version 1.0
 **/
@Service
@DC_A
public class SjzxSysServiceImpl extends Method implements IBaseService {

	@Override
	public Object executeTheSql(String type, String sql, Object ling) {
		return super.executeTheSqlByType(type,sql,ling);
	}
}

8. SqlDoorController

package com.zero.dimensiondoor.controller;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.zero.common.core.constant.Constants;
import com.zero.common.core.constant.HttpStatus;
import com.zero.common.core.domain.R;
import com.zero.common.core.lingdu.domain.SysVirtualInterface;
import com.zero.common.core.lingdu.utils.HttpRequestUtil;
import com.zero.common.core.utils.ServletUtils;
import com.zero.common.core.utils.StringUtils;
import com.zero.common.core.web.controller.BaseController;
import com.zero.common.log.annotation.Log;
import com.zero.common.log.enums.BusinessType;
import com.zero.common.log.service.AsyncLogService;
import com.zero.common.redis.service.RedisService;
import com.zero.common.security.annotation.RequiresPermissions;
import com.zero.common.security.annotation.RequiresRoles;
import com.zero.common.security.aspect.PreAuthorizeAspect;
import com.zero.common.security.auth.AuthLogic;
import com.zero.common.security.auth.AuthUtil;
import com.zero.dimensiondoor.service.ISqlDoorService;
import com.zero.dimensiondoor.utils.BeanInvokeUtil;
import com.zero.dimensiondoor.utils.Lingdu;
import com.zero.system.api.RemoteSysApiRepositoryService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;

import java.util.*;

/**
 * sql任意门执行控制器层
 * 所有调用本模块的请求理论上都走该控制器
 * 执行sql语句
 *
 * @author 99013
 * @ClassName SqlDoorController
 * @Description TODO
 * 作者:99013
 * 创建时间:2021年06月21日 18:47:16
 * @Version 1.0
 **/
@RestController
@RequestMapping("/*/sqlDoor")
@Api(value = "任意sql执行接口", tags = "任意sql执行接口")
public class SqlDoorController extends BaseController {
	/**
	 * [基于若依微服务版兼容]
	 * 远程调用 系统核心模块的接口[system]
	 */
	private final RemoteSysApiRepositoryService remoteSysApiRepositoryService;
	/**
	 * sql门业务层接口
	 */
	private final ISqlDoorService sqlDoorService;
	/**
	 * [基于若依微服务版兼容]
	 * 自定义动态权限
	 */
	private final PreAuthorizeAspect preAuthorizeAspect;
	/**
	 * [基于若依微服务版兼容]
	 * 虚拟接口缓存配置
	 */
	private final RedisService redisService;
	/**
	 * [基于若依微服务版兼容]
	 * 异步日志
	 */
	@Autowired
	private AsyncLogService asyncLogService;

	/**
	 * 过期时间 天
	 */
	public final static long EXPIRE_TIME = 30;

	public SqlDoorController(RemoteSysApiRepositoryService remoteSysApiRepositoryService, ISqlDoorService sqlDoorService, PreAuthorizeAspect preAuthorizeAspect, RedisService redisService) {
		this.remoteSysApiRepositoryService = remoteSysApiRepositoryService;
		this.sqlDoorService = sqlDoorService;
		this.preAuthorizeAspect = preAuthorizeAspect;
		this.redisService = redisService;
	}

	/**
	 * 任意sql门 执行	POST
	 *
	 * @param key 虚拟接口唯一标识
	 * @return com.zero.common.core.domain.R<?>
	 * <br><br><b>作者: 990130556 <a class=b href="https://blog.csdn.net/lingdu_dou">lingdu</a></b><br>
	 * 创建时间: 2021年06月21日 19:04:59
	 */
	@PostMapping("invoke/{virtualInterfaceKey}")
	@RequiresRoles("dba")
	@ApiOperation(value = "任意sql门", notes = "可执行任意sql")
	@Log(title = "sql门执行POST请求 form-data传参", businessType = BusinessType.INSERT)
	public R<?> invokePost(@PathVariable("virtualInterfaceKey") String key) {
		return invoke(HttpRequestUtil.POST, key);
	}

	/**
	 * feign调用
	 */
	@PostMapping("invokeFeign/{virtualInterfaceKey}")
	@RequiresPermissions("dimensiondoor:sqlDoor:invokePostFeign")// 权限字符串防止非法访问
	@ApiOperation(value = "任意sql门 feign请求", notes = "可执行任意sql")
	@Log(title = "sql门执行POST请求 json传参[feign请求]", businessType = BusinessType.INSERT)
	public R<Object> invokePostFeign(@PathVariable("virtualInterfaceKey") String key, @RequestBody(required = false) String json) {
		return invoke(true, HttpRequestUtil.POST, key, json);
	}

	/**
	 * json方式传参
	 */
	@PostMapping("invoke/{virtualInterfaceKey}/json")
	@RequiresRoles("dba")
	@ApiOperation(value = "任意sql门", notes = "可执行任意sql")
	@Log(title = "sql门执行POST请求 json传参", businessType = BusinessType.INSERT)
	public R<?> invokePostJson(@PathVariable("virtualInterfaceKey") String key, @RequestBody(required = false) String json) {
		return invoke(HttpRequestUtil.POST, key, json);
	}


	/**
	 * 任意sql门 执行	PUT
	 *
	 * @param key 虚拟接口唯一标识
	 * @return com.zero.common.core.domain.R<?>
	 * <br><br><b>作者: 990130556 <a class=b href="https://blog.csdn.net/lingdu_dou">lingdu</a></b><br>
	 * 创建时间: 2021年06月21日 19:04:59
	 */
	@PutMapping("invoke/{virtualInterfaceKey}")
	@RequiresRoles("dba")
	@ApiOperation(value = "任意sql门", notes = "可执行任意sql")
	@Log(title = "sql门执行PUT请求", businessType = BusinessType.UPDATE)
	public R<?> invokePut(@PathVariable("virtualInterfaceKey") String key) {
		return invoke(HttpRequestUtil.PUT, key);
	}

	@PutMapping("invokeFeign/{virtualInterfaceKey}")
	@RequiresPermissions("dimensiondoor:sqlDoor:invokePutFeign")// 权限字符串防止非法访问
	@ApiOperation(value = "任意sql门 feign调用", notes = "可执行任意sql")
	@Log(title = "sql门执行PUT请求 feign调用", businessType = BusinessType.UPDATE)
	public R<?> invokePutFeign(@PathVariable("virtualInterfaceKey") String key, @RequestBody(required = false) String json) {
		return invoke(HttpRequestUtil.PUT, key, json);
	}

	/**
	 * json方式传参
	 */
	@PutMapping("invoke/{virtualInterfaceKey}/json")
	@RequiresRoles("dba")
	@ApiOperation(value = "任意sql门", notes = "可执行任意sql")
	@Log(title = "sql门执行PUT请求 json传参", businessType = BusinessType.UPDATE)
	public R<?> invokePutJson(@PathVariable("virtualInterfaceKey") String key, @RequestBody() String json) {
		return invoke(HttpRequestUtil.PUT, key, json);
	}

	/**
	 * 任意sql门 执行	GET
	 *
	 * @param key 虚拟接口唯一标识
	 * @return com.zero.common.core.domain.R<?>
	 * <br><br><b>作者: 990130556 <a class=b href="https://blog.csdn.net/lingdu_dou">lingdu</a></b><br>
	 * 创建时间: 2021年06月21日 19:04:59
	 */
	@GetMapping("invoke/{virtualInterfaceKey}")
	@RequiresRoles("dba")
	@ApiOperation(value = "任意sql门", notes = "可执行任意sql")
	@Log(title = "sql门执行GET请求", businessType = BusinessType.SELECT)
	public R<?> invokeGet(@PathVariable("virtualInterfaceKey") String key, Integer pageNum, Integer pageSize) {
		return invoke(HttpRequestUtil.GET, key);
	}

	/**
	 * feign请求任意sql门 执行	GET
	 *
	 * @param key 虚拟接口唯一标识
	 * @return com.zero.common.core.domain.R<?>
	 * <br><br><b>作者: 990130556 <a class=b href="https://blog.csdn.net/lingdu_dou">lingdu</a></b><br>
	 * 创建时间: 2021年06月21日 19:04:59
	 */
	@GetMapping("invokeFeign/{virtualInterfaceKey}")
	@RequiresPermissions("dimensiondoor:sqlDoor:invokeGetFeign")// 权限字符串防止非法访问
	@ApiOperation(value = "任意sql门", notes = "可执行任意sql")
	@Log(title = "sql门执行GET请求[feign请求]", businessType = BusinessType.SELECT)
	public R<Object> invokeGetFeign(@PathVariable("virtualInterfaceKey") String key, @PathVariable(value = "json", required = false) String json) {
		return invoke(true, HttpRequestUtil.GET, key, json);
	}

	/**
	 * 任意sql门 执行	DELETE
	 *
	 * @param key 虚拟接口唯一标识
	 * @return com.zero.common.core.domain.R<?>
	 * <br><br><b>作者: 990130556 <a class=b href="https://blog.csdn.net/lingdu_dou">lingdu</a></b><br>
	 * 创建时间: 2021年06月21日 19:04:59
	 */
	@DeleteMapping("invoke/{virtualInterfaceKey}")
	@RequiresRoles("dba")
	@ApiOperation(value = "任意sql门", notes = "可执行任意sql")
	@Log(title = "sql门执行DELETE请求", businessType = BusinessType.DELETE)
	public R<?> invokeDelete(@PathVariable("virtualInterfaceKey") String key) {
		return invoke(HttpRequestUtil.DELETE, key);
	}

	@DeleteMapping("invokeFeign/{virtualInterfaceKey}")
	@RequiresPermissions("dimensiondoor:sqlDoor:invokeDeleteFeign")// 权限字符串防止非法访问
	@ApiOperation(value = "任意sql门[feign请求]", notes = "可执行任意sql")
	@Log(title = "sql门执行DELETE请求 [feign请求]", businessType = BusinessType.DELETE)
	public R<?> invokeDeleteFeign(@PathVariable("virtualInterfaceKey") String key, @PathVariable(value = "json", required = false) String json) {
		return invoke(HttpRequestUtil.DELETE, key, json);
	}


	/**
	 * 非json传参方式统一调用
	 */
	private R<?> invoke(String type, String virtualInterfaceKey) {
		return invoke(false, type, virtualInterfaceKey, null);
	}

	/**
	 * json传参方式统一调用
	 */
	private R<?> invoke(String type, String virtualInterfaceKey, String json) {
		return invoke(false, type, virtualInterfaceKey, json);
	}

	/**
	 * feign调用
	 */
	private R<?> invoke(Boolean isFeign, String type, String virtualInterfaceKey) {
		return invoke(isFeign, type, virtualInterfaceKey, null);
	}

	/**
	 * 获取虚拟接口信息
	 *
	 * @param isFeign             是否feign调用
	 * @param type                请求类型
	 * @param virtualInterfaceKey 虚拟接口唯一标识
	 * @param json                json字符串
	 * @return com.zero.common.dimensiondoor.lingdu.datareduction.domain.SysVirtualInterface
	 * <br><br><b>作者: 990130556 <a class=b href="https://blog.csdn.net/lingdu_dou">lingdu</a></b><br>
	 * 创建时间: 2021年06月24日 11:48:12
	 */
	private R<Object> invoke(Boolean isFeign, String type, String virtualInterfaceKey, String json) {

		// 先尝试从redis获取
		SysVirtualInterface svi = redisService.getCacheObject(Constants.SYS_VIRTUAL_INTERFACE_REDIS_KEY + virtualInterfaceKey);
		// redis中没获取到
		if (svi == null) {
			// 再尝试从数据库获取
			svi = remoteSysApiRepositoryService.selectSysVirtualInterfaceByVirtualInterfaceKey(virtualInterfaceKey).getData();
			// 如果从数据库获取到数据则存入redis
			if (svi != null) {
//				redisService.setCacheObject(Constants.SYS_VIRTUAL_INTERFACE_REDIS_KEY + virtualInterfaceKey, svi, EXPIRE_TIME, TimeUnit.DAYS);
				// 不设置时间则永久有效
				redisService.setCacheObject(Constants.SYS_VIRTUAL_INTERFACE_REDIS_KEY + virtualInterfaceKey, svi);
			}
		}
		// 如果没获取到任何数据
		if (null == svi) {
			return R.fail(HttpStatus.NOT_FOUND, "接口不存在");
		}
		String requestType = svi.getRequestType();
		// 非feign调用
		if (!isFeign) {
			// 权限认证[基于若依微服务版兼容]
			AuthUtil.authLogic.checkPermiAnd(svi.getPerms());
		}
		//判断接口请求方式是否一致 转大写↓
		if (!requestType.toUpperCase().contains(type)) {
			return R.fail(HttpStatus.BAD_METHOD, "只允许" + requestType + "请求!");
		}
		String sqlValue = svi.getSqlValue();

		// 接口参数集合 直接拿可能会出现被锁住不能修改的情况 所以new一下
		Map<String, String[]> parameterMap = new HashMap<>(Objects.requireNonNull(ServletUtils.getRequest()).getParameterMap());
		// 设置json方式传参内容到集合 优先设置
		if (StringUtils.isNotEmpty(json)) {
			setJsonParameters(json, parameterMap);
		}
		// 设置系统内置方法参数 优先级最低[基于若依微服务版兼容]
		settingBuiltInParameters(svi, parameterMap);
		// 参数实体化
		Object ling = Lingdu.virtualEntityEncapsulation("990130556@qq.com", parameterMap);

		// 查询请求 走分页
		if (type.equals(HttpRequestUtil.GET)) {
			return R.ok(getDataTable((List<?>) sqlDoorService.executeTheSql(type, svi.getSystemDsn(), sqlValue, ling)), "获取成功");
		} else {
			return R.ok(sqlDoorService.executeTheSql(type, svi.getSystemDsn(), sqlValue, ling), "操作成功");
		}
	}

	/**
	 * 设置json传参方式的参数到集合
	 *
	 * @param json         json字符串
	 * @param parameterMap 参数集
	 *                     <br><br><b>作者: 990130556 <a class=b href="https://blog.csdn.net/lingdu_dou">lingdu</a></b><br>
	 *                     创建时间: 2021年12月17日 15:59:11
	 */
	private void setJsonParameters(String json, Map<String, String[]> parameterMap) {
		JSONObject jsonObject = JSON.parseObject(json);
		Map<String, Object> innerMap = jsonObject.getInnerMap();
		Set<String> set = innerMap.keySet();
		Object o;
		for (String s : set) {
			o = innerMap.get(s);
			o = o == null ? "" : o.toString();
			parameterMap.put(s, new String[]{o.toString()});
		}
	}


	/**
	 * [基于若依微服务版兼容]
	 * 设置系统内置方法参数
	 *
	 * @param svi          虚拟接口信息
	 * @param parameterMap 参数集
	 *                     <br><br><b>作者: 990130556 <a class=b href="https://blog.csdn.net/lingdu_dou">lingdu</a></b><br>
	 *                     创建时间: 2021年12月16日 09:22:26
	 */
	private void settingBuiltInParameters(SysVirtualInterface svi, Map<String, String[]> parameterMap) {
		// 设置系统内置方法参数
		if (StringUtils.isNotEmpty(svi.getParameterName()) && StringUtils.isNotEmpty(svi.getParameterMethodsThePath())) {
			// 内置 系统参数 名
			String[] parameterNames = svi.getParameterName().replaceAll("\\s", "").split(";");
			// 内置系统参数 获取方法全路径
			String[] parameterMethodsThePaths = svi.getParameterMethodsThePath().replaceAll("\\s", "").split(";");
			if (StringUtils.isNotEmpty(parameterNames) && StringUtils.isNotEmpty(parameterMethodsThePaths)) {
				for (int i = 0; i < parameterNames.length; i++) {

					// 先尝试从前端获取该参数
					String[] strings = parameterMap.get(parameterNames[i]);
					// 如果前端没传有效值
					if (strings == null || strings.length == 0 || StringUtils.isEmpty(strings[0])) {
						try {
							Object o = BeanInvokeUtil.invokeMethod(parameterMethodsThePaths[i]);
							if (null == o) {
								o = "";
							}
							// 补充内置参数
							parameterMap.put(parameterNames[i], new String[]{o.toString()});
						} catch (Exception e) {
							e.printStackTrace();
						}
					}
				}
			}
		}
	}


}

9.其他相关类:

1.将接口的核心敏感信息存储在数据库 表字段实体类SysVirtualInterface

package com.zero.common.core.lingdu.domain;

import com.zero.common.core.annotation.Excel;
import com.zero.common.core.web.domain.BaseEntity;
import org.apache.commons.lang3.builder.ToStringBuilder;
import org.apache.commons.lang3.builder.ToStringStyle;
import org.apache.commons.text.StringEscapeUtils;

import java.util.List;

/**
 * 虚拟接口对象 sys_virtual_interface
 *
 * @author lingdu
 * @date 2021-06-23
 */
public class SysVirtualInterface extends BaseEntity{
    private static final long serialVersionUID = 1L;

    /**历史表主键*/
    private Long id;

    /** 虚拟接口主键 */
    private Long virtualInterfaceId;

    /** 虚拟接口唯一标识 */
    @Excel(name = "虚拟接口唯一标识")
    private String virtualInterfaceKey;

    /** 虚拟接口名 */
    @Excel(name = "虚拟接口名")
    private String virtualInterfaceName;

    /** 权限标识 */
    @Excel(name = "权限标识")
    private String perms;

    /** 所属系统模块 */
    @Excel(name = "所属系统模块")
    private String belongToTheSystem;

    /** 系统数据源 */
    @Excel(name = "系统数据源")
    private String systemDsn;

    /** 虚拟接口请求地址 */
    @Excel(name = "虚拟接口请求地址")
    private String path;

    /** sql内容 */
    @Excel(name = "sql内容")
    private String sqlValue;

    /** 虚拟接口请求方式 */
    @Excel(name = "虚拟接口请求方式")
    private String requestType;

    /** 删除标志(0代表存在 2代表删除) */
    private String delFlag;

    /**内置系统参数 名*/
    private String parameterName;
    /**内置系统参数 获取方法全路径.例: 1.类路径方法:com.lingdu.Ling.test("lingdu",123) 或2.Bean类路径方法:lingService.selectList()*/
    private String parameterMethodsThePath;

    /** 接口参数信息 */
    private List<SysApiParameter> sysApiParameterList;

    public Long getId() {
        return id;
    }

    public void setId(Long id) {
        this.id = id;
    }

    public void setVirtualInterfaceId(Long virtualInterfaceId)
    {
        this.virtualInterfaceId = virtualInterfaceId;
    }

    public Long getVirtualInterfaceId()
    {
        return virtualInterfaceId;
    }
    public void setVirtualInterfaceKey(String virtualInterfaceKey)
    {
        this.virtualInterfaceKey = virtualInterfaceKey;
    }

    public String getVirtualInterfaceKey()
    {
        return virtualInterfaceKey;
    }
    public void setVirtualInterfaceName(String virtualInterfaceName)
    {
        this.virtualInterfaceName = virtualInterfaceName;
    }

    public String getVirtualInterfaceName()
    {
        return virtualInterfaceName;
    }
    public void setPerms(String perms)
    {
        this.perms = perms;
    }

    public String getPerms()
    {
        return perms;
    }
    public void setBelongToTheSystem(String belongToTheSystem)
    {
        this.belongToTheSystem = belongToTheSystem;
    }

    public String getBelongToTheSystem()
    {
        return belongToTheSystem;
    }
    public void setSystemDsn(String systemDsn)
    {
        this.systemDsn = systemDsn;
    }

    public String getSystemDsn()
    {
        return systemDsn;
    }
    public void setPath(String path)
    {
        this.path = path;
    }

    public String getPath()
    {
        return path;
    }
    public void setSqlValue(String sqlValue)
    {
        if(sqlValue!=null){
//            sqlValue = sqlValue.replace("&lt;","<");
//            sqlValue = sqlValue.replace("&gt;",">");
            sqlValue = sqlValue.replace("&nbsp;"," ");
//            this.sqlValue = sqlValue;
            // 若开启了防止XSS攻击则必须转义↓
            this.sqlValue = StringEscapeUtils.unescapeHtml4(sqlValue);
        }

    }

    public String getSqlValue()
    {
//        return StringEscapeUtils.escapeHtml4(sqlValue);
        return sqlValue;
    }
    public void setRequestType(String requestType)
    {
        this.requestType = requestType;
    }

    public String getRequestType()
    {
        return requestType;
    }
    public void setDelFlag(String delFlag)
    {
        this.delFlag = delFlag;
    }

    public String getDelFlag()
    {
        return delFlag;
    }

    public String getParameterName() {
        return parameterName;
    }

    public void setParameterName(String parameterName) {
        this.parameterName = parameterName;
    }

    public String getParameterMethodsThePath() {
        return parameterMethodsThePath;
    }

    public void setParameterMethodsThePath(String parameterMethodsThePath) {
        this.parameterMethodsThePath = parameterMethodsThePath;
    }

    public List<SysApiParameter> getSysApiParameterList()
    {
        return sysApiParameterList;
    }

    public void setSysApiParameterList(List<SysApiParameter> sysApiParameterList)
    {
        this.sysApiParameterList = sysApiParameterList;
    }

    @Override
    public String toString() {
        return new ToStringBuilder(this,ToStringStyle.MULTI_LINE_STYLE)
            .append("id", getId())
            .append("virtualInterfaceId", getVirtualInterfaceId())
            .append("virtualInterfaceKey", getVirtualInterfaceKey())
            .append("virtualInterfaceName", getVirtualInterfaceName())
            .append("perms", getPerms())
            .append("belongToTheSystem", getBelongToTheSystem())
            .append("systemDsn", getSystemDsn())
            .append("path", getPath())
            .append("sqlValue", getSqlValue())
            .append("requestType", getRequestType())
            .append("delFlag", getDelFlag())
            .append("createBy", getCreateBy())
            .append("createTime", getCreateTime())
            .append("updateBy", getUpdateBy())
            .append("updateTime", getUpdateTime())
            .append("remark", getRemark())
            .append("parameterName", getParameterName())
            .append("parameterMethodsThePath", getParameterMethodsThePath())
            .append("sysApiParameterList", getSysApiParameterList())
            .toString();
    }
}

2. 封装虚拟实体用于前端传参封装的工具类 Lingdu

整套逻辑可执行保存到数据库中的sql例如:select * from a where a.name = #{ling.name}
ling.name中的name是由前端传入的参数,经过Lingdu类的动态封装,传入到mapper.xml中的sql字符串中的#{ling.name}就能获取的这个参数了

本文基于开源框架若依配套使用,在这记录可供参考思想,主要是思想参考,结合网上搜集的一些好的想法整的一套可用方案,作为学习参考,若有不合理的地方感谢指正

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

零〇°豆

今天快乐

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值