SpringBoot+CXF 实现简单的webservice,并支持Basic验证

SpringBoot+CXF 实现简单的webservice,并支持Basic验证

pom.xml 添加的依赖

<!-- CXF -->
<dependency>
    <groupId>org.apache.cxf</groupId>
    <artifactId>cxf-spring-boot-starter-jaxws</artifactId>
    <version>3.1.15</version>
</dependency>

一个简单的 interface 标记为webservice接口

package com.wzh.demo.webservice.service;

import javax.jws.WebMethod;
import javax.jws.WebParam;
import javax.jws.WebService;

/**
 * @desc: 测试发布的websercice服务
 * @author: wzh
 * @date: 2019年3月31日
 */
@WebService
public interface IhelloService {
    
    /**
     * @desc: 测试发布的websercice接口
     * @author: wzh
     * @date: 2019年3月31日
     * @param message
     * @return
     */
    @WebMethod
    public String helloWebService(@WebParam(name="msg")String message);

}

basic鉴权拦截器

CXF内置了很多拦截器,大部分默认添加到拦截器链中,有些拦截器也可以手动添加,如CXF的日志拦截器。如果需要自定义拦截器,只要继承AbstractPhaseInterceptor或者AbstractPhaseInterceptor的子类(如AbstractSoapInterceptor)

package com.wzh.demo.webservice.interceptor;


import javax.servlet.http.HttpServletRequest;
import javax.xml.soap.SOAPException;

import org.apache.commons.lang.StringUtils;
import org.apache.commons.net.util.Base64;
import org.apache.cxf.binding.soap.SoapMessage;
import org.apache.cxf.binding.soap.interceptor.AbstractSoapInterceptor;
import org.apache.cxf.interceptor.Fault;
import org.apache.cxf.phase.Phase;
import org.apache.cxf.transport.http.AbstractHTTPDestination;

/**
 * @desc: 测试用baisc鉴权拦截器
 * @author: wzh
 * @date: 2019年3月31日
 */
public class HelloAuthInterceptor extends AbstractSoapInterceptor{

    private static final String BASIC_PREFIX = "Basic ";
    private static final String USERNAME = "admin";
    private static final String PASSWORD = "123456";
    
    /**
     * 指定加入拦截器到某个阶段 
     */
    public HelloAuthInterceptor() {
        super(Phase.PRE_INVOKE);
    }

    @Override
    public void handleMessage(SoapMessage message) throws Fault {

        // 获取HttpServletRequest
        HttpServletRequest request = (HttpServletRequest) message.get(AbstractHTTPDestination.HTTP_REQUEST);
        
        String auth = request.getHeader("Authorization");
        
        if (auth == null) {
            SOAPException exception = new SOAPException("Authorization 授权信息为空!");
            throw new Fault(exception);
        }
        if (!auth.startsWith(BASIC_PREFIX)) {
            SOAPException exception = new SOAPException("Authorization 非baisc验证");
            throw new Fault(exception);
        }
        // 合法的baisc格式为username:password  例如:admin:123456
        String plaintext = new String(Base64.decodeBase64(auth.substring(BASIC_PREFIX.length())));
        if (StringUtils.isEmpty(plaintext) || !plaintext.contains(":")) {
            SOAPException exception = new SOAPException("Authorization 非baisc验证");
            throw new Fault(exception);
        }
        
        String[] usernameAndPass = plaintext.split(":");
        String username = usernameAndPass[0];
        String password = usernameAndPass[1];
        if (!USERNAME.equals(username) || !PASSWORD.equals(password)) {
            SOAPException exception = new SOAPException("用户名或密码不正确!");
            throw new Fault(exception);
        }

    }

}

webservice 服务接口实现类

package com.wzh.demo.webservice.service.impl;

import java.util.Date;

import javax.jws.WebService;
import javax.jws.soap.SOAPBinding;
import javax.jws.soap.SOAPBinding.Style;

import org.apache.cxf.interceptor.InInterceptors;
import org.springframework.stereotype.Component;

import com.wzh.demo.webservice.service.IhelloService;

@InInterceptors(interceptors={"com.wzh.demo.webservice.interceptor.HelloAuthInterceptor"})// 添加拦截器
@WebService
@SOAPBinding(style=Style.RPC)
@Component
public class HelloServiceImpl implements IhelloService {

