是否可以在 REST 服务的"post()"方法中提取原始消息正文字符串(即 XML 字符串或 JSON 字符串)?



问题:
是否可以在REST服务的"post()"方法中提取原始消息正文字符串(即XML字符串或JSON字符串)

环境

Java 8

WebLogic 12.1.3(w/jax-rs(2.0,2.5.1)可部署库)

("request.getInputStream()"不会产生任何结果。。。似乎"read()"已经在"内部"应用。此外,不支持"mark()"或"reset()")

"post()"方法

package aaa.bbb.ccc;
import javax.ejb.Stateless;
import javax.ws.rs.*;
import javax.ws.rs.core.MediaType;
import aaa.bbb.ccc.fieldslist.FieldsList;
import java.io.*;
import java.net.URI;
import javax.ws.rs.core.*;
import javax.xml.bind.JAXBException;
import org.apache.commons.io.IOUtils;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
@Stateless
@Path("/fieldsList")
public class Testws {
private static final Logger LOG = LogManager.getLogger(Testws.class);
public Testws() {
}
@POST
@Consumes({MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON})
public Response post(@Context UriInfo uriInfo, @Context javax.servlet.http.HttpServletRequest request, FieldsList fieldsList) throws IOException, JAXBException, Exception {
try {
//...returns empty string...
String s = IOUtils.toString(request.getInputStream(), "UTF-8");
LOG.info("message string from request.getInputStream()=" + s); <==  empty string...
} catch (Exception e) {
e.printStackTrace();
}
URI uri = UriBuilder.fromUri(uriInfo.getRequestUri()).build();
Response response = Response.created(uri).build();
return response;
}
}

我曾尝试使用拦截器(请参阅"aroundReadFrom()"方法)在后()方法使用InputStream之前对其进行操作,但没有效果。。。-也就是说,在REST服务的post()方法中,request.getInputStream()继续不产生任何结果

"aroundReadFrom()"方法

package aaa.bbb.ccc;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import javax.ws.rs.WebApplicationException;
import javax.ws.rs.ext.Provider;
import javax.ws.rs.ext.ReaderInterceptor;
import javax.ws.rs.ext.ReaderInterceptorContext;
import org.apache.commons.io.IOUtils;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
@Provider
public class MyReaderInterceptor implements ReaderInterceptor {
static final Logger LOG = LogManager.getLogger(MyReaderInterceptor.class);
@Override
public Object aroundReadFrom(ReaderInterceptorContext ctx) throws IOException {
try {
InputStream is = ctx.getInputStream();
byte[] content = IOUtils.toByteArray(is);
is.close();
ctx.setInputStream(new ByteArrayInputStream(content));            
return ctx.proceed();            
} catch (IOException | WebApplicationException e) {
e.printStackTrace();
}
return null;
}
}

这是测试xml消息…:

<?xml version="1.0" encoding="UTF-8"?>
<FieldsList xmlns="http://aaa.bbb.ccc.ws/testws">
<Fields>
<FieldA>fieldA_value</FieldA>
<FieldB>fieldB_value</FieldB>
<FieldC>fieldC_value</FieldC>
</Fields>
</FieldsList>

这是模式:

<?xml version="1.0" encoding="UTF-8"?>
<xs:schema 
targetNamespace="http://aaa.bbb.ccc.ws/testws"
attributeFormDefault="unqualified"
elementFormDefault="qualified"
xmlns:tw="http://aaa.bbb.ccc.ws/testws"
xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:complexType name="FieldsType">
<xs:all>
<xs:element name="FieldA" type="xs:string" minOccurs="0" />            
<xs:element name="FieldB" type="xs:string" minOccurs="0" />            
<xs:element name="FieldC" type="xs:string" minOccurs="0" />                                                 
</xs:all>
</xs:complexType>
<xs:element name="FieldsList">
<xs:complexType>
<xs:sequence>
<xs:element name="Fields" type="tw:FieldsType" minOccurs="0" maxOccurs="unbounded" />
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:schema>

更新:

在post()方法中,我只能使用此技术重建消息字符串

StringWriter sw = new StringWriter();
JAXBContext.newInstance(FieldsList.class).createMarshaller().marshal(fieldsList, sw);
System.out.println("posted xml string=" + sw.toString());

。。。但是,如果以JSON格式发布相同的数据,这将没有帮助。为了澄清,它将把JSON post消息重构为XML字符串,而不是原始的JSON字符串

同样,我想做的是访问post()方法中原始发布的XML/JSON消息字符串

使用请求属性的解决方案-测试工作100%

@Provider
public class ContainerRequestFilterImpl implements ContainerRequestFilter {
@Context
private HttpServletRequest request;
@Override
public void filter(ContainerRequestContext ctx) throws IOException {
InputStream is = ctx.getEntityStream();
byte[] content = IOUtils.toByteArray(is);
// Store content as Request Attribute
request.setAttribute("content", new String(content, "UTF-8"));
ctx.setEntityStream(new ByteArrayInputStream(content));
}
}

AND
@POST
@Consumes({MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON})
public Response post(@Context UriInfo uriInfo, @Context HttpServletRequest request, FieldsList fieldsList) throws IOException, JAXBException, Exception {
try {
String s = request.getAttribute("postContent");
LOG.info("Post content: " + s);
} catch (Exception e) {
e.printStackTrace();
}
}

我认为您可以使用ReaderInterceptor而不是ContainerRequestFilter。它也应该起作用。

您可以只使用ReaderInterceptor。这是您可以获取原始数据的地方。你基本上需要从ReaderInterceptorContext中获得InputStream,读取它,然后你需要设置新的InputStream,因为原来的InputStream只能读取一次。因此,在读取原始流时需要使用一些缓冲策略

@Override
public Object aroundReadFrom(ReaderInterceptorContext context) {
InputStream ogStream = context.getInputStream();
// readStream with some buffer
// set new stream
context.setInputStream(bufferedStream);
return context.proceed();
}

另请参阅:

  • 过滤器和拦截器
  • JAX-RS2打印JSON请求。此示例用于客户端,但可以很容易地重构为使用服务器端过滤器(即Container(Request|Response)Filter

相关内容

最新更新