一个"脱裤子放屁"的功能!

哩语
“脱了裤子放屁”,此话通常用来讥讽别人说话做事画蛇添足、多此一举。

1.背景

故事是这样的.公司的其他部门经常会要求我们部门以接口形式提供一些数据,这种突然的,毫无规划的,杂乱的需求很多.但是好在通过sql都可以完成查询,但是通过接口的形式就需要开发.
针对上面的情况,每次都需要开发功能(mybatis),然后测试上线,流程很长,对业务支撑也不好.
于是,我想到一个"脱裤子放屁"的功能(因为使用现有模式可以实现功能).我能不能开发一个"系统",在业务部门提出需求的时候,可以快速的通过sql,把数据以接口的形式返回呢?
答案当然是能,说着说着,我把功能实现了.至于是不是脱裤子放屁,已经不重要了,大不了不用.

2.问题

需要解决的问题:
1.通过接口形式提供数据,要控制好入参和出参.
2.入参的统一格式控制
3.出参的统一格式返回
4.内部的业务逻辑实现.
4.1需要实现sql可配置,因为接口的数据是根据录入的接口来返回的.

3.实现

1.一个web页面,完成数据源和sql的 crud;网上有很多现成的后台管理框架,我使用若依.
2.一个接口程序,根据传入的参数,到数据库中查询对应的数据源与sql完成查询,并返回结果集;

1.数据源信息管理

2.sql管理


在sql管理页面,记录2个值,后面我们会用到.
1.数据源id
2.接口名称

3.接口应用程序

4.实现思路

当访问接口被访问的时候,接口程序,会根据传入的数据源id和接口名称,到数据库中(之前在后台管理程序中添加的)查找对应的数据源id与接口名称.并且在指定的数据源中运行sql名称对应的sql脚本,并且把结果返回.

5.核心代码

5.1http请求入口

    /***  公用查询方法2* @param db    选择的db,根据输入的值来判断使用那个数据源* @param sqlName 选择执行的sql* @param paramStr 查询参数* @return 返回json数据*/@RequestMapping(value={"/commonv2_2/interface/{db}/{sqlName}/{paramStr}","/xxxx_2/xxxxx/{db}/{sqlName}/{paramStr}"}, method = {RequestMethod.POST,RequestMethod.GET})public Object commonInterfaceV2(@PathVariable String db,@PathVariable String sqlName,@PathVariable String paramStr) {return commonQueryv2(db, sqlName, paramStr);}

5.2接口程序,根据数据源和sql完成sql的执行

