由于现在WebService服务,用的最多的是http协议,最近研究了下soap协议(带请求头)报文的请求,以此总结一下写个笔记忘日后观看,有说的不对的地方请大家指出来,虚心讨教。
话不多说直接上干货。
1.首先我就用最简单的方式,jdk自带的webService发布服务。
1.1:准备工作,写一个接口,一个实现类,加一个测试类用来发布服务。截图如下:
接口截图:
实现类截图:
发布测试类截图:
简述:
@WebParam(name="USERS") Users user1 -------这个注解是指定接受报文的body信息名字为USERS的参数,如果不写系统会默认比如:arg0;
@WebParam(header = true, name = "auth") HisCallHeader user ------这个注解和上面有所不同是多了个header参数的设置,当header=true时时代表在报文的头信息中接受名字为auth的,如果不写则接受不到头信息的内容,同理不指定名字的话会系统会默认一个名字,在这里我们所有的接受参数都设置一个指定的名字,这样在实际项目中更加清晰明了。
@WebParam(header = true,name="parameter") HisCallParameter in) -----同上
@WebService(targetNamespace = "http://www.webser.com") -------这个targetNamespace参数可以不写,默认为当前类的包名,这里我们给它命名一个名字稍后我会解释下命名之后的好处,这里的命名可以随便写没什么限制,但大多数都会用http://*******,这样命名。
实际操作开始:使用eclispe中的自带的WebService工具去访问我的服务,
讲道理这个工具真的很好可以方便我们查看soap报文的格式:
(由于SOAP=RPC+HTTP+XML:采用HTTP作为底层通讯协议,
1.1:命名空间部分:
1.2:头部信息部分
1.3:body身体部分:
*****重点讲一个头部部分,因为这块容易出问题:
<ns:auth xmlns:ns="http://www.webser.com">
(我们自定义的命名空间以这种方式)
<q0:parameter>
(引用soap中报文最上部分的q0命名空间,也就是服务端规定的)
说一下上面这两个参数,里面那些参数是类里面的属性,我们就不多说了,这里面我只说实体类
其中auth,parameter这两个名字是我为两个实体类起的接受时指定的名字。
1.前面我说过如果我在编写WebService服务端的时候如果不写命名空间的会某人为包名,写的话系统会在soap报文中的命名空间处显示的是我们所命名的空间名 如下图:
详解:回过头来继续说,当我的参数引用这个服务器端规定的命名空间时我才会接收到,如果不是该命名空间则接受不到信息,而是为null,那么这个时候就会有人问上述头部信息中的这两个参数为什么不都引用“q0”这个我们服务端指定好的命名空间名字,为什么还用我们自定义一个命名空间,我个人理解哦一个报文如果由多个服务端读取的话,这样就便于根据命名空间去接受,这个根据命名空间名称服务端去选择接受那个参数。
我上述截图中头信息参数名字为“auth“它是我自定义的命名空间,但是我命名的名字适是和"q0"是一样的所以服务端可以接受到它,如果不一样我改成别的,跟服务端的命名空间不一样,那么服务端接收不到此信息。
下面简单提及一下body(身体部分)的有人会问“<q0:hiscall>"这块可不可以自定义命名一个呢,这块这个"hiscall“它是我们服务端的方法名称,这个方法里面接受头部的参数,body中的参数,如果和更改了命名空间,那个我们还如何访问该方法,又如何去取的参数,所以这块命名空间建议和系统一样(如果大家更改过可以使用那么请留言告诉我,我也学习一下,目前经常尝试仅仅了解这样);
服务端的返回值:
服务端接口以及实体类返回值什么都是可以字符串对象啦等等,而我用的是httpURLConnection,用输出流发送的字符串拼接的soap报文。
接受的是用输入流接受的拼接成字符串,你会发现这个字符串是soap响应报文,如果想取的里面的信息,就是dom解析xml节点的方式来获取即可。稍后我会贴出代码,大家参考下。
==========================================================================
服务端代码展示:
1.服务端接口
package abc;
import javax.jws.WebMethod;
import javax.jws.WebParam;
import javax.jws.WebService;
import com.Users;
@WebService
public interface SoapWebServvice {
@WebMethod
public Users hiscall(@WebParam(name="USERS") Users user1,
@WebParam(header = true, name = "auth") HisCallHeader user,
@WebParam(header = true,name="parameter") HisCallParameter in );
}
2.服务端接口实现类:
注解:(我把接受到的Users返回给了客户端,由客户端用dom解析)
package abc;
import java.util.HashSet;
import javax.jws.WebMethod;
import javax.jws.WebParam;
import javax.jws.WebService;
import javax.xml.namespace.QName;
import com.Users;
@WebService(targetNamespace = "http://www.webser.com")
public class SoapWebServviceImpl implements SoapWebServvice {
@Override
public Users hiscall(@WebParam(name="USERS") Users user1,
@WebParam(header = true, name = "auth") HisCallHeader user,
@WebParam(header = true,name="parameter") HisCallParameter in)//消息头)
{
System.out.println("接受数据头部:"+user);
System.out.println("不同命名空间:"+in);
System.out.println("接受数据身体:"+user1);
return user1; }
}
3.服务端WebService发布类:
package com;
import javax.xml.ws.Endpoint;
import abc.SoapWebServviceImpl;
public class TestWeb {
public static void main(String[] args) {
String url = "http://localhost:8080/webSer/ws";
//jdk发布
SoapWebServviceImpl wsi = new SoapWebServviceImpl();
Endpoint.publish(url,wsi);
System.out.println("服务发布成功");}
}
4.Users 实体类
package com;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;
import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlType;
public class Users implements Serializable{
private String name;
private String age;
private Double price;
private List<Users> list = new ArrayList<Users>();
public List<Users> getList() {
return list;
}
public void setList(List<Users> list) {
this.list = list;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getAge() {
return age;
}
public void setAge(String age) {
this.age = age;
}
public Double getPrice() {
return price;
}
public void setPrice(Double price) {
this.price = price;
}
public String toString() {
return "User [name=" + getName() + ", age=" + getAge() + ", price=" + getPrice() + "]";
}
}
5.HisCallHeader 实体类
package abc;
import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlType;
public class HisCallHeader {
//用户名
protected String userName;
//密码
protected String passWord;
//对称加***
protected String aesKey;
public String getUserName() {
return userName;
}
public void setUserName(String userName) {
this.userName = userName;
}
public String getPassWord() {
return passWord;
}
public void setPassWord(String passWord) {
this.passWord = passWord;
}
public String getAesKey() {
return aesKey;
}
public void setAesKey(String aesKey) {
this.aesKey = aesKey;
}
@Override
public String toString() {
return "HisCallHeader [userName=" + this.getUserName() + ", passWord=" + this.getPassWord()
+ ", aesKey=" + this.getAesKey() + "]"; }
}
6.HisCallParameter 实体类
package abc;
import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlType;
public class HisCallParameter {
protected String jybh;
protected String inputxml;
public String getJybh() {
return jybh;
}
public void setJybh(String value) {
this.jybh = value;
}
public String getInputxml() {
return inputxml;
}
public void setInputxml(String value) {
this.inputxml = value;
}
@Override
public String toString() {
return "HisCallParameter [jybh=" + this.getJybh() + ", inputxml=" + this.getInputxml()
+ "]";}
}
客户端代码展示:
注解:头部信息参数那个类的在客户端我没创建,参数都写死了,拼接在字符串中,大家仔细看一下,只创建了Body部分参数的类User
1..user实体类
package tests;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;
import com.thoughtworks.xstream.annotations.XStreamAlias;
public class User implements Serializable{
private String name;
private String age;
private Double price;
public User(){
}
public User(String name,String age,double price){
this.setName(name);
this.setAge(age);
this.setPrice(price);
}
private List<User> list = new ArrayList<User>();
public List<User> getList() {
return list;
}
public void setList(List<User> list) {
this.list = list;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getAge() {
return age;
}
public void setAge(String age) {
this.age = age;
}
public Double getPrice() {
return price;
}
public void setPrice(Double price) {
this.price = price;
}
@Override
public String toString() {
return "User [name=" + getName() + ", age=" + getAge() + ", price=" + getPrice() + "]";
}
}
2.客户端测试类
注解:响应报文我只查看了一个“name”字段的名字,其中服务发布的地址后面写不写后缀“?wsdl”都可以,“httpConn.connect();”这一句加不加也无所谓都不影响
package tests;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.net.HttpURLConnection;
import java.net.URL;
import java.net.URLConnection;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import org.apache.commons.collections.map.HashedMap;
import org.apache.poi.hssf.record.UserSViewBegin;
import org.apache.xmlbeans.impl.soap.SOAPHeader;
import org.bouncycastle.util.encoders.UrlBase64;
import org.codehaus.jackson.JsonGenerationException;
import org.codehaus.jackson.map.JsonMappingException;
import org.codehaus.jackson.map.ObjectMapper;
import org.dom4j.Document;
import org.dom4j.DocumentHelper;
import org.dom4j.Element;
import com.WebServiceImpl;
import com.WebServiceImplService;
import com.gome.common.xStream.XStreamUtil;
public class Tests {
public static Map<String,Object> map = new HashedMap();
public static void main(String[] args) throws Exception
{
User u = new User();
List<User> list = new ArrayList<User>();
list.add(new User("张一","15",100.00));
list.add(new User("张二","16",1000.00));
list.add(new User("张三","17",10000.00));
u.setList(list);
StringBuilder soap=new StringBuilder(); //构造请求报文
soap.append(" <soapenv:Envelope xmlns:soapenv=\"http://schemas.xmlsoap.org/soap/envelope/\" "+"\n");
soap.append("xmlns:q0=\"http://www.webser.com\" ");
soap.append("xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\" ");
soap.append("xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"> ");
soap.append("<soapenv:Header>"+"\n");
soap.append("<ns:auth xmlns:ns=\"http://www.webser.com\">"+"\n");
soap.append("<userName>1</userName>"+"\n");
soap.append("<passWord>2 </passWord>"+"\n");
soap.append("<aesKey>3</aesKey>"+"\n");
soap.append("</ns:auth>"+"\n");
soap.append("<ns:parameter xmlns:ns=\"http://www.wsm.com\">");
soap.append("<jybh>1</jybh>");
soap.append("<inputxml>2</inputxml>");
soap.append("</ns:parameter>");
soap.append("</soapenv:Header>"+"\n");
soap.append(" <soapenv:Body>"+"\n");
soap.append(" <q0:hiscall>"+"\n");
soap.append(" <USERS>"+"\n");
soap.append(" <name>二狗</name>"+"\n");
soap.append(" <age>18</age>"+"\n");
soap.append(" <price>1000000.00</price>"+"\n");
soap.append(" </USERS>"+"\n");
soap.append(" </q0:hiscall>"+"\n");
soap.append(" </soapenv:Body>"+"\n");
soap.append(" </soapenv:Envelope>"+"\n");
System.out.println("soap封装数据"+soap.toString());
String urlString = "http://localhost:8080/webSer/ws";//wsdl文档的地址
URL url = new URL(urlString);
HttpURLConnection httpConn = (HttpURLConnection) url.openConnection();//打开连接
httpConn.setRequestProperty("Content-Type", "text/xml; charset=utf-8");
httpConn.setRequestMethod("POST");
httpConn.setDoOutput(true);
httpConn.setDoInput(true);
httpConn.connect();
OutputStream out = httpConn.getOutputStream();
OutputStreamWriter osw = new OutputStreamWriter(out);
osw.write(soap.toString());
osw.flush();
out.close();
String result="";
if (httpConn.getResponseCode() == HttpURLConnection.HTTP_OK)
{
InputStream inputStream = httpConn.getInputStream();
InputStreamReader isr = new InputStreamReader(inputStream);
BufferedReader bf = new BufferedReader(isr);
String line;
while((line=bf.readLine())!=null){
result+=line;
}
System.out.println("接受:"+result);
bf.close();
inputStream.close();
}
httpConn.disconnect();
//解析response
Document doc = DocumentHelper.parseText(result);//报文转成doc对象
Element root = doc.getRootElement();//获取根元素,准备递归解析这个XML树
getCode(root);
System.out.println(map.get("name"));
}
public static void getCode(Element root){
if(root.elements()!=null){
List<Element>list = root.elements();//如果当前跟节点有子节点,找到子节点
for(Element e:list){//遍历每个节点
if(e.elements().size()>0){
getCode(e);//当前节点不为空的话,递归遍历子节点;
}
if(e.elements().size()==0){
map.put(e.getName(), e.getTextTrim());
}//如果为叶子节点,那么直接把名字和值放入map
}
}
}