java调用.net发布webservice心得

本文分享了作者在Java环境下调用.NET发布的Webservice时的经验,重点讨论了SOAP Header中的安全验证问题。文章提到了使用Axis2和JAX-WS两种方案,并详细阐述了每种方案的步骤、优缺点以及遇到的挑战。对于Axis2,作者介绍了如何生成类文件及调用Webservice服务。而对于JAX-WS,提到了使用wsimport工具生成类文件的方法。最后,作者提到URL Connection作为更原始的调用方式,虽然简单但可能存在更多问题。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

之前做.net,发布、引用webservice很容易,最近转做java,需要调用.net发布的webservice,于是网上找了几种方案,感觉很容易,实则遇到很多困难,放上来分享给大家。

WebService地址:http://localhost:8080/Service.asmx

请求SOAP:

<?xml version="1.0" encoding="utf-8"?>
<soap:Envelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
  <soap:Header>
    <SecurityContext xmlns="http://tempuri.org/">
      <UserName>string</UserName>
      <Password>string</Password>
    </SecurityContext>
  </soap:Header>
  <soap:Body>
    <GetProject xmlns="http://tempuri.org/">
      <strPrjCode>string</strPrjCode>
    </GetProject>
  </soap:Body>
</soap:Envelope>

响应SOAP:

<?xml version="1.0" encoding="utf-8"?>
<soap:Envelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
  <soap:Body>
    <GetProjectResponse xmlns="http://tempuri.org/">
      <GetProjectResult>string</GetProjectResult>
    </GetProjectResponse>
  </soap:Body>
</soap:Envelope>



其中有安全验证是重点,就是这个折腾我好久。请求需要用户名、密码,在SOAP Header里构造。


使用方案:axis2、jax-ws、url connection

一、axis2,用的比较多的方式,功能强大,需要了解详细资料,请自行百度。优点:使用简单,可发布、请求webservice,可以生成类文件,也会生成SOAP header节点安全验证类。缺点:比较重,如果只是请求webservice,不发布,也需要依赖很多第三方jar包。

axis2使用说明:

1、下载地址:http://archive.apache.org/dist/axis/axis2/java/core/1.6.2/axis2-1.6.2-bin.zip

2、生成类文件。axis2提供了一个生成类文件的工具,类似JDK提供的wsimport工具一样,可以根据webservice的WSDL生成类文件,使用这些类,可以像调用本地类一样调用webservice提供的服务。

cmd进入axis2-1.6.2\bin路径,执行wsdl2java -uri http://localhost:8080/Service.asmx?WSDL -p test.webservice -o stub -a -u Unpacks the databinding classes

参数说明:

-uri参数指定发布webservice地址。

-p指定生成的java类的包名。

-o指定生成一系列文件保存的根目录。

-a指定使用异步生成,默认同步生成。

-u Unpacks the databinding classes 避免生成的ServiceStub类特别大。


执行完,在当前目录下多了一个stub目录,可以看到ServiceStub.java,ServiceCallbackHandler.java文件,如果不加-a,不会有callbackHandler类。


3、使用,代码如下:

public String getProject(String projectCode, String userName, String password) {
		try {
			ServiceStub stub = new ServiceStub();
			stub._getServiceClient().getOptions().setProperty(
					org.apache.axis2.transport.http.HTTPConstants.CHUNKED,
					Boolean.FALSE);
			ServiceStub.SecurityContextE securityContextE = new ServiceStub.SecurityContextE();
			ServiceStub.SecurityContext securityContext = new ServiceStub.SecurityContext();
			securityContext.setUserName(userName);
			securityContext.setPassword(password);
			securityContextE.setSecurityContext(securityContext);

			ServiceStub.GetProject getProject = new ServiceStub.GetProject();

			getProject.setStrPrjCode(projectCode);

			String result = stub.getProject(getProject, securityContextE).getGetProjectResult();

			return result;

		} catch (Exception e) {
			logger.error(e.getMessage());
			return null;
		}
	}

maven依赖ar包:

<dependency>
    <groupId>org.apache.axis2</groupId>
    <artifactId>axis2-kernel</artifactId>
    <version>1.6.2</version>
</dependency>
<dependency>
    <groupId>org.apache.axis2</groupId>
    <artifactId>axis2-adb</artifactId>
    <version>1.6.2</version>
</dependency>
<dependency>
    <groupId>org.apache.axis2</groupId>
    <artifactId>axis2-transport-local</artifactId>
    <version>1.6.2</version>
</dependency>
<dependency>
    <groupId>org.apache.axis2</groupId>
    <artifactId>axis2-transport-http</artifactId>
    <version>1.6.2</version>
</dependency>

二、jax-ws,JDK自带类库,无需应用第三方jar包,所以也是最后选择的原因。缺点是构造SOAP Header搞了好久,用wsimport生成的代码,需要修改才好用。不生成类文件,需要构造SOAP Header,不如axis2好用、易用。

首先介绍硬编码,不用生成类文件方式。直接上代码:

