当前位置: 首页 > news >正文

脱离枯燥的CRUD,灵活使用Mybatis,根据mybatis动态的xml片段和接口规范动态生成代理类,轻松应付简单业务场景。

需求

需求是这样的,我们有一个数据服务平台的产品,用户先将数据源信息保存到平台上,一个数据源可以提供多个接口服务,而每个接口服务在数据库中存一个具有mybatis语法的sql片段。这样的话,对于一些简单的业务只需要编写好sql保存到数据库中然后提供一个接口文档就可以实现了。我们只需要对外提供一个http接口,http接口参数是接口服务ID和sql的参数。

保存在数据库中的xml片段大致如下:

select * from student as s left join score as sc on s.sno = sc.sno
<where><if sname != null and sname != ''>s.sname = #{sname}</if>
</where>

思路

从数据库中获取到xml文本片段后,如果手动去解析mybatis的各种标签和其中的OGNL表达式的话,无疑是一件很累人的事情。所以换种思路,既然功能是按照mybatis的规范来做的,那么mybatis有没有现成的API提供给我们使用呢?当然是有的,示例如下:

实现

  1. 先定义一套查询规范,也就是Mapper接口

    
    import java.util.List;
    import java.util.Map;/*** @author m*/
    public interface CommonMapper {/*** 查询列表** @param params* @return*/List<Map<String, Object>> selectList(Map<String, Object> params);/*** 查询单个** @param params* @return*/Map<String, Object> selectOne(Map<String, Object> params);
    }
    
  2. 再定义一套业务规范,也就是Service接口

    
    import java.util.List;
    import java.util.Map;/*** @author m*/
    public interface CommonService {/*** 查询列表** @param sql* @param params* @return*/List<Map<String, Object>> selectList(String sql, Map<String, Object> params);/*** 查询单个** @param params* @return*/Map<String, Object> selectOne(Map<String, Object> params);
    }
  3. 实现业务规范,在这里我们只实现查询列表的功能,其他的也就类似了。这里是没有实现数据源的切换和分页功能的,可以查询一下mybatis怎么切换数据源、PageHelper怎么去适配多数据源下的分页功能。当然也可以在评论区留言或者给我私信的。

    import com.demo.common.mapper.CommonMapper;
    import com.demo.common.service.CommonService;
    import org.apache.ibatis.builder.xml.XMLMapperBuilder;
    import org.apache.ibatis.session.SqlSession;
    import org.apache.ibatis.session.SqlSessionFactory;
    import org.springframework.stereotype.Service;import javax.annotation.Resource;
    import java.io.ByteArrayInputStream;
    import java.io.InputStream;
    import java.nio.charset.StandardCharsets;
    import java.util.Collections;
    import java.util.List;
    import java.util.Map;@Service
    public class CommonServiceImpl implements CommonService {@Resourceprivate SqlSessionFactory sqlSessionFactory;/*** 查询列表** @param params* @return*/@Overridepublic List<Map<String, Object>> selectList(String sql, Map<String, Object> params) {String sqlXml = wrapSql2SelectListXml(sql);InputStream inputStream = new ByteArrayInputStream(sqlXml.getBytes(StandardCharsets.UTF_8));// 手动加载 XML 配置到 MyBatisXMLMapperBuilder xmlMapperBuilder = new XMLMapperBuilder(inputStream, sqlSessionFactory.getConfiguration(), "dynamic-mapper", sqlSessionFactory.getConfiguration().getSqlFragments());xmlMapperBuilder.parse();// 获取 SqlSession 并执行查询try (SqlSession session = sqlSessionFactory.openSession()) {CommonMapper mapper = session.getMapper(CommonMapper.class);return mapper.selectList(params);} catch (Exception e) {e.printStackTrace();}return Collections.emptyList();}/*** 查询单个** @param params* @return*/@Overridepublic Map<String, Object> selectOne(Map<String, Object> params) {// TODO 待实现return Collections.emptyMap();}/*** 将sql封装为一个完整的xml,对应CommonMapper::selectList接口** @param sql* @return*/private String wrapSql2SelectListXml(String sql) {String xml = "<?xml version=\"1.0\" encoding=\"UTF-8\" ?>\n"+ "<!DOCTYPE mapper PUBLIC \"-//mybatis.org//DTD Mapper 3.0//EN\" \"http://mybatis.org/dtd/mybatis-3-mapper.dtd\">"+ "<mapper namespace='com.demo.common.mapper.CommonMapper'>"+ "  <select id='selectList' resultType='java.util.Map'>"+ 		sql+ "  </select>"+ "</mapper>";return xml;}}
  4. 测试,经过测试是OK的。

    
    import com.demo.common.service.CommonService;
    import org.springframework.web.bind.annotation.RequestMapping;
    import org.springframework.web.bind.annotation.RequestParam;
    import org.springframework.web.bind.annotation.RestController;import javax.annotation.Resource;
    import java.util.List;
    import java.util.Map;@RestController
    @RequestMapping("test")
    public class TestController {@Resourceprivate CommonService commonService;@RequestMapping("list")public Object test(@RequestParam Map<String, Object> params) {List<Map<String, Object>> maps = commonService.selectList("SELECT * FROM datagov.dg_alg WHERE alg_id = #{algId}", params);System.out.println(maps);return maps;}
    }

    在这里插入图片描述

总结

通过以上实现,不难发现,以上解决方案无非就是改变了Mybatis生成代理类的时机而已。在平常,Mybatis是通过扫描指定的xml目录和mapper接口,然后在容器启动时生成代理对象。而此时,我们是在方法执行的时候动态获取的xml并生成的动态的代理对象。两者使用起来是没有什么差别的。

当然以上只是平台一部分功能,像参数和结果集的提取,参数的校验,接口的鉴权、精细化控制、限流、负载均衡、熔断、幂等性,数据的分页处理、缓存等,在这里就不一一赘述了。

相关文章:

  • 北京网站建设多少钱?
  • 辽宁网页制作哪家好_网站建设
  • 高端品牌网站建设_汉中网站制作
  • JdbcTemplate常用方法一览AG网页参数绑定与数据寻址实操
  • Qwen2.5 本地部署的实战教程
  • 视频质量评价SimpleVQA
  • 力扣反转链表系列【25. K 个一组翻转链表】——由易到难,一次刷通!!!
  • 时序预测 | Python实现KAN+LSTM时间序列预测
  • elasticsearch实战应用
  • 缓存的思考与总结
  • 《拿下奇怪的前端报错》:nvm不可用报错`GLIBC_2.27‘‘GLIBCXX_3.4.20‘not Found?+ 使用docker构建多个前端项目实践
  • 计算机网络:概述 --- 体系结构
  • ML 系列:机器学习和深度学习的深层次总结(08)—欠拟合、过拟合,正确拟合
  • QT中添加资源文件(一看就会)
  • 开源实时多模态AI聊天机器人Moshi,语音对话延迟低至200毫秒!
  • MySQL面试题——第一篇
  • 信息学奥赛:青少年编程的高光舞台,通向未来科技的敲门砖
  • text2sql(NL2Sql)综述《The Dawn of Natural Language to SQL: Are We Fully Ready?》
  • 【RocksDB】TransactionDB源码分析
  • eclipse(luna)创建web工程
  • JavaScript 奇技淫巧
  • JSONP原理
  • PAT A1050
  • React-flux杂记
  • web标准化(下)
  • 闭包--闭包作用之保存(一)
  • 回流、重绘及其优化
  • 基于Mobx的多页面小程序的全局共享状态管理实践
  • 码农张的Bug人生 - 初来乍到
  • 排序算法之--选择排序
  • 如何优雅的使用vue+Dcloud(Hbuild)开发混合app
  • 新版博客前端前瞻
  • # 学号 2017-2018-20172309 《程序设计与数据结构》实验三报告
  • #define、const、typedef的差别
  • $L^p$ 调和函数恒为零
  • (14)目标检测_SSD训练代码基于pytorch搭建代码
  • (4)事件处理——(6)给.ready()回调函数传递一个参数(Passing an argument to the .ready() callback)...
  • (leetcode学习)236. 二叉树的最近公共祖先
  • (MTK)java文件添加简单接口并配置相应的SELinux avc 权限笔记2
  • (Python第六天)文件处理
  • (pytorch进阶之路)CLIP模型 实现图像多模态检索任务
  • (二十四)Flask之flask-session组件
  • (删)Java线程同步实现一:synchronzied和wait()/notify()
  • (转)C#调用WebService 基础
  • (转)全文检索技术学习(三)——Lucene支持中文分词
  • .bat批处理(五):遍历指定目录下资源文件并更新
  • .MSSQLSERVER 导入导出 命令集--堪称经典,值得借鉴!
  • .NET CORE使用Redis分布式锁续命(续期)问题
  • .NET IoC 容器(三)Autofac
  • .NET 读取 JSON格式的数据
  • .NET/C# 使用反射调用含 ref 或 out 参数的方法
  • .NET下的多线程编程—1-线程机制概述
  • @JSONField或@JsonProperty注解使用
  • [1204 寻找子串位置] 解题报告
  • [AAuto]给百宝箱增加娱乐功能
  • [AIGC] Spring Interceptor 拦截器详解
  • [Asp.net mvc]国际化
  • [C#]winform部署PaddleOCRV3推理模型