java_webservice_jaxws_服务端_客户端

之前项目需要与客户方进行接口交接,选择了webservice接口。这里记录下如何创建服务端,客户端。

  • 服务端
    关于发布webservice,其实主要使用了javax.xml.ws.Endpoint类提供的静态方法publish进行发布,但形式可以使用多种方式,比如:
    ①通过一个类的main方法+publish方法

    ②BS项目中的使用Servlet3.0提供的@WebListener注解将实现了ServletContextListener接口的WebServicePublishListener类标注为一个Listener

    ③通过servlet的init()方法,且在注解中@webService设置loadOnStartup=0:@WebServlet(value="",loadOnStartup=0)意思就是启动服务器是首先启动。

在项目中我主要采用的是第三种方式,通过init()在初始化servlet的时候就发布webService接口。
定义一个主类,里面是对外公布的public接口方法:

package test;

import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.xml.ws.Endpoint;


@WebServlet(value="",loadOnStartup=0)
public class publishWS extends HttpServlet {
	private static final long serialVersionUID = 1L;
       
    /**
     * @see HttpServlet#HttpServlet()
     */
    public publishWS() {
          super();
        // TODO Auto-generated constructor stub
    }
    
    public void init() throws ServletException {
        //自定义服务器端接口地址,如果是本地的话,ip需要自己查,后面的路径是自己
        //来定义,这里最好做成xml配置文件来取,部署的时候方便
        String Address = "http://192.168.103.145:9527/Service/Contract/WebService";
        //publish第二个参数是我们的实现类
        Endpoint.publish(Address , new mainInterface());
        System.out.println("webService接口发布成功!");
	 }
}

主要对外接口方法,需要注解@WebService

package test;

import javax.jws.WebService;

@WebService
public class mainInterface {

	public String func1(String xx...) {
		return 
	}
	

	public String func2(String xx ...) {
	    return 
	}
	
	public String func3(String xx...) {
		return 
	}
}
  • 更新20190121(今天客户那边要求加入安全验证性,发现上面那个例子不好用,上面虽然能调用但是其他事情不友好,下面更改了一版)
    创建一个接口 mainInterface.class
package test;

import javax.jws.HandlerChain;
import javax.jws.WebService;

import org.json.JSONException;

@WebService
@HandlerChain(file="handler-chain.xml")
public interface mainInterface {
	public String func1;
	
	public String func2;
	
	public String func3;
}

在创建一个类切实现这个接口 mainImplement.class

package test;

import javax.jws.HandlerChain;
import javax.jws.WebService;

import org.json.JSONException;

@WebService
@HandlerChain(file="handler-chain.xml")
public class mainImplatement implements mainInterface {

	@Override
	public String func1() {
		// TODO Auto-generated method stub
		
	}

	@Override
	public String func2() {
		// TODO Auto-generated method stub
	}

	@Override
	public String func3() {
		// TODO Auto-generated method stub
	}

}

  • 如何在服务器端添加安全验证?
    利用注解@HandlerChain(file=“handler-chain.xml”),且在classpath路径下(一般在WEB-INF下的classes里面),创建handle-chain.xml
<?xml version="1.0" encoding="UTF-8"?>
<javaee:handler-chains xmlns:javaee="http://java.sun.com/xml/ns/javaee"
	xmlns:xsd="http://www.w3.org/2001/XMLSchema">
	<javaee:handler-chain>
		<javaee:handler>
			<javaee:handler-class>test.validateAuthHeader</javaee:handler-class>
		</javaee:handler>
	</javaee:handler-chain>
</javaee:handler-chains>

validateAuthHeader.class

package test;

import java.util.Iterator;
import java.util.Set;

import javax.xml.namespace.QName;
import javax.xml.soap.SOAPBody;
import javax.xml.soap.SOAPElement;
import javax.xml.soap.SOAPEnvelope;
import javax.xml.soap.SOAPException;
import javax.xml.soap.SOAPFault;
import javax.xml.soap.SOAPHeader;
import javax.xml.soap.SOAPMessage;
import javax.xml.ws.handler.MessageContext;
import javax.xml.ws.handler.soap.SOAPHandler;
import javax.xml.ws.handler.soap.SOAPMessageContext;

public class validateAuthHeader implements SOAPHandler<SOAPMessageContext> {
	@Override
	public boolean handleFault(SOAPMessageContext context) {
		// TODO Auto-generated method stub
		return false;
	}

	@Override
	public void close(MessageContext context) {
		// TODO Auto-generated method stub
		
	}