<span style="white-space:pre">	</span>private String userName;
	private String password;

	private static String ns = "http://tempuri.org/";
	private static String wsdlUrl = "http://localhost:8080/Service.asmx?WSDL";

	public String getProject(String projectCode, String userName, String password) {
		this.userName = userName;
		this.password = password;
		try {
			Map<String, String> args = new HashMap<>();
			args.put("strPrjCode", projectCode);
			String result = invoke("GetProject", args);
			return result;
		} catch (Exception e) {
			logger.error(e.getMessage());
			return null;
		}
	}

	private SOAPMessage createSoapMessage(String userName, String password, String serviceName, Map<String, ?> args) {
		try {
			// 创建消息工厂
			MessageFactory factory = MessageFactory.newInstance(SOAPConstants.SOAP_1_2_PROTOCOL);
			// 根据消息工厂创建SoapMessage
			SOAPMessage message = factory.createMessage();
			// 创建SOAPPart
			SOAPPart part = message.getSOAPPart();

			// 获取SOAPEnvelope
			SOAPEnvelope envelope = part.getEnvelope();
			// 通过SoapEnvelope可以获取到相应的Body和Header等信息
			SOAPHeader header = envelope.getHeader();
			// 根据Qname创建相应的节点,Qname是一个带有命名空间的节点
			QName securityContext = new QName(ns, "SecurityContext");
			SOAPHeaderElement headerElement = header.addHeaderElement(securityContext);
			headerElement.addChildElement("UserName").setValue(userName);
			headerElement.addChildElement("Password").setValue(password);

			SOAPBody body = envelope.getBody();
			QName function = new QName(ns, serviceName);
			SOAPBodyElement bodyElement = body.addBodyElement(function);
			for (String argName : args.keySet()) {
				bodyElement.addChildElement(argName).setValue(args.get(argName).toString());
			}

			message.setProperty("SOAPAction", ns + serviceName);

			message.saveChanges();

			return message;
		} catch (Exception e) {
			e.printStackTrace();
			return null;
		}
	}

	private String invoke(String serviceName, Map<String, ?> args) {
		try {
			// 创建服务service
			URL url = new URL(wsdlUrl);
			QName sname = new QName(ns, "Service");
			Service service = Service.create(url, sname);

			//创建DIspatch
			Dispatch<SOAPMessage> dispatch = service.createDispatch(new QName(ns, "ServiceSoap12"),
					SOAPMessage.class, Service.Mode.MESSAGE);

			//创建SOAPMessage
			SOAPMessage msg = createSoapMessage(this.userName, this.password, serviceName, args);

			//通过Dispatch传递消息,会返回相应消息
			SOAPMessage response = dispatch.invoke(msg);

			//将相应的消息转换为doc对象
			Document doc = response.getSOAPPart().getEnvelope().getBody().extractContentAsDocument();
			String str = doc.getElementsByTagName(serviceName + "Response").item(0).getTextContent();

			return str;

		} catch (Exception e) {
			e.printStackTrace();
			return null;
		}
	}


注意:使用SOAPMessage构造SOAP Header,在构造时,一定要查看自己的应用webservice的SOAP格式,特别是namespace。


使用wsimport生成类文件方式:

1、在JDK的bin目录下,有wsimport.exe ,这个工具是根据wsdl文件生成相应的类文件。

如果jdk目录已经加入到环境变量,在cmd下执行如下命令:

wsimport -keep -p test.webservice http://localhost:8080/Service.asmx?WSDL

参数说明:

-d:生成客户端执行类的class文件的存放目录

-s:生成客户端执行类的源文件的存放目录

-p:定义生成类的包名

当前目录下会生成test目录,里面生成的文件列表是:

    |--test
      |--webservice
        |--GetProject.java
        |--GetProjectResponse.java
        |--GetProjectXmlSchema.java
        |--GetProjectXmlSchemaResponse.java
        |--ObjectFactory.java
        |--package-info.java
        |--SecurityContext.java
        |--Service.java
        |--ServiceSoap.java

需要改动SecurityContext.java文件才能构造soap header。

@XmlAccessorType(XmlAccessType.FIELD)
@XmlType(name = "SecurityContext", propOrder = {
		"userName",
		"password"
})
@XmlRootElement(name="SecurityContext")//添加这行,这行不会生成
public class SecurityContext {

	@XmlElement(name = "UserName", namespace = "http://tempuri.org/")//namespace不会生成
	protected String userName;
	@XmlElement(name = "Password", namespace = "http://tempuri.org/")<span style="font-family: Arial, Helvetica, sans-serif;">//namespace不会生成</span>
	protected String password;
	@XmlAnyAttribute
	private Map<QName, String> otherAttributes = new HashMap<QName, String>();
</pre><pre name="code" class="java">...

请求webervice:

	public String getProject() {
		try {
			test.webservice.Service service1 = new test.webservice.Service();
			ServiceSoap soap = service1.getServiceSoap();

			WSBindingProvider provider = (WSBindingProvider) soap;

			SecurityContext sc = new SecurityContext();
			sc.setUserName(userName);
			sc.setPassword(password);
			provider.setOutboundHeaders(sc);

			String result = soap.getProject(projectCode);

			return result;
		} catch (Exception e) {
			logger.error(e.getMessage());
			return null;
		}
	}


URL Connection我没有试,直接拼soap内容,太矬了,不过越是原始的东西,越容易做,不会像上面两种方案,碰到好多坑,解决起来很头疼。


好了,就到这里吧,不会的执行研究吧,研究的越多,对自己的成长越有好处.




评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值