private Map<String, Object> commonQueryv2(String db, String sqlName, String paramStr) {Map<String, Object> resultMap = new HashMap<>();List<CommonInterfaceEntity> commonInterfaceEntities = commonService.getSqlByName(db,sqlName);if (commonInterfaceEntities.isEmpty()){resultMap.put("code", ResultCode.APIKEY_INVALID);resultMap.put("message",ResultCode.APIKEY_INVALID.msg());resultMap.put("data",new ArrayList<Map<String, Object>>());return resultMap;}CommonInterfaceEntity commonInterfaceEntity = commonInterfaceEntities.get(0);NamedParameterJdbcTemplate namedParameterJdbcTemplate = null;//判断数据库是否存在Optional dataSource = Optional.ofNullable(Constants.DATASOURCE_MAP.get(commonInterfaceEntity.getAliasName()));if (!dataSource.isPresent()){//创建数据源namedParameterJdbcTemplate = sqlUtils.getDataSource(commonInterfaceEntity);}else{namedParameterJdbcTemplate = (NamedParameterJdbcTemplate)(Constants.DATASOURCE_MAP.get(commonInterfaceEntity.getAliasName()));}//封装注释try {String document = commonInterfaceEntity.getSqlDocument();if (null != document) {resultMap.put("INAME", sqlName);        //请求的接口名称String[] documentList = document.trim().split("\\|");for (String d : documentList){String[] documents = d.trim().split("=");resultMap.put(documents[0], documents[1]);}}else{log.warn("接口={},没有注释,请完善!",sqlName);}} catch (Exception e) {e.printStackTrace();log.error("解析注解异常"+sqlName,e);}List<Map<String, Object>> resultList = new ArrayList<Map<String, Object>>();//sql注入验证;if (sqlInj(paramStr.toLowerCase())){resultMap.put("code", ResultCode.DATA_FORMAT_ISVALID);resultMap.put("message",ResultCode.DATA_FORMAT_ISVALID.msg());resultMap.put("data",resultList);return resultMap;}String[] paramsList1 = paramStr.split("&");Map<String,Object> paramsMap = new HashMap<>();String sql = commonInterfaceEntity.getSqlContent();try {for (String param : paramsList1) {String[] params2 = param.split("=");/*** 对参数转换,* 如果是 l_ 开头的,转换成long 类型* 如果是 i_ 开头的,转换成int 类型* 如果是 s_ 开头的,转换成string 类型* 其他没有标记的,默认转换成string类型*/if (params2[0].startsWith("l_")){paramsMap.put(params2[0],Long.parseLong(params2[1]));}else if (params2[0].startsWith("i_")) {paramsMap.put(params2[0],Integer.parseInt(params2[1]));}else if (params2[0].startsWith("s_")) {paramsMap.put(params2[0],params2[1]);}else{paramsMap.put(params2[0],params2[1]);}//进行字符串替换sql = sql.replaceAll(String.format("\\$\\{%s}",params2[0]),params2[1]);     //字符串拼接sql = sql.replaceAll(String.format("\\#\\{%s}",params2[0]),":"+params2[0]); //参数拼接}} catch (Exception e) {e.printStackTrace();log.error(e.getMessage(),e);resultMap.put("code", ResultCode.PARAMS_INVALID);resultMap.put("message","参数无效或参数格式不正确");resultMap.put("data",resultList);return resultMap;}try {resultList = namedParameterJdbcTemplate.queryForList(sql,paramsMap);if(resultList.isEmpty()){resultMap.put("code", ResultCode.DATA_IS_NULL.val());resultMap.put("message", ResultCode.DATA_IS_NULL.msg());}else{resultMap.put("code", ResultCode.SUCCESS.val());resultMap.put("message",ResultCode.SUCCESS.msg());}resultMap.put("data",resultList);} catch (Exception e) {e.printStackTrace();log.error(e.getMessage(),e);resultMap.put("code",ResultCode.DATABASE_OPER_ERROR);resultMap.put("message","服务器内部错误,查询结果异常");resultMap.put("data",resultList);}return resultMap;}

5.3根据db和接口名,查询数据库中对应的数据源与需要执行的sql

/*** 通过db和接口名,查询数据库中对应的数据源与需要执行的sql* @param dbAliasName* @param sqlName* @return 接口对象*/
@Overridepublic List<CommonInterfaceEntity> getSqlByName(String dbAliasName, String sqlName) {//通过dbAliasName 初始化数据源String sql = "    select *\n" +"    from ci_data_source\n" +"             inner join ci_sql_properties on ci_data_source.id = ci_sql_properties.data_source_id\n" +"    where ci_data_source.alias_name = :alias_name\n" +"      and ci_sql_properties.sql_name = :sql_name\n" +"      and ci_data_source.is_effective = :is_effective\n" +"      and ci_sql_properties.is_effective = :is_effective;";NamedParameterJdbcTemplate namedParameterJdbcTemplateMaster = new NamedParameterJdbcTemplate(jdbcTemplate_master.getDataSource());Map<String,Object> params = new HashMap<>();params.put("alias_name",dbAliasName);params.put("sql_name",sqlName);params.put("is_effective",1);List<CommonInterfaceEntity> commonInterfaceEntities = new ArrayList<>();try {commonInterfaceEntities = namedParameterJdbcTemplateMaster.query(sql.replaceAll("[\r\n]", " "),params,new BeanPropertyRowMapper<CommonInterfaceEntity>(CommonInterfaceEntity.class));} catch (DataAccessException e) {e.printStackTrace();}return commonInterfaceEntities;}

6.使用体验

代码实现了,也运行了几年了.发现确实可以解决一些问题,尤其是一些在会议上的"遭遇战",响应及时,配置灵活.而且因为都是"简单sql"完成的,可以保证接口的性能,同时好扩展.

7.后续

在使用程序的这段时间,发现一个很严重的问题,就是要控制好需求的边界,要知道哪些东西可以做,哪些东西不可以做,不能无休止的无边界.现在这个功能实现起来,发现越来越像mybatis了.如果不及时控制,我恐怕要实现一个新的mybatis了.
我的例子:本来代码第一版实现,只是通过xml配置的方式来完成对sql的管理,但是业务部门抱怨,每次修改代码,都需要找运维到服务器上修改配置,还是不够灵活,然后我就实现了通过数据库来管理sql的版本.

8.后续的问题

1. 对可变参数的查询条件支持不好 – mybatis支持,抗住,不改.
2. 对系统的验证功能不够强大 – 接口现在只支持查询,同时只支持nginx代理的方式访问,可以在nginx上做一些验证,例如jwt.
3. 接口大部分都是原子性的,但是调用方总是希望通过一个接口来获取到所有的数据,这就出现了一个问题.
3.1 针对这种情况,是通过一个接口来满足调用方呢?(一个大而全的接口,多个表的联合查询,判断等等).
3.2 让调用方,通过调用多次接口来完成数据的获取呢?
3.3 我接着"脱裤子放屁",再做一个所谓的"二级接口",通过调用多次原子接口来把数据组合好,再返回给调用方.就是我来完成调用方的需求?

9.代码下载

https://download.csdn.net/download/taotao6086/86568163?spm=1001.2014.3001.5503

具体使用方法,详见附件中readme.md

一个“脱裤子放屁“的功能!相关推荐

  1. 一个夭折 脱裤子放屁的QSql Sqlite操作类

    本来想自己封装一下Sqlite操作类   写到一半才发现是脱裤子放屁       多此一举了 自己写的东西还没有Qt用起来简洁      唯一的好处估计就是能在整个工程里对同一个数据库进行操作     ...

  2. 设计模式是不是一件脱裤子放屁的事

    我这条老程序狗也曾有年轻的时候,当年毛色鲜亮,油光水滑,60级经验已满,正准备升级转职.跟职业训练师聊过后接受任务:学习名字很屌的专家级技能书<Head First Design Pattern ...

  3. 脱裤子放屁之用两个栈实现队列、用两个队列实现栈

    牛客网上有一道很nt的题目,用两个栈实现队列,你直接用队列不好吗?还耗内存,真的是脱裤子放屁,但是骂归骂,题目还是要做的. 用两个栈来实现一个队列,完成队列的Push和Pop操作. 队列中的元素为in ...

  4. 新一配:程序员因一行代码被老板开除,网友评论:你这不是脱裤子放屁吗?

    在生活中,只要是你自己能够写代码的就是程序员,但是程序员只是一个统称,其中的差距也是巨大.除了理论知识的差异之外,其实我们可以看见最直观的差异就是编码能力的差距或者项目经验的差距,最主要你还是你的编程 ...

  5. 脱裤子放屁,多此一举

    脱裤子放屁,多此一举. 转载于:https://www.cnblogs.com/zhangzujin/p/3892468.html

  6. 实践中的重构19_脱裤子放屁

    每当看到代码中有一个明显的冗余的时候,我就有一个感慨,这家伙时间真多啊,放个屁还要脱裤子. 看例子. if (addressCode != null && (StringUtil.eq ...

  7. 当着众多MM脱裤子放屁

    今天是我的生日,女友早早的打来电话说晚上要到家里去为我祝贺生日,还要带给我惊喜!听了这个好消息!我今天工作起来是格外买力,一下跑了十几个客户!回到公司.都下午三点了,到食堂一看,只剩下可怜巴巴的一菜一 ...

  8. 模板解析原理,脱裤子放屁

    <?php$datalist = array('11','11','11','11','11','11',);$hello = "模板测试";function compile ...

  9. 用三剑客取ip地址的方法(请忽略脱裤子放屁的~)

    在这里插入图片描述

最新文章

  1. Android-去除Button默认边框
  2. Java技术栈---语言基础
  3. c 通过jni调用java_使用c通过jni调用java
  4. 大众CEO迪斯承认芯片仍短缺
  5. L1 - 闭包和原型链
  6. android访问setting权限,如何获得我的Android应用程序的可怕WRITE_SECURE_SETTINGS权限?...
  7. [实战]挖掘CSRF姿势
  8. Numpy系列(二)对数组按索引查询
  9. 03-SSH server config
  10. java报表查询_数据查询 | 快逸报表工具 java报表软件
  11. c语言 什么是指针变量,c语言指针详解:什么是指针?
  12. JPA语法大全 特别是JPA的不等于
  13. php 网页截屏,php怎样实现网页截图
  14. 新唐 Nuvoton M031 入门 点亮板载LED
  15. 最短路——大胖子走迷宫
  16. AlexNet 参数计算
  17. 全球首个大规模虐童图像数据库!标记15万图像、20类信息,自动判断图片是否违法​...
  18. Linux Vi命令使用手册
  19. 从物理意义上了解PCA
  20. 【Office】新建的EXCEL打不开,而存在的EXCEL能打开

热门文章

  1. android屏幕颜色过滤调节(可用于护眼模式)
  2. fdm3d打印机有哪些? Stratasys多品类fdm3d打印机推荐
  3. 34. 实战:基于某api实现歌曲检索与下载(附完整源代码)
  4. BUU刷题记-网鼎杯专栏2
  5. 【Pyecharts50例】GEO图中忽略不存在的位置
  6. android smallestWidth 限定符屏幕适配方案dimens.xml
  7. 【C#】winform软件UI设计模板
  8. jQuery.Deferred() 方法
  9. 你见过最水的程序员是啥样的?
  10. fmm3d在windows环境中的编译使用过程