WSDL
definitions
为根节点,属性为
name
:WS 名称,默认为“实现类 + Service”
targetNamespace
:WS 目标命名空间,默认为“WS 实现类对应包名倒排后构成的地址”
definitions
的5个子节点
types
:描述了 WS 中所涉及的数据类型
portType
:定义了 WS 接口名称portType.name
(endpointInterface
默认为“WS 实现类所实现的接口”),及其操作名称,以及每个操作的输入与输出消息
message
:对相关消息进行了定义(供 types 与 portType 使用)
binding
:提供了对 WS 的数据绑定方式
service
:WS 名称及其端口名称service_port.name
(portName
默认为“WS 实现类 + Port”),以及对应的 WSDL 地址
SOAP
header
body
一
、产品
soap风格 (JAX-WS规范JSR-224)
JAX-WS RI:https://jax-ws.java.net/ Oracle 官方提供的实现
Axis:http://axis.apache.org/
CXF:http://cxf.apache.org/
rest风格 (JAX-RS规范JSR-339)
Jersey:https://jersey.java.net/ Oracle 官方提供的实现
Restlet:http://restlet.com/
RESTEasy:http://resteasy.jboss.org/
CXF:http://cxf.apache.org/
二
、JDK发布与调用
1
.发布
定义接口
//此注解必须
@WebService
public interface HelloService {
String say();
}
实现接口
@WebService(serviceName = "HelloService",
portName = "HelloServicePort",
endpointInterface = "org.sllx.practice.jdkws.HelloService")
public class HelloServiceImpl implements HelloService {
@Override
public String say() {
return "helloWorld";
}
}
发布服务
public class Server {
public static void main(String[] args){
String address = "http://localhost:8081/ws/soap/hello";
HelloService helloService = new HelloServiceImpl();
Endpoint.publish(address, helloService);
System.out.println("ws is published [" + address + "?wsdl]");
}
}
访问http://localhost:8081/ws/soap/hello?wsdl
即可查看详情
2
.调用
静态客户端
wsimport http://localhost:8080/ws/soap/hello?wsdl
//通过 WSDL 地址生成 class 文件
jar -cf client.jar .
//通过 jar 命令将若干 class 文件压缩为一个 jar 包
rmdir /s/q demo
//删除生成的 class 文件(删除根目录即可)
public static void main(String[] args){
HelloService_Service hss = new HelloService_Service();
HelloService hs = hss.getHelloServicePort();
System.out.println(hs.say());
}
动态代理客户端
只需提供HelloService
接口,无需jar
public static void main(String[] args){
try {
URL wsdl = new URL("http://localhost:8081/ws/soap/hello?wsdl");
QName serviceName = new QName("http://jdkws.practice.sllx.org/", "HelloService");
QName portName = new QName("http://jdkws.practice.sllx.org/", "HelloServicePort");
Service service = Service.create(wsdl, serviceName);
HelloService helloService = service.getPort(portName, HelloService.class);
String result = helloService.say();
System.out.println(result);
} catch (Exception e) {
e.printStackTrace();
}
}
三
、CXF
User为自定义的POJO类
web发布示例集成spring
1.
SOAP风格
定义接口
package top.rainynight.sitews.user.ws;
import top.rainynight.sitews.user.entity.User;
import javax.jws.WebService;
@WebService
public interface UserWS {
User lookOver(int id);
}
实现接口
package top.rainynight.sitews.user.ws;
import top.rainynight.sitews.user.entity.User;
import org.springframework.stereotype.Component;
@Component("userWS")
public class UserWSImpl implements UserWS {
@Override
public User lookOver(int id) {
return new User();
}
}
发布服务
①Jetty发布
配置依赖
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<cxf.version>3.0.0</cxf.version>
</properties>
<dependencies>
<dependency>
<groupId>org.apache.cxf</groupId>
<artifactId>cxf-rt-frontend-jaxws</artifactId>
<version>${cxf.version}</version>
</dependency>
<dependency>
<groupId>org.apache.cxf</groupId>
<artifactId>cxf-rt-transports-http-jetty</artifactId>
<version>${cxf.version}</version>
</dependency>
</dependencies>
发布
public class JaxWsServer {
public static void main(String[] args) {
JaxWsServerFactoryBean factory = new JaxWsServerFactoryBean();
factory.setAddress("http://localhost:8080/ws/user");
factory.setServiceClass(UserWS.class);
factory.setServiceBean(new UserWSImpl());
factory.create();
System.out.println("soap ws is published");
}
}
访问http://localhost:8080/ws/user?wsdl
②Web发布
配置依赖
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<spring.version>4.0.5.RELEASE</spring.version>
<cxf.version>3.0.0</cxf.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-web</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.apache.cxf</groupId>
<artifactId>cxf-rt-frontend-jaxws</artifactId>
<version>${cxf.version}</version>
</dependency>
<dependency>
<groupId>org.apache.cxf</groupId>
<artifactId>cxf-rt-transports-http</artifactId>
<version>${cxf.version}</version>
</dependency>
</dependencies>
配置web.xml
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>
classpath:spring.xml
</param-value>
</context-param>
<servlet>
<servlet-name>cxf</servlet-name>
<servlet-class>org.apache.cxf.transport.servlet.CXFServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>cxf</servlet-name>
<url-pattern>/*</url-pattern>
</servlet-mapping>
发布
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:jaxws="http://cxf.apache.org/jaxws"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-4.0.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd
http://cxf.apache.org/jaxws
http://cxf.apache.org/schemas/jaxws.xsd">
<context:component-scan base-package="top.rainynight.sitews.user.ws" />
<!-- 下面的方法更简单
<jaxws:server address="/ws/user">
<jaxws:serviceBean>
<ref bean="userWS"/>
</jaxws:serviceBean>
</jaxws:server>
-->
<jaxws:endpoint implementor="# userWS" address="/ws/user" />
</beans>
访问http://localhost:8080/ws/user?wsdl
调用服务
①静态客户端
public class JaxWsClient {
public static void main(String[] args) {
JaxWsProxyFactoryBean factory = new JaxWsProxyFactoryBean();
factory.setAddress("http://localhost:8080/ws/user");
factory.setServiceClass(UserWS .class);
UserWS userWS = factory.create(UserWS .class);
User result = userWS .lookOver(1);
System.out.println(result);
}
}
②动态代理客户端
public class JaxWsDynamicClient {
public static void main(String[] args) {
JaxWsDynamicClientFactory factory = JaxWsDynamicClientFactory.newInstance();
Client client = factory.createClient("http://localhost:8080/ws/user?wsdl");
try {
Object[] results = client.invoke("lookOver", 1);
System.out.println(results[0]);
} catch (Exception e) {
e.printStackTrace();
}
}
}
③通用动态代理客户端
既可调用 JAX-WS 服务,也可调用 Simple 服务
public class DynamicClient {
public static void main(String[] args) {
DynamicClientFactory factory = DynamicClientFactory.newInstance();
Client client = factory.createClient("http://localhost:8080/ws/user?wsdl");
try {
Object[] results = client.invoke("lookOver", 1);
System.out.println(results[0]);
} catch (Exception e) {
e.printStackTrace();
}
}
}
④Spring客户端
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:jaxws="http://cxf.apache.org/jaxws"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-4.0.xsd
http://cxf.apache.org/jaxws
http://cxf.apache.org/schemas/jaxws.xsd">
<jaxws:client id="userWSClient"
serviceClass="top.rainynight.sitews.user.ws.UserWS"
address="http://localhost:8080/ws/user"/>
</beans>
public class UserWSClient{
public static void main(String[] args) {
ApplicationContext context = new ClassPathXmlApplicationContext("spring-client.xml");
UserWS userWS= context.getBean("userWSClient", UserWS.class);
User result = userWS.lookOver(1);
System.out.println(result);
}
}
2
.REST风格
定义接口
!
REST 规范允许资源类没有接口
请求方式注解,包括:
@GET、@POST、@PUT、@DELETE
请求路径注解,包括:
@Path
,其中包括一个路径参数数据格式注解,包括:
@Consumes
(输入)、@Produces
(输出),可使用MediaType
常量相关参数注解,包括:
@PathParam
(路径参数)、@FormParam
(表单参数),此外还有@QueryParam
(请求参数)
package top.rainynight.sitews.user.ws;
import top.rainynight.sitews.user.entity.User;
import javax.jws.WebService;
@WebService
@Path("/")
public interface UserWS {
@GET
@Path("{id:[1-9]{1,9}}")
@Produces(MediaType.APPLICATION_JSON)
User lookOver(@PathParam("id") int id);
}
实现接口
package top.rainynight.sitews.user.ws;
import top.rainynight.sitews.user.entity.User;
import org.springframework.stereotype.Component;
@Component("userWS")
public class UserWSImpl implements UserWS {
@Override
public User lookOver(int id) {
return new User();
}
}
发布服务
①jetty发布
配置依赖
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<cxf.version>3.0.0</cxf.version>
<jackson.version>2.4.1</jackson.version>
</properties>
<dependencies>
<dependency>
<groupId>org.apache.cxf</groupId>
<artifactId>cxf-rt-frontend-jaxrs</artifactId>
<version>${cxf.version}</version>
</dependency>
<dependency>
<groupId>org.apache.cxf</groupId>
<artifactId>cxf-rt-transports-http-jetty</artifactId>
<version>${cxf.version}</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.jaxrs</groupId>
<artifactId>jackson-jaxrs-json-provider</artifactId>
<version>${jackson.version}</version>
</dependency>
</dependencies>
发布
public class Server {
public static void main(String[] args) {
// 添加 ResourceClass
List<Class<?>> resourceClassList = new ArrayList<Class<?>>();
resourceClassList.add(UserWSImpl .class);
// 添加 ResourceProvider
List<ResourceProvider> resourceProviderList = new ArrayList<ResourceProvider>();
resourceProviderList.add(new SingletonResourceProvider(new ProductServiceImpl()));
// 添加 Provider
List<Object> providerList = new ArrayList<Object>();
providerList.add(new JacksonJsonProvider());
// 发布 REST 服务
JAXRSServerFactoryBean factory = new JAXRSServerFactoryBean();
factory.setAddress("http://localhost:8080/rs/user");
factory.setResourceClasses(resourceClassList);
factory.setResourceProviders(resourceProviderList);
factory.setProviders(providerList);
factory.create();
System.out.println("rest ws is published");
}
}
访问http://localhost:8080/rs/user?_wadl
②web发布
配置依赖
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<spring.version>4.0.6.RELEASE</spring.version>
<cxf.version>3.0.0</cxf.version>
<jackson.version>2.4.1</jackson.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-web</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.apache.cxf</groupId>
<artifactId>cxf-rt-frontend-jaxrs</artifactId>
<version>${cxf.version}</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.jaxrs</groupId>
<artifactId>jackson-jaxrs-json-provider</artifactId>
<version>${jackson.version}</version>
</dependency>
</dependencies>
配置web.xml
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>
classpath:spring.xml
</param-value>
</context-param>
<servlet>
<servlet-name>cxf</servlet-name>
<servlet-class>org.apache.cxf.transport.servlet.CXFServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>cxf</servlet-name>
<url-pattern>/*</url-pattern>
</servlet-mapping>
发布
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:jaxrs="http://cxf.apache.org/jaxrs"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-4.0.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd
http://cxf.apache.org/jaxrs
http://cxf.apache.org/schemas/jaxrs.xsd">
<context:component-scan base-package="top.rainynight.sitews.user.ws" />
<jaxrs:server address="/rs/user">
<jaxrs:serviceBeans>
<ref bean="userWS"/>
</jaxrs:serviceBeans>
<jaxrs:providers>
<bean class="com.fasterxml.jackson.jaxrs.json.JacksonJsonProvider"/>
</jaxrs:providers>
</jaxrs:server>
</beans>
访问http://localhost:8080/rs/user?_wadl
调用服务
①JAX-RS 1.0 客户端
public class JAXRSClient {
public static void main(String[] args) {
String baseAddress = "http://localhost:8080/rs/user";
List<Object> providerList = new ArrayList<Object>();
providerList.add(new JacksonJsonProvider());
UserWS userWS = JAXRSClientFactory.create(baseAddress, UserWS.class, providerList);
}
}
②JAX-RS 2.0 客户端
public class JAXRS20Client {
public static void main(String[] args) {
String baseAddress = "http://localhost:8080/rs/user";
JacksonJsonProvider jsonProvider = new JacksonJsonProvider();
List<User> userList = ClientBuilder.newClient()
.register(jsonProvider)
.target(baseAddress)
.path("/1")
.request(MediaType.APPLICATION_JSON)
.get(new GenericType<List<User>>() {});
}
}
③WebClient 客户端
public class CXFWebClient {
public static void main(String[] args) {
String baseAddress = "http://localhost:8080/rs/user";
List<Object> providerList = new ArrayList<Object>();
providerList.add(new JacksonJsonProvider());
List<User> userList = WebClient.create(baseAddress, providerList)
.path("/1")
.accept(MediaType.APPLICATION_JSON)
.get(new GenericType<List<User>>() {});
}
}
④AJAX客户端
$.ajax({
type: 'get',
url: 'http://localhost:8080/rs/user/1',
dataType: 'json',
success: function(data) {
//...
}
});
跨域方案1:jsonp
<dependency>
<groupId>org.apache.cxf</groupId>
<artifactId>cxf-rt-rs-extension-providers</artifactId>
<version>${cxf.version}</version>
</dependency>
<jaxrs:server address="/rs/user">
<jaxrs:serviceBeans>
<ref bean="userWS"/>
</jaxrs:serviceBeans>
<jaxrs:providers>
<bean class="com.fasterxml.jackson.jaxrs.json.JacksonJsonProvider"/>
<bean class="org.apache.cxf.jaxrs.provider.jsonp.JsonpPreStreamInterceptor"/>
</jaxrs:providers>
<jaxrs:inInterceptors>
<bean class="org.apache.cxf.jaxrs.provider.jsonp.JsonpInInterceptor"/>
</jaxrs:inInterceptors>
<jaxrs:outInterceptors>
<bean class="org.apache.cxf.jaxrs.provider.jsonp.JsonpPostStreamInterceptor"/>
</jaxrs:outInterceptors>
</jaxrs:server>
$.ajax({
type: 'get',
url: 'http://localhost:8080/rs/user/1',
dataType: 'jsonp',
jsonp: '_jsonp',
jsonpCallback: 'callback',
success: function(data) {
//...
}
});
跨域方案2:cors
<dependency>
<groupId>org.apache.cxf</groupId>
<artifactId>cxf-rt-rs-security-cors</artifactId>
<version>${cxf.version}</version>
</dependency>
<jaxrs:server address="/rs/user">
<jaxrs:serviceBeans>
<ref bean="userWS"/>
</jaxrs:serviceBeans>
<jaxrs:providers>
<bean class="com.fasterxml.jackson.jaxrs.json.JacksonJsonProvider"/>
<bean class="org.apache.cxf.rs.security.cors.CrossOriginResourceSharingFilter">
<property name="allowOrigins" value="http://localhost"/>
</bean>
</jaxrs:providers>
</jaxrs:server>
allowOrigins 设置客户端域名
IE8 中使用 jQuery 发送 AJAX 请求时,需要配置 $.support.cors = true
~~
警告~~
!warning
极重要,cxf在wsdl中发布的targetNamespace
是实现类路径,而被调用时却只接受接口路径。所以,请将接口与实现类放在同一路径下,或者在实现类中指定targetNamespace
为接口的路径;否则客户端将抛出 ..common.i18n.UncheckedException: No operation was found with the name … 异常