REST支持(5.8.0+)

概述

自5.8.0版以来,Tapestry为将REST端点作为页面类中的常规事件处理程序方法写入提供了现成的支持。它们的工作方式与激活事件(即。onActivate()方法)的工作方式,包括事件处理程序方法参数的工作方式@请求正文注释已创建,因此事件处理程序方法可以访问请求正文。创建@StaticActivationContextValue注释是为了编写仅在URL路径的一个或多个部分与给定值匹配时才调用的事件处理程序方法。这两个注释都不是REST特定的,可以在任何事件处理程序方法中使用。一个新的子项目/JAR tapestry-rest-jackson自动使用jackson Databind进行JSON转换。tapestry-Swagger/OpenAPI 3.0描述是自动生成的,可以轻松定制。一个新的子项目/JAR tapestry-openapi-viewer为使用Swagger UI生成的openapi描述提供了一个现成的查看器。对于Tapestry REST支持示例项目,请查看https://github.com/thiagohp/tapestry-rest-example.

一些重要警告:

  1. Tapestry的REST支持不是JAX-RS的实现,所以他们希望它的任何概念都能在这里工作。它是以Tapestry方式实现的REST。
  2. 组件中的REST端点事件处理程序方法被忽略,就像onActivate()是。

支持以下HTTP方法:

HTTP方法Tapestry事件名称

事件常量

常量名称

事件处理程序

方法名称

GET(获取)httpGet(http获取)HTTP_获取onHttpGet上
邮政httpPost(httpPost)HTTP_测试在HttpPost上
删除http删除HTTP_选择onHttpDelete
PUT(输出)httpPutHTTP_输出打开HttpPut
头部httpHead(http头)HTTP_抬头在HttpHead上
补丁http补丁HTTP_附件onHttpPatch

写入REST端点

在Tapestry中编写REST端点与编写完全相同启用()方法。一切都是一样的:参数处理、返回值处理、优先级规则、类继承、URL等。如果您知道如何编写onActivate()方法,您已经了解了编写REST端点事件处理程序所需的几乎所有内容。两者之间只有2个小差异onActivate()和REST端点事件处理程序方法:

  1. REST事件处理程序方法在onActivate()
  2. 根据要处理的HTTP方法,事件名称不同。

因此,例如,如果您想要一个URL/userendpoint/[id]的REST端点,假设id是,处理GET(获取)HTTP方法,您只需编写以下页面类和事件处理程序:

公共类UserEndpoint{对象onHttpGet(长id){(...)}(...)}

也可以使用@OnEvent(OnEvent)注释,其工作原理相同:

