最近要做的一个项目,用到了webservice,使用soap(http+xml)协议和上层系统通信。
一边感叹技术古老,一边简单的学习了一下,做一点笔记。
相关定义
SOAP:简单对象访问协议
基本构成
必需的Envelope元素,可把此xml文档标识为一条SOAP消息
可选的Header元素,包含头部信息
必选的body元素,包含所有的调用和响应信息
可选的Fault元素,提供有关在处理此消息所发生错误的信息
一次webservice的调用,不是方法的调用,而是soap消息(xml格式规范的文档片段)之间的输入输出。
简而言之,soap = http协议 + xml形式的消息
soap协议的调用过程
1、客户端到UUDI上寻找service目录
2、客户端获得wsdl文件
3、客户端按照wsdl文件的约束和规范创建SOAP客户端。
4、客户端通过SOAP访问Service
WSDL:WebService描述语言
主要是用来描述接口的,包括接口的参数和返回值
基本结构
定义webservice使用的数据类型
一个消息都有一个或多个部件组成。可以把它当作java中函数的参数
它类似于Java中的一个函数库(或一个模板、或一个类)
为每个端口定义消息格式和协议细节
UDDI:统一描述、发现和集成协议
主要定义服务描述和发现的规范,规定不同的厂商、不同的平台之间服务的彼此发现、互相作用。
JAXB:Java对象和XML互转
soap本身就是利用http协议传输xml格式的数据。
所以在使用webservice的过程中,自然要进行java对象和xml的转换。但是在开发过程中,因为框架(例如 cxf)已经做了一层封装,我们不需要再做这种底层的解析,只需要专注于业务即可。
但还是有必要了解一下。
(注意,涉及工具类是javax包中的库,无需添加额外jar包)
importjavax.xml.bind.JAXBContext;importjavax.xml.bind.JAXBException;importjavax.xml.bind.Marshaller;importjavax.xml.bind.Unmarshaller;importjava.io.FileNotFoundException;importjava.io.StringReader;public classJAXBTest {//将java对象转化成xml
public static void myMarshaller() throwsJAXBException, FileNotFoundException {
JAXBContext jaxbContext= JAXBContext.newInstance(Book.class);
Marshaller marshaller=jaxbContext.createMarshaller();//格式化输出,如果不加这一行,就是非格式化输出
marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);//编码
marshaller.setProperty(Marshaller.JAXB_ENCODING, "utf-8");//输出到控制台
marshaller.marshal(new Book(11, "java", 25.8d), System.out);//输出到文件//marshaller.marshal(new Book(11, "java", 25.8d), new FileOutputStream("hello.txt"));
}//将xml转化成java对象
public static void myUnmarshaller() throwsJAXBException {
String xmlString= "<?xml version=\"1.0\" encoding=\"utf-8\" standalone=\"yes\"?>java1125.8";
JAXBContext jaxbContext= JAXBContext.newInstance(Book.class);
Unmarshaller unmarshaller=jaxbContext.createUnmarshaller();
Book book= (Book) unmarshaller.unmarshal(newStringReader(xmlString));
System.out.println(book);
}public static void main(String[] args) throwsJAXBException, FileNotFoundException {//myMarshaller();
myUnmarshaller();
}
}
Book对象
importjavax.xml.bind.annotation.XmlRootElement;
@XmlRootElementpublic classBook {private longid;privateString bookName;private doubleprice;publicBook() {}public Book(long id, String bookName, doubleprice) {this.id =id;this.bookName =bookName;this.price =price;
}public longgetId() {returnid;
}public void setId(longid) {this.id =id;
}publicString getBookName() {returnbookName;
}public voidsetBookName(String bookName) {this.bookName =bookName;
}public doublegetPrice() {returnprice;
}public void setPrice(doubleprice) {this.price =price;
}
@OverridepublicString toString() {return "Book{" +
"id=" + id +
", bookName='" + bookName + '\'' +
", price=" + price +
'}';
}
}
测试代码
环境部署
下载 apache cxf
地址:http://cxf.apache.org/download.html
解压文件,将lib文件夹下的jar包复制到项目中
在idea或者eclipse中添加进项目,比如idea中
服务端
接口
importjavax.jws.WebMethod;importjavax.jws.WebParam;importjavax.jws.WebResult;importjavax.jws.WebService;
@WebServicepublic interfaceHelloWorld {
@WebMethod
@WebResult(name= "sayHelloRetValue")
String sayHello(@WebParam(name= "username") String name, @WebParam(name = "age") intage);
}
接口实现
public class HelloWorldImpl implementsHelloWorld{
@Overridepublic String sayHello(String name, intage) {return "我是"+name+",我"+age+"岁";
}
}
发布
public classMainServer {public static voidmain(String[] args) {
JaxWsServerFactoryBean jaxWsServerFactoryBean= newJaxWsServerFactoryBean();
jaxWsServerFactoryBean.setAddress("http://localhost:9999/ws");
jaxWsServerFactoryBean.setServiceClass(HelloWorldImpl.class);
Server server=jaxWsServerFactoryBean.create();
server.start();
}
}
访问
http://localhost:9999/ws?wsdl
查看对服务接口的描述文件,也就是wsdl
客户端
public classClientTest {public static voidmain(String[] args) {
JaxWsProxyFactoryBean jaxWsProxyFactoryBean= newJaxWsProxyFactoryBean();
jaxWsProxyFactoryBean.setAddress("http://localhost:9999/ws");
jaxWsProxyFactoryBean.setServiceClass(HelloWorld.class);
HelloWorld helloWorld=(HelloWorld) jaxWsProxyFactoryBean.create();
String hello= helloWorld.sayHello("hello", 18);
System.out.println(hello);
}
}
目录结构
Book
wsdl文件生成java代码
上述代码的问题在于,服务端和客户端都放在一个项目中,所以可以公用服务接口。
现实项目中,只要涉及和其他系统对接,对方只会给你一个wsdl文件,我们需要通过wsdl文件来生成java类。
进入cxf的bin目录
命令行中打开,后面的地址可以是对方系统给的wsdl路径(必须在同一网段),
也可以是wsdl文件的所在的本地路径。
.\wsdl2java http://localhost:9999/ws?wsdl
bin目录下,将会出现自动生成的代码
将com文件夹复制到项目中
和我们的业务有关的只有前面两个,后面的类是对方法/接口的一些描述信息,用不到可以删掉。
最后客户端的结构为
服务消费
public classClientTest {public static voidmain(String[] args) {
HelloWorld test= newHelloWorldImplService().getHelloWorldImplPort();
System.out.println(test.sayHello("nihao", 18));
}
}
拓展
webservice不仅支持soap协议,还支持http+json格式的rest风格接口。
只是这种方式就没有wsdl文件了。
实体类:
importjavax.xml.bind.annotation.XmlRootElement;
@XmlRootElementpublic classEmployee {privateInteger id;privateString name;private intage;publicEmployee(){}public Employee(Integer id, String name, intage) {this.id =id;this.name =name;this.age =age;
}publicInteger getId() {returnid;
}public voidsetId(Integer id) {this.id =id;
}publicString getName() {returnname;
}public voidsetName(String name) {this.name =name;
}public intgetAge() {returnage;
}public void setAge(intage) {this.age =age;
}
@OverridepublicString toString() {return "Employee{" +
"id=" + id +
", name='" + name + '\'' +
", age=" + age +
'}';
}
}
接口
@Path("/crm")public interfaceEmployeeService {
@GET
@Path("/employee/{uuid}")//@Produces("application/xml")
@Produces("application/json")public Employee getEmployeeById(@PathParam("uuid") Integer uuid);
}
接口实现
public class EmployeeServiceImpl implementsEmployeeService{
@Override
@GET
@Path("/employee/{uuid}")//@Produces("application/xml") 返回xml格式
@Produces("application/json")public Employee getEmployeeById(@PathParam("uuid") Integer uuid) {
System.out.println("获的了uuid" +uuid);
Employee employee= new Employee(100, "admin", 18);returnemployee;
}
}
服务启动
public classMainServer {public static voidmain(String[] args) {
JAXRSServerFactoryBean jaxrsServerFactoryBean= newJAXRSServerFactoryBean();
jaxrsServerFactoryBean.setAddress("http://localhost:8888/rest");
jaxrsServerFactoryBean.setResourceClasses(EmployeeServiceImpl.class);
jaxrsServerFactoryBean.create();
}
}
调用
http://localhost:8888/rest/crm/employee/1
浏览器效果
参考
参考视频:
https://www.bilibili.com/video/BV1xE411d7hY?p=1
网上有一些免费提供web服务(webservice)的网站,等这个项目忙完,考虑做一个简单的天气预报网站开源。
如有错误,欢迎批评指正!