欢迎关注我新搭建的博客: http://www.itcodai.com/

WebService系列文章:
【WebService】带你走进webservice的世界
【WebService】自定义WebService服务及其调用
【WebService】wsdl配置详解以及使用注解修改wsdl配置
【WebService】CXF处理javaBean等复合类型以及Map等复杂类型的数据

CXF的拦截器和以前学过的servlet的拦截器类似的,都是在开始或结束切入一段代码,执行一些逻辑之类的。我们可以在调用ws服务前设置拦截器,也可以在调用ws服务后设置拦截器,当然了,拦截器也可以添加多个,CXF中有自己内置的拦截器,先来写个简单CXF自带的拦截器实例熟悉一下在CXF中如何添加,然后再来自定义CXF拦截器。

1. CXF内置的拦截器设置

还是使用上一节的ws,在原来的基础上添加以下拦截器,如下:
这里写图片描述
启动之后,客户端访问一下,看服务端控制台的输出(为了清楚点,我就不缩小了):
这里写图片描述
可以看到,请求的时候会被拦截器拦截,请求结束也会被拦截,从打印的日志消息可以看出,发送的是soap消息,返回的数据由于截屏的范围我就不截取了,这是在服务端添加的拦截器。
那客户端如何添加拦截器呢?由于client端无法直接获取拦截器组,所以我们需要首先获取一个client的代理,然后通过这个代理来获取拦截器组,如下:
这里写图片描述
客户端访问一下,看下客户端控制台的输出结果(为了清楚点,我就不缩小了):
这里写图片描述
可以看出,客户端如果设置拦截器的话,也会打印出日志消息,而且客户端和服务端的拦截器执行顺序刚好相反。这就是CXF内置的拦截器,下面我们来自定义CXF的拦截器。

2. 自定义CXF拦截器

自定义拦截器的话,我们来弄个需求,使用拦截器进行权限的认证。自定义拦截器需要继承 AbstractPhaseInterceptor<SoapMessage> ,其中SoapMessage是用来封装soap消息的,我们具体来看下如何自定义CXF拦截器,首先看服务端,在上面的代码的定义的两个内置拦截器下面添加一个自定义拦截器即可:

factoryBean.getInInterceptors().add(new MyInterceptor());

然后重点是这个MyInterceptor,如下:

