Rest 是否可以提取“文本”中的原始消息正文字符串(即XML字符串或JSON字符串);post();休息服务的方法?

Rest 是否可以提取“文本”中的原始消息正文字符串(即XML字符串或JSON字符串);post();休息服务的方法?,rest,java-8,jax-rs,weblogic12c,stateless-session-bean,Rest,Java 8,Jax Rs,Weblogic12c,Stateless Session Bean,问题: 是否可以在REST服务的“post()”方法中提取原始消息体字符串(即XML字符串或JSON字符串) 环境 爪哇8 WebLogic 12.1.3(带jax rs(2.0,2.5.1)可部署库) (request.getInputStream()不会产生任何结果…似乎“read()”已“内部”应用。此外,“mark()”或“reset()”不受支持) “post()”方法… package aaa.bbb.ccc; import javax.ejb.Stateless;

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

环境

爪哇8

WebLogic 12.1.3(带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;
        }
    }
    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>
…但是,如果相同的数据以JSON格式发布,这将没有帮助。为了澄清,它将把JSON post消息重构为XML字符串,而不是原始JSON字符串

同样,我想做的是在post()方法中访问原始发布的XML/JSON消息字符串,您可以使用。这是您可以获取原始数据的地方。基本上,您需要从
读取器接口上下文
获取
输入流
,读取它,然后需要设置新的
输入流
,因为原始的
输入流
只能读取一次。因此,在读取原始流时,需要使用一些缓冲策略

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

    <?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>
  • 。此示例用于客户端,但可以很容易地进行重构以使用服务器端过滤器(即
    容器(请求|响应)过滤器

使用请求属性的解决方案-测试工作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。它也应该可以工作。

谢谢您,peeskillet。我正在寻找一种方法,提取REST服务中发生异常时发布的原始XML/JSON字符串。换句话说,我想记录发布的请求正文(XML或JSON字符串)在try catch块中(在post()方法中)发生异常时(如果有意义的话)。不幸的是,request.getInputStream()此时为“空”。再次感谢!删除bais.reset();应该可以工作!Hi Loc-我当然可以获得“aroundReadFrom”中的原始消息字符串但是,在“post()”方法中,“request.getInputStream()”仍然不会产生原始消息字符串的值…-也就是说,调用“IOUtils.toString(request.getInputStream(),“UTF-8”)”只返回一个空字符串…-正如我所指出的,“mark()”和“reset()”方法对于通过在“post()中调用“request.getInputStream()”返回的ServletInputStream对象不可用方法。因此,我无法操纵指针。Hi Loc,thx,感谢您的努力。我已经知道了这个替代方法。但是,我试图从InputStream派生/提取原始消息字符串,而不是通过在请求属性中创建副本来复制/加倍请求对象的大小。我将处理非常大的消息s、 注意:如果事实证明这是不可能的,那么这也是一个有效的“答案”。只需要一些支持文档参考就可以了。thx!@sairm:“在请求属性中复制”?没有请求属性的副本。它们引用的是相同的内容对象内存。内容字符串内存仅在此处创建了一次。啊!…-似乎正在创建一个新的“byte[]”对象,该对象是使用“request.getEntityStream()”填充的。然后,使用“byte[]”的内容创建了一个新的“string()”对象然后,新的“String()”对象存储在请求对象的属性映射中。您确定没有新字节(即字符串大小)添加到请求对象吗?我只是想确保我理解。thx!“您确定没有新字节(即字符串大小)添加到请求对象吗?”---是的。您混淆了对象内存分配和对象引用。引用不会导致新的内存分配,它只是指向现有的对象内存。K,谢谢,Loc!我拒绝了此解决方案,因为我认为将消息字符串添加到请求对象的属性映射会增加请求对象的大小。很明显我错了!:-)-我会检查你的答案。谢谢!