从POST到http servlet读取xml的推荐/最快方法是什么?

时间:2013-10-25 10:19:43

标签: java xml servlets

我一直试图找到一个'参考'示例,用于从http servlet读取xml输入的最快/可接受的方式,但似乎无法找到明确的答案。

以下是上下文:我们有一个已有12年历史的应用程序,它在生产中运行良好,但我想看看我们是否错过了一个技巧并且可以让它更快。

它接受由xml组成的发布请求(请参阅帖子底部的schema和示例xml),并使用JAXB 1.0将其编组到java对象,然后根据请求ID找到请求处理器,然后处理请求并写下回复。

我对String操作的数量有点怀疑,我想也许我们应该使用更多的缓冲读取器/写入器,可能是扫描器,以及任何其他“新”(即比java 1.2更新... )功能。

以下是目前处理请求的粗略摘要:

public void doPost(HttpServletRequest request, HttpServletResponse response)
        throws ServletException, IOException {
try {
    InputStream is = request.getInputStream();
    InputStreamReader reader = new InputStreamReader( is ); 
    char[] buffer = new char[4096]; 
    StringWriter writer = new StringWriter(); 
    int bytes_read; 
    try
    {    //manual bufferering - can't we just use request.getReader() ?
        while ((bytes_read = reader.read(buffer)) != -1) { 
            writer.write(buffer, 0, bytes_read); 
        } 
    }
    catch(IOException e)
    {
        throw new RuntimeException("Unable to read the inputstream.  Please try again.");
    }

    String xml = writer.toString();
    //now we look for the payload and extract it:
    String tag = "payload";
    String header = null;
 String body = null;
 String innerPayload = null;
 String footer = null;
  int start = xml.indexOf("<" + tag);
    if(start < 0)
        throw new RuntimeException("Start tag \"" + tag + "\" was not found in the xml.");

    int end = xml.indexOf("</" + tag + ">");
    if(end < 0)
        throw new RuntimeException("End tag \"" + tag + "\" was not found in the xml.");

    int closeStart = xml.indexOf(">", start);
    int closeEnd = xml.indexOf(">", end);

    if(xml.charAt(closeStart - 1)=='/')
    {
        body = xml.substring(start,  closeStart + 1);
        innerPayload = null;
        header = xml.substring(0, closeStart + 1);
        footer = xml.substring(closeStart + 1, xml.length());
    }
    else
    {
        body = xml.substring(start, closeEnd + 1);
        innerPayload = xml.substring(closeStart + 1, end);
        header = xml.substring(0, closeStart + 1);
        footer = xml.substring(end, xml.length());
    }
FsRequest envelope;     
Object xml = JAXBRequestHelper.bind(header + footer);

        if(xml instanceof FsRequest)
            envelope = (FsRequest) xml;
        else
            throw new RuntimeException("Invalid XML request.");
Object payloadType = JAXBRequestHelper.bind(innerPayload);
//because the payload type is xs:any, I don't think we can avoid a cast here
//in this case, it's a purchase:
Purchase purchase = (Purchase) payloadType
//request processor then handles the purchase using purchase.getMsisdn(), etc

示例xml请求可能如下所示:

<?xml version="1.0" encoding="UTF-8"?>
 <fs-request id="100004"purchase_locale="en_GB">
  <payload>
   <purchase>
    <msisdn>13435456456</msisdn>
    <package-id>package123</package-id>
   </purchase>
  </payload>
</fs-request>

xsd的定义也有点特殊。 'payload'被定义为xs:any使得编组更加棘手:

 <xs:element name="fs-request">
    <xs:complexType>
        <xs:sequence>
            <xs:element name="payload" type="common:payloadType" minOccurs="0"/>    
        </xs:sequence>


<xs:complexType name="payloadType">
    <xs:sequence>
        <xs:any processContents="skip" minOccurs="0" />
    </xs:sequence>
</xs:complexType>

这只是我还是这段代码有点乱?如果是这样,是否有一种明显的方法可以使它更清洁/更快?我很乐意看到一个参考示例(尽管xs:任何有效载荷类型都会使事情变得更复杂)。

3 个答案:

答案 0 :(得分:1)

查看JAX-RS <{1}}框架,如Jersey

手动执行序列化作业通常是矫枉过正。

答案 1 :(得分:1)

如果您希望提高速度,可以查看SAXStAX(XML的简易API)(XML的流式API)。它们不需要在内存中加载整个文件来像DOM解析器那样解析它。

但使用它们是乏味的(特别是SAX)。我建议先检查一下易于使用的库,如JAXB(Java Architecture for XML Binding)。 JAXB可以为您的任务提供可接受的速度,同时提供更大的灵活性。

答案 2 :(得分:0)

如果您确实希望使用标准JRE库以手动方式执行此操作,则可以使用此方法。

你必须考虑潜在的XML威胁。

@Override
public void service(ServletRequest request, ServletResponse response)
        throws ServletException, IOException {
    try{
        HttpServletRequest hReq = (HttpServletRequest) request;
        if (hReq.getMethod().equalsIgnoreCase("POST") && hReq.getContentType().equals("text/xml")){
            // 1. Create XML doc from input         
            logger.debug("1. create XML content from input");
            DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
            factory.setNamespaceAware(true);
            DocumentBuilder documentBuilder = factory.newDocumentBuilder();
            Document doc = documentBuilder.parse(hReq.getInputStream());
            // 2. Do your stuff with the Doc e.g. use doc.getDocumentElement()));

        } else {
            HttpServletResponse hResponse = (HttpServletResponse) response;
            // Only HTTP POST is supported
            hResponse.sendError(500, "Unsupported");
        }
    } catch (Exception e) {
        logger.fatal(e,e);
        throw new ServletException(e);
    }
}