WebService 可以实现一种分布式的开发
--CXF:
Apache CXF = Celtix + Xfire,开始叫 Apache CeltiXfire,后来更名为 Apache CXF 了,以下简称为 CXF。Apache CXF 是一个开源的 web Services 框架,CXF 帮助您构建和开发 web Services ,它支持多种协议,比如:SOAP1.1,1,2XML/HTTP、RESTful 或者CORBA。
RESTful: 一种风格而不是一个协议。它理念是网络上的所有事物都被抽象为资源,每个资源对应一个唯一的资源标识符。
Cxf是基于SOA总线结构,依靠spring完成模块的集成,实现SOA方式。
灵活的部署: 可以运行在Tomcat,Jboss,Jetty(内置),weblogic上面。
--Restful网络
开发WebService的要素
1. Provider 提供者 webservice实现方,对外提供webservice的业务接口
2. Requester 请求者 webservice调用方,或者 客户端 app 程序 网站 ssm main()
3. Registry 注册者
WSDL 描述语言 就是一个XML文档
webservice是通过xml来进行交互
使用xml作用:与平台无关性,与语言无关性
WebService相当于一个部署在网络上的应用程序,此应用对外提供服务(业务功能)
例如,天气预告
这里详细阐述cxf在客户端和服务器的部署及使用:
1.首先在web.xml文件中配置一个中央控制器(服务端的开发本身就是基于MVC的)
<!-- CXF 中央控制器 -->
<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>
2.如果用到spring还要添加监听器(加载spring文件)
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:applicationContext-*.xml</param-value>
</context-param>
<listener>
<listener-class>
org.springframework.web.context.ContextLoaderListener
</listener-class>
</listener>
3.在创建的动态web工程中导入cxf的jar包:
4.创建服务器的pojo类(注意实现序列化接口并加版本号,因为数据要在网络上远程传输)
import java.io.Serializable;
public class Product implements Serializable {
//版本号
private static final long serialVersionUID = 1L;
private String productName;
private Double price;
public Product() {
super();
}
public Product(String productName, Double price) {
super();
this.productName = productName;
this.price = price;
}
public String getProductName() {
return productName;
}
public void setProductName(String productName) {
this.productName = productName;
}
public Double getPrice() {
return price;
}
public void setPrice(Double price) {
this.price = price;
}
@Override
public String toString() {
return "Product [productName=" + productName + ", price=" + price + "]";
}
}
5.然后创建服务端的业务层方法:接口必须要用@WebService方法修饰
@WebService
public interface ProduceService {
//在springcloud分布式开发中业务类就相当于一个web服务,对外就是提供业务数据的
List<Product> findAllProduct();
}
6.接下来要在(applicationContext-*.xml)服务端配置一段代码:
<!-- 暴露应用程序接口 -->
<jaxws:endpoint id="productServiceImpl"
implementor="com.cxf.service.ProductServiceImpl"
address="/productService"></jaxws:endpoint>
把业务接口的实现类的全路径名拷贝到implementor中,这里spring通过id得到实例,这个实例是通过远程访问address里的地址来得到一个接口对象(实例)
这样就完成了一个web服务的发布,接下来部署到tomcat中
访问路径:localhost8080/+项目名/+web.xml文件中cxf中央控制器的url-pattern标签中的内容+/
http://localhost:8080/Day1105_WebService/services
http://localhost:8080/Day1105_WebService/services/productService?wsdl这里的productService就是服务端spring配置文件中的address中的访问地址,?wsdl就是网络服务描述语言(Web Services Description Language)是一门基于 XML 的语言,用于描述 Web Services 以及如何对它们进行访问。
-------------------------------------------------------------------------------------------------------------------------------------------------------------------
7.接下来要在(applicationContext-*.xml)客户端配置一段代码;
启动服务端tomcat:访问http://localhost:8080/Day1105_WebService/services/productService?wsdl
在页面显示的xml文件末尾有个网站:
把这个网站地址放到客户端的spring配置文件里的address里:
<jaxws:client id="productService"
address="http://localhost:8080/Day1105_WebService/services/productService"
serviceClass="com.cxf.service.ProduceService" />
访问服务端以后要返回一个远程回来的代理接口:即serviceClass里的类
这个代理接口就是当初我们在客户端原封不动拷贝过来的带package名的接口(实际上客户端也可以将服务端的pojo和service两个package打成jar包放到客户端项目里供其调用)
把接口的全路径名(包名加类名)原封不动拷贝到serviceClass以后就完成了第一部配置,含义是:
address就是远程访问服务器的地址,serviceClass就是远程返回的代理接口对象,id就是spring容器当中的引用(通过id引用就可以得到远程访问的代理接口对象)
------------------------------------------------------------------------------------------------------------------------------------------------------------------------
怎么用这个cxf提供的服务:
在客户端做一个测试类访问(当然也可以通过其他方式访问)以spring的方式访问代码如下(main方法也相当于一个程序)
public class CXFSpringClient {
//以Spring方式访问
public static void main(String[] args) {
ApplicationContext context = new ClassPathXmlApplicationContext("classpath:applicationContext-client.xml");
//获取远程访问服务器返回的代理接口对象
ProduceService service = context.getBean("productService",ProduceService.class);
List<Product> list = service.findAllProduct();
for(Product product : list){
System.out.println(product);
}
}
}
第二种访问方式:使用JaxWsDynamicClientFactory工厂类(动态的方式)访问,用这种方式不需要配置applicationContext.xml
public class JaxWsDynamicClient {
public static void main(String[] args) {
try{
JaxWsDynamicClientFactory factory = JaxWsDynamicClientFactory.newInstance();
//现在网络上也会提供一些免费的web服务供我们访问
String url = "http://localhost:8080/Day1105_WebService/services/productService?wsdl";
String methodname="findAllProduct";
//通过工厂类创建客户端,通过invoke调用方法
Object[] results=factory.createClient(url).invoke(methodname);
List<Product> list =(List<Product>) results[0];
for (Product product:list) {
System.out.println(product);
}
}catch(Exception e){
e.printStackTrace();
}
}
注意,此处List里面的对象是pojo中的实体类,必须将pojo中的实体类放到service包中,也就是接口和实体类在同一个包下,否则接口包中找不到动态代理对象需要的实体类就会报错。
第三种:通用性更高的动态调用,客户端甚至不需要有代理对象的接口:
服务端会定义新方法把发送给客户端的对象类型或List等其他类型转换成String再发送到客户端!
这里用到了阿里巴巴的工具包fast-json.jar需要导包
@WebService
public interface ProduceService {
List<Product> findAllProduct();
String getByJson();
}
--------------------------------------------------------------------------
import com.alibaba.fastjson.JSON;
@WebService
public class ProductServiceImpl implements ProduceService {
@Override
public List<Product> findAllProduct() {
List<Product> list = new ArrayList<Product>();
for (int i=0;i<3;i++) {
list.add(new Product("ihpone",3000D));
}
return list;
}
@Override
public String getByJson() {
List<Product> list = new ArrayList<Product>();
for (int i=0;i<3;i++) {
list.add(new Product("ihpone",3000D));
}
String json = JSON.toJSONString(list);
return json;
}
}
然后发布出去(启动服务端tomcat),看wsdl里有没有新添加的json信息,有就说明发布成功
客户端创建一个测试类测试:
//不封装,收到的是json的数据而不是自定义的封装对象
public static void main(String[] args) {
try{
Object[] result = JaxWsDynamicClientFactory.newInstance()
.createClient("http://localhost:8080/Day1105_WebService/services/productService?wsdl")
.invoke("getByJson");
JSONArray array = JSON.parseArray(result[0].toString());
for (int i=0;i<array.size();i++ ){
JSONObject obj = array.getJSONObject(i);
System.out.println(obj.getString("productName")+","+obj.getDouble("price"));
}
}catch(Exception e){
e.printStackTrace();
}
}
}
----------------------------------------------------------------------------------------------------------------------------------------------------------------------
RESTful 风格的 webservice 越来越流行了, sun 也推出了 RESTful WebService 的官方规范: JAX-RS ,全称:
Java API for RESTful WebService。该规范定义了一系列的注解
RESTful 简化了 web service 的设计,它不再需要 wsdl ,也不再需要 soap 协议,
而是通过最简单的 http 协议传输数据 ( 包括 xml 或 json) 。
既简化了设计,也减少了网络传输量(因为只传输代表数据的 xml 或 json ,没有额外的 xml 包装)。
REST(Representational State Transfer-表现层状态转化)是一种新的软件架构风格,
它以资源(resource)为核心,使用 HTTP、 URI、XML 以及 HTML 等流行协议和标准来完成对资源的操作及显示。
这些操作包括获取、创建、修改和删除资源(CRUD),分别对应于 HTTP 协议的 GET、POST、PUT 和 DELETE 方法。
RESTful架构可以总结为以下三个内容:
(1)每一个URI代表一种资源;
(2)客户端和服务器之间,传递这种资源的某种表现层;
(3)客户端通过四个HTTP动词,对服务器端资源进行操作,实现”表现层状态转化”。
对应数据库的操作, 有以下请求
GET用来获取资源,
POST用来新建资源(也可以用于更新资源),
PUT用来更新资源,
DELETE用来删除资源。
注释(Annotation):
在 javax.ws.rs.* 中定义,是 JAX-RS (JSR 311) 规范的一部分。
@Path:定义资源基 URI。由上下文根和主机名组成,资源标识符类似于 http://localhost:8080/RESTful/rest/hello。
@GET:这意味着以下方法可以响应 HTTP GET 方法。
@Produces:以纯文本方式定义响应内容 MIME 类型。
@Context: 使用该注释注入上下文对象,比如 Request、Response、UriInfo、ServletContext 等。
@Path("{contact}"):这是 @Path 注释,与根路径 “/contacts” 结合形成子资源的 URI。
@PathParam("contact"):该注释将参数注入方法参数的路径,在本例中就是联系人 id。其他可用的注释有 @FormParam、@QueryParam 等。
@Produces:响应支持多个 MIME 类型。在本例和上一个示例中,APPLICATION/XML 将是默认的 MIME 类型。
http://localhost:8080/cxf-restful-server/services