1. Jaxws常用注解
如果不使用注解,默认namespace是服务类包名倒序;默认portType是服务类的类名。注解的作用:jaxws提供的注解可以对webservice的接口规范化。
1.1 @webservice注解
@WebService定义服务,在服务实现类上。
targetNamespace: 指定命名空间
name: portType的名称
portName: port的名称
serviceName: 服务名称
endpointInterface: SEI接口地址,如果一个服务类实现了多个接口,只需要发布一个接口的方法,可通过此注解指定要发布服务的接口。
1.2 @WebMethod 定义方法,在公开方法上面
operationName: 方法名
exclude: 设置为true表示此方法不是webservice方法,反之则表示webservice方法。
1.3 @WebResult 定义返回值,在方法返回值前面
name:返回结果值的名称
1.4 @WebParam定义参数,在方法参数前面
name:指定参数的名称
备注:如果修改webservice的接口内容,比如namespace、portType,必须要重新生成客户端调用代码。
2. CXF入门
2.1 什么是cxf
Cxf,apache下的webservice的开源框架。Apache CXF = Celtix + Xfire,开始叫Apache CeltiXfire,后来更名为Apache CXF了,以下简称为CXF。Apache CXF 是一个开源的web Services框架,CXF帮助构建和开发web Services,它支持多种协议,比如:SOAP1.1,1,2、XML/HTTP、RESTful HTTP或者CORBA。CORBA(Common Object Request Broker Architecture公共对象请求代理体系结构,早期语言使用的WS。C,c++,C#)Cxf是基于SOA总线结构,依靠spring完成模块的集成,实现SOA方式。灵活的部署:可以运行有Tomcat,Jboss,Jetty(内置),weblogic上面。
2.2 环境配置
从官网下载下载cxf2.7.11版本。
环境变量的配置:
CXF_HOME=cxf的目录
Path = %JAVA_HOME%\bin;%CXF_HOME%\bin;
CLASSPATH=.;%CXF_HOME%\lib\cxf-manifest.jar
2.3 Cxf第一个程序
2.3.1 服务端
1. 开发SEI及SEI实现类
//Model类字段内容如下:
public class WeatherModel {
private String detail;
private Date date;
private Integer tempratureMax;
private Integer tempratureMin;
}
package cn.keymobile.server;
import java.util.List;
import javax.jws.WebService;
import cn.keymobile.pojo.WeatherModel;
/**
* cxf第一个程序,SEI接口
* cxf开发SEI接口,需要将@WebService注解加在SEI接口上
* @author zhaojd
*/
/**
* 注解的作用:jaxws提供的注解可以对webservice的接口规范化。
* targetNamespace:指定wsdl命名空间
* name:指定portType名称
* portName:指定port的名称
* serviceName:服务视图的名称
*/
@WebService(
targetNamespace="http://server.keymobile.cn/",
name="WeatherInterface",
portName="WeatherInterfacePortName",
serviceName="WeatherInterfaceServiceName"
)
public interface WeatherInterface {
//查询三天的天气
List queryWeather(String cityName);
}
package cn.keymobile.server;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.List;
import cn.keymobile.pojo.WeatherModel;
public class WeatherInterfaceImpl implements WeatherInterface {
@Override
public List queryWeather(String cityName) {
//构造三天天气
List list = new ArrayList();
Calendar calendar = Calendar.getInstance();
int day = calendar.get(Calendar.DATE);
WeatherModel weatherModel_1 =new WeatherModel();
weatherModel_1.setDetail("晴");
weatherModel_1.setDate(new Date());
weatherModel_1.setTempratureMax(20);
weatherModel_1.setTempratureMin(15);
WeatherModel weatherModel_2 =new WeatherModel();
weatherModel_2.setDetail("阴");
calendar.set(Calendar.DATE, day+1);
weatherModel_2.setDate(calendar.getTime());
weatherModel_2.setTempratureMax(15);
weatherModel_2.setTempratureMin(10);
WeatherModel weatherModel_3 =new WeatherModel();
weatherModel_3.setDetail("晴");
calendar.set(Calendar.DATE, day+2);
weatherModel_3.setDate(calendar.getTime());
weatherModel_3.setTempratureMax(10);
weatherModel_3.setTempratureMin(5);
list.add(weatherModel_1);
list.add(weatherModel_2);
list.add(weatherModel_3);
return list;
}
}
2. 发布服务代码
package cn.keymobile.server;
import org.apache.cxf.jaxws.JaxWsServerFactoryBean;
public class WeatherServer {
public static void main(String[] args) {
//使用jaxWs发布soap协议的webservice
JaxWsServerFactoryBean jaxWsServerFactoryBean = new JaxWsServerFactoryBean();
//指定 webservice地址
jaxWsServerFactoryBean.setAddress("http://127.0.0.1:12345/weather");
//指定 porttype
jaxWsServerFactoryBean.setServiceClass(WeatherInterface.class);
//指定服务类对象
jaxWsServerFactoryBean.setServiceBean(new WeatherInterfaceImpl());
//发布服务
jaxWsServerFactoryBean.create();
}
}
2.3.2 客户端
1. 客户端开发技术不受webservice服务端限制,服务端使用cxf,客户端采用多种方法,比如Service类标准方法。如果使用cxf提供客户端类或方法,需要加入cxf的jar包。
2. 使用cxf的wsdl2java工具生成,生成源文件,命令如下:
wsdl2java -d . http://127.0.0.1:12345/weather?wsdl
客户端代码如下:
package cn.keymobile.client;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.List;
import org.apache.cxf.jaxws.JaxWsProxyFactoryBean;
import cn.keymobile.server.WeatherInterface;
import cn.keymobile.server.WeatherModel;
/**
* cxf实现webservice客户端
* @author zhaojd
*
*/
public class WeatherClient {
public static void main(String[] args) {
// jaxWsProxyFactoryBean调用webservice服务端
JaxWsProxyFactoryBean jaxWsProxyFactoryBean = new JaxWsProxyFactoryBean();
/**
* 1. 设置wsdl文档路径
* 2. 设置portType
* 3. 创建portType
*/
jaxWsProxyFactoryBean.setAddress("http://127.0.0.1:12345/weather?wsdl");
jaxWsProxyFactoryBean.setServiceClass(WeatherInterface.class);
WeatherInterface weatherInterface = (WeatherInterface) jaxWsProxyFactoryBean.create();
List list = weatherInterface.queryWeather("广州");
for (WeatherModel wm : list) {
System.out.println(wm.getDetail());
Date date = wm.getDate().toGregorianCalendar().getTime();
System.out.println(new SimpleDateFormat("yyyy-MM-dd").format(date));
System.out.println(wm.getTempratureMax());
System.out.println(wm.getTempratureMin());
}
}
}
2.3.3 服务端
1. Cxf编程方式实现webservice使用JaxWsServerFactoryBean发布webservice服务;在客户端使用JaxWsProxyFactoryBean创建portTypen,通过portType调用webservice服务端;
2. Cxf和spring整合后,可以将上边的编程方式修改为spring配置方式实现内部使用JaxWsServerFactoryBean和JaxWsProxyFactoryBean 。
2.3.4 Cxf发布soap1.2
使用cxf发布soap1.2不需要下载jaxws-ri扩展包。在服务接口的上面添加@BindingType(javax.xml.ws.soap.SOAPBinding.SOAP12HTTP_BINDING) 如下:
@WebService
@BindingType(javax.xml.ws.soap.SOAPBinding.SOAP12HTTP_BINDING)
public interface WeatherServerInterface
3. Cxf和spring整合
3.1 思路
Cxf框架本身依赖spring,从官方下载cxf包中有spring的jar包。上边使用JaxWsServerFactoryBean和JaxWsProxyFactoryBean,改为spring配置方式。发布服务:使用spring和cxf整合的标签jaxws:server 客户端调用服务:使用spring和cxf整合的标签 jaxws:client 上边的 jaxws:server和 jaxws:client相当于spring容器的bean,发布服务和客户端调用交给spring容器管理。
3.2 服务端
1. 创建工程、加入cxf的jar包
2. 开发SEI和实现类
//Model类字段信息
public class WeatherModel {
private String detail;
private Date date;
private Integer tempratureMax;
private Integer tempratureMin;
}
///////////////////////////////////////////////////
package cn.keymobile.server;
import java.util.List;
import javax.jws.WebService;
import cn.keymobile.pojo.WeatherModel;
/**
* 天气查询SEI接口;
* cxf开发SEI需要将@WebService 写在SEI接口上面
* @author zhaojd
*/
/**
* 注解的作用:jaxws提供的注解可以对webservice的接口规范化。
* targetNamespace:指定wsdl命名空间
* name:指定portType名称
* portName:指定port的名称
* serviceName:服务视图的名称
*/
@WebService(
targetNamespace="http://server.keymobile.cn/",
name="WeatherInterface",
portName="WeatherInterfacePort",
serviceName="WeatherInterfaceService"
)
public interface WeatherInterface {
List queryWeather(String cityName);
}
package cn.keymobile.server;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.List;
import cn.keymobile.pojo.WeatherModel;
/**
* 天气查询SEI 实现类
* @author zhaojd
*
*/
public class WeatherInterfaceImpl implements WeatherInterface {
@Override
public List queryWeather(String cityName) {
//构造三天天气
List list = new ArrayList();
Calendar calendar = Calendar.getInstance();
int day = calendar.get(Calendar.DATE);
WeatherModel weatherModel_1 = new WeatherModel();
weatherModel_1.setDetail("晴");
weatherModel_1.setDate(new Date());
weatherModel_1.setTempratureMax(20);
weatherModel_1.setTempratureMin(15);
WeatherModel weatherModel_2 = new WeatherModel();
weatherModel_2.setDetail("阴");
calendar.set(Calendar.DATE, day + 1);
weatherModel_2.setDate(calendar.getTime());
weatherModel_2.setTempratureMax(15);
weatherModel_2.setTempratureMin(10);
WeatherModel weatherModel_3 = new WeatherModel();
weatherModel_3.setDetail("晴");
calendar.set(Calendar.DATE, day + 2);
weatherModel_3.setDate(calendar.getTime());
weatherModel_3.setTempratureMax(10);
weatherModel_3.setTempratureMin(5);
list.add(weatherModel_1);
list.add(weatherModel_2);
list.add(weatherModel_3);
return list;
}
}
3. 编写applicationContext.xml
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:jaxws="http://cxf.apache.org/jaxws"
xmlns:jaxrs="http://cxf.apache.org/jaxrs" xmlns:cxf="http://cxf.apache.org/core"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://cxf.apache.org/jaxrs http://cxf.apache.org/schemas/jaxrs.xsd
http://cxf.apache.org/jaxws http://cxf.apache.org/schemas/jaxws.xsd
http://cxf.apache.org/core http://cxf.apache.org/schemas/core.xsd">
<bean id="weatherInterface" class="cn.keymobile.server.WeatherInterfaceImpl" />
<jaxws:server address="/weather"
serviceClass="cn.keymobile.server.WeatherInterface">
<jaxws:serviceBean>
<ref bean="weatherInterface" />
jaxws:serviceBean>
jaxws:server>
beans>
4. 在web.xml 中配置cxf的servlet及加载spring
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://java.sun.com/xml/ns/javaee"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
id="WebApp_ID" version="2.5">
<display-name>cxf_spring_serverdisplay-name>
<context-param>
<param-name>contextConfigLocationparam-name>
<param-value>/WEB-INF/classes/applicationContext.xmlparam-value>
context-param>
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListenerlistener-class>
listener>
<servlet>
<servlet-name>cxfservlet-name>
<servlet-class>org.apache.cxf.transport.servlet.CXFServletservlet-class>
<load-on-startup>1load-on-startup>
servlet>
<servlet-mapping>
<servlet-name>cxfservlet-name>
<url-pattern>/ws/*url-pattern>
servlet-mapping>
web-app>
5. 启动tomcat
http://localhost:8080/工程名/ws
7. 测试注意
因为通过spring和cxf整合将webservice通过tomcat发布,webservice和应用程序共用一个端口都是8080。测试webservice和应用程序(jsp)是否可以共存(都可以访问)。正式上线使用80端口。
3.3 客户端
1. 创建工程、加入jar包
2. 使用wsdl2java或者wsimport工具生成客户端调用代码
3. 编写applicationContext.xml
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:jaxws="http://cxf.apache.org/jaxws"
xmlns:jaxrs="http://cxf.apache.org/jaxrs" xmlns:cxf="http://cxf.apache.org/core"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://cxf.apache.org/jaxrs http://cxf.apache.org/schemas/jaxrs.xsd
http://cxf.apache.org/jaxws http://cxf.apache.org/schemas/jaxws.xsd
http://cxf.apache.org/core http://cxf.apache.org/schemas/core.xsd">
<jaxws:client id="weatherClient"
address="http://localhost:8080/cxf_spring_server/ws/weather?wsdl"
serviceClass="cn.keymobile.server.WeatherInterface">
jaxws:client>
beans>
4. 测试
package cn.keymobile.client;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.List;
import org.junit.Before;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import cn.keymobile.server.WeatherInterface;
import cn.keymobile.server.WeatherModel;
/**
* cxf和spring整合
* @author zhaojd
*
*/
public class ClientTest {
private ApplicationContext applicationContext;
@Before
public void before() {
applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");
}
@Test
public void testCxfSpringClient() {
// 从spring容器中取出portType
WeatherInterface weatherInterface =
(WeatherInterface) applicationContext.getBean("weatherClient");
// 调用portType的方法
List list = weatherInterface.queryWeather("广州");
for (WeatherModel weatherModel : list) {
System.out.println(weatherModel.getDetail());
Date date = weatherModel.getDate().toGregorianCalendar().getTime();
System.out.println(new SimpleDateFormat("yyyy-MM-dd").format(date));
System.out.println(weatherModel.getTempratureMax());
System.out.println(weatherModel.getTempratureMin());
}
}
}
4. CXF发布rest风格的webservice
4. 1 什么是restFul
REST是一种软件架构模式,只是一种风格,rest服务采用HTTP 做传输协议,REST对于HTTP的利用分为以下两种:资源定位和资源操作。
1. 资源定位
使用url更加准确去定位一个互联网资源,比如:查询一个学生信息url。
不使用rest的url:http://ip:port/queryUser.action?userType=XXX&studentid=001&XXXX
使用 rest的url:http://ip:port/user/student/001
使用rest方式表达url更加简单、可以准确表达这个url是一个学生信息查询url。
2. 资源操作
利用HTTP的GET、POST、PUT、DELETE四种操作来表示数据库操作的SELECT、UPDATE、INSERT、DELETE操作。比如:更新学生信息:设置http请求的方法为post。
定义rest的url:http://ip:port/user/student/001/张三/13
Rest方式一般要求url中不要有动词。动词采用GET、POST、PUT、DELETE表示。
Rest风格是对http协议很好的诠释。
Rest好处:
定义的url对资源定位更加准确、简单。
Rest缺点:
如果rest的url定义层级比较多,可读性较差。
4. 2 发布rest风格的webservice的实现
使用cxf发布rest的webservice,使用jaxrs(java开发webservice一个规范)
1. 创建工程、加入jar包
2. 编写pojo
/**
* 学生信息
* 使用 @XmlRootElement(name = "student") 将pojo转成xml。
* @author zhaojd
*/
@XmlRootElement(name = "student")
public class Student {
private long id;
private String name;
private Date birthday;
}
3. 编写SEI
package cn.keymobile.rest.server;
import java.util.List;
import javax.jws.WebService;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;
import cn.keymobile.rest.pojo.Student;
/**
* rest风格的SEI
* @author zhaojd
*/
@WebService
@Path("/student")
public interface StudentService {
/**
* @param id 通过url传递的id参数
* @return
*
* 根据id查询学生信息
* @GET
* http的get方法
* @Path("/query/{id}")
* id参数通过url传递
* @Produces(MediaType.APPLICATION_XML)
* 设置媒体类型xml格式
*/
@GET
@Path("/query/{id}")
@Produces(MediaType.APPLICATION_XML)
public Student queryStudent(@PathParam("id") long id);
/**
* @param type
* @return
*
* 根据类型查询所有的学生信息
* @Produces({"application/json;charset=utf-8",MediaType.APPLICATION_XML})
* 设置媒体类型xml格式和json格式
*
* 如果想让rest返回xml需要在rest的url后边添加?_type=xml,默认为xml
* 如果想让rest返回json需要在rest的url后边添加?_type=json
*/
//查询学生列表
@GET
@Path("/querylist/{type}")
@Produces({"application/json;charset=utf-8", MediaType.APPLICATION_XML})
public List queryStudentList(@PathParam("type") String type);
}
4. 编写SEI实现类
package cn.keymobile.rest.server;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import cn.keymobile.rest.pojo.Student;
/**
* rest风格的学生信息查询 SEI实现类
* @author zhaojd
*/
public class StudentServiceImpl implements StudentService {
@Override
public Student queryStudent(long id) {
// 使用静态数据
Student student = new Student();
student.setId(id);
student.setName("张三");
student.setBirthday(new Date());
return student;
}
@Override
public List queryStudentList(String type) {
// 使用静态数据
List list = new ArrayList();
Student student1 = new Student();
student1.setId(1000l);
student1.setName("张三");
student1.setBirthday(new Date());
Student student2 = new Student();
student2.setId(1000l);
student2.setName("张三");
student2.setBirthday(new Date());
list.add(student1);
list.add(student2);
return list;
}
}
5. 发布rest服务
package cn.keymobile.rest.server;
import org.apache.cxf.jaxrs.JAXRSServerFactoryBean;
/**
* 编程方式发布查询学生信息的rest风格的webservice服务
* @author zhaojd
*/
public class StudentServer {
public static void main(String[] args) {
/**
* 1. 使用jaxrsServerFactoryBean发布rest服务
* 2. 设置rest的服务地址
* 3. 设置资源对象,如果有多个资源对象,中间以半角逗号隔开
* 4. 发布rest风格的webservice服务
*/
JAXRSServerFactoryBean jaxrsServerFactoryBean = new JAXRSServerFactoryBean();
jaxrsServerFactoryBean.setAddress("http://127.0.0.1:12345/rest");
jaxrsServerFactoryBean.setServiceBean(new StudentServiceImpl());
jaxrsServerFactoryBean.setResourceClasses(StudentServiceImpl.class);
jaxrsServerFactoryBean.create();
}
}
6. 测试rest服务
http://127.0.0.1:12345/rest/student/query/001 查询学生信息
http://127.0.0.1:12345/rest/student/querylist/001?_type=xml 查询学生信息列表,返回xml
http://127.0.0.1:12345/rest/student/querylist/001?_type=json 查询学生信息列表,返回json
7. rest服务的客户端httpclient方式
package cn.keymobile.rest.client;
import java.io.ByteArrayOutputStream;
import java.io.InputStream;
import java.net.HttpURLConnection;
import java.net.URL;
/**
* 模拟http请求,向webservice的服务端发送soap协议体
* @author zhaojd
*
*/
public class HttpClient {
public static void main(String[] args) throws Exception {
/**
* 开启一个http链接;webservice的地址
*/
URL url = new URL("http://127.0.0.1:12345/rest/student/querylist/001?_type=json");
HttpURLConnection httpUrlConnection = (HttpURLConnection) url.openConnection();
//设置GET请求,GET是大写
httpUrlConnection.setRequestMethod("GET");
httpUrlConnection.setRequestProperty("Content-Type", "text/xml; charset=utf-8");
//设置请求和响应
httpUrlConnection.setDoInput(true);
httpUrlConnection.setDoOutput(true);
//接受响应内容
InputStream inputStream = httpUrlConnection.getInputStream();
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
int len = -1;
byte[] b = new byte[1024];
while((len= inputStream.read(b, 0, 1024))!=-1){
byteArrayOutputStream.write(b, 0, len);
}
//获取响应的内容
String responseString = byteArrayOutputStream.toString();
System.out.println(responseString);
//解析响应数据
}
}
8. 使用spring的配置方式发布rest服务
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:jaxws="http://cxf.apache.org/jaxws"
xmlns:jaxrs="http://cxf.apache.org/jaxrs" xmlns:cxf="http://cxf.apache.org/core"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://cxf.apache.org/jaxrs http://cxf.apache.org/schemas/jaxrs.xsd
http://cxf.apache.org/jaxws http://cxf.apache.org/schemas/jaxws.xsd
http://cxf.apache.org/core http://cxf.apache.org/schemas/core.xsd">
<bean id="studentService" class="cn.keymobile.rest.server.StudentServiceImpl" />
<jaxrs:server address="/rest">
<jaxrs:serviceBeans>
<ref bean="studentService" />
jaxrs:serviceBeans>
jaxrs:server>
beans>
9. rest服务的客户端ajax方式
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<script type="text/javascript" src="${pageContext.request.contextPath }/js/jquery-1.4.4.min.js">script>
<script type="text/javascript">
script>
<script type="text/javascript">
function rest() {
$.ajax({
type : 'get',
url : 'http://localhost:8080/cxf_spring_server_rest/ws/rest/student/querylist/001?_type=json',
success : function(data) {
alert(data.student[0].name);
}
});
}
script>
head>
<body>
<input type="button" value="rest请求" onclick="rest()"/>
body>
html>