示例背景简单描述.
有一个学校A提供一个Web Service服务:
1.只要使用者B 输入一个学生的ID号, A就能告诉B这个学生的详细信息.
2.只要使用者B 输入一个是否是男性的逻辑值, A就能向B提供这个班级中所有按逻辑值找到的学员信息
3.只要使用者B 输入一个学生的ID号和密码, 和这个学生的新的详细信息, 那么A就可以帮助B修改这个学生的信息.
根据这个需求, 应该先实现服务提供者A所能提供的服务(对应以上)
1.public Student getStudentInfoByStuID(Integer stuID){}
2.public List<Student> getStudentsInfoBySex(boolean isMale){}
3.public boolean updateStudentInfo(Integer stuID,String password,Student newStudentInfo){}
下面是具体操作步骤:
Step 01: 创建一个Web Project: StudentServer,完成实体类,业务逻辑和服务接口的实现.
Student.java
package com.apt.server.entity;
import java.util.Date;
/**
* A Student class
* @author Simonlv
*/
public class Student {
private Integer id;
private String name;
private String password;
private Integer age;
private Date birthDay;
private boolean isMale;
private double height;
public Student(Integer id, String name, String password, Integer age,
Date birthDay, boolean isMale, double height) {
this.id = id;
this.name = name;
this.password = password;
this.age = age;
this.birthDay = birthDay;
this.isMale = isMale;
this.height = height;
}
//getter/setter methods
}
StudentBiz.java
package com.apt.server.service;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import com.apt.server.entity.Student;
/**
* Student Business Logic Object .This class is mainly used for loading Student
* data or updating Student information by some condition.
*
* @author Simonlv
*/
public class StudentBiz {
/**
* Get the information of a student by giving this student ID NO.
*
* @param stuID
* Student's ID NO.
* @return The detailed information of a student,a student object.
*/
public Student getStudentInfoByStuID(Integer stuID) {
//student ZhangSan Female
Student s1 = new Student(1001, "zhangSan", "111111", 21, new Date(), false, 175.50d);
//student liSi Male
Student s2 = new Student(1002, "liSi", "222222", 25, new Date(), true, 185.50d);
if(stuID==1001){
return s1;
}else{
return s2;
}
}
/**
* Get the information of all students with gender is M or F
*
* @param isMale
* true indicate Male, false means Female
* @return A list collection with the object of student class.
*/
public List<Student> getStudentsInfoBySex(boolean isMale) {
//student zhangSan_1 Female
Student s1 = new Student(1001, "zhangSan_1", "111111", 21, new Date(), false, 171.50d);
//student zhangSan_2 Female
Student s2 = new Student(1001, "zhangSan_2", "111111", 22, new Date(), false, 172.50d);
//student zhangSan_3 Female
Student s3 = new Student(1001, "zhangSan_3", "111111", 23, new Date(), false, 173.50d);
//student zhangSan_4 Female
Student s4 = new Student(1001, "zhangSan_4", "111111", 24, new Date(), false, 174.50d);
//student liSi Male
Student s5 = new Student(1002, "liSi", "222222", 25, new Date(), true, 181.50d);
//student wangWu Male
Student s6 = new Student(1002, "wangWu", "222222", 25, new Date(), true, 182.50d);
//List collection of Student
List<Student> list = new ArrayList<Student>();
if(isMale){
//Male
list.add(s5);
list.add(s6);
}else{
//Female
list.add(s1);
list.add(s2);
list.add(s3);
list.add(s4);
}
return list;
}
/**
* Update a student information by putting ID,Password and the new
* information of this student
*
* @param stuID the ID of a student
* @param password the password of a student
* @param newStudentInfo An object of Student type.
* @return true-update successfully ,or false-update failure.
*/
public boolean updateStudentInfo(Integer stuID, String password,
Student newStudentInfo) {
//student ZhangSan Female
Student s1 = new Student(1001, "zhangSan", "111111", 21, new Date(), false, 175.50d);
//check
if(stuID==s1.getId() && password.equals(s1.getPassword())){
//success ...
return true;
}else{
return false;
}
}
}
Step02:要将此WEB程序发布成为 Web Service,找到此图标,点击进去
Step03:选中要发布成为WebService的项目, Framework:JAX-WS, Strategy: Create web service from Java class
在这里可以看出,创建WebService的方式有两种:
第一种是 Create web service from WSDL document . 先写WSDL 文档,然后再由WSDL文件生成服务器端的类和服务. 但是这种方式不是很直观, 对于WSDL文件的语法和格式以及提供的插件工具要很熟悉.
第二种是 Create web service form Java class. 这种方式非常简单, 我们只需要提供我们所写好的预备对外公开的API接口类(这里的接口不一定是指Interface.泛指提供方法入口的类)
Step04:准备选择哪个JAVA类将成为Web Service 对外服务的接口
Step05: 选择了StudentBiz 业务逻辑类,会自动创建一个 Delegate class name:com.apt.server.service.StudentBizDelegate
(此处有时需手动填写,并不是通过browser找到)
必须要注意的: 同时要求选择 Generate WSDL in project, 因为是通过类来生成映射的WSDL文件,最终对外发布的也是这个WSDL文件.
WSDL Customization 中
Target namespace 可以保持默认,ServiceName和Service port可以更改,但是需要知道更改了后,这些东西将会出现在哪个文件中. 所以初步阶段默认即可. 同时要说的是,如果你的包名,类名都设计的很合理,那么这几个参数的名字也是很合理的.
Step06: Generating JAX-WS Web Services' has encountered a problem. An internal error occurred during: Generating JAX-WS Web Services.
在我的印象中,类似于这样的错误发生了很多次,每次都有这样或那样不同的问题,绕不过去必须解决. 并且这种错误不是在某某编译器编译后告诉你一个结果, 也不是在某某服务器启动后加载时出现的异常.
所以遇到这样的问题,方式就是尽量理解它所提供的错误说明和 Error Log
Step07:对于“Generating JAX-WS Web Services' has encountered a problem. ”这种错误的处理
看Step06中图片, Show Error Log,点击进去查看错误日志-这是最最有效的方式, 如果在网上搜, 同样的问题可能会有N多不同的答案,原因一会再说.
看到下图中有一句很长的话吗?
counts of IllegalAnnotaionException.apt.server.entity.Student does not have a no-arg default constructor .....明白了吗?
再回头看看刚才所写的 Student.java 中,Student类中有无参的构造方法吗? 没有. 原因就在这里.
为什么刚才说同样的错误问题Step06有N个不同的回答.我故意又改错了某些代码,生成时报Step06的错误看看错误,还是看错误日志(如下图所示) : 第一行:
******.GetStudentInfoByStuID is not found.Have you run APT to generate them . 但是这个错误不会是像刚才那样容易理解,并且拿着 Have you run APT to generate them 去网上搜索的话估计也会被各种各样的答案弄崩溃掉.解决方式各种各样,有的需要下载jar,有的需要使用工具编译. 总之, 我受到过这样的错误引导. 其实如果这个代码接口是你写的,这个Web Service 现在也是你去发布生成的话, 对于 GetStudentInfoByStuID is not found - "GetStudentInfoByStuID 方法没有找到" 难道不会疑惑吗? 明明是写过的代码,有印象,并且好像写了它的几个重载方法.--问题就出在重载上了.导致不能找到这个方法. WebService目前应该可以做到重载了,但是我没有动手实践过.
所以同样的Step06不能 generate成功 ,其实有很多原因.
我在最初尝试发布Web Service的时候碰到的错误远不止这些,这是最好演示的几个错误问题.要说的是:
即使是发现了从未没有出现过的错误,那也要用从来没有过的态度坚决地把这个错误搞定.
知道这些错误原因了,就把代码中的错误解决掉,后面继续.
注解: 如果没有记错的话, 不同版本的IDE,错误出现的位置不一样,有的是在代码发布到容器和容器加载阶段(MyEclipse 6.5) , 有的是在WebService创建和发布阶段(MyEclipse8.x),个人认为这是MyEclipse8.x在这里比MyEclipse6.5好的地方吧.
Step08: 在解决了刚才错误的情况下,最后生成了 WebService的 Server 端,结构图如下:
多了一些内容:
com.apt.server.service.StudentBizDelegate.java
WEB-INF 下的 wsdl文件夹和两个文件 .xsd,和 wsdl 文件.
WEB-INF 下的 sun-jaxws.xml文件
修改了 web.xml文件.
<web-app version="2.5" xmlns=" http://java.sun.com/xml/ns/javaee"
xmlns:xsi=" http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation=" http://java.sun.com/xml/ns/javaee
http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd">
<servlet>
<description>JAX-WS endpoint - StudentBizService</description>
<display-name> StudentBizService</display-name>
<servlet-name> StudentBizService</servlet-name>
<servlet-class>com.sun.xml.ws.transport.http.servlet.WSServlet</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name> StudentBizService</servlet-name>
<url-pattern> /StudentBizPort</url-pattern>
</servlet-mapping>
<welcome-file-list>
<welcome-file>index.jsp</welcome-file>
</welcome-file-list>
<listener>
<listener-class>
com.sun.xml.ws.transport.http.servlet.WSServletContextListener</listener-class>
</listener>
</web-app>
java.lang.ClassNotFoundException: com.sun.xml.ws.transport.http.servlet.WSServletContextListener
复制 schemaLocation 的地址放到浏览器中,看看 XSD 文件.
至于WSDL文件,有时间的话可以好好研究其中各个元素的含义,特别重要的是它与我们程序中相关接口之间的对应关系.
Web Service 服务器端的配置和发布目前就算完成了. 记住在使用WSDL文件生成客户端时, Tomcat 服务器要一直开启,因为别人要使用你的服务.
下面就是怎样使用部署的webservice
准备使用一个web服务,首先要知道它的WSDL URL.
另外,我的客户端可以是C/S程序,也可以是B/S程序,可以使用JAVA,也可以是用C,C#等不同的程序语言,关键的就是需要知道WSDL文件即可. 但是在本示例中只使用了JAVA程序作为客户端, 原因前面也已经提过,就是对于List集合或者其它更复杂的接口在调用它们时不能很好的保证数据解析和传递的正确.
Step16:创建任意的一个JAVA客户端程序,可以是C/S也可以是B/S的程序.
Step17:这次是创建一个Web Service Client
Step18:使用已经存在的WSDL URL 创建一个Web Service 客户端程序
要注意URL中的localhost在实际使用中,应该是Web Service 发布的真正IP地址,端口号也要和服务器端口一致,由于我的服务器端程序和客户端在同一台电脑和部署在同一个服务器中,就只能这么演示.
例如以后可能实际使用的URL是这样的. http://202.87.33.42:8733/StudentServer/StudentBizPort?WSDL
还要创建一个java package - com.test.client .作为客户端生成代码的文件包位置,下一步.
Step19:会有一个验证界面会验证这个WSDL文件存不存在或者格式是否正确.
自我测试时,停掉服务就会发现这个验证界面或出现错误,可以试着读一读. 因为很多时候你需要在网上找别人发布的Web Service程序来创建你自己的客户端,也需要验证. 有时的验证不能通过,这时就知道原因了.
Step20:验证成功后生成的代码
看看其中也有Student类
主要的是StudentBizDelegate.java和StudentBizService.java
Step21:自己写代码测试成功输出
package com.test.clienttest;
import java.util.List;
import com.test.client.Student;
import com.test.client.StudentBizDelegate;
import com.test.client.StudentBizService;
/**
* Test Web Services
*
* @author Simonlv
*
*/
public class StudentClient {
// Service Object
private StudentBizService service;
// Service Delegate Object
private StudentBizDelegate delegate;
// init
public StudentClient() {
service = new StudentBizService();
delegate = service.getStudentBizPort();
}
// print student
private void printStudent(Student s) {
System.out.println("\nID:" + s.getId() + "\tName:" + s.getName()
+ "\tPWD:" + s.getPassword() + "\tAge:" + s.getAge()
+ "\tBirth day:" + s.getBirthDay() + "\tHeight:"
+ s.getHeight());
}
// get student by id
public void showStudentInfo(Integer ID) {
Student s = delegate.getStudentInfoByStuID(ID);
printStudent(s);
}
// get students by sex
public void showStudentBySex(boolean isMale) {
List<Student> list = delegate.getStudentsInfoBySex(isMale);
for (Student s : list) {
printStudent(s);
}
}
// update
public void updateStudent(Integer id, String pwd, Student stu) {
boolean suc = delegate.updateStudentInfo(id, pwd, stu);
System.out.println("Update result:" + suc);
}
// Main test
public static void main(String[] args) {
StudentClient sc = new StudentClient();
// 1.Get a student information by student's id.
sc.showStudentInfo(1001);
// print result
// ID:1001 Name:zhangSan PWD:111111 Age:21 Birth
// day:2010-06-27T20:09:14.437+08:00 Height:175.5
sc.showStudentInfo(1003);
// print result
// ID:1002 Name:liSi PWD:222222 Age:25 Birth
// day:2010-06-27T20:09:44.250+08:00 Height:185.5
// 2.Get all students - Male
sc.showStudentBySex(true);
// print result
/**
*
ID:1002 Name:liSi PWD:222222 Age:25 Birth
* day:2010-06-27T20:10:45.390+08:00 Height:181.5
*
* ID:1002 Name:wangWu PWD:222222 Age:25 Birth
* day:2010-06-27T20:10:45.390+08:00 Height:182.5
*/
//3. omit ..update ......
}
}