`
jackeysion
  • 浏览: 127614 次
  • 性别: Icon_minigender_1
  • 来自: 济南
社区版块
存档分类
最新评论

Cxf开发简易的WebService应用

 
阅读更多
为了简化WebService的开发,使用了CXF框架。单独创建一个应用,用于请求外部WebService服务、接收其他服务的调用请求,用这个应用与我们自己的应用系统采用Servlet的方式通信。

1. 创建WebService应用,创建一个Web工程,将Cxf2.7.4压缩包中的jar文件放到WEB-INF/lib目录下
修改 web.xml 文件,增加CXF的相关配置,如下:
<listener>
	<servlet>
		<servlet-name>CXFService</servlet-name>
		<servlet-class>
			org.apache.cxf.transport.servlet.CXFServlet
		</servlet-class>
	</servlet>

	<servlet-mapping>
		<servlet-name>CXFService</servlet-name>
		<url-pattern>/*</url-pattern>
	</servlet-mapping>



2. 在源代码的 src 目录下,增加xml文件:applicationContext-server.xml(名字自取),并配置到 web.xml 文件中,如下:
	<context-param>
		<param-name>contextConfigLocation</param-name>
		<param-value>
			classpath*:applicationContext-server.xml
		</param-value>
	</context-param>


3. web.xml中还需增加spring的配置(因为只是个接收和发送请求的应用,不需要太多的Spring的东西----其实本人对Spring了解也不多,尴尬ing...):
<listener>
		<listener-class>
			org.springframework.web.context.ContextLoaderListener
		</listener-class>
	</listener>

	<listener>
		<listener-class>
			org.springframework.web.util.IntrospectorCleanupListener
		</listener-class>
	</listener>



4. applicationContext-server.xml的内容:
<?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:aop="http://www.springframework.org/schema/aop"
	xmlns:jaxws="http://cxf.apache.org/jaxws"
	xsi:schemaLocation="
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.0.xsd
http://cxf.apache.org/jaxws 
http://cxf.apache.org/schemas/jaxws.xsd
http://www.springframework.org/schema/aop 
http://www.springframework.org/schema/aop/spring-aop-2.0.xsd">
	<!-- webservice start-->
	<!--  -->
	<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" />

	<!-- 注意下面的address,这里的address的名称就是访问的WebService的name -->
	<!-- 
		<jaxws:server id="forTest"
		serviceClass="com.dw.dzyd.jy.IComplexUserService"
		address="/forTest">
		</jaxws:server>
	-->
	<bean id="inMessageInterceptor"
		class="com.ydfw.pub.MessageInterceptor">
		<constructor-arg value="receive" />
	</bean>

	<jaxws:endpoint id="forTest1"
		implementor="com.ydfw.cb.ScSbjYdjkForYDZXImpl"
		address="/services/forTest1">

	</jaxws:endpoint>

	<jaxws:server id="scSbjYdjk"
		serviceClass="com.ydfw.dzservice.ScSbjYdjkForYDZX"
		address="/services/scSbjYdjkForYDZX">
		
		<jaxws:inInterceptors>
			<ref bean="inMessageInterceptor" />
		</jaxws:inInterceptors>
		
		<jaxws:serviceBean>
			<bean class="com.ydfw.cb.ScSbjYdjkForYDZXImpl" />
		</jaxws:serviceBean>
	</jaxws:server>
</beans>


简单解释一下:
	<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" />

这一段是加载cxf的一些配置,必须有。

<bean id="inMessageInterceptor"
		class="com.ydfw.pub.MessageInterceptor">
		<constructor-arg value="receive" />
	</bean>

此处定义了一个拦截器(具体问度娘,本人也是一知半解),当对方调用本应用时,用来过滤SOAPHeader中的信息,可参见后面的Java代码。


	<jaxws:server id="scSbjYdjk"
		serviceClass="com.ydfw.dzservice.ScSbjYdjkForYDZX"
		address="/services/scSbjYdjkForYDZX">
		
		<jaxws:inInterceptors>
			<ref bean="inMessageInterceptor" />
		</jaxws:inInterceptors>
		
		<jaxws:serviceBean>
			<bean class="com.ydfw.cb.ScSbjYdjkForYDZXImpl" />
		</jaxws:serviceBean>
	</jaxws:server>

此处定义了一个服务,明确了其接收请求的拦截器(id="inMessageInterceptor"的bean)、提供服务的类(com.ydfw.cb.ScSbjYdjkForYDZXImpl)、服务调用地址url(/services/scSbjYdjkForYDZX)

5. 服务类的写法,服务类是指接收其他 webservice 调用请求的类,该类需要配置在applicationContext-server.xml中,即com.ydfw.cb.ScSbjYdjkForYDZXImpl及其接口 com.ydfw.dzservice.ScSbjYdjkForYDZX
首先是接口 com.ydfw.dzservice.ScSbjYdjkForYDZX,如下:
import java.io.UnsupportedEncodingException;

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

@WebService(targetNamespace="http://dzservice.ydfw.com")
@SOAPBinding(style = SOAPBinding.Style.RPC)
public interface ScSbjYdjkForYDZX{

	@WebMethod(operationName = "scsydzxCall")
	public byte[] scsydzxCall(@WebParam(name = "inputData")
	byte[] inputByte) throws UnsupportedEncodingException;
}


实现类 com.ydfw.cb.ScSbjYdjkForYDZXImpl 的代码:
import java.io.BufferedOutputStream;
import java.io.BufferedReader;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.UnsupportedEncodingException;
import java.net.HttpURLConnection;
import java.net.URL;

import javax.annotation.Resource;
import javax.jws.WebParam;
import javax.jws.WebService;
import javax.jws.soap.SOAPBinding;
import javax.servlet.http.HttpServletRequest;
import javax.xml.ws.WebServiceContext;
import javax.xml.ws.handler.MessageContext;

import org.apache.cxf.transport.http.AbstractHTTPDestination;
import org.dom4j.Document;
import org.dom4j.DocumentHelper;
import org.dom4j.Element;

import com.dw.pojo.RemoteObj;
import com.util.LogUtil;
import com.ydfw.dzservice.ScSbjYdjkForYDZX;
import com.ydfw.pub.MessageGZIP;
import com.ydfw.pub.Names;

@SOAPBinding(style = SOAPBinding.Style.RPC)
@WebService(endpointInterface = "com.ydfw.dzservice.ScSbjYdjkForYDZX")
public class ScSbjYdjkForYDZXImpl implements ScSbjYdjkForYDZX{

	@Resource
	private WebServiceContext wsContext;

	@Override
	public byte[] scsydzxCall(@WebParam(name = "inputData")
	byte[] inputByte) throws UnsupportedEncodingException {
		StringBuffer logBF = new StringBuffer();
		MessageContext mc = wsContext.getMessageContext();
		HttpServletRequest request = (HttpServletRequest) mc.get(AbstractHTTPDestination.HTTP_REQUEST);
		RemoteObj ro = (RemoteObj) request.getAttribute("RemoteObjForCbd");
		if (ro == null) {
			throw new RuntimeException("参保地解析xml出错,没有获取到正确的Soap Head信息!");
		}
		String jybh = ro.getJybh();
		String jylsh = ro.getJylsh();
		String username = ro.getUsername();
		String password = ro.getPassword();
		String jyyzm = ro.getJyyzm();
<<方法体代码略去>>
		return MessageGZIP.compressToByte(returnXML, "utf-8");
	}


由于代码较多且涉及到公司业务相关代码,此处将方法体略去。解释一下该方法中几个对象变量:
1) RemoteObj,自定义对象,将SoapHeader中的相应变量作为该类的属性,并提供setter和getter方法,在拦截器类中初始化该类的值,并放将其放到 request的 RemoteObjForCbd 中;
2) wsContext,应该是cxf的内置对象,这里只需要定义为类变量,由cxf框架负责初始化。在服务方法里直接使用即可;
3) MessageGZIP 该类是第三方厂商提供的压缩类。

6. 拦截器类:com.ydfw.pub.MessageInterceptor
作用是将Webservice的Soap请求中的存储在 SoapHeader 中的变量取出来并放到RemoteObj对象中,供服务方法使用,代码如下:

import java.io.UnsupportedEncodingException;
import java.util.List;

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

import org.apache.cxf.binding.soap.SoapHeader;
import org.apache.cxf.binding.soap.SoapMessage;
import org.apache.cxf.headers.Header;
import org.apache.cxf.interceptor.Fault;
import org.apache.cxf.phase.AbstractPhaseInterceptor;
import org.apache.cxf.phase.Phase;
import org.apache.cxf.transport.http.AbstractHTTPDestination;
import org.w3c.dom.Element;
import org.w3c.dom.NodeList;

import com.dw.pojo.RemoteObj;

/**
 * <b>function:</b> 自定义消息拦截器
 * 
 * @author hoojo
 * @createDate Mar 17, 2011 8:10:49 PM
 * @file MessageInterceptor.java
 * @package com.hoo.interceptor
 * @project CXFWebService
 * @blog http://blog.csdn.net/IBM_hoojo
 * @email hoojo_@126.com
 * @version 1.0
 */
public class MessageInterceptor extends AbstractPhaseInterceptor<SoapMessage>{

	// 至少要一个带参的构造函数
	public MessageInterceptor() {
		super(Phase.PRE_INVOKE);
		System.out.println("no para");
	}

	public MessageInterceptor(String phase) {
		super(Phase.PRE_INVOKE);
		System.out.println("phase:" + phase);
	}

	public void handleMessage(SoapMessage message) throws Fault {
		// 获取SOAP消息的全部头
		List<Header> headers = message.getHeaders();
		if (null == headers || headers.size() < 1) {
			throw new Fault(new SOAPException("SOAP消息头格式不对哦!"));
		}
		SoapHeader soapHeader = (SoapHeader) headers.get(0);
		Element element = (Element) soapHeader.getObject();
		NodeList userIdNodes = element.getElementsByTagName("userName");
		NodeList pwdNodes = element.getElementsByTagName("passWord");

		// 读取自定义的节点

		String username = userIdNodes.item(0).getTextContent();
		String password = pwdNodes.item(0).getTextContent();
		String jylsh = element.getElementsByTagName("jylsh")
			.item(0)
			.getTextContent();
		String jybh = element.getElementsByTagName("jybh")
			.item(0)
			.getTextContent();
		String jyyzm = element.getElementsByTagName("jyyzm")
			.item(0)
			.getTextContent();
		// rsa解密
		try {
			username = new String(RsaUtil.pubDecrypt(username, GetSptPublicKey.getInstance()), "utf-8");
			password = new String(RsaUtil.pubDecrypt(password, GetSptPublicKey.getInstance()), "utf-8");
		} catch (UnsupportedEncodingException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
			return;
		}
		// 去掉交易流水号
		username = username.replaceFirst(jylsh, "");
		password = password.replaceFirst(jylsh, "");

		HttpServletRequest request = (HttpServletRequest) message.get(AbstractHTTPDestination.HTTP_REQUEST);// 这句可以获取到request

		RemoteObj ro = new RemoteObj(username, password, jybh, jyyzm, jylsh);
		request.setAttribute("RemoteObjForCbd", ro);
	}
}


关于消息拦截器,建议参考Spring或者是CXF的官方文档。

8. 上面叙述的是作为被调用方的程序写法,下面是作为调用方的写法(只列出import部分和方法体代码):

import java.io.BufferedReader;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.URL;

import org.dom4j.Document;
import org.dom4j.DocumentHelper;
import org.dom4j.Element;

import com.dareway.framework.util.DataObject;
import com.dareway.framework.workFlow.BPOSupport;
import com.util.LogUtilJyd;
import com.ydfw.pub.MessageGZIP;
import com.ydfw.pub.Names;

public DataObject requestService(DataObject para) throws Exception {
		DataObject vdo = new DataObject();
		StringBuffer logBF = new StringBuffer();
		// 接收业务系统传参
		// 交易流水号
		String jylsh = para.getString("jylsh", "");
		String jyyzm = para.getString("jyyzm", "");
		// 交易编号
		String jybh = para.getString("jybh", "");
		// xml参数
		String str_xml = para.getString("str_xml", "");

	org.apache.cxf.jaxws.endpoint.dynamic.JaxWsDynamicClientFactory dcf = org.apache.cxf.jaxws.endpoint.dynamic.JaxWsDynamicClientFactory.newInstance();
		org.apache.cxf.endpoint.Client client = dcf.createClient(Names.SPT_SERVICEADDRESS);//  
		client.getOutInterceptors().clear();
		client.getOutInterceptors()
			.add(new CallSptYdZxAddSoapHeader(Names.SPT_NAMESPACE, Names.SPT_USERNAME, Names.SPT_PASSWORD, jyyzm, jylsh, jybh));
		// 设置输入字符串
		byte[] xmlzip = MessageGZIP.compressToByte(str_xml, "utf-8");
		// 调用服务
		Object[] objects = client.invoke(Names.SPT_SERVICENAME, new Object[] { xmlzip });
		// 获取返回字符串
		String result = MessageGZIP.uncompressToString((byte[]) objects[0], "UTF-8");
		vdo.put("returnXML", result);
		return vdo;
	}



解释几个变量及常量:
1)Names.SPT_SERVICEADDRESS ,对方webservice的地址,格式如下:
http://IP:PORT/webproject/services/scydzxServer?wsdl

IP 和 PORT分别指 IP地址 和 端口

2)Names.SPT_NAMESPACE 命名空间,输入上面的地址看到的targetName

3)Names.SPT_USERNAME 和 Names.SPT_PASSWORD,调用对方需要验证的用户名和密码。可参看前面作为被调用方的消息拦截器中,会取到这两个密码,在服务方法中可进行校验。
4)CallSptYdZxAddSoapHeader 该类用于添加SOAPHeader信息,代码如下:
public class CallSptYdZxAddSoapHeader extends AbstractSoapInterceptor{
	private String nameURI;
	private String userName;
	private String passWord;
	private String jyyzm;
	private String jylsh;
	private String jybh;

	public CallSptYdZxAddSoapHeader() {
		super(Phase.WRITE);
	}

	public CallSptYdZxAddSoapHeader(String nameURI, String userName,
		String passWord, String jyyzm, String jylsh, String jybh) {
		super(Phase.WRITE);
		this.nameURI = nameURI;
		this.userName = userName;
		this.passWord = passWord;
		this.jyyzm = jyyzm;
		this.jylsh = jylsh;
		this.jybh = jybh;
	}

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

		QName qname = new QName("RequestSOAPHeader");
		Document doc = DOMUtils.createDocument();

		// 用户名
		Element el_username = doc.createElement("userName");

		// 密码
		Element el_password = doc.createElement("passWord");
		try {
			el_username.setTextContent(RsaUtil.pubEncrypt((jylsh + userName).getBytes("utf-8"), GetSptPublicKey.getInstance()));
			el_password.setTextContent(RsaUtil.pubEncrypt((jylsh + passWord).getBytes("utf-8"), GetSptPublicKey.getInstance()));
		} catch (DOMException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
			return;

		} catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
			return;
		}
		Element el_jylsh = doc.createElement("jylsh");
		el_jylsh.setTextContent(jylsh);
		Element el_jyyzm = doc.createElement("jyyzm");
		el_jyyzm.setTextContent(jyyzm);

		Element el_jybh = doc.createElement("jybh");
		el_jybh.setTextContent(jybh);

		Element root = doc.createElementNS(nameURI, "in:system");
		root.appendChild(el_username);
		root.appendChild(el_password);
		root.appendChild(el_jylsh);
		root.appendChild(el_jyyzm);
		root.appendChild(el_jybh);

		SoapHeader head = new SoapHeader(qname, root);
		List<Header> headers = message.getHeaders();
		headers.add(head);
	}

}



9. 该项目与业务系统通过Servlet的通信简介:
调用业务系统代码如下:
public DataObject requestService(DataObject para) throws Exception {
		DataObject vdo = new DataObject();
		try {
			String urlS = "http://10.160.32.239:9090/dzydfw/servlet/ServiceForJYDServlet";
						HttpURLConnection urlConnection = null;
			URL url = new URL(urlS);
			urlConnection = (HttpURLConnection) url.openConnection();

			urlConnection.setRequestMethod("POST");
			urlConnection.setRequestProperty("Content-Type", "text/xml;charset=GBK");
			urlConnection.setRequestProperty("Charset", "GBK");
			urlConnection.setDoOutput(true);
			urlConnection.setDoInput(true);
			urlConnection.setUseCaches(false);
			urlConnection.setConnectTimeout(20000);
			StringBuffer param = new StringBuffer();
			param.append(genXML(para.getString("jylsh"), para.getString("jybh"), para.getString("jyyzm"), para.getString("username"), para.getString("password"), para.getString("inputxml")));
			BufferedOutputStream outStream = new BufferedOutputStream(urlConnection.getOutputStream());
			outStream.write(param.toString().getBytes());
			outStream.flush();
			outStream.close();
			InputStream in = urlConnection.getInputStream();
	
			BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(in));
			StringBuffer temp = new StringBuffer();
			String line = bufferedReader.readLine();
			while (line != null) {
				temp.append(line);
				line = bufferedReader.readLine();
			}
			bufferedReader.close();
			in.close();
			urlConnection.disconnect();
			vdo.put("returnXML", temp.toString());
			return vdo;
		} catch (Exception e) {
			e.printStackTrace();

		}
	}


这里特别注意,
BufferedOutputStream outStream = new BufferedOutputStream(urlConnection.getOutputStream());
			outStream.write(param.toString().getBytes());
			outStream.flush();
			outStream.close();

不能写成


urlConnection.getOutputStream().write(param.toString().getBytes());
urlConnection.getOutputStream().flush();
urlConnection.getOutputStream().close();

这种方式在tomcat下没问题,但是在weblogic中无法将字节流写到servlet中。

因为需要传递xml,采用字节流的方式写到servlet中,接收方代码如下:
方法doPost中,


	BufferedReader curReader;
		curReader = request.getReader();

		String strtmp = curReader.readLine();
		for (; strtmp != null; strtmp = curReader.readLine()) {
			sb.append(strtmp);
		}
		curReader.close();




其他说明:
平时工作中webservice用的不是特别多,本人也是新接触,为了某个项目而突击找资料学习的,多有不足之处;
由于项目中使用了某公司提供的部分代码,不便于将程序包(war)放到附件中,如有需要的可给我发邮件,邮箱为 jackeysion@126.com。
再就是有一个问题还未解决,用cxf创建的项目在tomcat下可以正常运行,但是部署到weblogic上貌似会提示jar包冲突,问度娘没找到好的解决方案,如果大家有好的解决方案还望告知~
分享到:
评论

相关推荐

    CXF方式开发和部署webservice应用

    CXF方式开发和部署webservice应用,CXF方式开发和部署webservice应用,CXF方式开发和部署webservice应用,CXF方式开发和部署webservice应用,

    cxf开发的WebService实例

    实例分为两个工程,分别是web service的服务端和客户端。 实例采用cxf和spring的结合来实现web service的应用,经过测试可用,其中服务端经过测试可以用axis2的web service客户端访问。

    cxf+spring=webservice CXF 应用开发

    NULL 博文链接:https://showlike.iteye.com/blog/1005822

    WebService之CXF开发指南

    一、Web Services、SOA简介。 二、CXF简介。...5、CXF应用开发。 【a、创建项目骨架。 b、接口类创建。 c、具体类实现。 d、spring配置。 e、web应用配置。 f、应用部署。 g、启动服务。 h、消费服务。】

    基于Apache CXF构建SOA应用 随书源代码

    Apache CXF是一个开放源码的Web服务框架,提供了一个易于使用,用于开发Web Services标准为基础的编程模型。本书主要介绍Apache CXF在构建SOA架构各个方面的应用说明和编程案例。覆盖以下内容:基于JAX-WS规范和CXF...

    CXF框架应用在Web项目中

    基于CXF的webservice开发 1、服务器端 Ⅰ)开发web service业务接口,该接口用@WebService修饰; Ⅱ)开发web service业务接口的实现类,也要用@WebService修饰; Ⅲ)使用EndPoint类的静态方法publish()来发布...

    cxf-2.6.11.jar及其关联jar包

    应用cxf开发webservice应用所需要的相关jar包,不同的cxf版本对应的wss4j.jar,neethi.jar,woodstox-core-xx.jar,xmlschema-core-xx.jar版本都不相同,匹配错误的话开发过程中会报错。

    WebService CXF、 Mybatis简单实例

    WebService CXF同步通信接口编程和Mybatis , Spring 的简单应用。值得初学者和开发中用到的同学借鉴。

    java webservice实例教程PPT

    java webservice实例教程适合于各个层次的Java开发人员,对于初级程序员来说,可以在短时间掌握webService技术,熟练CXF框架应用,能马上应用于实际工作。对于中高级程序员来说,java webservice实例教程突破思想...

    apache-cxf-3.2.1.zip

    Apache CXF是一个开源的Service框架,可以用于简化用户的service开发,基于CXF开发的应用可提供SOAP、XML/HTTP、RESTFUL HTTP或CORBA等服务。CXF底层页可以使用不同的传输协议,包括HTTP、JMS或JBI等。

    WebService 7本书

    主要是webservice系列的电子书,AJAX CXF RESTFUL与ws的相关配合应用知识或书籍

    Java6开发WebService入门

    之前常常用CXF、Axis2、XFire等来开发结合Java语言来...但实际上Java6中已经支持用Java开发WebService应用了,而且很方便。这样就大大减少了项目安装部署的代价,因为选择开源的框架依赖大量第三方包,程序的尺寸倍增。

    Cxf+Spring集成案例代码

    Spring是目前最流行的JavaEE Framework,但是使用Spring的Spring-WS开发WebService却十分繁琐。CXF是一个简化WebService开发的开源项目,通过Spring和CXF的结合可以大大简化基于Spring Framework的应用中的...

    Web_Service开发指南电子版 PDF

    WebSevice 让一个程序可以透明地调用互联网程序,不用管具体的实现细节。只要WebService公开了服务接口,远程客户端就可以调用服务。...在Java领域 WebService常见的框架 Axis、XFire、CXF......。其中成熟实现的是AXIS。

    疯狂软件李刚WebService视频教程(15集)

    资源名称:疯狂软件李刚WebService视频教程(15集)资源目录:【】01.WebService概述和WebService在企业应用中的作用【】02.CXF功能概述_CXF发展历史和使用CXF开发WebService服务器端【】03.使用CXF开发WebService...

    android调用web service(cxf)实例应用详解

    Google为ndroid平台开发Web Service提供了支持,提供了Ksoap2-android相关架包接下来介绍android调用web service(cxf),感兴趣的朋友可以了解下

    webservice开发文档

    webservice 开发文档详解; CXF实现WebService; 很多情况下,我们并不希望我们的webservice和我们的应用分开两个服务器,而希望他们在同一个容器,tomcat或JBOSS或其他的,这样我们就必须通过WEB来部署我们前面完成...

    JAVA的WebService支持.rar

    JAVA的WebService支持.rar,详细介绍了cxf、axis、wsdl、soap等原理及应用开发!

    基于Spring MVC、CXF和Hibernate的Web服务与数据库操作设计源码

    本源码提供了一个基于Spring MVC、CXF和Hibernate的Web服务与数据库操作设计。...这个系统通过Web服务技术(webservice)实现了对数据库数据的增删查操作,适合需要进行远程数据访问和操作的应用场景。

    浪曦航母战斗编队式企业级项目培训系列明细

    浪曦航母战斗编队式企业级项目培训系列明细 JAVA,JSP/Servlet基础 Struts2 ...Mule Esb发布基于CXF,Axis的WebService, Extjs3.2与Html/css/js整合打造不规则九宫格效果 JBPM4.4开发销售工作流

Global site tag (gtag.js) - Google Analytics