Webservice之实现

<pre name="code" class="java">

webservice定义了一种不同系统之间功能调用的标准,也就是RPC调用。在j2ee中,ejb提供了这种分布式的RPC,原理是用jndi发布ejb远程无状态bean,客户端得到bean的引用完成方法调用,这种方式对于同是java系统的调用非常的方便,但对于异构系统的访问就非常的不便,特别是在互联网中,基于ejb调用的sockect连接可能无法穿过企业防火墙以完成方法的调用。

  webservice提供了一种标准的不同系统之间的调用,基于soap协议,底层可以选用http传输协议(可以穿过防火墙),而且中间信息传递是 xml格式的,消息体的打包和解析十分的方便,可以说ws就是基本于xml、http的远程RPC调用。

  java下常用的ws框架有axis2、xfire等,xfire已经升级为cxf,相对axis来说要,使用要简单得多,而且cxf与spring集成非常的紧密,下面我以具体实例来建立ws服务器,并写出了在cxf,axis以及php中的调用示例,本文中的示例可直接应用于生产环境。

  首先写出ws的接口,这里要用到外观模式。

1
2
3
4
5
6
7
@WebService
public interface IWebServiceFacade {
  public String sayHello(@WebParam(name="uname")String name);
  public User getFirstUserByParent(@WebParam(name="userParam")User u);
  public @WebResult(partName="users")List getAllUsers();
  public int add(@WebParam(name="num1")String number1, @WebParam(name="num2")int number2);
}

  为了让示例具有通用性,我定义了一些典型的方法,比如:方法接收对象类型参数,返加对象类型结果,返回集合类型结果,有两个参数的情况等等。

  该接口的实现代码如下(注意,bizService由spring注入):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
@WebService(endpointInterface="com.my.webservice.IWebServiceFacade")
public class WebServiceFacadeImpl implements IWebServiceFacade {
  //本地业务接口
  private IBizService bizService;
  @Override
  public String sayHello(String name) {
      return "Hello," + name;
  }
  public int add(String number1, int number2) {
      return (Integer.parseInt(number1) + number2);
  }
  @Override
  public List getAllUsers() {
      //此处应调用 bizService方法完成,作为示例,我直接返回模拟数据
      List users = new ArrayList();
      users.add(new User(1,"张三"));
      users.add(new User(2,"李四"));
      users.add(new User(3,"王五"));
      return users;
  }
  @Override
  public User getFirstUserByParent(User u) {
      //此处应调用 bizService方法完成,作为示例,我直接返回模拟数据
      System.out.println("example param user ,name is" + u.getUserName() + ", birth is:" + u.getBirthday().toLocaleString());
      return new User(1,u.getUserName() + "--admin");
  }
}

  至此,服务器端的代码已经完成了,但还需要一定的配置,在服务器上的配置代码片断如下(web.xml):

