CXF打印SOAP报文,记录WebService日志

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>
--------------------------------------






  • 1
    点赞
  • 18
    收藏
    觉得还不错? 一键收藏
  • 4
    评论
好的,我可以为您提供相关的帮助。在SpringBoot中,我们可以使用CXF来实现SOAP WebService。下面是一些基本的步骤: 1. 首先,需要在pom.xml文件中添加CXF依赖: ```xml <dependency> <groupId>org.apache.cxf</groupId> <artifactId>cxf-spring-boot-starter-jaxws</artifactId> <version>3.3.7</version> </dependency> ``` 2. 接下来,我们需要创建一个服务接口。例如: ```java @WebService public interface HelloWorldService { @WebMethod String sayHello(@WebParam(name = "name") String name); } ``` 3. 然后,我们需要创建服务实现类,实现服务接口中的方法。例如: ```java @WebService(endpointInterface = "com.example.demo.HelloWorldService") @Service public class HelloWorldServiceImpl implements HelloWorldService { @Override public String sayHello(String name) { return "Hello " + name + "!"; } } ``` 4. 然后,我们需要在application.properties文件中配置CXF服务。例如: ```properties # CXF properties cxf.path=/soap-api ``` 5. 最后,我们需要在启动类中添加注解@EnableWs和@Bean来配置CXF服务。例如: ```java @SpringBootApplication @EnableWs public class DemoApplication { public static void main(String[] args) { SpringApplication.run(DemoApplication.class, args); } @Bean public ServletRegistrationBean<CXFServlet> cxfServlet() { return new ServletRegistrationBean<>(new CXFServlet(), "/soap-api/*"); } @Bean(name = Bus.DEFAULT_BUS_ID) public SpringBus springBus() { return new SpringBus(); } @Bean public Endpoint endpoint() { EndpointImpl endpoint = new EndpointImpl(springBus(), new HelloWorldServiceImpl()); endpoint.publish("/hello"); return endpoint; } } ``` 这样,我们就可以在SpringBoot中整合CXF并实现SOAP WebService了。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值