基于Jax-WS和Mysql数据库的WEB服务开发
1 简介
近几年来,SOA,EAI等架构体系的日渐成熟,Webservice越来越炽手可热,尤其是在企业做异质平台整合时成为了首选的技术。Java的Webservice技术更是层出不穷,比较流行的有:Axis2,XFire以及JaxWS。
JAXWS适合几乎所有Webservice客户端的调用,因此不少巨头型的厂商如:IBM,Weblogic等,在他们的产品上都使用了以JAXWS为标准的Webservice接口。
另外,由于实验室的项目目前采用JaxWS作为Wevservice框架,同时JaxWS也是目前最标准,需要额外第三方插件最少,配置最少最灵活的webservice,故对其进行研习。
2 案例驱动学习
编写查询员工信息的Web服务(员工信息存储在数据库中)。
第一个Web服务:输入员工号,返回该员工号的员工的基本信息,包括员工号、员工名称、所在部门、出生日期、职位、职称、入职日期等信息。
第二个Web服务:输入部门、职称,返回该部门具有该职称的所有员工的基本信息,员工基本信息与上面相同。分别针对上述两个Web服务,分别编写调用这两个Web服务的程序(或网页)。
要求在输入界面上输入待查询数据,调用Web服务,并将Web服务返回的员工信息查询结果显示到输出界面上。
数据库表:
属性 | 含义 | 数据类型 |
---|---|---|
ID | 员工号 | Int(11) |
name | 员工名 | Varchar(20) |
dept | 部门 | Varchar(20) |
title | 职称 | Varchar(20) |
position | 职位 | Varchar(20) |
birthday | 出生日期 | Varchar(20) |
dateIn | 入职日期 | Varchar(20) |
这样的web服务如何用jax-ws实现呢?
3 开发流程
我们使用JAX-WS开发WebService只需要很简单的几个步骤:写接口和实现=>发布=>生成客户端(测试或使用)。
而在开发阶段我们也不需要导入外部jar包,因为这些api都是现成的。首先是接口的编写(接口中只需要把类注明为@WebService,把要暴露给客户端的方法注明为@WebMethod即可,其余如@WebResult、@WebParam等都不是必要的,而客户端和服务端的通信用RPC和Message-Oriented)。
开发采用Eclipse Indigo和JDK6
4 服务端开发
JAVA JDK1.6中JAX-WS规范定义了如何发布一个WebService服务。与Web服务相关的类都位于Javax.jws.*包中。其中:
@WebService——此注解用在类上指定将此类发布成一个WebService, targetNamespace属性定义了自己的命名空间,serviceName则定义了< definitions >标签和标签的name属性。
EndPoint——此类为端点服务类,其中publish()方法用于将一个已经添加了 @WebService注解的Web服务(类)绑定到一个地址的端口上,用于发布。
@WebMethod定义Web Service运作的方法。
@SOAPBinding标签定义了WSDL文档中SOAP的消息协议,其中style属 性对应SOAP的文档类型,可选的有RPC和DOCUMENT。
实现思路:
服务器端编写服务接口类、服务实现类、服务发布类,以及自定义复杂数据类型Userbean。服务器端通过调用API中的Endpoint.publish()方法发布服务,客户端通过service.getPort()方法提取服务端口,远程调用服务端的服务。服务器端和客户端传输数据采用的是复杂数据类型ArrayList,保存了Userbean类型的数据。
代码实现:
代码片1:服务接口设计
package webservice;
import java.sql.SQLException;
import java.util.ArrayList;
import javax.jws.WebMethod;
import javax.jws.WebService;
/**
* @author 孟政宇
* @Time 2016-6-10 22:23:29
* 接口 声明方法
*/
@WebService
public interface WebServiceI {
// 使用@WebMethod注解标注WebServiceI接口中的方法
@WebMethod
ArrayList<Userbean> getInfoByID(int ID) throws Exception;
//web服务1
@WebMethod
ArrayList<Userbean> getInfoByDD(String Dept,String rank) throws Exception;
//web服务2
@WebMethod
String soa(String name);
//测试
@WebMethod
boolean sayHello(String name);
//测试
}
代码片2:服务接口实现
package webservice;
import java.io.IOException;
import java.lang.reflect.Array;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import javax.jws.WebMethod;
import javax.jws.WebService;
import cn.edu.neu.dinner.app.WMMP.factory.MinaClient;
import cn.edu.neu.dinner.app.WMMP.factory.NotifyObject;
import cn.edu.neu.dinner.app.WMMP.factory.TransObject;
/**
* @author 孟政宇 SEI的具体实现 Service endpoint interface
*/
// 使用@WebService注解标注WebServiceI接口的实现类WebServiceImpl
@WebService
public class ServiceDemoImpl implements WebServiceI {
@Override
public String soa(String name) {
System.out.println("测试调用");
return ("你的名字:" + name);
}
@Override
public ArrayList<Userbean> getInfoByID(int id) throws Exception {
// 通过ID查询
System.out.println("调用方法成功yeah!");
Class.forName("com.mysql.jdbc.Driver");
java.sql.Connection conn = DriverManager
.getConnection("jdbc:mysql://localhost:3306/soa?user=root&password=123456");
java.sql.Statement sql = conn.createStatement();
StringBuffer sb = new StringBuffer();
sb.append("SELECT *");
sb.append(" FROM ");
sb.append(" user ");
sb.append(" WHERE ID =");
java.sql.ResultSet rs = sql
.executeQuery(sb.toString() + "‘" + id + "‘");
ArrayList<Userbean> list = new ArrayList<Userbean>();
Userbean ub = new Userbean();
while (rs.next()) {
ub.setId(rs.getString(1));
ub.setName(rs.getString(2));
ub.setDept(rs.getString(3));
ub.setBirthday(rs.getString(4));
ub.setLocation(rs.getString(5));
ub.setRank(rs.getString(6));
ub.setDateIn(rs.getString(7));
list.add(ub);
}
return list;
}
@Override
public ArrayList<Userbean> getInfoByDD(String Dept, String rank) throws Exception {
// 联合查询
System.out.println("调用方法成功yeah!");
Class.forName("com.mysql.jdbc.Driver");
java.sql.Connection conn = DriverManager
.getConnection("jdbc:mysql://localhost:3306/soa?user=root&password=123456");
java.sql.Statement sql = conn.createStatement();
StringBuffer sb = new StringBuffer();
sb.append("SELECT *");
sb.append(" FROM ");
sb.append(" user ");
sb.append(" WHERE dept=");
java.sql.ResultSet rs = sql
.executeQuery(sb.toString() + "‘" + Dept + "‘"+ "and rank=" +"‘"+rank+"‘");
ArrayList<Userbean> list = new ArrayList<Userbean>();
while (rs.next()) {
Userbean ub = new Userbean();
ub.setId(rs.getString(1));
ub.setName(rs.getString(2));
ub.setDept(rs.getString(3));
ub.setBirthday(rs.getString(4));
ub.setLocation(rs.getString(5));
ub.setRank(rs.getString(6));
ub.setDateIn(rs.getString(7));
list.add(ub);
}
return list;
}
@Override
public boolean sayHello(String name) {
System.out.println("WebService sayHello " + name);
return true;
}
代码片3:自定义复杂类型(必须实现序列化)
package webservice;
import java.io.*;
public class Userbean implements Serializable{
private String id;
private String name;
private String dept;
private String birthday;
private String location;
private String rank;
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getDept() {
return dept;
}
public void setDept(String dept) {
this.dept = dept;
}
public String getBirthday() {
return birthday;
}
public void setBirthday(String birthday) {
this.birthday = birthday;
}
public String getLocation() {
return location;
}
public void setLocation(String location) {
this.location = location;
}
public String getRank() {
return rank;
}
public void setRank(String rank) {
this.rank = rank;
}
public String getDateIn() {
return dateIn;
}
public void setDateIn(String dateIn) {
this.dateIn = dateIn;
}
private String dateIn;
}
代码片4:服务发布类
package webservice;
import javax.xml.ws.BindingType;
import javax.xml.ws.Endpoint;
/**
* @author 孟政宇
*
* 发布Web Service
*/
@BindingType("http://java.sun.com/xml/ns/jaxws/2003/05/soap/bindings/HTTP/")
public class WebServicePublish {
public static void main(String[] args) {
//定义WebService的发布地址,这个地址就是提供给外界访问Webervice的URL地址,URL地址格式为:http://ip:端口号/xxxx
String address = "http://127.0.0.1:8989/hdfs/webservice";
//使用Endpoint类提供的publish方法发布WebService,发布时要保证使用的端口号没有被其他应用程序占用
/**
*参数1:服务的发布地址
*参数2:服务的实现者
*/
Endpoint.publish(address , new ServiceDemoImpl());
System.out.println("发布webservice成功!");
}
}
5 客户端开发
实现思路:
为了验证服务端是否发布成功,我们可以采用三种方式来验证。
一.采用jdk自带工具wsimport来生成客户端,并编写客户端程序测试。
二.使用诸如MyEclipse(Eclipse for Jave EE也可以)创建一个Web Service Client的项目
三.本地编程实现,这里我采用编程实现。即编写client类,由于服务已经发布,故可以通过指定服务的URI和服务类对象,创建service对象调用getPort方法访问服务端口,并调用远端服务。
实现代码:
//服务器起来后,调用服务
//在客户端需要将wsimport导出的文件夹和Userbean考到客户端目录,且不能
//更改文件名
package webservice;
import javax.xml.namespace.QName;
import javax.xml.ws.Service;
import java.net.URL;
import java.net.MalformedURLException;
import java.util.ArrayList;
import java.util.Scanner;
public class client {
public static void main(String[] args) throws Exception_Exception, MalformedURLException {
URL url = new URL("http://127.0.0.1:8989/hdfs/webservice?wsdl");
// 第一个参数是服务的URI
// 第二个参数是在WSDL发布的服务名
QName qname = new QName("http://webservice/","ServiceDemoImplService");
// 创建服务
Service service = Service.create(url, qname);
ServiceDemoImpl sd = service.getPort(ServiceDemoImpl.class);
System.out.println("**********************web服务1测试**********************");
System.out.println("根据ID查询信息,请输入ID编号:");
Scanner scanner=new Scanner(System.in);
String ID=scanner.nextLine();
ArrayList<Userbean> list = new ArrayList<Userbean>();
list = (ArrayList<Userbean>)sd.getInfoByID(ID);
System.out.println("查询结果:");
for(int i=0 ; i< list.size() ; i++){
System.out.print("员工号:" + list.get(i).getId() + " ");
System.out.print("员工名称:" + list.get(i).getName() + " ");
System.out.print("所在部门:" + list.get(i).getDept() + " ");
System.out.println("出生日期:" + list.get(i).getBirthday() + " ");
System.out.print("职位:" + list.get(i).getLocation() + " ");
System.out.print("职称:" + list.get(i).getRank() + " ");
System.out.println("入职日期:" + list.get(i).getDateIn() + " ");
}
System.out.println("**********************web服务1测试**********************");
// System.out.println("**********************web服务2测试**********************");
// System.out.println("根据部门、职称查询信息,请输入参数:");
// Scanner scanner=new Scanner(System.in);
// String dept=scanner.nextLine();
// String rank=scanner.nextLine();
// ArrayList<Userbean> list = new ArrayList<Userbean>();
// list = (ArrayList<Userbean>)sd.getInfoByDD(dept,rank);
//
// System.out.println("查询结果:");
// for(int i=0 ; i< list.size() ; i++){
// System.out.print("员工号:" + list.get(i).getId() + " ");
// System.out.print("员工名称:" + list.get(i).getName() + " ");
// System.out.print("所在部门:" + list.get(i).getDept() + " ");
// System.out.println("出生日期:" + list.get(i).getBirthday() + " ");
// System.out.print("职位:" + list.get(i).getLocation() + " ");
// System.out.print("职称:" + list.get(i).getRank() + " ");
// System.out.println("入职日期:" + list.get(i).getDateIn() + " ");
// }
// System.out.println("**********************web服务2测试**********************");
//
// }
}}
结果展示:
Web服务1测试:客户端通过输入员工的ID编号,传递参数到服务端,服务端调用服务getInfoByID并返回一个ArrayList类型的参数,客户端获取参数解析并显示,如图所示。
Web服务2测试:客户端通过输入员工的部门和职称两个参数,服务端调用服务getInfoByDD,并返回一个ArrayList类型的参数,客户端获取参数解析并显示,如图所示。
6 遇到的问题
问题:服务器向客户端传递的list为object无法解析为自定义的Userbean
解决方法:采用序列化的方式,在自定义的Javabean类实现Serializable即可