Clojure提供了一个很好的Java互操作。但是,我真的想要这个:
(servlet IndexServlet
(service[parmas] ....)
(do-post[params] ....)
(do-get [params] ....))
(servlet-filter SecurityFilter
(do-filter [params] ....))
我猜这就是所谓的DSL,在Lisp世界中它是通过宏完成的。
我不确定如何/从哪里开始。 refiy和extends表单在这里肯定有重要作用,但我不知道它如何适合宏。
如何开始使用此DSL? 我们非常感谢一个片段,提示和技巧。
答案 0 :(得分:3)
您可能需要查看Ring的Jetty适配器,以获取Clojure中servlet实现的示例。源可用here(链接到1.1版本的源代码)。特别是,该命名空间中定义的第一个函数proxy-handler
基于Jetty提供的抽象类返回一个处理程序。
如果您选择实现类似的方法(将您的servlet基于Java类提供一些现成的方法impl),您将需要使用proxy
;如果你只需要实现接口(没有子类化),那么你可能需要reify
。宏是否有用取决于实现的哪些部分将被修复; Ring的Jetty适配器不会受益于宏的使用,但您可以(例如,如果您希望将类扩展/接口实现为参数,正如问题似乎表明的那样)。
在任何情况下,您选择实施的任何功能都需要成为接口或协议的一部分。因此,实施javax.servlet.Servlet
以及其他操作foo
可能如下所示:
(import (javax.servlet Servlet ServletRequest ServletResponse))
(defprotocol PFoo
(foo [this x y z]))
(reify
Servlet
(service [this ^ServletRequest req ^ServletResponse res]
...)
;; other Servlet methods here...
PFoo
(foo [this x y z]
...))
然后你可以将它包装在宏中以提供任何所需的语法糖。请注意reify
实际上并不关心在其体内交换接口/协议名称和方法定义的方式,因此您可以让宏发出
(reify
Servlet PFoo ... ; other interfaces & protocols
(service [...] ...)
(foo [...] ...)
;; other methods
)
如果那更方便。
一个宏的草图,它采用servlet接口的名称来实现(可能是扩展javax.servlet.Servlet
)并使用一些额外的方法注入协议:
(defprotocol PFancyServlet
(do-get [this ...])
(do-post [this ...]))
(defmacro servlet [servlet-iface & meths]
`(reify ~servlet-iface PFancyServlet
~@meths))
meths
需要包含do-get
和do-post
以及servlet-iface
方法;你可以添加一些参数验证来确保这种情况。一个示例电话:
(servlet SomeServletInterface
(service [this ...] ...)
;; ...
(do-get [this ...] ...)
(do-post [this ...] ...))