1 Star 0 Fork 25

skymysky / GoSqlGo

forked from drinkjava2 / MyServerless 
加入 Gitee
与超过 1200万 开发者一起发现、参与优秀开源项目,私有仓库也完全免费 :)
免费加入
克隆/下载
README.md 13.03 KB
一键复制 编辑 原始数据 按行查看 历史
drinkjava2 提交于 2019-01-08 01:17 . Update README.md

为避免误解,在此声明:

本项目架构上没有什么安全问题,有质疑安全、注入问题的,在吐槽之前请先看完这篇说明。

GoSqlGo简介 | Description

天下武功,唯快不破,程序无非就是接收用户输入、存到数据库。GoSqlGo能让前端直接存取数据库,独立完成项目开发。

缘起 | Origin

一直认为,开发效率最高的方式不是让MVC架构极简(SpringBoot/jFinal),而是彻底省略掉MVC架构和后端程序员,直接由前端搞定一切,由多层架构变成两层,在前端直接写SQL,缩短输入和SQL的矩离,才是最快的开发途径。基于此理念,在2011年本人在这里写了一句预言,没想到技术的发展如此之慢,现在要自己亲手去实现它了,这就是GoSqlGo项目,如果名字翻译成中文,可以翻成"Sql冲冲冲冲冲",这个比较形象,它表达了SQL为王,一路狂奔,冲到了前端的意思。

架构 | Software Architecture

GoSqlGo是一个运行于后端的开发工具,它的最大特点就是在开发期动态编译客户端Java代码,所有SQL和Java代码都可以在前端Html页面完成,可以彻底甩掉后端了。开发完成后利用打包工具再将SQL和Java从前端移到后端。
忘掉MVC吧,因为现在架构变成MV两层了;忘掉FreeMaker之类模板吧,因为Java本身变成了Javascript中的模板语言。忘掉后端程序员吧,因为后端除了写数据库,本来就没多少事干,现在这点活也由前端接管了。忘掉前端校验吧,因为后端校验这活也归前端了,前端校验能偷懒就偷吧。

特点 | Features

前端程序员可以直接在Javascript里写SQL和Java代码,例如以下为一个HTML片段,实测通过,完整文件位于这里
这是一个转账业务的演示,它把所有的业务逻辑都写在html里面,不再需要和后端程序员沟通了:

<!DOCTYPE html>
<html>
<head>
<script src="/js/jquery-1.11.3.min.js"></script>
<script src="/js/jquery-ajax-ext.js"></script>
<script src="/js/gosqlgo.js"></script>
</head>
<body>
    <h1>Transaction Demo</h1>
    <div id="msgid" class="msg"></div>
    <section>
        <header>Account A</header>
        <div id="A" class="amount">
            <script>
                document.write($qry('select amount from account where id=? and amount>=?', 'A',0));
            </script>
        </div>
    </section>
    <section>
        <header>Account B</header>
        <div id="B" class="amount">
            <script>
                document.write($qry('select amount from account where id=? and amount>=?', 'B',0));
            </script>
        </div>
    </section>
    <script>
      function transfer(from, to, money){
         var rst = $java(`TX
                        int money=Integer.parseInt($3);
                        if(money<=0)
                          throw new SecurityException("Money<=0, IP:"+ getRequest().getRemoteAddr());
                        Account a=new Account().setId($1).load();
                        if(a.getAmount()<money)
                           return "No enough balance!";
                        Account b=new Account().setId($2).load();
                        a.setAmount(a.getAmount()-money).update();
                        b.setAmount(b.getAmount()+money).update();
                        return "Transfer Success!|"+a.getAmount()+"|"+b.getAmount();
                        `,    from,to,money
                    );   
          if(rst.startsWith("Transfer Success!")) {
              var words=rst.split('|');
               $("#msgid").text(words[0]);
               $("#"+from).text(words[1]);
               $("#"+to).text(words[2]);
               $("#msgid").css("background", "#dfb");
          }
          else { $("#msgid").text(rst);
                 $("#msgid").css("background", "#ffbeb8");
          }
        }
    </script>
    <section>
        <header>Transfer</header>
        <form onsubmit="return false" action="##" method="post">
            <input name="amount" value="100" class="amount">
            <button name="btnA2B" value="true" onclick="transfer('A','B',100)">From
                account A to account B</button>
            <button name="btnB2A" value="true" onclick="transfer('B','A',100)">From
                account B to account A</button>
        </form>
    </section>
