在Spring MVC REST应用程序中自动生成WADL

上一次我们学习了WADL基础知识 。 语言本身并没有那么有趣,只写了一篇有关它的文章,但是本文的标题揭示了为什么我们需要这些知识。

JSR 311的许多实现:JAX-RS:RESTful Web服务的Java API提供了开箱即用的运行时WADL生成: Apache CXFJerseyRestletRESTeasy还在等待。 基本上,这些框架检查带有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

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
WADLWeb Application Description Language)是一种用于描述Web服务的语言,它支持基于HTTP的请求方法,包括POST请求。要使用WADL进行POST请求,可以参考以下步骤: 1. 获取服务描述文件(WADL) 可以使用浏览器访问服务URL,并在URL后面添加“?_wadl”参数,来获取服务描述文件。例如: ``` http://localhost:8080/your/service/url?_wadl ``` 2. 解析服务描述文件 使用工具(例如Java的jaxb)解析服务描述文件,获取服务请求的URL、请求参数等信息。 3. 构造POST请求 根据服务描述文件的信息,构造POST请求。例如: ```java URL url = new URL("http://localhost:8080/your/service/url"); HttpURLConnection conn = (HttpURLConnection) url.openConnection(); conn.setRequestMethod("POST"); conn.setRequestProperty("Content-Type", "application/xml"); String input = "<request><param1>value1</param1><param2>value2</param2></request>"; OutputStream os = conn.getOutputStream(); os.write(input.getBytes()); os.flush(); ``` 其,Content-Type头部指定请求数据的格式;input为请求数据。可以根据服务描述文件的参数信息,动态生成请求数据。 4. 处理响应 ```java int responseCode = conn.getResponseCode(); if (responseCode == HttpURLConnection.HTTP_OK) { BufferedReader in = new BufferedReader(new InputStreamReader(conn.getInputStream())); String inputLine; StringBuffer response = new StringBuffer(); while ((inputLine = in.readLine()) != null) { response.append(inputLine); } in.close(); System.out.println(response.toString()); } ``` 其,conn.getResponseCode()获取响应状态码;conn.getInputStream()获取响应数据流。可以根据服务描述文件的响应信息,解析响应数据。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值