cxf框架的简介

webservice测试工具-SoapUi

Apache CXF 是一个开源的 Services 框架,CXF 帮助您利用 Frontend 编程 API 来构建和开发 Services .

maven引用cxf:

<dependency>
    <groupId>org.apache.cxf</groupId>
    <artifactId>cxf-rt-frontend-jaxws</artifactId>
    <version>3.1.3</version>
</dependency>
<dependency>
    <groupId>org.apache.cxf</groupId>
    <artifactId>cxf-rt-transports-http</artifactId>
    <version>3.1.3</version>
</dependency>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11

启用cxf,web.xml文件中添加配置如下: 
备注:webservice访问路径为:项目访问地址/ws/地址

 <!-- Web Service 配置  cxf -->
    <servlet>  
        <servlet-name>CXFServlet</servlet-name>  
        <servlet-class>org.apache.cxf.transport.servlet.CXFServlet</servlet-class>  
        <load-on-startup>1</load-on-startup>  
    </servlet>  
    <servlet-mapping>  
        <servlet-name>CXFServlet</servlet-name>  
        <url-pattern>/ws/*</url-pattern>  
    </servlet-mapping> 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10

服务端发布webservice接口相关知识如下:

webservice接口(主要使用注解),示例代码如下:

接口(interface)
@WebService(targetNamespace = "urn:sinopec:ecc:fi:tmsno:fx")
public interface TmsImsWebService {

    @WebMethod(operationName = "MT_TMS_ECC_FI_TMSYXNO")
    public String tmsNo(@WebParam(name = "TmsYxNo") String tmsNo, @WebParam(name = "CODE") String compCode,
            @WebParam(name = "YWRQ") String ywrq);
}

接口实现:

@WebService(endpointInterface = "com.pcitc.cbs.webService.TmsImsWebService", targetNamespace = "urn:sinopec:ecc:fi:tmsno:fx")
public class TmsImsWebServiceImpl implements TmsImsWebService {

    @Autowired
    private TmsConfirmRemainService tmsRemain;

    @Override
    public String tmsNo(String tmsNo, String compCode, String ywrq) {
        String sss = tmsRemain.getTmsStrNo(tmsNo, compCode, ywrq);
        return sss;
    }

}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24

定义接口之后需要发布接口:配置文件如下

<bean id="TmsImsWebServiceImpl" class="com.pcitc.cbs.webService.impl.TmsImsWebServiceImpl">
    </bean>
    <jaxws:endpoint id="TmsImsWebService" implementor="#TmsImsWebServiceImpl"
        address="/tmsImsNo">
        <jaxws:inInterceptors>
            <ref bean="InMessageInterceptor" />
        </jaxws:inInterceptors>
    </jaxws:endpoint>

另一种发布方式:

<jaxws:server id="TmsImsWebService" address="/tmsImsNo"
        serviceClass="com.pcitc.cbs.webService.TmsImsWebService">
        <jaxws:serviceBean>
            <bean class="com.pcitc.cbs.webService.impl.TmsImsWebServiceImpl" />
        </jaxws:serviceBean>
        <jaxws:inInterceptors>
            <ref bean="InMessageInterceptor" />
        </jaxws:inInterceptors>
    </jaxws:server>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21

备注:接口真正调用地址: 
http://localhost:8080/fsscbs/ws/tmsImsNo 
浏览器访问时因接口协议访问地址需加上后缀如下: 
http://localhost:8080/fsscbs/ws/tmsImsNo?wsdl 
其中 

是定义的拦截器

webservice拦截器: 
继承:AbstractPhaseInterceptor message有好多种

public class InMessageInterceptor extends AbstractPhaseInterceptor<Message>{

    protected Logger log;

    public InMessageInterceptor(){

        this(Phase.RECEIVE, InMessageInterceptor.class.getName());
    }

    public InMessageInterceptor(String logName){

        this(Phase.RECEIVE, logName); 
    }

    protected InMessageInterceptor(String phase, String logName)
    {
        super(phase); 
        log = Logger.getLogger(logName);
    }

    protected String modifyMessage(String message)
    {
        return message;
    }

    public void handleMessage(Message message) {
        try { 

            String serviceName="";
            Exchange exchange = message.getExchange(); 

            if(exchange!=null && exchange.getService()!=null)
                serviceName = exchange.getService().getName().toString();

            log.info("Service = " + serviceName);

            InputStream is = message.getContent(InputStream.class);  
            String encode = (String) message.get(Message.ENCODING);  
            String xml = IOUtils.toString(is, encode);    

            if (log.isInfoEnabled()) {  
                log.info("Service = " + serviceName + ", soap message = " + xml); 
            }

            xml = modifyMessage(xml);

            message.setContent(InputStream.class, new ByteArrayInputStream(xml.getBytes(encode)));  

        } 

        catch (Exception e) {
            if (log.isEnabledFor(Level.DEBUG))
                log.error("Error when split original inputStream. CausedBy : " + "\n" + e);
        }
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56

增加安全校验使用拦截器:

public class AuthInterceptor extends AbstractPhaseInterceptor<SoapMessage> {  

    public AuthInterceptor() {  
        super(Phase.PRE_INVOKE); //拦截器在调用方法之前拦截SOAP消息  
    }  

    // 拦截器操作  
    @Override  
    public void handleMessage(SoapMessage msg) throws Fault {  
        System.out.println("come to auth interceptor...");  
        //获取SOAP消息的所有Header  
        List<Header> headers = msg.getHeaders();  

        if(headers == null || headers.size() < 1) {  
            throw new Fault(new IllegalArgumentException("没有Header,拦截器实施拦截"));  
        }  
        //获取Header携带是用户和密码信息  
        Header firstHeader = headers.get(0);  
        Element element = (Element) firstHeader.getObject();  

        NodeList userNameElement = element.getElementsByTagName("userName");  
        NodeList passwordElement = element.getElementsByTagName("password");  

        if (userNameElement.getLength() != 1) {  
            throw new Fault(new IllegalArgumentException("用户名格式不对"));  
        }  

        if (passwordElement.getLength() != 1) {  
            throw new Fault(new IllegalArgumentException("用户密码格式不对"));  
        }  

        //获取元素的文本内容  
        String userName = userNameElement.item(0).getTextContent();  
        String password = passwordElement.item(0).getTextContent();  

        // 实际项目中, 应该去查询数据库, 该用户名,密码是否被授权调用该webservice  
        if (!userName.equals("zheng") || !password.equals("123456")) {  
            throw new Fault(new IllegalArgumentException("用户名或密码不正确"));  
        }  
    }  
}  
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41

客户端调用webservice接口相关知识如下: 
使用jdk或者saopui生成客户端代码。 
调用接口客户端代码如下:

扫描二维码关注公众号,回复: 146062 查看本文章
JaxWsProxyFactoryBean svr = new JaxWsProxyFactoryBean();
        svr.setServiceClass(TmsImsWebService.class);
        svr.setAddress("http://localhost:8080/fsscbs/ws/tmsImsNo");
        TmsImsWebService hw = (TmsImsWebService) svr.create();
        System.out.println(hw.mtTMSECCFITMSYXNO("###", "####", "###"));
  • 1
  • 2
  • 3
  • 4
  • 5

备注:上述代码可考虑写静态方法作为工具类使用,调用接口时调用工具类即可

接口调用:BISSoapEntryBISInvoke 为接口名称:
BISSoapEntryBISInvoke tmsCancelPort = ProxyFactory.getTmsCancelPort(BISSoapEntryBISInvoke.class);

ProxyFactory 工具类如下

public class ProxyFactory {

    public static <T> T getMobile(Class<T> c) {
        String address = getAddress("Mobile_Url");
//      OutMessageInterceptor i = new OutMessageInterceptor();
        return getPort(c, address, null);
    }

    public static String getAddress(String propertyName) {
        PropertiesUtil util = new PropertiesUtil("cxf.properties");
        String address = util.getValue(propertyName);
        return address;
    }

    @SuppressWarnings("unused")
    private static String getAddress(String path, String propertyName) {
        PropertiesUtil util = new PropertiesUtil(path);
        String address = util.getValue(propertyName);
        return address;
    }

    // 获取WebService接口
    public static <T> T getPort(Class<T> c, String address) {
        return (T) getPort(c, address, null);

    }

    @SuppressWarnings("unchecked")
    private static <T> T getPort(Class<T> c, String address, Interceptor<?> interceptor) {
        JaxWsProxyFactoryBean soapFactoryBean = new JaxWsProxyFactoryBean();
        soapFactoryBean.setAddress(address);
        soapFactoryBean.setServiceClass(c);
        if (interceptor != null) {
            if (interceptor instanceof OutMessageInterceptor) {
                soapFactoryBean.getOutInterceptors().add(interceptor);
            }

            if (interceptor instanceof InMessageInterceptor) {
                soapFactoryBean.getInInterceptors().add(interceptor);
            }
        }
        return (T) soapFactoryBean.create();

    }
}

PropertiesUtil 工具类操作properties文件:
package com.guo.hui.util;

import java.io.IOException;
import java.io.InputStream;
import java.util.Map.Entry;
import java.util.Properties;
import java.util.Set;

import org.springframework.core.io.ClassPathResource;
import org.springframework.core.io.Resource;

public class PropertiesUtil {

    private String fileName;

    public PropertiesUtil(String fileName) {
        this.fileName = fileName;
    }

    /**
     * 获得数据库配置信息
     * 
     * @return
     * @throws IOException
     */
    private Properties loadProperties() throws IOException {
        Properties p = null;
        InputStream inputStream = null;
        try {
            p = new Properties();
            Resource resource = new ClassPathResource(this.fileName);
            inputStream = resource.getInputStream();
            p.load(inputStream);
        } catch (IOException e) {
            if (inputStream != null) {
                inputStream.close();
            }
            throw e;
        }
        return p;
    }

    private Properties properties;

    // 获取值
    public String getValue(String key) {
        if (properties == null) {
            try {
                properties = this.loadProperties();
            } catch (IOException e) {
                System.out.print(e.getMessage());
            }
        }
        if (properties != null) {
            return properties.getProperty(key);
        }
        return null;
    }

    public Set<Entry<Object, Object>> getData() {
        if (properties == null) {
            try {
                properties = this.loadProperties();
            } catch (IOException e) {
                System.out.print(e.getMessage());
            }
        }
        if (properties != null) {

            return properties.entrySet();
            // return properties.getProperty(key);
        }

        return null;
    }

}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
  • 107
  • 108
  • 109
  • 110
  • 111
  • 112
  • 113
  • 114
  • 115
  • 116
  • 117
  • 118
  • 119
  • 120
  • 121
  • 122
  • 123
  • 124
  • 125
  • 126
  • 127
  • 128
  • 129
  • 130

