CXF是Apache发布的一个用于快速构建Services的框架,用于构建WebService客户端及服务端。
使用cxf构建的java程序,在java层面看到的是很多层的java类对象,但是在实际的接口调用和数据传输过程中则使用的soap报文(网络传输过程中不可能真的把java对象传过去)。
第一种方法使用cxf自带拦截器直接在控制台打印输入输出报文,适合使用main()方法测试时使用。
第二种方法自己实现拦截器进行报文输出,报文可用日志工具进行存储,或者写入数据库,适合web项目使用。
第一种方法代码如下:
package com.action;
import org.apache.cxf.endpoint.Client;
import org.apache.cxf.frontend.ClientProxy;
import org.apache.cxf.transport.http.HTTPConduit;
import org.apache.cxf.transports.http.configuration.HTTPClientPolicy;
public class CoreAction {
public static void test(BaseDto b, QueryDto b1) {
// 设置URL
String url = "http://localhost:8080/core/services/query";
// 实例化service
QueryPolicy service = CxfUtil.getService(QueryPolicy.class, url);
// 超时
Client proxy = ClientProxy.getClient(service);
HTTPConduit conduit = (HTTPConduit) proxy.getConduit();
HTTPClientPolicy policy = new HTTPClientPolicy();
policy.setConnectionTimeout(6000); // 6000毫秒
policy.setReceiveTimeout(6000); // 6000毫秒
conduit.setClient(policy);
// 调用
response response = service.query(b, b1);
}
public static void main(String[] args) {
BaseDto b = new BaseDto();
QueryDto b1 = new QueryDto();
test(b, b1);
}
}
两行拦截器代码:
package com.util;
import java.util.HashMap;
import java.util.Map;
import org.apache.cxf.interceptor.LoggingInInterceptor;
import org.apache.cxf.interceptor.LoggingOutInterceptor;
import org.apache.cxf.jaxws.JaxWsProxyFactoryBean;
public class CxfUtil {
private static Map<String, Object> serviceMap = new HashMap<String, Object>();
public static <T> T getService(Class<? extends T> type, String serviceUrl) {
Object client = serviceMap.get(serviceUrl);
if (client == null) {
synchronized (serviceMap) {
JaxWsProxyFactoryBean factory = new JaxWsProxyFactoryBean();
factory.setServiceClass(type);
factory.setAddress(serviceUrl);
// 输入报文拦截器
factory.getInInterceptors().add(new LoggingInInterceptor());
// 输出报文拦截器
factory.getOutInterceptors().add(new LoggingOutInterceptor());
client = factory.create();
serviceMap.put(serviceUrl, client);
}
}
if (client == null) {
throw new IllegalArgumentException(String.format("The url:%s is not a service url", serviceUrl));
}
if (!type.isAssignableFrom(client.getClass())) {
throw new IllegalArgumentException(String.format("The service's type should be %s", client.getClass()));
}
return (T) client;
}
}
第二种方法代码如下:
1.实现输入报文拦截器InInterceptor
package com.util;
import java.io.IOException;
import java.io.InputStream;
import org.apache.cxf.helpers.IOUtils;
import org.apache.cxf.interceptor.Fault;
import org.apache.cxf.interceptor.LoggingMessage;
import org.apache.cxf.io.CachedOutputStream;
import org.apache.cxf.message.Message;
import org.apache.cxf.phase.AbstractPhaseInterceptor;
import org.apache.cxf.phase.Phase;
public class InInterceptor extends AbstractPhaseInterceptor<Message> {
private int limit = 102400;
public int getLimit() {
return limit;
}
public void setLimit(int limit) {
this.limit = limit;
}
public InInterceptor() {
// 拦截器在调用方法之前拦截SOAP消息
super(Phase.RECEIVE);
}
public void handleMessage(Message message) throws Fault {
logging(message);
}
private void logging(Message message) throws Fault {
if (message.containsKey(LoggingMessage.ID_KEY)) {
return;
}
String id = (String) message.getExchange().get(LoggingMessage.ID_KEY);
if (id == null) {
id = LoggingMessage.nextId();
message.getExchange().put(LoggingMessage.ID_KEY, id);
}
message.put(LoggingMessage.ID_KEY, id);
LoggingMessage buffer = new LoggingMessage("Inbound Message\n----------------------------", id);
String encoding = (String) message.get(Message.ENCODING);
if (encoding != null) {
buffer.getEncoding().append(encoding);
}
String ct = (String) message.get("Content-Type");
if (ct != null) {
buffer.getContentType().append(ct);
}
Object headers = message.get(Message.PROTOCOL_HEADERS);
if (headers != null) {
buffer.getHeader().append(headers);
}
String uri = (String) message.get(Message.REQUEST_URI);
if (uri != null) {
buffer.getAddress().append(uri);
}
InputStream is = (InputStream) message.getContent(InputStream.class);
if (is != null) {
CachedOutputStream bos = new CachedOutputStream();
try {
IOUtils.copy(is, bos);
bos.flush();
is.close();
message.setContent(InputStream.class, bos.getInputStream());
if (bos.getTempFile() != null) {
buffer.getMessage().append("\nMessage (saved to tmp file):\n");
buffer.getMessage().append("Filename: " + bos.getTempFile().getAbsolutePath() + "\n");
}
if (bos.size() > this.limit) {
buffer.getMessage().append("(message truncated to " + this.limit + " bytes)\n");
}
bos.writeCacheTo(buffer.getPayload(), this.limit);
bos.close();
} catch (IOException e) {
throw new Fault(e);
}
}
// 打印日志,保存日志保存这里就可以,可写库或log4j记录日志
System.out.println(buffer.toString());
}
// 出现错误输出错误信息和栈信息
public void handleFault(Message message) {
Exception exeption = message.getContent(Exception.class);
System.out.println(exeption.getMessage());
}
}
2.实现输出报文拦截器OutInterceptor
package com.util;
import java.io.OutputStream;
import org.apache.cxf.interceptor.Fault;
import org.apache.cxf.interceptor.LoggingMessage;
import org.apache.cxf.io.CacheAndWriteOutputStream;
import org.apache.cxf.io.CachedOutputStream;
import org.apache.cxf.io.CachedOutputStreamCallback;
import org.apache.cxf.message.Message;
import org.apache.cxf.phase.AbstractPhaseInterceptor;
import org.apache.cxf.phase.Phase;
public class OutInterceptor extends AbstractPhaseInterceptor<Message> {
private int limit = 102400;
public int getLimit() {
return limit;
}
public void setLimit(int limit) {
this.limit = limit;
}
public OutInterceptor() {
// 拦截器在调用方法之前拦截SOAP消息
super(Phase.PRE_STREAM);
}
public void handleMessage(Message message) throws Fault {
OutputStream os = (OutputStream) message.getContent(OutputStream.class);
if (os == null) {
return;
}
CacheAndWriteOutputStream newOut = new CacheAndWriteOutputStream(os);
message.setContent(OutputStream.class, newOut);
newOut.registerCallback(new LoggingCallback(message, os));
}
// 出现错误输出错误信息和栈信息
public void handleFault(Message message) {
Exception exeption = message.getContent(Exception.class);
System.out.println(exeption.getMessage());
}
class LoggingCallback implements CachedOutputStreamCallback {
private final Message message;
private final OutputStream origStream;
public LoggingCallback(Message msg, OutputStream os) {
this.message = msg;
this.origStream = os;
}
public void onFlush(CachedOutputStream cos) {
}
public void onClose(CachedOutputStream cos) {
String id = (String) this.message.getExchange().get(LoggingMessage.ID_KEY);
if (id == null) {
id = LoggingMessage.nextId();
this.message.getExchange().put(LoggingMessage.ID_KEY, id);
}
LoggingMessage buffer = new LoggingMessage("Outbound Message\n---------------------------", id);
String encoding = (String) this.message.get(Message.ENCODING);
if (encoding != null) {
buffer.getEncoding().append(encoding);
}
String address = (String) this.message.get(Message.ENDPOINT_ADDRESS);
if (address != null) {
buffer.getAddress().append(address);
}
String ct = (String) this.message.get("Content-Type");
if (ct != null) {
buffer.getContentType().append(ct);
}
Object headers = this.message.get(Message.PROTOCOL_HEADERS);
if (headers != null) {
buffer.getHeader().append(headers);
}
if (cos.getTempFile() == null) {
if (cos.size() > OutInterceptor.this.limit)
buffer.getMessage().append("(message truncated to " + OutInterceptor.this.limit + " bytes)\n");
} else {
buffer.getMessage().append("Outbound Message (saved to tmp file):\n");
buffer.getMessage().append("Filename: " + cos.getTempFile().getAbsolutePath() + "\n");
if (cos.size() > OutInterceptor.this.limit)
buffer.getMessage().append("(message truncated to " + OutInterceptor.this.limit + " bytes)\n");
}
try {
cos.writeCacheTo(buffer.getPayload(), OutInterceptor.this.limit);
} catch (Exception ex) {
}
// 打印日志,保存日志保存这里就可以,可写库或log4j记录日志
System.out.println(buffer.toString());
try {
cos.lockOutputStream();
cos.resetOut(null, false);
} catch (Exception ex) {
}
this.message.setContent(OutputStream.class, this.origStream);
}
}
}
3.在Spring配置文件中引用拦截器
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:jaxws="http://cxf.apache.org/jaxws"
xmlns:cxf="http://cxf.apache.org/core"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://cxf.apache.org/jaxws
http://cxf.apache.org/schemas/jaxws.xsd
http://cxf.apache.org/core
http://cxf.apache.org/schemas/core.xsd">
<import resource="classpath:META-INF/cxf/cxf.xml" />
<import resource="classpath:META-INF/cxf/cxf-extension-soap.xml" />
<import resource="classpath:META-INF/cxf/cxf-servlet.xml" />
<bean id="find" class="com.vehicleservice.facade.findImpl"></bean>
<jaxws:endpoint id="findID" implementor="#find" address="/find" />
<bean id="listTest" class="com.vehicleservice.facade.listTestImpl"></bean>
<jaxws:endpoint id="listTestID" implementor="#listTest" address="/listTest" />
<bean id="threeTest" class="com.vehicleservice.facade.threeImpl"></bean>
<jaxws:endpoint id="threeTestID" implementor="#threeTest" address="/threeTest" />
<!-- 在此处引用拦截器 -->
<bean id="InInterceptor" class="com.util.InInterceptor" />
<bean id="OutInterceptor" class="com.util.OutInterceptor" />
<cxf:bus>
<cxf:inInterceptors>
<ref bean="InInterceptor" />
</cxf:inInterceptors>
<cxf:outInterceptors>
<ref bean="OutInterceptor" />
</cxf:outInterceptors>
</cxf:bus>
</beans>
报文输出结果:
信息: Outbound Message
---------------------------
ID: 1
Address: http://192.168.6.166:8080/SP/queryIndex
Encoding: UTF-8
Content-Type: text/xml
Headers: {SOAPAction=[""], Accept=[*/*]}
Payload: <soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/"><soap:Body><ns1:query xmlns:ns1="http://facade.com/"><arg0><busiServName>CompService</busiServName><businessNo>123456</businessNo></arg0><arg1><atomObject><reqCarBaseInfoDto><companyCode>123</companyCode><engineNo>123</engineNo><licenseNo>123</licenseNo></reqCarBaseInfoDto></atomObject></arg1></ns1:query></soap:Body></soap:Envelope>
--------------------------------------
信息: Inbound Message
----------------------------
ID: 1
Encoding: UTF-8
Content-Type: text/xml; charset=UTF-8
Headers: {content-type=[text/xml; charset=UTF-8], Date=[Tue, 14 Nov 2017 01:58:36 GMT], transfer-encoding=[chunked], X-Powered-By=[Servlet/2.5 JSP/2.1]}
Payload: <soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/"><soap:Body><ns1:queryResponse xmlns:ns1="http://facade.com/"><return><MessageVo><errorCode>23</errorCode><errorMessage>Index</errorMessage></MessageVo></return></ns1:queryResponse></soap:Body></soap:Envelope>
--------------------------------------