最近工作中需要做产品之间的对接工作,作为服务器端对外开放服务接口,而本次所采用的是webservice开放接口。在选择使用何种技术开放接口,曾考虑使用http开放接口,最终选择webservice原因有:1、此接口非网络公开接口,只适用于本次产品对接。2、webservice接口稳定且支持跨域,使用http还要考虑跨域的问题。3、webservice支持复杂类型的数据传输。基于此,选用webservice开放接口。
考虑到简化webservice开发过程,在开发中并未对每个功能开放webservice接口,而是依赖于接口文档,开放统一的webservice接口,用业务编号区分不同的接口,统一调用。以下是开发过程:
1、导入依赖包(cxf)
<apache.cxf.version>3.1.10</apache.cxf.version>
<dependency>
<groupId>org.apache.cxf</groupId>
<artifactId>cxf-rt-frontend-jaxws</artifactId>
<version>${apache.cxf.version}</version>
</dependency>
<dependency>
<groupId>org.apache.cxf</groupId>
<artifactId>cxf-rt-transports-http</artifactId>
<version>${apache.cxf.version}</version>
</dependency>
2、配置服务(web.xml)
<!-- cxf -->
<servlet>
<servlet-name>CXFServlet</servlet-name>
<servlet-class>org.apache.cxf.transport.servlet.CXFServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>CXFServlet</servlet-name>
<url-pattern>/webservice/*</url-pattern>
</servlet-mapping>
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:p="http://www.springframework.org/schema/p"
xmlns:aop="http://www.springframework.org/schema/aop" xmlns:context="http://www.springframework.org/schema/context"
xmlns:jee="http://www.springframework.org/schema/jee" xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:jaxws="http://cxf.apache.org/jaxws"
xsi:schemaLocation="
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/jee http://www.springframework.org/schema/jee/spring-jee.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd
http://cxf.apache.org/jaxws http://cxf.apache.org/schemas/jaxws.xsd"
default-autowire="byName"> <!-- spring自动扫包 -->
<context:component-scan base-package="com.my.webservice" />
<bean id="myWebServiceExcuteUtil"
class="com.my.webservice.utils.MyWebServiceExcuteUtil"
init-method="init" lazy-init="default"></bean>
<bean id="MyWebService"
class="com.my.webservice.impl.MyWebServiceImpl">
</bean>
<!-- 导入jar包中的cxf配置文件。这里不用写,是写好的放在jar包里,直接引入即可。 -->
<import resource="classpath:META-INF/cxf/cxf.xml" />
<import resource="classpath:META-INF/cxf/cxf-servlet.xml" />
<!-- define web service provider -->
<!-- 要暴露给外部调用的接口,address:请求路径 -->
<jaxws:endpoint
implementor="com.my.webservice.impl.TestWebServiceImpl"
address="/testWebServiceImpl" />
<jaxws:endpoint
implementor="com.my.webservice.impl.MyWebServiceImpl"
address="/myWebServiceImpl" />
</beans>
4、编写webservice接口及实现类
/**
* $Id:$
* Copyright 2014-2018 Hebei Sinounited Technology Company Ltd. All rights reserved.
*/
package com.my.webservice;
import javax.jws.WebParam;
import javax.jws.WebService;
/**
*
* @author Heller.Zhang
* @since 2018年11月1日 下午5:30:02
*/
@WebService(targetNamespace = "com.my.webservice.TestWebService")
public interface TestWebService {
public String test(@WebParam(name = "type") Integer type, @WebParam(name = "data") String data);
}
/**
* $Id:$
* Copyright 2014-2018 Hebei Sinounited Technology Company Ltd. All rights reserved.
*/
package com.my.webservice.impl;
import javax.jws.WebService;
import org.springframework.stereotype.Component;
import com.my.webservice.TestWebService;
/**
*
* @author Heller.Zhang
* @since 2018年11月1日 下午5:12:08
*/
@WebService(targetNamespace="com.my.webservice.TestWebService",endpointInterface="com.my.webservice.TestWebService")
@Component("TestWebService")
public class TestWebServiceImpl implements TestWebService {
@Autowired
private MyWebServiceExcuteUtil myWebServiceExcuteUtil;
@Override
public String test(Integer type, String data) {
return myWebServiceExcuteUtil.excute(type, data);
}
}
/**
* $Id:$
* Copyright 2014-2018 Hebei Sinounited Technology Company Ltd. All rights reserved.
*/
package com.my.webservice.utils;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Map;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import com.my.webservice.contant.GpWebServiceEnum;
import com.my.webservice.model.MyWebServiceModel;
import com.my.framework.common.spring.utils.SpringContextUtils;
import com.my.framework.exception.DaoException;
import com.my.framework.exception.ManagerException;
import com.my.framework.exception.ServiceException;
import com.my.framework.model.ResultDTO;
import com.my.framework.util.JsonHelper;
/**
* webservice调用统一工具类
*
* @author Heller.Zhang
* @since 2018年11月2日 上午9:30:04
*/
public class MyWebServiceExcuteUtil {
Logger logger = LoggerFactory.getLogger(MyWebServiceExcuteUtil .class);
Map<Integer, MyWebServiceModel> map = new HashMap<Integer, MyWebServiceModel>();
/**
* 初始化
*
* @author Heller.Zhang
* @since 2018年11月2日 下午12:48:07
*/
public void init() {
logger.debug("-------------init MyWebServiceExcuteUtil-----------------");
for (MyWebServiceEnume : MyWebServiceEnum.values()) {
MyWebServiceModelmodel = new MyWebServiceModel();
model.setType(e.getType());
Object bean = SpringContextUtils.getBean(e.getBean());
model.setBean(bean);
Class<?> dataType = null;
try {
dataType = Class.forName(e.getDataType());
model.setDataClass(dataType);
} catch (ClassNotFoundException e1) {
throw new RuntimeException("未找到【" + e.getDataType() + "】实体类!", e1);
}
Method method = BeanUtils.findMethod(bean.getClass(), e.getMethod(),
new Class[] { dataType});
model.setMethod(method);
map.put(e.getType(), model);
}
}
/**
* webservice接口调用
*
* @param type 业务类型
* @param data 数据
* @return
* @author Heller.Zhang
* @since 2018年11月2日 上午9:32:52
*/
public String excute(Integer type, String data) {
// 获取到webservice配置信息
MyWebServiceModel model = map.get(type);
if (model == null) {
ResultDTO<Object> faildResult = new ResultDTO<Object>();
faildResult.setSuccess(false);
faildResult.setMsg("错误的业务编号!");
return JsonHelper.serialize(faildResult);
}
// 将data转换为相应类型的数据
Object dataObj = JsonHelper.readValueCustom(data, model.getDataClass());
// 调用方法
try {
Object result = model.getMethod().invoke(model.getBean(), dataObj);
return JsonHelper.serialize(result);
} catch (ServiceException | ManagerException | DaoException e) {
logger.error(e.getMessage(), e);
ResultDTO<Object> faildResult = new ResultDTO<Object>();
faildResult.setSuccess(false);
faildResult.setMsg(e.getMessage());
return JsonHelper.serialize(faildResult);
} catch (Exception e1) {
logger.error("调用webservice接口失败!", e1);
ResultDTO<Object> faildResult = new ResultDTO<Object>();
faildResult.setSuccess(false);
faildResult.setMsg("调用webservice接口失败!");
return JsonHelper.serialize(faildResult);
}
}
}
/**
* $Id:$
* Copyright 2014-2018 Hebei Sinounited Technology Company Ltd. All rights reserved.
*/
package com.my.webservice.contant;
/**
* 业务及实现对应枚举
*
* @author Heller.Zhang
* @since 2018年11月2日 上午9:34:51
*/
public enum MyWebServiceEnum {
SERVICE1(0, "*****Impl", "******",
"com.my.qo.******"),// NL,因涉及业务,故以*代替具体配置
;
/** 业务编号 */
private Integer type;
/** 业务实现类(必须是业务模块的service bean名称) */
private String bean;
/** 业务实现方法名称 */
private String method;
/** 接收数据类型(全称) */
private String dataType;
MyWebServiceEnum(Integer type, String bean, String method, String dataType) {
this.type = type;
this.bean = bean;
this.method = method;
this.dataType = dataType;
}
/**
* @return the type
*/
public Integer getType() {
return type;
}
/**
* @param type the type to set
*/
public void setType(Integer type) {
this.type = type;
}
/**
* @return the bean
*/
public String getBean() {
return bean;
}
/**
* @param bean the bean to set
*/
public void setBean(String bean) {
this.bean = bean;
}
/**
* @return the method
*/
public String getMethod() {
return method;
}
/**
* @param method the method to set
*/
public void setMethod(String method) {
this.method = method;
}
/**
* @return the dataType
*/
public String getDataType() {
return dataType;
}
/**
* @param dataType the dataType to set
*/
public void setDataType(String dataType) {
this.dataType = dataType;
}
public static MyWebServiceEnum of(Integer type) {
for (MyWebServiceEnum e : MyWebServiceEnum .values()) {
if (e.getType().equals(type)) {
return e;
}
}
return null;
}
}
以上,便将webservice配置完成并与springMVC相结合,在定义业务实现时,需要遵循一定的规则(因为依赖于接口文档,所以需要一定的开发规则),如:入参类型、出参类型、解析方式等。上述例子中对外接口使用业务编号的方式指定不同的业务接口调用,数据传输使用json格式字符串进行序列化和反序列化。webservice接口使用统一接口。
webservice地址可以配置多个,同时每一个webservice地址下可以有多个webservice接口,本例只提供了一个接口test,以上接口结构适合于接口参数、返回数据的格式一致且接口数量较多的情况,依赖于webservice接口文档用以对接,所以对文档的严谨和准确性要求较高。如果接口量不多,或者接口参数、返回数据的格式大多不一致的情况下,可使用开放多接口的形式,在webservice实现类中直接调用业务实现方法,做到一个webservice接口对应一个业务方法的结构。
结语:webservice是对外开放服务接口的一种方式,在技术选型、模式选型时没必要生搬硬套,适合项目的才是最好的。