我一直在尝试为从 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 有效负载类型使事情变得更复杂一些)。