JSR 311的许多实现:JAX-RS:RESTful Web服务的Java API提供了开箱即用的运行时WADL生成: Apache CXF , Jersey和Restlet 。 RESTeasy还在等待。 基本上,这些框架检查带有JSR-311批注的Java代码,并在某些URL下生成WADL文档。 不幸的是,Spring MVC不仅不实现JSR-311标准(请参阅: Spring MVC是否支持JSR 311注释? ),而且即使它非常适合于我们,也不会为我们生成WADL(请参阅: SPR-8705 )。公开REST服务。
由于种种原因,我开始使用Spring MVC开发服务器端REST服务,过了一会儿(比如说,后来的第三方资源),我开始迷路了。 我确实需要一种对所有可用资源和操作进行分类和记录的方法。 WADL似乎是一个不错的选择。
幸运的是,Spring框架已开放扩展,如果您愿意在一段时间内浏览代码,可以轻松地基于现有基础结构添加新功能。 为了生成WADL,我需要一个应用程序处理的URI列表,实现的HTTP方法以及(理想情况下)哪种Java方法处理每个方法。 为@Controller,@RequestMapping,@PathVariable等扫描- -显然Spring启动捆扎MVC 的DispatcherServlet在做这项工作已经某处这样看来聪明重用这些信息而不是再次执行任务。
猜猜看,看起来我们需要的所有信息都保存在一个奇怪的RequestMappingHandlerMapping类中。 这是一个调试器屏幕截图,仅用于概述如何提供丰富的信息:
但是它变得更好:RequestMappingHandlerMapping实际上是一个Spring Bean,您可以轻松地注入和使用它:
@Controller
class WadlController @Autowired()(mapping: RequestMappingHandlerMapping) {@RequestMapping(method = Array(GET))@ResponseBody def generate(request: HttpServletRequest) = new WadlApplication()}
没错,我们将使用另一个Spring MVC控制器来生成WADL文档。 上一次我们设法生成表示WADL文档的JAXB类(毕竟WADL是一个XML文件),因此通过返回空的WadlApplication实例,我们实际上返回的是空的但有效的WADL:
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<application xmlns="http://wadl.dev.java.net/2009/02"/>
我不会解释实现的细节(提供完整的源代码 ,包括示例应用程序)。 基本上,这是将Spring模型重写为WADL类的问题。 如果您有兴趣,请查看WadlGenerator.scala,它是解决方案和测试用例的中心点。 这是其中之一:
test("should add parameter info for template parameter in URL") {given("")val mapping = Map(mappingInfo("/books", GET) -> handlerMethod("listBooks"),mappingInfo("/books/{bookId}", GET) -> handlerMethod("readBook"))when("")val wadl = generate(mapping)then("")assertXMLEqual(wadlHeader + """<resource path="books"><method name="GET"><doc title="com.blogspot.nurkiewicz.springwadl.TestController.listBooks"/></method><resource path="{bookId}"><param name="bookId" required="true" /><method name="GET"><doc title="com.blogspot.nurkiewicz.springwadl.TestController.readBook"/></method></resource></resource>""" + wadlFooter, wadl)
}
不幸的是,我懒得不能正确地给定名称/何时/然后命名。 但是测试应该可读性强。
我要提及的唯一技术难题是将Spring基础结构提供的平面URI模式转换为分层的WADL对象(基本上是树)。 这是此问题的简化版本:具有URI模式的列表,如下所示:
/books
/books/{bookId}
/books/{bookId}/reviews
/books/best-sellers
/readers
/readers/{readerId}
/readers/{readerId}/account/new-password
/readers/active
/readers/passive
生成以下树数据结构:
当然,数据结构就像持有标签和Node子列表的Node对象一样简单。 并不是那么有挑战性,但是可能是一个有趣的CodeKata 。
那么,这个WADL有什么意义呢? XML是否真的更具可读性,并有助于管理大量REST应用程序? 如果没有对WADL的 soapUI强大的支持,我什至不会打扰它。 为我推送的示例应用程序生成的WADL也可以轻松导入到soapUI:
值得一提的两个功能。 首先,soapUI显示一棵 REST资源树 (与导入WSDL时的平面操作列表相反)。 每个HTTP方法旁边都有一个相应的Java方法(可以禁用此方法)来处理它,以进行故障排除和调试。 其次,我们可以选择任何HTTP方法/资源并调用它。 基于WADL的描述,soapUI将创建一个用户友好的向导,可以在其中输入参数。 默认值将自动填充。 完成后,应用程序将生成带有正确URL和内容的HTTP请求,并在到达时显示响应。 真的很有帮助!
顺便说一句,您是否注意到max和page查询参数? 我们的小型图书馆使用反射来查找@RequestParam批注,例如以下控制器:
@Controller
@RequestMapping(value = Array("/book/{bookId}/review"))
class ReviewController @Autowired()(reviewService: ReviewService) {@RequestMapping(method = Array(GET))@ResponseBody def listReviews(@RequestParam(value = "page", required = false, defaultValue = "1") page: Int,@RequestParam(value = "max", required = false, defaultValue = "20") max: Int) =new ResultPage(reviewService.listReviews(new PageRequest(page - 1, max)))//...}
将被翻译成与WADL兼容的描述:
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<application xmlns="http://wadl.dev.java.net/2009/02"><doc title="Spring MVC REST appllication"/><resources base="http://localhost:8080/api"><resource path="book"><!-- --><resource path="{bookId}"><param required="true" style="template" name="bookId"/><!-- --><resource path="review"><method name="GET"><doc title="com.blogspot.nurkiewicz.web.ReviewController.listReviews"/><request><param required="false" default="1" style="query" name="page"/><param required="false" default="20" style="query" name="max"/></request></resource></resource></resource></resource
</application>
希望您对我编写的这个小型图书馆感到开心。 随时将其包含在您的项目中,不要犹豫,报告错误。 GitHub上提供了Apache许可下的完整源代码: https : //github.com/nurkiewicz/spring-rest-wadl。
参考: JCG合作伙伴 在Spring MVC REST应用程序中自动生成WADL Java和社区博客中的Tomasz Nurkiewicz。
翻译自: https://www.javacodegeeks.com/2012/02/automatically-generating-wadl-in-spring.html