公共类UserEndpoint{@OnEvent(事件常量.HTTP_GET)对象getById(长id){//或任何其他方法名(...)}(...)}

使用读取请求正文@请求正文

很多时候,特别是对于POST、PUT和PATCH请求,数据都是通过请求体发送的。要获取此数据,事件处理程序方法需要添加一个参数@请求正文注释。它只有一个属性,allowEmpty(允许空),使用作为其默认值,用于定义空的请求体是否为空。否则,将引发异常。

@OnEvent(事件常量.HTTP_PUT)对象保存(@RequestBody User用户){(...)}@OnEvent(事件常量.HTTP_PUT)对象保存(长id,@RequestBody User用户){(...)}

现成支持以下类型:

  • 字符串
  • 阅读器
  • InputStream(输入流)
  • JSON对象
  • JSON数组
  • 基元类型及其包装类型

实际转换逻辑在HttpRequestBodyConverter(HttpRequestBodyConverter)服务,定义为的有序配置HttpRequestBodyConverter实例。该服务调用所有提供的实例,直到其中一个实例返回非空值。如果它们都没有返回非空值,则返回到尝试从HttpServlet请求到所需类型。 

下面是一个实现新HttpRequestBodyConverter然后将代码添加到应用程序模块或任何其他Tapestry-IoC模块类@请求正文:

/***将HTTP请求体转换为{@link User}实例。它委派此任务*到{@link UserService#toObject(String)}。*/公共类UserHttpRequestBodyConverter实现Http请求BodyConverser{私有最终UserService UserService;公共UserHttpRequestBodyConverter(UserService UserService){super();this.userService=用户服务;}@禁止警告(“未选中”)@覆盖public转换(HttpServletRequest请求,Class类型){T值=空;//检查此转换器是否处理给定类型if(User.class.equals(type)){//实际转换逻辑尝试{value=(T)userService.toObject(IOUtils.toString(request.getReader()));}捕获(IOException e){抛出新的RuntimeException(e);}       }返回值;}}
UserHttpRequestBodyConverter贡献
公共静态void contributeHttpRequestBodyConverter(OrderedConfiguration(有序配置<HttpRequestBodyConverter>配置){configuration.addInstance(“用户”,UserHttpRequestBodyConverter.class);//自动实例化和依赖项注入//或configuration.add(“用户”,new UserHttpRequestBodyConverter(…));}

回答REST请求

与任何其他Tapestry事件处理程序方法一样,返回的值定义了要发送给发出请求的用户代理的内容。此逻辑写入组件事件结果处理器实现,通常但不一定每个返回类型/类都有一个实现组件事件结果处理器服务。这些实现还可以设置其他HTTP头并设置HTTP状态代码。

REST请求响应通常分为两种类型:只返回HTTP状态和标头的响应(例如,头部删除请求)和返回请求以及内容的请求(例如,GET(获取),有时还有其他方法)。

内容回复

对于内容响应,Tapestry提供了现成的支持流式响应(主要是二进制内容)文本流响应(简单文本内容),JSON数组(自Tapestry 5.8.0起)和JSON对象(自5.8.0起)。下面是一个添加类支持的示例,用户,将其转换为JSON格式:

/***处理事件处理程序方法返回的{@link User}实例。*灵感来自Tapestry本身的{@link JSONCollectionEventResultProcessor}。*/最终公共类UserComponentEventResultProcessor实现ComponentEventResultProcessor<用户>{私人最终响应;私有最终ContentType ContentType;私有最终UserService UserService;public UserComponentEventResultProcessor(响应响应,@符号(TapestryHttpSymbolConstants.CHARSET)字符串输出编码,用户服务用户服务){this.response=响应;this.userService=用户服务;contentType=新contentType(InternalConstants.JSON_MIME_TYPE).withCharset(outputEncoding);}public void processResultValue(用户用户)引发IOException{PrintWriter pw=响应.getPrintWriter(contentType.toString());pw.write(userService.toJsonString(用户));pw.close();//您还可以在此处设置额外的HTTP头或状态代码}        }
UserComponentEventResultProcessor贡献
公共void contributeComponentEventResultProcessor(MappedConfiguration<类,组件事件结果处理器>配置){configuration.addInstance(User.class,UserComponentEventResultProcessor.class);}

非内容回复

对于没有内容、只有HTTP状态和标头的响应,以及简单的String响应,Tapestry 5.8.0引入了Http状态类。您可以使用与HTTP状态名称匹配的实用程序静态方法来创建它的实例,例如ok(),创建(),接受()未找到()禁止()或使用其构造函数之一。在这两种情况下,您都可以通过使用流畅的接口和特定于header的方法进一步定制响应,例如带位置(url)包含内容位置(url)或通用withHttpHeader(字符串名称,字符串值).检查Http状态JavaDoc获取方法的完整列表。

@OnEvent(事件常量.HTTP_PUT)对象保存(@RequestBody User用户){userService.save(用户);return HttpStatus.created().withContentLocation(“某些URL”).withHttpHeader(“X-Something”,“X-Value”);}

映射实体管理器服务

这是一个提供映射实体列表的服务。它们通常是映射到JSON和XML等其他格式的类,用于表示接收或发送到外部进程(例如REST端点)的数据。贡献由包完成,贡献中的所有类都被视为映射实体。这个[根包]。rest.实体包是自动贡献的。

Tapestry代码使用此服务,包括OpenAPI描述生成器和挂毯rest jackson,以了解哪些类应该被视为Web应用程序外部API的一部分。

以下是一个贡献示例:

public static void contributeMappedEntityManager(配置<String>配置){configuration.add(“com.example.rest.entities”);}

与Jackson Databind与tapestry-rest-Jackson集成

JSON被广泛用作REST端点中的数据交换格式,而Jackson Databind可能是JSON映射最常用的Java库。tapestry-rest-jackson公司

自动在Tapestry中使用Jackson Databind,定义对象映射器源服务,贡献组件事件结果处理器HttpRequestBodyConverter(HttpRequestBodyConverter)所有映射实体类的实现(由映射实体管理器服务),并使用victorools/jsonschema生成器

这个对象映射器源服务定义了tapestry-rest-jackson如何获得对象映射器实例用于给定实体类。它的有序配置为对象映射器源.方法单一,ObjectMapper get(类<?>clasz)。调用时,它会遍历所有贡献的实例,对它们调用相同的方法,直到其中一个实例返回非空值。当返回非空值时,服务方法将返回该值。如果未找到任何值,则回退始终返回由新建ObjectMapper()。对对象映射器实例应作为对对象映射器源服务。下面是一个定义所有实体类应使用哪种日期格式的示例:

/***自定义Jackson数据绑定的{@link ObjectMapper}的示例,特别是*日期格式。*/公共静态void contributeObjectMapperSource(OrderedConfiguration<ObjectMapperResource>configuration){configuration.add(“自定义”,新的CustomObjectMapperSource());}私有静态最终类CustomObjectMapperSource实现ObjectMapperResource{最终私有ObjectMapper映射器;公共CustomObjectMapperSource(){mapper=新ObjectMapper(/*…*/);mapper.setDateFormat(新的SimpleDateFormat(“yyyy/MM/dd hh:MM:ss”));//此处显示任何其他自定义设置。}@覆盖public ObjectMapper get(类<?>clasz){//您可以检查类以提供特定于类的ObjectMapper//实例,但本例并非如此返回映射器;}}

OpenAPI 3.0(Swagger)描述的自动生成

Tapestry提供了一个现成的OpenAPI 3.0(Swagger)描述生成器,由REST端点事件处理程序(即处理本页顶部表格中列出的事件的处理程序)、配置符号和国际化消息(即app.properties)驱动。描述采用JSON格式。

默认情况下,它是禁用的。通过设置tapestry.publish-openapi-描述(符号常量。发布_操作_定义)配置符号到真的。如果启用,它将在/openapi.json软件URL。可以使用磁带.openapi-description-path(符号常量。OPENAPI_DESCRIPTION_PATH(打开_描述_路径))配置符号。 

MappedEntityManager.getEntities()返回的所有实体类都会自动添加到模式部分。 

使用消息和配置符号自定义名称、摘要和描述

摘要、名称和描述以及消息首先取自消息,其次取自配置符号,但OpenAPI版本除外,该版本仅取自磁带.openapi-version(符号常量。打开版本(_V))符号,默认值为3.0.0。给定消息键,相应的配置符号为挂毯。[信息键]格式。

HTTP方法名称是小写的。

构建消息密钥时,如果它基于路径,则不会删除起始斜杠。例如/某物POST方法的端点为openapi/某物.帖子.摘要.

通过设置org.apache.tapestry5.internal.services.rest.DefaultOpenApiDescriptionGenerator类到调试.

使用自定义端点的已使用和生成MIME内容类型@RestInfo(重置信息)

这个@RestInfo(重置信息)注释允许您仅为OpenAPI描述生成目的定义REST端点事件处理程序方法接受的MIME内容类型、生成的类型以及方法执行成功时的实际返回值类型。许多REST事件处理程序方法的返回类型通常为对象因此它可以返回Http状态调用成功时,出现错误的实例和映射的实体类实体。

这里有一个例子:

@RestInfo(products=“text/plain”,produces=“application/json”,returnType=User.class)对象onHttpGet(@RequestBody长id){用户用户=。。。;if(!未找到){return HttpStatus.notFound()}其他{返回用户;}}

进一步自定义

可以通过实现OpenApiDescriptionGenerator接口并将其贡献给OpenApiDescriptionGenerator服务。这个JSON对象生成(JSONObject文档)方法将接收生成的描述,可以使用JSON对象方法。返回值应与作为参数接收的对象相同。

tapestry-openapi-viewer

tapestry-openapi-viewer tapestry子项目/JAR嵌入了开源Swagger用户界面OpenAPI/Swagger并在/openapi查看器URL。除了在类路径中包含JAR之外,不需要任何配置。