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

WSDL:WebService描述语言

主要是用来描述接口的,包括接口的参数和返回值

基本结构

<definition>
    <types>
        定义webservice使用的数据类型
    </types>
    
    <message>
        一个消息都有一个或多个部件组成。可以把它当作java中函数的参数
    </message>
    
    <portType>
        它类似于Java中的一个函数库(或一个模板、或一个类)
    <portType>
    
    <binding>
        为每个端口定义消息格式和协议细节
    </binding>
</definition>

UDDI:统一描述、发现和集成协议

主要定义服务描述和发现的规范,规定不同的厂商、不同的平台之间服务的彼此发现、互相作用。

JAXB: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)的网站,等这个项目忙完,考虑做一个简单的天气预报网站开源。

如有错误,欢迎批评指正!

 

posted @ 2021-01-13 19:23  小楼夜听雨QAQ  阅读(449)  评论(0编辑  收藏  举报