Weka 设置 JDBC

最近在学习数据挖掘方面的内容,刚准备学习 Weka 不过网上设置 MySQL JDBC 的例子似乎有问题,所以写下来备忘。这里用 %WEKA% 表示 Weka 的安装文件夹。

  1. 下载 JDBC 驱动,Weka 3.6 版本默认支持常见的数据库(MySQL、Oracle、H2Database 等)。这里以 MySQL 为例:
    MySQL JDBC 驱动下载地址:http://dev.mysql.com/downloads/connector/j/
  2. 修改 %WEKA%/RunWeka.ini ,这是一个典型的 ini 文件,修改 cp 属性即可。可以修改为(把mysql-connector-java.jar改为你下载到本机的地址。)
    cp=%CLASSPATH%;E:/Libraries/mysql-connector-java-5.1.21/mysql-connector-java.jar
  3. 修改 %WEKA%/weka.jar/weka/experiment/DatabaseUtils.props(没看错,的确是在 jar 文件中,可以借助好压等压缩软件辅助操作) ,在找到 INTEGER=5 的地方,添加 INT=5 。或者把那个目录下面的 DatabaseUtils.props.mysql 替换为 DatabaseUtils.props ,这个是由 Weka 自己编辑的对 MySQL 支持的文件。(对应地,如果需要 oracle 支持,就把 DatabaseUtils.props.oracle 替换为 DatabaseUtils.props ,但目前只测试过 MySQL)

从配置文件到 DSL

DSL 是什么?一开始只是听说过,叫 Domain Specific Language,领域定制语言,也就是说,这种语言与特定领域相关的?于是我想起了什么 Cobol 之类的商业语言,也许对于一般的开发人员来说,它和我们没什么关系吧……不过,这个完全是一个误解,DSL 存在于各种领域,甚至, Web 开发、项目管理等。

而不知道从什么时候开始, Spring 项目的项目管理程序已经从 Maven 迁移到基于 Groovy 的 Gradle 了。初看上去, Maven 和 Gradle 并没有多大区别, Gradle 的依赖关系甚至完全照搬 Maven ,有一种多此一举的想法。而去年年初发布的 Android Studio ,也是采用 Gradle 进行项目管理。那么 Gradle 有什么优势?我觉得,从 Maven 上迁移,实际上是自定义工作的配置文件到 DSL 的转变。

Struts 2 的动作模型

一直以来都没有很好地考究 Struts 2 用的是怎样一个模型。多数人认为 Struts 2 的精髓在于拦截器,如果单从 Struts 2 的包来看似乎的确这样,因为很多 Action 部分的包都由 xwork 提供了。
 
但我觉得,这个 interceptor (拦截器)的概念实际上和 Servlet 规范中的 Filter 十分像,Struts 1 是对 Servlet 规范进行一封封装,实际上架构还是依循 Servlet 而建立的。而 Struts 2 的架构和 Struts 1 类似吗?
 
就我们所知道的,Struts 2 是 Struts 1 和 WebWork 的结合,实际上更偏向于 WebWork 框架(具体历史不考究了,只看软件包结构可以看出)。Struts2 框架实际上并不直接封装请求的信息传递给 Java 类,而是通过配置文件和参数约定把逻辑类的参数和请求参数绑定起来,使用统一的控制器(请求分发器)作为边界。因此,这个模型和 Struts 1 的架构来说差异还是很大的。
 
Strus 1 的 Action 控制器实际上只是对 Servlet 进行了封装,分离了控制和视图(实际上用 Servlet 控制,转发给 JSP 同样可以做到),外加上 ActionForm 对标单提交和校验作了封装。
 
而 Struts 2 采用的实际上是另一套模型。大家知道为了复用而让请求和 Action 解耦,但是却没想过这时候 Action 应该算是什么。我觉得这个改变促使其对 Struts 1 下的 MVC 模型进行了补充,把 Struts 1 中的 Action 整合为组件,既可以模仿 Struts 1 的方式写 Action ,又可以把服务类直接当作 ction 。
 
Struts 2 的组件化实际上可以使得边界类可以不再出现(理想情况下),达到代码复用的最好情况。

Web开发中的报告输出(rtf、xls)

这几天碰到一个看起来比较难处理的一个任务:把数据库中的数据导出为可以打印或者方便办公软件查看的格式。

