18. 三层架构中的 MVC Web 应用程序——示例 4,Postgres
18.1. Postgres 数据库
在此版本中,我们将人员列表存储在 Postgres 8.x 数据库表中 [http://www.postgres.org]。下文中的屏幕截图均来自 EMS PostgreSQL Manager Lite 客户端 [http://www.sqlmanager.net/fr/products/postgresql/manager],这是一个用于 Postgres 数据库管理系统 (DBMS) 的免费管理客户端。
该数据库命名为 [dbpersonnes]。其中包含一个名为 [PERSONNES] 的表:

[PERSONNES] 表将存储由 Web 应用程序管理的人员列表。该表是通过以下 SQL 语句创建的:
我们不会过多讨论这个表,它与前面讨论过的 Firebird [PERSONNES] 表类似。但请注意,列名和表名都用引号括起来。此外,这些名称区分大小写。Postgres 8.x 中的这种行为可能是可配置的。我尚未对此进行进一步研究。
[PERSONNES] 表可能包含以下内容:

除了 [PERSONNES] 表外,[dbpersonnes] 数据库中还有一个名为 [SEQ_ID] 的序列对象。该生成器会生成连续的整数,我们将用这些整数来填充 [PERSONNES] 类的 [ID] 主键。让我们通过一个示例来说明其工作原理:
![]() |
![]() |
我们可以看到 [SEQ_ID] 序列的 [下一个值] 已发生变化(双击该序列并按 F5 刷新):
![]() |
SQL 语句
因此,该 SQL 语句允许我们检索 [SEQ_ID] 序列中的下一个值。我们将在 [people-postgres.xml] 文件中使用它,该文件包含在数据库管理系统(DBMS)上执行的 SQL 语句。
18.2. 用于 [dao] 和 [service] 层的 Eclipse 项目
为了使用 Postgres 8.x 数据库开发应用程序的 [dao] 和 [service] 层,我们将使用以下 Eclipse 项目 [spring-mvc-39]:

该项目是一个简单的 Java 项目,而非 Tomcat Web 项目。
[src] 文件夹
该文件夹包含 [dao] 和 [service] 层的源代码:

所有文件名中包含 [postgres] 的文件,与 Firebird 版本相比,可能已被修改,也可能未被修改。下面我们将描述已修改的文件。
[database] 文件夹
该文件夹包含用于为用户创建 Postgres 数据库的脚本:
![]()
[lib] 文件夹
此文件夹包含应用程序所需的资源包:
![]() |
请注意其中包含 Postgres 8.x 数据库管理系统 (DBMS) 的 JDBC 驱动程序。所有这些文件均属于 Eclipse 项目的类路径。
18.3. [dao] 层
[dao] 层如下所示:

我们仅展示与 [Firebird] 版本相比的变更。
映射文件 [personne-postgres.xml] 如下:
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE sqlMap
PUBLIC "-//iBATIS.com//DTD SQL Map 2.0//EN"
"http://www.ibatis.com/dtd/sql-map-2.dtd">
<!-- warning - Postgresql 8 requires exact spelling of column names
et des tables ainsi que des guillemets autour de ces noms -->
<sqlMap>
<!-- alias class [Person] -->
<typeAlias alias="Personne.classe"
type="istia.st.mvc.personnes.entites.Personne"/>
<!-- mapping table [PERSONNES] - object [Person] -->
<resultMap id="Personne.map"
class="istia.st.mvc.personnes.entites.Personne">
<result property="id" column="ID" />
<result property="version" column="VERSION" />
<result property="nom" column="NOM"/>
<result property="prenom" column="PRENOM"/>
<result property="dateNaissance" column="DATENAISSANCE"/>
<result property="marie" column="MARIE"/>
<result property="nbEnfants" column="NBENFANTS"/>
</resultMap>
<!-- list of all persons -->
<select id="Personne.getAll" resultMap="Personne.map" > select "ID",
"VERSION", "NOM", "PRENOM", "DATENAISSANCE", "MARIE", "NBENFANTS" FROM
"PERSONNES"</select>
<!-- get a specific person -->
<select id="Personne.getOne" resultMap="Personne.map" >select "ID",
"VERSION", "NOM", "PRENOM", "DATENAISSANCE", "MARIE", "NBENFANTS" FROM
"PERSONNES" WHERE "ID"=#value#</select>
<!-- add a person -->
<insert id="Personne.insertOne" parameterClass="Personne.classe">
<selectKey keyProperty="id">
SELECT nextval('"SEQ_ID"') as value
</selectKey>
insert into "PERSONNES"("ID", "VERSION",
"NOM", "PRENOM", "DATENAISSANCE", "MARIE", "NBENFANTS") VALUES(#id#,
#version#, #nom#, #prenom#, #dateNaissance#, #marie#, #nbEnfants#)
</insert>
<!-- update a person -->
<update id="Personne.updateOne" parameterClass="Personne.classe"> update
"PERSONNES" set "VERSION"=#version#+1, "NOM"=#nom#, "PRENOM"=#prenom#,
"DATENAISSANCE"=#dateNaissance#, "MARIE"=#marie#, "NBENFANTS"=#nbEnfants#
WHERE "ID"=#id# and "VERSION"=#version#</update>
<!-- delete a person -->
<delete id="Personne.deleteOne" parameterClass="int"> delete FROM
"PERSONNES" WHERE "ID"=#value# </delete>
</sqlMap>
这与 [people-firebird.xml] 的内容相同,仅有以下细微差异:
- 列名和表名需用引号括起,且区分大小写
- 第 34–41 行中的 SQL 语句 "Person.insertOne" 已发生变更。Postgres 生成主键的方式与 Firebird 不同:
- 第 36 行:SQL 语句 [SELECT nextval('"SEQ_ID"')] 提供主键。必须使用 [as value] 语法。[value] 代表获取的键值。该值将被赋给 [Person] 对象中由 [keyProperty] 属性(第 35 行)指定的字段,此处即 [id] 字段。
- <insert> 标签内的 SQL 语句按其出现的顺序执行。因此,SELECT 语句会在 INSERT 语句之前执行。当插入操作发生时,[Person] 对象的 [id] 字段已由 SELECT SQL 语句更新完毕。
- 第 38–40 行:插入 [Person] 对象
[dao] 层的实现类 [DaoImplCommon] 即 [Firebird] 版本中研究的那个类。
[dao]层的配置已适配至[Postgres]数据库管理系统。因此,配置文件[spring-config-test-dao-postgres.xml]如下所示:
<?xml version="1.0" encoding="ISO_8859-1"?>
<!DOCTYPE beans SYSTEM "http://www.springframework.org/dtd/spring-beans.dtd">
<beans>
<!-- data source DBCP -->
<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource"
destroy-method="close">
<property name="driverClassName">
<value>org.postgresql.Driver</value>
</property>
<property name="url">
<value>jdbc:postgresql:dbpersonnes</value>
</property>
<property name="username">
<value>postgres</value>
</property>
<property name="password">
<value>postgres</value>
</property>
</bean>
<!-- SqlMapCllient -->
<bean id="sqlMapClient"
class="org.springframework.orm.ibatis.SqlMapClientFactoryBean">
<property name="dataSource">
<ref local="dataSource"/>
</property>
<property name="configLocation">
<value>classpath:sql-map-config-postgres.xml</value>
</property>
</bean>
<!-- the [dao] layer access classes -->
<bean id="dao" class="istia.st.mvc.personnes.dao.DaoImplCommon">
<property name="sqlMapClient">
<ref local="sqlMapClient"/>
</property>
</bean>
</beans>
- 第 5–19 行:[dataSource] Bean 现在指向 [Postgres] 数据库 [dbpersonnes],其管理员为 [postgres],密码为 [postgres]。读者应根据自身环境修改此配置。
- 第 31 行:[DaoImplCommon] 类是 [dao] 层的实现类
完成这些修改后,我们可以进行测试。
18.4. 针对 [dao] 和 [service] 层的测试
针对 [dao] 和 [service] 层的测试与 [Firebird] 版本的测试相同。让我们启动 Postgres 数据库管理系统,然后运行 Eclipse 测试。所得结果如下:
![]() |
我们可以看到,使用 [DaoImplCommon] 实现时测试已成功通过。与 [Firebird] 数据库管理系统的情况不同,我们无需派生该类。
18.5. [Web] 应用程序测试
为了使用 [Postgres] 数据库管理系统测试 Web 应用程序,我们以与构建基于 Firebird 数据库的 [mvc-personnes-03B] 项目类似的方式,构建了一个 Eclipse 项目 [mvc-personnes-04B](参见第 17.7 节)。 不过,我们无需重新生成 [personnes-dao.jar] 和 [personnes-service.jar] 归档文件。事实上,与 [mvc-personnes-03B] 项目相比,我们并未修改任何类。 [personnes-dao.jar] 归档文件中仅包含 [DaoImplFirebird] 类,而该类现已不再需要。

我们将 Web 项目 [mvc-personnes-04B] 部署到 Tomcat 中:
![]() | ![]() |
现在可以进行测试了 。 [PERSONNES] 表中的内容如下:

Tomcat 正在运行。我们使用浏览器访问 URL [http://localhost:8080/mvc-personnes-04B]:

我们通过 [Add] 链接添加一位新用户:
![]() | ![]() |
我们在数据库中验证新增记录:

欢迎读者进行进一步测试 [更新、删除]。








