此解决方案目录项的样例应用程序是一个 Swing 客户端,它提供了一个 GUI,用于将订单文档发送到字符串订单 Web 服务。以下便是该应用程序的屏幕快照:
此应用程序是用 Netbeans[TM] IDE 4.1 编写的。应用程序中的主类是 MainWindow
,它是作为 Swing 框架实现的。它使用委托类 POServiceBD 来调用 Web 服务。
此应用程序可以独立运行,也可以与 Java Web Start 一起运行。此应用程序的 Java Web Start 启用版本在 webstart-client.war
中包含的 Web 应用程序中。
POServiceBD
调用的。
// import stub classes
import
com.sun.j2ee.blueprints.stringposervice.StringPurchaseOrderService_Impl;
import com.sun.j2ee.blueprints.stringposervice.StringPurchaseOrderServiceSEI;
// ... other contents of the class file
// Using stubs
StringPurchaseOrderService_Impl svcimpl = new StringPurchaseOrderService_Impl();
StringPurchaseOrderServiceSEI poservice = svcimpl.getStringPurchaseOrderServiceSEIPort();
((Stub)poservice)._setProperty(Stub.ENDPOINT_ADDRESS_PROPERTY, serviceUrl);
String result = poservice.submitPO(xmlDocStr);
代码示例 1:使用桩模块调用 Web 服务
// import classes for service endpoint interface
import com.sun.j2ee.blueprints.stringposervice_wrapped.StringPurchaseOrderServiceSEI;
import com.sun.j2ee.blueprints.stringposervice_wrapped.SubmitPO;
import com.sun.j2ee.blueprints.stringposervice_wrapped.SubmitPOResponse;
// ... other contents of the class file
// Using dynamic proxy
ServiceFactory sf = ServiceFactory.newInstance();
URL wsdlURL = new URL(serviceUrl + "?WSDL");
QName serviceQname = new QName(NS_BODY, "StringPurchaseOrderService");
Service s = sf.createService(wsdlURL, serviceQname);
QName portQname = new QName(NS_BODY, "StringPurchaseOrderServiceSEIPort");
StringPurchaseOrderServiceSEI port =
(StringPurchaseOrderServiceSEI) s.getPort(portQname, StringPurchaseOrderServiceSEI.class);
SubmitPO param = new SubmitPO(xmlDocStr);
SubmitPOResponse response = port.submitPO(param);
String result = response.getResult();
代码示例 2:使用动态代理调用 Web 服务
SubmitPO
类是从服务 WSDL 生成的,但是需要重新编写该类才能解决 JAX-RPC 编译器中的错误,在编译器中,该类以不同的方式命名其中一个私有字段 (String_1
),其名称为 string_1
而不是 String_1
。此错误导致 SubmiPO
类无法与动态代理或 DII 一起使用。 // import classes for service endpoint interface
import com.sun.j2ee.blueprints.stringposervice_wrapped.StringPurchaseOrderServiceSEI;
import com.sun.j2ee.blueprints.stringposervice_wrapped.SubmitPO;
import com.sun.j2ee.blueprints.stringposervice_wrapped.SubmitPOResponse;
// ... other contents of the class file
// Using DII
ServiceFactory sf = ServiceFactory.newInstance();
URL wsdlURL = new URL(serviceUrl + "?WSDL");
QName serviceQname = new QName(NS_BODY, "StringPurchaseOrderService");
Service s = sf.createService(wsdlURL, serviceQname);
QName portQname = new QName(NS_BODY, "StringPurchaseOrderServiceSEIPort");
Call call = s.createCall(portQname);
call.setTargetEndpointAddress(serviceUrl);
call.setProperty(Call.SOAPACTION_USE_PROPERTY, new Boolean(true));
call.setProperty(Call.SOAPACTION_URI_PROPERTY,"");
// For WS-I compliant document-literal, need to set the encoding style
// to literal by specifying "" as the encoding style,
// and by setting the operation style to document
String ENCODING_STYLE_PROPERTY = "javax.xml.rpc.encodingstyle.namespace.uri";
String URI_ENCODING = "";
call.setProperty(ENCODING_STYLE_PROPERTY, URI_ENCODING);
call.setProperty(Call.OPERATION_STYLE_PROPERTY, "document");
// Note that the operation name need not be set by calling
// call.setOperationName(new QName(NS_BODY, "submitPO"));
// This is because the SOAP binding used by the Web service is document, not rpc.
// The types for the request parameter and return value are defined in the
// WSDL file itself, so their qnames are defined with the namespace of the body
QName requestQname = new QName(NS_BODY, "submitPO");
QName responseQname = new QName(NS_BODY, "submitPOResponse");
// Define the type of the return value for the DII call.
// SubmitPOResponse must match the wrapped type sent by the Web service.
call.setReturnType(responseQname, SubmitPOResponse.class);
// Define the type of the method parameter for the DII call.
// In the WSDL file, the name of the message part for submitPO is "parameters"
// Hence the request parameter is defined in this way.
call.addParameter("parameters", requestQname, SubmitPO.class, ParameterMode.IN);
SubmitPO param = new SubmitPO(xmlDocStr);
Object[] params = {param};
// Invoke the DII call
SubmitPOResponse response = (SubmitPOResponse) call.invoke(params);
String result = response.getResult();
代码示例 3:使用 DII 调用 Web 服务
lib/
目录)。所有这些 Jar 文件都需要通过同一证书进行签名。使用 s1as
证书对 Jar 文件进行签名,该证书存在于 J2EE SDK 缺省域 (domain1
) 的密钥库中。代码示例 4 提供了如何对 Jar 文件进行签名的 ant build.xml
片段: <!-- use the keystore present in the default domain of the J2EE SDK -->
<property name="keystore.location" value="${j2ee.home}/domains/domain1/config/keystore.jks"/>
<!-- we are using the default password used for the
keystore. This value should be changed if the keystore password has
been changed for the J2EE SDK -->
<property name="keystore.password" value="changeit"/>
<property name="key.alias" value="s1as"/>
<!-- sign application jar -->
<signjar
jar="${war.build.dir}/swing-client.jar"
signedjar="${war.build.dir}/swing-client-signed.jar"
alias="${key.alias}" keystore="${keystore.location}"
storepass="${keystore.password}"/>
<property name="jaxrpc-webstart-support.dir" value="${war.build.dir}/jws-support"/>
<!-- sign JAXRPC runtime jars -->
<signjar
jar="${j2ee.home}/lib/j2ee.jar"
signedjar="${jaxrpc-webstart-support.dir}/j2ee.jar"
alias="${key.alias}" keystore="${keystore.location}"
storepass="${keystore.password}"/>
<signjar jar="${j2ee.home}/lib/jaxrpc-api.jar"
signedjar="${jaxrpc-webstart-support.dir}/jaxrpc-api.jar"
alias="${key.alias}" keystore="${keystore.location}"
storepass="${keystore.password}"/>
<!-- ..... sign other jar files in the same way -->
代码示例 4:对 Jar 文件进行签名的 Ant 生成片段
jnlp
元素需要代码库属性,该属性是应用程序 jar 文件所在的 URL。我们希望动态发现代码库,以便与部署应用程序 war 模块的 URL 匹配。同样,Swing 客户端需要动态确定字符串订单 Web 服务运行所在的 URL。通过在应用程序 war 模块中捆绑的 JSP 文件生成 JNLP 描述符,可以完成上述操作。application/x-java-jnlp-file
的 XML 文件,以便正确调用 Java Web Start。这可以通过使用一个 JSP 页指令来实现,如代码示例 5 所示:<%@ page contentType="application/x-java-jnlp-file" info="Swing Client JNLP" %>
代码示例 5:将 contentType 页指令用于 JNLP 描述符
http
或 https
)、服务器名称、服务器端口和应用程序 jar 文件所在的上下文路径组成。如果服务器端口为 80(对于 http
)和 443(对于 https
),则不需要指定它。代码示例 6 提供了计算代码库的 JSP 代码片段:<%
StringBuffer serverurl = new StringBuffer();
serverurl.append(!request.isSecure() ? "http://" : "https://");
serverurl.append(request.getServerName());
if (request.getServerPort() != (!request.isSecure() ? 80 : 443))
{
serverurl.append(':');
serverurl.append(request.getServerPort());
}
serverurl.append('/');
String codebase = serverurl + request.getContextPath() + '/';
%>
<?xml version="1.0" encoding="UTF-8"?>
<%-- JNLP File for launching Swing Client with JavaWebStart --%>
<jnlp spec="1.0+" codebase="<%=codebase%>" href="swing-client.jnlp">
代码示例 6:动态生成代码库
<%
String serviceurl = serverurl + "webservice/StringPurchaseOrderService";
%>
<!-- ... other JNLP descriptor contents -->
<resources>
<!-- ... other resource delcarations -->
<property name="stringwebservice.url" value="<%=serviceurl%>"/>
</resources>
代码示例 7:将系统属性传递到 Java Web Start 应用程序
stringwebservice.url
属性设置 Web 服务 URL,如代码示例 8 所示。 String serviceurl = System.getProperty("stringwebservice.url");
if (serviceurl != null) {
serviceUrlTextField.setText(serviceurl);
}
代码示例 8:在 Java Web Start 应用程序中检索系统属性
index.html
) 提供了通过 Java Web Start 启动 Swing 应用程序的链接。此链接不直接指向生成 JNLP 描述符的 JSP 文件。而是链接到已映射到 JSP 文件的虚拟 URL swing-client.jnlp
。这样做可确保浏览器获取 JNLP 文件的 .jnlp
扩展名,以处理浏览器使用文件扩展名调用 Java Web Start 的情况。通过使用 servlet-mapping
元素(如代码示例 9 所示),可以做到这一点: <!-- map the JNLP JSP as a servlet since only servlets can have servlet-mapings -->
<servlet>
<servlet-name>jnlp-gen</servlet-name>
<jsp-file>swing-client-jnlp.jsp</jsp-file>
</servlet>
<!-- map the virtual URL /swing-client.jnlp to the JSP file -->
<servlet-mapping>
<servlet-name>jnlp-gen</servlet-name>
<url-pattern>/swing-client.jnlp</url-pattern>
</servlet-mapping>
代码示例 9:将生成 JNLP 描述符的 JSP 文件映射到 .jnlp 扩展名