※SOAPBody
try { // 查API javax.xml.soap的MessageFactory和SOAPMessage就會有以下的順序 MessageFactory factory = MessageFactory.newInstance(); SOAPMessage msg = factory.createMessage(); SOAPPart part = msg.getSOAPPart(); SOAPEnvelope envlope = part.getEnvelope(); SOAPBody body = envlope.getBody(); // <xx:bMethod xmlns:xx="!@#" /> SOAPBodyElement element = body.addBodyElement(new QName("!@#", "bMethod", "xx")); element.setValue("1"); // element.setTextContent("1"); element.addChildElement("p1").setValue("2"); element.addChildElement("p2").setValue("3"); msg.writeTo(System.out); } catch (SOAPException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } -------------------- <SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/"> <SOAP-ENV:Header/> <SOAP-ENV:Body> <xx:bMethod xmlns:xx="!@#"> 1 <p1>2</p1> <p2>3</p2> </xx:bMethod> </SOAP-ENV:Body> </SOAP-ENV:Envelope>
※上面的測試是不需要啟動伺服器的
※主要程式
※IMessage.java
package webservice; import javax.jws.WebParam; import javax.jws.WebResult; import javax.jws.WebService; import jaxb.Dept; @WebService public interface IMessage { @WebResult(name = "dept") // 使用JAXB的unmarshal時,一定要叫dept,才能轉換,否則會出預期xxx的錯 public Dept aMethod(@WebParam(name = "dept") Dept d);// 使用XPath的NodeList時,一定要叫dept(預設是arg0),這樣XML才會正確,否則都找不到資料 /* @WebResult的name裡面不要有空格,將SOAPMessage傳進來時, 例如將「bFunctionReturn」改成「b function return」之後, 會出「關聯元素類型 "b" 的屬性名稱 "function" 之後必須緊接 ' = ' 字元。」的錯 */ @WebResult(name = "bFunctionReturn") public String bMethod(@WebParam(name = "num") Integer i); @WebResult(name = "dept") // 名稱要對應到QName,然後給HeaderElement public Dept cMethod(@WebParam(name = "headerName", header = true) String headInfo); }
※MessageImpl.java
package webservice; import java.util.ArrayList; import java.util.List; import javax.jws.WebService; import jaxb.Dept; import jaxb.Employee; @WebService(endpointInterface = "webservice.IMessage") public class MessageImpl implements IMessage { @Override public Dept aMethod(Dept dept) { System.out.println("a方法" + dept); return dept; } @Override public String bMethod(Integer i) { System.out.println("b方法"); return i + "b"; } @Override public Dept cMethod(String headInfo) { System.out.println("headInfo=" + headInfo); List<Employee> list = new ArrayList<>(); list.add(new Employee("e1", 1)); list.add(new Employee("e2", 2)); return new Dept("d1", 123, list); } }
※MyServer.java
package webservice; import javax.xml.ws.Endpoint; public class MyServer { public static void main(String[] args) { Endpoint.publish("http://localhost:8888/aaa/bbb/ccc", new MessageImpl()); System.out.println("server is start..."); } }
※打開xxx~~~?wsdl的網頁
<definitions ... targetNamespace="http://webservice/" name="MessageImplService"> ... <service name="MessageImplService"> <port name="MessageImplPort" binding="tns:MessageImplPortBinding"> <soap:address location="http://localhost:8888/aaa/bbb/ccc"/> </port> </service> </definitions>
※會用到definitions標籤的targetNamespace和name、還有service的子標籤port的name屬性
※測試Service.Mode.MESSAGE
import java.io.IOException; import java.net.MalformedURLException; import java.net.URL; import javax.xml.namespace.QName; import javax.xml.soap.MessageFactory; import javax.xml.soap.SOAPBody; import javax.xml.soap.SOAPBodyElement; import javax.xml.soap.SOAPEnvelope; import javax.xml.soap.SOAPException; import javax.xml.soap.SOAPMessage; import javax.xml.soap.SOAPPart; import javax.xml.ws.Dispatch; import javax.xml.ws.Service; import org.w3c.dom.Document; import org.w3c.dom.Node; import org.w3c.dom.NodeList; String ns = "http://webservice/"; try { URL url = new URL("http://localhost:8888/aaa/bbb/ccc?wsdl"); QName sqname = new QName(ns, "MessageImplService"); Service service = Service.create(url, sqname); QName qname = new QName(ns, "MessageImplPort"); Dispatch<SOAPMessage> dispatch = service.createDispatch(qname, SOAPMessage.class, Service.Mode.MESSAGE); MessageFactory factory = MessageFactory.newInstance(); SOAPMessage msg = factory.createMessage(); SOAPPart part = msg.getSOAPPart(); SOAPEnvelope envlope = part.getEnvelope(); SOAPBody body = envlope.getBody(); SOAPBodyElement element = body.addBodyElement(new QName(ns, "bMethod", "xx")); // 不打num會接收不到,物件會接收「null」字串;基本型別接收「0」 element.addChildElement("num").setValue("2"); msg.writeTo(System.out); System.out.println(); // 將msg傳到server SOAPMessage resMsg = dispatch.invoke(msg); resMsg.writeTo(System.out); System.out.println(); // 從server傳回來的訊息 Document doc = resMsg.getSOAPPart().getEnvelope().getBody().extractContentAsDocument(); NodeList nodeList = doc.getElementsByTagName("bFunctionReturn"); for (int i = 0; i < nodeList.getLength(); i++) { Node node = nodeList.item(i); System.out.println(node.getTextContent()); // 2b } } catch (MalformedURLException e) { e.printStackTrace(); } catch (SOAPException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } -------------------- <SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/"> <SOAP-ENV:Header/> <SOAP-ENV:Body> <xx:bMethod xmlns:xx="http://webservice/"> <num>2</num> </xx:bMethod> </SOAP-ENV:Body> </SOAP-ENV:Envelope> -------------------- <S:Envelope xmlns:S="http://schemas.xmlsoap.org/soap/envelope/" xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/"> <SOAP-ENV:Header/> <S:Body> <ns2:bMethodResponse xmlns:ns2="http://webservice/"> <bFunctionReturn>2b</bFunctionReturn> </ns2:bMethodResponse> </S:Body> </S:Envelope>
※
※Service.Mode.PAYLOAD
import java.io.StringReader; import java.io.StringWriter; import java.net.MalformedURLException; import java.net.URL; import java.util.ArrayList; import java.util.List; import javax.xml.bind.JAXBContext; import javax.xml.bind.JAXBException; import javax.xml.bind.Marshaller; import javax.xml.namespace.QName; import javax.xml.transform.Source; import javax.xml.transform.Transformer; import javax.xml.transform.TransformerConfigurationException; import javax.xml.transform.TransformerException; import javax.xml.transform.TransformerFactory; import javax.xml.transform.TransformerFactoryConfigurationError; import javax.xml.transform.dom.DOMResult; import javax.xml.transform.stream.StreamSource; import javax.xml.ws.Dispatch; import javax.xml.ws.Service; import javax.xml.xpath.XPath; import javax.xml.xpath.XPathConstants; import javax.xml.xpath.XPathExpressionException; import javax.xml.xpath.XPathFactory; import org.w3c.dom.NodeList; import jaxb.Dept; import jaxb.Employee; public void serviceModePAYLOADExample() { String ns = "http://webservice/"; try { URL url = new URL("http://localhost:8888/aaa/bbb/ccc?wsdl"); QName sqname = new QName(ns, "MessageImplService"); Service service = Service.create(url, sqname); QName qname = new QName(ns, "MessageImplPort"); Dispatch<Source> dispatch = service.createDispatch(qname, Source.class, Service.Mode.PAYLOAD); List<Employee> list = new ArrayList<>(); list.add(new Employee("Bruce", 123)); list.add(new Employee("Jacky", 456)); list.add(new Employee("Mary", 789)); Dept dept = new Dept("information", 2, list); JAXBContext jaxb = JAXBContext.newInstance(Dept.class); Marshaller ms = jaxb.createMarshaller(); // 去掉前面的<?xml version="1.0" encoding="UTF-8" standalone="yes"?> ms.setProperty(Marshaller.JAXB_FRAGMENT, true); StringWriter out = new StringWriter(); ms.marshal(dept, out); StringBuffer payload = new StringBuffer(); payload.append("<xxx:aMethod xmlns:xxx=\""); payload.append(ns); payload.append("\">"); payload.append(out.toString()); payload.append("</xxx:aMethod>"); System.out.println(payload); StreamSource rs = new StreamSource(new StringReader(payload.toString())); Source response = (Source) dispatch.invoke(rs); Transformer tran = TransformerFactory.newInstance().newTransformer(); DOMResult result = new DOMResult(); tran.transform(response, result); XPath xpath = XPathFactory.newInstance().newXPath(); // 如果是找dept它的子元素,能找到,但unmarshal會有錯誤 NodeList nodeList = (NodeList) xpath.evaluate("//dept", result.getNode(), XPathConstants.NODESET); System.out.println(nodeList.getLength()); for (int i = 0; i < nodeList.getLength(); i++) { System.out.println(nodeList.item(i)); Dept ru = (Dept) jaxb.createUnmarshaller().unmarshal(nodeList.item(i)); System.out.println(ru.getName() + System.getProperty("line.separator")); for (Employee emp : ru.getEmps()) { System.out.println(emp.getName()); } } } catch (MalformedURLException e) { e.printStackTrace(); } catch (JAXBException e) { e.printStackTrace(); } catch (TransformerConfigurationException e) { e.printStackTrace(); } catch (TransformerFactoryConfigurationError | TransformerException e) { e.printStackTrace(); } catch (XPathExpressionException e) { e.printStackTrace(); } }
※
※SOAP Header測試
import java.io.IOException; import java.net.MalformedURLException; import java.net.URL; import javax.xml.bind.JAXBContext; import javax.xml.bind.JAXBException; import javax.xml.namespace.QName; import javax.xml.soap.MessageFactory; import javax.xml.soap.SOAPBody; import javax.xml.soap.SOAPEnvelope; import javax.xml.soap.SOAPException; import javax.xml.soap.SOAPHeader; import javax.xml.soap.SOAPHeaderElement; import javax.xml.soap.SOAPMessage; import javax.xml.soap.SOAPPart; import javax.xml.ws.Dispatch; import javax.xml.ws.Service; import org.w3c.dom.Document; import org.w3c.dom.NodeList; import jaxb.Dept; public void soapHeadTest() { String ns = "http://webservice/"; try { URL url = new URL("http://localhost:8888/aaa/bbb/ccc?wsdl"); QName sqname = new QName(ns, "MessageImplService"); Service service = Service.create(url, sqname); QName qname = new QName(ns, "MessageImplPort"); Dispatch<SOAPMessage> dispatch = service.createDispatch(qname, SOAPMessage.class, Service.Mode.MESSAGE); MessageFactory factory = MessageFactory.newInstance(); SOAPMessage msg = factory.createMessage(); SOAPPart part = msg.getSOAPPart(); SOAPEnvelope envlope = part.getEnvelope(); SOAPBody body = envlope.getBody(); SOAPHeader header = envlope.getHeader(); if (header == null) { header = envlope.addHeader(); } SOAPHeaderElement headElement = header.addHeaderElement(new QName(ns, "headerName", "xx")); headElement.setValue("header value!"); body.addBodyElement(new QName(ns, "cMethod", "xx")); msg.writeTo(System.out); System.out.println(); // 將msg傳到server SOAPMessage resMsg = dispatch.invoke(msg); resMsg.writeTo(System.out); System.out.println(); // 從server傳回來的訊息 Document doc = resMsg.getSOAPPart().getEnvelope().getBody().extractContentAsDocument(); // Document doc = resMsg.getSOAPBody().extractContentAsDocument(); NodeList nodeList = doc.getElementsByTagName("dept"); JAXBContext jaxb = JAXBContext.newInstance(Dept.class); for (int i = 0; i < nodeList.getLength(); i++) { Dept dept = (Dept) jaxb.createUnmarshaller().unmarshal(nodeList.item(i)); System.out.println(dept.getName()); } } catch (MalformedURLException e) { e.printStackTrace(); } catch (SOAPException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } catch (JAXBException e) { e.printStackTrace(); } }
※
※Exception
加入Exception後,會在wsdl的網址出現fault的標籤@WebResult(name = "dept") public Dept dMethod(@WebParam(name = "name") String name, @WebParam(name = "did") int did) throws DeptException; -------------------- @Override public Dept dMethod(String name, int did) throws DeptException { if ("xxx".equals(name) && did == 111) { List<Employee> list = new ArrayList<>(); list.add(new Employee("e1", 1)); list.add(new Employee("e2", 2)); Dept dept = new Dept("xxx", 111, list); return dept; } /* * 使用RuntimeException,也會在伺服器端的console報錯,因為DeptException在wsdl的網頁有截取(fault * );而RuntimeException沒有 * 只要有在wsdl有設定Exception,截取到就會直接往客戶端拋,所以伺服器端沒有截取錯誤訊息 * 如沒有在wsdl設定,則伺服器端和客戶端接會拋出訊息 */ // throw new RuntimeException(name + " and " + did + " not match!" + // System.getProperty("line.separator")); throw new DeptException(name + " and " + did + " not match!" + System.getProperty("line.separator")); }
※name是xxx,did是111才不會出錯,但這裡要測試出錯,所以待會的測試類不要輸入這一組
※DeptException.java
public class DeptException extends Exception { public DeptException() { super(); } public DeptException(String arg0, Throwable arg1, boolean arg2, boolean arg3) { super(arg0, arg1, arg2, arg3); } public DeptException(String message, Throwable cause) { super(message, cause); } public DeptException(String message) { super(message); } public DeptException(Throwable cause) { super(cause); } }
※這裡的建構子都是用IDE產生的
※測試類
String ns = "http://webservice/"; try { URL url = new URL("http://localhost:8888/aaa/bbb/ccc?wsdl"); QName sqname = new QName(ns, "MessageImplService"); Service service = Service.create(url, sqname); QName qname = new QName(ns, "MessageImplPort"); Dispatch<SOAPMessage> dispatch = service.createDispatch(qname, SOAPMessage.class, Service.Mode.MESSAGE); MessageFactory factory = MessageFactory.newInstance(); SOAPMessage msg = factory.createMessage(); SOAPPart part = msg.getSOAPPart(); SOAPEnvelope envlope = part.getEnvelope(); SOAPBody body = envlope.getBody(); SOAPBodyElement element = body.addBodyElement(new QName(ns, "dMethod", "xx")); element.addChildElement("name").setValue("xxx");// 不打num會接收null;但如果是int會接收0 element.addChildElement("did").setValue("222"); msg.writeTo(System.out); System.out.println(); // 將msg傳到server SOAPMessage resMsg = dispatch.invoke(msg); resMsg.writeTo(System.out); System.out.println(); // 從server傳回來的訊息 Document doc = resMsg.getSOAPBody().extractContentAsDocument(); NodeList nodeList = doc.getElementsByTagName("dept"); JAXBContext jaxb = JAXBContext.newInstance(Dept.class); for (int i = 0; i < nodeList.getLength(); i++) { Dept dept = (Dept) jaxb.createUnmarshaller().unmarshal(nodeList.item(i)); for (Employee e : dept.getEmps()) { System.out.println(e.getName()); } } } catch (MalformedURLException e) { e.printStackTrace(); } catch (SOAPException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } catch (JAXBException e) { e.printStackTrace(); } catch (SOAPFaultException e) { // 不可截取DeptException,使用wsimport就可以知道 System.out.println(e.getMessage());// call DeptException(String) }
※
※Handler
LogicalHandler:獲取SOAPBody的訊息SOAPHandler:獲取SOAPMessage的訊息
伺服器和客戶端都可以設定很多LH的和SH
客戶端都先處理LH,全部的LH處理完才處理SH
伺服器端則相反
參考網址:apache JAVAEE連結
@WebService(endpointInterface = "webservice.IMessage") @HandlerChain(file="/soap/handler/handlers.xml") public class MessageImpl implements IMessage { // ... }
※這裡的@HandlerChain裡的xml路徑只要抓的到,在啟伺服器時才不會出錯
※handlers.xml
<?xml version="1.0" encoding="UTF-8"?> <handler-chains xmlns="http://java.sun.com/xml/ns/javaee"> <handler-chain> <handler> <handler-name>ooo.xxx.z1</handler-name> <handler-class>soap.handler.Handler1</handler-class> </handler> <handler> <handler-name>ooo.xxx.z2</handler-name> <handler-class>soap.handler.Handler2</handler-class> </handler> </handler-chain> </handler-chains>
※寫了兩支處理handler的xml,所以也要實作出來,將上面的網址複製下來改即可
※Handler1.xml
public class Handler1 implements SOAPHandler<SOAPMessageContext> { @Override public void close(MessageContext arg0) { System.out.println("s1 close"); } @Override public boolean handleFault(SOAPMessageContext arg0) { System.out.println("s1 handleFault"); return true; } @Override public boolean handleMessage(SOAPMessageContext arg0) { System.out.println("s1 handleMessage"); return true; } @Override public Set<QName> getHeaders() { System.out.println("s1 getHeaders"); return null; } }
※
※Handler2.java
public class Handler2 implements SOAPHandler<SOAPMessageContext> { @Override public void close(MessageContext arg0) { System.out.println("s2 close"); } @Override public boolean handleFault(SOAPMessageContext arg0) { System.out.println("s2 handleFault"); return true; } @Override public boolean handleMessage(SOAPMessageContext arg0) { System.out.println("s2 handleMessage"); return true; } @Override public Set<QName> getHeaders() { System.out.println("s2 getHeaders"); return null; } }
※測試時還是用Exception的測試類
※沒有錯時的結果為:
s1 getHeaders
s2 getHeaders
server is start...
s2 handleMessage
s1 handleMessage
s1 handleMessage
s2 handleMessage
s1 close
s2 close
※有錯時的結果為:
s1 getHeaders
s2 getHeaders
server is start...
s2 handleMessage
s1 handleMessage
s1 handleFault
s2 handleFault
s1 close
s2 close
※可以發現在啟何服器時都會先執行兩支的getHeaders方法,結束也都會執行close
※有錯時才會執行handleFault方法
※要注意handleMessage和其他是相反的,先執行s2;後執行s1
沒錯時,一支handleMessage是request和response,共兩次;有錯時只會執行一次
※handleMessage執行完才會執行Exception;使用RuntimeException還是會在伺服器端報錯
沒有留言:
張貼留言