Ho avuto lo stesso problema. Sfortunatamente (o meno) WebServiceTemplate con l'implementazione di SOAPMessageFactory (come SaajSoapMessageFactory) farà tutto il possibile per assicurare che tu stia inviando un XML ben formato come richiesta legandoti ai Transformer da Source a Result, incluso non lasciare mai ripetere 'xmlns' 'nei bambini quando hai già fatto in genitore. Hai un paio di opzioni eleganti da provare - ciò che non significa che siano le più semplici. Puoi lavorare a livello XML usando l'interfaccia javax.xml.ws.Service e Dispatch, che è abbastanza facile se non hai bisogno dell'autenticazione SSL. Controllare questi collegamenti out (primo è scritto in Pt-BR):
http://www.guj.com.br/t/nfe-v2-00-veja-como-consumir-o-ws/297304
https://alesaudate.wordpress.com/2010/08/09/how-to-dynamically-select-a-certificate-alias-when-invoking-web-services/
Inoltre si può provare un altro stabilimento messaggio, come ad esempio DomPoxMessageFactory. Questo collegamento può essere utile:
http://forum.spring.io/forum/spring-projects/web-services/128221-webservicetemplate-get-it-to-stop-adding-soap-envelope
Tuttavia, se cambiando la struttura del progetto non è un'opzione (che era il mio caso), ho una soluzione per voi. Sì, una soluzione, ma una volta che il webservice bersaglio si aspetta un XML valido, mi assolve me: D
Ho appena creato astrazioni di HttpComponentsMessageSender e HttpComponentsConnection classi, la seconda viene creata un'istanza attraverso il metodo del primo uno CreateConnection (Uri Uri) .Così posso creare il mio WebServiceTemplate in questo modo:
WebServiceTemplate wst = new WebServiceTemplate(new SaajSoapMessageFactory());
wst.setMessageSender(new CustomHttpComponentsMessageSender());
Purtroppo dovrete rispondere il metodo createConnecion alla nuova astrazione solo per un'istanza di connessione personalizzata. Come ho detto, è una soluzione!
@Override
public WebServiceConnection createConnection(URI uri) throws IOException {
HttpPost httpPost = new HttpPost(uri);
if (isAcceptGzipEncoding()) {
httpPost.addHeader(HttpTransportConstants.HEADER_ACCEPT_ENCODING,
HttpTransportConstants.CONTENT_ENCODING_GZIP);
}
HttpContext httpContext = createContext(uri);
return new CustomHttpComponentsConnection(getHttpClient(), httpPost, httpContext);
}
il messaggio viene inviato in modo efficace all'interno del metodo onSendAfterWrite (messaggio WebServiceMessage) della classe HttpComponentsConnection sto astraendo da. Sorprendentemente, il parametro 'message' non è usato all'interno del metodo. È lì solo per le regole di ereditarietà. E la buona notizia: è un metodo protetto. Il rovescio della medaglia, ancora, è che ho bisogno di copiare quasi l'intera classe per poter cambiare solo questo metodo, una volta che i campi non hanno visibilità pubblica, e il framework ne avrà bisogno nella gestione della risposta. Quindi, vi posterò la mia intera classe verso il basso:
public class CustomHttpComponentsConnection extends HttpComponentsConnection {
private final HttpClient httpClient;
private final HttpPost httpPost;
private final HttpContext httpContext;
private HttpResponse httpResponse;
private ByteArrayOutputStream requestBuffer;
protected CustomHttpComponentsConnection(HttpClient httpClient, HttpPost httpPost, HttpContext httpContext) {
super(httpClient, httpPost, httpContext);
Assert.notNull(httpClient, "httpClient must not be null");
Assert.notNull(httpPost, "httpPost must not be null");
this.httpClient = httpClient;
this.httpPost = httpPost;
this.httpContext = httpContext;
}
public HttpResponse getHttpResponse() {
return httpResponse;
}
public HttpPost getHttpPost() {
return httpPost;
}
@Override
protected OutputStream getRequestOutputStream() throws IOException {
return requestBuffer;
}
@Override
protected void onSendBeforeWrite(WebServiceMessage message) throws IOException {
requestBuffer = new ByteArrayOutputStream();
}
@Override
protected void onSendAfterWrite(WebServiceMessage message) throws IOException {
OutputStream out = getRequestOutputStream();
String str = out.toString();
str = str.replaceAll("<NFe>", "<NFe xmlns=\"http://www.portalfiscal.inf.br/nfe\">");
ByteArrayOutputStream bs = new ByteArrayOutputStream();
bs.write(str.getBytes());
getHttpPost().setEntity(new ByteArrayEntity(bs.toByteArray()));
requestBuffer = null;
if (httpContext != null) {
httpResponse = httpClient.execute(httpPost, httpContext);
}
else {
httpResponse = httpClient.execute(httpPost);
}
}
@Override
protected int getResponseCode() throws IOException {
return httpResponse.getStatusLine().getStatusCode();
}
@Override
protected String getResponseMessage() throws IOException {
return httpResponse.getStatusLine().getReasonPhrase();
}
@Override
protected long getResponseContentLength() throws IOException {
HttpEntity entity = httpResponse.getEntity();
if (entity != null) {
return entity.getContentLength();
}
return 0;
}
@Override
protected InputStream getRawResponseInputStream() throws IOException {
HttpEntity entity = httpResponse.getEntity();
if (entity != null) {
return entity.getContent();
}
throw new IllegalStateException("Response has no enclosing response entity, cannot create input stream");
}
@Override
public Iterator<String> getResponseHeaderNames() throws IOException {
Header[] headers = httpResponse.getAllHeaders();
String[] names = new String[headers.length];
for (int i = 0; i < headers.length; i++) {
names[i] = headers[i].getName();
}
return Arrays.asList(names).iterator();
}
@Override
public Iterator<String> getResponseHeaders(String name) throws IOException {
Header[] headers = httpResponse.getHeaders(name);
String[] values = new String[headers.length];
for (int i = 0; i < headers.length; i++) {
values[i] = headers[i].getValue();
}
return Arrays.asList(values).iterator();
}
Ancora una volta, questo è il modo più semplice che ho trovato quando si cambia la struttura del progetto non è un'opzione. Spero che questo ti aiuti.
controlli la chiamata 'transformer.transform (Source, Result)', cioè puoi passare diversi oggetti Source o Result se vuoi? – wero
No, non ne ho il controllo. Il risultato arriva da Spring-ws. –