web.xml
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<servlet>
  <servlet-name>CXFServlet</servlet-name>
  <servlet-class>org.apache.cxf.transport.servlet.CXFServlet</servlet-class>
  <load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
  <servlet-name>CXFServlet</servlet-name>
  <url-pattern>/services/*</url-pattern>
</servlet-mapping>
<listener>
  <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<context-param>
  <param-name>contextConfigLocation</param-name>
  <param-value>/WEB-INF/classes/app_ws_server.xml</param-value>
</context-param>

  app_ws_server.xml中(这是一个spring配置文件),关键配置代码如下:

app_ws_server.xml
1
2
3
4
5
<import resource="classpath:META-INF/cxf/cxf.xml" />
<import resource="classpath:META-INF/cxf/cxf-extension-soap.xml" />
<import resource="classpath:META-INF/cxf/cxf-servlet.xml" />
<jaxws:endpoint id="myWebService" address="/myWebService"        implementor="com.my.webservice.WebServiceFacadeImpl">
</jaxws:endpoint>

  重新启动服务器,如果一切正常的话,在浏览器地址栏中输入http://localhost:8088/web_service_server/services/myWebService?wsdl就可以看到wsdl文件,有了wsdl,其它客户端的调用将不存在问题。

  下面,我将写出不同客户端对上面的ws调用代码

  最为简单的是cxf自己的客户端调用方式,先写一篇spring配置文件,将要调用的客户端写入:

ws-client.xml
1
2
3
4
5
6
7
8
<bean id="wsClient" class="com.my.webservice.IWebServiceFacade"
  factory-bean="wsClientProxy" factory-method="create" />

<bean id="wsClientProxy" class="org.apache.cxf.jaxws.JaxWsProxyFactoryBean">
  <property name="serviceClass" value="com.my.webservice.IWebServiceFacade" />
  <property name="address"
      value="http://localhost:8088/web_service_server/services/myWebService" />
</bean>

  cxf的测试代码如下,wsClient由测试框架自动注入,这种方式应该是在java下调用ws服务最简单的方法,和本地方法调用没有任何区别。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
public class WebServiceTest extends
      AbstractDependencyInjectionSpringContextTests {

  private IWebServiceFacade wsClient;

  public void testSayHello() {

      System.out.println("====================");

      String result = wsClient.sayHello("lovo");

      System.out.println(result);

      System.out.println("add:" + wsClient.add("5", 3));

      User u = wsClient.getFirstUserByParent(new User(1,"刘江华"));

      System.out.println(u.getUserName());

      List<User> users = wsClient.getAllUsers();

      System.out.println("users List size: " + users.size());
      System.out.println(users.get(0).getUserName() );
      System.out.println(users.get(0).getBirthday());

  }

  @Override
  protected String[] getConfigLocations() {
      setAutowireMode(AUTOWIRE_BY_NAME);
      return new String[]{"classpath:ws-client.xml"};
  }

  public void setWsClient(IWebServiceFacade wsClient) {
      this.wsClient = wsClient;
  }

}

  鉴于axis使用比较广泛,我写出了相应的调用代码,axis下调用代码相对来说要繁琐些,特别要注意在传对象参数时需要call.setProperty(AxisEngine.PROP_DOMULTIREFS, false),关闭multirefs的生成(通过http抓包工具可以观察向服务器提交的请求),调用代码示例如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
String endpoint = "http://localhost:8088/web_service_server/services/myWebService";

      Service service = new Service();

      //测试sayHello
      Call call = (Call) service.createCall();

      call.setTargetEndpointAddress(new java.net.URL(endpoint));

      call.setOperationName(new QName("http://webservice.my.com/", "sayHello"));

      call.addParameter("uname", XMLType.SOAP_STRING, ParameterMode.IN);
      call.setReturnType(XMLType.SOAP_STRING);
      String result = (String) call.invoke(new Object[] {"good"});
      System.out.println(result);

      //测试add
      call = (Call) service.createCall();
      call.setTargetEndpointAddress(new java.net.URL(endpoint));

      call.setOperationName(new QName("http://webservice.my.com/", "add"));

      call.addParameter("num1", XMLType.SOAP_STRING, ParameterMode.IN);
      call.addParameter("num2", XMLType.SOAP_INT, ParameterMode.IN);
      call.setReturnType(XMLType.SOAP_INT);
      //参数顺序和addParameter一致
      int r = (Integer) call.invoke(new Object[] {"5", "3"});
      System.out.println(r);

      //测试得到所有用户
      call = (Call) service.createCall();
      call.setTargetEndpointAddress(new java.net.URL(endpoint));

      call.setOperationName(new QName("http://webservice.my.com/", "getAllUsers"));


      call.setReturnType(org.apache.axis.encoding.XMLType.SOAP_VECTOR);
      Vector v = (Vector) call.invoke(new Object[] {});

      for (int i = 0; i< v.size(); i++) {
          Vector v2 = (Vector)v.get(i);
          for (int j = 0; j < v2.size(); j++) {
              System.out.print(v2.get(j) + "  ");
          }
          System.out.println();
      }

      //传入用户对象,得到一个用户
      call = (Call) service.createCall();
      call.setTargetEndpointAddress(new java.net.URL(endpoint));

      call.setOperationName(new QName("http://webservice.my.com/", "getFirstUserByParent"));

      QName qn = new QName("http://webservice.my.com/", "user" );

      call.addParameter("userParam",qn, ParameterMode.IN);

      call.setProperty(AxisEngine.PROP_DOMULTIREFS, false);

      call.registerTypeMapping(User.class, qn, new BeanSerializerFactory(User.class, qn), null);

      call.setReturnType(org.apache.axis.encoding.XMLType.SOAP_VECTOR);

      User u = new User(1," 刘江华 ");

      v = (Vector) call.invoke(new Object[] {u});

      System.out.println(v);

  最后,给出非java系统的一个客户端调用示例,php的调用代码如下(要注意,php默认情况下没有开启对soap的支持,需求修改php的配置文件):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
<?php
$ws = "http://localhost:8088/web_service_server/services/myWebService?wsdl";
$client = new SoapClient($ws, array ('trace' => 1, 'uri' => 'http://webservice.my.com/' ));

echo("sayHello ws call:");
print_r( $client->sayHello(array('uname'=>'ljh')));
echo("<br><br>");
echo("add ws call: ");
print_r( $client->add(array('num1'=>5,'num2'=>3)));

echo("<br><br>");
echo("getAllUsers ws call: ");
print_r( $client->getAllUsers());


echo("<br><br>");
echo("getFirstUserByParent ws call: ");

$aUser = array();
$aUser['id']=1;
$aUser['userName']='刘江华';
$aUser['birthday']=date("Y-m-d");

print_r($client->getFirstUserByParent(array('userParam'=>$aUser)));

?>

  在客户端的调用中我们可以发现,php对ws的调用是相当的简单(请注意在构建SoapClient对象时传入了wsdl的路径,php就是根据wsdl来发送和接收服务器端数据的),正是由于这些原因,php在建站中被广泛使用(入门门槛比较低)。



                
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值