Возврат XML из результата запроса в сервлете - PullRequest
4 голосов
/ 14 августа 2010

Я пытаюсь вернуть файл 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;
         }

   }
}

Любая помощь / советы будут оценены.*

Ответы [ 5 ]

9 голосов
/ 14 августа 2010

Вам не хватает пролога.Добавьте это в начало вашего XML:

<?xml version="1.0" encoding="UTF-8"?>

Кстати, здесь вам не нужен анализатор SAX.Вы вообще не модифицируете XML.Избавьтесь от парсера и просто напишите xml прямо в ответ.Вы также неправильно обрабатываете ресурсы JDBC в try -with-resources .Вот основной пример улучшения:

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>");

Чтобы записать все записи, просто замените if (resultSet.next()) на while (resultSet.next()).

Чтобы обработать исключение более изящното есть, выбрасывая ServletException, заканчивающийся страницей с ошибкой, вместо полусгоревшего XML, вы хотели бы построить XML, используя StringBuilder.Просто замените PrintWriter на new StringBuilder(), а затем в конце сделайте response.getWriter().write(builder.toString()).

8 голосов
/ 14 августа 2010

Одним из советов было бы наложение вашего кода немного больше. Сервлеты не должны импортироваться из java.sql. Поместите этот код в отдельный класс, протестируйте его и позвольте вашему сервлету вызывать его методы.

Вы создаете XML самым разумным способом, конкатенируя строки таким образом. Почему бы не использовать такую ​​библиотеку, как JDOM или хотя бы StringBuilder?

И Скаффман прав: твой код не имеет никакого смысла.

Вот несколько идей, которые вы можете придумать для наслоения. Начните с объекта модели для продажи - в конце концов, 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:

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

Пусть ваш сервлет создает эти объекты и вызывает их методы.

Это может выглядеть сложнее - больше классов, чем один - но вы достигли двух вещей: вы разбили свою проблему на более мелкие части и можете протестировать их отдельно.

2 голосов
/ 14 августа 2010

Вместо того, чтобы использовать конкатенацию строк для построения XML, попробуйте использовать XML API, например DOM , JDOM и т. Д.

Несколько ссылок в учебнике:

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/

2 голосов
/ 14 августа 2010

Чего ты здесь пытаешься достичь?Этот код выглядит очень запутанным по нескольким причинам:

  1. Вы, вероятно, пытаетесь создать строку XML, но не добавляете к ней какие-либо теги XML.
  2. Там есть много бездействующих, например, xml = xml + "";, который ничего не дает.
  3. Я не уверен на 100%, чего вы хотите достичь в try блок ближе к концу.У этого блока будет побочный эффект, заключающийся в том, что ваша строка xml является допустимым XML, но если это то, что вы хотите сделать, возможно, существуют более четкие (и более эффективные) способы проверки.Если вы надеетесь, что он волшебным образом преобразует вашу String в XML, тогда он этого не сделает (фактически, несмотря ни на что, он не может изменить содержимое переменной xml, так что это будет недопустимо.

Возможно, было бы полезно, если бы вы обсудили то, что вы пытаетесь сделать здесь, с конкретной ссылкой на то, что вы ожидаете, что положение дел будет на каждом этапе. Сейчас вы создаетестрока, которая выглядит примерно так:

FirstSaleIDFirstHomeFirstAgentFirstCustomerSecondSaleIDSecondHomeSecondAgentSecondCustomer...

Затем вы пытаетесь проанализировать это как XML. Как и следовало ожидать, это недопустимый XML, поэтому анализатор выдает ошибку (в частности, «нет содержимого в прологе» означаетчто у вас есть символьные данные до определения первого тега).

Я бы дал вам совет, как улучшить это, но я действительно не представляю, что вы ожидаете от этого ...

0 голосов
/ 14 августа 2010

Если мы предположим, что эти значения вы извлекаете из базы данных

|sale_id | home_id | agent_id | customer_id |
|   1    |    10   |  100     |   1000      | 
|   2    |    20   |  200     |   2000      | 
|   3    |    30   |  300     |   3000      | 

xml a конец выглядит такиз этого.

О чем вы должны прочитать:

Сначала о ResultSet , я действительно сомневаюсь, что эти идентификаторы - это строки, а не числа.следующий за классом StringBuilder , способ, которым вы объединяете строки, неверен, потому что строки неизменяемы.И наверняка вам стоит взглянуть на Java API для XML

...