这是对文档类型输出中,最近解决的一个方法。我考虑到这里大家主要是使用 PDF 输出和 Doc 格式的输出,但是 PDF 格式和 Doc 格式输出都不是很靠谱。其实简单的方法就是利用 RTF 格式进行中转输出。因为 RTF 格式实际上和 HTML 格式类似,也采用文本格式存储并且用文本标签描述的方式为文本添加显示属性,纯文本的操作能够更清楚地考虑进行的操作,错误恢复也会比二进制格式的 PDF 和 Doc 好点。

由于是一个打印文档,或者带有一定格式的文档,发现大家主要采用模版替代的方案。即先把文档编辑好,然后需要填写的内容用一些特殊的文本进行标记。在输出的时候,先读取文本,然后替代预先设置好的文本标记为要输出的内容即可。

Word 格式的输出

Word 格式输出是一个很不明确的说法,大概指的是可以用 Word (Microsoft Word 以及类似软件)打开的格式吧。这种格式的输出大概是为了打印而准备的。由于HTML天生没过多地考虑页面打印的问题。以前做过利用 CSS 的媒体类型来做的打印功能,大家说总是不那么方便。

直接导出 doc 格式文件是首选的。如果采用的是 Java 或者 .NET 平台,这个是一个好消息,因为很多人已经做过这方面的尝试了。比较好用的库有 Apache POI(For Java)以及对应的 .NET 版本 NPOI (For .NET)。

在 PHP 或者其他脚本语言(例如 Python 等)就没找到比较好用的库了,有谁了解的给我留个言吧。但是,临时的解决方法也不是没有,可以尝试输出 RTF 文件格式。这种文件格式和 HTML 类似,也是用纯文本编码,用标记来为文本添加格式等(只是标记不一样)。因此,只需要编辑好模板 Word 文件,然后保存为 RTF 格式,然后要输出的时候,把这个 RTF 格式的文件直接读入,然后进行字符串替换就好了。

不过,需要注意的是,由于格式化标签的存在,你输出的替代文本可能不是连着的(参考一下 HTML 代码,对于 RTF 来说也有类似的问题,只是标签格式不一样),文本替换的时候也很难发现,导致输出的时候根本替换不了。

例如,你用来做模板替换的内容是 \$PLACEHOLDER\$ 而实际上,在文件中表达却是:







<span><span>$</span><span>PLACEHOLDER</span><span>$</span></span>

这个问题实际上就是无效格式相互嵌套,显示效果还是无效格式的情况。或许可以用离散数学里面的关系给它命名为“幂等性”(这也是常说的,工具生成冗余代码的原因)。所以,在考虑输出的时候一定要先考察模板文件是否存在这个情况。

对于简单的情况,使用 RTF 格式或许更易于排错

XLS 输出

越来越觉得 XLS 是一种重要的格式。虽然不是什么标准,但是,非技术人员都对这种表格形式的格式十分熟悉,而且用户体验也比较好。所以,作为一种数据交流格式,输出 XLS 是一种不错的选择。而业界似乎对 XLS 格式已经做了很多研究了,很多语言都有对应的版本读写库。

在 Java/.NET 平台中,还是采用 Apache POINPOI For .NET)库。这个库的两个版本对 XLS 读写支持都是很完善的,不过对于 .NET 平台还可以采用微软官方的库(可能依赖 Microsoft Office 以及其授权)。

在 PHP 中可以采用 PHPExcel 库,这个库可以输出包括 Excel 97~2003 格式的xls格式,还可以输出类似的 xlsx 格式和 ods 格式。


现在发现,其实这些格式在深入研究以后都不是很困难,即使是非文本格式的,其实也是采用附加格式进行编码的,而困难在于了解其编码的方式。

有更好的解决方案或者更好的库推荐可以留言提出来,帮助更多有需要的人。:)

使用 Maven 管理 Java 项目

 

使用 Maven 并不是什么新鲜事了。不过,如果不是接触到 Node.js 里的 NPM 和 git ,或许我还真的很少会考虑到项目管理的问题。我想或许是以前真的很少接触过很多依赖关系的项目吧,但是,如果开发基于 Spring 的应用程序,依赖缺失的问题真的是一个十分困扰的问题。建议所有学习 Spring 的人都学习一下 Maven 这个工具。

