CXF实现WebService

CXF搭建WebService服务端

引入依赖


<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);
    }
}

编写cxf配置类

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搭建WebService客户端

使用cxf搭建client有两种方式:代理工厂和动态调用。为了方便调用,客户端的代码同样写在另一个项目上。

准备工作

当用cxf发布服务后,在idea通过Tools–>WebServices—>Generate Java Code From Wsdl…—>输入配置时,可能会有如下提示:
CXF实现WebService_第1张图片
无法按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那栏中,将解压后的文件夹路径填上去。注意,这里建议复制文件夹路径粘贴上去,而不是按右边的按钮选择,否则无法指定文件夹路径。文件夹路径不能出现中文。
CXF实现WebService_第2张图片
之后再次Generate Java Code From Wsdl就能用cxf来下载服务。这样就能将文件下载到本地了。

这里再次提醒一句,在下载服务前要确保服务端是启动的。

使用代理工厂调用webservice服务

创建一个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);
}

使用动态工厂调用webservice服务

如果不想用代理工厂,也可以用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等等的技术调用。

你可能感兴趣的:(JavaWeb,java)