簡體   English   中英

從servlet中的查詢結果返回XML

[英]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實例化這些對象並調用它們的方法。

它可能看起來更復雜 - 更多的課程而不僅僅是一個 - 但你已經完成了兩件事:你已經將問題分解成更小的部分,你可以單獨測試它們。

你想在這里完成什么? 此代碼看起來很混亂,原因如下:

  1. 您可能正在嘗試構建XML字符串,但您根本不會向其添加任何XML標記。
  2. 那里有很多無操作,例如xml = xml + ""; 這沒有任何成就。
  3. 我不是100%肯定你想要在接近結束的try塊中實現什么。 這個塊會產生副作用,確保你的xml字符串是有效的XML,但如果這是你想要做的,那么可能有更清晰(和更有效)的驗證方法。 如果您希望它會將您的String神奇地轉換為XML,那么它就不會(事實上無論如何,它都無法修改xml變量的內容,因此這將是一個無操作。

如果你在這里談論你想要做的事情,或許特別提到你對每個階段的狀況的期望,這可能會有所幫助。 現在,您正在構建一個類似於以下內容的字符串:

FirstSaleIDFirstHomeFirstAgentFirstCustomerSecondSaleIDSecondHomeSecondAgentSecondCustomer...

然后嘗試將其解析為XML。 正如您所料,這不是有效的XML,因此解析器會拋出錯誤(特別是“prolog中沒有內容”意味着您在第一個標記定義之前有字符數據)。

我會就如何改進這個問題給你建議,但我真的不知道你期望做什么......

而不是使用String concatanation來構建XML,嘗試使用XML API,如DOMJDOM等。

幾個教程鏈接:

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

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

http://swik.net/JDOM+Tutorial

http://www.ibm.com/developerworks/java/library/j-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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM