使用Eclipse自动生成Soap Client的代码

在项目按右键,选择New -> Other ->Web Services -> Web Service Client,进入向导。

Java for Web学习笔记(一一八):【篇外】Soap client_Web

加入自有代码,例如加入Envelope Header

在xxxxStub.java文件相应的方法中加入:

public com.example.api.ApiStatus.EchoResponse echo(com.example.api.ApiStatus.Echo echo) throws java.rmi.RemoteException {
    if (super.cachedEndpoint == null) {
        throw new org.apache.axis.NoEndPointException();
    }
    org.apache.axis.client.Call _call = createCall();
    _call.setOperation(_operations[0]);
    _call.setUseSOAPAction(true);
    _call.setSOAPActionURI("");
    _call.setEncodingStyle(null);
    _call.setProperty(org.apache.axis.client.Call.SEND_TYPE_ATTR, Boolean.FALSE);
    _call.setProperty(org.apache.axis.AxisEngine.PROP_DOMULTIREFS, Boolean.FALSE);
    _call.setSOAPVersion(org.apache.axis.soap.SOAPConstants.SOAP11_CONSTANTS);
    _call.setOperationName(new javax.xml.namespace.QName("", "echo"));

    setRequestHeaders(_call);
    setAttachments(_call);
    //这里是加入的Header的内容
    SoapUtils.addAuthSoapHeader(_call);        
try {    
   。。。。。。
public class SoapUtils {
	private static final Logger log = LogManager.getLogger();
	private static SOAPFactory soapFactory;
	static{
		try {
			soapFactory = SOAPFactory.newInstance();
		} catch (SOAPException e) {
			log.fatal("[FATAL] create SOAP Factory error : {}",e.toString());
		}
	}

	private static SOAPHeaderElement createDcpSoapHeader(String userName, String password){
		try {
			String AUTH_PREFIX = "wsse";
			String AUTH_NS = "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd";
			SOAPElement wsSecHeaderElm = soapFactory.createElement("Security", AUTH_PREFIX, AUTH_NS);
			SOAPElement userNameTokenElm = soapFactory.createElement("UsernameToken", AUTH_PREFIX, AUTH_NS);
			SOAPElement userNameElm = soapFactory.createElement("Username", AUTH_PREFIX, AUTH_NS);
			SOAPElement passwdElm = soapFactory.createElement("Password", AUTH_PREFIX, AUTH_NS);
			userNameElm.addTextNode(userName);
			passwdElm.addTextNode(password);
			userNameTokenElm.addChildElement(userNameElm);
			userNameTokenElm.addChildElement(passwdElm);
			wsSecHeaderElm.addChildElement(userNameTokenElm);
			SOAPHeaderElement soapHeaderElement = new SOAPHeaderElement(wsSecHeaderElm);
			soapHeaderElement.setMustUnderstand(true);
			return soapHeaderElement;
		} catch (Exception e) {
			return null;
		}
	}
	
	public static void addAuthSoapHeader(org.apache.axis.client.Call call,String userName, String password){
		SOAPHeaderElement header = createDcpSoapHeader(userName,password);
		if(header != null)
			call.addHeader(header);
	}
}

更好的方式还可以参考 Web Service SOAP Client 设置 SOAP Header,那里给出更通用的解决方式,而这里需要对每个接口都进行设置。主要是了解一下soap client的代码。

网络出现问题,多次重发的实现

利用Java的Function类,在SoapUtils实现通用的多次重发方法。

public class SoapUtils {
	private static final Logger log = LogManager.getLogger();
	......

	//在log上显示错误,并判断是否因为网络连接问题而需要重复
	public static boolean showAndCheckRetryEAxisFault(Exception e){
		if( e instanceof ConnectException)
			return true;
		
		if( e instanceof AxisFault){
			AxisFault fault = (AxisFault)e;
			if(fault.getFaultString().startsWith("java.net.ConnectException"))
				return true;
			log.error( fault.dumpToString());
			return false;
		}
		
		return false;
	}

	//在log上显示错误	
	public static void showAxisFault(Exception e){		
		if( e instanceof AxisFault){
			AxisFault fault = (AxisFault)e;
			log.error( fault.dumpToString());
		}		
	}

	// 根据重复后退的retriesDelay参数,在网络出现故障时,进行重复。其中SoapUtils.ThrowingFunction<T, R> func就是soap proxy中的具体某个方法。这个func因为抛出异常,不能直接使用Function<T,R>,需要通过ThrowingFunction<T,R> extends Function<T,R>来实现。
	public static <T, R> R funcApplyWithThrow(SoapUtils.ThrowingFunction<T, R> func,T param, Long ... retriesDelay) throws AxisFault,Exception{		
		if(retriesDelay != null){
			for(int i = 0 ; i< retriesDelay.length ; i ++){	
				try {
					return func.applyThrows(param);
				} catch (Exception e) {					
					if(!SoapUtils.showAndCheckRetryEAxisFault(e))
						throw e;
					log.debug("Try to fix {}, resend({}) after {}ms", e.toString(), i+1, retriesDelay[i]);	
				}		
				NormalUtils.sleep(retriesDelay[i]);			
			}
		}
		
		try{
			return func.applyThrows(param);
		}catch(Exception e){
			SoapUtils.showAxisFault(e);
			throw e;
		}		
	}	

	//参考slieb.org/blog/throwable-interfaces/
	@FunctionalInterface
	public static interface ThrowingFunction<T,R> extends Function<T,R> {
	    @Override
	    default R apply(T t){
	        try{
	            return applyThrows(t);
	        }catch (RemoteException e){
	            throw new RuntimeException(e);
	        }
	    }

	    R applyThrows(T t) throws RemoteException;
	}
}

具体某个重发的实现:

private final MySoapProxy proxy = new MySoapProxy(url);

@Override
public QueryResponse query(Long ...retriesDelay) throws AxisFault,Exception{ 
	QueryParam param = new QueryParam();
	return SoapUtils.funcApplyWithThrow(proxy::query, param, retriesDelay);
}