稍微采纳一段来自百度百科的简介:(有修改,详情请参考 百度百科的 Maven 介绍 )

Maven是基于项目对象模型(POM),可以通过一小段描述信息来管理项目的构建,报告和文档的软件项目管理工具。 Maven这个单词来自于意第绪语,意为知识的积累,最早在 Jakata Turbine 项目中它开始被用来试图简化构建过程。当时有很多项目,它们的Ant build文件仅有细微的差别,而JAR文件都由CVS来维护。于是Maven创始者开始了Maven这个项目,该项目的清晰定义包括,一种很方便的发布项目信息的方式,以及一种在多个项目中共享JAR的方式。

这个项目和 Node.js 中的 npm 以及 ruby 中的 gem 很相似。简单地说,就是一个描述项目以及项目间关系的一个工具。

使用这个工具的两点好处:

  • 不需要手工维护依赖的文件位置。简化项目间依赖的问题。(在初学 Spring 的时候很容易找不到足够的依赖包,而这个文件可以帮助寻找)
  • 在 git 代码仓库中只保存和本项目相关的信息,其他代码可以通过描述由 Maven 自动获取。

在 Eclipse 中并未集成对 Maven 的支持。如果要在 Eclipse 中添加对 Maven 的支持,可以选择安装 Maven 的 Eclipse 的插件(即 m2e 插件,在 Eclipse 帮助菜单下的 Eclipse Marketplace 中可以搜索到)。对于开发基于 Spring 的程序,可以选择使用 STS 或者 MyEclipse 等第三方工具或者插件(这些工具包含了 m2e)。

只需要在新建项目的时候,选择 Maven 工程即可。对于已经建立的工程来说,也可以在项目窗格下右击项目,然后选择 Configure 菜单下的 Convert to Maven Project 即可。

