【问题标题】:Intercept JAX-RS web service request to add JSON field拦截 JAX-RS Web 服务请求以添加 JSON 字段
【发布时间】:2016-08-01 05:47:54
【问题描述】:

我有一个 JAX-RS Web 服务,它返回一个接受 JSON 请求参数(映射到 Parameter 对象),如下所示(它在 WebLogic 12.2.1 中运行)。是否可以编写一个拦截器或过滤器,这样当调用 Web 服务时,它会在 JSON 请求消息中添加一个额外的字段,以便下面的方法在 requestParameters 中获取该额外的字段?

@POST
@Consumes(MediaType.APPLICATION_JSON)
@Produces(MediaType.APPLICATION_JSON)
@Path("LogIn")
public Response logIn(@Context HttpServletRequest request, Parameters requestParameters) {...}

谢谢!

【问题讨论】:

标签: json web-services jax-rs weblogic12c


【解决方案1】:

拦截器

这可以通过拦截器来实现。

拦截器旨在通过操纵实体输入/输出流来操纵实体。有两种拦截器,ReaderInterceptorWriterInterceptor

阅读器拦截器用于操作入站实体流。这些是来自“电线”的流。因此,使用阅读器拦截器,您可以在服务器端操纵请求实体流。编写器拦截器用于将实体写入“线路”的情况,这在服务器上意味着写出响应实体时

以下拦截器实现了ReaderInterceptor 接口,允许您在服务器端修改请求的实体:

@Provider
public class CustomReaderInterceptor implements ReaderInterceptor {

    @Override
    public Object aroundReadFrom(ReaderInterceptorContext context) 
                      throws IOException, WebApplicationException {

        InputStream stream = context.getInputStream();

        // Manipulate the HTTP entity using the InputStream

        context.setInputStream(stream);
        return context.proceed();
    }
}

请注意上面的拦截器是全局的,即对所有资源方法都会执行。

使用Jackson 时,您的ReaderInterceptor#aroundReadFrom(ReaderInterceptorContext) 方法实现可能如下:

// Create a Jackson ObjectMapper instance (it can be injected instead)
ObjectMapper mapper = new ObjectMapper();

// Parse the requested entity into a JSON tree
JsonNode tree = mapper.readTree(context.getInputStream());

// Add a property to the JSON
((ObjectNode) tree).put("field", "value");

// Set the input stream containing the manipulated JSON
context.setInputStream(new ByteArrayInputStream(mapper.writeValueAsBytes(tree)));

// Proceed to the next interceptor in the chain
context.proceed();

名称绑定

要仅对某些精选资源方法执行拦截器,您可以使用名称绑定

名称绑定 是一个概念,它允许对 JAX-RS 运行时说特定过滤器或拦截器将仅针对特定资源方法执行。当过滤器或拦截器仅限于特定的资源方法时,我们说它是 name-bound

可以使用@NameBinding 注释将过滤器分配给资源方法。注释用作其他用户实现的注释的元注释,这些注释应用于提供者和资源方法。

名称绑定注解可以定义如下(注解名称由你决定):

@NameBinding
@Retention(RUNTIME)
@Target({TYPE, METHOD})
public @interface CustomizeResponse { }

将上面定义的注释放在你的拦截器类上:

@Provider
@CustomizeResponse
public class CustomReaderInterceptor implements ReaderInterceptor {
    ...
}

要将拦截器分配给资源方法,请将上面定义的注释放在资源方法上:

@GET
@CustomizeResponse
@Produces(MediaType.APPLICATION_JSON)
public Response myMethod() {
    ...
}

名称绑定也可以应用于资源类。这意味着将为该资源类的所有资源方法执行拦截器:

@Path("/foo")
@CustomizeResponse
public class MyResource() {
    ...
}

请注意,全局过滤器和拦截器总是被执行,因此即使对于具有任何名称绑定注释的资源方法。

其他资源

有关拦截器的更多详细信息,请查看 Jersey documentation

【讨论】:

  • 这个question会给你一些关于如何注入ObjectMapper的说明。
  • 嗨,我想你误解了我的问题。我希望在调用我的 Web 服务之前在请求 JSON 消息中添加额外的字段。这样 Web 服务将获得额外的字段。您提出的是在响应中添加额外的字段,我已经知道该怎么做。
  • 你从上下文中得到一个 InputStream。那么我应该如何获取 JSON 消息并对其进行修改呢?之后,您将相同的 InputStream 设置为上下文,这对我来说似乎没有任何意义。你能举一个更详细的例子吗?
  • @user3573403 我用杰克逊的例子更新了我的答案。让我知道它是否适合您。
  • 谢谢。您的最新解决方案有效。这实际上可以使用 ContainerRequestFilter 而不是 ReaderInterceptor 来完成吗?
猜你喜欢
  • 1970-01-01
  • 2014-03-25
  • 1970-01-01
  • 2014-02-28
  • 2014-02-04
  • 1970-01-01
  • 2019-10-24
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多