MyServerless项目原名为GoSqlGo,表示可以直接在前端写SQL的意思,后来考虑到它的开发模式有点类似于serverless,后端不参与业务,而是将业务转给前端来开发,所以项目更名为MyServerless。
MyServerless与通常大厂的Serverless服务相比,主要区别是:1.通常的Serverless是将代码放在云服务器上管理和运行,而MyServerless则是直接将SQL或Java源码写在前端,开发期由前端负责保存和维护。 2)通常的Serverless服务不区分开发期和布署期,而MyServerless因为安全原因,必须明确分为开发和布署两个阶段,开发期源码写在前端,布署期利用工具将前端的源码和SQL抽取到后端。
使用MyServerless是一个标准Servlet,需要后端作一定的配置。以下使用介绍基于示范项目ReactMRP展开,它是一个开箱即用的项目,这个示例中包含了后端和前端两部分,后端使用Servlet容器Undertow来支持MyServerlss这个Servlet,前端基于ReactJS和Ant-Design,该项目链接位于这里:ReactMRP,它最主要特点是把所有业务都写在前端。目前还在开发中,已完成登录和用户管理模块。
后端启动ReactMRP开发阶段要同时启动后端和前端服务,运行ReactMRP的backend目录下的run-server.bat即可启动后端的MyServerless服务,服务启动后会自动打开浏览器访问https://localhost:8001
前端启动运行frontend目录下的:npminstall(仅第一次运行)run_npm_start.bat启动完成后会自动打开浏览器访问https://localhost:3000
打包和发布运行backend目录下的go-backend.bat,把SQL和Java抽取到后端,以实现安全性。运行npmrunbuild生成发布包,并上传到生产服务器方法说明|Methods在前端引入myserverless.js这个javascript文件后,就可以直接在前端调用以下方法执行后端业务:
$java(String,Object...)在后端执行Java,第一个参数是Java源码,后续参数是业务参数,在Java源码里用$1,$2...来代表。$javaTx(String,Object...)在后端执行Java并开启事务,如果有异常发生,事务自动回滚。$qryString(String,Object...)将SQL查询结果的第一行第一列值转为字符串返回,第一个参数是SQL,后面是SQL参数,下同$qryObject(String,Object...)将SQL查询结果的第一行第一列值对象返回,第一个参数是SQL,后面是SQL参数,下同$qryArray(String,Object...)返回SQL查询的第一行数据,以Javascript数组对象格式返回$qryArrayList(String,Object...)返回多行查询结果,以数组列表格式返回$qryTitleArrayList(String,Object...)返回多行查询结果,以数组列表格式返回,第一行内容是各个列的标题$qryMap(String,Object...)返回SQL查询的第一行数据,为Map格式$qryMapList(String,Object...)返回SQL查询的多行数据,为List格式$qryEntity(String,Object...)返回第一行数据为实体对象,SQL写法是实体类名+逗号+SQL,示例:$qryEntity(`#admina.b.Demo,select*fromdemo`);$qryEntityList(String,Object...)返回多行数据为List<实体>对象,SQL写法是实体类名+逗号+SQL,示例:$qryEntityList(`#publica.b.Demo,select*fromdemo`);$executeSql(String,Object...)执行一个SQL,返回SQL影响行数注意事项:1.以上方法Java源码或SQL文本,要使用键盘ESC下方的单引号,这是Javascript的特殊引号,支持多行文本。2.以上方法并不是MyServerless自带的,而是项目自定义的,用户对每个项目可以自定义和登记自己的方法,具体细节请参见项目src/main/resources/template下的方法模板和InitConfig类。3.每个方法都要起一个方法ID,方法ID名允许重复,方法ID的作用是为了权限配置。例如下面这个方法定义了一个名为ReadUserAmount的方法ID
$java(`#ReadUserAmountimportabc.DemoUser;returnnewDemoUser().loadById($1).getAmount();`,123);4.方法默认是异步的,返回值是一个json对象,如{code:200,data:"123",msg:""}5.每个方法可在前面加前缀改变它的返回值,每个方法有4种变体:
$java(`#xxxxreturn123;`);//异步方法,返回{code:200,data:123,msg:""},返回后要在promise的then方法里接收值data$java(`#xxxxreturn123;`);//异步方法,返回json的data字段,即123这个值,返回后要在promise的then方法里接收值sync$java(`#xxxxreturn123;`);//同步阻塞方法,返回{code:200,data:123,msg:""}syncData$java(`#xxxxreturn123;`);//同步阻塞方法,返回json的data字段,即123这个值下面以一个实例来解说如何在前端使用MyServerless:
import*asmyfrom"@/myserverless/myserverless.js"exportfunctiontableList(query){returnmy.data$java(`#publicMapm=(Map)$1;Object[]sql=newObject[]{"fromsamplewhere1=1",noBlank("andtitlelike?","%",m.get("title"),"%"),notBlank("andstar=?",m.get("star")),notBlank("andstatus=?",m.get("status"))};Listitems=DB.qryMapList("select*",sql,pagin((int)m.get("pageNumber"),(int)m.get("pageSize")));inttotal=DB.qryIntValue("selectcount(*)",sql);m.clear();m.put("items",items);m.put("total",total);returnm;`,query);1.首先在js/ts/jsx文件里引入myserverless.js2.方法ID为public,说明这个方法的用户权限是public,即无需登录即可使用,但是因为是动态代码,实际只有两种情况才允许执行,即以developer权限登录的用户,或代码已抽取并布署到服务器上。3.这个方法传入了一个参询对象query,在java方法里1代表这第一个参数,这段代码逻辑是根据参数动态分页查询,返回列表和符合条件的总记录数4.my.data$java()这个方法变体,说明返回的是一个值,即方法中的m变量,而且这是一个异步方法,要用promise形式来调用:
//异步方法要用.then来处理tableList(query).then((map)=>{if(map){constlist=map.items;consttotal=map.total;if(this._isMounted){this.setState({list,total});}}配置在类根目录(项目的resources目录)下,有一个名为myserverless.properties的配置文件,可以进行配置,例如配置deploy目录、设定开发/生产阶段、打包时是否生成API文档等,详见它的注释。
安全安全是重头戏,放在最后讲:
开发期用具有developer权限的账户登录,可在前端任意写SQL和Java,并发送到后端动态编译执行。项目需要写一个实现了TokenSecurity接口的类,在这个类里针对token、方法ID、用户权限来判断是否可以执行,具体参见ProjectTokenSecurity示例。开发期对于每一个方法,由前端赋一个方法ID,比如my.$executeSql(#ReadUserdroptabletb_userifexists);这个ReadUser方法ID说明登录用户必须服务端配置有ReadUser权限才能运行,用这种方式可以精确控制每个方法的执行权限。无须登录的公开方法必须起名为public前缀。如方法ID省略,系统默认起名为default。发布前进行命名检查,防止方法ID要求的权限与它的代码内容不符,比如上面这个ReadUser方法ID,它的代码是在删库,和命名不符,所以要修改代码或者修改方法ID名。发布前,用MyServerless提供的打包工具将前端SQL和java代码抽取到后端,这样线上运行时前端是看不到SQL和Java源码的,而且线上运行配置成拒绝动态编译执行。方法也可以采用传统前后分离模式直接写在后端,参见项目中PublicBackend$TokenLogin示例,签权依然是统一按方法ID来判断。关于MyServerless的安全设计,大家可以启动ReactMRP用developer和admin、guest账号登录体验一下就知道了,除了developer账号,其余账号都无权动态执行前端的SQL和Java。也就是说当你可以为所欲为的时候,你是开发者身份,当你想捣乱的时候,你却没有执行权限。 欢迎大家来找出MyServerless项目的安全漏洞,虽然理论上是不存在的。
MyServerless该说的重点都说完了,所以这篇介绍本身就是它的全部用户手册了,如果还有不清楚的,可以把ReactMRP实际跑一下,把后端部分研究一下就可以了。
缘起对了,最后上一张图来说一下我为什么开发这个项目,我承经有过2个预言,第一个是2017年人工智能将越过奇点,很遗憾这个预言没有实现。第二个预言就是下面这张图,虽然作为一个预言家,自己实现自己的预言脸皮太厚了,但好在看来这第二个预言不会再失败了,因为道理很简单,我没有给它加上时间限制,哈哈。。。。。。
相关开源项目|RelatedProjectsORM数据库工具jSqlBox期望|Futures如对MyServerless感兴趣请点个赞
版权|LicenseApache2.0
关注我|AboutMeGithub码云
评论