- CXF入门篇
https://blog.csdn.net/tongxin_tongmeng/article/details/126482362 - Server端项目结构

- Server端pom.xml
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"><modelVersion>4.0.0</modelVersion><groupId>com.cxf.webservice</groupId><artifactId>WS_Server</artifactId><version>0.0.1-SNAPSHOT</version><dependencies><!-- springboot webservice --><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web-services</artifactId></dependency><!-- cxf webservice --><dependency><groupId>org.apache.cxf</groupId><artifactId>cxf-spring-boot-starter-jaxws</artifactId><version>3.2.14</version></dependency><!--JDK11需要添加此依赖--><dependency><groupId>com.sun.xml.ws</groupId><artifactId>jaxws-ri</artifactId><version>2.3.1</version></dependency></dependencies>
</project>
- Server端实体类
package com.cxf.entity;import java.util.List;public class MyRole {private String key;private List<Role> value;public String getKey() {return key;}public void setKey(String key) {this.key = key;}public List<Role> getValue() {return value;}public void setValue(List<Role> value) {this.value = value;}}
package com.cxf.entity;public class Role {private Integer id;private String roleName;public Role() {super();// TODO Auto-generated constructor stub}public Role(Integer id, String roleName) {super();this.id = id;this.roleName = roleName;}public Integer getId() {return id;}public void setId(Integer id) {this.id = id;}public String getRoleName() {return roleName;}public void setRoleName(String roleName) {this.roleName = roleName;}}
package com.cxf.entity;public class User {private Integer id;private String userName;private String password;public Integer getId() {return id;}public void setId(Integer id) {this.id = id;}public String getUserName() {return userName;}public void setUserName(String userName) {this.userName = userName;}public String getPassword() {return password;}public void setPassword(String password) {this.password = password;}}
- Server端接口
package com.cxf.webservice;import com.cxf.adapter.MapAdapter;
import com.cxf.entity.Role;
import com.cxf.entity.User;import java.util.List;
import java.util.Map;import javax.jws.WebMethod;
import javax.jws.WebParam;
import javax.jws.WebService;
import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter;@WebService(name="HelloWorld", targetNamespace = "webservice.cxf.com")
public interface HelloWorld {@WebMethod(operationName = "say")public String say(@WebParam(name = "str") String str);@WebMethod(operationName = "getRoleByUser")public List<Role> getRoleByUser(@WebParam(name = "user") User user);@XmlJavaTypeAdapter(MapAdapter.class)@WebMethod(operationName = "getRoles")public Map<String,List<Role>> getRoles();}
- Server端接口实现
package com.cxf.webservice.impl;import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;import javax.jws.WebService;import com.cxf.entity.Role;
import com.cxf.entity.User;
import com.cxf.webservice.HelloWorld;
import org.springframework.stereotype.Component;@Component
public class HelloWorldImpl implements HelloWorld{public String say(String str) {return "Hello:"+str;}public List<Role> getRoleByUser(User user) {List<Role> roleList=new ArrayList<Role>();roleList.add(new Role(1,"AAAA"));roleList.add(new Role(2,"BBBB"));return roleList;}public Map<String, List<Role>> getRoles() {Map<String,List<Role>> map=new HashMap<String,List<Role>>();List<Role> roleList1=new ArrayList<Role>();roleList1.add(new Role(1,"CCCC"));map.put("cccc", roleList1);List<Role> roleList2=new ArrayList<Role>();roleList2.add(new Role(2,"DDDD"));map.put("dddd", roleList2);return map;}}
- Map类型返回值适配器
package com.cxf.adapter;import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;import javax.xml.bind.annotation.adapters.XmlAdapter;import com.cxf.entity.MyRole;
import com.cxf.entity.Role;public class MapAdapter extends XmlAdapter<MyRole[], Map<String,List<Role>>>{/*** 适配转换 MyRole[] -> Map<String, List<Role>>*/@Overridepublic Map<String, List<Role>> unmarshal(MyRole[] myRoles) throws Exception {Map<String, List<Role>> map=new HashMap<String,List<Role>>();for(int i=0;i<myRoles.length;i++){MyRole myRole=myRoles[i];map.put(myRole.getKey(), myRole.getValue());}return map;}/*** 适配转换 Map<String, List<Role>> -> MyRole[]*/@Overridepublic MyRole[] marshal(Map<String, List<Role>> map) throws Exception {MyRole[] roles=new MyRole[map.size()];Set<Map.Entry<String, List<Role>>> entries = map.entrySet();Integer index = 0;for (Map.Entry<String, List<Role>> entry : entries) {roles[index]=new MyRole();roles[index].setKey(entry.getKey());roles[index].setValue(entry.getValue());index++;}return roles;}}
- Server端自定义拦截器(调用接口方法前执行)
package com.cxf.interceptor;import org.apache.cxf.binding.soap.SoapMessage;
import org.apache.cxf.databinding.DataBinding;
import org.apache.cxf.headers.Header;
import org.apache.cxf.interceptor.Fault;
import org.apache.cxf.phase.AbstractPhaseInterceptor;
import org.apache.cxf.phase.Phase;
import org.w3c.dom.Element;import javax.xml.namespace.QName;
import java.util.List;public class MyInterceptor extends AbstractPhaseInterceptor<SoapMessage> {public MyInterceptor() {super(Phase.PRE_INVOKE); // 在调用方法之前调用自定拦截器}@SuppressWarnings("null")public void handleMessage(SoapMessage message) throws Fault {List<Header> headers = message.getHeaders();
// throw new Fault(new IllegalArgumentException("#############"+headers.size()));
// for (Header header : headers) {
// Element ele=(Element) header.getObject();
// if (ele.getTagName().equalsIgnoreCase("userproperty")) {
// if (ele.getElementsByTagName("username").getLength()==0) {
// throw new Fault(new IllegalArgumentException("没有用户名,拦截器实施拦截"));
// }
// if (ele.getElementsByTagName("password").getLength()==0) {
// throw new Fault(new IllegalArgumentException("没有密码,拦截器实施拦截"));
// }
// String username = ele.getElementsByTagName("username").item(0).getNodeValue();
// String password = ele.getElementsByTagName("password").item(0).getNodeValue();
//
// if(!username.equals("cxf")||!password.equals("123456")){
// throw new Fault(new IllegalArgumentException("用户名或者密码错误!"));
// }
// }
// }}}
- Server端配置类
package com.cxf.config;import com.cxf.interceptor.MyInterceptor;
import com.cxf.webservice.HelloWorld;
import org.apache.cxf.Bus;
import org.apache.cxf.jaxws.EndpointImpl;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;import javax.xml.ws.Endpoint;@Configuration
public class CxfConfig {@AutowiredBus bus;@AutowiredHelloWorld helloWorld;@Beanpublic Endpoint endpoint() {EndpointImpl endpoint = new EndpointImpl(bus, helloWorld);endpoint.getInInterceptors().add(new MyInterceptor()); // 添加自定义拦截器endpoint.publish("/HelloWorld");return endpoint;}
}
- Server端application.yml
server:port: 8888servlet:context-path: /
- 启动Server端

- Client端自动生成
https://pan.baidu.com/s/1wTK2ly-SJgZM99TyAdmPiw?pwd=hbn1 1.apache-cxf-3.1.5.zip解压后在环境变量添加bin路径2.执行命令:wsdl2java -encoding utf-8 -d C:\Users\Administrator\Desktop\wsdl http://localhost:8888/services/HelloWorld?wsdl3.将C:\Users\Administrator\Desktop\wsdl路径下自动生成的java文件复制到Client端


- Client端pom.xml
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"><modelVersion>4.0.0</modelVersion><groupId>com.java1234.webservice</groupId><artifactId>WS_Client</artifactId><version>0.0.1-SNAPSHOT</version><dependencies><!-- springboot webservice --><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web-services</artifactId></dependency><!-- cxf webservice --><dependency><groupId>org.apache.cxf</groupId><artifactId>cxf-spring-boot-starter-jaxws</artifactId><version>3.2.14</version></dependency><!--JDK11需要添加此依赖--><dependency><groupId>com.sun.xml.ws</groupId><artifactId>jaxws-ri</artifactId><version>2.3.1</version></dependency></dependencies>
</project>
- Client端自定义拦截器(发送SOAP消息时调用)
package com.cxf.interceptor;import java.util.List;import javax.xml.namespace.QName;import org.apache.cxf.binding.soap.SoapMessage;
import org.apache.cxf.headers.Header;
import org.apache.cxf.helpers.DOMUtils;
import org.apache.cxf.interceptor.Fault;
import org.apache.cxf.phase.AbstractPhaseInterceptor;
import org.apache.cxf.phase.Phase;
import org.w3c.dom.Document;
import org.w3c.dom.Element;public class AddHeaderInterceptor extends AbstractPhaseInterceptor<SoapMessage> {private String userName;private String password;public AddHeaderInterceptor(String userName,String password) {super(Phase.PREPARE_SEND); // 准备发送SOAP消息的时候调用拦截器this.userName=userName;this.password=password;}/*** 客户端拦截器和服务端拦截器对应,客户端拦截器向SoapMessage添加的参数可以在服务端拦截器获取到并进行校验* 校验失败通过:throw new Fault(new IllegalArgumentException("没有Header,拦截器实施拦截"))抛出的异常在客户端控制台可见* @param message* @throws Fault*/public void handleMessage(SoapMessage message) throws Fault {List<Header> headerList=message.getHeaders();Document doc=DOMUtils.createDocument();Element ele=doc.createElement("authHeader");Element uElement=doc.createElement("userName");uElement.setTextContent(userName);Element pElement=doc.createElement("password");pElement.setTextContent(password);ele.appendChild(uElement);ele.appendChild(pElement);headerList.add(new Header(new QName("cxf"),ele));}}
- Client端测试类
package com.cxf.webservice;import java.util.List;import com.cxf.interceptor.AddHeaderInterceptor;
import com.cxf.webservice.impl.HelloWorldImplService;
import org.apache.cxf.frontend.ClientProxy;
import org.apache.cxf.interceptor.LoggingInInterceptor;
import org.apache.cxf.interceptor.LoggingOutInterceptor;public class Client {public static void main(String[] args) {HelloWorldImplService service=new HelloWorldImplService();HelloWorld helloWorld = service.getHelloWorldImplPort();org.apache.cxf.endpoint.Client client=ClientProxy.getClient(helloWorld);client.getInInterceptors().add(new AddHeaderInterceptor("cxf","123456")); // 添加自定义拦截器client.getInInterceptors().add(new LoggingInInterceptor()); // 添加In拦截器 日志拦截器client.getOutInterceptors().add(new LoggingOutInterceptor()); // 添加Out拦截器 日志拦截器System.out.println(helloWorld.say("=========================="));List<Role> roles1=helloWorld.getRoleByUser(new User());for(Role role:roles1){System.out.println(role.getId()+","+role.getRoleName());}// 返回值为Map,服务端需要适配转换 @XmlJavaTypeAdapter(MapAdapter.class)-->Map<String, List<Role>> -> MyRole[]List<MyRole> roles2 = helloWorld.getRoles().item;for (MyRole myRole : roles2) {String key = myRole.getKey();List<Role> roles = myRole.getValue();System.out.println(key+":"+roles.toString());}}
}

- 彩蛋
https://pan.baidu.com/s/1LrW4XRW71qB-ngeRgCMNHg?pwd=f68d 客户端拦截器添加的参数在Server端拦截器获取失败,测试代码包点击上面链接下载,如果找到问题原因、解决办法、其他传参方式,请在评论区留言!