WebService第二天
课程安排:(CXF+HESSIAN)
框架CXF概述(是什么,SOA概述,下载安装) CXF快速入门(服务端、客户端开发,日志拦截器,SOAP版本相互调用的) CXF与spring的整合(一个完整案例:服务端+客户端) Hessian概述(rmi、支持的语言。。。。下载。。。) Hessian与servlet整合(服务端,客户端) Hessian与spring的整合(服务端,客户端) Hessian的复杂数据类型的支持 接口业务的相关事项
课程目标:
CXF框架的学习 Hessian框架的学习
官方概述
Apache CXF is an open source services framework. CXF helps you build and develop services using frontend programming APIs, like JAX-WS and JAX-RS. These services can speak a variety of protocols such as SOAP, XML/HTTP, RESTful HTTP, or CORBA and work over a variety of transports such as HTTP, JMS or JBI.
翻译:
Apache CXF 是一个开源的 Services 框架,CXF 帮助您利用 Frontend 编程 API 来构建和开发 Services ,像 JAX-WS 。这些 Services 可以支持多种协议,比如:SOAP、XML/HTTP、RESTful HTTP 或者 CORBA ,并且可以在多种传输协议上运行,比如:HTTP、JMS 或者 JBI,CXF 大大简化了 Services 的创建,同时它继承了 XFire 传统,一样可以天然地和 Spring 进行无缝集成。
CXF的出身:
Apache CXF = Celtix + XFire,Apache CXF 的前身叫 Apache CeltiXfire,现在已经正式更名为 Apache CXF 了,以下简称为 CXF。CXF 继承了 Celtix 和 XFire 两大开源项目的精华,提供了对 JAX-WS 全面的支持。
CXF是基于SOA总线结构,可用于构建SOA架构的应用,最终SOA方式。
SOA (Service-oriented architecture)(面向服务的体系结构):-(百度百科)
面向服务的体系结构是一个组件模型(架构的范式),它将应用程序的不同功能单元(称为服务)通过这些服务之间定义良好的接口和契约联系起来。接口是采用中立的方式进行定义的,它应该独立于实现服务的硬件平台、操作系统和编程语言。这使得构建在各种各样的系统中的服务可以使用一种统一和通用的方式进行交互。
SOA应该具有五个特征:可重用、松耦合、明确定义的接口、无状态的服务设计、基于开放标准。
SOA的明显特征是服务之间的松耦合。松耦合系统的好处有两点,一点是它的灵活性,另一点是,当组成整个应用程序的每个服务的内部结构和实现逐渐地发生改变时,它能够继续存在。而另一方面,紧耦合意味着应用程序的不同组件之间的接口与其功能和结构是紧密相连的,因而当需要对部分或整个应用程序进行某种形式的更改时,它们就显得非常脆弱。
另一种解释
SOA-面向服务的架构,可以说是一种架构风格,一种IT系统咨询和建设的方法论,也可以说是一种新的商业模式,SOA核心从SOA定义可以看到包括两个方面内容,一个是抽象出服务,这些服务满足离散,松耦合,可复用,自治,无状态等基本特征,一个是服务可以灵活的组装和编排,满足流程整合和业务变化的需要。所以SOA是一个很宽泛的概念,只要满足上面两条,实施思路是符合上面两条都是SOA的思路。
SOA不限定采用何种技术,只要是开放、标准的技术即可,比如JMS、RESTful Service、Axis2、CXF等。
换句话说:
SOA是一种思想,就是把项目拆成组件,每个组件暴露出服务,"你调我,我调你",大家一起把活干完。强调的是服务的相互调用。
web service是SOA很常用的一种传输协议。
WebService和SOA的关系:
WebService和SOA架构风格没有直接关系,Web-Service只是一种实现方法,不用Web-Service也可以实现SOA架构风格,这一点必须明确。否则一谈到SOA就简单理解为web service就犯大错误了。
SOA随着历史的发展,理解也不断在更新,现在更多的分布式的思想。(组件的分离+互相调用—解耦合)
【提示】
SOAP容易与SOA——Service-oriented architecture产生歧义,虽然它们之间存在非常大的差异。
网址:http://cxf.apache.org
官方最新:3.1.6
本次:2.6.15
下载:
安装方式:
1.先解压到一个目录(不能有中文、特殊字符)
2.配置环境变量
CXF_HOME=D:\DevIDE\Java\apache-cxf-2.6.15
path=%CXF_HOME%/bin;
测试是否安装成功?
提示:不管用什么技术,尽量多参考官方文档。
参考官方的案例,来开发:
开发:
1.创建java工程
2.导入jar包
将目录中的jar都引入到工程即可。(注意一个目录和一个which_jar不要拷贝进去)
【补充】
如何选择jar
可以参考该版本lib中的which_jar文件
3.编写SEI
4.在SEI的接口类上添加注解
5.发布服务
测试(通过访问wsdl):
【提示】
如果用火狐访问,头部信息隐藏。其他浏览器没有问题
【扩展】
jetty就是一个应用服务器,和tomcat作用差不多。但它更轻量级。可以用于内嵌的web服务、可以方便测试。
基本启动方式:
【提示】
cxf开发的时候,sei上面的注解都写在接口上。
wsdl文档的生成更依赖于接口,和实现类关系不大,好处是解耦合,更加面向对象。
参考:
1.生成桩、本地代理接口类—wsdl2java
将其复制到工程中
2.编写测试代码
拦截器:增强功能!
CXF拦截器:增强扩展CXF的!
拦截器的作用:
拦截器的原理
【了解】
CXF已经实现了很多种拦截器,如果要自定义拦截器,则需要实现PhaseInterceptor接口,不过一般都是继承自AbstractPhaseInterceptor< T extends org.apache.cxf.message.Message >类,这个类可以指定继承它的拦截器在什么阶段被启用,阶段属性可以通过org.apache.cxf.phase.Phase 中的常量指定值。
日志拦截器的作用:
它是cxf拦截器的一种,查看日志(soap相关)。
可以解决:相互调用的日志、发送或接收的报文、请求的次数等。
日志拦截器分类:
目标:要在服务端查看被调用的情况(请求的数据和响应的数据等)。
方式:在服务端加入日志拦截器。
重启服务端,调用客户端测试:
【日志的作用】
主要用来"联调"(联合调试)
业务场景:双方发生了纠纷。客户端说,服务端给的数据不对。双方就要进行联合调试(简称联调),大家约个时间,把各自的日志打开,客户端开始发请求,双方要对日志。目的看看双方的请求和响应是否达到预期。
还有个作用,用来查询错误。
比如,有客户投诉,经常请求之后结果不对,请求超时。。。。。
解决方案:查看日志。
日志拦截器中的ID,是拦截的编号,作用是为了标识请求的次数以及请求和响应对应的编号。
日志拦截器客户端的加入:
ok
可以调用。
客户端:请求1。1,接收:1。1
服务端:接收1。1,响应:1。1
原因:服务端自动降级。
更改客户端的代码
结论:
客户端:请求1。2,接收1。2
服务端:接收1。2,响应1。2
【扩展回顾】单例:
将服务端更改为1。1,直接去掉注解就可以了
结论:
客户端:请求1。2,接收:服务端错误信息
服务端:接收1。2,响应:http(错误处理的cxf拦截器,直接向客户端发出错误信息,起始根本没有调用业务代码。)
服务端的整合方式:
发挥spring的粘合剂的作用,将对象创建的权利和管理都交给spring。(IoC思想)
可以将webservice的服务和普通的web服务放在一起启动。换句话说,我们要使用tomcat来启动ws服务。不再使用main方法。
整体:web容器tomcat---》加载spring容器----》初始化webservice服务。
架构设计:
数据库itcast30:
准备数据:
参考:官方demo
1.新建web工程:
2.导入jar搭建基本开发环境
Spring:4(core\bean\context\ expression)+web
CXF:cxf相关和依赖
【提示】
如果你的项目用的新版本,那么这里的spring的包就别拷贝了。
3.SEI的编写,并在接口类上加注解—业务层
业务层:将其放到service层
MobileAddressService
//SEI的接口(服务端点接口)
//手机号归属地查询
@WebService(
name="MobileAddress"//porttype
,serviceName="MobileAddressService"//服务名字
,portName="MobileAddressPort"//端口的名字
,targetNamespace="http://ws.itcast.cn/"//自定义名称空间
)
//更改soap版本
@BindingType(value=javax.xml.ws.soap.SOAPBinding.SOAP12HTTP_BINDING)
public interface MobileAddress {
/**
* 根据手机号码查询返回归属地信息
* @param mobileNo
* @return
*/
@WebMethod(operationName="getAddressByMobileNo")
public @WebResult(name="address") String
getAddressByMobileNo(@WebParam(name="mobileNo")String mobileNo);
}
MobileAddressServiceImpl
//sei实现类
public class MobileAddressImpl implements MobileAddress{
//dao
private MobileAddressDAO mobileAddressDAO;
public void setMobileAddressDAO(MobileAddressDAO mobileAddressDAO) {
this.mobileAddressDAO = mobileAddressDAO;
}
@Override
public String getAddressByMobileNo(String mobileNo) {
//实际业务开发:
//判别处理传过来的手机号码是否符合规则等等--校验
//拿手机号调用dao层,向数据库查询数据,返回数据
//调用dao层(使用)
String address=mobileAddressDAO.getAddressByMobileNo(mobileNo.substring(0, 7));
return address;
}
}
4.持久层
引入jdbc工具类:
MobileAddressDAO:
//dao接口
public interface MobileAddressDAO {
/**
* 根据手机号码获取归属地
* @param mobileNo
* @return
*/
public String getAddressByMobileNo(String mobileNo);
}
MobileAddressDAOImpl
//dao实现类
public class MobileAddressDAOImpl implements MobileAddressDAO{
@Override
public String getAddressByMobileNo(String mobileNo) {
//获取连接
Connection conn =null;
PreparedStatement pstmt=null;
ResultSet rs=null;
//pstmt
try {
conn = JDBCUtils.getConnection();
String sql="select * from t_mobileaddress where mobileno = ?";
pstmt = conn.prepareStatement(sql);
//设置参数的值
pstmt.setString(1, mobileNo);
//执行查询
rs = pstmt.executeQuery();
//业务最多只有一条记录
String address="";
if(rs.next()){
address = rs.getString("address");
}
return address;
} catch (SQLException e) {
// e.printStackTrace();
throw new RuntimeException("服务端查询手机号归属地异常", e);
}finally{
JDBCUtils.release(conn, pstmt, rs);
}
}
}
5.配置web.xml
目的:web容器启动的时候自动加载、初始化cxf的服务。
<!-- cxf的核心servlet控制器 -->
<servlet>
<servlet-name>cxf</servlet-name>
<servlet-class>org.apache.cxf.transport.servlet.CXFServlet</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>cxf</servlet-name>
<url-pattern>/services/*</url-pattern>
</servlet-mapping>
6.配置cxf服务端的配置文件
通过源代码分析:
默认情况下,加载
所以,配置一个名字叫cxf-servlet.xml的文件。
<?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:jaxws="http://cxf.apache.org/jaxws"
xsi:schemaLocation="
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://cxf.apache.org/jaxws http://cxf.apache.org/schemas/jaxws.xsd">
<!-- 内置的cxf的功能bean:初始化用 -->
<import resource="classpath:META-INF/cxf/cxf.xml" />
<import resource="classpath:META-INF/cxf/cxf-servlet.xml" />
<!-- 配置webservice的服务 -->
<!-- addresss:服务地址名字 -->
<jaxws:server address="/mobile" serviceClass="cn.itcast.ws.server.service.MobileAddress">
<jaxws:serviceBean>
<ref bean="mobileAddressService"/>
</jaxws:serviceBean>
</jaxws:server>
<!-- dao -->
<bean id="mobileAddressDAO" class="cn.itcast.ws.server.dao.MobileAddressDAOImpl"></bean>
<!-- service -->
<!-- 实例化一个bean -->
<bean id="mobileAddressService" class="cn.itcast.ws.server.service.MobileAddressImpl">
<property name="mobileAddressDAO" ref="mobileAddressDAO"/>
</bean>
</beans>
引入本地提示。
【补充】
xsd的获取:
测试:
地址的访问:
Web容器的地址+servletmap地址+服务地址
http://localhost:8080/ws_day2_cxfspring_server/services/mobile?wsdl
应该用soapui调试测试一下。
更改加载Cxf核心配置文件的方式。
原来是在cxf的servlet
现在主动让spring容器来初始化cxf:
Web.xml
<!-- spring的核心监听器,加载初始化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>
applicationContext.xml
日志拦截器的添加
applictionContext.xml:
<!-- 内置的cxf的功能bean:初始化用 -->
<import resource="classpath:META-INF/cxf/cxf.xml" />
<import resource="classpath:META-INF/cxf/cxf-servlet.xml" />
<!-- 配置webservice的服务 -->
<!--
jaxws:server:jaxwsServerFactoryBean
addresss:服务地址名字
serviceClass:sei接口
jaxws:serviceBean:sei的bean,暴漏给客户端的实例
-->
<jaxws:server address="/mobile" serviceClass="cn.itcast.ws.server.service.MobileAddress">
<jaxws:serviceBean>
<ref bean="mobileAddressService"/>
</jaxws:serviceBean>
<!-- 日志拦截器 -->
<!-- 输入拦截器 -->
<jaxws:inInterceptors>
<!-- 输入的日志拦截器 -->
<ref bean="loggingInInterceptor"/>
</jaxws:inInterceptors>
<!-- 输出的拦截器 -->
<jaxws:outInterceptors>
<!-- 输出的日志拦截器 -->
<ref bean="loggingOutInterceptor"/>
</jaxws:outInterceptors>
</jaxws:server>
<!-- 输入的日志拦截器 -->
<bean id="loggingInInterceptor" class="org.apache.cxf.interceptor.LoggingInInterceptor"/>
<!-- 输出的日志拦截器 -->
<bean id="loggingOutInterceptor" class="org.apache.cxf.interceptor.LoggingOutInterceptor"/>
使用soapui测试:
目标:客户端获取桩(本地代理—spring自动提供)对象就ok
如果和spring整合后,直接从spring容器中获取就可以了。(原理:cxf整合进了spring了)
新建工程:
引入jar。。。和服务端一样。
1.生成桩
拷贝到工程:
2.配置客户端的bean
在类路径下创建
官方头部有问题:
<?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:jaxws="http://cxf.apache.org/jaxws"
xsi:schemaLocation="
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://cxf.apache.org/jaxws http://cxf.apache.org/schemas/jaxws.xsd">
<!-- 配置cxf客户端,获取桩的实例
jaxws:client:jaxwsproxyfactorybean
address:客户端请求的地址
serviceClass:桩的接口
id:桩的实例
-->
<jaxws:client id="mobileStub" address="http://localhost:8080/ws_day2_cxfspring_server/services/mobile"
serviceClass="cn.itcast.ws.client.stub.MobileAddress">
</jaxws:client>
</beans>
客户端测试类:获取桩,通过桩得到数据
public class MobileAddressTest {
public static void main(String[] args) {
//获取spirng容器
ApplicationContext ac = new ClassPathXmlApplicationContext("applicationContext.xml");
//桩本地代理对象实例
MobileAddress ma=(MobileAddress) ac.getBean("mobileStub");
//调用方法,发出请求,打印数据
System.out.println(ma.getAddressByMobileNo("1333333333"));
}
}
Dao:
//手机号查询的dao层
public interface MobileAddressDAO {
/**
* 持久层获取数据:根据手机号码获取归属地
* @param mobileNo
* @return
*/
public String getAddressByMobileNo(String mobileNo);
}
//手机号查询的dao层实现类
public class MobileAddressDAOImpl implements MobileAddressDAO {
//注入桩
private MobileAddress mobileAddress;
public void setMobileAddress(MobileAddress mobileAddress) {
this.mobileAddress = mobileAddress;
}
@Override
public String getAddressByMobileNo(String mobileNo) {
//调用桩
try {
return mobileAddress.getAddressByMobileNo(mobileNo);
} catch (Exception e) {
e.printStackTrace();
throw new RuntimeException("客户端:webservice查询手机号归属地失败", e);
}
}
}
ApplicationContext.xml
<!-- dao -->
<bean id="mobileAddressDAO" class="cn.itcast.ws.client.dao.MobileAddressDAOImpl">
<property name="mobileAddress" ref="mobileStub"/>
</bean>
业务层:service:
//手机号归属地查询的业务层接口
public interface MobileAddressService {
/**
* 持久层获取数据:根据手机号码获取归属地
* @param mobileNo
* @return
*/
public String findAddressByMobileNo(String mobileNo);
}
//手机号归属地查询的业务层实现类
public class MobileAddressServiceImpl implements MobileAddressService{
//注入dao
private MobileAddressDAO mobileAddressDAO;
public void setMobileAddressDAO(MobileAddressDAO mobileAddressDAO) {
this.mobileAddressDAO = mobileAddressDAO;
}
@Override
public String findAddressByMobileNo(String mobileNo) {
//调用dao
return mobileAddressDAO.getAddressByMobileNo(mobileNo);
}
}
ApplicationContext.xml
<!-- service -->
<bean id="mobileAddressService" class="cn.itcast.ws.client.service.MobileAddressServiceImpl">
<property name="mobileAddressDAO" ref="mobileAddressDAO"/>
</bean>
Web.xml:
测试。。。。。
配置多个tomcat,启动测试。
更改tomcat的端口:
启动服务:
测试:
http://localhost:8180/ws_day2_cxfspring_client/mobile.jsp
页面:
引入js:
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>查询手机号归属地</title>
<!-- 引入jquery包 -->
<script type="text/javascript" src="${pageContext.request.contextPath}/js/jquery-1.8.3.js"></script>
<script type="text/javascript">
//加载
$(function(){
//给按钮绑定点击事件
$("#queryBtn").click(function(){
//获取输入的手机号码
var mobileNo =$("input[name='mobileNo']").val();
//异步请求服务器
$("#result").load("${pageContext.request.contextPath}/mobile",{"mobileNo":mobileNo});
});
});
</script>
</head>
<body>
<h1>欢迎使用手机号归属地查询业务</h1>
请输入手机号码:<input type="text" name="mobileNo"/>
<input type="button" id="queryBtn" value="查询"/>
<br/>
查询结果为:<span id="result">没有查询结果</span>
</body>
</html>
表现层:
public class MobileAddressServlet extends HttpServlet {
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
//1.获取页面的参数
request.setCharacterEncoding("utf-8");
String mobileNo = request.getParameter("mobileNo");
//2.调用业务层
//从web容器中获取spring容器
ApplicationContext ac = WebApplicationContextUtils.getWebApplicationContext(this.getServletContext());
MobileAddressService mobileAddressService =(MobileAddressService) ac.getBean("mobileAddressService");
//获取数据
String address = mobileAddressService.findAddressByMobileNo(mobileNo);
//3.将数据放入响应
String result="手机号码没有查询出归属地";
if(StringUtils.isNotBlank(address)){
result=mobileNo+"的手机号码归属地是:"+address;
}
response.setContentType("text/html; charset=UTF-8");
response.getWriter().print(result);
}
public void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
doGet(request, response);
}
}
RMI(Remote Method Invocation,远程方法调用)是Java在JDK1.2中实现的, Java RMI 支持存储于不同地址空间的程序级对象之间彼此进行通信,实现远程对象之间的无缝远程调用。(即它能够让在某个 Java 虚拟机上的对象调用另一个 Java 虚拟机中的对象上的方法)
【优点】:
Java RMI具有Java的"Write Once,Run Anywhere"的优点,是分布式应用系统的百分之百纯Java解决方案。用Java RMI开发的应用系统可以部署在任何支持JRE(Java Run Environment Java,运行环境)的平台上。
【缺点】:
RMI对于用非Java语言开发的应用系统的支持不足。不能与用非Java语言书写的对象进行通信。
在大力鼓吹Web Service、SOA的时代,是不是每个应用都应该选用笨拙的Web Service组件来实现,通过对比测试后,RMI是最简单的,在一些小的应用中是最合适的。
官网介绍:
The Hessian binary web service protocol makes web services usable without requiring a large framework, and without learning yet another alphabet soup of protocols. Because it is a binary protocol, it is well-suited to sending binary data without any need to extend the protocol with attachments.
Hessian是一个由Caucho Technology开发的轻量级二进制RPC协议。和其他Web服务的实现框架不同的是,Hessian是一个使用二进制格式传输的Web服务协议的框架,相对传统soap web service,更轻量,更快速。它的好处在于免除了一大堆附加的API包,例如XML的处理之类的jar包,这也就是为什么说它是一个轻量级的Web服务实现框架的原因,这个原因还在于手机上的应用程序可以通过Hessian提供的API很方便的访问Hessian的Web服务。
目前已经支持N多语言(跨语言平台的特性):
.
对于我们来说,用来在不同的java服务器之间交换数据使用。底层:rmi。
人员系统,订单系统,统计分析系统。--子系统间用快的hessian。
官网: http://hessian.caucho.com/
创建Web工程,引入Hessian的Jar
编写业务接口和实现类(SEI)
配置web.xml
部署到tomcat,测试是否发布成功
创建Java工程,添加Hessian的jar
将服务端的业务接口(stub)复制到客户端工程中
提示:接口名字、包名要和服务端的一致。
编写客户端测试代码
【优化扩展】
客户端的接口类的名字、包名也可以不和服务端的不一致,但需要在创建桩实例的时候指定接口的class,否则会抛出异常。将接口代码更改后,
再运行测试,抛出异常:
优化后的代码:
Spring中除了提供HTTP调用器方式的远程调用,还对第三方的远程调用实现提供了支持,其中提供了对Hessian的支持。
创建Web工程,引入Hessian与Spring整合的Jar
编写业务接口和实现类(SEI)
将上节代码复制过来:
配置web.xml
【提示】DispatcherServlet是前端控制器设计模式的实现,提供Spring Web MVC的集中访问点,而且负责职责的分派,而且与Spring IoC容器无缝集成,从而可以获得Spring的所好处。
所有以/hessian/开头的访问路径,约定成hessian服务地址,详细配置在hessian-servlet.xml中,内容如下:
配置hessian核心配置文件(Spring配置文件)
在WEB-INF下建立一个spring的配置文件,文件名称改为:hessian-servlet.xml
编写内容如下:
【提示】
1)Spring的HessianServiceExporter把远程调用服务整合到Spring MVC框架中,通过DispatcherServlet将客户端请求转发到服务器端相应的请求url远程对象上。
注意:serviceUrl要和客户端serviceUrl中配置的相同,service即是服务端提供服务的远程对象。
2)默认spring MVC的前端控制器会自动读取WEB-INF/ hessian-servlet.xml,文件名必须满足如下要求:
a)hessian-servlet.xml的文件名必须以<servlet-name>hessian</servlet-name>名字开头,并且加上-servlet.xml一段,组成完整的文件名。
b)hessian-servlet.xml的文件名格式必须是[servlet-name]-servlet.xml格式,否则出错。
DispatcherServlet的父类FrameworkServlet中的英文解释:
<p>The default namespace is "'servlet-name'-servlet", e.g. "test-servlet" for a
* servlet-name "test" (leading to a "/WEB-INF/test-servlet.xml" default location
* with XmlWebApplicationContext).
部署到tomcat,测试是否发布成功
地址:http://localhost:8080/hessian_spring_server/hessian/mobile
【提示】
大家不要以为出错了,实际是正常的。
我们用Java客户端代码测试一下。(使用上节的客户端代码)。
【扩展优化】
默认加载的hessian配置文件是在WEB-INF/ hessian-servlet.xml,一般我们会将配置文件放入classpath下,操作方式如下:
新建Web工程,导入整合好的Jar 将服务端的业务接口复制到客户端工程中
配置Spring的配置文件
编写客户端测试代码
【扩展优化】
客户端调用服务端时需要依赖服务端的接口类,一般服务端不将接口类的java文件直接给客户端,可以仅将class文件发给客户端即可。那么可以将需要提供给客户端的接口类统一打成一个jar给客户端:
将其复制到客户端的lib目录即可使用,而不需要再从服务端复制源码了。
客户端测试,ok。
服务端的修改:
增加一个实体类user
在业务层的接口上增加新的方法(保存用户)
发布服务,ok!
客户端调用:
必须将服务端接口和接口依赖的东东都要提供给客户端
拷贝到lib中:
测试类:
发生异常:
Exception in thread "main" java.lang.IllegalStateException: Serialized class cn.itcast.hessian.server.domain.User must implement java.io.Serializable
提示:user类型必须实现序列化接口才能在网络上传输。
注意:必须在服务端序列化,在服务端的实体类上增加序列化:
小结:自定义的类型必须实现序列化才能当参数或返回值传递。
接口机:是独立的一台服务器或者一个服务,专门用来提供接口服务的。它与业务系统分开的。
如果接口的服务和业务(下订单)模块放在一个服务器中,那么可能接口的服务会影响到业务的运转。
如果业务参数比较多,或者返回结果比较多,如何处理?
参数仍然一个:类型字符串(json,xml)--可以在json中传很多数据。
返回仍然也是一个:类型字符串(json,xml)-甚至可以返回列表
这样写,开发工作量,就不在接口开发上了,在解析json和xml上了。
为了跨平台、跨语言,需要使用json字符串来传递数据。
但如果不是为了跨平台和语言,如hessian,建议直接传对象,快!
接口的规范(数据格式等)谁来订?
一般是甲方订。谁强势谁指定。
都不知道谁来指定?一般接口提供方来指定。
SOA思想架构:组件式开发。将不同业务进行解耦合、复用、、。。。。。 Webserice三要素:soap,wsdl,uddi
大Webservice(重)
小Webservice(轻)--restful
Cxf框架与spring整合的开发(服务端和客户端)--完整流程—代码量 Soapui调试工具。(测试的一点概念) Hessian与spring整合开发(服务端和客户端) 杂的知识:单例模式、spring配置、jquery应用 思想+概念---理解记忆
转载于:https://www.cnblogs.com/beyondcj/p/6271114.html
相关资源:数据结构—成绩单生成器