java整合webservice笔记
最近要做的一个项目,用到了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
基本结构
<definition> <types> 定义webservice使用的数据类型 </types> <message> 一个消息都有一个或多个部件组成。可以把它当作java中函数的参数 </message> <portType> 它类似于Java中的一个函数库(或一个模板、或一个类) <portType> <binding> 为每个端口定义消息格式和协议细节 </binding> </definition>
UDDI:统一描述、发现和集成协议
主要定义服务描述和发现的规范,规定不同的厂商、不同的平台之间服务的彼此发现、互相作用。
Java对象和XML互转
soap本身就是利用http协议传输xml格式的数据。
所以在使用webservice的过程中,自然要进行java对象和xml的转换。但是在开发过程中,因为框架(例如 cxf)已经做了一层封装,我们不需要再做这种底层的解析,只需要专注于业务即可。
但还是有必要了解一下。
(注意,涉及工具类是javax包中的库,无需添加额外jar包)
import javax.xml.bind.JAXBContext; import javax.xml.bind.JAXBException; import javax.xml.bind.Marshaller; import javax.xml.bind.Unmarshaller; import java.io.FileNotFoundException; import java.io.StringReader; public class JAXBTest { // 将java对象转化成xml public static void myMarshaller() throws JAXBException, 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() throws JAXBException { String xmlString = "<?xml version=\"1.0\" encoding=\"utf-8\" standalone=\"yes\"?><book><bookName>java</bookName><id>11</id><price>25.8</price></book>"; JAXBContext jaxbContext = JAXBContext.newInstance(Book.class); Unmarshaller unmarshaller = jaxbContext.createUnmarshaller(); Book book = (Book) unmarshaller.unmarshal(new StringReader(xmlString)); System.out.println(book); } public static void main(String[] args) throws JAXBException, FileNotFoundException { // myMarshaller(); myUnmarshaller(); } }
Book对象
import javax.xml.bind.annotation.XmlRootElement; @XmlRootElement public class Book { private long id; private String bookName; private double price; public Book() {} public Book(long id, String bookName, double price) { this.id = id; this.bookName = bookName; this.price = price; } public long getId() { return id; } public void setId(long id) { this.id = id; } public String getBookName() { return bookName; } public void setBookName(String bookName) { this.bookName = bookName; } public double getPrice() { return price; } public void setPrice(double price) { this.price = price; } @Override public String toString() { return "Book{" + "id=" + id + ", bookName='" + bookName + '\'' + ", price=" + price + '}'; } }
测试代码
环境部署
下载 apache cxf
地址:http://cxf.apache.org/download.html
解压文件,将lib文件夹下的jar包复制到项目中
在idea或者eclipse中添加进项目,比如idea中
服务端
接口
import javax.jws.WebMethod; import javax.jws.WebParam; import javax.jws.WebResult; import javax.jws.WebService; @WebService public interface HelloWorld { @WebMethod @WebResult(name = "sayHelloRetValue") String sayHello(@WebParam(name = "username") String name, @WebParam(name = "age") int age); }
接口实现
public class HelloWorldImpl implements HelloWorld{ @Override public String sayHello(String name, int age) { return "我是"+name+",我"+age+"岁"; } }
发布
public class MainServer { public static void main(String[] args) { JaxWsServerFactoryBean jaxWsServerFactoryBean = new JaxWsServerFactoryBean(); jaxWsServerFactoryBean.setAddress("http://localhost:9999/ws"); jaxWsServerFactoryBean.setServiceClass(HelloWorldImpl.class); Server server = jaxWsServerFactoryBean.create(); server.start(); } }
访问
http://localhost:9999/ws?wsdl
查看对服务接口的描述文件,也就是wsdl
客户端
public class ClientTest { public static void main(String[] args) { JaxWsProxyFactoryBean jaxWsProxyFactoryBean = new JaxWsProxyFactoryBean(); 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 class ClientTest { public static void main(String[] args) { HelloWorld test = new HelloWorldImplService().getHelloWorldImplPort(); System.out.println(test.sayHello("nihao", 18)); } }
拓展
webservice不仅支持soap协议,还支持http+json格式的rest风格接口。
只是这种方式就没有wsdl文件了。
实体类:
import javax.xml.bind.annotation.XmlRootElement; @XmlRootElement public class Employee { private Integer id; private String name; private int age; public Employee(){} public Employee(Integer id, String name, int age) { this.id = id; this.name = name; this.age = age; } public Integer getId() { return id; } public void setId(Integer id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } @Override public String toString() { return "Employee{" + "id=" + id + ", name='" + name + '\'' + ", age=" + age + '}'; } }
接口
@Path("/crm") public interface EmployeeService { @GET @Path("/employee/{uuid}") // @Produces("application/xml") @Produces("application/json") public Employee getEmployeeById(@PathParam("uuid") Integer uuid); }
接口实现
public class EmployeeServiceImpl implements EmployeeService{ @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); return employee; } }
服务启动
public class MainServer { public static void main(String[] args) { JAXRSServerFactoryBean jaxrsServerFactoryBean = new JAXRSServerFactoryBean(); 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)的网站,等这个项目忙完,考虑做一个简单的天气预报网站开源。
如有错误,欢迎批评指正!