</body>
</html>

GoSqlGo运行在服务端,只需要进行简单的数据源设定、ActiveRecord实体类定义就可以了,详见demo/gsg-tomcat/src/main/java/com/gitee/gosqlgo/demo/InitConfig.java文件内容。

GoSqlGo在客户端只需要添加一个gosqlgo.js,就可以进行服务端调用了,所有业务写在客户端。gosqlgo.js只有2个方法:

  • qry() 执行单个SQL查询,返回一个文本对象。
  • java() 执行多行Java语句,返回一个文本对象,如果Java片段以“TX”打头表示将开启事务,任何异常发生,事务将自动回滚。

细节 | Description

开发阶段:GoSqlGo在服务端运行,它自带一个动态编译工具,前端发来的SQL和Java片段,被运态编译为Java类,并调用其自带的ORM工具(采用jSqlBox),运行并返回文本或JSON对象。
在Sql/Java片段里面,返回值可以分为以下类型,但客户端最终收到的都是一个字符串:

  1. 字符串类型,可以为普通字符串或JSON字符串,由客户端来自行解析。
  2. WebBox对象,可以用new WebBox().setText()方法来设定一个字符串,或用new WebBox("xxx.htm")方法来设定一个跳转页面, 由客户端来自行解析。
  3. 异常抛出,服务端会捕获异常,并返回异常页面信息字符串,由客户端来自行解析。
  4. 空值,服务端会返回"null"字符串,由客户端来自行解析。
  5. 其它Java对象,服务端会对Java对象调用JSON.toString(obj)方法进行字符串化,由客户端来自行解析收到的JSON字符串。

布署阶段:通过一个打包工具,将前端所有的SQL和原生Java片段打包到服务端去,静态存为可调试的Java源文件,原有客户端的SQl和JAVA代码在打包后将成为类似于qry('C9GK90J27','A');之类的通过ID进行的调用,以实现安全性。
对于Sql/Java字符串片段,有以下可选控制字符:
TX,表示开启事务
SERV,永远留在后端,一旦用goServ命令抽取到服务端,就不能再用goFront命令塞回到前端了
FRONT, 永远留在前端,不会被抽取出来,直到使用deploy命令才会被抽取到Server端
#xxxxx形式,手工指定ID, 如果不定义ID, 则由工具随机自动生成,用goFront命令塞回到前端时会删除这个随机ID
import 开头,为标准Java的import语句
示例: qry('TX SERV #ReadAmount import abc.Demo1;import abc.Demo2; select amount from account where id=? and amount<>?', 'A',0);

安装使用 | Installation

GoSqlGO使用需要在项目里加入以下依赖:

    <dependency>
      <groupId>com.github.drinkjava2</groupId>
      <artifactId>gosqlgo</artifactId>
      <version>1.0.0</version>
    </dependency>

它主要有两个功能:
1.动态编译客户端传来的SQL/Java,生成Java类,例如以下调用会动态地根据Java源码生成内存中的Java类:
DynamicCompileEngine.instance.javaCodeToClass(className, classSrc); 这个功能通常前端程序员不需要了解。

2.打包工具,将前端的SQL/Java抽出到后端, 有三个方法,使用示例:

new DeployTool().toServ();    //将HTML/Javascript中的sql和java代码抽取出来,生成Java类发布到项目源码的deploy目录下
                              //如果SQL/Java片段开头含有"FRONT"关键字打头将不抽取
new DeployTool().deploy();    //同上,但是忽略FRONT关键字,一律抽取到服务端,以实现安全性
new DeployTool().toFront();   //逆操作,将抽取出来的SQL/Java类再塞回到HTML/Javascript中

原则上GoSqlGo可以使用在任意支持JSP的Servlet容器内,并可搭配不同的DAO工具使用,但是学习它最简单的方法是运行它的示例项目"gsg-tomcat",这是个微型的服务端框架:

"gsg-tomcat"项目需Java8或以上,用git clone下载后, 有三种运行方式:
方式1,发布war包到本机的Tomcat7或Tomcat8目录下执行:
运行:修改run-normal-tomcat.bat批处理文件中的TomcatFolder为本机Tomcat目录,并执行
查看:浏览器输入 http://localhost

