mem*_*und 2 java spring soap web-services cxf
我提供SOAP @WebMethod使用Spring和 CXF。而且我想捕获任何异常(已检查和未检查)并将其转换为custom @WebFault。
我可以以某种方式为我的@WebSerivce班级分配一个错误处理程序/拦截器,这样我就不必try-catch为每个webserivce方法都提供额外的块了吗?
<jaxws:endpoint implementor="de.MyService" address="/MyService" />
@Component
@WebService
public class MyService {
@WebMethod
public void test() throws MyException {
try {
service.run();
} catch (Exception e) {
throw new MyException("test");
}
}
}
@WebFault
public class MyException extends Exception {
public MyException(String message) {
super(message);
}
}
Run Code Online (Sandbox Code Playgroud)
因此,使用某种拦截器,我的方法将如下所示:
@WebMethod
public void test() {
service.run();
}
Run Code Online (Sandbox Code Playgroud)
那可能吗?
好吧,第一个可能会建议一种“低技术含量”的方法:为所有try/catch在一个invoke方法中处理web服务的基类提供一个基类。将此方法委托给抽象doInvoke方法,并使其成为所有JAXWS实现仅调用的策略invoke。
@kan涉及AOP的解决方案也肯定是可能的解决方案。
但是,如果要构建自定义错误拦截,则可以在CXF级别上进行。
当与JAX-WS一起使用时,最简单形式的CXF可以被认为是JAX WS引擎周围的(复杂)拦截器链:拦截器链是CXF所有“实质”的去向。
CXF拦截器按链排列(“进”链,“故障”链,“出”和“出故障”链)。
每个链都有不同的“阶段”,例如:RECEIVE, (PRE/USER/POST)_STREAM, READ, (PRE/USER/POST)PROTOCOL, UNMARSHAL, (PRE/USER/POST)LOGICAL, PRE_INVOKE, INVOKE, POST_INVOKE是传入链的默认阶段。
拦截器是“按顺序”执行的(阶段与优先级相关联,拦截器实现声明它们属于哪个阶段。在一个阶段内,每个拦截器都可以选择在其他某个拦截器类之前或之后放置)。
在您的情况下,最重要的是ServiceInvokerInterceptor,属于INVOKE阶段的,负责调用@Webservice。处理完“输入”链中的所有拦截器后,CXF会将响应对象处理到“输出”链,以对输出进行序列化(或者,如果您有单向SOAP方法,则在此停止所有操作,这是特例)。
如果标准链中的任何地方发生异常,CXF会做两件事:
因此,您添加自己的SOAP错误“全部捕获”错误处理的一种可能方法是使用基于此生命周期的拦截器。
您创建一个Interceptor实现(AbstractSoapInterceptor对此很有用),您可以在实现之前将其绑定到INVOKE阶段。 ServiceInvokerInterceptor
public class YourInterceptor extends AbstractSoapInterceptor {
public YourInterceptor() {
super(Phase.INVOKE);
addBefore(Arrays.asList(ServiceInvokerInterceptor.class.getName()));
// This means handleMessage will be called juste before your @WebMethod
// If it fails, you will be the first to be noticed through #handleFault()
}
}
Run Code Online (Sandbox Code Playgroud)
当“正常消息通过”时,此拦截器将不执行任何操作:
@Override
public void handleMessage(SoapMessage message) throws Fault {
// Do nothing
}
Run Code Online (Sandbox Code Playgroud)
但这是要处理的错误:
@Override
public void handleFault(SoapMessage message) {
// Every exception will be wrapped into a Fault object by CXF
Fault f = (Fault) message.getContent(Exception.class);
// You should inspect its g.getCause() to maybe identify what went wrong
// A CXF Fault also much ressembles a SOAPFault element
f.setMessage("Your SOAP Fault message");
// You can access the DOM detail of the fault
Element detail = f.getOrCreateDetail();
Element newDetailEntry = detail.getOwnerDocument().createElementNS("detailNs", "detailName");
newDetailEntry.setTextContent("Content for your soap fault detail");
detail.appendChild(newDetailEntry);
// And so on. f.setFaultCode(qName);...
}
Run Code Online (Sandbox Code Playgroud)
另一种实现方式是Fault通过custom 交换原始SoapFault内容Fault,如果这对您更有意义,则它也是的子类。
诚然,这比启动您自己的异常要困难得多,但是它允许您构建精确的,有意义的肥皂故障。但是请注意,优良作法是仅启动作为WSDL一部分存在的SOAP Fault,因此要与客户端“巧妙地”玩耍,不要在此处构建与WSDL不匹配的错误(在您的情况下为@Webfault定义)。
最后,您必须声明要将拦截器添加到链中。这样做有多种方法:基于每个bean:
<bean id="myIt" class="com.yourInterceptor" />
<jaxws:endpoint implementor="de.MyService" address="/MyService">
<jaxws:inInterceptors>
<ref bean="myIt"/>
</jaxws:inInterceptor>
</jaxws:endpoint>
Run Code Online (Sandbox Code Playgroud)
或在巴士一级。
<cxf:bus>
<cxf:inInterceptors>
<ref bean="myIt"/>
</cxf:inInterceptors>
</cxf:bus>
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
4819 次 |
| 最近记录: |