MyBatis 另类用法:动态载入 xml 配置,获取渲染好的 SQL 语句。
业务场景:
在制作报表系统的时候,经常会有一个很头疼的事情:
明明只是写一个 SQL 的事情,但是系统各种配置,客户用不明白,时间久了,我们自己忘得差不多;
这时候,我们就会去思考:要不直接开放写 SQL 的权限?
客户想怎么查怎么查,我们不再需要考虑“报表系统怎么做”,将工作重心放到数据权限就好了。
mybatis 是我们常用的工具,我们能不能通过什么手段让它变成动态的?
比如说:客户想增加一个查询,上传一份 xml 配置,我们动态载入。
几个疑问:
前面提出的解决方案肯定是可行的。
你可能会有疑问,xml不是要对应一个 java 类么(Mapper类),客户上传 xml,没有对应的 java 类不会报错嘛?
mybatis 可以只有 xml,java 类的确不是必要的。
xml 没有对应的 java 类的话,怎么调用查询呢?
直接获取 mybatis 渲染好的 SQL,将渲染好的 SQL 直接交给 JDBC 执行。
方案缺陷:
对于同名的 xml,mybatis 只会加载一次,第二次加载不会触发更新;
比如:我们有一份 xml 配置,叫做 test.xml,加载到 Configuration 之后,
我们修改 xml 文件的内容,再加载这一份文件, Configuration 是不会再去读取这个文件的。
或许可以使用 java 反射技术暴力修改,不过我还是推荐重新 new 一个 Configuration 对象,避免产生错误逻辑。
import cn.seaboot.commons.file.IOUtils; import org.apache.ibatis.builder.xml.XMLMapperBuilder; import org.apache.ibatis.mapping.MappedStatement; import org.apache.ibatis.session.Configuration; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.core.io.Resource; import org.springframework.core.io.support.PathMatchingResourcePatternResolver; import org.springframework.core.io.support.ResourcePatternResolver; import java.io.IOException; import java.io.InputStream; /** * mybatis 配置信息读取工具 * <p> * mybatis 不支持动态修改配置,源码上直接做了限制,详见: {@link XMLMapperBuilder#parse()} * 如果期望 mybatis 支持动态修改配置,修改 xml 内容后,new 一个新的 Configuration 即可。 * * @author Mr.css * @version 2023-06-06 16:18 */ public class MyBatisConfiguration { private final Logger logger = LoggerFactory.getLogger(MyBatisConfiguration.class); private Configuration configuration = new Configuration(); /** * 用于加载 xml 配置文件 */ private static final ResourcePatternResolver resourceResolver = new PathMatchingResourcePatternResolver(); /** * 清除所有配置信息 */ public void clean() { configuration = null; configuration = new Configuration(); } /** * 获取 xml中的配置信息 * * @param id sql ID * @return {{@link MappedStatement}} */ public MappedStatement getMappedStatement(String id) { return configuration.getMappedStatement(id); } /** * 获取xml中的配置信息 * * @param id sql ID * @return {{@link MappedStatement}} */ public MappedStatement getMappedStatement(String id, boolean validateIncompleteStatements) { return configuration.getMappedStatement(id, validateIncompleteStatements); } /** * 加载 * * @param locations xml位置信息 * @throws IOException 内容读取失败 */ public void resolve(String... locations) throws IOException { for (String location : locations) { Resource[] resources = this.getResources(location); for (Resource resource : resources) { logger.debug("resolve resource: " + resource.toString()); XMLMapperBuilder xmlMapperBuilder = new XMLMapperBuilder(resource.getInputStream(), configuration, resource.toString(), configuration.getSqlFragments()); xmlMapperBuilder.parse(); } } } /** * 载入配置 * * @param name 资源名称,资源名称相同的情况下,不会覆盖历史配置 * @param is 包含 xml 信息的输入流 */ public void resolve(String name, InputStream is) { logger.debug("resolve resource: " + name); XMLMapperBuilder xmlMapperBuilder = new XMLMapperBuilder(is, configuration, name, configuration.getSqlFragments()); xmlMapperBuilder.parse(); } /** * 载入配置 * * @param name 资源名称,资源名称相同的情况下,不会覆盖历史配置 * @param content xml 字符串内容 */ public void resolve(String name, String content) { this.resolve(name, IOUtils.stringToInputStream(content)); } /** * 获取资源 * * @param location 配置路径 * @return Resource */ private Resource[] getResources(String location) throws IOException { return resourceResolver.getResources(location); } }
/** * @author Mr.css * @version 2021-01-13 17:40 */ public class TestScanner { public static void main(String[] args) throws IOException { MyBatisConfiguration configuration = new MyBatisConfiguration(); configuration.resolve("sys_menu", IOUtils.openFileInputStream("D:\\seaboot\\seaboot\\mybatis-proxy\\src\\main\\resources\\mapper/sys_menu.xml")); MappedStatement statement = configuration.getMappedStatement("cn.seaboot.db.test.dao.MenuDao.selectById"); // 构建参数 Map<String, Object> params = new HashMap<>(); params.put("menuLevel", "3"); params.put("pid", "1"); params.put("path", "2"); // 获取渲染的 SQL BoundSql sql = statement.getBoundSql(params); System.out.println(sql.getSql()); System.out.println(sql.getParameterMappings()); System.out.println(statement.getResultMaps().get(0).getResultMappings()); } }
标签:xml,configuration,String,new,MyBatis,import,动态,public From: https://www.cnblogs.com/chenss15060100790/p/17462396.html