CXF
来源:互联网 发布:网络质量监控技术 编辑:程序博客网 时间:2024/06/05 15:15
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>
启用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>
服务端发布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; }}
定义接口之后需要发布接口:配置文件如下
<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>
备注:接口真正调用地址:
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); } }}
增加安全校验使用拦截器:
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("用户名或密码不正确")); } } }
客户端调用webservice接口相关知识如下:
使用jdk或者saopui生成客户端代码。
调用接口客户端代码如下:
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("###", "####", "###"));
备注:上述代码可考虑写静态方法作为工具类使用,调用接口时调用工具类即可
接口调用: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; }}
备注: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> */ }}
备注: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>
http:tlsClientParameters
._EXPORT_.
._EXPORT1024_.
._WITH_DES_.
._WITH_AES_.
._WITH_NULL_.
._DH_anon_.