方式2, 命令行方式运行嵌入式Tomcat,这种方式本机不需要安装Tomcat, Maven会自动下载
运行:双击运行run-embeded-tomcat.bat批处理即可
查看:浏览器输入 http://localhost

方式3, 导入到Eclipse中运行
1.运行run-embeded-tomcat.bat批处理一次
2.运行maven_eclipse_eclipse.bat批处理,生成eclipse配置
3.打开Eclipse,导入项目,并运行其中的EmbedMain.java的main方法
查看:浏览器输入 http://localhost

另外在项目resources目录下,有一个名为GoSqlGo.properties的配置文件,可以进行一些配置,例如配置后端Java类模板等,请自行打开查看。

计划:目前只有Tomcat示范版本,今后可能发行Tomcat/Jetty/Undertow等多个示范项目

常见问题 | FAQ

  • 安全上有没有问题?
    有,在java方法里,可以手工进行参数合法性检查,不存在架构上的安全漏洞,但是在qry方法里,没有进行参数校验的语句,如果遇到客户端恶意传入非法SQL参数,例如想要调入用户A的账户,却传入了用户C的账户ID,这时候就会出现非法存取,甚至出现扫表情况,整张表的信息都会泄露。
    为什么有这么大的漏洞还要保留qry方法? 因为作者认为方便性要大于安全性。例如对于OSC这种社交类网站,除了用户密码外,大多数表格内容都是可以公开的,即使出现非法参数或扫表,也不是件大事。当然扫表太历害就成了DDOS攻击了,后端要加上对qry进行存取频率限制或登录检查的切面处理。
    对于安全性要求高的公司,可以强制要求不允行使用qry方法。或者后端对SQL写法提出要求,如存取到的表格、字段必须用!、#等符号注明出来,并结合切面类进行安全检查。

  • 为什么采用过时的JSP技术?
    也可以不用。但作者的技术栈比较落后,采用JSP技术后,可以更简单地进行后端页面布局(jWebBox对标Apache Tiles)和模块式开发。大前端时代,后端的页面布局有时还是要用到的,它可以一次将页面渲染后发给前端,提高用户体验,防止多次AJAX调用造成的马塞克似的东一块、西一块的页面加载,尤其在网速差的情况下。
    一般情况下,前端并不需要了解后端的实现技术细节,如果我不提,前端的人可能根本不知道GoSqlgo采用了JSP技术。

  • 为什么示例项目采用jSqlBox这么小众的、没经过时间检验的DAO工具?
    因为jSqlBox是作者自已写的DAO工具,打广告用的,它的DAO功能很全,号称SQL写法百科全书,目前已支持DAO层的分片,将来有可能将分布式事务、容错等技术也做在DAO层,方便前端使用。如果前端对jSqlBox不感冒,可以对公司的后端提要求,搭配不同的DAO工具即可。
    GoSqlGo与其说是个产品,不如说是个概念,稍有经验的后端都可以在它的基础上开发出支持其它ORM、MVC框架的更稳定的后端平台。前端并不需要太关心后端框架技术细节,只需要关心SQL的写法和ORM工具的使用。
    如果所有业务逻辑写在前端,则不管后端采用什么框架,前端的写法基本不变,例如SQl的写法和ActiveRecord的写法,所有ORM工具都大同小异。

  • (小鹏提出)Java写在HTML/Javascript里没有错误检查、语法提示
    这个将来可以通过IDE插件解决,但目前只能用goServ方法将Sql/Java抽取成Java源码类,在IDE里找错、更正后再用goFront方法塞回到HTML里去,也可以干脆就不塞回去了,后者就对应传统的前后端分离开发情形。

作者其它开源项目 | Other Projects

期望 | Futures

GoSqlGo第一版已正式发布,对它感兴趣的请加关注,或发issue提出更好的意见,帮助完善它。也欢迎加入GoSqlGo开发组。

版权 | License

Apache 2.0

关注我 | About Me

Github
码云

点赞 | DianZan

点赞很重要,必须的

Java
1
https://gitee.com/skymysky/gosqlgo.git
git@gitee.com:skymysky/gosqlgo.git
skymysky
gosqlgo
GoSqlGo
master

搜索帮助