java调用WCF问题

来源:互联网 发布:起点是网络出版社吗 编辑:程序博客网 时间:2024/04/27 21:31

过去微软.NET的ASMX Web Service已被大家广泛应用﹐但在信息安全日愈重视之下﹐微软有意以WCF取代原有的 ASMX Web Service。WCF 具有许多先进的技术﹐而跨平台作业已是现在不可避免的问题﹐同样是微软的 Solution之下如何使用WCF应该不是什么问题﹐但在不同的平台上是否有那么容易呢?因此这里以 Java 实作如何来调用具有使用身份验证的 WCF﹐并以WCF 预设的wsHttpBinding 及一般常使用的 basicHttpBinding 的系结方式实作。

我本身并非专研 Java﹐但既然日后使用了 WCF 也势必面临 Java 或其它平台的呼叫﹐Java 是Open Source 具有多种 Framework﹐且有多种开发工具﹐参考了网络上许多范例与讨论﹐Java 对于WCF比较常用的是 ASIX 和 Metro 套件﹐因此这里主要使用 NetBeans IDE 搭配 Metro﹐eclipse 搭配asix 这两种﹐不过因为不是专研 Java﹐故仍有些地方不是实作的很完全﹐这里就抛砖引玉﹐期待高手来解惑了。

 

