简体   繁体   English

从servlet中的查询结果返回XML

[英]Returning XML from query result in servlet

I'm trying to return an XML file based on my query results. 我正在尝试根据查询结果返回XML文件。 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: 现在我得到这些例外:

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. 任何帮助/提示将不胜感激。

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. 顺便说一下,这里不需要SAX解析器。 You aren't modifying the XML at all. 您根本没有修改XML。 Get rid of the parser and just write xml directly to the response. 摆脱解析器,直接将xml写入响应。 You are also not handling JDBC resources correctly in try -with-resources . 您还没有在try -with-resources中正确处理JDBC 资源 Here's a basic example of the improvement: 以下是改进的基本示例:

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 all records, just replace if (resultSet.next()) by while (resultSet.next()) . 要编写所有记录,只需用while (resultSet.next())替换if (resultSet.next()) while (resultSet.next())

To handle the exception more gracefully, ie throwing an ServletException which ends in an error page instead of a halfbaked XML, you'd like to build the XML using StringBuilder . 为了更优雅地处理异常,即抛出一个以错误页面而不是半熟的XML结尾的ServletException ,您希望使用StringBuilder构建XML。 Just replace PrintWriter by new StringBuilder() and then at end, do response.getWriter().write(builder.toString()) . 只需用new StringBuilder()替换PrintWriter ,然后在最后,执行response.getWriter().write(builder.toString())

One tip would be layering your code a bit more. 一个提示是将代码分层一些。 Servlets shouldn't be importing from java.sql. Servlet不应该从java.sql导入。 Put that code in a separate class, test it, and let your servlet call its methods. 将该代码放在一个单独的类中,对其进行测试,并让您的servlet调用其方法。

You're creating XML in the most brain dead way possible by concatentating strings that way. 你通过这种方式串联字符串,以最大脑死亡的方式创建XML。 Why not use a library like JDOM or at least a StringBuilder? 为什么不使用像JDOM这样的库或至少使用StringBuilder?

And skaffman's right: your code makes no sense otherwise. 而且skaffman是对的:否则你的代码毫无意义。

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的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;
    }
}

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. 它可能看起来更复杂 - 更多的课程而不仅仅是一个 - 但你已经完成了两件事:你已经将问题分解成更小的部分,你可以单独测试它们。

What are you trying to accomplish here? 你想在这里完成什么? This code looks very confusing for several reasons: 此代码看起来很混乱,原因如下:

  1. You're presumably trying to build up an XML string, but you're not appending any XML tags to it at all. 您可能正在尝试构建XML字符串,但您根本不会向其添加任何XML标记。
  2. There's a lot of no-ops in there, such as xml = xml + ""; 那里有很多无操作,例如xml = xml + ""; which doesn't achieve anything. 这没有任何成就。
  3. I'm not 100% sure what you want to achieve in the try block near the end. 我不是100%肯定你想要在接近结束的try块中实现什么。 This block will have the side-effect of ensuring your xml string is valid XML, but if this is what you want to do there are probably clearer (and more efficient) ways of validating. 这个块会产生副作用,确保你的xml字符串是有效的XML,但如果这是你想要做的,那么可能有更清晰(和更有效)的验证方法。 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 the xml variable so this would be a no-op. 如果您希望它会将您的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. 然后尝试将其解析为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,因此解析器会抛出错误(特别是“prolog中没有内容”意味着您在第一个标记定义之前有字符数据)。

I would give you advice on how to improve this but I really have no idea what you expect this to do... 我会就如何改进这个问题给你建议,但我真的不知道你期望做什么......

Rather than using String concatanation for building XML, Trying using XML API's like DOM , JDOM etc. 而不是使用String concatanation来构建XML,尝试使用XML API,如DOMJDOM等。

Few Tutorial links: 几个教程链接:

http://www.w3schools.com/dom/default.asp http://www.w3schools.com/dom/default.asp

http://www.xul.fr/en/dom/ http://www.xul.fr/en/dom/

http://swik.net/JDOM+Tutorial http://swik.net/JDOM+Tutorial

http://www.ibm.com/developerworks/java/library/j-jdom/ http://www.ibm.com/developerworks/java/library/j-jdom/

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. 首先关于ResultSet ,我真的怀疑那些id是字符串而不是数字。 next the class StringBuilder , the way you concat strings is wrong because strings is inmutable. 接下来是StringBuilder类,你串联字符串的方式是错误的,因为字符串是不可变的。 And for sure you should look about the Java API for XML 当然,您应该查看Java API for XML

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM