[英]Returning XML from query result in servlet
我正在尝试根据查询结果返回XML文件。 我对此很新,所以我不确定自己哪里出错了。 这是一种现实的方式来做这件事还是有更简单的事情? 现在我得到这些例外:
Error performing query: javax.servlet.ServletException: org.xml.sax.SAXParseException: Content is not allowed in prolog.
如果我在isql * plus中运行我的查询,它确实执行
import java.io.*;
import java.util.*;
import java.sql.*; // JDBC packages
import javax.servlet.*;
import javax.servlet.http.*;
import javax.xml.parsers.*;
import org.xml.sax.*;
import org.xml.sax.helpers.*;
public class step5 extends HttpServlet {
public static final String DRIVER = "sun.jdbc.odbc.JdbcOdbcDriver";
public static final String URL = "jdbc:odbc:rreOracle";
public static final String username = "cm485a10";
public static final String password = "y4e8f7s5";
SAXParserFactory factory;
public void init() throws ServletException {
factory = SAXParserFactory.newInstance();
}
public void doGet (HttpServletRequest request,
HttpServletResponse response)
throws ServletException, IOException
{
PrintWriter out = response.getWriter();
Connection con = null;
try {
Class.forName(DRIVER);
con = DriverManager.getConnection(URL,username,password);
try {
Statement stmt = con.createStatement();
ResultSet rs = stmt.executeQuery("SELECT sale_id, home_id, agent_id, customer_id FROM sale");
String xml = "";
xml = xml + "<sales_description>";
xml = xml + "<sale>";
boolean courseDataDone = false;
while (rs.next()) {
String sale_id = rs.getString(1);
String home_id = rs.getString(2);
String agent_id = rs.getString(3);
String customer_id = rs.getString(4);
if (!courseDataDone) {
xml = xml + "<sale_id>" + sale_id + "</sale_id>" +
"<home_id>" + home_id + "</home_id>" +
"<agent_id>" + agent_id + "</agent_id>" +
"<customer_id>" + customer_id + "</customer_id>" +
"" +
"";
courseDataDone = true;
}
}
xml = xml + "</sale>" +
"</sales_description>";
try {
SAXParser parser = factory.newSAXParser();
InputSource input = new InputSource(new StringReader(xml));
parser.parse(input, new DefaultHandler());
} catch (ParserConfigurationException e) {
throw new ServletException(e);
} catch (SAXException e) {
throw new ServletException(e);
}
response.setContentType("text/xml;charset=UTF-8");
out.write(xml);
} catch(Exception ex) {
out.println("Error performing query: " + ex);
con.close();
return;
}
} catch(Exception ex) {
out.println("Error performing DB connection: " + ex);
return;
}
}
}
任何帮助/提示将不胜感激。
你错过了这个序幕。 将其添加到XML的开头:
<?xml version="1.0" encoding="UTF-8"?>
顺便说一下,这里不需要SAX解析器。 您根本没有修改XML。 摆脱解析器,直接将xml
写入响应。 您还没有在try
-with-resources中正确处理JDBC 资源 。 以下是改进的基本示例:
response.setContentType("text/xml;charset=UTF-8");
PrintWriter writer = response.getWriter();
writer.append("<?xml version=\"1.0\" encoding=\"UTF-8\"?>");
writer.append("<sales_description>");
try (
Connection connection = dataSource.getConnection();
Statement statement = connection.createStatement();
ResultSet resultSet = statement.executeQuery("SELECT sale_id, home_id, agent_id, customer_id FROM sale");
) {
if (resultSet.next()) {
writer.append("<sale>");
writer.append("<sale_id>").append(resultSet.getString("sale_id")).append("</sale_id>");
writer.append("<home_id>").append(resultSet.getString("home_id")).append("</home_id>");
writer.append("<agent_id>").append(resultSet.getString("agent_id")).append("</agent_id>");
writer.append("</sale>");
}
} catch (SQLException e) {
throw new ServletException(e);
}
writer.append("</sales_description>");
要编写所有记录,只需用while (resultSet.next())
替换if (resultSet.next())
while (resultSet.next())
。
为了更优雅地处理异常,即抛出一个以错误页面而不是半熟的XML结尾的ServletException
,您希望使用StringBuilder
构建XML。 只需用new StringBuilder()
替换PrintWriter
,然后在最后,执行response.getWriter().write(builder.toString())
。
一个提示是将代码分层一些。 Servlet不应该从java.sql导入。 将该代码放在一个单独的类中,对其进行测试,并让您的servlet调用其方法。
你通过这种方式串联字符串,以最大脑死亡的方式创建XML。 为什么不使用像JDOM这样的库或至少使用StringBuilder?
而且skaffman是对的:否则你的代码毫无意义。
以下是您可以考虑分层的一些想法。 从销售模型对象开始 - 毕竟,Java是一种面向对象的语言:
package badservlet.model;
public class Sale
{
private String saleId;
private String homeId;
private String agentId;
private String customerId;
public Sale(String saleId, String homeId, String agentId, String customerId)
{
if ((saleId == null) || (saleId.trim().length() == 0)
throw new IllegalArgumentException("sales id cannot be blank or null");
if ((homeId == null) || (homeId.trim().length() == 0)
throw new IllegalArgumentException("home id cannot be blank or null");
if ((agentId == null) || (agentId.trim().length() == 0)
throw new IllegalArgumentException("agent id cannot be blank or null");
if ((customerId == null) || (customerId.trim().length() == 0)
throw new IllegalArgumentException("customer id cannot be blank or null");
this.saleId = saleId;
this.homeId = homeId;
this.agentId = agentId;
this.customerId = customerId;
}
public String getSaleId()
{
return saleId;
}
public String getHomeId()
{
return homeId;
}
public String getAgentId()
{
return agentId;
}
public String getCustomerId()
{
return customerId;
}
@Override
public String toString()
{
return "Sale{" +
"saleId='" + saleId + '\'' +
", homeId='" + homeId + '\'' +
", agentId='" + agentId + '\'' +
", customerId='" + customerId + '\'' +
'}';
}
}
对于持久性,从DAO接口开始:
package badservlet.persistence;
import badservlet.model.Sale;
import java.sql.SQLException;
import java.util.List;
public interface SaleDao
{
List<Sale> find() throws SQLException;
}
它的实施:
package badservlet.persistence;
import badservlet.model.Sale;
import javax.sql.DataSource;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.ArrayList;
import java.util.List;
public class SaleDaoImpl implements SaleDao
{
private static final String SELECT_ALL_SQL = "SELECT sale_id, home_id, agent_id, customer_id FROM sale";
private Connection connection;
public SaleDaoImpl(Connection connection)
{
this.connection = connection;
}
public SaleDaoImpl(DataSource dataSource) throws SQLException
{
this(dataSource.getConnection());
}
public List<Sale> find() throws SQLException
{
List<Sale> allSales = new ArrayList<Sale>();
Statement st = null;
ResultSet rs = null;
try
{
st = this.connection.createStatement();
rs = st.executeQuery(SELECT_ALL_SQL);
while (rs.next())
{
String saleId = rs.getString("sale_id");
String homeId = rs.getString("home_id");
String agentId = rs.getString("agent_id");
String customerId = rs.getString("customer_id");
Sale sale = new Sale(saleId, homeId, agentId, customerId);
allSales.add(sale);
}
}
catch (SQLException e)
{
e.printStackTrace();
}
finally
{
try { if (rs != null) rs.close(); } catch (SQLException e) { e.printStackTrace(); }
try { if (st != null) st.close(); } catch (SQLException e) { e.printStackTrace(); }
}
return allSales;
}
}
和一个对象到XML的unmarshaller:
package badservlet.xml;
import badservlet.model.Sale;
import org.jdom.Document;
import org.jdom.Element;
import org.jdom.transform.JDOMResult;
import javax.xml.bind.JAXBException;
import javax.xml.transform.Result;
import java.util.List;
public class SaleUnmarshaller
{
public void unmarshal(Object object, Result xml) throws JAXBException
{
List<Sale> allSales = (List<Sale>) object;
Document document = new Document(new Element("sales"));
for (Sale sale : allSales)
{
Element child = new Element("sale");
child.setAttribute("id", sale.getSaleId());
child.addContent(new Element("home", sale.getHomeId()));
child.addContent(new Element("agent", sale.getAgentId()));
child.addContent(new Element("customer", sale.getCustomerId()));
document.addContent(child);
}
JDOMResult result = new JDOMResult();
result.setDocument(document);
xml = result;
}
}
让您的servlet实例化这些对象并调用它们的方法。
它可能看起来更复杂 - 更多的课程而不仅仅是一个 - 但你已经完成了两件事:你已经将问题分解成更小的部分,你可以单独测试它们。
你想在这里完成什么? 此代码看起来很混乱,原因如下:
xml = xml + "";
这没有任何成就。 try
块中实现什么。 这个块会产生副作用,确保你的xml
字符串是有效的XML,但如果这是你想要做的,那么可能有更清晰(和更有效)的验证方法。 如果您希望它会将您的String神奇地转换为XML,那么它就不会(事实上无论如何,它都无法修改xml
变量的内容,因此这将是一个无操作。 如果你在这里谈论你想要做的事情,或许特别提到你对每个阶段的状况的期望,这可能会有所帮助。 现在,您正在构建一个类似于以下内容的字符串:
FirstSaleIDFirstHomeFirstAgentFirstCustomerSecondSaleIDSecondHomeSecondAgentSecondCustomer...
然后尝试将其解析为XML。 正如您所料,这不是有效的XML,因此解析器会抛出错误(特别是“prolog中没有内容”意味着您在第一个标记定义之前有字符数据)。
我会就如何改进这个问题给你建议,但我真的不知道你期望做什么......
而不是使用String concatanation来构建XML,尝试使用XML API,如DOM , JDOM等。
几个教程链接:
如果我们假设这个值你从表单数据库中检索
|sale_id | home_id | agent_id | customer_id |
| 1 | 10 | 100 | 1000 |
| 2 | 20 | 200 | 2000 |
| 3 | 30 | 300 | 3000 |
xml的结尾看起来像这样
1010100100020003000
毕竟你想要从中创建一个XML文件。
您应该阅读的内容:
首先关于ResultSet ,我真的怀疑那些id是字符串而不是数字。 接下来是StringBuilder类,你串联字符串的方式是错误的,因为字符串是不可变的。 当然,您应该查看Java API for XML
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.