Получение и обработка нескольких предметов в JAX-WS
Я занимаюсь разработкой WebService JAX-WS для записи в журнал статуса приложений клиентов.
Я отправляю на каждый запрос идентификатор, метку времени и сообщение о статусе. WS только записывает это в базу данных.
Сервис работает отлично, и я использую его с Delphi, делая запросы XML "вручную".
Поэтому я не заинтересован в обслуживании клиентов. Клиент является приложением Delphi, и я не могу это изменить...
Я могу использовать этот JAX-WS только один запрос за раз. Каждое обновление статуса заключается в полном вызове WS.
Проблема заключается в следующем: как я могу отправить много информации о состоянии в одном запросе, и, в частности, как мне нужно аннотировать JAX-WS для распознавания нескольких элементов в XML и дать мне в теле реализации функции доступ ко всем элементам, например к массиву.
Я отправляю XML на WS в Delphi с этим кодом:
function JAXWS_getResponse( vXMLRequest_Envelope : WideString; vURL : String ) : WideString;
var sRequest : TStringStream;
sResponse : TStringStream;
JAXWS_Request : THTTPReqResp;
begin
sRequest := TStringStream.Create( vXMLRequest_Envelope );
sResponse := TStringStream.Create( EmptyStr );
JAXWS_Request := THTTPReqResp.Create( nil );
try
JAXWS_Request.URL := vURL;
JAXWS_Request.UseUTF8InHeader := True;
JAXWS_Request.Execute( sRequest, sResponse );
Result := sResponse.DataString;
finally
JAXWS_Request.Free;
sRequest.Free;
sResponse.Free;
end;
end;
Содержимое параметра vXMLRequest_Envelope имеет вид (сделать "вручную"):
<?xml version="1.0" encoding="utf-8"?>
<soapenv:Envelope
xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/"
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<soapenv:Body>
<ns2:updateStatus
xmlns:ns2="http://webVersao.microdata.com.br/">
<id_customer>123</id_customer>
<status_date>2014-08-26 15:30:05</status_date>
<status_message>WORKING</status_message>
</ns2:updateStatus>
</soapenv:Body>
</soapenv:Envelope>
Итак, это код веб-сервиса:
WebVersao_Interface.java
package br.com.microdata.webVersao;
import java.util.Date;
import javax.jws.WebMethod;
import javax.jws.WebParam;
import javax.jws.WebService;
import javax.jws.soap.SOAPBinding;
import javax.jws.soap.SOAPBinding.Style;
@WebService
@SOAPBinding(style = Style.RPC)
public interface WebVersao_Interface {
@WebMethod
String updateStatus(
@WebParam(name="id_customer", partName="id_customer")
String id_customer,
@WebParam(name="status_date", partName="status_date")
String status_date, // yyyy-mm-dd hh:nn:ss
@WebParam(name="status_message", partName="status_message")
String status_message
);
}
WebVersao_Implementation.java
package br.com.microdata.webVersao;
import java.sql.Connection;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.Date;
import javax.jws.WebService;
@WebService(endpointInterface = "br.com.microdata.webVersao.WebVersao_Interface")
public class WebVersao_Implementation implements WebVersao_Interface {
@Override
public String updateStatus(String id_customer, String status_date, String status_message) {
Connection conn = WebVersao_Connection.getConnection();
try {
Statement stmt = conn.createStatement();
String query =
"insert into status_log ( id_customer, status_date, status_message ) " +
String.format( "values ( %d, timestamp '%s', '%s' )",
id_customer, status_date, status_message );
stmt.execute(query);
return "DONE";
} catch (SQLException e) {
return "ERROR: " + e.getMessage();
}
}
}
Итак, наконец, мой вопрос:
Как я могу сделать мой XML как:
<status>
<id_customer>123</id_customer>
<status_date>2014-08-26 12:30:05</status_date>
<status_message>WAITING</status_message>
</status>
<status>
<id_customer>789</id_customer>
<status_date>2014-08-26 13:43:52</status_date>
<status_message>SLEEPING</status_message>
</status>
<status>
<id_customer>123</id_customer>
<status_date>2014-08-26 15:30:05</status_date>
<status_message>WORKING</status_message>
</status>
<status>
<id_customer>456</id_customer>
<status_date>2014-08-26 18:10:08</status_date>
<status_message>SLEEPING</status_message>
</status>
и правильно получить в Java, как:
public String updateManyStatus( List<StatusInfo> manyStatus) { ... }
или же
public String updateManyStatus( StatusInfo[] manyStatus) { ... }
или любой другой подобный метод...
public class StatusInfo {
private Long id_customer;
private String status_date;
private String status_message;
public Long getId_customer() {
return id_customer;
}
public void setId_customer(Long id_customer) {
this.id_customer = id_customer;
}
public String getStatus_date() {
return status_date;
}
public void setStatus_date(String status_date) {
this.status_date = status_date;
}
public String getStatus_message() {
return status_message;
}
public void setStatus_message(String status_message) {
this.status_message = status_message;
}
}
Заранее спасибо всему сообществу Stackru. Вы все рок!
2 ответа
Вот как я решил свой вопрос.
Очень далеко от элегантного решения, но оно мне нужно, и это решает мою проблему.
Пожалуйста, кто-нибудь, кто знает, как это сделать лучше, пожалуйста, прокомментируйте.
Мне не нравится этот подход, но я не знаю, как сделать это лучше!
Ну, есть мое решение:
Я просто маскирую свой XML множеством элементов в одном параметре WideString <xml_content>
и затем в Java снимите маску, проанализируйте как обычный XML и заполните массив.
Мой XML-запрос:
<?xml version="1.0" encoding="utf-8"?>
<soapenv:Envelope
xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/"
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<soapenv:Body>
<ns2:updateStatusMulti
xmlns:ns2="http://webVersao.microdata.com.br/">
<xml_content>
{?xml version="1.0" encoding="utf-8"?}
{many_status}
{status}
{id_customer}123{/id_customer}
{status_date}2014-08-26 12:30:05{/status_date}
{status_message}WAITING{/status_message}
{/status}
{status}
{id_customer}789{/id_customer}
{status_date}2014-08-26 13:43:52{/status_date}
{status_message}SLEEPING{/status_message}
{/status}
{status}
{id_customer}123{/id_customer}
{status_date}2014-08-26 15:30:05{/status_date}
{status_message}WORKING{/status_message}
{/status}
{status}
{id_customer}456{/id_customer}
{status_date}2014-08-26 18:10:08{/status_date}
{status_message}SLEEPING{/status_message}
{/status}
{/many_status}
</xml_content>
</ns2:updateStatusMulti>
</soapenv:Body>
</soapenv:Envelope>
Затем я добавил эту функцию в интерфейс веб-сервиса:
@WebMethod
String updateStatusMulti(
@WebParam(name="xml_content", partName="xml_content")
String xml_content);
и в реализации я заполняю массив и вызываю функцию updateManyStatus
на моем пути, как я хочу!
@Override
public String updateStatusMulti( String xml_content ) {
try{
//"unmask" then xml
xml_content = xml_content.replace('{', '<');
xml_content = xml_content.replace('}', '>');
DocumentBuilderFactory dbFactory = DocumentBuilderFactory.newInstance();
DocumentBuilder dBuilder = dbFactory.newDocumentBuilder();
Document doc = dBuilder.parse(new InputSource(new ByteArrayInputStream(xml_content.getBytes("utf-8"))));
//optional, but recommended
//read this - http://stackru.com/questions/13786607/normalization-in-dom-parsing-with-java-how-does-it-work
doc.getDocumentElement().normalize();
NodeList nList = doc.getElementsByTagName("status");
int nCount = nList.getLength();
StatusInfo[] manyStatus = new StatusInfo[nCount];
for (int index = 0; index < nCount; index++) {
Node nNode = nList.item(index);
//("\nCurrent Element :" + nNode.getNodeName());
if (nNode.getNodeType() == Node.ELEMENT_NODE) {
Element eElement = (Element) nNode;
String id_customer = eElement.getElementsByTagName("id_customer").item(0).getTextContent();
String status_date = eElement.getElementsByTagName("status_date").item(0).getTextContent();
String status_message = eElement.getElementsByTagName("status_message").item(0).getTextContent();
manyStatus[index].setId_customer( Long.valueOf(id_customer) );
manyStatus[index].setStatus_date( status_date );
manyStatus[index].setStatus_message( status_message );
}
}
//return String.format( "DONE: ( %d )", nCount );
//here is my wanted call
return updateManyStatus( manyStatus );
} catch (Exception e) {
return "ERROR: " + e.getMessage(); //xml_content;
}
}
В любом случае, спасибо всем!!!
Stackru качается!
Я полагаю, вы почти у цели.
Во-первых, вам нужно изменить свой стиль привязки SOAP на вашем WebVersao_Interface с @SOAPBinding(style = Style.RPC)
в @SOAPBinding(style = Style.DOCUMENT)
, Стиль RPC имеет минимальную поддержку для определенного пользователем типа данных или сложных типов.
Любая из этих подписей в веб-сервисе будет делать
public String updateManyStatus( ArrayList<StatusInfo> manyStatus) { ... }
или же
public String updateManyStatus( StatusInfo[] manyStatus) { ... }
Рекомендовал бы использовать версию массива для обеспечения функциональной совместимости для использования веб-сервиса среди других не Java-клиентов.
И в клиенте, почему вы вручную пишете XML-сообщение. Вместо этого вы можете создать / заполнить все ваши объекты StatuInfo; поместите их в массив или список и вместо этого вызовите соответствующий метод веб-сервиса. Дай мне знать, если это работает.