这里使用的 NetBeans 版本为 NetBeans IDE 7.2 (Build 201207301726)﹐JDK 是1.6.0_37。NetBeans可至Oracle官网(http://netbeans.org/downloads/index.html)下载。

在 Viusal Studio 上建立WCF 项目时﹐预设所产生的就是使用 wsHttpBinding 的系结。wsHttpBinding 预设的安全性模式为 Message(讯息模式加密)﹐在 WCF 中也是普遍的被使用。当我想以 Java 调用时却发现在网络上有许多人询问﹐但很少看到一个完整的范例。同时所看到的讨论回复都很片断﹐因此实作过程并不容易。在这里分别以 Java Application 与 Web应用程序当Client程序调用WCF为范例。

这一篇是搭配使用者认证的WCF服务—wsHttpBinding系结所建置的WCF 服务。

1. 自订使用者账号/密码﹐Java Application client 不以Glassfish为container

1.1. 汇入凭证档

因为WCF自订使用者账号/密码认证是需要X.509凭证﹐因此在开始之前必须先取得凭证放置到Java可以读取的位置。

这里的凭证继续延用WCF自定义用户账号密码之使用者认证的WCF服务wsHttpBinding总结这一篇中的凭证﹐其凭证主体为 MyWCFCert。首先使用windows凭证管理将之前制作WCF时所制作的凭证先汇出。

 \
 

将汇出的凭证档档名命名为 MyWCFCert.cer﹐接着使用 JDK 所提供的工具 keytool 指令建立放置凭证的 keystore 或汇入已存在的 keystore(金钥库)。Keytool.exe是java的凭证管理工具。

指令:

把一个凭证档导入到指定的keystore www.it165.net

keytool -import -file MyWCFCert.cer -keystore my.TrustStore -alias wcfsvrkey

用-keystore 参数指定 keystore 档案﹐my.TrustStore 是我自己建立的 keystore﹐如果不存在﹐会自动建立同时会询问keystore的密码。

-alias则是为这个汇入的凭证建立一个别名。

 

汇入成功后应该做一下检查﹐同样使用keytool指令

指令:

列出keystore中的内容信息

keytool -list -v -keystore my.TrustStore

执行之后可以检视这个keystore所有的凭证档。

 

\
 

如果有删除凭证的需要时同样使用keytool

指令:

删除指定的keystore中的凭证

keytool -delete -alias wcfsvrkey -keystore my.TrustStore

 

1.2. 下载 METRO 2.2.1

我由Oracle 官网下载使用的NetBeans IDE是7.2 版﹐内附 METRO 是 2.0 版﹐对于要使用具有使用者账号密码认证的WCF服务在国外论坛上有不少﹐有许多人都说必须将Metro更新到2.0版才行﹐不过经过我实测后发现必须使用 2.2.1版才行。

Metro 2.2.1 版可至 http://metro.java.net/2.2.1/ 此处下载。将下载的metro-standalone-2.2.1.zip档案解压至自订的路径之下﹐例如以我个人放置到D:\Java\metro-2_2_1。然后开启NetBeans﹐到工具/链接库将 METRO 2.2.1 加入链接库。

 

\

在链接库管理器中﹐按下[加入JAR/数据夹]指向Metor 2.2.1的位置﹐之后在NetBeans 中就可以直接选择了。

 

\
 

1.3. 建立项目

开启NetBeans新增项目﹐左侧选择Java﹐右侧选择Java Application﹐[下一步]继续。

 

\
 

输入项目名称﹑项目位置﹑Class文件等各项信息﹐按下[完成]。

 

\
 

专案名称:wsHttpClient

Class名称:JavaClient

 

1.4. 加入 Web Service Client

项目建立后﹐在该项目的名称上以鼠标右键选择 New/Web Service Client。

 

\
 

完成后回到NetBeans IDE接口等一下﹐NetBeans正在产生WSDL档及自动产生一些相关的设定档和程序代码。NetBeans跑完后大约如下图。

 

\
 

1.5. 档案转换为 UT-8 格式

检视项目之下有个Generated Source﹐将其展开后会如下﹐在Generated Source是NetBeans依WSDL所自动产生的class檔。

 

\
 

点选开启 GetProduct.java﹐画面会出现警告﹐这是因为NetBeans自动Generated的档案为ANSI格式﹐但这个档案中有中文﹐而NetBeans要读取的档案为UTF-8﹐故这里NetBeans跳出了警告。

 

\
 

因为档案带有中文字﹐因此必须要先将档案改存为UTF-8才行﹐不然后续做 Builde Project 时是会出错的。可以用记事本开启档案﹐再以另存新档方式变更格式再回存。不过因为档案不只一个﹐这样改比较慢﹐可以去网络找一个老牌的工具 ConverZ 做批次转换。 www.it165.net

 

1.6. 编辑 Web 服务属性

接着在Web服务参照下的MyProducts按下鼠标右键﹐选择[编辑Web服务属性]。

 

\
 

开出的是Web服务属性的画面﹐这里我们只要设定Quality Of Service页签下关于安全的部分。

 

\
 

在编辑Web服务属性的设定画面上有一个[使用开发默认值]的复选框﹐点击一下﹐画面会跳出一些讯息。

 

\
 

这个讯息是询问我们,是否使用METRO Library﹐如果要使用则会移除JAX-WS library﹐因为JAX-WS已被包含于METRO之中。按下Yes则NetBeans会帮我们项目加上METRO。如下图﹐回到Project中展开链接库﹐就可以看到METRO 2.0已被加入。

 

\
 

再回到编辑Web服务属性设定画面﹐刚刚所点击的[使用开发默认值]的复选框如果已经有被勾选了﹐请将勾选取消。然后先离开编辑Web服务属性设定画面。

 

1.7. 加入CallbackHandler 档案

这里需要加入一个继承CallbackHandler的档案

TrustStoreCallbackHandler.java

 

view source
print?
01.public class TrustStoreCallbackHandler implements CallbackHandler {
02.KeyStore keyStore = null
03.String password = "123456";  // keystore的密码
04.public TrustStoreCallbackHandler() { 
05.System.out.println("Truststore CBH.CTOR Called.........."); 
06.InputStream is null
07.try 
08.keyStore = KeyStore.getInstance("JKS"); 
09.String keystoreURL = "C:\\Java\\Certificate\\myTrustStore"//放置凭证档的keystore
10.is new FileInputStream(keystoreURL); 
11.keyStore.load(is, password.toCharArray()); 
12.catch (IOException ex) { 
13.Logger.getLogger(TrustStoreCallbackHandler.class.getName()).log(Level.SEVERE,null, ex); 
14.throw new RuntimeException(ex); 
15.catch (NoSuchAlgorithmException ex) { 
16.Logger.getLogger(TrustStoreCallbackHandler.class.getName()).log(Level.SEVERE,null, ex); 
17.throw new RuntimeException(ex); 
18.catch (CertificateException ex) { 
19.Logger.getLogger(TrustStoreCallbackHandler.class.getName()).log(Level.SEVERE,null, ex); 
20.throw new RuntimeException(ex); 
21.catch (KeyStoreException ex) { 
22.Logger.getLogger(TrustStoreCallbackHandler.class.getName()).log(Level.SEVERE,null, ex); 
23.throw new RuntimeException(ex); 
24.finally 
25.try 
26.is.close(); 
27.catch (IOException ex) { 
28.Logger.getLogger(TrustStoreCallbackHandler.class.getName()).log(Level.SEVERE,null, ex); 
29.
30.
31.}
32. 
33.public void handle(Callback[] callbacks) throws IOException, UnsupportedCallbackException { 
34.System.out.println("Truststore CBH.handle() Called.........."); 
35.for (int i = 0; i < callbacks.length; i++) {
36.if (callbacks[i] instanceof KeyStoreCallback) { 
37.KeyStoreCallback cb = (KeyStoreCallback) callbacks[i]; 
38.print(cb.getRuntimeProperties()); 
39.cb.setKeystore(keyStore); 
40.else 
41.throw new UnsupportedCallbackException(callbacks[i]); 
42.
43.
44.}
45. 
46.private void print(Map context) { 
47.Iterator it = context.keySet().iterator(); 
48.while (it.hasNext()) { 
49.System.out.println("Prop " + it.next()); 
50.
51.}
52.}


 

1.8. 重回编辑 Web 服务属性

重新开启 编辑Web服务属性

 

\
 

将[认证凭证]选择动态。变更完后画面会改变。

 

\
 

在[使用者名称回呼处理程序]及[密码回呼处理程序]后方的浏览键按下后选择刚刚所建立的CallbackHandler档案TrustStoreCallbackHandler.java。

接下来点选画面上的[信任库]按键。

 

\
 

画面将出现信任库配置的画面。



 

\
 

位置请选择凭证文件所在的keystor﹐同时在信任库密码输入keystore的密码。这时候如果要去选择别名是选不到的﹐请先按下「OK」键﹐并离开编辑Web服务属性的画面回到NetBeans IDE画面。

观察Project之下在原始码套件/META-INF之下多了两个档案﹐MyProducts.svc.xml及wsit-client.xml﹐这是刚刚的设定之后产生的。

 

\
 

现在必须先开启MyProducts.svc.xml做些修改。修改<sc:TrustStore>下的type属性﹐type 必须改为 JKS。

MyProducts.svc.xml 取需要修改的部分

 

view source
print?
01.<wsp1:Policy wsu:Id="WSHttpBinding_IProductServicePolicy">
02.<wsp1:ExactlyOne>
03.<wsp1:All>
04.<sc:TrustStore wspp:visibility="private" type="JKS" storepass="123456"location="C:\Java\Certificate\myTrustStore" />
05.<sc:CallbackHandlerConfiguration wspp:visibility="private">
06.<sc:CallbackHandler name="usernameHandler"classname="wshttpclient.TrustStoreCallbackHandler"/>
07.<sc:CallbackHandler name="passwordHandler"classname="wshttpclient.TrustStoreCallbackHandler"/>
08.</sc:CallbackHandlerConfiguration>
09.</wsp1:All>
10.</wsp1:ExactlyOne>
11.</wsp1:Policy>


 

上述修改之后﹐再次回到Web服务属性编辑画面并点选信任库﹐这时再去拉选别名﹐就可以选择到凭证档的别名了﹐按下OK后并离开Web服务属性编辑画面﹐再次检视刚刚刚的MyProducts.svc.xml可以发现设定多了peeralais的设定。

<sc:TrustStore wspp:visibility="private" type="JKS" storepass="123456"

        location="C:\Java\Certificate\myTrustStore" peeralias="win7svrkey"/>

 
1.9. 撰写 Client 程序

前面的设定已完成了工作中的大部分﹐剩下client程序。

wcfClient.java

 

view source
print?
01.public class wcfClient {
02.public static void main(String[] args) {
03.org.tempuri.ProductService client;
04.org.tempuri.IProductService port;
05. 
06.Product product;
07.try{
08.client=new org.tempuri.ProductService();
09.port=client.getWSHttpBindingIProductService();
10. 
11.//设定呼叫WCF的使用者账号/密码
12.((BindingProvider)port).getRequestContext().put(BindingProvider.USERNAME_PROPERTY,"testman");
13.((BindingProvider)port).getRequestContext().put(BindingProvider.PASSWORD_PROPERTY,"a0987");
14. 
15.String result= port.saySomething("Hello~~");
16.System.out.println(result);
17.System.out.println();
18. 
19.product=port.getProduct("P-001");
20.System.out.println("产品编号:"+product.getNo().getValue());
21.System.out.println("产品名称:"+product.getName().getValue());
22.System.out.println("单价:"+product.getPrice());
23.System.out.println("数量:"+product.getQuantity());
24.}catch(Exception er){
25.System.out.println(er.getMessage());
26.}
27.}
28.}

1.10. 测试程序

执行Build Project﹐如果没有任何错误﹐那么就直接执行程序。结果﹐失败~~

 

view source
print?
01.java.util.logging.ErrorManager: 5
02.java.lang.NullPointerException
03.at java.util.PropertyResourceBundle.handleGetObject(PropertyResourceBundle.java:136)
04.at java.util.ResourceBundle.getObject(ResourceBundle.java:368)
05.at java.util.ResourceBundle.getString(ResourceBundle.java:334)
06.at java.util.logging.Formatter.formatMessage(Formatter.java:108)
07.at java.util.logging.SimpleFormatter.format(SimpleFormatter.java:63)
08.at java.util.logging.StreamHandler.publish(StreamHandler.java:177)
09.at java.util.logging.ConsoleHandler.publish(ConsoleHandler.java:88)
10.at java.util.logging.Logger.log(Logger.java:478)
11.at java.util.logging.Logger.doLog(Logger.java:500)
12.at java.util.logging.Logger.log(Logger.java:589)
13.at com.sun.xml.ws.security.impl.policy.CertificateRetriever.digestBST(CertificateRetriever.java:136)
14.at com.sun.xml.wss.jaxws.impl.SecurityClientTube.processRequest(SecurityClientTube.java:211)
15.at com.sun.xml.ws.api.pipe.Fiber.__doRun(Fiber.java:629)
16.at com.sun.xml.ws.api.pipe.Fiber._doRun(Fiber.java:588)
17.at com.sun.xml.ws.api.pipe.Fiber.doRun(Fiber.java:573)
18.com.sun.org.apache.xml.internal.security.exceptions.Base64DecodingException: It should be divisible by four
19.at com.sun.xml.ws.api.pipe.Fiber.runSync(Fiber.java:470)
20.at com.sun.xml.ws.client.Stub.process(Stub.java:319)
21.at com.sun.xml.ws.client.sei.SEIStub.doProcess(SEIStub.java:157)
22.at com.sun.xml.ws.client.sei.SyncMethodHandler.invoke(SyncMethodHandler.java:109)
23.at com.sun.xml.ws.client.sei.SyncMethodHandler.invoke(SyncMethodHandler.java:89)
24.at com.sun.xml.ws.client.sei.SEIStub.invoke(SEIStub.java:140)
25.at $Proxy43.saySomething(Unknown Source)
26.at wshttpclient.wcfClient.main(wcfClient.java:31)

\
 

接着在[链接库]上按鼠标右键选择[Add Library…]﹐点选之前所加入的Metro 2.2.1按下[加入链接库]就可以了。

 

\  \ 

\
 

重新再Build一次程序后﹐再一次执行。结果﹐再次失败~~~

错误的讯息

2012/12/22 上午 10:44:09 [com.sun.xml.ws.policy.parser.PolicyConfigParser]  parse
信息: WSP5018: 已从档案 file:/D:/MyProject/WCF/WCFSite/WCFSolution/Java/NetBeansProjects/wsHttpClient/build/classes/META-INF/wsit-client.xml 载入 WSIT 组态.
Truststore CBH.CTOR Called..........
Truststore CBH.CTOR Called..........
2012/12/22 上午 10:44:12 com.sun.xml.wss.jaxws.impl.SecurityClientTube processClientResponsePacket
严重的: WSSTUBE0025: 验证输入讯息中的安全性时发生错误.
com.sun.xml.wss.impl.PolicyViolationException: ERROR: No security header found in the message
at com.sun.xml.wss.impl.policy.verifier.MessagePolicyVerifier.verifyPolicy(MessagePolicyVerifier.java:138)
at com.sun.xml.ws.security.opt.impl.incoming.SecurityRecipient.createMessage(SecurityRecipient.java:1016)
at com.sun.xml.ws.security.opt.impl.incoming.SecurityRecipient.validateMessage(SecurityRecipient.java:252)
at com.sun.xml.wss.jaxws.impl.SecurityTubeBase.verifyInboundMessage(SecurityTubeBase.java:455)
at com.sun.xml.wss.jaxws.impl.SecurityClientTube.processClientResponsePacket(SecurityClientTube.java:434)
at com.sun.xml.wss.jaxws.impl.SecurityClientTube.processResponse(SecurityClientTube.java:362)
at com.sun.xml.ws.api.pipe.Fiber.__doRun(Fiber.java:1074)
at com.sun.xml.ws.api.pipe.Fiber._doRun(Fiber.java:979)
at com.sun.xml.ws.api.pipe.Fiber.doRun(Fiber.java:950)
at com.sun.xml.ws.api.pipe.Fiber.runSync(Fiber.java:825)
at com.sun.xml.ws.client.Stub.process(Stub.java:443)
at com.sun.xml.ws.client.sei.SEIStub.doProcess(SEIStub.java:174)
at com.sun.xml.ws.client.sei.SyncMethodHandler.invoke(SyncMethodHandler.java:119)
at com.sun.xml.ws.client.sei.SyncMethodHandler.invoke(SyncMethodHandler.java:102)
WSSTUBE0025: 验证输入讯息中的安全性时发生错误.
at com.sun.xml.ws.client.sei.SEIStub.invoke(SEIStub.java:154)
at $Proxy41.saySomething(Unknown Source)
at wshttpclient.wcfClient.main(wcfClient.java:31)
成功建置 (总时间:3 秒)
失败的原因是什么呢?这里必须回到 WCF 的设定﹐检视 WCF 下的 wcf.config 中的 Binding 设定

修改前

 

   1:  <bindings>
   2:     <wsHttpBinding>
   3:          <binding name="Product.wsHttpBinding">
   4:            <security>
   5:              <message clientCredentialType="UserName" />
   6:            </security>
   7:          </binding>
   8:    </wsHttpBinding>
   9:  </bindings>
修改后
   1:  <bindings>
   2:     <wsHttpBinding>
   3:        <binding name="Product.wsHttpBinding">
   4:            <security>
   5:              <message clientCredentialType="UserName"
   6:                       negotiateServiceCredential="false"
   7:                       algorithmSuite="Basic128"
   8:                       establishSecurityContext="false" />
   9:            </security>
  10:        </binding>
  11:    </wsHttpBinding>
  12:  </bindings>
在message标签中negotiateServiceCredential预设是true﹐这个属性和Windows认证有关﹐可以参考MSDN的文章http://msdn.microsoft.com/zh-tw/library/system.servicemodel.messagesecurityoverhttp.negotiateservicecredential.aspx 及http://paper.dic123.com/lunwen_234540427/ ﹐不是很好了解﹐这里Java要呼叫必须将 negotiateServiceCredential 设为 false。
另外algorithmSuite原本默认值为Basic256必须要修改为Basic128﹐理由是什么…我记得曾在一篇国外讨论区看到说Java不支持到256的长度﹐文章已遗落在茫茫网海中﹐这给Java高手去回答吧。establishSecurityContext默认值为true也必须改为false。
注意﹐WCF的web.config一旦有改变﹐原本呼叫此WCF的Client程序必须跟着修改设定。
之后重新执行Build Project﹐那么就直接执行程序。结果﹐这次总算成功~~

 \
 

网络上有许多人询问Java可否调用wsHttpBinding的WCF呢?根据实作后的经验﹐当然是可以﹐不过为什么会有人有疑惑?首先﹐WCF具有多项认证技术﹐例如Windows认证﹑SQL Membership﹑使用者账号密码…等﹐而在wsHttpBinding其预设是使用Windows认证﹐这在微软各项Solution中不会有什么太大的问题﹐但是像Java就不一定。在这一小节里提到negotiateServiceCredential这个属性必须改为false﹐就是因为这个设定和 Windows 认证有关﹐当然可以在WCF组态设定变更认证方式﹐但一奱更之后就跟随着必须提供凭证﹐例如本次的范例实作﹐这一部分是常被大家所混淆的。

2. 自订使用者账号/密码﹐Java Client 以Glassfish为container

2.1. 建立项目

档案/New Project/Java Web/Web应用程序﹐建立一个Web应用程序。这次就不再示范无认证的WCF﹐直接跑有认证的WCF。专案名称:wsHttpWebAppUseAuth

 

\ 

\
 

下一步之后这里要选择所使用的容器﹐这里选择的是GlassFish Server 3.1.2。

 

\
 

按下[完成]后﹐可以看到所产生的项目架构。

 

\
 

2.2. 加入 Web Service Client

在项目名称上鼠标右键选择New/Web Service Client。

 

\
 

选择WSDL URL并输入具有认证的WCF URL。

WSDL URL:http://10.0.100.101:85/wsHttpUserAuth.webhost/MyProducts.svc?wsdl

 \
 

[完成]之后在项目中可以看到同样产生了Generated Sources还有服务参照。请记得Generated出来的class档带有中文﹐要先将档案格式转换成UTF-8﹐不然在最后做builder时会失败。

 

\
 

2.3. 编辑 Web 服务属性

在Web服务参照之下的MyProducts按下鼠标右键选择[编辑Web服务属性]。

 

\
 

到此和之前的Java Application的做法都相同﹐但这次是搭配GlassFish做container﹐因此不需要METRO﹐故接下来直接点[信任库]设定keystore就可以。

 

\
 

将位置改选择放置凭证的keystore档案﹐并输入keystore的密码。同样的现在是选不到别名的。请按下[OK]回到前一个画面后也按下[OK]离开Web服务属性的编辑。

 

\
 

重新检视项目﹐在原始码套件/META-INF之下多了MyProducts.svc.xml档案。

 

\
 

开启MyProducts.svc.dml﹐并修改<sc:TrustStrore>下的Type属性改为JKS。
修改后
   1:  <wsp1:Policy wsu:Id="WSHttpBinding_IProductServicePolicy">
   2:    <wsp1:ExactlyOne>
   3:      <wsp1:All>
   4:        <sc:TrustStore wspp:visibility="private" storepass="123456" type="JKS" location="C:\Java\Certificate\myTrustStore"/>
   5:      </wsp1:All>
   6:    </wsp1:ExactlyOne>
   7:  </wsp1:Policy>
再重新回到之前的Web服务属性的编辑并进入信任库中﹐这时就已经可以选择别名了。指定别名后回头看MyProducts.svc.xml的设定就会发现已有修改。如果指令很熟悉的人就不需要这么麻烦了﹐直接编写设定档即可。
 
2.4. 建立 Servlet
在原始码套件上以鼠标右键﹐选择New/Servlet﹐然后输入ClassName和Package﹐按下[完成]。

 

\
 

然后在所产生的wsService.java中输入以下程序代码

wsService.java

 

view source
print?
01.@WebServlet(name = "wsService", urlPatterns = {"/wsService"})
02.public class wsService extends HttpServlet {
03./**
04.* Processes requests for both HTTP
05.* <code>GET</code> and
06.* <code>POST</code> methods.
07.*
08.* @param request servlet request
09.* @param response servlet response
10.* @throws ServletException if a servlet-specific error occurs
11.* @throws IOException if an I/O error occurs
12.*/
13.protected void processRequest(HttpServletRequest request, HttpServletResponse response)
14.throws ServletException, IOException {
15.response.setContentType("text/html;charset=UTF-8");
16.PrintWriter out = response.getWriter();
17.org.tempuri.ProductService client=null;
18.org.tempuri.IProductService port=null;
19.Product product;
20.try {
21.client=new org.tempuri.ProductService();
22.port=client.getWSHttpBindingIProductService();
23.BindingProvider bp=(BindingProvider)port;
24.bp.getRequestContext().put(BindingProvider.USERNAME_PROPERTY, "testman");
25.bp.getRequestContext().put(BindingProvider.PASSWORD_PROPERTY, "a0987");
26. 
27.out.println("<html>");
28.out.println("<head>");
29.out.println("<title>Servlet wsService</title>");           
30.out.println("</head>");
31.out.println("<body>");
32.String result=port.saySomething("Hello~~");
33.out.println("<h1>Servlet wsService at " + result + "</h1>");
34.out.println("<br/>");
35. 
36.product=port.getProduct("P-001");
37.out.println("产品编号:"+product.getNo().getValue()+"<br>");
38.out.println("产品名称:"+product.getName().getValue()+"<br>");
39.out.println("单价:"+product.getPrice()+"<br>");
40.out.println("数量:"+product.getQuantity()+"<br>");
41. 
42.out.println("</body>");
43.out.println("</html>");
44.finally {           
45.out.close();
46.}
47.}
48.}

将项目builder之后执行应该可以得到如下的结果。

 

\
 

在撰写过程﹐花了最多时间是在Java Application 如何调用WCF 的部分﹐目前我所成功的就是 NetBeans + Metro 及 GlassFish﹐至于使用ASIX 2 还没成功过﹐不过如果是 basicHttpBinding 以 Transport 方式加密﹐使用 ASIX 倒是可以﹐这留待下一篇再继续了。


原创粉丝点击