EJB3 阶段总结+一个EJB3案例 (2)
这篇博文接着上一篇博文的EJB案例。
在上一篇博文中,将程序的架构基本给描述出来了,EJB模块分为5层。
1)DB层,即数据库层
在则一部分,我使用的数据库为mysql。在EJB程序中,访问数据库是通过Jboss中配置好的数据源进行的,然后在数据库中建立相应的数据库,不用建立表,在程序中使用JPA后通过Jboss启动会自动在数据库中间表
具体的,可以看我之前写过的博文 wildfly8+jpa EntityBean 简单入门 在这篇博文中具体讲解了如何在Jboss中绑定一个数据源
2)dao层
在这一层中,首先设计好具体的对象EntityBean,然后通过JPA的注解,将EntityBean和数据库进行映射。
在这里还要使用一个EntityManage对象,该对象用于操作数据库,通过该对象可以使程序进行持久化,免去了JDBC时复杂的代码,该对象可分为容器管理和Bean管理,这里使用的是容器管理的EntityManage,通过@PersistenceContext注解将对象注入
并且在该层中,通过接口的方式实现该层,并将该层定义为Local和Stateless,应为该层主要是用于该EJB的内部使用,是在一个JVM中的调用所以使用@Local注解的方式更加的节省资源。
在该层中的方法均抛出继承RunTimeException的异常,为之后的Rollback做准备
3)Business层
该层是业务层,其设计方式同dao层类似,均为实现类和接口方式,使用@Stateless和@Local将接口继续暴露给下一层。
使用@EJB注解调用dao层的对象。(@EJB只能注入EJB对象,@Resource可以注入普通对象)
在该层中,继续抛出RunTimeException异常,以支持回滚,在此处使用容器管理的事物方式,不需要代码管理开头结束,通过RunTimeException来管理
4)Service层
服务层,主要是用于暴露给其他模块调用,在这里我使用的是WebService的方式,当然也可以通过Remote的方式(个人觉得太low),其设置为@Stateless的EJB
在设计这一层代码时,应为使用的是WebService的模式,便产生一个问题:即现有Wsdl还是先有代码。前者的工作量无疑是大于后者的,在设计之初我也更倾向于后者,但项目组的技术大牛给了我很多的启示。一般的企业级javaee项目都会有许多不同的模块,甚至于在有的企业中还有C、C#等各种不同语言写的模块。而在这种情况下,如果使用的是先有代码再有wsdl,无疑开发速度将会加快,但在后期不同模块间使用WebService进行交互时会产生许多问题,如传输的参数在两个模块间类型不一致、参数的个数不一致等等。所以在这里我使用的是先有wsdl再有代码的方式。
一个wsdl分为5个类型节点:types、message、porttype、binding、service。
一个binding表示一个类。一个prottype中包含了具体的方法返回对象。message表示的是具体的方法参数通常成对出现。types中包含各种基本的类型(即组成方法参数的元素)。service表示的是服务,通常是将一个binding注册到服务上,service中包括了webservice访问的地址。
为了便于维护,在一个webservice项目中,通常将types节点中的元素定义部分分割出去,即schema文件。(schema的作用类似与DTD,用于约束xml的节点元素,其适用性强于DTD,目前的项目大部分使用schema)
话不多讲,先上wsdl和一个最基础的schema:
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<wsdl:definitions xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/"
xmlns:tns="http://www.welv.com/wsdl/TeaStuService" xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/"
xmlns:xsd="http://www.w3.org/2001/XMLSchema" name="TeaStuService"
targetNamespace="http://www.welv.com/wsdl/TeaStuService"
xmlns:addGroupType="http://www.welv.com/schema/business/addGroupType"
xmlns:addTeacheType="http://www.welv.com/schema/business/addTeacheType"
xmlns:findTeacheType="http://www.welv.com/schema/business/findTeacheType">
<wsdl:types xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<xsd:schema targetNamespace="http://www.welv.com/wsdl/TeaStuService">
<xsd:import schemaLocation="../schema/business/addGroupType.xsd"
namespace="http://www.welv.com/schema/business/addGroupType" />
<xsd:import schemaLocation="../schema/business/addTeacheType.xsd"
namespace="http://www.welv.com/schema/business/addTeacheType" />
<xsd:import schemaLocation="../schema/business/findTeacheType.xsd"
namespace="http://www.welv.com/schema/business/findTeacheType" />
</xsd:schema>
</wsdl:types> <wsdl:message name="addGroupRequest">
<wsdl:part element="addGroupType:addGroupRequest" name="addGroupRequest" />
</wsdl:message>
<wsdl:message name="addGroupResponse">
<wsdl:part element="addGroupType:addGroupResponse" name="addGroupResponse" />
</wsdl:message>
<wsdl:message name="addTeacheRequest">
<wsdl:part element="addTeacheType:addTeacheRequest" name="addTeacheRequest" />
</wsdl:message>
<wsdl:message name="addTeacheResponse">
<wsdl:part element="addTeacheType:addTeacheResponse" name="addTeacheResponse" />
</wsdl:message>
<wsdl:message name="findTeacheRequest">
<wsdl:part element="findTeacheType:findTeacheRequest" name="findTeacheRequest" />
</wsdl:message>
<wsdl:message name="findTeacheResponse">
<wsdl:part element="findTeacheType:findTeacheResponse" name="findTeacheResponse" />
</wsdl:message> <wsdl:portType name="TeaStuService">
<wsdl:operation name="addGroup">
<wsdl:input message="tns:addGroupRequest" />
<wsdl:output message="tns:addGroupResponse" />
</wsdl:operation>
<wsdl:operation name="addTeache">
<wsdl:input message="tns:addTeacheRequest" />
<wsdl:output message="tns:addTeacheResponse" />
</wsdl:operation>
<wsdl:operation name="findTeache">
<wsdl:input message="tns:findTeacheRequest" />
<wsdl:output message="tns:findTeacheResponse" />
</wsdl:operation>
</wsdl:portType>
<wsdl:binding name="TeaStuServiceBinding-SOAP11HTTP" type="tns:TeaStuService">
<soap:binding style="document"
transport="http://schemas.xmlsoap.org/soap/http" />
<wsdl:operation name="addGroup">
<soap:operation soapAction="http://www.welv.com/wsdl/TeaStuService/addGroup" />
<wsdl:input>
<soap:body use="literal" />
</wsdl:input>
<wsdl:output>
<soap:body use="literal" />
</wsdl:output>
</wsdl:operation>
<wsdl:operation name="addTeache">
<soap:operation soapAction="http://www.welv.com/wsdl/TeaStuService/addTeache" />
<wsdl:input>
<soap:body use="literal" />
</wsdl:input>
<wsdl:output>
<soap:body use="literal" />
</wsdl:output>
</wsdl:operation>
<wsdl:operation name="findTeache">
<soap:operation soapAction="http://www.welv.com/wsdl/TeaStuService/findTeache" />
<wsdl:input>
<soap:body use="literal" />
</wsdl:input>
<wsdl:output>
<soap:body use="literal" />
</wsdl:output>
</wsdl:operation>
</wsdl:binding>
<wsdl:service name="TeaStuService-SOAP11HTTP">
<wsdl:port binding="tns:TeaStuServiceBinding-SOAP11HTTP"
name="TeaStuServiceSOAP">
<soap:address location="http://localhost:8080/service/TeaStuServiceSOAP" />
</wsdl:port>
</wsdl:service>
</wsdl:definitions>
wsdl
<?xml version="1.0" encoding="UTF-8"?>
<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema"
targetNamespace="http://www.welv.com/schema/common/common" xmlns:tns="http://www.welv.com/schema/common/common"
elementFormDefault="qualified"> <xsd:simpleType name="nameType">
<xsd:restriction base="xsd:string"></xsd:restriction>
</xsd:simpleType> <xsd:simpleType name="ageType">
<xsd:restriction base="xsd:integer"></xsd:restriction>
</xsd:simpleType> <xsd:simpleType name="addressType">
<xsd:restriction base="xsd:string"></xsd:restriction>
</xsd:simpleType> <xsd:simpleType name="idType">
<xsd:restriction base="xsd:int"></xsd:restriction>
</xsd:simpleType> <xsd:simpleType name="infoType">
<xsd:restriction base="xsd:string"></xsd:restriction>
</xsd:simpleType> <xsd:element name="name" type="tns:nameType"></xsd:element> <xsd:element name="address" type="tns:addressType"></xsd:element> <xsd:element name="age" type="tns:ageType"></xsd:element> <xsd:element name="id" type="tns:idType"></xsd:element> <xsd:element name="info" type="tns:infoType"></xsd:element>
</xsd:schema>
schema
在schema中可以看到,在types节点中,使用了import节点,将schema引入了wsdl中,而schema则将方法的参数给细分,通过最基本的common文件来组合成各个方法的参数,有利于后期的维护,如Student中的name的字段长度设置为7,则可通过修改common文件中的定义便可。
wsdl准备好后,将其放入EJB工程的Src目录下,然后使用命令:wsimport -keep -verbose -s E:\Resources\JavaEcA\EJB-all\ejbModule E:\Resources\JavaEcA\EJB-all\ejbModule\META-INF\wsdl\TeaStuService.wsdl 将wsdl对应的java代码生成到src目录下,这样一来wsdl对应的java代码便有了。
以下是我使用命令生成的java代码,实现的带有Webservice功能的EJB代码:
@Stateless
@WebService(name = "TeaStuService", targetNamespace = "http://www.welv.com/wsdl/TeaStuService", wsdlLocation = "META-INF/wsdl/TeaStuService.wsdl")
public class TeaStuService_SOAP implements
com.welv.wsdl.teastuservice.TeaStuService { @EJB
private TeaStuService teaStuService; public AddGroupResponseType addGroup(AddGroupRequestType addGroupRequest) {
// TODO Auto-generated method stub
AddGroupResponseType dd = new AddGroupResponseType();
dd.setInfo("wwwww");
return dd;
} public AddTeacheResponseType addTeache(AddTeacheRequestType addTeacheRequest) { TeacheType tt = addTeacheRequest.getTeache();
Teache t = new Teache();
t.setAddress(tt.getAddress());
t.setAge(tt.getAge());
t.setName(tt.getName());
AddTeacheResponseType atr = new AddTeacheResponseType();
atr.setInfo(teaStuService.addTeache(t));
return atr; } public FindTeacheResponseType findTeache(
FindTeacheRequestType findTeacheRequest) {
Teache teache = teaStuService.findTeache(findTeacheRequest.getId());
FindTeacheResponseType ftr = new FindTeacheResponseType();
TeacheType tt = new TeacheType();
tt.setAddress(teache.getAddress());
tt.setAge(teache.getAge());
tt.setId(teache.getId());
tt.setName(teache.getName());
ftr.setTeache(tt);
return ftr;
} }
该类是继承由wsdl生成的java接口的一个类。在类的开头使用@WebService注解,并将wsdl的相对路径注册其中,并要有name和targetnamespace两个属性
将该类部署到Jboss8中,我使用的是Eclipse部署的方式。