备注:String address = getAddress(“TMS_Status_ServiceUrl”);

TMS_Status_ServiceUrl是读取配置文件(properties)地址: 
TMS_Status_ServiceUrl={webserviceroot}/webservices/##{webserviceroot} el表达式去maven项目pom文件中的地址,是接口能适应不同运行环境(生产,预生产,测试等) 
pom中的配置:IP+端口+通用地址部分 
http://IP:port/#

客户端可设置拦截器,记录日志或者增加用户密码,示例代码如下:

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.phase.AbstractPhaseInterceptor;
import org.apache.cxf.phase.Phase;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import com.hpzc.model.exception.BizException; //自定义异常类


public class AddHeaderInterceptor extends AbstractPhaseInterceptor<SoapMessage> {

    private String userName;
    private String password;

    public AddHeaderInterceptor(String userName, String password) {
        super(Phase.PREPARE_SEND);
        this.userName = userName;
        this.password = password;
    }

    @Override
    public void handleMessage(SoapMessage msg) throws BizException {

        List<Header> headers = msg.getHeaders();

        // 创建Document对象
        Document document = DOMUtils.createDocument();
        Element element = document.createElement("authHeader");

        // 配置服务器端Head信息的用户密码
        Element userNameElement = document.createElement("userName");
        userNameElement.setTextContent(userName);
        System.out.println(userNameElement.getElementsByTagName("userName"));
        Element passwordElement = document.createElement("password");
        passwordElement.setTextContent(password);

        element.appendChild(userNameElement);
        element.appendChild(passwordElement);
        headers.add(new Header(new QName(""), element));
        /**
         * 生成的XML文档 <authHeader> <userName>zheng</userName>
         * <password>1111</password> </authHeader>
         */
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48

备注:userNameElement.setTextContent(userName); 
passwordElement.setTextContent(password); 可能会报错.报错可能原因是xml-api.jar包冲突.

org.w3c.dom.Element 缺少 setTextContent 方法 
  org.w3c.dom.Element没有setTextContent方法 的编译错。 
  主要是 xercesImpl.jar 和 xml-apis.jar的Element版本太老造成的,setTextContent是DOM3中的方法。 
  但在pom文件中,未发现有直接引用这两个jar包的地方。好在eclipse maven插件功能强大,在Project Explorer的Maven Dependencies中 
  找到了xml-api.jar,然后右键->Maven->Exclude Maven artifact,弹出窗口,提示会在当前pom文件中的hibernate-core依赖中,排除掉 
  xml-api.jar,确认后,pom文件被修改,更新Maven Dependencies,重新编译,问题解决

假设访问接口时增加了http校验也就是访问接口时先验证则可以增加如下配置,通过验证。 
cxf配置文件中增加如下配置,可以增加用户/密码 
配置文件增加验证:pom中的配置:IP+端口+通用地址部分相同

    <http:authorization>
        <sec:UserName>ims</sec:UserName>
        <sec:Password>ims</sec:Password>
    </http:authorization>
    <http:client AutoRedirect="true" Connection="Keep-Alive" />

</http:conduit>

猜你喜欢

转载自blog.csdn.net/qq_40158032/article/details/78837658