我有基于Spring MVC的Web应用程序,它调用Web服务。 Web服务需要对每个调用进行基于http的身份验证。我在applicationContext.xml中保存Web服务代理配置:
<beans...
<bean id="paymentWebService"
class="org.springframework.remoting.jaxws.JaxWsPortProxyFactoryBean">
<property name="customProperties">
<ref local="jaxwsCustomProperties"/>
</property>
<property name="serviceInterface" value="com.azercell.paymentgateway.client.PaymentGatewayWebService"/>
<property name="wsdlDocumentUrl"
value="#{config.wsdlDocumentUrl}"/>
<property name="namespaceUri" value="http://webservice.paymentgateway.azercell.com/"/>
<property name="serviceName" value="PaymentGatewayWebServiceImplService"/>
<property name="portName" value="PaymentGatewayWebServiceImplPort"/>
</bean>
我的控制器中有Web服务端口的实例字段:
@Controller
public class PaymentController {
@Resource(name = "paymentWebService")
private PaymentGatewayWebService paymentPort;
@ModelAttribute
public void ajaxAttribute(WebRequest request, Model model) {
UtilMethods.authenticationWebServicePort(paymentPort);
...
}
...
@RequestMapping(value = "/massPayment", method = RequestMethod.POST)
public String massPayment(@RequestParam String amount, @RequestParam MultipartFile file, Model model, Locale locale) {
...
WebServiceResponse response = paymentPort.massPayment(UtilMethods.getNewRequestId()
, fileUploader, UtilMethods.getAmountInCoins(amountBigDecimal), null);
...
return SpringView.MASS_PAYMENT.toString(ajaxRequest);
}
}
UtilMethods.authenticationWebServicePort代码:
public static void authenticationWebServicePort(PaymentGatewayWebService paymentPort) {
String username = (String) RequestContextHolder.currentRequestAttributes().getAttribute(USERNAME_SESSION_VARIABLE_NAME, RequestAttributes.SCOPE_SESSION);
String password = (String) RequestContextHolder.currentRequestAttributes().getAttribute(PASSWORD_SESSION_VARIABLE_NAME, RequestAttributes.SCOPE_SESSION);
BindingProvider prov = (BindingProvider) paymentPort;
prov.getRequestContext().put(BindingProvider.USERNAME_PROPERTY, username);
prov.getRequestContext().put(BindingProvider.PASSWORD_PROPERTY, password);
}
由于控制器是单例对象,每次请求重叠时都会出现问题,如果错误地只是一个用户,则可以使用具有属于另一个用户的用户名和密码的Web方法。
为了防止这种情况,我试图在配置中设置范围内的Web服务端口请求,如下所示:
<bean id="paymentWebService"
class="org.springframework.remoting.jaxws.JaxWsPortProxyFactoryBean" scope="request">
在这种情况下我收到了错误:
SEVERE: Exception sending context initialized event to listener instance of class org.springframework.web.context.ContextLoaderListener
org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'org.springframework.security.filterChains': Cannot resolve reference to bean 'org.springframework.security.web.DefaultSecurityFilterChain#0' while setting bean property 'sourceList' with key [0]; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'org.springframework.security.web.DefaultSecurityFilterChain#0': Cannot resolve reference to bean 'org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter#0' while setting constructor argument with key [2]; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter#0': Cannot resolve reference to bean 'org.springframework.security.authentication.ProviderManager#0' while setting bean property 'authenticationManager'; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'org.springframework.security.authentication.ProviderManager#0': Cannot resolve reference to bean 'org.springframework.security.config.authentication.AuthenticationManagerFactoryBean#0' while setting constructor argument; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'org.springframework.security.config.authentication.AuthenticationManagerFactoryBean#0': FactoryBean threw exception on object creation; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'org.springframework.security.authenticationManager': Cannot resolve reference to bean 'myAuthenticationProvider' while setting constructor argument with key [0]; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'myAuthenticationProvider': Injection of resource dependencies failed; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'paymentWebService': Scope 'request' is not active for the current thread; consider defining a scoped proxy for this bean if you intend to refer to it from a singleton; nested exception is java.lang.IllegalStateException: No thread-bound request found: Are you referring to request attributes outside of an actual web request, or processing a request outside of the originally receiving thread? If you are actually operating within a web request and still receive this message, your code is probably running outside of DispatcherServlet/DispatcherPortlet: In this case, use RequestContextListener or RequestContextFilter to expose the current request.
如何创建请求范围的Web服务端口?
答案 0 :(得分:0)
尝试将当前的http请求公开给spring。只需在RequestContextListener
:
web.xml
即可
<web-app>
...
<listener>
<listener-class>
org.springframework.web.context.request.RequestContextListener
</listener-class>
</listener>
...
</web-app>
有关详情/选项,请参阅官方文档中的this entry。
编辑。考虑控制器和paymentPort
依赖关系之间生命周期的差异。控制器始终相同,但必须为每个新请求刷新paymentPort
。所以你不能继续直接注射它。您需要为每个请求获取新的实例。您可以使用javax.inject.Provider
界面执行此操作。