Мы изо всех сил пытаемся настроить наше веб-приложение так, чтобы оно могло подключаться к веб-службам через Spring WS. Мы попытались использовать пример из документации клиентской Spring-WS, но в итоге получили исключение WebServiceTransportException. Конфигурация XML выглядит так:
<bean id = "webServiceTemplate" class = "org.springframework.ws.client.core.WebServiceTemplate">
<constructor-arg ref = "messageFactory"/>
<property name = "messageSender">
<bean class = "org.springframework.ws.transport.http.CommonsHttpMessageSender">
<property name = "credentials">
<bean class = "org.apache.commons.httpclient.UsernamePasswordCredentials">
<constructor-arg value = "john"/>
<constructor-arg value = "secret"/>
</bean>
</property>
</bean>
</property>
</bean>
Нам удалось настроить приложение программно, но эту конфигурацию невозможно «перенести» в конфигурацию Spring XML, поскольку некоторые сеттеры не использовали формат, ожидаемый Spring. (HttpState.setCredentials (...) принимает два параметра). Конфигурация была взята из другого клиентского кода Spring-WS в компании.
Это конфигурация, которая работает:
public List<String> getAll() {
List<String> carTypes = new ArrayList<String>();
try {
Source source = new ResourceSource(request);
JDOMResult result = new JDOMResult();
SaajSoapMessageFactory soapMessageFactory = new SaajSoapMessageFactory(MessageFactory.newInstance());
WebServiceTemplate template = new WebServiceTemplate(soapMessageFactory);
HttpClientParams clientParams = new HttpClientParams();
clientParams.setSoTimeout(60000);
clientParams.setConnectionManagerTimeout(60000);
clientParams.setAuthenticationPreemptive(true);
HttpClient client = new HttpClient(clientParams);
client.getState().setCredentials(AuthScope.ANY,
new UsernamePasswordCredentials("username", "password"));
CommonsHttpMessageSender messageSender = new CommonsHttpMessageSender(client);
template.setMessageSender(messageSender);
template.sendSourceAndReceiveToResult(SERVICE_URI,
source, result);
// Handle the XML
} catch (IOException e) {
throw new RuntimeException(e);
} catch (SOAPException e) {
throw new RuntimeException(e);
}
return carTypes;
}
Кто-нибудь знает, как решить мою проблему? В каждом учебном пособии, которое я видел, указана первая конфигурация. Кажется, что когда я устанавливаю учетные данные для объекта messageSender, они просто игнорируются ...





Как вы их различите:
<constructor-arg value = "john"/>
<constructor-arg value = "secret"/>
попробуйте заменить его на это:
<property name = "userName" value = "john" />
<property name = "password" value = "secret" />
Надеюсь, это поможет.
Переопределите HttpClient с помощью конструктора, который принимает параметры и подключается к Spring с помощью constructor-args
public MyHttpClient(HttpClientParams params, UsernamePasswordCredentials usernamePasswordCredentials) {
super(params);
getState().setCredentials(AuthScope.ANY, usernamePasswordCredentials);
}
Если вы используете defaultHttpClient, как в своем примере, используйте метод afterPropertiesSet в своем HTTPMessageSender, и это должно решить вашу проблему, правильно применив учетные данные.
Сначала мы устанавливали учетные данные в нашем проекте следующим образом:
<bean id = "authenticationEnabledCommonsHttpMessageSender" parent = "commonsHttpMessageSender"
p:credentials-ref = "clientCredentials" lazy-init = "true" />
<bean id = "clientCredentials"
class = "org.apache.commons.httpclient.UsernamePasswordCredentials"
c:userName = "${clientCredentials.userName}"
c:password = "${clientCredentials.password}"
lazy-init = "true" />
Это наша опция включения критических данных. При настройке таких учетных данных возникла проблема. Если сервер, который мы отправляем сообщение (имеет Axis impl), не имеет учетных данных для имени пользователя и пароля, мы получаем исключение «Неавторизованный». Потому что, когда мы отслеживаем TCPMon, мы обнаружили, что строка «username: password:» была отправлена, так как вы можете видеть, что имя пользователя и пароль не имеют значения.
После этого мы устанавливаем такие учетные данные:
public Message sendRequest(OutgoingRequest message, MessageHeaders headers,
EndpointInfoProvider endpointInfoProvider,
WebServiceMessageCallback requestCallback){
Assert.notNull(endpointInfoProvider, "Destination provider is required!");
final Credentials credentials = endpointInfoProvider.getCredentials();
URI destinationUri = endpointInfoProvider.getDestination();
for (WebServiceMessageSender messageSender : webServiceTemplate.getMessageSenders()) {
if (messageSender instanceof CommonsHttpMessageSender) {
HttpClient httpClient = ((CommonsHttpMessageSender) messageSender).getHttpClient();
httpClient.getState().setCredentials(
new AuthScope(destinationUri.getHost(),
destinationUri.getPort(), AuthScope.ANY_REALM,
AuthScope.ANY_SCHEME), credentials
);
httpClient.getParams().setAuthenticationPreemptive(true);
((CommonsHttpMessageSender) messageSender)
.setConnectionTimeout(endpointInfoProvider
.getTimeOutDuration());
}
}
И метод getCredentials:
@Override
public Credentials getCredentials(){
if (credentials != null) {
return credentials;
}
String username = parameterService.usernameFor(getServiceName());
String password = parameterService.passwordFor(getServiceName());
if (username == null && password == null) {
return null;
}
credentials = new UsernamePasswordCredentials(username, password);
return credentials;
}
Если указано, как указано выше, Spring различает аргументы конструктора по порядку появления. Обозначение <property ...> будет переключаться только между установкой атрибутов конструктором и установкой их с помощью средства доступа. Боюсь, это ничего не изменит.