Web 是使应用程序可以与平台和编程语言无关的方式进行相互通信的一项技术。Web 服务是一个软件接口,它描述了一组可以在网络上通过标准化的 XML 消息传递访问的操作。它使用基于 XML 语言的协议来描述要执行的操作或者要与另一个 Web 服务交换的数据。一组以这种方式交互的 Web 服务在面向服务的体系结构(Service-Oriented Architecture,SOA)中定义了特殊的 Web 服务应用程序。
简单的说WebService是一个SOA(面向服务的编程)的架构,它是不依赖于语言,不依赖于平台,可以实现不同的语言(通过 xml 描述)间的相互调用,通过Internet进行基于Http协议的网络应用间的交互。通过SOAP在Web上提供的软件服务,使用WSDL文件进行说明,并通过UDDI进行注册。
org.springframework.boot
spring-boot-starter-web
org.apache.cxf
cxf-spring-boot-starter-jaxws
3.4.0
org.springframework.boot
spring-boot-starter-web-services
net.sf.json-lib
json-lib
2.4
jdk15
org.projectlombok
lombok
true
com.alibaba
fastjson
1.2.73
server:
port: 80
servlet:
contest-path: /
spring:
application:
name: springboot-cxf
cxf:
path: /user
package com.dev.cxf.service;
import com.dev.cxf.model.DataResult;
import com.dev.cxf.model.MapAdapter;
import com.dev.cxf.model.MapListAdapter;
import com.dev.cxf.model.User;
import javax.jws.WebMethod;
import javax.jws.WebParam;
import javax.jws.WebService;
import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
/**
* @Description : webservice接口 //描述
*/
@WebService(
//服务名
name = "management",
//命名空间,一般是接口的包名倒序
targetNamespace = "http://service.cxf.dev.com"
)
public interface Management {
@WebMethod
public String getName(@WebParam(name = "ip") String ip);
@WebMethod
public User getUser(@WebParam(name = "name") String name);
@WebMethod
public ArrayList getUserList(@WebParam(name = "name") String name);
@WebMethod
public DataResult getDataResult();
@WebMethod
@XmlJavaTypeAdapter(MapAdapter.class)
public Map getUserMap();
@WebMethod
@XmlJavaTypeAdapter(MapListAdapter.class)
public Map> getUserMapListUser();
@WebMethod
public Map getMap(@WebParam(name = "user") User user);
}
package com.dev.cxf.service.impl;
import com.dev.cxf.model.DataResult;
import com.dev.cxf.model.User;
import com.dev.cxf.service.Management;
import org.springframework.stereotype.Component;
import javax.jws.WebService;
import java.util.*;
/**
* @Description : webservice接口实现类 //描述
*/
@Component
@WebService(
//与接口中的命名空间一致
targetNamespace = "http://service.cxf.dev.com",
//接口地址
endpointInterface = "com.dev.cxf.service.Management"
)
public class ManagementImpl implements Management {
@Override
public String getName(String ip) {
return "hello world!";
}
@Override
public User getUser(String name) {
System.out.println(name);
User user = new User();
user.setName("cxf demo");
user.setIp("127.0.0.1");
return user;
}
@Override
public ArrayList getUserList(String name) {
System.out.println(name);
ArrayList list = new ArrayList();
list.add(new User("ip","127.0.0.1"));
list.add(new User("ip","127.0.0.2"));
list.add(new User("ip","127.0.0.3"));
return list;
}
@Override
public DataResult getDataResult() {
DataResult dataResult = new DataResult();
List list = new ArrayList();
list.add(new User("ip","127.0.0.1"));
list.add(new User("ip","127.0.0.2"));
Map s = new HashMap();
s.put("name", new User("ip","127.0.0.1"));
dataResult.setUserMap(s);
dataResult.setUserList(list);
return dataResult;
}
@Override
public Map getUserMap() {
HashMap s = new HashMap();
s.put("name",new User("ip","127.0.0.1"));
s.put("name2",new User("ip","127.0.0.2"));
s.put("name3",new User("ip","127.0.0.3"));
return s;
}
@Override
public Map> getUserMapListUser() {
Map> s = new HashMap>();
List list = new ArrayList();
list.add(new User("ip","127.0.0.1"));
list.add(new User("ip","127.0.0.2"));
s.put("name",list);
s.put("name2",list);
s.put("name3",list);
return s;
}
@Override
public HashMap getMap(User user) {
System.out.println(user);
HashMap s = new HashMap();
s.put("ip1", "127.0.0.1");
s.put("ip2", "127.0.0.1");
return s;
}
}
package com.dev.cxf.config;
import com.dev.cxf.model.User;
import com.dev.cxf.service.Management;
import org.apache.cxf.Bus;
import org.apache.cxf.bus.spring.SpringBus;
import org.apache.cxf.jaxws.EndpointImpl;
import org.apache.cxf.transport.servlet.CXFServlet;
import org.springframework.boot.web.servlet.ServletRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import javax.annotation.Resource;
import javax.xml.ws.Endpoint;
/**
* @Description : webservice发布配置 //描述
* @Author : //作者
*/
@Configuration
public class WebServiceConfig {
@Resource
private Management management;
@Bean(name = Bus.DEFAULT_BUS_ID)
public SpringBus springBus(){
return new SpringBus();
}
/**
* JAX-WS
*/
@Bean
public Endpoint endpoint(){
EndpointImpl endpoint = new EndpointImpl(springBus(), management);
endpoint.publish("/test");
return endpoint;
}
/**
* 访问地址 http://127.0.0.1:80/user/test?wsdl
*
* 但cxf 2.0.4之后的版本不需再配置此项内容,只需在application中配置
* cxf.path=/user
* 或者
* cxf:
* path: /user
*/
// @Bean()
// public ServletRegistrationBean registrationBean(){
// return new ServletRegistrationBean(new CXFServlet(),"/user/*");
// }
}
这里以Map
package com.dev.cxf.model;
import javax.xml.bind.annotation.*;
import java.util.ArrayList;
import java.util.List;
/**
* @ClassName : MapListUser //类名
* @Description : //描述
*/
@XmlType(name = "MapListUser")
@XmlAccessorType(XmlAccessType.FIELD)
@XmlRootElement
@XmlSeeAlso({User.class})
public class MapListUser {
private List listEntry;
static class ListEntry{
private String key;
private List userList = new ArrayList();
public ListEntry() {
}
public ListEntry(String key, List userList) {
this.key = key;
this.userList = userList;
}
public String getKey() {
return key;
}
public void setKey(String key) {
this.key = key;
}
public List getUserList() {
return userList;
}
public void setUserList(List value) {
this.userList = value;
}
}
public List getListEntry() {
return listEntry;
}
public void setListEntry(List listEntry) {
this.listEntry = listEntry;
}
}
package com.dev.cxf.model;
import lombok.Data;
import java.io.Serializable;
/**
* @ClassName : User //类名
* @Description : //描述
*/
@Data
public class User implements Serializable {
private String name;
private String ip;
public User() {
}
public User(String name, String ip) {
this.name = name;
this.ip = ip;
}
}
package com.dev.cxf.model;
import javax.xml.bind.ValidationEventHandler;
import javax.xml.bind.annotation.adapters.XmlAdapter;
import java.util.*;
/**
* @Description : //描述
*/
public class MapListAdapter extends XmlAdapter>> {
/**
* Convert a value type to a bound type.
*
* @param v The value to be converted. Can be null.
* @throws Exception if there's an error during the conversion. The caller is responsible for
* reporting the error to the user through {@link ValidationEventHandler}.
*/
@Override
public Map> unmarshal(MapListUser v) throws Exception {
Map> map = new HashMap<>();
for (MapListUser.ListEntry listEntry : v.getListEntry()) {
map.put(listEntry.getKey(), listEntry.getUserList());
}
return map;
}
/**
* Convert a bound type to a value type.
*
* @param v The value to be convereted. Can be null.
* @throws Exception if there's an error during the conversion. The caller is responsible for
* reporting the error to the user through {@link ValidationEventHandler}.
*/
@Override
public MapListUser marshal(Map> v) throws Exception {
MapListUser mapListUser = new MapListUser();
List listEntries = new ArrayList<>();
for (String s : v.keySet()) {
MapListUser.ListEntry listEntry= new MapListUser.ListEntry();
listEntry.setKey(s);
listEntry.setUserList(v.get(s));
listEntries.add(listEntry);
}
mapListUser.setListEntry(listEntries);
return mapListUser;
}
}
配置完成启动项目
启动浏览器输入:http://127.0.0.1:80/user/test?wsdl或者http://localhost/user/test?wsdl
客户端使用JaxWsDynamicClientFactory动态调用
package com.dev.cxf.client;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson.parser.ParserConfig;
import com.dev.cxf.model.DataResult;
import com.dev.cxf.model.User;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.sun.xml.bind.v2.runtime.unmarshaller.XsiNilLoader;
import lombok.extern.slf4j.Slf4j;
import org.apache.cxf.endpoint.Client;
import org.apache.cxf.jaxws.endpoint.dynamic.JaxWsDynamicClientFactory;
import org.apache.cxf.transport.http.HTTPConduit;
import org.apache.cxf.transports.http.configuration.HTTPClientPolicy;
import org.springframework.core.io.ClassPathResource;
import org.springframework.core.io.support.PropertiesLoaderUtils;
import java.io.File;
import java.io.IOException;
import java.lang.reflect.Method;
import java.security.Key;
import java.util.*;
import java.util.stream.Collectors;
import java.util.stream.Stream;
/**
* @Description : cxf操作类 //描述
*/
@Slf4j
public class CxfClientUtil {
private static Client client = null;
/**
* 获取yml中配置
* @param name 配置文件名 如:application.yml
* @param key 配置文件名 如:cxf
*/
public static Hashtable getYml(String name,String key){
//"application.yml"
ClassPathResource resource = new ClassPathResource(File.separator + name);
try {
Hashtable props = PropertiesLoaderUtils.loadProperties(resource);
return props;
} catch (IOException e) {
e.printStackTrace();
return null;
}
}
/**
* 创建client
* @param wsdlUrl webservice地址
*/
public static boolean create(String wsdlUrl){
try {
JaxWsDynamicClientFactory dcf = JaxWsDynamicClientFactory.newInstance();
client = dcf.createClient(wsdlUrl);
// 如果返回的address不是远程服务地址,重新制定地址
client.getEndpoint().getEndpointInfo().setAddress(wsdlUrl);
// 策略
HTTPClientPolicy httpClientPolicy = new HTTPClientPolicy();
// 连接超时
httpClientPolicy.setConnectionTimeout(6000000);
httpClientPolicy.setAllowChunking(false);
// 接收超时
httpClientPolicy.setReceiveTimeout(6000000);
HTTPConduit http = (HTTPConduit) client.getConduit();
http.getClient().setReceiveTimeout(0);
http.setClient(httpClientPolicy);
if (null != client) {
return true;
}
} catch (Exception e) {
e.printStackTrace();
log.error(e.toString());
return false;
}
return false;
}
/**
* 返回String
* @param wsdlUrl 地址
* @param method 方法名
* @param parm 入参
*
* @return String 字符串
*/
public static String transferToString(String wsdlUrl, String method, String parm) {
if (create(wsdlUrl)) {
Object[] objects = null;
try {
objects = client.invoke(method, parm);
if (objects.length > 0){
return objects[0].toString();
} else {
return "";
}
} catch (Exception e) {
e.printStackTrace();
}
}
return "调用失败!";
}
/**
* 返回实体类
* @param wsdlUrl 地址
* @param method 方法名
* @param parm 入参
*
* @return User 实体类
*/
public static User transferToEntity(String wsdlUrl, String method, String parm) {
if (create(wsdlUrl)) {
Object[] objects = null;
User user = null;
try {
objects = client.invoke(method, parm);
if (objects.length > 0){
user = JSON.parseObject(JSON.toJSONString(objects[0]), User.class);
return user;
}
} catch (Exception e) {
e.printStackTrace();
return user;
}
}
return new User();
}
/**
* 返回List
* @param wsdlUrl 地址
* @param method 方法名
* @param parm 入参
*
* @return List 实体类
*/
public static ArrayList transferToList(String wsdlUrl, String method, String parm) {
if (create(wsdlUrl)) {
Object[] objects = null;
ArrayList list = null;
try {
objects = client.invoke(method, parm);
if (objects.length > 0){
list = (ArrayList) JSON.parseArray(JSON.toJSONString(objects[0]), User.class);
return list;
}
} catch (Exception e) {
e.printStackTrace();
return list;
}
}
return new ArrayList();
}
/**
* 返回List与Map
*
* @param wsdlUrl 地址
* @param method 方法名
* @param parm 入参
*
* @return DataResult 实体类
*/
public static DataResult transferToDataResult(String wsdlUrl, String method) {
if (create(wsdlUrl)) {
Object[] objects = null;
DataResult dataResult = null;
try {
objects = client.invoke(method);
if (objects.length > 0){
// https://www.cnblogs.com/tfxz/p/12621560.html
Map> classMap = new HashMap>();
classMap.put("userList",User.class);
dataResult = (DataResult) net.sf.json.JSONObject.toBean(net.sf.json.JSONObject.fromObject(JSONObject.toJSONString(objects[0])), DataResult.class, classMap);
return dataResult;
}
} catch (Exception e) {
e.printStackTrace();
return dataResult;
}
}
return new DataResult();
}
public static Map transferToUserMap(String wsdlUrl, String method) {
if (create(wsdlUrl)) {
Object[] objects = null;
Map map = new HashMap<>();
try {
objects = client.invoke(method);
if (objects.length > 0) {
JSONArray entries = JSON.parseObject(JSON.toJSONString(objects[0])).getJSONArray("entries");
//https://www.cnblogs.com/tfxz/p/12621560.html
Map> classMap = new HashMap>();
for (Object object : entries) {
net.sf.json.JSONObject jsonObject1 = net.sf.json.JSONObject.fromObject(object);
User table = (User) net.sf.json.JSONObject.toBean(net.sf.json.JSONObject.fromObject(jsonObject1.getString("value")), User.class, classMap);
map.put(jsonObject1.getString("key"), table);
}
return map;
}
} catch (Exception e) {
e.printStackTrace();
return map;
}
}
return new HashMap();
}
public static Map transferToMap(String wsdlUrl, String method,Map m) {
if (create(wsdlUrl)) {
Object[] objects = null;
Map map = new HashMap<>();
try {
//CXF传入复杂参数:调用服务器端实体类->调用set方法->提交参数
Object ajjySjth = Thread.currentThread().getContextClassLoader().loadClass("com.dev.cxf.service.User").getDeclaredConstructor().newInstance();// 加载类为服务端自定义对象命名空间
Method setIp = ajjySjth.getClass().getMethod("setIp", String.class);// 调用set方法设置参数
Method setName = ajjySjth.getClass().getMethod("setName", String.class);// 调用set方法设置参数
setIp.invoke(ajjySjth, m.get("ip"));
setName.invoke(ajjySjth, m.get("name"));
objects = client.invoke(method, ajjySjth);
if (objects.length > 0){
net.sf.json.JSONObject jsonObject = net.sf.json.JSONObject.fromObject(objects[0]);
net.sf.json.JSONArray entry = jsonObject.getJSONArray("entry");
for (Object o : entry) {
JSONObject object = JSON.parseObject(JSON.toJSONString(o));
map.put(object.getString("key"), object.getString("value"));
}
return map;
}
} catch (Exception e) {
e.printStackTrace();
return map;
}
}
return new HashMap();
}
public static Map> transferToUserMapListUser(String wsdlUrl, String method) {
if (create(wsdlUrl)) {
Object[] objects = null;
Map> map = new HashMap<>();
try {
objects = client.invoke(method);
if (objects.length > 0) {
JSONArray listEntry = JSON.parseObject(JSON.toJSONString(objects[0])).getJSONArray("listEntry");
for (Object o : listEntry) {
JSONObject object = JSON.parseObject(JSON.toJSONString(o));
map.put(object.getString("key"), JSON.parseObject(JSON.toJSONString(object.getJSONArray("userList")), List.class));
}
return map;
}
} catch (Exception e) {
e.printStackTrace();
return map;
}
}
return new HashMap>();
}
}
package com.dev.cxf.client;
import lombok.extern.slf4j.Slf4j;
import java.util.*;
/**
* @Description : client端测试 //描述
*/
@Slf4j
public class Test {
private static final String wsdlUrl = "http://127.0.0.1:80/user/test?wsdl";
public static void main(String[] args) {
Map map = new HashMap();
map.put("name","zhansgan");
map.put("ip","127.0.0.1");
//string
// System.out.println(CxfClientUtil.transferToString(wsdlUrl, "getName", map.get("ip").toString()));
//entity
// System.out.println(CxfClientUtil.transferToEntity(wsdlUrl,"getUser",map.get("name").toString()));
//list
// System.out.println(CxfClientUtil.transferToList(wsdlUrl,"getUserList",map.get("name").toString()));
//list + map
// System.out.println(CxfClientUtil.transferToDataResult(wsdlUrl,"getDataResult"));
//map
// System.out.println(CxfClientUtil.transferToUserMap(wsdlUrl, "getUserMap"));
//map
System.out.println(CxfClientUtil.transferToMap(wsdlUrl, "getMap", map));
//map>
// System.out.println(CxfClientUtil.transferToUserMapListUser(wsdlUrl, "getUserMapListUser"));
}
}
运行Test这里调用的是"getMap"接口,实现类中传入参数User对象,返回是HashMap
getMap打印
Test打印
项目中写的例子有:
java.lang.IllegalStateException: Unable to create schema compiler
这个问题相信不少人都遇到过,动态编译时找不到tools.jar报错导致
解决方式: 将引用的jre换为jdk,或者将tools.jar复制到你引用jre目录下
参考链接:
https://www.cnblogs.com/tfxz/p/12621560.html
https://www.cnblogs.com/zhengyuanyuan/p/9277059.html
GitHub:传送门
链接另一篇传递复杂类型参数:传送门