Java 6 內建 JAX-WS,可使用 wsimport 從 WSDL 產生客戶端存根。本文示範如何產生代碼、設定 HandlerResolver 注入 SOAP Header 進行驗證(如 Username/Password)。
wsimport -keep -extension -s ./src -p com.jaxws.test https://192.168.1.1:8080/service?wsdl
public String callService(Object[] args) {
ServicesService service = new ServicesService();
service.setHandlerResolver(new HandlerResolver() {
@Override
public List<Handler> getHandlerChain(PortInfo portInfo) {
List<Handler> list = new ArrayList<>();
list.add(new ClientHandler()); // 加入驗證 Handler
return list;
}
});
return service.getServicesPort().getResults(args.toString());
}
public class ClientHandler implements SOAPHandler<SOAPMessageContext> {
@Override
public boolean handleMessage(SOAPMessageContext ctx) {
Boolean outbound = (Boolean) ctx.get(MessageContext.MESSAGE_OUTBOUND_PROPERTY);
if (outbound) { // 輸出訊息,加入 Header
try {
SOAPMessage msg = ctx.getMessage();
SOAPEnvelope env = msg.getSOAPPart().getEnvelope();
SOAPHeader header = env.getHeader();
if (header == null) header = env.addHeader();
QName authQName = new QName("https://csdc.info/", "Authentication", "wsse");
SOAPHeaderElement authElem = header.addHeaderElement(authQName);
SOAPElement user = authElem.addChildElement("Username", "wsse");
user.addTextNode("admin");
SOAPElement pass = authElem.addChildElement("Password", "wsse");
pass.addTextNode("admin");
msg.saveChanges();
msg.writeTo(System.out); // 除錯輸出
return true;
} catch (Exception e) {
e.printStackTrace();
}
}
return false;
}
// 其他方法略...
}
<wsse:Authentication xmlns:wsse="https://csdc.info/">
<wsse:Username>admin</wsse:Username>
<wsse:Password>admin</wsse:Password>
</wsse:Authentication>
HandlerResolver 讓每個 Port 都能注入共同的 Handler 鏈。handleMessage 中判斷 MESSAGE_OUTBOUND_PROPERTY 只處理輸出訊息。QName 定義命名空間與前綴,確保對方能正確解析。