在控制台的log中可以看到一个地址,即wsdl中Service节点中定义的webservice地址,在该地址后面加上?wsdl即可访问部署到jboss上的webservice服务。
5)测试
部署完EJB后,使用SoapUI进行测试,Soap的使用不在这里描述。
使用webservice的访问地址将测试工程在SoapUI中建立好后,首先测试的是添加一个Teache对象:

从图中的信息可看出访问成功,然后使用查找Teache的功能检验上一个case是否成功插入数据库

查找成功,WebService和EJB的功能实现
*********************************************************
技术点:
1)wsdl开发中,使用的targetnamespace即目标名称空间,他表示的是文件本身,所以在文件中使用xmlns:tns=“targetnamespace URL”来表示应用自身的节点,而要使用其他的schema文件中的节点会使用import也是通过namespace来引用
2)在EJB中通常使用@Stateless的EJB,应为该类型占内存少
上述EJB的继续开发:
1)目前使用的是SoapUI进行访问WebService服务,但实际的开发中,还是会有许多不同的模块,而由于历史原因这些模块的WebService接口往往是不同的,会导致不同模块间难以交互,这时可以使用ESB的技术,将ESB作为一个中转站,将不同的Wsdl的信息进行交换转发
2)在EJB的事物中,可以支持JDBC事物和JTA事物,我使用的是JTA事物,但在程序中只管理了JDBC的事物并没有跨资源管理事物
3)没有使用更加复杂的sql语句
4)可以使用Jmoke来进行单元测试
在上述的EJBdemo中,还有一些问题尚未解决:
1)我之前设想的是将wsdl文件以及wsdl生成的java文件独立的使用一个java工程,然后将其打成jar包,在EJB中使用该jar包,但编译可以通过,部署到jboss中则会产生无法找到jar的异常(notfundclassException)
2)如何使用maven搭建一个EJB工程
3)事物管理的时候,runtimeException的作用不是很清楚
###代码下载
EJB3 阶段总结+一个EJB3案例 (2)的更多相关文章
- EJB3 阶段总结+一个EJB3案例 (1)
经过一段时时间的学习,对EJB3的相关知识和jboss8的配置有了大概的了解. 网上对EJB的评论很多,基本都是负面的,都表示EJB太过于沉重,不容易维护.但通过这段时间的学习,私下认为,EJB3在某 ...
- 第一个struts案例及分析
软件中的框架,是一种半成品: 我们项目开发需要在框架的基础上进行!因为框架已经实现了一些功能,这样就可以提高开发效率! Struts2 = struts1 + xwork (struts是基于MV ...
- 用一个开发案例详解Oracle临时表
用一个开发案例详解Oracle临时表 2016-11-14 bisal ITPUB  一.开发需求 最近有一个开发需求,大致需要先使用主表,或主表和几张子表关联查询出ID(主键)及一些主表字段 ...
- SAP C/4HANA与人工智能和增强现实(AR)技术结合的又一个创新案例
今天这篇迟到的文章,来自我的同事Aviva. 去年SAP C/4HANA发布之后,SAP的从业者们可能或多或少都读过一些来自SAP官方渠道,比如微信公众号"SAP天天事"发布的一些 ...
- Python:通过一个小案例深入理解IO多路复用
通过一个小案例深入理解IO多路复用 假如我们现在有这样一个普通的需求,写一个简单的爬虫来爬取校花网的主页 import requests import time start = time.time() ...
- Lucene3.6.2包介绍,第一个Lucene案例介绍,查看索引信息的工具lukeall介绍,Luke查看的索引库内容,索引查找过程
2.Lucene3.6.2包介绍,第一个Lucene案例介绍,查看索引信息的工具lukeall介绍,Luke查看的索引库内容,索引查找过程 2014-12-07 23:39 2623人阅读 评论(0) ...
- java线程基础巩固---分析Thread的join方法详细介绍,结合一个典型案例
关于Thread中的join方法貌似在实际多线程编程当中没怎么用过,在当初学j2se的时候倒时去学习过它的用法,不过现在早已经忘得差不多啦,所以对它再复习复习下. 首先先观察下JDK对它的介绍: 其实 ...
- 编程中易犯错误汇总:一个综合案例.md
# 11编程中易犯错误汇总:一个综合案例 在上一篇文章中,我们学习了如何区分好的代码与坏的代码,如何写好代码.所谓光说不练假把式,在这篇文章中,我们就做一件事——一起来写代码.首先,我会先列出问题,然 ...
- 零基础学习java------35---------删除一个商品案例,删除多个商品,编辑(修改商品信息),校验用户名是否已经注册(ajax)
一. 删除一个商品案例 将要操作的表格 思路图 前端代码 <%@ page language="java" contentType="text/html; cha ...
随机推荐
- HDU1269 迷宫城堡 2016-07-24 13:47 84人阅读 评论(0) 收藏
迷宫城堡 Problem Description 为了训练小希的方向感,Gardon建立了一座大城堡,里面有N个房间(N<=10000)和M条通道(M<=100000),每个通道都是单向的 ...
- C++中的关键字用法---typename
1. typename 关键字 "typename"是一个C++程序设计语言中的关键字.当用于泛型编程时是另一术语"class"的同义词.这个关键字用于指出模板 ...
- GoF设计模式学习-单例模式
1.目的 控制实例的个数,类设计者应该保证只有一个实例,不能将此责任[只有一个实例]强制交给类使用者. 2.整体实现 1.单线程单例模式的实现. using System; using System. ...
- 手动设置3G的wifi迷你无线路由
1.插入中兴的3G无线网卡,终端上显示如下内容: ~ >: usb 1-1.3: new full speed USB device number 11 using s3c2410-ohci u ...
- kafka不停止服务的情况下修改日志保留时间
kafka配置文件如下: broker.id=1 port=9092 host.name=ssy-kafka1 num.network.threads=4 num.io.threads=8 socke ...
- VSTS 更名为 Azure DevOps
微软正式对外宣布Azure DevOps,其实就是原来的VSTS,我们来看一下Azure DevOps的介绍: 今天我们宣布Azure DevOps.与世界各地的客户和开发人员合作,很明显,DevOp ...
- asp.net缓存使用介绍
介绍: 在我解释cache管理机制时,首先让我阐明下一个观念:IE下面的数据管理.每个人都会用不同的方法去解决如何在IE在管理数据.有的会提到用状态管理,有的提到的cache管理,这里我比较喜欢cac ...
- asp.net—自定义轻量级ORM
大型项目中ORM的使用已经是相当的频繁.目前.NET(C#)中比较流行的ORM框架也有很多,比如SqlSugar,Dapper,Entity Framework(EF)等. 相信很多有2年以上工作经验 ...
- .Net Core + NGINX跳转登录时端口丢失
使用.Net Core + NGINX部署到服务器的时候,如果端口不是使用默认的80端口,在跳转到登录页面时,URL中的端口丢失. NGINX的配置如下: server { listen ; loca ...
- NetCore偶尔有用篇:NetCore项目添加MIME
一.简介 1.系统默认给我们提供的一些文件类型的处理方式. 2.系统没有为我们提供处理的文件类型无法使用,例如:apk 3.这里候就需要自己添加MIME,才能进行访问 4.下面就是添加apk访问的示例 ...