webservices的开源组件很多,这里我们选用的是MyEclipse集成的一个组件xfire,利用这个组件的最大好处就是配置简单,而且功能也十分的强大。
在很多行业软件开发中用到的都是1.4的JDK,所以要求组件一定要支持。下面我就使用xfire+weblogic 8.x 开发做一个使用介绍。
XFire是codeHaus组织提供的一个开源框架,它构建了POJO和SOA之间的桥梁,主要特性就是支持将POJO通过非常简单的方式发布成Web服务,这种处理方式不仅充分发挥了POJO的作用,简化了Java应用转化为Web服务的步骤和过程,也直接降低了SOA的实现难度,用过xfire的朋友一定会这样的感触,对于xfire的基本配置及调用方式已经很多的相关文章,这里主要对xfire的权限管理的实现做一下详细的讲解。
下面是我的包结构

首先,我们就开始讲解怎样实现一个webservice;再讲解,怎样用xfire进行用户的权限验证和获取客户端IP进行验证;最后讲解怎么把webservices整合到我们的项目中去。
第一步:实现一个简单的webservices
在MyEclipse里怎么建立一个xfire webservices工程,这个在我的资源里有对应的视频,如果看下面的内容看不太懂的话建议先下载视频看看。
服务器端代码:
package helloword; import java.util.ArrayList; import java.util.List; public class HelloWordwebservicesImpl implements IHelloWordwebservices { public String example(String message) { return "w de :"+message; } public List getList(String message) { List list = new ArrayList(); String aaString = "a"+message; list.add(aaString); list.add("b"+message); list.add("c"+message); list.add("d"+message); return list ; } }
package helloword; import java.util.List; //Generated by MyEclipse public interface IHelloWordwebservices { public String example(String message); public List getList(String message); }
利用工具生成客户端的时候,会生成泛型来获取参数,但在JDK1.4下并不支持泛型,于是可以采用aegis绑定方法配置
方法是在接口类同目录下建一个文件名为 接口类名+.aegis.xml的文件,如下
IHelloWordwebservices.aegis.xml文件如下:
<?xml version="1.0" encoding="UTF-8"?> <mappings> <mapping> <method name="getList"> <parameter index="0" componentType="java.lang.String" /> <return-type componentType="java.lang.String" /> </method> </mapping> </mappings>
其中,method代表需要配置的方法名,由于XFire可以支持基本类型,针对集合类型时,需要配置,返回类型或参数类型为基本类型时不需要特殊配置。
<return-type/>为配置返回类型,componentType属性代表返回的集合中所包含的类,此类可以是自定义的对象,也可以是基本类型,例如java.lang.String
index="0"代表方法的参数的序号,0即第一个参数。 当参数为基本类型时可以不用配置
componentType代表集合参数内包含的类型,也可以为自定义对象
web.xml
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE web-app PUBLIC "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN" "http://java.sun.com/dtd/web-app_2_3.dtd"> <web-app id="WebApp_ID"> <servlet> <servlet-name>XFireServlet</servlet-name> <servlet-class>org.codehaus.xfire.transport.http.XFireConfigurableServlet</servlet-class> <load-on-startup>0</load-on-startup> </servlet> <servlet-mapping> <servlet-name>XFireServlet</servlet-name> <url-pattern>/services/*</url-pattern> </servlet-mapping> <welcome-file-list> <welcome-file>index.jsp</welcome-file> </welcome-file-list> </web-app>
services.xml
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://xfire.codehaus.org/config/1.0"> <xfire> <inHandlers> <handler handlerClass="services.jdqb.Test"> </handler> </inHandlers> </xfire> <service> <name>HelloWordwebservices</name> <serviceClass>helloword.IHelloWordwebservices</serviceClass> <implementationClass> helloword.HelloWordwebservicesImpl </implementationClass> <mce:style><!-- wrapped --></mce:style><style mce_bogus="1">wrapped</style> <use>literal</use> <scope>application</scope> </service></beans>
到此服务器端就写完了。
部署到weblogic上,注意现在服务器配置才刚刚开始,如果不配置的话在tomcat上可以正常运行的的,但在weblogic上就会报错。
第一个可能的错误DTD解析错误
weblogic8.1的版本,只支持jdk1.4和servlet2.3的规范,在web.xml的配置文件中需要将Myeclipse工具默认生成的
<web-app version="2.4" xmlns="http://java.sun.com/xml/ns/j2ee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd">
改为:
<!DOCTYPE web-app PUBLIC "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN" "http://java.sun.com/dtd/web-app_2_3.dtd"> <web-app id="WebApp_ID">
再启动就不会包DTD解析错误了
第二个错误,将下载的xfire jar包导入lib,启动weblogic可能会报QName异常,结果到官方网站又去下了个QName.jar包,解压后把qname.class文件覆盖到weblogic路径 d:/bea/weblogic81/server/lib中有个weblogic.jar包,解压后可以看到javax.xml.namespace文件夹下也有个QName.class,我把这两个class反编译后看到原来weblogic.jar中的这个类的放在QName.jar包中都有,所以把QName.jar包中的QName.class覆盖过去,QName Exception排除
第三:在Xfire1.2.6类中有依赖到spring包中的类,所以xfire还需要spring-1.2. 6和xben-spring-2.8的jar包,不然会报springframework的异常错误,因为services.xml文件中节点的读取需要依赖spring。(这个在建立工程的时候选择xfire 1.2Core 和心包时里面已经包含了spring的两个包,所以这个问题一般不会遇到,遇到的话就看看xfire 1.2Core 里有没包含,没有的话再加进去就ok了)
最后注意用JDK1.4编译运行哦。
到此服务器全部搞定,在ie输入http://127.0.0.1:7001/webservices/services/Interface?wsdl就可以访问了哦,显示xml结构页面说明接口访问成功。
客户端的开发
现在开始客户端的开发,客户端可以利用xfire wsdl 的url来生成,但生成的默认文件使用的是泛型,我们的JDK1.4是不支持的,所以最好还是手动的编写客户端吧,代码如下:
package webservicesclient; import java.net.URL; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; import org.apache.crimson.tree.XmlDocument; import org.codehaus.xfire.client.Client; import org.w3c.dom.*; public class WebServices { public static void main(String[] args) throws Exception { /** * 调用接口创建Client */ Client client = new Client( new URL( "http://127.0.0.1:7001/jdqb/services/JdqbInterface?wsdl")); /** * 调用接口方法(getList就是我们接口中定义的) */ Object[] results = client.invoke("getList", new String[] { "0020100400000009" }); /** * 得到了返回的数据文件,数据被封装在了一个XmlDocument里 * ,获得XmlDocument后可以对XmlDocument进行解析得到目标文件, * 具体的解析XmlDocument的方法很多就不啰嗦了 */ XmlDocument doc = (XmlDocument) results[0]; } }
客户端编写完成,注意把客户端jar包导入到lib,所有jar包在我的资源了下载
XFire 通过 继承AbstractHandler 实现安全验证
WebSerice是一种开放的web服务,任何人都可以访问,但我们有时候需要考虑只有付费用户才能使用WS,所以,我们就需要对WS加入安全验证机制,当然,可以利用防火墙的IP过滤,web应用的配置从最外层去隔离非法用户,但在内层,我们也可以使用SOAP Header的方式,由客户端发送验证数据,服务端验通过后基WS访问权限。(拦截器)
首先,编写服务端验证类继承AuthenticationHandler
import javax.servlet.http.HttpServletRequest; import org.codehaus.xfire.MessageContext; import org.codehaus.xfire.handler.AbstractHandler; import org.codehaus.xfire.transport.http.XFireServletController; import org.jdom.Element; public class AuthenticationHandler extends AbstractHandler{ public void invoke(MessageContext cfx) throws Exception { /** * 获得HttpServletRequest对象 */ HttpServletRequest request = XFireServletController.getRequest(); /** * 获得客户端IP */ String ip = request.getRemoteAddr(); System.out.println( "remote ip: " + ip); if(cfx.getInMessage().getHeader() == null) { throw new org.codehaus.xfire.fault.XFireFault("请求必须包含验证信息",org.codehaus.xfire.fault.XFireFault.SENDER); } Element token=cfx.getInMessage().getHeader().getChild("AuthenticationToken"); if (token == null) { throw new org.codehaus.xfire.fault.XFireFault("请求必须包含身份验证信息", org.codehaus.xfire.fault.XFireFault.SENDER); } String username = token.getChild("Username").getValue(); String password = token.getChild("Password").getValue(); try { //进行身份验证 ,只有abcd@1234的用户为授权用户 if(username.equals("abcd") && password.equals("1234")) //这语句不显示 System.out.println("身份验证通过"); else throw new Exception(); } catch (Exception e) { throw new org.codehaus.xfire.fault.XFireFault("非法的用户名和密码", org.codehaus.xfire.fault.XFireFault.SENDER); } } }
接着,在客户端编写类ClientAuthenticationHandler继承AbstractHandler
import org.codehaus.xfire.MessageContext; import org.codehaus.xfire.handler.AbstractHandler; import org.jdom.Element; public class ClientAuthenticationHandler extends AbstractHandler { private String username = null; private String password = null; public ClientAuthenticationHandler() { } public ClientAuthenticationHandler(String username,String password){ this.username = username; this.password = password; } public void setUsername(String username) { this.username = username; } public void setPassword(String password) { this.password = password; } public void invoke(MessageContext context) throws Exception { //为SOAP Header构造验证信息 Element el = new Element("header"); context.getOutMessage().setHeader(el); Element auth = new Element("AuthenticationToken"); Element username_el = new Element("Username"); username_el.addContent(username); Element password_el = new Element("Password"); password_el.addContent(password); auth.addContent(username_el); auth.addContent(password_el); el.addContent(auth); } }
然后,在调用WebService的客户端中加入如下代码
client.addOutHandler(new ClientAuthenticationHandler("abcd","1234"));
加入权限后代码如下:
import java.net.URL;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.apache.crimson.tree.XmlDocument;
import org.codehaus.xfire.client.Client;
import org.w3c.dom.*;
public class WebServices {
public static void main(String[] args) throws Exception {
/**
* 调用接口创建Client
*/
Client client = new Client(
new URL(
"http://127.0.0.1:7001/jdqb/services/JdqbInterface?wsdl"));
client.addOutHandler(new ClientAuthenticationHandler("abcd","1234"));
/**
* 调用接口方法(getList就是我们接口中定义的)
*/
Object[] results = client.invoke("getList",
new String[] { "0020100400000009" });
/**
* 得到了返回的数据文件,数据被封装在了一个XmlDocument里
* ,获得XmlDocument后可以对XmlDocument进行解析得到目标文件,
* 具体的解析XmlDocument的方法很多就不啰嗦了
*/
XmlDocument doc = (XmlDocument) results[0];
同时修改services.xml,绑定Handler
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://xfire.codehaus.org/config/1.0">
<xfire>
<inHandlers>
<handler handlerClass="services.jdqb.Test">
</handler>
</inHandlers>
</xfire>
<service>
<name>HelloWordwebservices</name>
<serviceClass>helloword.IHelloWordwebservices</serviceClass>
<implementationClass>
helloword.HelloWordwebservicesImpl
</implementationClass>
<inHandlers>
<handler handlerClass ="services.AuthenticationHandler" ></handler>
</inHandlers>
<style>wrapped</style>
<use>literal</use>
<scope>application</scope>
</service></beans>
权限控制开发完毕,使用abcd@1234,可以正常访问WS,如果用错误帐号,则会报异常
使用abcd@1234,可以正常访问WS,如果用错误帐号,则会报异常
xfire与web项目整合
xfire集成到项目中,有几个注意点:
第一、在web.xml添加xfire servlet;
第二、将META-INF/xfire/services.xml中要对外发布的web service类配置好;
第三、把META-INF目录移到src下;
第四、发布到应用服务器上;
所需jar包下载连接:
第五、将web工程原有的META-INF文件夹删除,保留web-inf/classes里的META-INF,整合完成。
816

被折叠的 条评论
为什么被折叠?