    @Override
    public String helloWebService(String message) {
        System.out.println(message);
        return "响应:" + new Date();
    }

}

配置发布webservice服务

package com.wzh.demo.webservice.Config;

import javax.xml.ws.Endpoint;

import org.apache.cxf.Bus;
import org.apache.cxf.bus.spring.SpringBus;
import org.apache.cxf.jaxws.EndpointImpl;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.boot.web.servlet.ServletRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.apache.cxf.transport.servlet.CXFServlet;

import com.wzh.demo.webservice.service.IhelloService;

/**
 * @desc: CXF SOAP 接口配置发布
 * @author: wzh
 * @date: 2019年3月31日
 */
@Configuration
public class SoapConfig {

    @Autowired
    @Qualifier(Bus.DEFAULT_BUS_ID)
    private SpringBus bus;

    @Autowired
    private IhelloService ihelloService;
    
    /**
     * 改变项目中服务名的前缀名
     * 方法被注释后:wsdl访问地址为http://localhost:8080/SpringBootDemo_eclipse/services/ihelloService?wsdl
     * 去掉注释后:wsdl访问地址为http://localhost:8080/SpringBootDemo_eclipse/soap/ihelloService?wsdl
     * @return
     */
    @Bean
    public ServletRegistrationBean dispatcherServlet() {
        return new ServletRegistrationBean(new CXFServlet(), "/soap/*");
    }

    // 发布多个接口 添加多个@Bean endpoint.publish 这里不能一样
    @Bean
    public Endpoint helloEndpoint() {
        EndpointImpl endpoint = new EndpointImpl(bus, ihelloService);
        endpoint.publish("/ihelloService");
        return endpoint;
    }
}

如果是传统的spring+cxf 项目,拦截器的写法是一样的,只是发布和配置的方法在cxf的配置文件的xml中进行

    <!--id:名称(随意配),implementor:指定接口具体实现类,address:随意配-->  
    <jaxws:endpoint id="helloWorld"  implementor="#HelloWorldImpl" address="/HelloWorld"  >  
        <!-- 输入日志拦截器 -->  
       <jaxws:inInterceptors>  
          <bean class="org.apache.cxf.interceptor.LoggingInInterceptor"/>
       </jaxws:inInterceptors>  
       <!-- 输出日志拦截器 -->  
       <jaxws:outInterceptors>  
          <bean class="org.apache.cxf.interceptor.LoggingOutInterceptor"/>
       </jaxws:outInterceptors>  
       <jaxws:properties>  
          <entry key="mtom_enabled" value="true"></entry>  
       </jaxws:properties>   
          
    </jaxws:endpoint>  

测试

WSDL 地址:http://localhost:8080/SpringBootDemo_eclipse/soap/ihelloService?wsdl

代码客户端测试

CXF 自动编译解析的客户端

package com.wzh.demo.webservice.client;

import javax.jws.WebMethod;
import javax.jws.WebParam;
import javax.jws.WebResult;
import javax.jws.WebService;
import javax.jws.soap.SOAPBinding;

/**
 * This class was generated by Apache CXF 2.6.2
 * 2019-03-31T19:54:58.255+08:00
 * Generated source version: 2.6.2
 * 
 */
@WebService(targetNamespace = "http://service.webservice.demo.wzh.com/", name = "IhelloService")
@SOAPBinding(style = SOAPBinding.Style.RPC)
public interface IhelloService {

    @WebResult(name = "return", targetNamespace = "http://service.webservice.demo.wzh.com/", partName = "return")
    @WebMethod
    public java.lang.String helloWebService(
        @WebParam(partName = "msg", name = "msg")
        java.lang.String msg
    );
}

package com.wzh.demo.webservice.client;

import java.net.MalformedURLException;
import java.net.URL;
import javax.xml.namespace.QName;
import javax.xml.ws.WebEndpoint;
import javax.xml.ws.WebServiceClient;
import javax.xml.ws.WebServiceFeature;
import javax.xml.ws.Service;

/**
 * This class was generated by Apache CXF 2.6.2
 * 2019-03-31T19:54:58.261+08:00
 * Generated source version: 2.6.2
 * 
 */
