脱离枯燥的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并生成的动态的代理对象。两者使用起来是没有什么差别的。

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

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

如若内容造成侵权/违法违规/事实不符,请联系一条长河网进行投诉反馈,一经查实,立即删除!

相关文章

c++进阶学习-----继承

1.继承的概念及定义 1.1继承的概念 继承(inheritance)机制是面向对象程序设计使代码可以复用的最重要的手段&#xff0c;它允许程序员在保持原有类特性的基础上进行扩展&#xff0c;增加功能&#xff0c;这样产生新的类&#xff0c;称派生类。 继承呈现了面向对象 程序设计的…

006——队列

队列&#xff1a; 一种受限的线性表&#xff08;线性逻辑结构&#xff09;&#xff0c;只允许在一段进行添加操作&#xff0c;在另一端只允许进行删除操作&#xff0c;中间位置不可操作&#xff0c;入队的一端被称为队尾&#xff0c;出队的一端被称为队头&#xff0c;在而我们…

iOS 中 KVC 与 KVO 底层原理

KVC 本质&#xff1a; [object setValue: forKey:];即使没有在.h 文件中有property 的属性声明&#xff0c;setValue:forKey依然会按照上图流程执行代码 KVC 如果成功改变了成员变量&#xff0c;是一定可以被 KVO 监听到成员变量的前后改变的 KVO runtime会生成中间类&…

Leetcode 378. 有序矩阵中第 K 小的元素

1.题目基本信息 1.1.题目描述 给你一个 n x n 矩阵 matrix &#xff0c;其中每行和每列元素均按升序排序&#xff0c;找到矩阵中第 k 小的元素。 请注意&#xff0c;它是 排序后 的第 k 小元素&#xff0c;而不是第 k 个 不同 的元素。 你必须找到一个内存复杂度优于 O(n^2…

GPT1-GPT3论文理解

GPT&#xff11;&#xff0d;GPT&#xff13;论文理解 视频参考&#xff1a;https://www.bilibili.com/video/BV1AF411b7xQ/?spm_id_from333.788&vd_sourcecdb0bc0dda1dccea0b8dc91485ef3e74 1 历史 2017.6 Transformer 2018.6 GPT 2018.10 BERT 2019.2 GPT-2 2020…

ER论文阅读-Decoupled Multimodal Distilling for Emotion Recognition

基本介绍&#xff1a;CVPR, 2023, CCF-A 原文链接&#xff1a;https://openaccess.thecvf.com/content/CVPR2023/papers/Li_Decoupled_Multimodal_Distilling_for_Emotion_Recognition_CVPR_2023_paper.pdf Abstract 多模态情感识别&#xff08;MER&#xff09;旨在通过语言、…

闯关leetcode——67. Add Binary

大纲 题目地址内容 解题代码地址 题目 地址 https://leetcode.com/problems/add-binary/description/ 内容 Given two binary strings a and b, return their sum as a binary string. Example 1: Input: a “11”, b “1” Output: “100” Example 2: Input: a “101…

【LeetCode:116. 填充每个节点的下一个右侧节点指针 + BFS(层次遍历)】

&#x1f680; 算法题 &#x1f680; &#x1f332; 算法刷题专栏 | 面试必备算法 | 面试高频算法 &#x1f340; &#x1f332; 越难的东西,越要努力坚持&#xff0c;因为它具有很高的价值&#xff0c;算法就是这样✨ &#x1f332; 作者简介&#xff1a;硕风和炜&#xff0c;…

MFC - 常用基础控件

前言 各位师傅大家好&#xff0c;我是qmx_07&#xff0c;今天给大家讲解MFC中的基础控件 基础控件 单选按钮 绘图准备: 调整窗口大小&#xff0c;设置 radio button 单选按钮button 按钮 设置单选按钮变量分别为 m_BN1、 m_BN2、m_BN3 void CMFCApplication3Dlg::OnBnC…

【笔记】机器学习算法在异常网络流量监测中的应用

先从一些相对简单的综述类看起&#xff0c;顺便学学怎么写摘要相关工作的&#xff0c;边译边学 机器学习算法在异常网络流量监测中的应用 原文&#xff1a;Detecting Network Anomalies in NetFlow Traffic with Machine Learning Algorithms Authors: Quc Vo, Philippe Ea, Os…

