<dependency>
<groupId>org.apache.cxfgroupId>
<artifactId>cxf-spring-boot-starter-jaxwsartifactId>
<version>3.2.4version>
dependency>
import javax.jws.WebMethod;
import javax.jws.WebParam;
import javax.jws.WebService;
/**
* webservice服务端接口类
*/
@WebService
public interface CXFTestService {
/**
* 提供调用的方法,使用@WebMethod注释
* @param id
* @return StudentScore
*/
@WebMethod(operationName = "getStudentScoreById")
StudentScore getStudentScore(@WebParam(name = "id") long id);
}
import com.javatest.po.StudentScore;
import com.javatest.service.StudentScoreService;
import com.javatest.webservice.server.CXFTestService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import javax.jws.WebService;
/**
* webservice服务端实现类。注意,如果使用面向接口,那么在此实现类中必须通过endpointInterface指定服务端接口类
*/
@WebService(targetNamespace = "http://impl.server.webservice.javatest.com/", // 命名空间一般为包名的倒置
endpointInterface = "com.javatest.webservice.server.CXFTestService"
)
@Service
public class CXFTestServiceImpl implements CXFTestService {
@Autowired
private StudentScoreService service;
@Override
public StudentScore getStudentScore(long id) {
return service.selectByPrimaryKey(id);
}
}
import com.javatest.webservice.server.impl.CXFTestServiceImpl;
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 org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
import javax.xml.ws.Endpoint;
/**
* 使用cxf发布webservice服务,实现同一端口同时提供API和webservice
*/
@Configuration
public class WebServiceConfig implements WebMvcConfigurer {
@Bean(name = Bus.DEFAULT_BUS_ID)
public SpringBus springBus() {
return new SpringBus();
}
// 发布cxf的webservice接口
@Bean
public CXFTestServiceImpl CXFTestService() {
return new CXFTestServiceImpl();
}
@Bean
public Endpoint endpointForResources() {
EndpointImpl endpoint = new EndpointImpl(springBus(), CXFTestService());
endpoint.publish("/getCXF");
return endpoint;
}
// 修改拦截的路径,效果与在application.yml中配置cxf.path是一样的。
// 如果两者都没配置,默认路径为/services/*。如果两者都配置了,以本配置类配置的为准。非必需项
@Bean
public ServletRegistrationBean newServlet() {
return new ServletRegistrationBean(new CXFServlet(), "/cxf/*");
}
}
启动项目后访问:http://localhost:9010/javatest/cxf/getCXF?wsdl ,同样进入了wsdl文档,说明服务端已经正常启动。
使用cxf搭建client有两种方式:代理工厂和动态调用。为了方便调用,客户端的代码同样写在另一个项目上。
当用cxf发布服务后,在idea通过Tools–>WebServices—>Generate Java Code From Wsdl…—>输入配置时,可能会有如下提示:
无法按ok了。原因是,这里需要安装cxf并指定有效的cxf路径,具体做法为:
1)进入cxf的官网http://cxf.apache.org/download.html,下载对应的zip包(windows);
2)解压压缩包;
3)配置cxf路径:在Idea中Ctrl+Alt+s进入Settings–>Tools–>Web Services,在cxf那栏中,将解压后的文件夹路径填上去。注意,这里建议复制文件夹路径粘贴上去,而不是按右边的按钮选择,否则无法指定文件夹路径。文件夹路径不能出现中文。
之后再次Generate Java Code From Wsdl就能用cxf来下载服务。这样就能将文件下载到本地了。
这里再次提醒一句,在下载服务前要确保服务端是启动的。
创建一个controller,利用JaxWsProxyFactoryBean来创建webservice服务。
@PostMapping("/getStudentScoreById")
public StudentScore getStudentScoreById(long id) {
JaxWsProxyFactoryBean factory = new JaxWsProxyFactoryBean();
factory.setServiceClass(CXFTestService.class);
factory.setAddress("http://localhost:9010/javatest/cxf/getCXF?wsdl");
// 需要服务接口文件
CXFTestService client = (CXFTestService) factory.create();
return client.getStudentScoreById(id);
}
如果不想用代理工厂,也可以用JaxWsDynamicClientFactory创建服务。这里用到了QName来指定标签。
@PostMapping("/getStudentScoreByIdDynamic")
public Object getStudentScoreByIdDynamic(long id) throws Exception {
JaxWsDynamicClientFactory dcf = JaxWsDynamicClientFactory.newInstance();
Client client = dcf.createClient("http://localhost:9010/javatest/cxf/getCXF?wsdl");
// 用QName指定调用的服务端方法
// 注意:第一个参数不是targetNamespace,而是wsdl文档中,标签里的namespace
QName qName = new QName("http://server.webservice.javatest.com/","getStudentScoreById");
// client.invoke返回的是一个Object[],因为getStudentScoreById只返回一个对象,所以取索引为0的对象
return client.invoke(qName, id)[0];
}
两个调用方法的完整代码如下:
import org.apache.cxf.endpoint.Client;
import org.apache.cxf.jaxws.JaxWsProxyFactoryBean;
import org.apache.cxf.jaxws.endpoint.dynamic.JaxWsDynamicClientFactory;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import javax.xml.namespace.QName;
@RestController
@RequestMapping("/cxf")
public class CxfController {
@PostMapping("/getStudentScoreById")
public StudentScore getStudentScoreById(long id) {
JaxWsProxyFactoryBean factory = new JaxWsProxyFactoryBean();
factory.setServiceClass(CXFTestService.class);
factory.setAddress("http://localhost:9010/javatest/cxf/getCXF?wsdl");
// 需要服务接口文件
CXFTestService client = (CXFTestService) factory.create();
return client.getStudentScoreById(id);
}
@PostMapping("/getStudentScoreByIdDynamic")
public Object getStudentScoreByIdDynamic(long id) throws Exception {
JaxWsDynamicClientFactory dcf = JaxWsDynamicClientFactory.newInstance();
Client client = dcf.createClient("http://localhost:9010/javatest/cxf/getCXF?wsdl");
// 用QName指定调用的服务端方法
// 注意:第一个参数不是targetNamespace,而是wsdl文档中,标签里的namespace
QName qName = new QName("http://server.webservice.javatest.com/","getStudentScoreById");
// client.invoke返回的是一个Object[],因为getStudentScoreById只返回一个对象,所以取索引为0的对象
return client.invoke(qName, id)[0];
}
}
webservice服务端和客户端的开发是分离的,意思是服务端使用哪种技术搭建并不会影响客户端选用的技术,如果服务端使用cxf技术搭建,那么客户端既可以用cxf,也可以用axis2、JWS、wsimport等等的技术调用。