@WebServiceClient(name = "HelloServiceImplService", 
                  wsdlLocation = "http://localhost:8080/SpringBootDemo_eclipse/soap/ihelloService?wsdl",
                  targetNamespace = "http://impl.service.webservice.demo.wzh.com/") 
public class HelloServiceImplService extends Service {

    public final static URL WSDL_LOCATION;

    public final static QName SERVICE = new QName("http://impl.service.webservice.demo.wzh.com/", "HelloServiceImplService");
    public final static QName HelloServiceImplPort = new QName("http://impl.service.webservice.demo.wzh.com/", "HelloServiceImplPort");
    static {
        URL url = null;
        try {
            url = new URL("http://localhost:8080/SpringBootDemo_eclipse/soap/ihelloService?wsdl");
        } catch (MalformedURLException e) {
            java.util.logging.Logger.getLogger(HelloServiceImplService.class.getName())
                .log(java.util.logging.Level.INFO, 
                     "Can not initialize the default wsdl from {0}", "http://localhost:8080/SpringBootDemo_eclipse/soap/ihelloService?wsdl");
        }
        WSDL_LOCATION = url;
    }

    public HelloServiceImplService(URL wsdlLocation) {
        super(wsdlLocation, SERVICE);
    }

    public HelloServiceImplService(URL wsdlLocation, QName serviceName) {
        super(wsdlLocation, serviceName);
    }

    public HelloServiceImplService() {
        super(WSDL_LOCATION, SERVICE);
    }
    
    //This constructor requires JAX-WS API 2.2. You will need to endorse the 2.2
    //API jar or re-run wsdl2java with "-frontend jaxws21" to generate JAX-WS 2.1
    //compliant code instead.
    public HelloServiceImplService(WebServiceFeature ... features) {
        super(WSDL_LOCATION, SERVICE, features);
    }

    //This constructor requires JAX-WS API 2.2. You will need to endorse the 2.2
    //API jar or re-run wsdl2java with "-frontend jaxws21" to generate JAX-WS 2.1
    //compliant code instead.
    public HelloServiceImplService(URL wsdlLocation, WebServiceFeature ... features) {
        super(wsdlLocation, SERVICE, features);
    }

    //This constructor requires JAX-WS API 2.2. You will need to endorse the 2.2
    //API jar or re-run wsdl2java with "-frontend jaxws21" to generate JAX-WS 2.1
    //compliant code instead.
    public HelloServiceImplService(URL wsdlLocation, QName serviceName, WebServiceFeature ... features) {
        super(wsdlLocation, serviceName, features);
    }

    /**
     *
     * @return
     *     returns IhelloService
     */
    @WebEndpoint(name = "HelloServiceImplPort")
    public IhelloService getHelloServiceImplPort() {
        return super.getPort(HelloServiceImplPort, IhelloService.class);
    }

    /**
     * 
     * @param features
     *     A list of {@link javax.xml.ws.WebServiceFeature} to configure on the proxy.  Supported features not in the <code>features</code> parameter will have their default values.
     * @return
     *     returns IhelloService
     */
    @WebEndpoint(name = "HelloServiceImplPort")
    public IhelloService getHelloServiceImplPort(WebServiceFeature... features) {
        return super.getPort(HelloServiceImplPort, IhelloService.class, features);
    }

}

客户端basic 认证调用

package com.wzh.demo.webservice.client;

import javax.xml.ws.BindingProvider;

/**
 * @desc: 测试连接用客户端
 * @author: wzh
 * @date: 2019年3月31日
 */
public class testClient {
    
    public static void main(String[] args) {
        IhelloService service = new HelloServiceImplService().getHelloServiceImplPort();
        
        // 添加basc 认证
        BindingProvider bp = (BindingProvider) service;
        bp.getRequestContext().put(BindingProvider.USERNAME_PROPERTY, "admin");
        bp.getRequestContext().put(BindingProvider.PASSWORD_PROPERTY, "1234562");
        
        System.out.println(service.helloWebService("测试一下"));
    }
}

SOAPUI 测试

《SpringBoot+CXF 实现简单的webservice,并支持Basic验证》 image.png

    原文作者:Harry_ZH_Wang
    原文地址: https://www.jianshu.com/p/e9ac2790539e
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