• 1. EJB3.0入门经典赵端阳 信息工程分院 www.acmbook.org1
  • 2. 关于开题报告答辩请各位同学,根据答辩时老师的建议,认真修改三大件; 将修改结束以压缩包的形式发给指导教师。2
  • 3. 重点章节第2章 会话Bean (Session Bean) 第3章 实体Bean (Entity Bean) 第6章 Web服务 (Web Service) 3
  • 4. 题型读程序,写结果; 编程; 写操作步骤。4
  • 5. 2.1.2 开发只实现 Local 接口的无状态 Session Bean开发只有 Local 接口的无状态会话Session Bean,使用@Local 注释声明接口是本地接口。 开发只有 Remote 接口的无状态会话Session Bean ,使用@Remote 注释声明接口是远程接口。 当@Local 和@Remote 注释都不存在时,容器会将 Bean class 实现的接口默认为 Local 接口。如果 EJB 与客户端 部署在同一个应用服务器,采用 Local 接口访问 EJB 优于 Remote 接口。5
  • 6. 业务接口:LocalHelloWorld.java 工程:LocalSessionBean6
  • 7. 2.4 Stateful Session Bean开发在一些应用场合中,有时我们需要每个用户都有自己的一个实例,这个实例不受其他用户影响。 购物车对象,每个用户都应有自己的购物车,不希望有人往你的购物车里添加或拿掉商品,而有状态Bean正好满足你的这种需求。 每个有状态Bean在bean实例的生命周期内都只服务于一个用户,bean class的成员变量可以在不同的方法调用间维护特定于某个用户的数据。7
  • 8. 2.4 Stateful Session Bean开发8
  • 9. Bean 类:CartBean.java 9
  • 10. 有状态 Bean 的 JSP 客户端代码:StatefulBeanTest.jsp 先试图从session中获取购物车的存根。 如果当前session不存在购物车,就创建一个新的购物车放入session中。 后面每执行一次页面都会添加一个相同的商品。10
  • 11. 2.9 Session Bean的生命周期事件@PostConstruct:当bean对象完成实例化后会被立即调用,每个beanclass只能定义一个@PostConstruct方法。这个注释同时适用于有状态和无状态会话bean。 @PreDestroy:标注了这个注释的方法会在容器销毁一个无用的或者过期的bean实例之前调用。这个注释同时适用于有状态和无状态会话bean。 @PrePassivate:当一个有状态的bean实例空闲时间过长,就会发生钝化(passivate)。标注了这个注释的方法会在钝化之前被调用。bean实例被钝化后,在一段时间内,如果仍然没有用户对bean实例进行操作,容器将会从硬盘中删除它。以后,任何针对该bean方法的调用,容器都会抛出例外。这个注释适用于有状态会话bean。11
  • 12. 2.9 Session Bean的生命周期事件@PostActivate:当客户端再次使用已经被钝化的有状态bean时,EJB容器会重新实例化一个Bean实例,并从硬盘中将之前的状态恢复。标注了这个注释的方法会在激活完成时被调用。这个注释只适用于有状态会话bean。 @Init:这个注释指定了有状态bean初始化的方法。它区别于@PostConstruct注释在于:多个@Init注释方法可以同时存在于有状态sessionbean中,但每个bean实例只会有一个@Init注释的方法会被调用。@PostConstruct在@Init之后被调用。 @Remove:当客户端调用标注了@Remove注释的方法时,容器将在方法执行结束后把bean实例删除。12
  • 13. 2.9 Session Bean的生命周期事件13
  • 14. 2.9 Session Bean的生命周期事件14
  • 15. 15
  • 16. 2.10 拦截器(Interceptor) 拦截器可以拦截Session bean和message-driven bean的方法调用或生命周期事件。 拦截器用于封装应用的公用行为,使这些行为与业务逻辑分离,一旦这些公用行为发生改变,而不必修改很多业务类。 拦截器可以是同一bean类中的方法或是一个外部类。16
  • 17. 2.10 拦截器(Interceptor)@Interceptors 注释指定一个或多个在外部类中定义的拦截器,多个拦截器类之间用逗号分隔,如: @Interceptors({A.class,B.class,C.class}),如果只有一个拦截器可以省略大括号。17
  • 18. 2.10 拦截器(Interceptor)@AroundInvoke注释指定了要用作拦截器的方法,拦截器方法与被拦截的业务方法执行在同一个java调用堆栈、同一个事务和安全上下文中。 用@AroundInvoke注释指定的方法必须遵守以下格式: public Object XXX(javax.interceptor.InvocationContext ctx) throws Exception XXX代表方法名可以任意 javax.interceptor.InvocationContext封装客户端所调用业务方法的一些信息18
  • 19. 2.10 拦截器(Interceptor)19
  • 20. 2.10 拦截器(Interceptor)20
  • 21. 2.11 依赖注入(dependency injection)在实际应用中,EJB可能会使用到其它EJB或资源。 在传统的开发中,我们要使用某个类对象,可以通过new object的方式来使用它。 但在EJB中,不能这样做,因为EJB实例的创建及销毁是由容器管理的。 要在bean中要用其它EJB,必须通过JNDI查找或注入注释。 如在InjectionBean中使用HelloBean EJB,需要在InjectionBean中通过JNDI查找HelloBean的引用21
  • 22. 2.11 依赖注入(dependency injection)通过注入注释22
  • 23. 2.11 依赖注入(dependency injection)通过ejb-jar.xml 添加注册项,该文件需放在 jar的 META-INF 23
  • 24. Bean 类:InjectionBean.java 24
  • 25. 2.11.1 资源类型的注入如何注入数据源? “DefaultMySqlDS”是数据源的局部 JNDI 名称,只供 Jboss 容器内的应用访问。 查找该局部 JNDI 名称时,需要带有前缀“java:/”。 25
  • 26. 2.11.1 资源类型的注入26
  • 27. 2.12 定时服务(Timer Service)定时服务可以用在stateless session bean和message-driven bean,当某个stateless session bean或message-driven bean的定时器启动时,容器会从实例池中选择bean的一个实例,然后调用其timeout回调方法。 可以使用@Resource注释注入定时服务,或者使用容器对象SessionContext创建定时器。 下面例子在session bean中定义一个定时器,每隔3秒钟触发一次事件,当定时事件触发5次的时候便终止定时器的执行。27
  • 28. 2.12 定时服务(Timer Service)28
  • 29. 2.12 定时服务(Timer Service)当定时器创建完成后,我们还需要添加定时事件的回调方法。回调方法使用@javax.ejb.Timeout注释标注,必须返回void,并接受一个javax.ejb.Timer类型的参数,回调方法声明的格式: void XXX(Timer timer) 在定时事件发生时,此方法将被执行。29
  • 30. JSP 客户端代码:TimerServiceTest.jsp 30
  • 31. 2.13 安全服务(Security service)使用Java验证和授权服务(Java Authentication Authorization Services JAAS)可以很好地解决上面的问题,可以用它来管理应用程序的安全性。 验证(Authentication)认证是完成用户名和密码的匹配校验;其校验的对象是试图访问受保护系统的用户。在进行校验时,应用服务器会检查用户是否存在于系统之中,是否提供了凭证(通常指密码)。 授权(authorization)用户一旦通过了系统验证,需要与系统进行某种形式的交互。授权就是决定用户是否有权执行某项操作的过程,授权是基于角色的。31
  • 32. 2.13 安全服务(Security service)Jboss服务器提供了安全服务来进行用户认证和根据用户规则来限制对POJO的访问。 对每一个POJO来说,可以使用@SecurityDomain注释为它指定一个安全域,安全域告诉容器到哪里去找密码和用户角色列表。 Plain Old Java Objects,简单的Java对象,就是普通JavaBeans,是为了避免和EJB混淆所创造的简称。 JBoss中的other域指明要到classpath下寻找users.propertes和roles.properties。 对每一个方法来说,我们可以使用一个安全限制注释来指定谁可以运行这个方法32
  • 33. 2.13 安全服务(Security service)本例使用Jboss默认的安全域“other”,“other”安全域告诉容器到classpath下的users.properties和roles.properties中寻找密码和用户角色列表。 “other”安全域定义 [jboss安装目录]/server/default/conf/login-config.xml文件中33
  • 34. 2.13 安全服务(Security service)34
  • 35. 2.13 安全服务(Security service)下面我们开始安全服务的具体开发: 第一步,定义安全域,安全域的定义有两种方法: 第一种方法:通过 Jboss 部署描述文件 jboss.xml 进行定义(本例采用的方法) 指定我们使用的安全域是“other”, AnonymousUser节点指定允许匿名用户访问。 jboss.xml 必须 放进 Jar 文件的 META-INF 目录。35
  • 36. 2.13 安全服务(Security service)36
  • 37. 2.13 安全服务(Security service)第三步,为业务方法定义访问角色(后台)。 @RolesAllowed 注释指定允许访问方法的角色列表,如果角色存在多个,可以用逗号分隔。 @PermitAll 注释指定 任何角色都可以访问此方法。37
  • 38. 2.13 安全服务(Security service)38
  • 39. 2.13 安全服务(Security service)39
  • 40. 2.13 安全服务(Security service)40
  • 41. 2.13.1 自定义安全域把用户名/密码及角色存放在users.propertes和roles.properties文件,不便于日后的管理。 大多数情况下都希望把用户名/密码及角色存放在数据库中。 我们需要自定义安全域,下面的例子定义了一个名为foshanshop的安全域,它采用数据库存储用户名及角色。41
  • 42. 2.13.1 自定义安全域42
  • 43. 2.13.1 自定义安全域“DefaultMySqlDS” 数据源, principalsQuery属性指定如何通过给定的用户名获取密码, rolesQuery属性指定如何通过给定的用户名获取角色列表。 注意:SQL中的‘Roles’常量字段不能去掉。 unauthenticatedIdentity属性指定允许匿名用户访问。43
  • 44. 2.13.1 自定义安全域44
  • 45. 2.13.1 自定义安全域45
  • 46. 第三章 实体 Bean(Entity Bean)Jboss 数据源的配置 单表映射的实体Bean 成员属性映射 建议重载实体 Bean的 Equals()和 Hashcode()方法 映射的表名或列名与数据库保留字同名时的处理 多表映射的实体Bean 持久化实体管理器 Entity Manager 关系/对象映射 JPQL 查询46
  • 47. 3.1 JBoss 数据源的配置数据源用于配置数据库的连接信息,每个数据源必须指定一个唯一的JNDI名称。应用通过JNDI名称找到数据源。 在Jboss中,有一个默认的数据源DefaultDS,它使用Jboss内置的HSQLDB数据库。 实际项目中,可能使用不同的数据库,如MySql、SqlServer、Oracle等。 每种数据库的数据源配置模版可以在[Jboss安装目录]\docs\examples\jca目录中找到,名称为:数据库名+-ds.xml。47
  • 48. 3.1 JBoss 数据源的配置数据源部署的过程很简单,直接把它拷贝到jboss的deploy目录即可。 容器遇到以*-ds.xml结尾的文件时,会进行动态发布。发布完成后,你可以在http://localhost:8080/jmx-console/查看到数据源的信息48
  • 49. 3.1 JBoss 数据源的配置49
  • 50. 3.1 JBoss 数据源的配置数据源配置文件的取名格式必须为xxx–ds.xml,其中xxx代表任意名称,如:mysql-ds.xml,mssqlserver-ds.xml,oracle-ds.xml。 数据源部署前,必须把数据库驱动Jar拷贝到[jboss安装目录]/server/配置名/lib目录,本书采用的配置名为default,因此需要把数据库驱动拷贝到[jboss安装目录]/server/default/lib。完成拷贝后,必须重启Jboss服务器。 本书使用的数据库是mysql-5.0.22,其驱动为mysql-connector-java-3.1.13-bin.jar。50
  • 51. 3.2 单表映射的实体 Bean在本例子,该表由持久化驱动自动生成,不需要我们创建。 51
  • 52. 3.2 单表映射的实体 Bean52
  • 53. Session Bean 的业务接口 在EJB3.0,实体Bean并不直接与客户端打交道。而是被Session bean或Message-Driven Bean使用。 定义一个Session Bean,在Session Bean中通过实体bean间接操作数据库。53
  • 54. Session Bean的实现 Database name54
  • 55. Session Bean的实现 Database nameem.find()方法用于查找特定主键的实体bean。em.persist()方法用于保存实体bean,即插入一条记录。em.merge()方法用于更新或保存实体 当实体不存在时,执行保存操作 当实体已经存在时,执行更新操作em.remove()方法用于删除实体,即删除一条记录。em.createQuery()用于执行JPQL语句。55
  • 56. JSP 客户端代码:EntityBeanTest.jsp 56
  • 57. 3.6 多表映射的实体Bean如果实体的成员属性映射的字段分布在多张表中,如何处理? 本例子的实体MainTable具有四个成员属性:id、name、address和postcode。 其中与id和name映射的字段在MainTable表,与address和postcode属性映射的字段在Address表。 需要使用@javax.persistence.SecondaryTable注释和@Column.table()属性57
  • 58. 3.6 多表映射的实体Bean MainTable.class58
  • 59. 3.6 多表映射的实体Bean59
  • 60. 3.6 多表映射的实体Bean重载实体 equals() 方法重载实体 hashCode()方法重载实体 toString() 方法60
  • 61. 3.6 多表映射的实体Bean MultitableMappingDAO.java实体Bean的使用者Session Bean61
  • 62. 3.6 多表映射的实体Bean MultitableMappingDAOBean.class62
  • 63. 3.6 多表映射的实体Bean MultitableMappingTest.jsp63
  • 64. 3.6 多表映射的实体Bean64
  • 65. 3.8 关系/对象映射双向一对多及多对一映射 单向一对多 单向多对一 双向一对一映射 单向一对一 双向多对多映射 单向多对多65
  • 66. 3.8.1 双向一对多及多对一映射现实应用中存在很多一对多的情况,如一项订单中存在一个或多个订购项。 当one方存在与many方关系的定义,而many方同时也存在与one方关系的定义,这样的关系被称为双向关系。 代码上体现为在one方有一个集合属性指向many方,而在many方也有一个属性指向one方。66
  • 67. 3.8.1 双向一对多及多对一映射双向一对多关系,必须包含一个关系维护端。持久化规范要求多的一方为关系维护端(ownerside),一的一方为关系被维护端(inverseside)。 在one方的@OneToMany注释设置mappedBy属性,以指定它是这一关联中的被维护端,Many方是关系维护端。67
  • 68. 3.8.1 双向一对多及多对一映射Order.java 68
  • 69. 3.8.1 双向一对多及多对一映射指明Order与OrderItem关联关系为一对多关系69
  • 70. 3.8.1 双向一对多及多对一映射70
  • 71. 3.8.1 双向一对多及多对一映射OrderItem.java 变量定义 构造函数 71
  • 72. 3.8.1 双向一对多及多对一映射72
  • 73. 3.8.1 双向一对多及多对一映射public @interface ManyToOne { Class targetEntity( ) default void.class; CascadeType[] cascade( ) default {}; FetchType fetch( ) default EAGER; boolean optional( ) default true; }targetEntity()、cascade()和fetch()的具体含义和@OneToMany注释的同名属性相同,但@ManyToOne注释的fetch()属性默认值是FetchType.EAGER。optional()指定关联方是否可以为空(null),该属性值默认为true。 若将其设为false,则要求双方必须存在。 我们不需要设置@JoinColumn注释的nullable()属性。 通过EntityManager.find()、EntityManager.getReference()查询OrderItem实体: 当optional=false时,OrderItem与Order关联形式为inner join, 当optional=true时,OrderItem与Order关联形式为left join。73
  • 74. 3.8.1 双向一对多及多对一映射SessionBean的业务接口:OrderDAO.java74
  • 75. 3.8.1 双向一对多及多对一映射SessionBean的业务接口:OrderDAOBean.java75
  • 76. JSP 客户端代码:OneToManyTest.jsp76
  • 77. 3.8.1 双向一对多及多对一映射OrderItem表Order表77
  • 78. 3.8.2 单向一对多Order.java 78
  • 79. 3.8.2 单向一对多OrderItem.java 79
  • 80. 3.8.3 单向多对一Order.java 80
  • 81. 3.8.3 单向多对一指明Order与OrderItem关联关系为一对多关系Order.java 81
  • 82. 3.8.3 单向多对一OrderItem.java 82
  • 83. 3.8.3 单向多对一OrderItem.java 保持不变!83
  • 84. 3.8.6 双向多对多映射实现生活中,一个学生有多个老师,一个老师有多个学生,他们具有明显的多对多关系。 多对多映射采取中间表连接的映射策略,建立的中间表将分别引入两边的主键作为外键。 EJB3对于中间表的元数据提供了可配置的方式,用户可以自定义中间表的表名、列名。studentteacherteacher- student**84
  • 85. 3.8.6 双向多对多映射Student.java85
  • 86. 3.8.6 双向多对多映射Student.java在双向ManyToMany关联中,必须包含有一个关系维护端。 在Student的@ManyToMany注释中指定mappedBy()属性,将其标识为关系被维护端,自然Teacher就成了关系维护端。@ManyToMany注释指定Student是多对多关系的一端,mappedBy属性指定Student为双向关系的被维护端(inverse side),指出该关系映射信息是在被关联实体Teacher的成员属性students上定义的。86
  • 87. 3.8.6 双向多对多映射Teacher.java87
  • 88. 3.8.6 双向多对多映射Teacher.java88
  • 89. 3.8.6 双向多对多映射TeacherDAO.java89
  • 90. 3.8.6 双向多对多映射TeacherDAOBean.java90
  • 91. 3.8.6 双向多对多映射TeacherDAOBean.java91
  • 92. 3.8.6 双向多对多映射ManyToManyTest.jspteacher teacher_studentstudent92
  • 93. 3.8.7 单向多对多Teacher.java93
  • 94. 3.8.7 单向多对多Teacher.java94
  • 95. 3.8.7 单向多对多Student.java95
  • 96. 3.8.7 单向多对多Student.java96
  • 97. 3.9 JPQL查询命名参数查询 位置参数查询 Date参数 一个JPQL查询例子 命名查询 排序(order by) 查询部分属性 查询中使用构造器(Constructor) 聚合查询(Aggregation) 关联(join) 排除相同的记录DISTINCT 比较Entity 批量更新(Batch Update) 批量删除(Batch Remove)逻辑非运算符NOT 使用操作符BETWEEN 使用操作符IN 使用操作符LIKE 使用操作符IS NULL 使用操作符IS EMPTY 字符串函数 日期和时间函数 数学函数 Member of 子查询 EXISTS All, ANY, SOME 结果集分页97
  • 98. 实例数据库Person表Order表OrderItem表98
  • 99. (1) 命名参数查询命名参数的格式为冒号加上参数名:“:+参数名”99
  • 100. (2) 位置参数查询位置参数的格式为问号加上位置编号:“?+位置编号”100
  • 101. (3) Date参数如果需要将 java.util.Date 或 java.util.Calendar 作为参数传进一个参数查询,使用对应的 setParameter()方法101
  • 102. Person.java 102
  • 103. Person.java103
  • 104. Person.javaOrder表104
  • 105. Order.java105
  • 106. Order.java106
  • 107. OrderItem.java107
  • 108. OrderItem.javaOrder表108
  • 109. QueryDAOBean.javaPerson表Order表OrderItem表109
  • 110. QueryDAOBean.java110
  • 111. JSP客户端代码:QueryTest.jsp 111
  • 112. (5) 命名查询你可以在实体bean上定义一个或多个查询语句,这样可以减少每次因书写错误而引起的BUG。 实际应用中,一般把经常使用的查询语句定义成命名查询。当命名查询定义好了之后,我们可以通过其名称执行查询:……112
  • 113. (5) 命名查询如果需要定义多个命名查询,可以使用@javax.persistence.NamedQueries注释。 在该注释里面,可以放置多个@NamedQuery注释:当命名查询定义好了之后,我们可以通过其名称执行查询:113
  • 114. (6) 排序(order by)"ASC"和"DESC"分别为升序和降序,如果不显式指定,JPQL默认使用ASC升序。(QueryDAOBean.java)114
  • 115. (7) 查询部分属性(QueryDAOBean.java)在前面的例子中,都是针对实体的查询,返回的结果也是实体类型。JPQL允许查询返回我们需要的成员属性。在一些实体成员属性比较多的情况,这样的查询可以提高性能。115
  • 116. (8) 查询中使用构造器(Constructor)JPQL支持将查询的结果直接作为一个Java类的构造器参数,并产生类对象作为结果返回。116
  • 117. (8) 查询中使用构造器(Constructor)将查询的属性结果直接作为 SimplePerson 的构造器参数。 117
  • 118. (9) 聚合查询(Aggregation)像大部分的SQL一样,JPQL也支持查询中的聚合函数: AVG()求平均数,返回值类型为Double; SUM()求和,返回值类型为被求值的成员属性所对应的类型; COUNT()统计,返回类型为Long,注意count(*)语法并不属于JPA规范,它在hibernate中可用; MAX()求最大值,返回值类型为被求值的成员属性所对应的类型。可用于基本数据类型,字符串及可序列化对象; MIN()求最小值,返回值类型为被求值的成员属性所对应的类型。可用于基本数据类型,字符串及可序列化对象。 聚合函数在统计时,会忽略掉带null值的记录。 如果查询的集合为空(即没有记录),count()在处理时会返回0,而AVG()、SUM()、MAX()、MIN()返回null值。118
  • 119. (9) 聚合查询(Aggregation)119
  • 120. (9) 聚合查询(Aggregation)和SQL一样,如果聚合函数不是select...from的唯一一个返回列,需要使用"GROUPBY"语句。120
  • 121. //去掉相同的编号(10)关联(join)left out join/left join等,都是允许右边表达式的实体为空。OrderOrderItem121
  • 122. (10)关联(join)inner join 要求右边表达式的实体必须存在。OrderOrderItem122
  • 123. (10)关联(join)left/left out/inner join fetch 提供了一种灵活的查询加载方式来提高查询的性能。 在默认的查询中,实体的延迟属性不会被加载。 当应用需要时,EJB3 Runtime才会执行一条SQL语句来加载属于当前Order的OrderItems。 使用了fetch,这个查询只会产生一条 SQL 语句。123
  • 124. (11) 排除相同的记录Distinct使用关联查询,我们很经常得到重复的对象,如下面语句: select o from Order o inner join fetch o.orderItems order by o.orderid 如果一个Order有多个orderItem,返回的结果就会有多个相同的Order,需要使用Distinct关键字排除相同的对象。 Distinct 操作符还可以与任何聚合函数结合使用,首先去掉重复值,然后再统计。124
  • 125. (12) 比较Entity在使用参数查询时,参数类型除了String、原始数据类型(int, double等)和它们的对象类型(Integer, Double等),也可以是实体对象。125
  • 126. (13)批量更新(Batch Update)Order表(修改前)126
  • 127. (14) 批量删除(Batch Remove)127
  • 128. (15) 逻辑非运算符NOT128
  • 129. (16) 使用操作符BETWEEN129
  • 130. (17) 使用操作符IN130
  • 131. (18) 使用操作符LIKE131
  • 132. (19) 使用操作符IS NULL132
  • 133. (20) 使用操作符IS EMPTY133
  • 134. (21) 字符串函数CONCAT(string 1, string 2) 将字符串2追加到字符串1。 SUBSTRING(string, starting position, length) 从字符串string开始位置starting position截取长度为length字符。 LOWER(string) 将一个字符串string转换成小写形式。 UPPER(string) 将一个字符串string转换成大写形式。 LENGTH(string) 返回字符串string的长度,为整数。 TRIM([[LEADING|TRAILING|BOTH] [char] FROM] string) 去掉字符串string头,尾或两者的字符char。最简形式是TRIM(string),可以去掉字符串string头尾的空格字符。 LOCATE(string1, string2 [,start]) 返回string2在string1的位置。定位函数有一个可选的起始位置start。134
  • 135. (21) 字符串函数135
  • 136. (23) 数学函数ABS (arithmetic expression) 返回算术表达式的绝对值。 SQRT (arithmetic expression) 求算术表达式的方根,返回一个Double。 MOD (arithmetic expression 1, arithmetic expression 2) 求参数1与参数2的模,返回一个整数。 SIZE (collection-valued path-expression) 计算一个集合中元素的数量,并返回一个整数。 如果集合为空,返回0。136
  • 137. (23) 数学函数137
  • 138. (24) Member ofMember of操作符用于判断实体是否是集合中的一员。 138
  • 139. (25) 子查询子查询可以用于WHERE和HAVING条件语句中。139
  • 140. (26) EXISTSEXISTS需要和子查询配合使用,用来判断子查询是否存在记录。140
  • 141. (26) EXISTSEXISTS需要和子查询配合使用,用来判断子查询是否存在记录。141
  • 142. (27) All, ANY, SOME当子查询返回多条记录时,你可以使用表达式ALL、ANY和SOME对结果做进一步限定。142
  • 143. (28) 结果集分页有些时候执行一个查询会返回成千上万条记录,事实上我们只需要显示其中一部分数据,这时我们需要对结果集进行分页。 QueryAPI有两个接口方法可以解决这个问题: setMaxResults方法设置获取多少条记录 setFirstResult方法设置从结果集中的那个索引开始获取 (索引从0开始)143
  • 144. (28) 结果集分页JSP 客户端调用代码片断 设置每页记录数为2,如果数据库中存在7条记录,第一页显示的记录索引应为(0,1),第二页为(2,3),第三页为(3,4)...等。 在分页中,为了显示数据有序,建议在查询中进行排序。144
  • 145. 3.10 调用存储过程调用无返回值的存储过程 调用返回单值的存储过程 调用返回表全部列的存储过程 调用返回部分列的存储过程145
  • 146. 1、调用无返回值的存储过程存储过程 146
  • 147. 2、调用返回单值的存储过程有一个INTEGER类型的输入参数147
  • 148. 2、调用返回单值的存储过程如果程序或线程总是对同样的输入参数产生同样的结果,则被认为它是“确定的”,否则就是“非确定”的。如果既没有给定DETERMINISTIC也没有给定NOT DETERMINISTIC,默认的就是NOT DETERMINISTIC。 SQL SECURITY特征可以用来指定子程序该用创建子程序者的许可来执行,还是使用调用者的许可来执行。默认值是DEFINER。 COMMENT子句是一个MySQL的扩展,它可以被用来描述存储程序。148
  • 149. 3、调用返回表全部列的存储过程让EJB3 Persistence运行环境将列值直接填充入实体对象(本例填充进Person对象),返回结果为实体类型的List。149
  • 150. 4、调用返回部分列的存储过程150
  • 151. 3.11复合主键(Composite Primary Key)当需要使用多个属性变量(多列)联合起来作为主键,需要使用复合主键。复合主键要求我们编写一个复合主键类( Composite Primary Key Class )。 复合主键类需要符合以下一些要求: 复合主键类必须是public和具备一个没有参数的构造函数; 复合主键类的每个属性变量必须有getter/setter。如果没有,每个属性变量则必须是public或者protected; 复合主键类必须实现java.io.serializable; 复合主键类必须实现equals()和hashcode()方法; 复合主键类中的主键属性变量的名字必须和对应的Entity中主键属性变量的名字相同。 151
  • 152. 示例:一条航线是由出发地和到达地决定的152
  • 153. AirtLinePK.java153
  • 154. AirLine.java154
  • 155. AirLine.java155
  • 156. Flight.java156
  • 157. Flight.java157
  • 158. Flight.java158
  • 159. AirLineDAOBean.java159
  • 160. EJBTest/web/CompositePKTest.jsp160
  • 161. 第6章 Web服务(Web Service)EJB容器模型的Web Service开发 Web容器模型的Web Service开发 Web Service的客户端调用 3.1 在J2SE或Web中调用Web Service 3.2 在EJB中调用Web Service161
  • 162. 第6章 Web服务(Web Service)Web服务也是一种分布式技术,它与EJB最大的不同是,Web服务属于行业规范,可以跨平台及语言。 EJB属于java平台的规范,尽管理论上可以跨平台,但实现起来比较复杂,所以其应用范围局限在java平台。 看上去两者好像是互相竞争的关系,其实不是。 它们两者的偏重点不一样,Web服务偏重的是这个系统对外提供什么功能,而EJB偏重的是如何用一个个组件组装这些功能。 就好比一个硬盘,它对外提供的是存储服务,这是web服务的关注点。对于怎样组装这个硬盘,怎样构造这些小零件,web服务并不关心,但这些却是EJB所关注的。162
  • 163. 第6章 Web服务(Web Service)Web Service技术到今天仍在不断地发展,规范也在不断地升级,将以最新的JAX-WS2.x规范(Java API for XML-based Web Services)介绍Web Service的开发。 由于Web Service这个主题相当大,关联的协议也比较多。 尽管Web Service的内容比较多,但站在开发的角度来说,实际要我们掌握的知识并不多,因为很多实现细节都由平台或第三方组件实现了。 JavaEE为Web Service提供了两种不同的编程模型: EJB容器模型及Web容器模型,而EJB容器模型是推荐使用的。 163
  • 164. 6.1 EJB容器模型的Web Service开发HelloWorldBean.java 加入@javax.jws.WebService注释164
  • 165. 6.1 EJB容器模型的Web Service开发HelloWorldBean.java165
  • 166. WSDL文档166
  • 167. WSDL文档结构分析类型Types 定义Web服务使用的所有数据类型集合,可被元素的各消息部件(Part)所引用。 它使用某种类型系统(通常使用XML Schema中的类型系统)。167
  • 168. WSDL文档结构分析消息Message 通信消息数据结构的抽象类型化定义。使用Types所定义的类型定义整个消息的数据结构。 包含一组Part元素,每个Part元素都是最终消息的一个组成部分,每个Part都会引用一个DataType表示它的结构。 Part元素不支持嵌套(可以使用DataType来完成这方面的需要),都是并列出现。168
  • 169. WSDL文档结构分析操作Operation 对服务中所支持操作的抽象描述。 一般单个Operation描述了一个访问入口的请求/响应消息对。//SOAP的编码方式为literal169
  • 170. WSDL文档结构分析端口类型PortType 对于某个访问入口点类型所支持操作的抽象集合。这些操作可以由一个或多个服务访问点来支持。 一个PortType可以包含若干个Operation,而一个Operation则是指访问入口支持的一种类型的调用。170
  • 171. WSDL文档结构分析绑定Binding 包含了如何将抽象接口的元素(portType)转变为具体表示的细节,即特定的数据格式和协议的结合;特定端口类型的具体协议和数据格式规范的绑定。 171
  • 172. WSDL文档结构分析端口Port 定义协议/数据格式绑定与具体Web访问地址组合的单个服务访问点。 是一个服务访问入口的部署细节,包括通过哪个Web地址(URL)来访问,应当使用怎样的消息调用模式来访问等。其中消息调用模式则是使用Binding结构来表示。172
  • 173. WSDL文档结构分析服务Service 描述的是一个具体的被部署的Web服务所提供的所有访问入口的部署细节,一个Service往往会包含多个服务访问入口,而每个访问入口都会使用一个Port元素来描述。173
  • 174. 使用JAC-WS注释控制生成的WSDL174
  • 175. 6.3.2 在EJB中调用Web Service在EJB容器中,一般通过注入注释来使用Web Service。 利用工具生成辅助类。 使用注释注入服务类或服务端口。 把JBoss内JBOSS_HOME/client目录下的文件复制到JBoss内的JBOSS_HOME/lib/endorsed目录下,重启服务: jboss-jaxrpc.jar jboss-jaxws.jar jboss-saaj.jar175
  • 176. 6.3.2 在EJB中调用Web Service176
  • 177. 6.3.2 在EJB中调用Web ServiceWSClientBean.java177
  • 178. 6.3.2 在EJB中调用Web Service注释类型@WebServiceRef Classtype资源的Java类型。Classvalue服务类,扩展javax.xml.ws.Service的类型。Stringname资源的JNDI名称。StringwsdlLocation指向Web服务WSDL文档的URL。StringmappedName此资源必须映射到的特定产品名称。178
  • 179. JUnit Test中国人说:你好!世界,这是我的第一个web service哦.EJB Web Service179