我一直试图找到一个'参考'示例,用于从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:任何有效载荷类型都会使事情变得更复杂)。
答案 0 :(得分:1)
查看JAX-RS
<{1}}框架,如Jersey
手动执行序列化作业通常是矫枉过正。
答案 1 :(得分:1)
如果您希望提高速度,可以查看SAX的StAX(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);
}
}