2016年 2月 20日
Groovy学习笔记之Jetty+Docker实现快速原型
实现一个快速原型是一个苦逼的全栈程序员经常碰到的事情,对于使用快速原型进行迭代开发,最可怕的情况就是80%的时间花在了原型的框架选型开发环境部署上,而20%的时间才用在解决和实现业务上。这是有多低的效率,可能是仅次于去机关办证的低效率了吧!而浪费的时间远远大于坐马桶上刷手机微博所消耗的时间总和。
今天,我们要在使用Jetty + Docker快速实现和部署一个能显示随机正态分布的页面,非常简单,最终效果如下:
图中的钟型曲线是使用Java的Random.nextGaussian产生的。用户可以在页面上输入限制最大值、最小值、数学期望值、标准差和样本总量并由这些参数生成正态分布图。
Jetty服务器
要实现这个快速原型,首先假设你已经在自己的机器上安装了Java,Groovy和Docker。
上述各软件安装好了之后,我们需要写一个Groovy脚本来跑Jetty,首先新建一个文件夹,把这个文件夹作为这个原型的根目录。
然后在原型根目录中新建app.groovy作为程序入口。这个脚本主要的任务就是为我们启动Jetty服务器,内容如下:
简单说明一下这个脚本的作用。
首先我们用@Grab抓取需要的jar包,完了之后导入一些Servlet和Server,然后把这些Servlet挂到端口为8080的Jetty Server上,最后启动Jetty。
服务器有了,接下来我们需要写正态分布的页面了。
正态分布
在原型根目录下新建webroot,在其中新建一个脚本,名字随意取,在这里我们取名叫test1.groovy。我不准备在这里贴这个脚本的全部代码了,你可以在这个项目里面看到源代码。我准备首先说一下算法的基本思路,然后贴一下怎么使用markupBuilder生产html页面配合chart.js生成钟图。
随机正态分布数据的收集
Java的java.util.Random
中自带一个能生成数学期望(u)是0、标准差(a)是1的近似随机标准正态分布的随机方法,叫做nextGaussian
,我们用它来生成随机数。
由标准正态分布的特性可知,99%以上的数值落在(u-2.58a, u+2.58a)区间中,由于标准正态分布u = 0, a = 1所以我们可以假定nextGaussian
方法生成的双精度值范围在-2.58 ~ +2.58之间,我们要做的只是对这个结果值做一下线性平移,然后收集结果即可。
譬如,我们可以把nextGaussian
产生的结果a(99%以上落于(-2.58 ~ +2.58)区间)乘以100,然后截取整数位,放入一个map做key,value设置成1。下次再随机到这个值时,map中的value + 1。然后用样本总量值作为循环次数收集产生的随机值。
收集完成后,将map.key进行升序排序,然后map.key的第一个值便是随机生成的最小值min,map.key的最后一个值是最大值max。
之后用Groovy的Range生成从min到max的范围,针对范围中每一个值i,map[i]便可以取得该值出现过的次数。我们可以用'='*map[i]
打印到Console中,就能很形象地看到一个正态分布图像了。
废话不多说,看代码吧
运行一下,你应该能看到console上打印出下面这坨东西(太长,截取部分)
如果你把它打印成txt文件(用groovy test.groovy > out.txt
),缩小后能看到
看到没,近似正态分布了吧。就是console中比较丑,没事儿,接下来我们把上面的概念想办法搞到html页面上去。
test1.groovy脚本中代码虽然不是完全按照上面的来,但是思路是一样的。具体代码可以看这里。
GroovyServlet
好了,正态分布的数据有了,接下来要可视化。我们准备使用chart.js的曲线图来显示。chart.js的曲线图实现起来比较简单,只要提供data和options(可忽略),把canvas包到Chart类中去即可,具体可以参考这里的中文文档。
好了,有了chart.js的加持,我们只要生成html和json的数据即可了。首先我们来看看怎么生成html。
你可以把test1.groovy看做一个servlet,如果你查看groovy.servlet.ServletBinding
,可以看到在GroovyServlet中,已经默认绑定了以下几个变量供我们调遣
Eager variables
- “request” : the HttpServletRequest object
- “response” : the HttpServletRequest object
- “context” : the ServletContext object
- “application” : same as context
- “session” : shorthand for request.getSession(false) - can be null!
- “params” : map of all form parameters - can be empty
- “headers” : map of all request header fields
Lazy variables
- “out” : response.getWriter()
- “sout” : response.getOutputStream()
- “html” : new MarkupBuilder(response.getWriter()) - expandEmptyElements flag is set to true
- “json” : new JsonBuilder()
Methods
- “forward(String path)” : request.getRequestDispatcher(path).forward(request, response)
- “include(String path)” : request.getRequestDispatcher(path).include(request, response)
- “redirect(String location)” : response.sendRedirect(location)
有没有jsp中的隐含变量的感觉?OK,里面有个叫html的MarkupBuilder,好了我们用它来生成html。咱先把chart.js的javascript和form表单部分省略了吧。
会生成以下html页面源码
好了,html的框架有了,接下来我们要把之前算出来的随机数结果改造成chart.js能用的数据格式然后显示,我们来看看怎么做:
完成!浏览器访问http://localhost:8080/test1.groovy
,塔拉~~~
哦,form提交什么的很简单的就不再赘述啦请戳这里看源代码。
部署
部署Groovy其实是个很简单的事情,只要你有Java环境然后安装上Groovy,然后用groovy运行即可。
什么?你说这没有一点部署服务器的庄重感?感觉太简单不能完成你的需求?怕运维人员失业?好吧,那我们就用Docker部署吧,因为很简单,写个Dockerfile就行了。
Docker源文件可以在这里看到。
OK,然后在docker环境中运行:(如果你是docker-machine的话,就是mac或者windows的docker,就是在Docker Quickstart Terminal
中,对就是头上有个金鱼鲸鱼的那个终端)
等待Docker下载并构建成功后运行
浏览器访问http://localhost:8080, 如果是docker-machine环境请访问http://192.168.99.100:8080
塔拉~~~完成。
哦对了,首次运行Groovy需要下载依赖包, 可能需要点时间, 请耐心等候.
好了,现在,你有了一个app,有可以通过命令行直接运行的源代码(命令行运行groovy app.groovy
),还有了可以通过registry push到生产环境的docker image,怎么?还不满意?没事儿,你还可以用maven、gradle这种构建工具来编译打包groovy项目,当然,还可以用spring CLI直接运行groovy脚本,或者一键打包成可执行jar或可部署war,可选项太多了。
对了,还有数据库相关的都还没说呢。
且听下回分解。