	@Override
	public Set<QName> getHeaders() {
		// TODO Auto-generated method stub
		return null;
	}
	
	@Override
	public boolean handleMessage(SOAPMessageContext context) {
		// TODO Auto-generated method stub
		
		//判断消息是请求还是响应
		Boolean output = (Boolean) context.get(MessageContext.MESSAGE_OUTBOUND_PROPERTY);
		
		Boolean result = false;
		
		SOAPMessage message = context.getMessage();
		
		if(!output) {
			result = validateSuccess(message);
			if(!result) {
				validateFail(message);
			}
		}
		
		//System.out.println(output ? "服务端响应:" : "服务端接收:");
		try {
			message.writeTo(System.out);			
		} catch (Exception e) {
			e.printStackTrace();
		}
		
		System.out.println("\r\n");
 
		return result;
	}

	
	
	//成功验证
	private boolean validateSuccess(SOAPMessage message) {
		boolean result = false;
		try {
			SOAPEnvelope envelop = message.getSOAPPart().getEnvelope();
			SOAPHeader header = envelop.getHeader();
			
			if(header != null){
				Iterator iterator = header.getChildElements(new QName("http://www.tmp.com/auth", "auth"));
				SOAPElement auth = null;
				
				if(iterator.hasNext()){
					//获取auth
					auth = (SOAPElement)iterator.next();
					
					//获取username
					Iterator it = auth.getChildElements(new QName("http://www.tmp.com/auth", "username"));
					SOAPElement username = null;
					if(it.hasNext()){
						username = (SOAPElement)it.next();
					}
					
					//获取password
					it = auth.getChildElements(new QName("http://www.tmp.com/auth", "password"));
					SOAPElement password = null;
					if(it.hasNext()){
						password = (SOAPElement)it.next();
					}
					
					//判断username和password是否符合要求
					if(username != null && password != null && "admin".equals(username.getValue()) && "admin".equals(password.getValue())){
						result = true;
					}
				}
			}
			
		} catch (SOAPException e) {
			e.printStackTrace();
		}
		
		return result;
	}
	
	//失败验证
	private void validateFail(SOAPMessage message) {
		try {
			SOAPEnvelope envelop = message.getSOAPPart().getEnvelope();
 
			envelop.getHeader().detachNode();
			envelop.addHeader();
 
			envelop.getBody().detachNode();
			SOAPBody body = envelop.addBody();
 
			SOAPFault fault = body.getFault();
 
			if (fault == null) {
				fault = body.addFault();
			}
 
			fault.setFaultString("用户名密码验证失败 请重新输入");
 
			message.saveChanges();
		} catch (SOAPException e) {
			e.printStackTrace();
		}
	}
}

添加上服务器端的安全验证后,那么客户端的soap请求头中必须包含如下:

	<soapenv:Header>
		<auth xmlns="http://www.tmp.com/auth">
			<username>admin</username>
			<password>admin</password>
		</auth>
	</soapenv:Header>

在这里插入图片描述
在浏览器中输入url地址:
在这里插入图片描述
查看接口的报文格式:
在这里插入图片描述
这里我使用的soapUI这款软件,加载带wsdl的报文地址,可以看到接口的方法及它request请求的soap格式,可以用来测试接口:
在这里插入图片描述

  • 客户端
    一般对方接口人员也会给你个webService地址,此时我们可以查看带?wsdl的url来查看它的报文xml结构,里面会显示对方公布的方法。生产客户端代码的方式有很多种,比如jdk自带的wsimport,apache cxf等,项目里我选择了jdk这种方式:
wsimport -d '指定生成代码的路径' -keep '对方的webservice地址+?wsdl'

个别参数含义:
-d : 表示输出的目录,目录必须事先存在,否则导出失败
-keep : 表示生成客户端执行类的源代码
-p : 定义客户端生成类的包名称
-s : 指定客户端执行类的源文件存放目录
-b : 指定jaxws/jaxb绑定文件或额外的schemas
-verbose : verbose表示详细信息
-extension : 使用扩展来支持SOAP1.2

这里再记录下,当时对方的接口需要权限认证,就是要求用户名,密码,但是我生成的代码里面没有设置这类的方法,后面查询了很多资料,需要重写指定方法:

//这里的xxx 类是根据wsdl自动解析生成的
xxx xx= new xxx();
		xx.setHandlerResolver(new HandlerResolver() {
			@Override
			public List<Handler> getHandlerChain(PortInfo arg0) {
				List<Handler> handlerList = new ArrayList<Handler>();
				// 添加认证信息
				handlerList.add(new setHeader());
				return handlerList;
			}
		});

