Java 从 servlet 中的查询结果返回 XML
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/3484185/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Returning XML from query result in servlet
提问by relyt
I'm trying to return an XML file based on my query results. I'm very new to this so I'm not really sure where I'm going wrong. Is this a realistic way to go about doing this or is there something simpler? Right now I'm getting these exceptions:
我正在尝试根据我的查询结果返回一个 XML 文件。我对此很陌生,所以我不确定我哪里出错了。这是一种现实的方法,还是有更简单的方法?现在我得到这些例外:
Error performing query: javax.servlet.ServletException: org.xml.sax.SAXParseException: Content is not allowed in prolog.
If I run my query in isql*plus, it does execute
如果我在 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;
}
}
}
Any help/tips would be appreciated.
任何帮助/提示将不胜感激。
采纳答案by BalusC
You're missing the prolog. Add this to beginning of your XML:
你错过了序言。将此添加到您的 XML 的开头:
<?xml version="1.0" encoding="UTF-8"?>
By the way, you don't need the SAX parser here. You aren't modifying the XML at all. Get rid of the parser and just write xml
directly to the response. You are also not handling JDBC resources correctly in try
-with-resources. Here's a basic example of the improvement:
顺便说一下,这里不需要 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>");
To write allrecords, just replace if (resultSet.next())
by while (resultSet.next())
.
要写入所有记录,只需替换if (resultSet.next())
为while (resultSet.next())
.
To handle the exception more gracefully, i.e. throwing an ServletException
which ends in an error page instead of a halfbaked XML, you'd like to build the XML using StringBuilder
. Just replace PrintWriter
by new StringBuilder()
and then at end, do response.getWriter().write(builder.toString())
.
为了更优雅地处理异常,即抛出以ServletException
错误页面结尾的 ,而不是半生不熟的 XML,您希望使用StringBuilder
. 只需替换PrintWriter
为new StringBuilder()
,然后在最后,做response.getWriter().write(builder.toString())
。
回答by Andrzej Doyle
What are you trying to accomplish here? This code looks very confusing for several reasons:
你想在这里完成什么?由于以下几个原因,这段代码看起来非常混乱:
- You're presumably trying to build up an XML string, but you're not appending any XML tags to it at all.
- There's a lotof no-ops in there, such as
xml = xml + "";
which doesn't achieve anything. - I'm not 100% sure what you want to achieve in the
try
block near the end. This block will have the side-effect of ensuring yourxml
string is valid XML, but if this is what you want to do there are probably clearer (and more efficient) ways of validating. If you're hoping it will magically transform your String into XML, then it won't (in fact no matter what, it can't modify the contents of thexml
variable so this would be a no-op.
- 您可能正在尝试构建一个 XML 字符串,但您根本没有向其附加任何 XML 标记。
- 那里有很多空操作,例如
xml = xml + "";
什么都没有实现。 - 我不是 100% 确定你想在
try
接近尾声的块中实现什么。此块将具有确保您的xml
字符串是有效 XML的副作用,但如果这是您想要做的,则可能有更清晰(更有效)的验证方法。如果您希望它能够神奇地将您的 String 转换为 XML,那么它不会(实际上无论如何,它都无法修改xml
变量的内容,因此这将是无操作的。
Perhaps it would help if you talked through what you're trying to do here, with particular reference to what you expect the state of affairs to be at each stage. Right now, you're building up a string that looks something like:
如果您详细说明您在此处尝试执行的操作,并特别提及您期望每个阶段的事态状况,也许会有所帮助。现在,您正在构建一个类似于以下内容的字符串:
FirstSaleIDFirstHomeFirstAgentFirstCustomerSecondSaleIDSecondHomeSecondAgentSecondCustomer...
Then you try to parse this as XML. As you might expect, this is not valid XML hence the parser throws the error (in particular "no content in prolog" means that you have character data before the first tag definition).
然后您尝试将其解析为 XML。正如您所料,这不是有效的 XML,因此解析器会抛出错误(特别是“序言中没有内容”意味着您在第一个标签定义之前有字符数据)。
I would give you advice on how to improve this but I really have no idea what you expect this to do...
我会给你关于如何改进这一点的建议,但我真的不知道你期望它做什么......
回答by duffymo
One tip would be layering your code a bit more. Servlets shouldn't be importing from java.sql. Put that code in a separate class, test it, and let your servlet call its methods.
一个技巧是将您的代码分层一点。不应从 java.sql 导入 Servlet。将该代码放在一个单独的类中,对其进行测试,然后让您的 servlet 调用它的方法。
You're creating XML in the most brain dead way possible by concatentating strings that way. Why not use a library like JDOM or at least a StringBuilder?
通过以这种方式连接字符串,您正在以最脑残的方式创建 XML。为什么不使用像 JDOM 这样的库或至少是 StringBuilder?
And skaffman's right: your code makes no sense otherwise.
斯卡夫曼是对的:否则你的代码毫无意义。
Here are a few ideas you can think about for layering. Start with a model object for Sale - after all, Java's an object-oriented language:
这里有一些你可以考虑的分层想法。从销售的模型对象开始 - 毕竟,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 + '\'' +
'}';
}
}
For persistence, start with a DAO interface:
对于持久性,从 DAO 接口开始:
package badservlet.persistence;
import badservlet.model.Sale;
import java.sql.SQLException;
import java.util.List;
public interface SaleDao
{
List<Sale> find() throws SQLException;
}
And its implementation:
及其实现:
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;
}
}
And an object-to-XML unmarshaller:
还有一个对象到 XML 的解组器:
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;
}
}
Let your servlet instantiate these objects and call their methods.
让您的 servlet 实例化这些对象并调用它们的方法。
It might look more complicated - more classes than just one - but you've accomplished two things: you've broken your problem down into smaller pieces, and you can test them separately.
它可能看起来更复杂——更多的类而不仅仅是一个——但是你已经完成了两件事:你已经把你的问题分解成更小的部分,你可以单独测试它们。
回答by Damian Leszczyński - Vash
If we assume that this values you retrive form database
如果我们假设您从数据库中检索此值
|sale_id | home_id | agent_id | customer_id |
| 1 | 10 | 100 | 1000 |
| 2 | 20 | 200 | 2000 |
| 3 | 30 | 300 | 3000 |
the xml a the end look like this
xml 最终看起来像这样
1010100100020003000
And after all You are tying to create a XML file from this.
毕竟,您要从中创建一个 XML 文件。
What You should read about:
您应该阅读的内容:
First about the ResultSet, i really doubt that those id are string not numbers. next the class StringBuilder, the way you concat strings is wrong because strings is inmutable. And for sure you should look about the Java API for XML
首先关于ResultSet,我真的怀疑那些 id 是字符串而不是数字。接下来是StringBuilder类,连接字符串的方式是错误的,因为字符串是不可变的。当然,您应该查看Java API for XML
回答by YoK
Rather than using String concatanation for building XML, Trying using XML API's like DOM, JDOMetc.
与其使用字符串连接来构建 XML,不如尝试使用 XML API,如DOM、JDOM等。
Few Tutorial links:
几个教程链接:
http://www.w3schools.com/dom/default.asp
http://www.w3schools.com/dom/default.asp