首先咱们来谈一下为何须要学习webService这样的一个技术吧....html
若是咱们的网站须要提供一个天气预报这样一个需求的话,那咱们该怎么作?????前端
天气预报这么一个功能并非简单的JS组件就可以实现的,它的数据是依赖数据库分析出来的,甚至须要卫星探测..咱们我的建站是不可能搞这么一个数据库的吧。java
那么既然咱们本身干不了,咱们能够去找别人吗???咱们从搜索引擎搜索,能够发现不少提供天气预报的网站,可是它返回的是一个网页,而咱们仅仅须要的是对应的数据!android
咱们可能就在想,咱们能不能仅仅只要它返回的数据,而并非通过加工处理后返回的网页呢??ios
因而乎,webService就诞生了,webservice就是一个部署在Web服务器上的,它向外界暴露出一个可以经过Web进行调用的API。也就是说:当咱们想要获取天气预报的信息,咱们能够调用别人写好的service服务,咱们调用就可以获得结果了!web
但是咱们写网站主流的就有好几个平台:Java、.net、PHP等等,那么部署在Web服务器上的服务器也就是webserice怎么可以就让咱们不一样的平台都可以调用呢??spring
咱们知道java、.net这样的平台他们语言的基本数据类型、复杂数据类型就可能不同,那么怎么可以实现调用的呢???数据库
来引用一段话apache
你们在写应用程序查询数据库时,并无考虑过为何能够将查询结果返回给上层的应用程序,甚至认为,这就是数据库应该作的,其实否则,这是数据库经过TCP/IP协议与另外一个应用程序进行交流的结果,而上层是什么样的应用程序,是用什么语言,数据库自己并不知道,它只知道接收到了一份协议,这就是SQL92查询标准协议。编程
不管是Java、.net、PHP等等的平台,只要是网页开发都是能够经过http协议来进行通讯的,而且返回的数据要是通用的话,那么咱们早就学过这样的一种技术【XML】
因此webservice实际上就是http+XML
WebService,顾名思义就是基于Web的服务。它使用Web(HTTP)方式,接收和响应外部系统的某种请求。从而实现远程调用.
咱们能够调用互联网上查询天气信息Web服务,而后将它嵌入到咱们的程序(C/S或B/S程序)当中来,当用户从咱们的网点看到天气信息时,他会认为咱们为他提供了不少的信息服务,但其实咱们什么也没有作,只是简单调用了一下服务器上的一段代码而已。
学习WebService能够将你的服务(一段代码)发布到互联网上让别人去调用,也能够调用别人机器上发布的WebService,就像使用本身的代码同样.。
咱们在学习Java基础网络编程章节已经知道了Scoket这么一个链接了。
public class SocketSer { public static void main(String[] args) throws Exception { ServerSocket ss = new ServerSocket(6666); boolean flag = true; while (flag) { //接收客户端的请求 System.out.println("监听客户端的数据:"); Socket sc = ss.accept(); InputStream is = sc.getInputStream(); byte[] buffer = new byte[1024]; int len = -1; len = is.read(buffer); String getData = new String(buffer, 0, len); System.out.println("从客户端获取的数据:" + getData); //业务处理 大小写转化 String outPutData = getData.toUpperCase(); //向客户端写数据 OutputStream os = sc.getOutputStream(); os.write(outPutData.getBytes("UTF-8")); //释放资源 os.close(); is.close(); sc.close(); } ss.close(); } }
public class SocketClient { public static void main(String[] args) throws Exception { //获取用户输入的数据 Scanner input = new Scanner(System.in); System.out.println("请输入数据:"); String inputData = input.nextLine(); //开启一个Socket端口 Socket sc = new Socket("127.0.0.1", 6666); OutputStream os = sc.getOutputStream(); os.write(inputData.getBytes()); //获取服务端回传的数据 InputStream is = sc.getInputStream(); byte[] buffer = new byte[1024]; int len = -1; len = is.read(buffer); String getData = new String(buffer, 0, len); System.out.println("从服务端获取的数据:" + getData); //是否流 is.close(); os.close(); sc.close(); } }
当咱们从客户端输入数据之后,那么服务端就会把数据转成是大写
其实HTTP协议就是基于Socket对其进行封装,咱们也能够在IE浏览器中对其进行访问.咱们同样可以获取获得数据!
ISO的七层模型 : 物理层、数据链路层、网络层、传输层、表示层、会话层、应用层
Socket访问 : Socket属于传输层,它是对Tcp/ip协议的实现,包含TCP/UDP,它是全部通讯协议的基础,Http协议须要Socket支持,以Socket做为基础
Socket通讯特色:
Http协议访问 :属于应用层的协议,对Socket进行了封装
**数据封装不够友好 :能够用xml封装数据 **
**但愿给第三方应用提供web方式的服务 (http + xml) = web Service**
首先,咱们来尝试一下调用别人写好的webService,来体验一把:咱们访问www.webxml.com.cn/zh_cn/index…
进入到里边
当咱们输入一个号码,它就可以查询出咱们的手机位置信息:
咱们如今要作的就是将这个服务让咱们本身写的应用程序中也能够调用,那怎么作呢???
public void get(String mobileCode ,String userID ) throws Exception{ URL url=new URL("http://ws.webxml.com.cn/WebServices/MobileCodeWS.asmx/getMobileCodeInfo?mobileCode="+mobileCode+ "&userID="+userID); HttpURLConnection conn=(HttpURLConnection) url.openConnection(); conn.setConnectTimeout(5000); conn.setRequestMethod("GET"); if(conn.getResponseCode()==HttpURLConnection.HTTP_OK){ //结果码=200 InputStream is=conn.getInputStream(); //内存流 , ByteArrayOutputStream boas=new ByteArrayOutputStream(); byte[] buffer=new byte[1024]; int len=-1; while((len=is.read(buffer))!=-1){ boas.write(buffer, 0, len); } System.out.println("GET请求获取的数据:"+boas.toString()); boas.close(); is.close(); } }
为何要使用HttpClient工具:
HttpClient使用步骤以下:
//2.Post请求 :经过Http-Client 框架来模拟实现 Http请求 public void post(String mobileCode ,String userID) throws Exception{ /**HttpClient访问网络的实现步骤: * 1. 准备一个请求客户端:浏览器 * 2. 准备请求方式: GET 、POST * 3. 设置要传递的参数 * 4.执行请求 * 5. 获取结果 */ HttpClient client=new HttpClient(); PostMethod postMethod=new PostMethod("http://ws.webxml.com.cn/WebServices/MobileCodeWS.asmx/getMobileCodeInfo"); //3.设置请求参数 postMethod.setParameter("mobileCode", mobileCode); postMethod.setParameter("userID", userID); //4.执行请求 ,结果码 int code=client.executeMethod(postMethod); //5. 获取结果 String result=postMethod.getResponseBodyAsString(); System.out.println("Post请求的结果:"+result); } //2.Post请求 :经过Http-Client 框架来模拟实现 Http请求 public void soap() throws Exception{ HttpClient client=new HttpClient(); PostMethod postMethod=new PostMethod("http://ws.webxml.com.cn/WebServices/MobileCodeWS.asmx"); //3.设置请求参数 postMethod.setRequestBody(new FileInputStream("c:/soap.xml")); //修改请求的头部 postMethod.setRequestHeader("Content-Type", "text/xml; charset=utf-8"); //4.执行请求 ,结果码 int code=client.executeMethod(postMethod); System.out.println("结果码:"+code); //5. 获取结果 String result=postMethod.getResponseBodyAsString(); System.out.println("Post请求的结果:"+result); }
上面咱们使用的是GET方式或者使用Http-Client框架来调用webservice的服务,其实这两种方式也有弊端
若是咱们能够把整个对象传递进去,返回的结果更加友好的话,就好像咱们日常调用Java类同样使用webservice就好咯!
Java也提供了相似的方法,把webservice服务搞成是Java类让咱们本身调用,既然是Java类的话,那么咱们使用起来就很是方便了!
把webservice服务搞成是Java类让咱们本身调用其实就是Java帮咱们生成本地代理,再经过本地代理来访问webservice
wsimport是Java自带的一个命令,咱们想要使用该命令,就必须配置环境变量,而且jdk的版本最好是1.7或以上
值得注意的是:ide带的JDK版本要和wsimport生成本地的版本一致,否则就用不了!!!
wsimport [opations] <wsdl_uri>
wsdl_uri:wsdl 的统一资源标识符
d :指定要输出的文件的位置
s :表示要解析java的源码 ,默认解析出的是class字节码
p : 指定输出的包名
首先咱们先把cmd的路径退到桌面上:
而后对WSDL文件生成本地代理
该本地代理其实就是一堆的字节码文件
将获得的字节码文件打包成jar,那么咱们只要在项目中导入jar包,就能够调用了!
语法
jar cvf test.jar【jar包的名称】 打包目录
原本我是想将本地代理的class文件生成jar包,而后导入到idea环境下,那么直接调用就好了。但是idea总是报出找不到对应的类,找了半天也找不到,很烦呀!!!!我考虑了如下的几种状况
最后我仍是没有找到办法,若是知道是什么缘由的,麻烦在评论中告诉我吧....所以此次的测试import,我就不只仅生成class字节码文件,还生成了.java文件。我就直接使用java文件来测试了。
在zhongfucheng目录下生成本地代理,把java源码也带上
因而我就把java源码复制到个人项目中,用java源码来进行测试
有的同窗可能会疑问,为啥wsimport能那么厉害,将http://ws.webxml.com.cn/WebServices/MobileCodeWS.asmx?WSDL
这么一个url生成本地代理,其实咱们看了WSDL文件就知道了。
值得注意的是,本地代理仅仅是有其方法,类,并不能解析出具体的实现的。具体的操做其实仍是webservice去完成的。代理这么一个概念就更加清晰了。
咱们在上一章节中已经使用wsimport生成本地代理来调用webservice的服务了,其实咱们本身写的web应用程序也是能够发布webservice的
咱们发布了webservice的话,那么其余人也是能够调用咱们本身写的webservice!
那么咱们怎么自定义webservice而后发布出去呢???
在jdk 1.6 版本之后 ,**经过jax-ws 包提供对webservice的支持 **
写一个实体:
public class Phone { private String name;//操做系统名 private String owner;//拥有者 private int total;//市场占有率 public String getName() { return name; } public void setName(String name) { this.name = name; } public String getOwner() { return owner; } public void setOwner(String owner) { this.owner = owner; } public int getTotal() { return total; } public void setTotal(int total) { this.total = total; } }
发布service,经过注解来让WSDL文件更加可读...
package cn.it.ws.d; import cn.it.ws.model.Phone; import javax.jws.WebMethod; import javax.jws.WebParam; import javax.jws.WebResult; import javax.jws.WebService; import javax.xml.ws.Endpoint; /* *手机的业务类,该业务类经过webservice 对外提供服务 * 1. 声明: @webservice * 2. 发布 EndPoint */ @WebService (serviceName="PhoneManager",//修改服务名 targetNamespace="http://dd.ws.it.cn") //修改命名空间 ,默认包名,取反 //声明该业务类 对外提供webservice服务 ,默认只是对public 修饰的方法对外以webservice形式发布 public class PhoneService { /**@WebMethod(operationName="getMObileInfo"): 修改方法名 * @WebResult(name="phone"):修改返回参数名 * @WebParam(name="osName"):修改输入参数名 */ @WebMethod(operationName="getMObileInfo") public @WebResult(name="phone") Phone getPhoneInfo(@WebParam(name="osName")String osName){ Phone phone=new Phone(); if(osName.endsWith("android")){ phone.setName("android");phone.setOwner("google");phone.setTotal(80); }else if(osName.endsWith("ios")){ phone.setName("ios");phone.setOwner("apple");phone.setTotal(15); }else{ phone.setName("windows phone");phone.setOwner("microsoft");phone.setTotal(5); } return phone; } @WebMethod(exclude=true)//把该方法排除在外 public void sayHello(String city){ System.out.println("你好:"+city); } private void sayLuck(String city){ System.out.println("好友:"+city); } void sayGoodBye(String city){ System.out.println("拜拜:"+city); } protected void saySayalala(String city){ System.out.println("再见!"+city); } public static void main(String[] args) { String address1="http://127.0.0.1:8888/ws/phoneService"; // String address2="http://127.0.0.1:8888/ws/phoneManager"; /** * 发布webservice服务 * 1.address:服务的地址 * 2:implementor 服务的实现对象 */ Endpoint.publish(address1, new PhoneService()); // Endpoint.publish(address2, new PhoneService()); System.out.println("wsdl地址 :"+address1+"?WSDL"); } }
@WebService // 添加了此注解,表明是一个WebService public class HelloWorld { // 非 static final private 方法默认会发布 public String sayHi(String name) { return "hello" + name; } @WebMethod(exclude=true) public void exclude(){ // 被注解排除的方法 } protected void protected1(){ //受保护的方法默认不发布 } private void private1(){ // 私有方法默认不发布 } public static void static1(){ // static 方法默认不发布 } public final void final1(){ // final 方法默认不发布 } }
生成的webservice可以在浏览器访问
目前WebService的协议主要有SOAP1.1和1.2。
xmlns:soap="http://www.w3.org/2003/05/soap-envelope“
Soa(Service-Oriented Architecture) :面向服务的架构,它是一种思想,IBM大力倡导是即插即用的,IBM大力提倡,但愿以组装电脑的方式来开发应用
组成:
面向web的服务,面向web的组件 :WebService : 硬盘、cpu、内存条
企业服务总线 (EnterPrise Service Bus :ESB)。主板
uddi (Universal Description, Discovery and Integration)统一描述、发现、集成
import javax.jws.WebService; /**面向接口的webservice发布方式 * * */ @WebService public interface JobService { public String getJob(); }
import javax.jws.WebService; @WebService(endpointInterface="cn.it.ws.e.JobService")//设置服务端点接口 ,指定对外提供服务的接口 public class JobServiceImpl implements JobService { @Override public String getJob() { return "JEE研发工程师|Android研发工程师|数据库工程师|前端工程师|测试工程师|运维工程师"; } public void say(){ System.out.println("早上好!"); } }
import javax.xml.ws.Endpoint; public class Test { public static void main(String[] args) { JobService jobService=new JobServiceImpl(); String address="http://192.168.114.10:9999/ws/jobservice"; Endpoint.publish(address, jobService); System.out.println("wsdl地址:"+address+"?WSDL"); } }
Apache CXF 是一个开源的 Services 框架,CXF 帮助您来构建和开发 Services 这些 Services 能够支持多种协议,好比:SOAP、POST/HTTP、RESTful HTTP CXF 大大简化了 Service能够自然地和 Spring 进行无缝集成。
CXF介绍 :soa的框架
* cxf 是 Celtrix (ESB框架)和 XFire(webserivice) 合并而成,而且捐给了apache
* CxF的核心是org.apache.cxf.Bus(总线),相似于Spring的 ApplicationContext
* CXF默认是依赖于Spring的
* Apache CXF 发行包中的jar,若是所有放到lib中,须要 JDK1.6 及以上,不然会报JAX-WS版本不一致的问题
* CXF 内置了Jetty服务器 ,它是servlet容器,比如tomcat
CXF特色
要想使用CXF框架,那么就先导入jar包
接口
import javax.jws.WebParam; import javax.jws.WebResult; import javax.jws.WebService; @WebService(serviceName="languageManager") public interface LanguageService { public @WebResult(name="language")String getLanguage(@WebParam(name="position")int position); }
实现:
package cn.it.ws.cxf.a; import org.apache.cxf.frontend.ServerFactoryBean; import org.apache.cxf.interceptor.LoggingInInterceptor; import org.apache.cxf.interceptor.LoggingOutInterceptor; import org.apache.cxf.jaxws.JaxWsServerFactoryBean; /**开发语言排行描述服务 * * * @author 李俊 2015年5月17日 */ public class LanguageServiceImpl implements LanguageService { /* (non-Javadoc) * @see cn.it.ws.cxf.a.LanguageService#getLanguage(int) */ @Override public String getLanguage(int position){ String language=null; switch (position) { case 1: language="java"; break; case 2: language="C"; break; case 3: language="Objective-C"; break; case 4: language="C#"; break; default: break; } return language; } /**经过cxf框架发布webservice * 1. ServerFactoryBean * - 不设置注解也能够发布webservice服务, 不支持注解 * - 不支持拦截器的添加 * 2. JaxWsServerFactoryBean * - 支持注解 * - 能够添加拦截器 * 3. webservice 访问流程: * 1. 检测本地代理描述的wsdl是否与服务端的wsdl一致 ,俗称为握手 * 2. 经过soap协议实现通讯 ,采用的是post请求 , 数据封装在知足soap规约的xml中 * 3. 返回数据 一样采用的是soap通讯, 数据封装在知足soap规约的xml中 * @param args public static void main(String[] args) { LanguageService languageService=new LanguageServiceImpl(); ServerFactoryBean bean=new ServerFactoryBean(); //Endpoint :地址 , 实现对象 bean.setAddress("http://192.168.114.10:9999/ws/cxf/languangeService"); bean.setServiceClass(LanguageService.class);//对外提供webservcie的业务类或者接口 bean.setServiceBean(languageService);//服务的实现bean bean.create();//建立,发布webservice System.out.println("wsdl地址:http://192.168.114.10:9999/ws/cxf/languangeService?WSDL"); } */ public static void main(String[] args) { LanguageService languageService=new LanguageServiceImpl(); JaxWsServerFactoryBean bean=new JaxWsServerFactoryBean(); //Endpoint :地址 , 实现对象 bean.setAddress("http://192.168.114.10:9999/ws/cxf/languangeService"); bean.setServiceClass(LanguageService.class);//对外提供webservcie的业务类或者接口 bean.setServiceBean(languageService);//服务的实现bean //添加输入拦截器 :输入显示日志信息的拦截器 bean.getInInterceptors().add(new LoggingInInterceptor()); //添加输出拦截器 :输出显示日志信息的拦截器 bean.getOutInterceptors().add(new LoggingOutInterceptor()); bean.create();//建立,发布webservice System.out.println("wsdl地址:http://192.168.114.10:9999/ws/cxf/languangeService?WSDL"); } }
web.xml配置文件:
<?xml version="1.0" encoding="UTF-8"?> <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_3_0.xsd" version="3.0"> <display-name>CXF_Server</display-name> <!-- 添加 CXF 的Servlet ,处理 webservice的请求 --> <servlet> <servlet-name>cxf</servlet-name> <servlet-class>org.apache.cxf.transport.servlet.CXFServlet</servlet-class> <load-on-startup>0</load-on-startup> </servlet> <servlet-mapping> <servlet-name>cxf</servlet-name> <url-pattern>/ws/*</url-pattern> </servlet-mapping> <!-- Spring 监听添加 --> <listener> <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class> </listener> <context-param> <param-name>contextConfigLocation</param-name> <param-value>classpath:applicationContext.xml</param-value> </context-param> </web-app>
实体:
public class Employee { private Integer id; private String name; private Integer age; public Integer getId() { return id; } public void setId(Integer id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } public Integer getAge() { return age; } public void setAge(Integer age) { this.age = age; } }
接口:
package cn.it.ws.cxf.b; import java.util.List; import javax.jws.WebParam; import javax.jws.WebResult; import javax.jws.WebService; import cn.it.ws.cxf.bean.Employee; @WebService(serviceName="EmployeeService") public interface EmployeeManager { void add(@WebParam(name="employee")Employee employee); @WebResult(name="employees")List<Employee> query(); }
接口实现:
package cn.it.ws.cxf.b; import java.util.ArrayList; import java.util.List; import cn.it.ws.cxf.bean.Employee; /**员工管理的业务实现类 * @author 李俊 2015年5月17日 */ public class EmployeeManagerImpl implements EmployeeManager { private List<Employee> employees=new ArrayList<>(); @Override public void add(Employee employee){ //添加到集合中 employees.add(employee); } @Override public List<Employee> query(){ return employees; } }
Spring配置信息:
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:p="http://www.springframework.org/schema/p" xmlns:jaxws="http://cxf.apache.org/jaxws" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.1.xsd http://cxf.apache.org/jaxws http://cxf.apache.org/schemas/jaxws.xsd"> <bean id="employeeManagerImpl" class="cn.it.ws.cxf.b.EmployeeManagerImpl"></bean> <!-- 配置cxf 地址: http://192.168.114.10:8080/CXF_Server/ws/employeeManager 组成 : http://192.168.114.10:8080 +CXF_Server( 项目名)+ws(过滤的路径)+/employeeManager(自定义部分) 服务类 : 服务的实现类: 拦截器 --> <jaxws:server address="/employeeManager" serviceClass="cn.it.ws.cxf.b.EmployeeManager"> <jaxws:serviceBean> <ref bean="employeeManagerImpl"/> </jaxws:serviceBean> <!-- 配置输入显示日志信息的拦截器 --> <jaxws:inInterceptors> <bean class="org.apache.cxf.interceptor.LoggingInInterceptor"></bean> </jaxws:inInterceptors> <jaxws:outInterceptors> <bean class="org.apache.cxf.interceptor.LoggingOutInterceptor"></bean> </jaxws:outInterceptors> </jaxws:server> </beans>
咱们的Intellij idea是一个很是好用的java ide,固然了,它也支持webservice开发。很是好用...因为在网上见到的教程很是多,我就贴几个我认为比较好的教程:
咱们如今webservice就基本入门了,如今我想要作的就是本身写的网站可以拿到天气预报的信息,因而我去www.webxml.com.cn/zh_cn/index…找到了天气预报的服务
这个是天气预报的WSDL地址:ws.webxml.com.cn/WebServices…,那么咱们只要解析该WSDL服务便可
若是不想获得全部的信息,那么咱们能够在服务上找到咱们想要对应的数据,也就是说:
若是文章有错的地方欢迎指正,你们互相交流。习惯在微信看技术文章,想要获取更多的Java资源的同窗,能够关注微信公众号:Java3y