【问题标题】:How to deal with input parameter in CXF request handler in general?一般如何处理 CXF 请求处理程序中的输入参数?
【发布时间】:2012-06-01 13:48:02
【问题描述】:

我一直在使用 apache CXF(2.2.2 版)JAX-RS 做一些工作。我试图在调用业务方法之前在 CXF 请求处理程序中引入数据验证层。幸运的是:),我在请求处理程序(DataValidationHandler)中遇到输入参数处理问题。我可以按照请求处理程序中的代码行手动读取 JSON 对象。但它与在 CXF 框架中注册的 JSONProvider 重复。因为 JSON 对象输入流只能读取一次,否则会遇到异常“java.io.EOFException: No content to map to Object due to input end”。此外,重复的 JSON 对象反序列化会影响性能。以下代码是供您参考的示例。

手动从 HTTP 正文读取 JSON 对象:

OperationResourceInfo ori = paramMessage.getExchange().get(OperationResourceInfo.class);
MultivaluedMap<String, String> values = new MetadataMap<String, String>();
List<Object> objList = JAXRSUtils.processParameters(ori, values, paramMessage);

在 CXF JAX-RS 框架中注册 JSONProvider:

<bean id="JSONProvider" class="com.accela.govxml2.jaxrs.util.JSONProvider"></bean>

从输入流中读取 JSON 对象到 Java 对象:

public Object readFrom(......){
    ObjectMapper objectMapper = new ObjectMapper();
    Object result = objectMapper.readValue(entityStream, TypeFactory.defaultInstance().constructType(genericType));
    Return result;
}

我正在通过以下代码行手动处理路径参数。

OperationResourceInfo ori = paramMessage.getExchange().get(OperationResourceInfo.class);
URITemplate t1 = ori.getClassResourceInfo().getURITemplate();
URITemplate t2 = ori.getURITemplate();
UriInfo uriInfo = new UriInfoImpl(paramMessage, null);
MultivaluedMap<String, String> map = new MetadataMap<String, String>();
t1.match(uriInfo.getPath(), map);
String str = map.get(URITemplate.FINAL_MATCH_GROUP).get(0);
t2.match(str, map);
String pathParameter= null;
if (map.containsKey("pathParam") && !ValidationUtil.isEmpty(map.get("pathParam")))
{
    pathParameter= map.get("pathParam").get(0);
}

我的问题在这里:

  1. 在请求处理程序中一般如何处理http body的POST/PUT输入参数?
  2. 如何避免性能问题以高效读取输入参数?
  3. 有没有办法在 CXF(JSONProvider) 读取参数和业务方法调用之间注入验证(处理程序/拦截器)层?
  4. 有什么优雅的方式来处理路径参数吗?

感谢您的帮助。任何 cmets 和建议将不胜感激。

问候, 迪伦

【问题讨论】:

    标签: java rest cxf jax-rs cxfrs


    【解决方案1】:

    经过研究,我可以根据以下问题的答案(Read stream twice)读取输入流两次。

    然而,JSON 对象反序列化性能仍然是我关心的问题。谁有更好的解决方案?

    拦截请求并将消息内容从 CoyoteInputStream 更改为 ByteArrayInputStream,这样我就可以读取 InputStream 两次。

    InputStream in = message.getContent(InputStream.class);
    if (in != null)
    {
        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        IOUtils.copy(in, baos);
        byte[] bytes = baos.toByteArray();
        ByteArrayInputStream bais = new ByteArrayInputStream(bytes);
        message.setContent(InputStream.class, bais);
    }
    

    在从输入流中读取 JSON 对象到 Java 对象之前重置 ByteArrayInputStream:

    public Object readFrom(......){
        ObjectMapper objectMapper = new ObjectMapper();
        if (entityStream.markSupported())
        {
            entityStream.reset();
        }
        Object result = objectMapper.readValue(entityStream, TypeFactory.defaultInstance().constructType(genericType));
        return result;
    }
    

    【讨论】:

      【解决方案2】:

      我找到了另一种将 DataValidation Interceptor 注入读取参数阶段的方法。我们可以重用来自消息内容的反序列化输入模型,这些模型由框架中注册的 JSONProvider 进行反序列化。它可以提高性能,因为只需反序列化输入模型一次。

      public class DataValidationInInterceptor extends AbstractPhaseInterceptor<Message>
      {
      public DataValidationInInterceptor()
      {
          super(Phase.READ);
      }
      
      @Override
      public void handleMessage(Message message)
      {
          OperationResourceInfo ori = message.getExchange().get(OperationResourceInfo.class);
          Method method = ori.getMethodToInvoke();
          Class<?>[] types = method.getParameterTypes();
          Type[] genericParameterTypes = method.getGenericParameterTypes();
      
          for (int i = 0; i < types.length; i++)
          {
              Class<?> type = types[i];
              List obj = (List) message.getContent(List.class);
              System.out.println(obj);
              System.out.println(type);
          }
      }
      }
      

      【讨论】:

      • 实际上这应该是 pre_invoke 阶段,因为 OperationResourceInfo 尚未构建。
      猜你喜欢
      • 1970-01-01
      • 2023-01-18
      • 2022-07-01
      • 1970-01-01
      • 1970-01-01
      • 2022-01-21
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多