public class MyInterceptor extends AbstractPhaseInterceptor<SoapMessage>  {
    public MyInterceptor() {
        super(Phase.PRE_INVOKE); //在调用方法之前调用自定义拦截器
    public void handleMessage(SoapMessage message) throws Fault {
        List<Header> headers = message.getHeaders(); //根据soap消息获取头部
        if(headers == null && headers.size() == 0) {
            throw new Fault(new IllegalArgumentException("没有Header,拦截器实施拦截"));
        Header firstHeader = headers.get(0); //我们等会只传一个头部过来
        Element elm = (Element) firstHeader.getObject();//将该头部转成一个Element对象
        NodeList userList = elm.getElementsByTagName("username"); //根据标签获取值
        NodeList pwdList = elm.getElementsByTagName("password");
        // 进行身份认证
        if(userList.getLength() != 1) {//只有一个用户
            throw new Fault(new IllegalArgumentException("用户名格式不对"));
        if(pwdList.getLength() != 1) {//只有一个密码
            throw new Fault(new IllegalArgumentException("密码格式不对"));
        String username = userList.item(0).getTextContent(); //因为就一个,所以获取第一个即可
        String  password= pwdList.item(0).getTextContent();
        if(!username.equals("admin") || !password.equals("123")) {
            throw new Fault(new IllegalArgumentException("用户名或者密码错误"));

  上面的代码逻辑很简单,等会儿客户端会传过来一个soap消息,我们会将用户名和密码封装到头部中传过来,那么在这边,通过解析soap消息中头部的数据,来进行身份认证。所以接下来完成客户端那边的拦截器。
  客户端这边要自定义一个out拦截器了,因为这边是发送数据,同上,首先在原来客户端定义的两个内置CXF拦截器上面添加一个自定义拦截器,如下:

client.getOutInterceptors().add(new AddHeaderInterceptor("admin", "123"));//添加自定义拦截器

在自定义拦截器中,将用户名和密码传进去,重点来看一下这个自定义拦截器,如下:

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;
    public void handleMessage(SoapMessage message) throws Fault {
        List<Header> headerList = message.getHeaders();
        Document doc = DOMUtils.createDocument();
        // 定义三个对象
        Element elm = doc.createElement("authHeader");
        Element userElm = doc.createElement("username");
        Element pwdElm = doc.createElement("password");
        // 给用户名和密码对象赋值
        userElm.setTextContent(username);
        pwdElm.setTextContent(password);
        // 将用户名和密码的对象添加到elm中
        elm.appendChild(userElm);
        elm.appendChild(pwdElm);
        headerList.add(new Header(new QName("head"), elm));//往soap消息头部中添加这个elm元素

  从上面的代码中可以看出,首先通过构造函数将用户名和密码传进去,然后获取将要发送的soap消息的头部,紧接着认为构造出几个元素,将用户名和密码封装到元素中去,并放到soap消息的头部,这样等会soap消息就会携带这个用户名和密码的消息了,这样就能在上面的服务端取出,进行身份认证了,这样就前后连通了起来。测试结果我就不贴了,可以查看控制台打印的结果,重点看一下soap消息,里面封装好了一个DOM对象,封装了用户名和密码。

【友情提示】我的 Spring Boot 达人课上线了,您的支持是我创作的最大动力!

扫码试读或 CXF的拦截器和以前学过的servlet的拦截器类似的,都是在开始或结束切入一段代码,执行一些逻辑之类的。我们可以在调用ws服务前设置拦截器,也可以在调用ws服务后设置拦截器,当然了,拦截器也可以添加多个,CXF中有自己内置的拦截器,先来写个简单CXF自带的拦截器实例熟悉一下在CXF中如何添加,然后再来自定义CXF拦截器。1. CXF内置的拦截器设置还是使用上一节的ws,在原来的基础上
听到拦截,其实我们就应该想到它的作用:即在我们每次访问请求的时候都会被拦截,先去处理一些其它的事情。比如说在webService上,我们对发布的服务有权限要求,只有有权限的才可以访问我们的服务。而在此处,其实现就要用到我们的拦截了,具体如下: 1、添加拦截类(用户接受客户端消息)public class AuthInterceptor extends AbstractPhase
昨晚合租的一个小弟弟问我CXF的问题,配置正常,但是服务端一直发布不成功,项目也不报错,后面发现原因是配置文件加载问题,需要子父容分别加载。一下子勾起了我的好奇心,今天正好不忙,于是研究一番。 一、服务端 首先上一下配置文件: 1. pom文件 定义下版本,mvn中最新都到3.3.x了,我们用3.1.6.Spring4.x与CXF2.*不兼容 ​<cxf.version...
定义拦截: 需要实现Interceptor接口,实际上,我们一般会继承AbstractPhaseInterceptor; 做一个权限控制,有用户名和密码的时候才允许调用 Web Service: * 1 . 在服务端将系统提供的In拦截改为自定义拦截 在运行起来的CXF服务端不需要做任何的改动,只需要修改In拦截
  定义者:系统拦截定义拦截:LoggingInInteceptor   ①:创建webservice服务端的自定义拦截,用于检查客户端传入的参数:   package com.zhiwei.ws.imp;... Spring Boot集成CXF框架可以方便地调用Web服务。以下是使用Spring Boot和CXF调用Web服务的步骤: 1. 在pom.xml文件中添加CXF依赖: <dependency> <groupId>org.apache.cxf</groupId> <artifactId>cxf-spring-boot-starter-jaxws</artifactId> <version>3.3.6</version> </dependency> 2. 创建一个接口来定义Web服务的操作: @WebService public interface MyWebService { @WebMethod String sayHello(String name); 3. 创建一个实现类来实现接口中定义的操作: @Service @WebService(endpointInterface = "com.example.MyWebService") public class MyWebServiceImpl implements MyWebService { @Override public String sayHello(String name) { return "Hello " + name + "!"; 4. 在应用程序的配置文件中添加CXF配置: cxf: servlet: path: /services/* jaxws: properties: javax.xml.ws.soap.http.soapaction.use: "false" 5. 在控制中注入Web服务并调用它: @RestController public class MyController { @Autowired private MyWebService myWebService; @GetMapping("/hello/{name}") public String sayHello(@PathVariable String name) { return myWebService.sayHello(name); 6. 启动应用程序并访问Web服务: http://localhost:8080/services/MyWebServiceImpl?wsdl 以上就是使用Spring Boot和CXF调用Web服务的步骤。 ### 回答2: Spring Boot是一个使用习惯优秀的Web应用开发框架,它可以帮助我们快速构建应用,提高开发效率。而CXF是一个开源的WebService框架,它提供了一系列的API和工具来帮助开发人员可以很轻易地实现一个基于SOAP的Web服务。 在Spring Boot中调用CXF框架中的WebService,需要进行以下步骤: 1. 添加依赖 在pom.xml中添加CXF和Spring Boot Web依赖: <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.apache.cxf</groupId> <artifactId>cxf-spring-boot-starter-jaxws</artifactId> <version>3.3.1</version> </dependency> </dependencies> 2. 编写WebService客户端类 编写一个类来调用CXF产生的webservice服务,其中包括Endpoint指向和需要调用的方法等信息。 @Service public class WebServiceClient { @Autowired private JaxWsProxyFactoryBean jaxWsProxyFactoryBean; private HelloPortType helloPortType; public String sayHello(final String name) { initPortType(); return helloPortType.sayHello(name); private void initPortType() { if (helloPortType == null) { jaxWsProxyFactoryBean.setServiceClass(HelloPortType.class); jaxWsProxyFactoryBean.setAddress("http://localhost:8080/hello"); helloPortType = (HelloPortType) jaxWsProxyFactoryBean.create(); 3. 编写WebService 通过CXF创建web服务,并实现接口提供服务,返回接口需要的数据。 @javax.jws.WebService(serviceName = "HelloService", portName = "HelloPort", targetNamespace = "http://www.example.org/HelloService/", endpointInterface = "org.example.service.HelloPortType") public class HelloPortTypeImpl implements HelloPortType { private final static Logger LOGGER = LoggerFactory.getLogger(HelloPortTypeImpl.class); @Resource private WebServiceContext webServiceContext; @Override public String sayHello(final String name) { final MessageContext mc = webServiceContext.getMessageContext(); final HttpServletRequest req = (HttpServletRequest) mc.get(MessageContext.SERVLET_REQUEST); LOGGER.info("服务SayHello calling, name: {}, IP addr:{}, sessionId: {}", name, req.getRemoteAddr(), req.getSession().getId()); return String.format("Hello, %s!", name); 4. 进行测试 在控制中注入WebService客户端类,并进行测试。 @RestController @RequestMapping("/test") public class TestController { @Autowired private WebServiceClient webServiceClient; @GetMapping("/sayHello") public String sayHello(@RequestParam(value = "name") final String name) { return webServiceClient.sayHello(name); 总的来说,Spring Boot和CXF框架结合起来使用,可以很方便地调用WebService,提供服务的代码也可以很容易地进行编写。 ### 回答3: SpringBoot是一个非常受欢迎的Java框架,其有很多优秀的特性让使用者更方便地进行应用的开发。其中,SpringBoot与CXF框架结合使用来调用Webservice可以非常简单地完成。本文将介绍SpringBoot与CXF框架结合使用来调用Webservice。 首先,我们需要在pom.xml文件中加入CXF及相关依赖。 ```xml <dependency> <groupId>org.apache.cxf</groupId> <artifactId>cxf-rt-frontend-jaxws</artifactId> <version>3.2.14</version> </dependency> <dependency> <groupId>org.apache.cxf</groupId> <artifactId>cxf-rt-transport-http</artifactId> <version>3.2.14</version> </dependency> 然后,我们需要在配置文件中设置一些参数,具体如下: ```yaml cxf: client: simple.frontend: true logging.enabled: true timeout: connect: 2000 receive: 5000 path: /ws servlet: url-pattern: /soap/* 在上述配置中,我们开启了日志记录,设置了连接超时和读取超时时间,以及指明了Webservice的路径。 接下来就可以创建一个接口来调用我们的Webservice。例如,我们想要调用一个返回学生列表的Webservice: ```java @WebService public interface StudentWebService { @WebMethod List<Student> getStudents(); 我们使用CXF的JAX-WS Frontend创建了一个接口,同时使用@WebService注解来标记该接口。然后我们就可以创建一个实现类来实现该接口: ```java @Service public class StudentWebServiceImpl implements StudentWebService { @Override public List<Student> getStudents() { // 调用Webservice,返回学生列表 return new ArrayList<>(); 在上述实现类中,我们使用@Service注解来标记该类为SpringBoot的一个服务,同时实现了我们在接口中声明的getStudents()方法,去调用Webservice并返回学生列表。在该方法中,我们可以使用Spring提供的RestTemplate或者使用CXF的Client接口来进行调用。 然后我们同样使用CXF开放一个服务端口,供客户端调用: ```java @Configuration public class CxfConfig { @Bean(name = Bus.DEFAULT_BUS_ID) public SpringBus springBus() { return new SpringBus(); @Bean public ServletRegistrationBean<CXFServlet> cxfServlet() { return new ServletRegistrationBean<CXFServlet>(new CXFServlet(), "/soap/*"); @Bean public StudentWebService studentWebService() { return new StudentWebServiceImpl(); @Bean public Endpoint endpoint() { EndpointImpl endpoint = new EndpointImpl(springBus(), studentWebService()); endpoint.publish("/StudentWebService"); return endpoint; 在上述代码中,我们创建了一个CXFServlet,并将其映射到/soap/*路径下,同时创建了一个WebService的实现类,在SpringBoot启动时通过Endpoint暴露出来。这样我们就可以在客户端中通过CXF框架来访问Webservice了。 总结一下,SpringBoot与CXF框架结合使用调用Webservice可以非常方便地完成。我们只需要提供一个接口,实现其方法并使用CXF暴露出去,就可以在客户端通过CXF框架来访问了。同时,我们还可以使用CXF的一些特性来定制化我们的调用过程,包括定制连接超时、读取超时、日志记录等。 菜鸟提问:刚学这个的时候演示到 关了本地的tomcat再打开 session还是一样的 他自己就自动在这过程中钝化和激活了 但是我的那个servlet里面没有像文章一样的继承序列化的接口 为什么不用这样也行呢