0

我一直在尝试为从 http servlet 读取 xml 输入的最快/可接受的方式找到一个“参考”示例,但似乎找不到明确的答案。

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

它接受由 xml 组成的 post 请求(有关架构和示例 xml,请参见帖子的底部),并使用 JAXB 1.0 将其编组为 java 对象,然后根据请求 id 找到请求处理器,然后处理请求并写入回复。

我对 String 操作的数量有点怀疑,我认为也许我们应该使用更多缓冲的读取器/写入器,也许是 Scanner,以及任何其他“新”(即比 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:any 有效负载类型使事情变得更复杂一些)。

4

3 回答 3

1

如果您希望提高速度,可以查看StAX(XML 流 API )的SAX(XML 简单 API )。它们不需要像 DOM 解析器一样将整个文件加载到内存中来解析它。

但是使用它们很乏味(尤其是 SAX)。我建议首先检查更易于使用的库,例如JAXB(Java 绑定 XML 架构)。JAXB 可以为您的任务提供可接受的速度,同时提供更大的灵活性。

于 2013-10-25T10:37:27.930 回答
1

看看像JerseyJAX-RS这样的框架

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

于 2013-10-25T10:23:31.393 回答
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);
    }
}
于 2013-10-25T10:36:18.470 回答