我也經歷過同樣的麻煩。不幸的是,WebServiceTemplate與SOAPMessageFactory的實現(如SaajSoapMessageFactory)將盡一切可能確保您通過將Source綁定到Transformers從Source到Result來發送格式良好的XML作爲請求,包括永不讓你重複'xmlns '如果你已經在父母身上做過這些事情,你有幾個優雅的選擇來嘗試 - 並不意味着它們是最簡單的選項。您可以使用javax.xml.ws.Service和Dispatch接口在XML級別工作,如果您不需要SSL身份驗證,這很容易。檢查這些鏈接了(第一個是寫在鉑-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/
您也可以嘗試其他的消息工廠,如DomPoxMessageFactory。此鏈接可能是有用的:
http://forum.spring.io/forum/spring-projects/web-services/128221-webservicetemplate-get-it-to-stop-adding-soap-envelope
但是,如果更改項目的結構是不是一種選擇(這是我的情況),我對你有一種變通方法。是的,一個解決方法,但一旦目標webservice是預測畸形的XML,我absolve自己:D
我剛剛創建了HttpComponentsMessageSender和HttpComponentsConnection類的抽象,第二個是通過第一個方法createConnection(URI URI) 。所以,我可以創建WebServiceTemplate這樣的:
WebServiceTemplate wst = new WebServiceTemplate(new SaajSoapMessageFactory());
wst.setMessageSender(new CustomHttpComponentsMessageSender());
可悲的是你需要回復createConnecion方法到新的抽象只是實例化自定義連接。正如我所說,這是一個解決方法!
@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);
}
該消息有效的HttpComponentsConnection類我是從提取的方法onSendAfterWrite(WebServiceMessage消息)內發送。令人驚訝的是,'message'參數不在方法內部使用。它只存在於繼承規則中。好消息是:這是一種受保護的方法。不利的一面是,我需要複製幾乎整個類,以便僅更改此方法,一旦這些字段沒有公開可見性,並且框架將需要它們進行響應處理。所以,我會後我的整個堂課下來:
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();
}
再次,這是改變項目結構時,我發現最簡單的方法是不是一種選擇。希望這可以幫助。
你是否控制調用'transformer.transform(Source,Result)',即如果你想傳遞不同的Source或Result對象? – wero
不,我無法控制。結果來自spring-ws。 –