C++入门——类的默认成员函数(构造函数)

文章目录 前言一、构造函数二、栈的构造函数总结 前言 ⼀个类&#xff0c;我们不写的情况下编译器会默认⽣成以下6个默认成员函数 默认成员函数很重要&#xff0c;也⽐较复杂&#xff0c;我们要从两个⽅⾯去学习&#xff1a; 第⼀&#xff1a;我们不写时&#xff0c;编译器默认…

Spring后端直接用枚举类接收参数,自定义通用枚举类反序列化器

在使用枚举类做参数时&#xff0c;一般会让前端传数字&#xff0c;后端将数字转为枚举类&#xff0c;当枚举类很多时&#xff0c;很可能不知道这个code该对应哪个枚举类。能不能后端直接使用枚举类接收参数呢&#xff0c;可以&#xff0c;但是受限。 Spring反序列默认使用的是J…

如何用Shell命令结合 正则表达式 统计文本中的ip地址数量

文章目录 简介问题回答 简介 IP 地址&#xff08;Internet Protocol Address&#xff09;是互联网协议地址的简称&#xff0c;是互联网上为联网的设备&#xff08;如计算机、服务器、路由器、手机等&#xff09;分配的唯一标识符。IP 地址的主要功能是实现不同网络设备之间的通…

[Python]一、Python基础编程(2)

F:\BaiduNetdiskDownload\2023人工智能开发学习路线图\1、人工智能开发入门\1、零基础Python编程 1. 文件操作 把⼀些内容 ( 数据 )存储存放起来,可以让程序下⼀次执⾏的时候直接使⽤,⽽不必重新制作⼀份,省时省⼒ 。 1.1 文件的基本操作 1. 打开文件 2. 读写操作 3. 关闭…

hive-拉链表

目录 拉链表概述缓慢变化维拉链表定义 拉链表的实现常规拉链表历史数据每日新增数据历史数据与新增数据的合并 分区拉链表 拉链表概述 缓慢变化维 通常我们用一张维度表来维护维度信息&#xff0c;比如用户手机号码信息。然而随着时间的变化&#xff0c;某些用户信息会发生改…

【软件工程】需求分析概念

一、定义 二、为什么要进行需求分析&#xff1f; 三、需求分析任务 四、与用户沟通获取需求的方法 五、分析建模 六、软件需求规格说明 例题 选择题

【题解】【枚举,数学】——小 Y 拼木棒

【题解】【枚举&#xff0c;数学】——小 Y 拼木棒 小 Y 拼木棒题目背景题目描述输入格式输出格式输入输出样例输入 #1输出 #1 提示数据规模与约定 1.题意简述2.思路解析3.AC代码 前置知识&#xff1a;排列组合&#xff0c;暴力枚举基础知识。 小 Y 拼木棒 通往洛谷的传送门 …

基于SpringBoot+Vue+MySQL的医院信息管理系统

系统展示 用户前台界面 管理员后台界面 系统背景 在当今社会&#xff0c;随着医疗服务需求的不断增长和医疗信息化的快速发展&#xff0c;提升医院管理效率和服务质量成为了医疗行业的核心需求。传统的医院管理模式面临着效率低下、资源分配不均、患者就医体验差等问题。为了应…

图像处理基础知识点简记

简单记录一下图像处理的基础知识点 一、取样 1、释义 图像的取样就是图像在空间上的离散化处理,即使空间上连续变化的图像离散化, 决定了图像的空间分辨率。 2、过程 简单描述一下图象取样的基本过程,首先用一个网格把待处理的图像覆盖,然后把每一小格上模拟图像的各个…

一种求解无人机三维路径规划的高维多目标优化算法,MATLAB代码

在无人机三维路径规划的研究领域&#xff0c;高维多目标优化算法是一个重要的研究方向。这种算法能够同时考虑多个目标&#xff0c;如航迹距离、威胁代价、能耗代价以及多无人机协同性能等&#xff0c;以实现无人机路径的最优规划。 无人机路径规划算法的研究进展表明&#xf…