在 JAX-RS Web 服务过滤器中获取 JSON 消息



我有一个如下的Web服务方法(部署在WebLogic 12.2.1上),我可以在POJO对象"requestParameters"中接收JSON请求正文:

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

我有一个过滤器,我想在调用上述 Web 服务方法之前拦截请求。

@Provider
@SessionChecker
public class CheckSessionFilter implements ContainerRequestFilter {
    @Context
    private HttpServletRequest servletRequest;
    @Override
    public void filter(ContainerRequestContext requestContext) throws WebApplicationException {
        ....
    }
}

在 filter() 方法中,如何将 JSON 消息正文获取到参数类型的 POJO 对象中?我只需要从 JSON 消息中获取一个属性。筛选器完成后,JSON 消息应传递到 Web 服务方法,而无需更改。

提前谢谢。

这就是问题所在。命中筛选器时,尚未读取请求流 ( InputStream )。因此,如果您尝试读取它,那么泽西岛将无法读取它,因为流只能读取一次,因此它将是空的。

泽西岛实际上为此提供了一个解决方案。ContainerRequestContext,其实是泽西岛特有的ContainerRequest的实例。如果您查看链接的 API,您会发现一个bufferEntity()方法。这使我们能够读取实体,泽西岛将能够再次读取它。所以你的第一步是打这个电话

@Override
public void filter(ContainerRequestContext requestContext)
    ContainerRequest cr = (ContainerRequest) requestContext;
    cr.bufferEntity();
}

现在,您可以获取实体。如果你看一下 API for ContainerRequest ,也有方法可以readEntity(..)。如果您熟悉 JAX-RS 客户机 API,那么之前可能已经使用Response#readEntity(...class)来读取响应实体。ContainerRequest#readEntity(..)的工作方式几乎相同。

因此,如果您知道JSON格式应该是什么,并且您有POJO,则可以这样做。

POJO pojo = cr.readEntity(POJO.class);

否则,如果格式因请求而异,则可以将数据提取为地图

Map<String, Object> json = cr.readEntity(new GenericType<Map<String, Object>>(){});
<小时 />

更新

如果您使用的是 JAX-RS API,而不是特定于 Jersey 的 API,则上述操作不可行。相反,您需要读取流以获取 JSON,并将流设置回来,以便 Jersey 可以读取它。如果可能看起来像

InputStream entityIn = requestContext.getEntityStream();
ByteArrayOutputStream baos = new ByteArrayOutputStream();
// write `entityIn` to `baos`
byte[] bytes = baos.toByteArray();
POJO pojo = new ObjectMapper().readValue(bytes, POJO.class);
// do something with POJO
requestContext.setEntityStream(new ByteArrayInputStream(bytes));

当然,您需要一些 JSON 反序列化程序来执行此操作。我只是在例子中使用了杰克逊。

它不像第一个示例那样优雅,但是如果您严格遵循 JAX-RS API,则没有太多选择。如果可以的话,我建议按照提供的方式将 Jersey 依赖项添加到您的项目中(编译时),以便您可以使用 API,因为无论如何您都在将 Jersey 与 WebLogic 一起使用。

最新更新