然后, Maven 项目的关键在于使用 pom.xml 来管理项目以及项目依赖。在 pom.xml 中,主要分为几个区域:与当前项目相关的区域、依赖项、Maven 代码库地址、插件信息、编译代码等等。示例如下:

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <groupId><!-- 项目的组ID --></groupId>
    <artifactId><!-- 项目ID --></artifactId>
    <version><!-- 版本信息 --></version>
    <name><!-- 项目名称 --></name>
    <description><!-- 项目描述 --></description>
    <dependencies>
        <!-- 项目依赖项设置 -->
    </dependencies>

    <repositories>
        <!-- 项目依赖项的代码库,即如何获取依赖 -->
    </repositories>

    <build> <!-- 构建规则 -->
        <sourceDirectory>src</sourceDirectory>
        <resources> <!-- 资源位置 -->
            <resource>
                <directory>src</directory>
                <excludes>
                    <exclude>**/*.java</exclude>
                </excludes>
            </resource>
        </resources>
        <plugins> <!-- 插件 -->
            <plugin>
                <artifactId>maven-compiler-plugin</artifactId>
                <version>3.0</version>
                <configuration>
                    <source>1.7</source>
                    <target>1.7</target>
                </configuration>
            </plugin>
        </plugins>
    </build>
</project>

对于项目的依赖信息。Eclipse的图形化插件已经提供了相当详细的说明,例如,一个典型的依赖项可以写为:(在 <dependencies> 标签内)

<!-- mysql-connector-java -->
<dependency>
    <groupId>mysql</groupId>
    <artifactId>mysql-connector-java</artifactId>
    <version>5.1.17</version>
</dependency>

而对于特定的代码库地址,可以在 <repositories> 中定义如下:

<repository>
    <id>EclipseLink</id>
    <url>http://download.eclipse.org/rt/eclipselink/maven.repo</url>
</repository>

至于构建目录以及包含文件,可以参考上述 pom.xml 中 <build> 标签内的内容。

一般来说,要找到 Maven 的依赖地址,可以通过在 Google 中搜索。

对 <base>标签的设计评论

 

今天又把上次改的东西重新改了一遍,因为相信世界是美好的。别人总是用比较好的思路来进行框架的设计。但事实上,理想是美好,现实是残酷的。

就像 <base> 标签的设置。

本来客户端的事情,应该交给客户端来处理。发送请求到服务器,是客户端的事情,而关于请求的地址,是客户端的事情。如果服务器不告诉客户端必须有某一个地址,那么客户端应该用他认为正确的地址与服务器进行通信。

如果,地址只是服务器的唯一标识,那么,由客户端或者服务器端处理都一样。但是,一个服务器确实可以处理多个不同的站点,称之为虚拟地址。于是,地址不在是唯一标识了。

而, 本来应该设置为定义整个站点的链接基础前缀,却没有遵循这个规则。 标签必须指明通信的地址,不能依靠客户端推断。只是近期到了 HTML 5 以后,才出现一些转折,支持相对路径(也就是客户端推断地址)。

实际上,这个也许就是当初设计的时候考虑不周的后果吧。

大概因为当时没考虑到,到底会有多少种地址存在。

现在想想,其实真正的地址大概有 3 种吧。因为地址的构成实际上是三部分,主机、端口、主机上地址。但是单凭主机和端口,实际上只能确定一个地址,就是根地址,这个地址不具有扩展性,而且是绝对地址的一个子集,所以,不在考虑之内;而地址实际上有 2 种,一种是相对路径绝对路径,实际上,是分别以当前路径和根路径为标准的两种地址表示方式;那么,而相对路径和绝对路径都必须以来主机和端口。但是如果没有给出主机端口的时候,客户端可以推断是当前的主机和端口,于是,实际上形成了 3 种地址方式。

  • 绝对资源地址:主机、端口、绝对地址
  • 绝对地址:只含有绝对地址(推断主机、端口为当前的主机、端口)
  • 相对地址:相对当前的地址(推断主机、端口为当前的主机、端口,并且,相对与当前的地址)

但是, 标签的设计却只考虑了第一种,而实际上,后两种也很常见。

或者 HTML 定制之初的 90 年代,当时简单的应用,就想到一个地址对应一个应用程序吧。但明显,Java 系的 ContextPath 已经突破了这个。现在大数据时代的到来,服务器平衡等早已经把服务器端做得越来越复杂,但是用户看起来却越来越简单……

Github使用简略指南

为了更好地进行团队开发,所以写了这篇短文,简略介绍了一下 git 的使用(主要在 Windows 下)。

版本控制简介

至于什么是版本控制?作为程序员大军之一,想必大家有这样的经历吧。开始一个项目的时候,脑子一热,把程序一下子写了七七八八了,然后慢慢地到了瓶颈了,要实现新的功能,要改变某些结构。这个过程肯定是有很大风险的,说不定改变的时间要很长。但是客户又在催着要代码,那就为当前的版本起一个版本号吧,然后复制一份来重新改写部分,如果写好了,就交新的代码,改不好就又回到原来的版本。至少还可以交差。版本控制工具的原理也是这样,只是这个工具把代码都压缩存储了,省得自己手工复制代码然后存储。

然后我们来看看另一个场景。一个团队的人希望合作开发一个软件,为了让所有人都看到最新的改动,他们把代码放到一个 ftp 上,然后每个人做完自己的工作后,上传到 ftp 然后替换相关的文件。但是,我们知道,软件的开发很难做到完全不耦合,或者两个人的指责是相同的,只是工作时间不同,他们的更改很可能有冲突。于是,要么两个人消极地等待对方进行修改然后自己再修改,要么两个人过于积极以至于每次更改都要仔细看看对方的代码有没有和自己的冲突,费劲地更改代码。而版本控制工具则提供了一种更好的方法,可以自动合并修改(如果没有冲突的话),或者,如果遇到冲突就对用户进行提示。

而 git 就是解决这些问题的工具之一。

Git 以及 Github 简介

Git 是 Linus 在开发 Linux 内核时用于替换 Bitkeeper 版本控制工具(该工具不是免费的)而写的一个开源的分布式版本控制软件。而 Github 是一个代码托管网站。而代码托管的意思是允许人们把代码放到 Github ,并为团队开发提供一种比较简单的代码同步方法。Git 是一个分布式的版本控制工具。分布式主要是针对已有的 SVN 、CVS 受中央控制的版本控制工具而言的。在git里,每个代码库在相互独立的同时,又可以相互交换代码(通过push/pull)进行代码的交换。这里主要介绍Github在 Windows 上的使用。

安装 Github for Windows

http://windows.github.com/上下载 Github for Windows ,按提示安装即可。在安装过程中,git 的命令行版本也会一并安装。虽然在 Windows 下大多数应用都是基于图形界面的,但是使用 git 还是很有必要用命令行。

Github for Windows 实际上是 Github 网站的客户端版本,有网站上的一切功能,并且,为上传、更新位于 github.com 的代码库进行了良好的支持。使用 Github 帐号登陆以后,在图形界面里可以轻易地创建代码库。

Git 常用命令使用

命令行里git的命令列表以及解释:

  • git clone <address>:复制代码库到本地。
  • git add <file> ...:添加文件到代码库中。
  • git rm <file> ...:删除代码库的文件。
  • git commit -m <message>:提交更改,在修改了文件以后,使用这个命令提交修改。
  • git pull:从远程同步代码库到本地。
  • git push:推送代码到远程代码库。
  • git branch:查看当前分支。带*是当前分支。
    • git branch <branch-name>:新建一个分支。
    • git branch -d <branch-name>:删除一个分支。
  • git checkout <branch-name>:切换到指定分支。
  • git log:查看提交记录(即历史的 commit 记录)。
  • git status:当前修改的状态,是否修改了还没提交,或者那些文件未使用。
  • git reset <log>:恢复到历史版本。

看了这些命令以后,对里面的名词肯定有所疑问。**代码库**应该很好理解,就是存放代码的地方,而在 git clone 里,代码库一般指的是远程的代码库,即 github 给出的链接。而**分支**则是开发的一个阶段或者一个旁系版本,至于怎么定则取决于使用者了。例如,有一个分支叫做stable,代表里面的代码是经过测试的、稳定的;另一个分支叫dev,则是保存开发中的代码,不一定经过足够测试。

一般的开发流程

一般使用 git 的流程: 1. 编辑文件,更新代码。 2. 添加代码到当前待提交的更改列表中:git add <修改的文件>。 3. 提交当前修改作为一个记录:git commit -m '修改了<修改的文件>,原因是:……'。 4. 更新代码:git push

常见问题

这里的常见问题只是基于我的使用经历,如果有错或者有更好的想法,留言通知我~

  1. 什么时候提交更改记录( commit )?

    这个问题其实很随意,新增一个特性或者破坏了原有结构,甚至每一次改动都可以作为提交更改记录的依据。

  2. 什么时候推送更新( push )?

    一般来说,更改了项目的结构(包括文件、目录),就应该尽快推送更新,以通知其他协作者跟进这个更新。对于其它细微的修改,没有破坏到别人的工作的,可以随自己的想法更新(如果是提交了某些激动人心的特性,就赶紧推送给别人分享吧~ )

    不过切记,更改了目录结构、文件结构等一定要在commit中写清楚,否则别人可能还是一头雾水。

  3. 什么时候和远程同步( pull )?

    每次开始工作前都应该同步一下,以免自己的修改和别人冲突或者别人做了结构性的调整和自己的修改不协调了。

  4. 分支( branch )的使用?

    至于远程分支的使用,可以参考 github 的推荐方法功能划分方法,来自,就是说,每一个功能设定一个分支,当修改完成以后再合并到 master ,保证 master 分支是可用的。

    对于本地分支(就是本地代码库的分支了,这两个是不同的概念哦,记得 git 是分布式的,每个代码库有关联但又互相独立),使用就比较随便了。主要是方便自己开发即可。

  5. 怎么解决冲突( conflict )?

    在团队开发中,同时对某一个文件进行改写是常见的事,但是我们应该尽可能避免。每个模块之间应该进行良好的隔离。但一旦遇到冲突,git也有很好的解决方法。

    在同步代码的过程中,git会自动检查冲突,并尝试进行**自动合并**。最好的情况应该是大家同时修改一个文件,但是大家修改的地方不同了。在这样的情况下,git会进行非冲突合并,这时,在调用 git pull 的时候,git会尝试进行非冲突合并。

    而在合并过程中有冲突的时候, git 会把修改记录直接保存在文件中,让开发者判断文件如何解决合并。例如,在一个描述文件中同时修改了一句话,在合并的时候,git会这么做:

    <<<<<<< HEAD
    It's not a project cool enough for you to enjoy the code but a mix of my thoughts in the year 2012~2013. I didn't know where the project leads to. Hope it will became useful after practice.
    =======
    It's not a project cool enough for you to enjoy the code but it's a mix of my thoughts in the year 2012~2013. I didn't know where the project leads to. Hope it will became useful after practice.
    >>>>>>> 2b41083cf969979d8e4a1eedc987976af544d129

    即把两个更改都写在文件上,但是用=======来区别发生冲突的位置,在=======以上是 HEAD,即本地的代码;而=======以下则是来自远程的更改了。这个时候,你可以选择保留远程或本地的修改或者都不要(简单地说,把不需要的内容删除即可)。

  6. 怎样恢复到历史版本( reset )?

    使用 git log 查看更改记录,记住其中的 commit 版本号,然后,运行 git reset <log> --hard 即可( <log> 即 commit 版本号)。另外, git reset HEAD 可以恢复到上一个 commit 版本。

    如果只是想把更改状态切换到某一个历史记录,那么,可以 git reset <log> 这样,文件不会恢复到历史版本,但是,在这个记录后修改的文件会被标记为已修改,但未添加修改记录里。

Enterprise JavaBean笔记:Domain Object

首先解释一下DO的意思:Domain Object,域对象,在某一个范围(域)内有效的对象。

之所以设置DO,是因为Entity bean在远程传输(RMI)的过程中会舍弃信息(那些由EntityManager控制的信息会在RMI传输后丢失),从而使得部分方法失效。

如 果探究过Entity Bean的OneToMany、ManyToMany模型的Lazy fetch机制的话,就会发现,这些方法是受EntityManager控制的,只有在需要调用的时候才会有内容(即再向服务器发送请求获取内容)。如果 经过RMI后,Entity Bean不再受EntityManager控制,那么Lazy fetch机制将失效(对应的方法返回的结果是未知的,也就是说Entity Bean的部分方法也失效了。为了避免使得Entity Bean失效,设置一个轻量级的DO来代替Entity Bean,保证DO的方法都是可用的。

因此,每个Entity Bean可能会有多个DO,用来对应不同的功能,有些DO预先获取了lazy fetch的列表,有些则不,充分发挥lazy fetch需要才调用的效果。

 

Enterprise JavaBean笔记:第一印象

这篇文章只是对 EJB 起一个很初步的认识。

以前觉得,既然有了 JSP 和 Servlet ,基本分离了表现和逻辑,再加上 Filter 作为视图层的补充,Listener 为事件监听。已经是一个比较完善的架构了。EJB 要作为那一部分的补充而存在呢?

实际上,EJB 的存在应该是为了补充 Servlet 对拓展性不足而存在的。EJB 的存在,一个基本的修改的是,把两层结构 user -> Servlet ,修改为 user -> Servlet -> EJB。实际上,如果按照原来的设想,Servlet本身就可以作为一个 Stateless Session Bean,但由于 Servlet 实现的历史原因, Servlet 必须继承于 HttpServlet 类,并且带有 HTTP 的特征,作为视图层的 JSP 实际上是一个特殊化的 Servlet 。也就是说, Servlet 本来也是为单一业务(HTTP)而存在的,算是一个适配器。而客户端技术,却不仅仅只是 HTTP 和 HTML,因此,一个只为业务而生的逻辑层应运而生,即 EJB 。

在《Java EE 6 Tutorial》中对 EJB 的介绍:

You should consider using enterprise beans if your application has any of the following requirements.

  • The application must be scalable. To accommodate a growing number of users, you may need to distribute an application’s components acrossmultiplemachines. Not only can the enterprise beans of an application run on differentmachines, but also their locationwill
  • remain transparent to the clients.
  • Transactionsmust ensure data integrity. Enterprise beans support transactions, the mechanisms thatmanage the concurrent access of shared objects.
  • The application will have a variety of clients. With only a few lines of code, remote clients can easily locate enterprise beans. These clients can be thin, various, and numerous.

EJB 的拓展性,主要体现在 EJB 容器的对象缓存上。由于 EJB 的缓存,客户端(包括 Web 应用)可以很快地获取 EJB 对象。而其他特点,数据一致性、支持多客户端,都基于对象池的设计。

EJB 的类型分为 Session bean 和 Message Driven Bean。 Session Bean 中的无状态 Bean 就是缓存的主要对象。关于这方面的资料,可以参考《The Java EE 6 Tutorial》。

Enterprise JavaBean 笔记:JBoss安装与配置

记得刚上大学不久,学 Java 的时候,就曾经听说过 Enterprise JavaBean 了,但一直没有试用过,因为,从这个名字看来,很容易和 JavaBean 混淆。而在 Enterprise JavaBean 介绍中提到的分布式、可伸缩的网络模块的时候,又显然和作为对象数据存取规范的 JavaBean 规范不同。Enterprise JavaBean 更像是一个遵循 JavaBean 规范的网络服务提供者。一直以来用PHP来开发网站,对 Java 这边规范的 MVC 开发模式还是颇为羡慕。而这个学期就开始 EJB 的旅程了~

这个系列博客大概会持续讨论关于 Enterprise JavaBean 的问题,欢迎大家提出意见。 :-)

环境选择:

这里选择 NetBeans + JBoss AS 5.1 作为开发环境。选择 JBoss AS 5.1 是因为课程需要,其实 NetBeans + Glassfish 的组合可能更好。

  1. JBoss AS 5.1:可以在http://sourceforge.net/projects/jboss/files/JBoss/JBoss-5.1.0.GA找到,下载后解压即可。
  2. Netbeans 7.2:可以在http://www.netbeans.org下载NetBeans 7.2 for Java EE(按提示安装即可,其中可以选择安装安装包带上的Glassfish 3.2.2,Java EE 6兼容服务器)。

配置:

NetBeans安装成功后,如果开始时选择了Glassfish,那么已经有一个Java EE 6兼容服务器。不过,这里选择课堂要求的JBoss Application Server 5.1。

  1. 在NetBeans的服务器平台上,点击“工具”->“服务器”。
  2. 在服务器窗口点击“添加服务器”,按提示添加“JBoss Application Server”,选择JBoss的安装根目录即可。
  3. 启动JBoss AS 5.1,如果出现“java.lang.IllegalArgumentException: Wrong arguments. new for target java.lang.reflect.Constructor expected=[java.net.URI] actual=[java.io.File]”的提示,大多是因为注入AttachmentStore类的时候没有指定注入类型导致。
    编辑%JBOSS_HOME%/server/default/conf/bootstrap/profile.xml文件:
    ……
    
    <bean name="AttachmentStore" class="org.jboss.system.server.profileservice.repository.AbstractAttachmentStore">
        <constructor>
            <parameter>
                <inject bean="BootstrapProfileFactory" property="attachmentStoreRoot" />
            </parameter>
        </constructor>
    ……

    修改<parameter>标签为:

    ……
            <parameter class="java.io.File">
    ……

    即可。

测试:

  1. 新建 EJB 模块。新建 Stateless Session Bean(无状态会话Bean),新建向导创建Local(本地)接口的无状态会话 Bean,添加一个 Bussiness Method (在编辑区域内,按 alt + Insert,即弹出生成代码框,选择 NetBeans 的原因一部分就是因为 NetBeans 挺方便的代码生成功能)。
    代码看起来像:
    package hello.greeting;
    
    import javax.ejb.Stateless;
    
    @Stateless
    public class Greeting implements GreetingLocal {
    
        public String greet(String name) {
            return "Hello, " + name + "!";
        }
    }

    接口如下:

    package hello.greeting;
    
    import javax.ejb.Local;
    
    @Local
    public interface GreetingLocal {
    
        public String greet(String name);
    }
  2. 新建 Web 应用程序项目,编辑项目属性,添加 上面创建的 EJB 模块到 Libraries (库)中,不需要包括在编译包中。这里只是为了让这个 Web 应用程序知道会话 Bean 的接口而已。
    编辑 index.jsp,在空白处添加对 EJB 的引用:
    <%@page contentType="text/html" pageEncoding="UTF-8"%>
    <%@page import="javax.naming.*" %>
    <%
    InitialContext context = new InitialContext();
    GreetingLocal bean = (GreetingLocal) context.lookup("Greeting/local");
    out.println(bean.greet("Jack"));
    %>
  3. 发布 EJB 模块和 Web 应用程序来测试吧~