Я разрабатываю WebService JAX-WS для записи состояния журналов приложений клиентов.
Я посылаю по каждому запросу сообщение id, timestamp и status. 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;
}
}
Спасибо заранее всем сообществу StackOverflow. Вы все рок!
Вот как я решил свой собственный вопрос.
Далеко от элегантного решения, но мне он нужен, и это решает мою проблему.
Пожалуйста, кто-нибудь, кто знает, как это сделать лучше, прокомментируйте.
Мне не нравится этот подход, но я не знаю, как это сделать лучше!
Ну, есть мое решение:
Я просто замаскирую свой XML множеством элементов в одном параметре <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>
то я добавил эту функцию в webservice inteface:
@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://stackoverflow.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;
}
}
В любом случае, спасибо всем!
Скалы StackOverflow!
Наверное, ты почти там.
Во-первых, вам нужно изменить стиль привязки 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; поместите их в массив или список и вызовите соответствующий метод webservice. Дай мне знать, если это работает.