??
因此好的WebService接口,应该从下面几个方面仔细考虑:
一. 参数
(1) 参数应该直接使用简单的数据类型(POCO、POJO),甚至时间类型都可以考虑用string,只要双方约束好时间字符串的格式。
(2) 如果参数个数超过3个,那就需要考虑设计一个Class了,避免参数列表过长,当然这没有硬性规定。
(3) 设计统一的参数规则。比如对外提供的查询接口就要考虑分页相关的数据。保证类似的接口都有统一的参数定义,形成习惯是提升效率最好方式。
? ? ? 业务参数和非业务参数应该分开,比如分页的数据就可以抽象出基类。
二. 异常
(1) 使用框架中定义的Exception类型,比如:SoapException,FaultException(WCF)。
(2) 尽量避免将异常定义在返回值中,通过返回值定义错误那么无论服务端还是客户端都要写很多if ... else 分支。
(3) 系统异常和业务异常要区分好,比如使用 SoapException 可以用 Code 来区分,比如:System.Error 表示系统错误,Bussiness.Error 表示业务错误。
(4) 补充:.net framework ?如果没有包装那么默认有两种 fautCode: ?soap:Client 和 soap:Server。假设客户端传入BadRequest 基本就是 soap:Client 错误,其他?没有自定义code的则就是 soap:Server 的错误。
三. 安全
无论何时都要保证系统的安全性,我觉得安全也分系统安全和业务安全两种:
(1) 系统安全主要是指客户端的认证授权,调用次数(需要考虑会不会拖垮业务系统) 等
(2) 业务安全主要是指数据查询/操作权限,当然这个主要是从业务角度考虑的。
四. 日志
日志可以方便排查错误,还可以通过日志来分析服务基本信息(比如:调用次数,失败次数等),必要时还可以通过日志来进行重试。
另外要考虑开发的便捷,设计统一的日志拦截处理。
以 WebService Application (.NET 3.5) 为例,记录几种常用的编程技巧。
原始的 WebService 如下:
- using?System;??
- using?System.Collections.Generic;??
- using?System.Linq;??
- using?System.Web;??
- using?System.Web.Services;??
- using?WebService1.Entity;??
- using?WebService1.Service;??
- using?System.Web.Services.Protocols;??
- ??
- namespace?WebService1??
- {??
- ????[WebService(Namespace?=?"http://tempuri.org/")]??
- ????[WebServiceBinding(ConformsTo?=?WsiProfiles.BasicProfile1_1)]??
- ????[System.ComponentModel.ToolboxItem(false)]??
- ????public?class?Service1?:?System.Web.Services.WebService??
- ????{??
- ????????[WebMethod]?????????
- ????????public?PageResult<Order>?QueryOrder(Query<OrderCondition>?queryInfo)??
- ????????{??
- ????????????OrderService?service?=?new?OrderService();??
- ????????????return?service.Query(queryInfo);??
- ????????}??
- ????}??
- }??
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Services;
using WebService1.Entity;
using WebService1.Service;
using System.Web.Services.Protocols;
namespace WebService1
{
[WebService(Namespace = "http://tempuri.org/")]
[WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)]
[System.ComponentModel.ToolboxItem(false)]
public class Service1 : System.Web.Services.WebService
{
[WebMethod]
public PageResult<Order> QueryOrder(Query<OrderCondition> queryInfo)
{
OrderService service = new OrderService();
return service.Query(queryInfo);
}
}
}
PageResult<T>,Query<T> ?将统一的业务部分抽取出来,这样定义其他的业务对象就能简化了。
- using?System;??
- using?System.Collections.Generic;??
- ??
- namespace?WebService1.Entity??
- {??
- ????[Serializable]??
- ????public?class?PageResult<T>??
- ????{??
- ????????public?int?PageNo?{?get;?set;?}??
- ????????public?int?PageSize?{?get;?set;?}??
- ????????public?int?TotalCount?{?get;?set;?}??
- ????????public?int?PageCount?{?get;?set;?}??
- ????????public?bool?HasNextPage?{?get;?set;?}??
- ????????public?List<T>?Data?{?get;?set;?}??
- ????}??
- }??
using System;
using System.Collections.Generic;
namespace WebService1.Entity
{
[Serializable]
public class PageResult<T>
{
public int PageNo { get; set; }
public int PageSize { get; set; }
public int TotalCount { get; set; }
public int PageCount { get; set; }
public bool HasNextPage { get; set; }
public List<T> Data { get; set; }
}
}
- using?System;??
- using?System.Collections.Generic;??
- ??
- namespace?WebService1.Entity??
- {??
- ????[Serializable]??
- ????public?class?Query<T>??
- ????{??
- ????????public?int?PageNo?{?get;?set;?}??
- ????????public?int?PageSize?{?get;?set;?}??
- ????????public?T?Condition?{?get;?set;?}??
- ????}??
- }??
using System;
using System.Collections.Generic;
namespace WebService1.Entity
{
[Serializable]
public class Query<T>
{
public int PageNo { get; set; }
public int PageSize { get; set; }
public T Condition { get; set; }
}
}
跳过业务处理部分,来关注一下应用框架考虑的日志和安全拦截。可以利用 .NET framework 的 Soap Extensions (
msdn) ?很容易地实现对 WebMethod 的 AOP。
Soap Extensions 可以通过两种方式“注入”: 自定义Atrribute 或者通过 Web.config 里的?soapExtensionTypes 进行声明。
TraceExtension 的实现:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.IO;
using System.Web.Services.Protocols;
using log4net;
using System.Xml;
namespace WebService1.Common
{
public class TraceExtension : SoapExtension
{
private ILog logger = LogManager.GetLogger(typeof(TraceExtension));
Stream oldStream;
Stream newStream;
public override System.IO.Stream ChainStream(System.IO.Stream stream)
{
oldStream = stream;
newStream = new MemoryStream();
return newStream;
}
public override void ProcessMessage(SoapMessage message)
{
switch (message.Stage)
{
case SoapMessageStage.BeforeDeserialize:
log4net.ThreadContext.Properties["ip"] = HttpContext.Current.Request.UserHostAddress;
log4net.ThreadContext.Properties["action"] = message.Action;
WriteInput(message);
break;
case SoapMessageStage.AfterDeserialize:
break;
case SoapMessageStage.BeforeSerialize:
break;
case SoapMessageStage.AfterSerialize:
WriteOutput(message);
break;
default:
throw new Exception("Invalid Stage");
}
}
public override object GetInitializer(Type serviceType)
{
return null;
}
public override object GetInitializer(LogicalMethodInfo methodInfo,SoapExtensionAttribute attr)
{
return null;
}
public override void Initialize(object initializer)
{
//filename = (string)initializer;
}
public void WriteOutput(SoapMessage message)
{
string soapString = (message is SoapServerMessage) ? "SoapResponse" : "SoapRequest";
string content = GetContent(newStream);
// 为了Format XML,如果从性能考虑应该去掉此处的处理
if (!string.IsNullOrEmpty(content))
{
XmlDocument xmlDoc = new XmlDocument();
xmlDoc.LoadXml(content);
using (StringWriter sw = new StringWriter())
{
using (XmlTextWriter xtw = new XmlTextWriter(sw))
{
xtw.Formatting = Formatting.Indented;
xmlDoc.WriteTo(xtw);
content = sw.ToString();
}
}
}
logger.Info(soapString + ":n" + content);
Copy(newStream,oldStream);
}
public void WriteInput(SoapMessage message)
{
Copy(oldStream,newStream);
string soapString = (message is SoapServerMessage) ? "SoapRequest" : "SoapResponse";
string content = GetContent(newStream);
logger.Info(soapString + ":n" + content);
}
void Copy(Stream from,Stream to)
{
TextReader reader = new StreamReader(from);
TextWriter writer = new StreamWriter(to);
writer.WriteLine(reader.ReadToEnd());
writer.Flush();
}
string GetContent(Stream stream)
{
stream.Position = 0;
TextReader reader = new StreamReader(stream);
string content = reader.ReadToEnd();
stream.Position = 0;
return content;
}
}
}
TraceAttribute 实现如下:
- using?System;??
- using?System.Web.Services.Protocols;??
- ??
- namespace?WebService1.Common??
- {??
- ????[AttributeUsage(AttributeTargets.Method)]??
- ????public?class?TraceAttribute?:?SoapExtensionAttribute??
- ????{??
- ????????private?int?priority?=?0;??
- ????????public?override?Type?ExtensionType??
- ????????{??
- ????????????get?{?return?typeof(TraceExtension);?}??
- ????????}??
- ??
- ????????public?override?int?Priority??
- ????????{??
- ????????????get?{?return?priority;?}??
- ????????????set?{?priority?=?value;?}??
- ????????}??
- ????}??
- }??
using System;
using System.Web.Services.Protocols;
namespace WebService1.Common
{
[AttributeUsage(AttributeTargets.Method)]
public class TraceAttribute : SoapExtensionAttribute
{
private int priority = 0;
public override Type ExtensionType
{
get { return typeof(TraceExtension); }
}
public override int Priority
{
get { return priority; }
set { priority = value; }
}
}
}
其中 TraceExtension 利用 log4net 来记录调用 WebMethod 的Request 和 Response,还包括 ip 和 Action(Action其实对应的 WebMethod)
对应的 log4net 配置如下:
- <log4net>??
- ????<appender?name="RollingFileAppender"?type="log4net.Appender.RollingFileAppender">??
- ????????<param?name="File"?value="F:ProgrammingVSProject2008WebServiceSampleWebService1WebService1Logsservice.log"/>??
- ???????????????????????<param?name="DatePattern"?value=".yyyy-MM-dd'.log'"?/>??
- ????????<param?name="AppendToFile"?value="true"/>??
- ????????<param?name="MaxSizeRollBackups"?value="10"/>??
- ????????<param?name="MaximumFileSize"?value="5MB"/>??
- ????????<param?name="RollingStyle"?value="Date"/>??
- ????????<param?name="StaticLogFileName"?value="false"/>??
- ????????<layout?type="log4net.Layout.PatternLayout">??
- ????????????<param?name="ConversionPattern"?value="%d?[%t]?%-5p?[%property{ip}]?[%property{action}]?-?%m%n"/>??
- ????????</layout>??
- ????</appender>??
- ????<root>??
- ????????<level?value="DEBUG"/>??
- ????????<appender-ref?ref="RollingFileAppender"/>??
- ????</root>??
- </log4net>??
<log4net>
<appender name="RollingFileAppender" type="log4net.Appender.RollingFileAppender">
<param name="File" value="F:ProgrammingVSProject2008WebServiceSampleWebService1WebService1Logsservice.log"/>
<param name="DatePattern" value=".yyyy-MM-dd'.log'" />
<param name="AppendToFile" value="true"/>
<param name="MaxSizeRollBackups" value="10"/>
<param name="MaximumFileSize" value="5MB"/>
<param name="RollingStyle" value="Date"/>
<param name="StaticLogFileName" value="false"/>
<layout type="log4net.Layout.PatternLayout">
<param name="ConversionPattern" value="%d [%t] %-5p [%property{ip}] [%property{action}] - %m%n"/>
</layout>
</appender>
<root>
<level value="DEBUG"/>
<appender-ref ref="RollingFileAppender"/>
</root>
</log4net>
那么 WebMethod 只要加上 [Trace] 特性,就可以开启日志记录功能。
- [WebMethod]??
- [Trace]??
- public?PageResult<Order>?QueryOrder(Query<OrderCondition>?queryInfo)??
- {??
- ????OrderService?service?=?new?OrderService();??
- ????return?service.Query(queryInfo);??
- }??
[WebMethod]
[Trace]
public PageResult<Order> QueryOrder(Query<OrderCondition> queryInfo)
{
OrderService service = new OrderService();
return service.Query(queryInfo);
}
输出日志如下:
- 2014-05-25?22:05:02,292?[8]?INFO??[127.0.0.1]?[http://tempuri.org/QueryOrder]?-?SoapRequest:??
- <soapenv:Envelope?xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/"?xmlns:tem="http://tempuri.org/">??
- ???<soapenv:Body>??
- ??????<tem:QueryOrder>??
- ???????????
- ?????????<tem:queryInfo>??
- ????????????<tem:PageNo>1</tem:PageNo>??
- ????????????<tem:PageSize>1</tem:PageSize>??
- ??????????????
- ????????????<tem:Condition>??
- ?????????????????
- ???????????????<tem:StartTime>?</tem:StartTime>??
- ?????????????????
- ???????????????<tem:EndTime>?</tem:EndTime>??
- ?????????????????
- ???????????????<tem:ShopId>?</tem:ShopId>??
- ?????????????????
- ???????????????<tem:ProductId>?</tem:ProductId>??
- ????????????</tem:Condition>??
- ?????????</tem:queryInfo>??
- ??????</tem:QueryOrder>??
- ???</soapenv:Body>??
- </soapenv:Envelope>??
- ??
- 2014-05-25?22:05:02,357?[8]?INFO??[127.0.0.1]?[http://tempuri.org/QueryOrder]?-?SoapResponse:??
- <?xml?version="1.0"?encoding="utf-8"?>??
- <soap:Envelope?xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/"?xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"?xmlns:xsd="http://www.w3.org/2001/XMLSchema">??
- ??<soap:Body>??
- ????<QueryOrderResponse?xmlns="http://tempuri.org/">??
- ??????<QueryOrderResult>??
- ????????<PageNo>1</PageNo>??
- ????????<PageSize>1</PageSize>??
- ????????<TotalCount>3</TotalCount>??
- ????????<PageCount>1</PageCount>??
- ????????<HasNextPage>false</HasNextPage>??
- ????????<Data>??
- ??????????<Order>??
- ????????????<Id>1</Id>??
- ????????????<OrderDate>2014-05-25?22:05:02</OrderDate>??
- ????????????<ShopId>SHOP001</ShopId>??
- ????????????<ProductId>PRD001</ProductId>??
- ????????????<Quantity>1</Quantity>??
- ????????????<Price>59</Price>??
- ??????????</Order>??
- ??????????...??
- ????????</Data>??
- ??????</QueryOrderResult>??
- ????</QueryOrderResponse>??
- ??</soap:Body>??
- </soap:Envelope>??
2014-05-25 22:05:02,292 [8] INFO [127.0.0.1] [http://tempuri.org/QueryOrder] - SoapRequest:
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:tem="http://tempuri.org/">
<soapenv:Body>
<tem:QueryOrder>
<!--Optional:-->
<tem:queryInfo>
<tem:PageNo>1</tem:PageNo>
<tem:PageSize>1</tem:PageSize>
<!--Optional:-->
<tem:Condition>
<!--Optional:-->
<tem:StartTime>?</tem:StartTime>
<!--Optional:-->
<tem:EndTime>?</tem:EndTime>
<!--Optional:-->
<tem:ShopId>?</tem:ShopId>
<!--Optional:-->
<tem:ProductId>?</tem:ProductId>
</tem:Condition>
</tem:queryInfo>
</tem:QueryOrder>
</soapenv:Body>
</soapenv:Envelope>
2014-05-25 22:05:02,357 [8] INFO [127.0.0.1] [http://tempuri.org/QueryOrder] - SoapResponse:
<?xml version="1.0" encoding="utf-8"?>
<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<soap:Body>
<QueryOrderResponse xmlns="http://tempuri.org/">
<QueryOrderResult>
<PageNo>1</PageNo>
<PageSize>1</PageSize>
<TotalCount>3</TotalCount>
<PageCount>1</PageCount>
<HasNextPage>false</HasNextPage>
<Data>
<Order>
<Id>1</Id>
<OrderDate>2014-05-25 22:05:02</OrderDate>
<ShopId>SHOP001</ShopId>
<ProductId>PRD001</ProductId>
<Quantity>1</Quantity>
<Price>59</Price>
</Order>
...
</Data>
</QueryOrderResult>
</QueryOrderResponse>
</soap:Body>
</soap:Envelope>
接下来利用 SoapHeader 实现最基本的 Basic Authentication 校验,当然你不想每一个 WebMethod 去做相同的Check,同样我们实现一个 Soap Extension。
Authentication (SoapHeader) 的定义:
- using?System;??
- using?System.Web.Services.Protocols;??
- ??
- namespace?WebService1.Common??
- {??
- ????public?class?Authentication?:?SoapHeader??
- ????{??
- ????????public?string?UserName?{?get;?set;?}??
- ????????public?string?Password?{?get;?set;?}??
- ????}??
- }??
using System;
using System.Web.Services.Protocols;
namespace WebService1.Common
{
public class Authentication : SoapHeader
{
public string UserName { get; set; }
public string Password { get; set; }
}
}
AuthCheckExtension 的实现:在 SoapMessage AfterDeserialize 这个阶段,取出客户端传的 SoapHeader 验证 UserName 和 Password 在服务端是否存在。
如果不存在或者错误则抛出
no auth ! 的错误。
- using?System;??
- using?System.Collections.Generic;??
- using?System.Linq;??
- using?System.Web;??
- using?System.IO;??
- using?System.Web.Services.Protocols;??
- using?WebService1.Config;??
- ??
- namespace?WebService1.Common??
- {??
- ????public?class?AuthCheckExtension?:?SoapExtension??
- ????{??
- ????????public?override?void?ProcessMessage(SoapMessage?message)??
- ????????{??
- ????????????if?(message.Stage?==?SoapMessageStage.AfterDeserialize)??
- ????????????{??
- ????????????????foreach?(SoapHeader?header?in?message.Headers)??
- ????????????????{??
- ????????????????????if?(header?is?Authentication)??
- ????????????????????{??
- ????????????????????????var?authHeader?=?header?as?Authentication;??
- ????????????????????????var?isValidUser?=?true;??
- ????????????????????????var?users?=?AuthConfiguration.AuthSettings.Users;??
- ????????????????????????if?(users?!=?null?&&?users.Count?>?0)??
- ????????????????????????{???
- ????????????????????????????isValidUser?=?users.Any(u?=>?u.UserName?==?authHeader.UserName?&&?u.Password?==?authHeader.Password);??
- ????????????????????????}??
- ??
- ????????????????????????if?(!isValidUser)??
- ????????????????????????????throw?new?BizException("no?auth?!");??
- ????????????????????}??
- ????????????????}??
- ????????????}??
- ????????}??
- ??
- ??
- ????????public?override?object?GetInitializer(Type?serviceType)??
- ????????{??
- ????????????return?null;??
- ????????}??
- ??
- ????????public?override?object?GetInitializer(LogicalMethodInfo?methodInfo,?SoapExtensionAttribute?attribute)??
- ????????{??
- ????????????return?null;??
- ????????}??
- ??
- ????????public?override?void?Initialize(object?initializer)??
- ????????{??
- ??????????????
- ????????????AuthConfiguration.Config();??
- ????????}??
- ????}??
- ??
- }??
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.IO;
using System.Web.Services.Protocols;
using WebService1.Config;
namespace WebService1.Common
{
public class AuthCheckExtension : SoapExtension
{
public override void ProcessMessage(SoapMessage message)
{
if (message.Stage == SoapMessageStage.AfterDeserialize)
{
foreach (SoapHeader header in message.Headers)
{
if (header is Authentication)
{
var authHeader = header as Authentication;
var isValidUser = true;
var users = AuthConfiguration.AuthSettings.Users;
if (users != null && users.Count > 0)
{
isValidUser = users.Any(u => u.UserName == authHeader.UserName && u.Password == authHeader.Password);
}
if (!isValidUser)
throw new BizException("no auth !");
}
}
}
}
public override object GetInitializer(Type serviceType)
{
return null;
}
public override object GetInitializer(LogicalMethodInfo methodInfo,SoapExtensionAttribute attribute)
{
return null;
}
public override void Initialize(object initializer)
{
// 初始化 AuthSettings
AuthConfiguration.Config();
}
}
}
然后给 WebMethod 加上 [SoapHeader("Authentication"),AuthCheck]?就OK了。
- using?System;??
- using?System.Collections.Generic;??
- using?System.Web;??
- using?System.Web.Services;??
- using?WebService1.Entity;??
- using?WebService1.Service;??
- using?System.Web.Services.Protocols;??
- using?WebService1.Common;??
- ??
- namespace?WebService1??
- {??
- ????[WebService(Namespace?=?"http://tempuri.org/")]??
- ????[WebServiceBinding(ConformsTo?=?WsiProfiles.BasicProfile1_1)]??
- ????[System.ComponentModel.ToolboxItem(false)]??
- ????public?class?Service1?:?System.Web.Services.WebService??
- ????{??
- ????????public?Authentication?Authentication?{?get;?set;?}??
- ??
- ????????[WebMethod]??
- ????????[Trace]??
- ????????[SoapHeader("Authentication"),?AuthCheck]??
- ????????public?PageResult<Order>?QueryOrder(Query<OrderCondition>?queryInfo)??
- ????????{??
- ????????????OrderService?service?=?new?OrderService();??
- ????????????return?service.Query(queryInfo);??
- ????????}??
- ??
- ????}??
- }??
using System;
using System.Collections.Generic;
using System.Web;
using System.Web.Services;
using WebService1.Entity;
using WebService1.Service;
using System.Web.Services.Protocols;
using WebService1.Common;
namespace WebService1
{
[WebService(Namespace = "http://tempuri.org/")]
[WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)]
[System.ComponentModel.ToolboxItem(false)]
public class Service1 : System.Web.Services.WebService
{
public Authentication Authentication { get; set; }
[WebMethod]
[Trace]
[SoapHeader("Authentication"),AuthCheck]
public PageResult<Order> QueryOrder(Query<OrderCondition> queryInfo)
{
OrderService service = new OrderService();
return service.Query(queryInfo);
}
}
}
最后我们拿 SoapUI 来测试一下:


再来看看错误处理,如果故意输错 UserName:

顺便要赞一下 SoapUI,真是 WebService 调试的利器,还可以生成 .NET / Java 代码,推荐大家使用。我们用 SoapUI 生成一下 Java 代码。
Java 客户端我决定用 CXF 来实现。所以要先配置一下 SoapUI:

JAVA CXF Client 代码:
- public?static?void?main(String[]?args)?{??
- ????????try?{??
- ??
- ????????????Service1?service1?=?new?Service1();??
- ????????????Service1Soap?service1Soap?=?service1.getService1Soap();??
- ????????????BindingProvider?provider?=?(BindingProvider)service1Soap;??
- ??
- ????????????List<Header>?headers?=?new?ArrayList<Header>();??
- ????????????Authentication?authentication?=?new?Authentication();??
- ????????????authentication.setUserName("fangxing");??
- ????????????authentication.setPassword("123456");??
- ????????????Header?authHeader?=?new?Header(ObjectFactory._Authentication_QNAME,?authentication,??
- ????????????????????new?JAXBDataBinding(Authentication.class));??
- ??
- ????????????headers.add(authHeader);??
- ????????????provider.getRequestContext().put(Header.HEADER_LIST,?headers);??
- ??
- ????????????QueryOfOrderCondition?queryInfo?=?new?QueryOfOrderCondition();??
- ????????????queryInfo.setPageNo(1);??
- ????????????queryInfo.setPageSize(1000);??
- ??
- ????????????OrderCondition?condition?=?new?OrderCondition();??
- ????????????condition.setShopId("SHOP001");??
- ????????????condition.setStartTime("2014-05-01?00:00:00");??
- ????????????condition.setEndTime("2014-05-10?23:59:59");??
- ??
- ????????????queryInfo.setCondition(condition);??
- ??
- ????????????PageResultOfOrder?result?=?service1Soap.queryOrder(queryInfo);??
- ????????????System.out.println("get?order?size:?"?+?result.getData().getOrder().size());??
- ??
- ????????}?catch?(Exception?e)?{??
- ????????????e.printStackTrace();??
- ????????}??
- ??
- ????}??
public static void main(String[] args) {
try {
Service1 service1 = new Service1();
Service1Soap service1Soap = service1.getService1Soap();
BindingProvider provider = (BindingProvider)service1Soap;
List<Header> headers = new ArrayList<Header>();
Authentication authentication = new Authentication();
authentication.setUserName("fangxing");
authentication.setPassword("123456");
Header authHeader = new Header(ObjectFactory._Authentication_QNAME,authentication,new JAXBDataBinding(Authentication.class));
headers.add(authHeader);
provider.getRequestContext().put(Header.HEADER_LIST,headers);
QueryOfOrderCondition queryInfo = new QueryOfOrderCondition();
queryInfo.setPageNo(1);
queryInfo.setPageSize(1000);
OrderCondition condition = new OrderCondition();
condition.setShopId("SHOP001");
condition.setStartTime("2014-05-01 00:00:00");
condition.setEndTime("2014-05-10 23:59:59");
queryInfo.setCondition(condition);
PageResultOfOrder result = service1Soap.queryOrder(queryInfo);
System.out.println("get order size: " + result.getData().getOrder().size());
} catch (Exception e) {
e.printStackTrace();
}
}
示例代码下载,下载请阅 Readme.txt