setHeader.class

package test;

import java.util.Set;

import javax.xml.namespace.QName;
import javax.xml.soap.SOAPElement;
import javax.xml.soap.SOAPEnvelope;
import javax.xml.soap.SOAPHeader;
import javax.xml.soap.SOAPHeaderElement;
import javax.xml.soap.SOAPMessage;
import javax.xml.ws.handler.MessageContext;
import javax.xml.ws.handler.soap.SOAPHandler;
import javax.xml.ws.handler.soap.SOAPMessageContext;

public class setHeader implements SOAPHandler<SOAPMessageContext> {

	@Override
	public void close(MessageContext arg0) {
		// TODO Auto-generated method stub

	}

	@Override
	public boolean handleFault(SOAPMessageContext arg0) {
		// TODO Auto-generated method stub
		return false;
	}

	@Override
	public boolean handleMessage(SOAPMessageContext ctx) {
		// TODO Auto-generated method stub
		
		// 出站,即客户端发出请求前,添加表头信息
		Boolean request_p = (Boolean) ctx.get(MessageContext.MESSAGE_OUTBOUND_PROPERTY);
		if (request_p) {
			try {
				SOAPMessage msg = ctx.getMessage();
				SOAPEnvelope env = msg.getSOAPPart().getEnvelope();
				SOAPHeader hdr = env.getHeader();
				if (hdr == null)
					hdr = env.addHeader();

				// 添加认证信息头
				QName name = new QName(
						"http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd",
						"Security", "wsse");
				SOAPHeaderElement header = hdr.addHeaderElement(name);
				SOAPElement UsernameToken = header.addChildElement("UsernameToken", "wsse");
				SOAPElement userElement = UsernameToken.addChildElement("Username", "wsse");
				userElement.addTextNode("你的用户名");
				SOAPElement passElement = UsernameToken.addChildElement("Password", "wsse");
				passElement.addTextNode("你的密码");

				msg.saveChanges();

				// 把SOAP消息输出到System.out,即控制台
				//msg.writeTo(System.out);

				return true;
			} catch (Exception e) {
				e.printStackTrace();
			}
		}
		return false;
	}

	@Override
	public Set<QName> getHeaders() {
		// TODO Auto-generated method stub
		return null;
	}
}

其余的就是根据实际业务来进行编码。对于webservcie还有很多方法可以实现,这里我只是简单记录下自己在项目中使用到的几点。但是我感觉这种根据别人的wsdl地址来生成代码很受限制,如果对方更改了webservice地址或者接口 方法我都需要重新切生成一遍,可能是我不清楚或者还没找到合适的方式来适应这种,都是这种笨办法重新生成。

参考资料:
初识webservice

添加安全认证

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
Java WebService 简单实例 http://blog.csdn.net/kingmax54212008/article/details/49764401 前言:朋友们开始以下教程前,请先看第五大点的注意事项,以避免不必要的重复操作。 一、准备工作(以下为本实例使用工具) 1、MyEclipse10.7.1 2、JDK 1.6.0_22 二、创建服务端 1、创建【Web Service Project】,命名为【TheService】。 2、创建【Class】类,命名为【ServiceHello】,位于【com.hyan.service】包下。 3、编写供客户端调用的方法,即编译方法代码。 4、进行编译 说明:编译失败的话,请将该项目引用的jdk设置为1.6.0_17版本或更高版本 5、测试结果 测试地址:http://localhost:9001/Service/ServiceHello?wsdl 三、生成客户端 1、创建【Web Service Project】,命名为【TheClient】。 2、命令提示窗口执行生成命令。 格式:wsimport -s "src目录" -p “生成类所在包名” -keep “wsdl发布地址” 示例: wsimport -s G:\\workspace\\webService\\TheClient\\src -p com.hyan.client -keep http://localhost:9001/Service/ServiceHello?wsdl 说明: 1)"src目录"地址不可含空格 2)“wsdl发布地址”不要漏了“?wsdl” 3、刷新项目,检查生成类 四、最终测试 1、创建【Class】类,命名为【ServiceTest】,位于【com.hyan.test】包下。 2、编写测试方法,调用服务端方法,并打印返回的结果。 五、注意事项 1、JDK版本过低问题 报类似如下的异常:runtime modeler error: Wrapper class com.hyan.service.jaxws.GetValue is not found. Have you run APT to generate them? 原因:JDK版本低于1.6.0_17 解决方法:调整该服务端项目所引用的JDK版本为安装的高版本JDK

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值