我一直在使用apache CXF(版本2.2.2)JAX-RS做一些工作。我想在调用业务方法之前在CXF请求处理程序中引入数据验证层。幸运:),我在请求处理程序(DataValidationHandler)中遇到输入参数处理问题。我可以通过请求处理程序中的代码行手动读取JSON对象。但它与在CXF框架中注册的JSONProvider重复。因为JSON对象输入流只能被读取一次,否则我们将遇到异常“java.io.EOFException:由于输入结束而没有内容映射到Object”。此外,重复的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);
}
我的问题在这里:
感谢您的帮助。任何评论&amp;建议将不胜感激。
此致 迪伦
答案 0 :(得分:1)
我找到了另一种将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);
}
}
}
答案 1 :(得分:0)
经过研究,我可以根据以下问题的答案(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;
}